diff --git a/.gitignore b/.gitignore index c29fa3e3a48e9846b5c7c422b746589cb740802d..163d09fd929ab0a4e414915592c68e0293c11eb8 100644 --- a/.gitignore +++ b/.gitignore @@ -32,6 +32,7 @@ examples/*/*/*.dat examples/*/*/*.png examples/*/*/*.pdf examples/*/*/*.mp4 +examples/*/*/*.txt examples/*/*/*.rst examples/*/*/*.hdf5 examples/*/*/*.csv @@ -53,6 +54,7 @@ examples/*/*/used_parameters.yml examples/*/*/unused_parameters.yml examples/*/*/fof_used_parameters.yml examples/*/*/fof_unused_parameters.yml +examples/*/*/partition_fixed_costs.h examples/*/*.mpg examples/*/*/gravity_checks_*.dat examples/*/*/coolingtables.tar.gz @@ -162,6 +164,7 @@ tests/testOutputList tests/testCbrt tests/testFormat.sh tests/testCooling +tests/testComovingCooling tests/testHashmap tests/*.png tests/*.txt diff --git a/README b/README index 8d722a66da5083889e0adfb5af51206509bef53d..ccbb7cfeb178bccd9333ef14071efadebe9eec1c 100644 --- a/README +++ b/README @@ -6,7 +6,7 @@ /____/ |__/|__/___/_/ /_/ SPH With Inter-dependent Fine-grained Tasking - Version : 0.8.4 + Version : 0.8.5 Website: www.swiftsim.com Twitter: @SwiftSimulation @@ -41,7 +41,17 @@ Parameters: black holes seeding. -x, --velociraptor Run with structure finding. --limiter Run with time-step limiter. - + --sync Run with time-step synchronization + of particles hit by feedback events. + + Simulation meta-options: + + --eagle Run with all the options needed for the + EAGLE model. This is equivalent to --hydro + --limiter --sync --self-gravity --stars + --star-formation --cooling --feedback + --black-holes --fof. + Control options: -a, --pin Pin runners using processor affinity. diff --git a/README.md b/README.md index f91b03d3f6a9656e33adc3216a15ed41e7b971de..c9b373be64dcde03732b63c1bc2190102fe0c2ec 100644 --- a/README.md +++ b/README.md @@ -57,7 +57,7 @@ Runtime parameters /____/ |__/|__/___/_/ /_/ SPH With Inter-dependent Fine-grained Tasking - Version : 0.8.4 + Version : 0.8.5 Website: www.swiftsim.com Twitter: @SwiftSimulation @@ -92,7 +92,16 @@ Parameters: perform black hole seeding. -x, --velociraptor Run with structure finding. --limiter Run with time-step limiter. - + --sync Run with time-step synchronization + of particles hit by feedback events. + Simulation meta-options: + + --eagle Run with all the options needed for the + EAGLE model. This is equivalent to --hydro + --limiter --sync --self-gravity --stars + --star-formation --cooling --feedback + --black-holes --fof. + Control options: -a, --pin Pin runners using processor affinity. diff --git a/configure.ac b/configure.ac index b220255b068f6724f9a7588f1a49a4765dbd4fd8..e46d7a27d34c19c0d086cb6b33a341ba0fbd4ae2 100644 --- a/configure.ac +++ b/configure.ac @@ -16,7 +16,7 @@ # along with this program. If not, see <http://www.gnu.org/licenses/>. # Init the project. -AC_INIT([SWIFT],[0.8.4],[https://gitlab.cosma.dur.ac.uk/swift/swiftsim]) +AC_INIT([SWIFT],[0.8.5],[https://gitlab.cosma.dur.ac.uk/swift/swiftsim]) swift_config_flags="$*" # We want to stop when given unrecognised options. No subdirs so this is safe. @@ -71,6 +71,13 @@ AC_USE_SYSTEM_EXTENSIONS AX_COMPILER_VENDOR AX_COMPILER_VERSION +# Check whether we have a recent enough GCC +if test "$ax_cv_c_compiler_vendor" = "gnu"; then + AX_COMPARE_VERSION([$ax_cv_c_compiler_version], [ge], [8.1.0], + [gcc_handles_avx512="yes"], + [gcc_handles_avx512="no"]) +fi + # Restrict support. AC_C_RESTRICT @@ -85,6 +92,12 @@ AC_ARG_ENABLE([logger], if test "$with_logger" = "yes"; then AC_DEFINE([WITH_LOGGER], 1, [logger enabled]) + # The logger requires that long long is a 64bit type, let's + # check that. + AC_CHECK_SIZEOF([long long int]) + if test "$ac_cv_sizeof_long_long_int" != "8"; then + AC_MSG_ERROR([The particle logger requires that 'long long int' has size 8 bytes]) + fi fi AM_CONDITIONAL([HAVELOGGER],[test $with_logger = "yes"]) @@ -463,6 +476,35 @@ if test "$enable_opt" = "yes" ; then AX_CC_MAXOPT ac_test_CFLAGS="yes" + # Choose the best flags for the gravity sub-library on this compiler and architecture + if test "$ax_cv_c_compiler_vendor" = "intel"; then + case "$icc_flags" in + *CORE-AVX512*) + GRAVITY_CFLAGS="$GRAVITY_CFLAGS -qopt-zmm-usage=high" + ;; + *) + AC_MSG_WARN([No additional flags needed for gravity on this platform]) + ;; + esac + elif test "$ax_cv_c_compiler_vendor" = "gnu"; then + if test "$gcc_handles_avx512" = "yes"; then + case "$ax_gcc_arch" in + *skylake-avx512*) + GRAVITY_CFLAGS="$GRAVITY_CFLAGS -mprefer-vector-width=512" + ;; + *) + AC_MSG_WARN([No additional flags needed for gravity on this platform]) + ;; + esac + else + AC_MSG_WARN([No additional flags needed for gravity on this platform]) + fi + else + AC_MSG_WARN([Do not know what best gravity vectorization flags to choose for this compiler]) + fi + AC_ARG_VAR([GRAVITY_CFLAGS], [C compiler flags added to the basic CFLAGS to compile + the gravity-related files.]) + # Check SSE & AVX support (some overlap with AX_CC_MAXOPT). # Don't use the SIMD_FLAGS result with Intel compilers. The -x<code> # value from AX_CC_MAXOPT should be sufficient. @@ -690,7 +732,8 @@ if test "x$with_parmetis" != "xno"; then PARMETIS_LIBS="-lparmetis -lmetis" PARMETIS_INCS="" fi - AC_CHECK_LIB([parmetis],[ParMETIS_V3_RefineKway], [have_parmetis="yes"], + # Note use different function to avoid caching of first check. + AC_CHECK_LIB([parmetis],[ParMETIS_V3_PartKway], [have_parmetis="yes"], [have_parmetis="no"], [$METIS_LIBS $PARMETIS_LIBS]) fi @@ -1022,6 +1065,16 @@ fi AC_SUBST([TBBMALLOC_LIBS]) AM_CONDITIONAL([HAVETBBMALLOC],[test -n "$TBBMALLOC_LIBS"]) +# check for a random seed +AC_ARG_WITH([random-seed], + [AS_HELP_STRING([--with-random-seed=SHORT INT], + [Set the random seed.] + )], + [with_random_seed="$withval"], + [with_random_seed="0"] +) +AC_DEFINE_UNQUOTED([SWIFT_RANDOM_SEED_XOR], [$with_random_seed],[Value of the random seed.]) + # Check for python. have_python="no" AC_ARG_WITH([python], @@ -1388,6 +1441,7 @@ with_subgrid_pressure_floor=none with_subgrid_stars=none with_subgrid_star_formation=none with_subgrid_feedback=none +with_subgrid_task_order=none case "$with_subgrid" in yes) @@ -1397,12 +1451,14 @@ case "$with_subgrid" in ;; GEAR) with_subgrid_cooling=grackle_0 - with_subgrid_chemistry=GEAR + with_subgrid_chemistry=GEAR_10 with_subgrid_pressure_floor=GEAR with_subgrid_stars=GEAR with_subgrid_star_formation=GEAR - with_subgrid_feedback=none + with_subgrid_feedback=GEAR with_subgrid_black_holes=none + # GEAR's order is not used anymore + with_subgrid_task_order=none enable_fof=no ;; EAGLE) @@ -1414,6 +1470,7 @@ case "$with_subgrid" in with_subgrid_star_formation=EAGLE with_subgrid_feedback=EAGLE with_subgrid_black_holes=EAGLE + with_subgrid_task_order=EAGLE enable_fof=yes ;; *) @@ -1512,8 +1569,11 @@ case "$with_hydro" in planetary) AC_DEFINE([PLANETARY_SPH], [1], [Planetary SPH]) ;; + sphenix) + AC_DEFINE([SPHENIX_SPH], [1], [SPHENIX SPH]) + ;; anarchy-du) - AC_DEFINE([ANARCHY_DU_SPH], [1], [ANARCHY (DU) SPH]) + AC_DEFINE([SPHENIX_SPH], [1], [SPHENIX SPH]) ;; anarchy-pu) AC_DEFINE([ANARCHY_PU_SPH], [1], [ANARCHY (PU) SPH]) @@ -1744,7 +1804,8 @@ esac # chemistry function AC_ARG_WITH([chemistry], [AS_HELP_STRING([--with-chemistry=<function>], - [chemistry function @<:@none, GEAR, EAGLE default: none@:>@] + [chemistry function @<:@none, GEAR_*, EAGLE default: none@:>@ + For GEAR, you need to provide the number of elements (e.g. GEAR_10)] )], [with_chemistry="$withval"], [with_chemistry="none"] @@ -1762,8 +1823,10 @@ case "$with_chemistry" in none) AC_DEFINE([CHEMISTRY_NONE], [1], [No chemistry function]) ;; - GEAR) + GEAR_*) AC_DEFINE([CHEMISTRY_GEAR], [1], [Chemistry taken from the GEAR model]) + number_element=${with_chemistry:5} + AC_DEFINE_UNQUOTED([GEAR_CHEMISTRY_ELEMENT_COUNT], [$number_element], [Number of element to follow]) ;; EAGLE) AC_DEFINE([CHEMISTRY_EAGLE], [1], [Chemistry taken from the EAGLE model]) @@ -1773,6 +1836,16 @@ case "$with_chemistry" in ;; esac +if test "$with_chemistry" != "none"; then + if test "$enable_hand_vec" == "yes"; then + if test "$enable_vec" == "yes"; then + if test "$with_hydro" == "gadget2"; then + AC_MSG_ERROR([Cannot run with hand vectorisation and chemistry yet. Please use --disable-hand-vec]) + fi + fi + fi +fi + # Particle tracers AC_ARG_WITH([tracers], [AS_HELP_STRING([--with-tracers=<function>], @@ -1856,6 +1929,9 @@ case "$with_feedback" in EAGLE) AC_DEFINE([FEEDBACK_EAGLE], [1], [EAGLE stellar feedback and evolution model]) ;; + GEAR) + AC_DEFINE([FEEDBACK_GEAR], [1], [GEAR stellar feedback and evolution model]) + ;; none) AC_DEFINE([FEEDBACK_NONE], [1], [No feedback]) ;; @@ -1894,6 +1970,38 @@ case "$with_black_holes" in ;; esac +# Task order +AC_ARG_WITH([task-order], +[AS_HELP_STRING([--with-task-order=<model>], +[Task order to use @<:@none, EAGLE, GEAR default: none@:>@] +)], +[with_task_order="$withval"], +[with_task_order="none"] +) + +if test "$with_subgrid" != "none"; then +if test "$with_task_order" != "none"; then +AC_MSG_ERROR([Cannot provide with-subgrid and with-task-order together]) +else +with_task_order="$with_subgrid_task_order" +fi +fi + +case "$with_task_order" in +EAGLE) +AC_DEFINE([TASK_ORDER_EAGLE], [1], [EAGLE task order]) +;; +none) +AC_DEFINE([TASK_ORDER_NONE], [1], [Default task order]) +;; +GEAR) +AC_DEFINE([TASK_ORDER_GEAR], [1], [GEAR task order]) +;; +*) +AC_MSG_ERROR([Unknown task ordering: $with_task_order]) +;; +esac + # External potential AC_ARG_WITH([ext-potential], [AS_HELP_STRING([--with-ext-potential=<pot>], @@ -2050,6 +2158,12 @@ AM_CONDITIONAL([HAVEEAGLECOOLING], [test $with_cooling = "EAGLE"]) # Check if using EAGLE feedback AM_CONDITIONAL([HAVEEAGLEFEEDBACK], [test $with_feedback = "EAGLE"]) +# check if using grackle cooling +AM_CONDITIONAL([HAVEGRACKLECOOLING], [test ${with_cooling:0:7} == "grackle"]) + +# check if using gear feedback +AM_CONDITIONAL([HAVEGEARFEEDBACK], [test $with_feedback == "GEAR"]) + # Handle .in files. AC_CONFIG_FILES([Makefile src/Makefile examples/Makefile examples/Cooling/CoolingRates/Makefile doc/Makefile doc/Doxyfile tests/Makefile]) AC_CONFIG_FILES([argparse/Makefile tools/Makefile logger/Makefile logger/tests/Makefile]) @@ -2129,6 +2243,7 @@ AC_MSG_RESULT([ Star formation model : $with_star_formation Star feedback model : $with_feedback Black holes model : $with_black_holes + Task dependencies : $with_task_order Individual timers : $enable_timers Task debugging : $enable_task_debugging diff --git a/doc/RTD/source/CommandLineOptions/index.rst b/doc/RTD/source/CommandLineOptions/index.rst index 5251b36f7394465c59577932155544a755c0ee43..f7cadd1f3a1f049392c1465f4bbc23065a562d67 100644 --- a/doc/RTD/source/CommandLineOptions/index.rst +++ b/doc/RTD/source/CommandLineOptions/index.rst @@ -38,6 +38,15 @@ can be found by typing ``./swift -h``: perform black hole seeding. -x, --velociraptor Run with structure finding. --limiter Run with time-step limiter. + --sync Run with time-step synchronization + of particles hit by feedback events. + Simulation meta-options: + + --eagle Run with all the options needed for the + EAGLE model. This is equivalent to --hydro + --limiter --sync --self-gravity --stars + --star-formation --cooling --feedback + --black-holes --fof. Control options: diff --git a/doc/RTD/source/HydroSchemes/anarchy_sph.rst b/doc/RTD/source/HydroSchemes/anarchy_sph.rst index 267842936bddaf70f36c4aa4f53c27eb8c802108..aedd65ca61dc56676b77f48d7cd69d6f32e27878 100644 --- a/doc/RTD/source/HydroSchemes/anarchy_sph.rst +++ b/doc/RTD/source/HydroSchemes/anarchy_sph.rst @@ -62,64 +62,3 @@ There is also a compile-time parameter, ``viscosity_beta`` that we set to ``hydro_props_default_viscosity_alpha_feedback_reset = 2.0`` and the diffusion is set to ``hydro_props_default_diffusion_alpha_feedback_reset = 0.0``. These can be changed in ``src/hydro/AnarchyPU/hydro_parameters.h``. - - -ANARCHY-DU SPH -============== - -This is the new scheme that will be used in EAGLE-XL. This scheme includes: - -+ Durier & Dalla Vecchia (2012) time-step limiter -+ Density-Energy SPH -+ Thermal diffusion following Price (2012) -+ A simplified version of the 'Inviscid SPH' artificial viscosity - (Cullen & Dehnen 2010), with a Balsara switch -+ A diffusion limiter, used to prevent energy leakage out of EAGLE - supernovae (Borrow in prep). - -More information will be made available in a forthcoming publication. - -The simplified version of the 'Inviscid SPH' artificial viscosity calculates -the time differential of the velocity divergence explicitly, using the value -from the previous step. We also use the Balsara switch instead of the improved -neighbour-based limiter from Cullen & Dehnen 2010, to avoid matrix -calculations. - -The diffusion limiter is implemented to ensure that the diffusion is turned -ff in very viscous flows and works as follows: - -.. code-block:: C - - float new_diffusion_alpha = old_diffusion_alpha; - - const float viscous_diffusion_limit = - diffusion_alpha_max * - (1.f - maximum_alpha_visc_over_ngb / viscosity_alpha_max); - - new_diffusion_alpha = min(new_diffusion_alpha, viscous_diffusion_limit); - - -The parameters available for this scheme, and their defaults, are: - -.. code-block:: yaml - - SPH: - viscosity_alpha: 0.1 # Initial value for the alpha viscosity - viscosity_length: 0.25 # Viscosity decay length (in terms of sound-crossing time) - # These are enforced each time-step - viscosity_alpha_max: 2.0 # Maximal allowed value for the viscosity alpha - viscosity_alpha_min: 0.0 # Minimal allowed value for the viscosity alpha - - diffusion_alpha: 0.0 # Initial value for the diffusion alpha - diffusion_beta: 0.25 # Timescale to raise the diffusion coefficient over - # (decay is on the sound-crossing time) - # These are enforced each time-step - diffusion_alpha_max: 1.0 - diffusion_alpha_min: 0.0 - - -There is also a compile-time parameter, ``viscosity_beta`` that we set to -3.0. During feedback events, the viscosity is set to the compile-time -``hydro_props_default_viscosity_alpha_feedback_reset = 2.0`` and the -diffusion is set to ``hydro_props_default_diffusion_alpha_feedback_reset = -0.0``. These can be changed in ``src/hydro/AnarchyPU/hydro_parameters.h``. diff --git a/doc/RTD/source/HydroSchemes/index.rst b/doc/RTD/source/HydroSchemes/index.rst index 7331331bda7c28fad2f471dedb1335f1201d4a21..807ef42ddca8b4269a1007c4bbcdc2d3e8558971 100644 --- a/doc/RTD/source/HydroSchemes/index.rst +++ b/doc/RTD/source/HydroSchemes/index.rst @@ -18,6 +18,7 @@ schemes available in SWIFT, as well as how to implement your own. planetary hopkins_sph anarchy_sph + sphenix_sph gizmo adding_your_own diff --git a/doc/RTD/source/HydroSchemes/sphenix_sph.rst b/doc/RTD/source/HydroSchemes/sphenix_sph.rst new file mode 100644 index 0000000000000000000000000000000000000000..eff56e5da9547325c16f009608564b66c527cd26 --- /dev/null +++ b/doc/RTD/source/HydroSchemes/sphenix_sph.rst @@ -0,0 +1,80 @@ +.. SPHENIX SPH + Josh Borrow 8th January 2020 + +SPHENIX +======= + +This is the new scheme that will be used in EAGLE-XL. This scheme includes: + ++ Durier & Dalla Vecchia (2012) time-step limiter ++ Density-Energy SPH ++ Thermal diffusion following Price (2012) ++ A simplified version of the 'Inviscid SPH' artificial viscosity + (Cullen & Dehnen 2010), with a Balsara switch ++ A diffusion limiter, used to prevent energy leakage out of EAGLE + supernovae (Borrow+ 2020). + + +The simplified version of the 'Inviscid SPH' artificial viscosity calculates +the time differential of the velocity divergence explicitly, using the value +from the previous step. We also use the Balsara switch instead of the improved +neighbour-based limiter from Cullen & Dehnen 2010, to avoid matrix +calculations. + + +To configure with this scheme, use + +.. code-block:: bash + + ./configure --with-hydro=sphenix --with-kernel=quintic-spline --disable-hand-vec + + +The diffusion limiter is implemented to ensure that the diffusion is turned +off in very viscous flows and works as follows: + +.. code-block:: C + + float new_diffusion_alpha = old_diffusion_alpha; + + const float viscous_diffusion_limit = + diffusion_alpha_max * + (1.f - maximum_alpha_visc_over_ngb / viscosity_alpha_max); + + new_diffusion_alpha = min(new_diffusion_alpha, viscous_diffusion_limit); + + +The parameters available for this scheme, and their defaults, are: + +.. code-block:: yaml + + SPH: + viscosity_alpha: 0.1 # Initial value for the alpha viscosity + viscosity_length: 0.25 # Viscosity decay length (in terms of sound-crossing time) + # These are enforced each time-step + viscosity_alpha_max: 2.0 # Maximal allowed value for the viscosity alpha + viscosity_alpha_min: 0.0 # Minimal allowed value for the viscosity alpha + + diffusion_alpha: 0.0 # Initial value for the diffusion alpha + diffusion_beta: 0.25 # Timescale to raise the diffusion coefficient over + # (decay is on the sound-crossing time) + # These are enforced each time-step + diffusion_alpha_max: 1.0 + diffusion_alpha_min: 0.0 + + +There is also a compile-time parameter, ``viscosity_beta`` that we set to +3.0. During feedback events, the viscosity is set to the compile-time +``hydro_props_default_viscosity_alpha_feedback_reset = 2.0`` and the +diffusion is set to ``hydro_props_default_diffusion_alpha_feedback_reset = +0.0``. These can be changed in ``src/hydro/SPHENIX/hydro_parameters.h``. + +Pressure Floor +~~~~~~~~~~~~~~ + +The pressure floor is implemented for this scheme. The +pressure floor is used in the sound-speed and hence the +time-step will be lower in this case than if the pressure +floor was not taken into account. The only other impact +of the pressure floor is in the force loop, where the +sub-grid floor pressure is used instead of the pressure +calculated from the internal energy and density. diff --git a/doc/RTD/source/Logger/index.rst b/doc/RTD/source/Logger/index.rst new file mode 100644 index 0000000000000000000000000000000000000000..c9d8f376af37342397d3009ed6a94beaa28dfaad --- /dev/null +++ b/doc/RTD/source/Logger/index.rst @@ -0,0 +1,16 @@ +Logger Output +============= + +The logger is a particle based output (e.g. snapshot) that takes into account the large difference of timescale. +If you have any question, a slack channel is available for it in SWIFT's slack. + +To run it, you will need to use the configuration option ``--enable-logger``. +Currently the logger is implemented only for Gadget2 and the default gravity / stars, but can be easily extended to the other schemes by adding the logger structure to the particles (see ``src/hydro/Gadget2/hydro_part.h``). +The main parameters of the logger are ``Logger:delta_step`` and ``Logger:index_mem_frac`` that define the time accuracy of the logger and the number of index files. +The first parameter defines the number of active steps that a particle is doing before writing and the second defines the total storage size of the index files as function of the dump file. + +Unfortunately, the API is not really developed yet. Therefore if you wish to dump another field, you will need to trick the logger by replacing a field in the ``logger_log_part`` function. + +For reading, the python wrapper is available through the configuration option ``--with-python``. Once compiled, you will be able to use the file ``logger/examples/reader_example.py``. +The first argument is the basename of the index file and the second one is the time requested. +During the first reading, the library is manipulating the dump file and therefore it should not be killed and may take a bit more time than usual. diff --git a/doc/RTD/source/ParameterFiles/output_selection.rst b/doc/RTD/source/ParameterFiles/output_selection.rst index 728079023b937d699819e595d18b5a233773c29b..3ec69485d175e9c295e9883125e920e687c66453 100644 --- a/doc/RTD/source/ParameterFiles/output_selection.rst +++ b/doc/RTD/source/ParameterFiles/output_selection.rst @@ -38,7 +38,12 @@ Example of file with redshift:: If an output list is specified, the basic values for the first snapshot (``time_first``, ``scale_factor_first``) and difference (``delta_time``) are ignored. - + +When an output list is used SWIFT will not write a "0th" snapshot +straight after having read the ICs. Similarly, SWIFT will also *not* +write a snapshot at the end of a simulation unless a snapshot at the +final time is specified in the list. + .. _Output_selection_label: Output Selection diff --git a/doc/RTD/source/ParameterFiles/parameter_description.rst b/doc/RTD/source/ParameterFiles/parameter_description.rst index dcc829fe2a40c08d394e0222834b6dc40b4819a1..726631b7e0de1e2ed134fbba456f0a7f3288ea38 100644 --- a/doc/RTD/source/ParameterFiles/parameter_description.rst +++ b/doc/RTD/source/ParameterFiles/parameter_description.rst @@ -222,8 +222,12 @@ The accuracy of the gravity calculation is governed by the following two paramet * The time-step size pre-factor :math:`\eta`: ``eta``, The time-step of a given particle is given by :math:`\Delta t = -\sqrt{\frac{2\eta\epsilon}{|\overrightarrow{a}|}}`, where -:math:`\overrightarrow{a}` is the particle's acceleration. `Power et al. (2003) <http://adsabs.harvard.edu/abs/2003MNRAS.338...14P>`_ recommend using :math:`\eta=0.025`. +\sqrt{2\eta\epsilon_i/|\overrightarrow{a}_i|}`, where +:math:`\overrightarrow{a}_i` is the particle's acceleration and +:math:`\epsilon_i` its (spline) softening length. `Power et al. (2003) +<http://adsabs.harvard.edu/abs/2003MNRAS.338...14P>`_ recommend using +:math:`\eta=0.025`. + The last tree-related parameter is * The tree rebuild frequency: ``rebuild_frequency``. @@ -233,7 +237,7 @@ The tree rebuild frequency is an optional parameter defaulting to 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: +Particle-Mesh part of the calculation. The last five 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 @@ -244,9 +248,17 @@ Particle-Mesh part of the calculation. The last three are optional: * The scale below 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``), +* Whether or not to dither the particles randomly at each tree rebuild: + ``dithering`` (default: ``1``), +* The magnitude of each component of the dithering vector to use in units of the + top-level cell sizes: ``dithering_ratio`` (default: ``1.0``). For most runs, the default values can be used. Only the number of cells along -each axis needs to be specified. The remaining three values are best described +each axis needs to be specified. The mesh dithering is only used for simulations +using periodic boundary conditions and in the absence of an external potential. +At each tree rebuild time, all the particles are moved by a random vector (the +same for all particles) and the periodic BCs are then applied. This reduces the +correlation of erros across time. 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` @@ -257,17 +269,18 @@ simulation: # Parameters for the self-gravity scheme for the EAGLE-100 box Gravity: eta: 0.025 - theta: 0.7 + theta: 0.6 mesh_side_length: 512 comoving_DM_softening: 0.0026994 # 0.7 proper kpc at z=2.8. max_physical_DM_softening: 0.0007 # 0.7 proper kpc comoving_baryon_softening: 0.0026994 # 0.7 proper kpc at z=2.8. max_physical_baryon_softening: 0.0007 # 0.7 proper kpc rebuild_frequency: 0.01 # Default optional value - a_smooth: 1.25 # Default optional value - r_cut_max: 4.5 # Default optional value - r_cut_min: 0.1 # Default optional value - + a_smooth: 1.25 # Default optional value + r_cut_max: 4.5 # Default optional value + r_cut_min: 0.1 # Default optional value + dithering: 1 # Default optional value + dithering_ratio: 1.0 # Default optional value .. _Parameters_SPH: @@ -360,6 +373,15 @@ prevent the smoothing length from going below this value in dense environments. This will lead to smoothing over more particles than specified by :math:`\eta`. +The optional parameter ``particle_splitting`` (Default: 0) activates the +splitting of overly massive particles into 2. By switching this on, the code +will loop over all the particles at every tree rebuild and split the particles +with a mass above a fixed threshold into two copies that are slightly shifted +(by a randomly orientated vector of norm :math:`0.2h`). Their masses and other +relevant particle-carried quantities are then halved. The mass threshold for +splitting is set by the parameter ``particle_splitting_mass_threshold`` which is +specified using the internal unit system. + The final set of parameters in this section determine the initial and minimum temperatures of the particles. @@ -386,14 +408,17 @@ The full section to start a typical cosmological run would be: .. code:: YAML SPH: - resolution_eta: 1.2 - CFL_condition: 0.1 - h_tolerance: 1e-4 - h_min_ratio: 0.1 - initial_temperature: 273 - minimal_temperature: 100 - H_mass_fraction: 0.755 - H_ionization_temperature: 1e4 + resolution_eta: 1.2 + CFL_condition: 0.1 + h_tolerance: 1e-4 + h_min_ratio: 0.1 + h_max: 1. # U_L + initial_temperature: 273 # U_T + minimal_temperature: 100 # U_T + H_mass_fraction: 0.755 + H_ionization_temperature: 1e4 # U_T + particle_splitting: 1 + particle_splitting_mass_threshold: 5e-3 # U_M .. _Parameters_Stars: @@ -618,6 +643,15 @@ the case of non-cosmological runs, the time of the first snapshot is expressed in the internal units of time. Users also have to provide the difference in time (or scale-factor) between consecutive outputs: +* Directory in which to write snapshots: ``subdir``. + (default: empty string). + +If this is set then the full path to the snapshot files will be generated by +taking this value and appending a slash and then the snapshot file name +described above - e.g. ``subdir/base_name_1234.hdf5``. The directory is +created if necessary. Any VELOCIraptor output produced by the run is also written +to this directory. + * Time difference between consecutive outputs: ``delta_time``. In non-cosmological runs this is also expressed in internal units. For @@ -1180,13 +1214,28 @@ scale-factor of the next call. This implies that the outputs are equally spaced in :math:`\log(a)` (See :ref:`Output_list_label` to have calls not regularly spaced in time). +Since VELOCIraptor produces many small output files when running with MPI, +it can be useful to make a separate directory for each output time: + +* Base name of directory created for each VELOCIraptor output: ``subdir_per_output`` + (default: empty string). + +If this is set then a new directory is created each time VELOCIraptor is run. +The directory name will be subdir_per_output followed by the same output number +used in the filenames. Note that this directory is relative to the ``subdir`` parameter +from the Snapshots section if that is set. + +By default this is an empty string, which means that all VELOCIraptor outputs will +be written to a single directory. + Showing all the parameters for a basic cosmologica test-case, one would have: .. code:: YAML StructureFinding: config_file_name: my_stf_configuration_file.cfg # See the VELOCIraptor manual for the content of this file. - basename: ./haloes/ # Write the catalogs in this sub-directory + basename: haloes # Base name for VELOCIraptor output files + subdir_per_output: stf # Make a stf_XXXX subdirectory for each output scale_factor_first: 0.1 # Scale-factor of the first output delta_time: 1.1 # Delta log-a between outputs diff --git a/doc/RTD/source/Snapshots/index.rst b/doc/RTD/source/Snapshots/index.rst index fa11058edfa202b548936dac3ca55ada86eb9e84..a7f2bf50fc2355770ac78458a4bf102e2ac8dee0 100644 --- a/doc/RTD/source/Snapshots/index.rst +++ b/doc/RTD/source/Snapshots/index.rst @@ -215,17 +215,21 @@ triplet of floating-point numbers) is given by the attribute simulation volumes the cells themselves can have different sizes along each axis. -The ``/Cells/Centres`` array gives the centre of each of the top-level cells in the -simulation volume. Both the cell sizes and positions of the centres are +The ``/Cells/Centres`` array gives the centre of each of the top-level cells in +the simulation volume. Both the cell sizes and positions of the centres are expressed in the unit system used for the snapshots (see above) and are hence -consistent with the particle positions themselves. +consistent with the particle positions themselves. Once the cell(s) containing the region of interest has been located, users can use the ``/Cells/Offsets/PartTypeN/Counts`` and ``/Cells/Offsets/PartTypeN/Offsets`` to retrieve the location of the particles -of type ``N`` in the ``/PartTypeN`` arrays. For instance, if one is interested -in retriving all the densities of the gas particles in the cell around the -position `[1, 1, 1]` one could use a piece of code similar to: +of type ``N`` in the ``/PartTypeN`` arrays. The cells, offsets and counts are +sorted spatiall using C-style ordering. That is we first loop over the z axis +then y axis and x is the slowest varying dimension. + +As an example, if one is interested in retriving all the densities of the gas +particles in the cell around the position `[1, 1, 1]` one could use a piece of +code similar to: .. code-block:: python :linenos: @@ -243,7 +247,10 @@ position `[1, 1, 1]` one could use a piece of code similar to: size = f["/Cells/Meta-data"].attrs["size"] half_size = size / 2. - # Look for the cell containing the position of interest + # Look for the cell containing the position of interest. + # + # Note that since the cells are sorted spatially, we would formally + # not need to do this search and could jump directly to the correct 'i'. my_cell = -1 for i in range(nr_cells): if my_pos[0] > centres[i, 0] - half_size[0] and my_pos[0] < centres[i, 0] + half_size[0] and diff --git a/doc/RTD/source/SubgridModels/EAGLE/index.rst b/doc/RTD/source/SubgridModels/EAGLE/index.rst index b87eff98ecd2c836095438586c6c5e00b5f8826b..3cbfbaccd9cea682bde42f7b615894d023be1075 100644 --- a/doc/RTD/source/SubgridModels/EAGLE/index.rst +++ b/doc/RTD/source/SubgridModels/EAGLE/index.rst @@ -144,56 +144,56 @@ inherits all the chemical tracers of its parent gas particle. In the snapshots, we output for each gas and star particle: -+----------------------------------+-------------------------------------+-----------+-----------------------------+ -| Name | Description | Units | Comments | -+==================================+=====================================+===========+=============================+ -| ``ElementAbundance`` | | Fraction of the gas/star mass | [-] | | Array of length | -| | | in the different elements | | | 9 for each particle | -+----------------------------------+-------------------------------------+-----------+-----------------------------+ -| ``SmoothedElementAbundance`` | | Fraction of the gas/star mass | [-] | | Array of length | -| | | in the different elements | | | 9 for each particle | -| | | smoothed over SPH neighbours | | | -+----------------------------------+-------------------------------------+-----------+-----------------------------+ -| ``Metallicity`` | | Fraction of the gas/star mass | [-] | | -| | | in *all* metals | | | -+----------------------------------+-------------------------------------+-----------+-----------------------------+ -| ``SmoothedMetallicity`` | | Fraction of the gas/star mass | [-] | | -| | | in *all* metals | | | -| | | smoothed over SPH neighbours | | | -+----------------------------------+-------------------------------------+-----------+-----------------------------+ -| ``TotalMassFromSNIa`` | | Total mass of the gas/star | [U_M] | | -| | | that was produced by enrichment | | | -| | | from SNIa stars | | | -+----------------------------------+-------------------------------------+-----------+-----------------------------+ -| ``MetalMassFracFromSNIa`` | | Fraction of the *total* gas/star | [-] | | -| | | mass that is in metals produced | | | -| | | by enrichment from SNIa stars | | | -+----------------------------------+-------------------------------------+-----------+-----------------------------+ -| ``TotalMassFromAGB`` | | Total mass of the gas/star | [U_M] | | -| | | that was produced by enrichment | | | -| | | from AGB stars | | | -+----------------------------------+-------------------------------------+-----------+-----------------------------+ -| ``MetalMassFracFromAGB`` | | Fraction of the *total* gas/star | [-] | | -| | | mass that is in metals produced | | | -| | | by enrichment from AGB star | | | -+----------------------------------+-------------------------------------+-----------+-----------------------------+ -| ``TotalMassFromSNII`` | | Total mass of the gas/star | [U_M] | | -| | | that was produced by enrichment | | | -| | | from SNII stars | | | -+----------------------------------+-------------------------------------+-----------+-----------------------------+ -| ``MetalMassFracFromSNII`` | | Fraction of the gas/star mass | [-] | | -| | | that is in metals produced by | | | -| | | enrichment from SNII stars | | | -+----------------------------------+-------------------------------------+-----------+-----------------------------+ -| ``IronMassFracFromSNIa`` | | Fraction of the *total* gas/star | [-] | | -| | | mass in *iron* produced produced | | | -| | | by enrichment from SNIa stars | | | -+----------------------------------+-------------------------------------+-----------+-----------------------------+ -| ``SmoothedIronMassFracFromSNIa`` | | Fraction of the *total* gas/star | [-] | | -| | | mass in *iron* produced produced | | | -| | | by enrichment from SNIa stars | | | -| | | smoothed over SPH neighbours | | | -+----------------------------------+-------------------------------------+-----------+-----------------------------+ ++---------------------------------------+-------------------------------------+-----------+-----------------------------+ +| Name | Description | Units | Comments | ++=======================================+=====================================+===========+=============================+ +| ``ElementMassFractions`` | | Fraction of the gas/star mass | [-] | | Array of length | +| | | in the different elements | | | 9 for each particle | ++---------------------------------------+-------------------------------------+-----------+-----------------------------+ +| ``SmoothedElementMassFractions`` | | Fraction of the gas/star mass | [-] | | Array of length | +| | | in the different elements | | | 9 for each particle | +| | | smoothed over SPH neighbours | | | ++---------------------------------------+-------------------------------------+-----------+-----------------------------+ +| ``MetalMassFractions`` | | Fraction of the gas/star mass | [-] | | +| | | in *all* metals | | | ++---------------------------------------+-------------------------------------+-----------+-----------------------------+ +| ``SmoothedMetalMassFractions`` | | Fraction of the gas/star mass | [-] | | +| | | in *all* metals | | | +| | | smoothed over SPH neighbours | | | ++---------------------------------------+-------------------------------------+-----------+-----------------------------+ +| ``MassesFromSNIa`` | | Total mass of the gas/star | [U_M] | | +| | | that was produced by enrichment | | | +| | | from SNIa stars | | | ++---------------------------------------+-------------------------------------+-----------+-----------------------------+ +| ``MetalMassFractionsFromSNIa`` | | Fraction of the *total* gas/star | [-] | | +| | | mass that is in metals produced | | | +| | | by enrichment from SNIa stars | | | ++---------------------------------------+-------------------------------------+-----------+-----------------------------+ +| ``MassesFromAGB`` | | Total mass of the gas/star | [U_M] | | +| | | that was produced by enrichment | | | +| | | from AGB stars | | | ++---------------------------------------+-------------------------------------+-----------+-----------------------------+ +| ``MetalMassFractionsFromAGB`` | | Fraction of the *total* gas/star | [-] | | +| | | mass that is in metals produced | | | +| | | by enrichment from AGB star | | | ++---------------------------------------+-------------------------------------+-----------+-----------------------------+ +| ``MassesFromSNII`` | | Total mass of the gas/star | [U_M] | | +| | | that was produced by enrichment | | | +| | | from SNII stars | | | ++---------------------------------------+-------------------------------------+-----------+-----------------------------+ +| ``MetalMassFractionsFromSNII`` | | Fraction of the gas/star mass | [-] | | +| | | that is in metals produced by | | | +| | | enrichment from SNII stars | | | ++---------------------------------------+-------------------------------------+-----------+-----------------------------+ +| ``IronMassFractionsFromSNIa`` | | Fraction of the *total* gas/star | [-] | | +| | | mass in *iron* produced produced | | | +| | | by enrichment from SNIa stars | | | ++---------------------------------------+-------------------------------------+-----------+-----------------------------+ +| ``SmoothedIronMassFractionsFromSNIa`` | | Fraction of the *total* gas/star | [-] | | +| | | mass in *iron* produced produced | | | +| | | by enrichment from SNIa stars | | | +| | | smoothed over SPH neighbours | | | ++---------------------------------------+-------------------------------------+-----------+-----------------------------+ The stars will lose mass over their lifetime (up to ~45%). The fractions will remain unchanged but if one is interested in computing an absolute metal mass @@ -350,7 +350,7 @@ they are listed for every gas particle: +---------------------+-------------------------------------+-----------+-------------------------------------+ | Name | Description | Units | Comments | +=====================+=====================================+===========+=====================================+ -| ``Temperature`` | | Temperature of the gas as | [U_T] | | The calculation is performed | +| ``Temperatures`` | | Temperature of the gas as | [U_T] | | The calculation is performed | | | | computed from the tables. | | | using quantities at the last | | | | | | time-step the particle was active | +---------------------+-------------------------------------+-----------+-------------------------------------+ @@ -404,12 +404,12 @@ the snapshots for each gas and star particle: +----------------------------------------+---------------------------------------+-----------+-----------------------------+ | Name | Description | Units | Comments | +========================================+=======================================+===========+=============================+ -| | ``Maximal Temperature`` | | Mximal temperature reached by | | [U_T] | | +| | ``MaximalTemperatures`` | | Mximal temperature reached by | | [U_T] | | | | | this particle. | | | +----------------------------------------+---------------------------------------+-----------+-----------------------------+ -| | ``Maximal Temperature scale-factor`` | | Scale-factor (cosmological runs) | | [-] | | +| | ``MaximalTemperaturesScaleFactors`` | | Scale-factor (cosmological runs) | | [-] | | | | OR | | or time (non-cosmological runs) at | | OR | | -| | ``Maximal Temperature time`` | | which the maximum value was reached.| | [U_t] | | +| | ``MaximalTemperaturesTimes`` | | which the maximum value was reached.| | [U_t] | | +----------------------------------------+---------------------------------------+-----------+-----------------------------+ @@ -424,14 +424,14 @@ metal-dependent star-formation density threshold following the relation derived by `Schaye (2004) <http://adsabs.harvard.edu/abs/2004ApJ...609..667S>`_. Above a density threshold :math:`n^*_{\rm H}`, expressed in number of Hydrogen atoms per (physical) cubic centimeters, the star formation rate is expressed as a -pressure-law :math:`\dot{m}_* = m_g \times A \times \left( 1 {\rm -M_\odot}~{\rm pc^2} \right)^{-n} \times \left(\frac{\gamma}{G_{\rm -N}}f_gP\right)^{(n-1)/2}`, where :math:`n` is the exponent of the -Kennicutt-Schmidt relation (typically :math:`n=1.4`) and :math:`A` is the -normalisation of the law (typically :math:`A=1.515\times10^{-4} {\rm -M_\odot}~{\rm yr^{-1}}~{\rm kpc^{-2}}`). :math:`m_g` is the gas particle mass, -:math:`\gamma` is the adiabatic index, :math:`f_g` the gas fraction of the disk -and :math:`P` the total pressure of the gas including any subgrid turbulent terms. +pressure-law :math:`\dot{m}_* = m_g \times A \times \left( 1 {\rm M_\odot}~{\rm +pc^2} \right)^{-n} \times \left(\frac{\gamma}{G_{\rm N}}f_gP\right)^{(n-1)/2}`, +where :math:`n` is the exponent of the Kennicutt-Schmidt relation (typically +:math:`n=1.4`) and :math:`A` is the normalisation of the law (typically +:math:`A=1.515\times10^{-4} {\rm M_\odot}~{\rm yr^{-1}}~{\rm kpc^{-2}}` for a +Cabrier IMF). :math:`m_g` is the gas particle mass, :math:`\gamma` is the +adiabatic index, :math:`f_g` the gas fraction of the disk and :math:`P` the +total pressure of the gas including any subgrid turbulent terms. Once a gas particle has computed its star formation rate, we compute the probability that this particle turns into a star using :math:`Prob= @@ -463,14 +463,15 @@ the figure below. does *not* enter the model at all). The values used to produce this figure are the ones assumed in the reference EAGLE model. -In the EAGLE model, the pressure entering the star formation includes pressure -from the unresolved turbulence. This is modeled in the form of a polytropic -equation of state for the gas :math:`P = P_{\rm -norm}\left(\frac{\rho}{\rho_0}\right)^{\gamma_{\rm eff}}`. For practical reasons, -this relation is expressed in term of densities. Note that unlike the entropy -floor, this is applied at *all* densities and not only above a certain -threshold. This equation of state with the relevant YAML parameters defining it -is shown on the figure below. +In the `Schaye & Dalla Vecchia (2008) +<http://adsabs.harvard.edu/abs/2008MNRAS.383.1210S>`_ model, the pressure +entering the star formation includes pressure from the unresolved +turbulence. This is modeled in the form of a polytropic equation of state for +the gas :math:`P_{EoS} = P_{\rm norm}\left(\frac{\rho}{\rho_0}\right)^{\gamma_{\rm +eff}}`. For practical reasons, this relation is expressed in term of +densities. Note that unlike the entropy floor, this is applied at *all* +densities and not only above a certain threshold. This equation of state with +the relevant YAML parameters defining it is shown on the figure below. .. figure:: EAGLE_SF_EOS.svg :width: 400px @@ -488,17 +489,32 @@ is shown on the figure below. star formation rate. The values used to produce this figure are the ones assumed in the reference EAGLE model. +In EAGLE, an entropy floor is already in use, so that the pressure of the gas is +mentained high enough to prvent fragmentation of the gas. In such a scenario, +there is no need for the internal EoS described above. And, of course, in such a +scenario, the gas can have a pressure above the floor. The code hence uses +:math:`P = \max(P_{\rm gas}, P_{\rm floor}, P_{\rm EoS})`. + To prevent star formation in non-collapsed objects (for instance at high redshift when the whole Universe has a density above the threshold), we apply an over-density criterion. Only gas with a density larger than a multiple of the critical density for closure can form stars. +Finally, to prevent gas much above the entropy floor (that has, for instance, +been affected by feedback) from forming stars, an optional entropy margin can be +specified. Only gas with an entropy :math:`A` such that :math:`A_{\rm EoS} \leq A < +A_{\rm EoS} \times 10^\Delta`, with :math:`\Delta` specified in the parameter +file. This defaults to a very large number, essentially removing the limit. In +simulations with an entropy floor, the limit is calculated above +:math:`\max(A_{\rm floor}, A_{EoS})`, to be consistent with the pressure used in +the star formation law. + Additionally to the pressure-law corresponding to the Kennicutt-Schmidt relation described, above, we implement a second density threshold above which the slope of the relationship varies (typically steepens). This is governed by two additional parameters: the density at which the relation changes and the second slope. Finally, we optionally use a maximal density above which any gas particle -automatically gets a probability to form a star of 100%. +automatically gets a probability to form a star of 100%. The code applying this star formation law is located in the directory ``src/star_formation/EAGLE/``. To simplify things, all constants are converted @@ -513,12 +529,12 @@ For a normal EAGLE run, that section of the parameter file reads: EOS_density_norm_H_p_cm3: 0.1 # Physical density used for the normalisation of the EOS assumed for the star-forming gas in Hydrogen atoms per cm^3. EOS_temperature_norm_K: 8000 # Temperature om the polytropic EOS assumed for star-forming gas at the density normalisation in Kelvin. EOS_gamma_effective: 1.3333333 # Slope the of the polytropic EOS assumed for the star-forming gas. - KS_normalisation: 1.515e-4 # The normalization of the Kennicutt-Schmidt law in Msun / kpc^2 / yr. - KS_exponent: 1.4 # The exponent of the Kennicutt-Schmidt law. - min_over_density: 57.7 # The over-density above which star-formation is allowed. + KS_normalisation: 1.515e-4 # Normalization of the Kennicutt-Schmidt law in Msun / kpc^2 / yr. + KS_exponent: 1.4 # Exponent of the Kennicutt-Schmidt law. + min_over_density: 57.7 # Over-density above which star-formation is allowed. KS_high_density_threshold_H_p_cm3: 1e3 # Hydrogen number density above which the Kennicut-Schmidt law changes slope in Hydrogen atoms per cm^3. KS_high_density_exponent: 2.0 # Slope of the Kennicut-Schmidt law above the high-density threshold. - EOS_temperature_margin_dex: 0.5 # (Optional) Logarithm base 10 of the maximal temperature difference above the EOS allowed to form stars. + EOS_entropy_margin_dex: 0.5 # (Optional) Logarithm base 10 of the maximal entropy above the EOS at which stars can form. KS_max_density_threshold_H_p_cm3: 1e5 # (Optional) Hydrogen number density above which a particle gets automatically turned into a star in Hydrogen atoms per cm^3. threshold_norm_H_p_cm3: 0.1 # Normalisation of the metal-dependant density threshold for star formation in Hydrogen atoms per cm^3. threshold_Z0: 0.002 # Reference metallicity (metal mass fraction) for the metal-dependant threshold for star formation. @@ -531,6 +547,89 @@ For a normal EAGLE run, that section of the parameter file reads: Stellar enrichment: Wiersma+2009b ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +The enrichment is governed by three "master" parameters in the +``EAGLEFeedback`` section of the parameter file. Each individual channel +can be switched on or off individually: + +.. code:: YAML + + # EAGLE stellar enrichment master modes + EAGLEFeedback: + use_AGB_enrichment: 1 # Global switch for enrichement from AGB stars. + use_SNII_enrichment: 1 # Global switch for enrichement from SNII stars. + use_SNIa_enrichment: 1 # Global switch for enrichement from SNIa stars. + +Setting one of these switches to 0 will cancel the mass transfer, metal +mass transfer and energy transfer (AGB only) from the stars. + +The lifetime and yield tables are provided to the code via pre-computed +tables whose location is given by the ``filename`` parameter. + +Choice of IMF properies +----------------------- + +Enrichment from SNII & AGB stars +-------------------------------- + +Enrichment from SNIa stars +-------------------------- + +The enrichment from SNIa is done over the lifetime of the stars and uses a +delay time distribution (DTD) to parametrize the number of SNIa events for +a star of a given age. Two functional forms are available: an exponentially +decaying function and a power-law with a slope of -1. The parameter +``SNIa_DTD`` can hence take the two values: ``PowerLaw`` or +``Exponential``. + +In the case of an exponential DTD, two parameters must be defined, the +normalisation (``SNIa_DTD_exp_norm_p_Msun``) and the time-scale +(``SNIa_DTD_exp_timescale_Gyr``). The original EAGLE model is reproduced by +setting the parameters to :math:`0.002` and :math:`2.0` respectively. + +In the case of a power-law DTD, only a normalisation needs to be provided +via the parameter (``SNIa_DTD_power_law_norm_p_Msun``). The examples in the +repository use a value of :math:`0.0012` for this. + +Additionally, the age above which SNIa stars start to go off has to be +provided. Below that age, there are no explosions; above that age, the DTD +is used to determine the number of supernovae exploding in a given +time-step. This is controlled by the parameter ``SNIa_DTD_delay_Gyr`` which +sets the minimal age of SNIa in giga-years. A value of :math:`0.04~\rm{Gyr} += 40~\rm{Myr}` is used in all the examples. This corresponds +approximatively to the lifetime of stars of mass :math:`8~\rm{M}_\odot`. + +Finally, the energy injected by a single SNIa explosion has to be provided +via the parameter ``SNIa_energy_erg``. The canonical value of +:math:`10^{51}~\rm{erg}` is used in all the examples. + +The SNIa section of the YAML file for an original EAGLE run looks like: + +.. code:: YAML + + # EAGLE-Ref SNIa enrichment and feedback options + EAGLEFeedback: + use_SNIa_feedback: 1 + use_SNIa_enrichment: 1 + SNIa_DTD: Exponential + SNIa_DTD_exp_norm_p_Msun: 0.002 + SNIa_DTD_exp_timescale_Gyr: 2.0 + SNIa_DTD_delay_Gyr: 0.04 + SNIa_energy_erg: 1.0e51 + +whilst for the more recent runs we use: + +.. code:: YAML + + # EAGLE-Ref SNIa enrichment and feedback options + EAGLEFeedback: + use_SNIa_feedback: 1 + use_SNIa_enrichment: 1 + SNIa_DTD: PowerLaw + SNIa_DTD_power_law_norm_p_Msun: 0.0012 + SNIa_DTD_delay_Gyr: 0.04 + SNIa_energy_erg: 1.0e51 + + .. _EAGLE_feedback: Supernova feedback: Dalla Vecchia+2012 & Schaye+2015 @@ -548,9 +647,10 @@ Supernova feedback: Dalla Vecchia+2012 & Schaye+2015 filename: ./yieldtables/ # Path to the directory containing the EAGLE yield tables. IMF_min_mass_Msun: 0.1 # Minimal stellar mass considered for the Chabrier IMF in solar masses. IMF_max_mass_Msun: 100.0 # Maximal stellar mass considered for the Chabrier IMF in solar masses. - SNII_min_mass_Msun: 6.0 # Minimal mass considered for SNII feedback (not SNII enrichment!) in solar masses. - SNII_max_mass_Msun: 100.0 # Maximal mass considered for SNII feedback (not SNII enrichment!) in solar masses. - SNII_wind_delay_Gyr: 0.03 # Time in Gyr between a star's birth and the SNII thermal feedback event. + SNII_min_mass_Msun: 8.0 # Minimal mass considered for SNII stars in solar masses. + SNII_max_mass_Msun: 100.0 # Maximal mass considered for SNII stars in solar masses. + SNII_sampled_delay: 1 # Sample the SNII lifetimes to do feedback. + SNII_wind_delay_Gyr: 0.03 # Time in Gyr between a star's birth and the SNII thermal feedback event when not sampling. SNII_delta_T_K: 3.16228e7 # Change in temperature to apply to the gas particle in a SNII thermal feedback event in Kelvin. SNII_energy_erg: 1.0e51 # Energy of one SNII explosion in ergs. SNII_energy_fraction_min: 0.3 # Maximal fraction of energy applied in a SNII feedback event. @@ -559,18 +659,22 @@ Supernova feedback: Dalla Vecchia+2012 & Schaye+2015 SNII_energy_fraction_n_0_H_p_cm3: 1.4588 # Pivot point for the birth density dependance of the SNII energy fraction in cm^-3. SNII_energy_fraction_n_Z: 0.8686 # Power-law for the metallicity dependance of the SNII energy fraction. SNII_energy_fraction_n_n: 0.8686 # Power-law for the birth density dependance of the SNII energy fraction. - SNIa_max_mass_Msun: 8.0 # Maximal mass considered for SNIa feedback and enrichment in solar masses. - SNIa_timescale_Gyr: 2.0 # Time-scale of the exponential decay of the SNIa rates in Gyr. - SNIa_efficiency_p_Msun: 0.002 # Normalisation of the SNIa rates in inverse solar masses. + SNIa_DTD: PowerLaw # Functional form of the SNIa delay time distribution Two choices: 'PowerLaw' or 'Exponential'. + SNIa_DTD_delay_Gyr: 0.04 # Stellar age after which SNIa start in Gyr (40 Myr corresponds to stars ~ 8 Msun). + SNIa_DTD_power_law_norm_p_Msun: 0.0012 # Normalization of the SNIa delay time distribution in the power-law DTD case (in Msun^-1). + SNIa_DTD_exp_norm_p_Msun: 0.002 # Normalization of the SNIa delay time distribution in the exponential DTD case (in Msun^-1). + SNIa_DTD_exp_timescale_Gyr: 2.0 # Time-scale of the SNIa delay time distribution in the exponential DTD case (in Gyr). SNIa_energy_erg: 1.0e51 # Energy of one SNIa explosion in ergs. AGB_ejecta_velocity_km_p_s: 10.0 # Velocity of the AGB ejectas in km/s. + stellar_evolution_age_cut_Gyr: 0.1 # Stellar age in Gyr above which the enrichment is down-sampled. + stellar_evolution_sampling_rate: 10 # Number of time-steps in-between two enrichment events for a star above the age threshold. SNII_yield_factor_Hydrogen: 1.0 # (Optional) Correction factor to apply to the Hydrogen yield from the SNII channel. SNII_yield_factor_Helium: 1.0 # (Optional) Correction factor to apply to the Helium yield from the SNII channel. SNII_yield_factor_Carbon: 0.5 # (Optional) Correction factor to apply to the Carbon yield from the SNII channel. SNII_yield_factor_Nitrogen: 1.0 # (Optional) Correction factor to apply to the Nitrogen yield from the SNII channel. SNII_yield_factor_Oxygen: 1.0 # (Optional) Correction factor to apply to the Oxygen yield from the SNII channel. SNII_yield_factor_Neon: 1.0 # (Optional) Correction factor to apply to the Neon yield from the SNII channel. - SNII_yield_factor_Magnesium: 2.0 # (Optional) Correction factor to apply to the Magnesium yield from the SNII channel. + SNII_yield_factor_Magnesium: 4.0 # (Optional) Correction factor to apply to the Magnesium yield from the SNII channel. SNII_yield_factor_Silicon: 1.0 # (Optional) Correction factor to apply to the Silicon yield from the SNII channel. SNII_yield_factor_Iron: 0.5 # (Optional) Correction factor to apply to the Iron yield from the SNII channel. @@ -578,6 +682,12 @@ Note that the value of ``SNII_energy_fraction_n_0_H_p_cm3`` given here is different from the value (:math:`0.67`) reported in table 3 of `Schaye (2015) <http://adsabs.harvard.edu/abs/2015MNRAS.446..521S>`_ , as a factor of :math:`h^{-2} = 0.6777^{-2} = 2.1773` is missing in the paper. + +The Magnesium yields from SNII have also been doubled since the +original EAGLE simulations were run and the minimal mass for SNII stars has +been raised to 8 solar masses (from 6). + + .. _EAGLE_black_hole_seeding: diff --git a/doc/RTD/source/SubgridModels/GEAR/index.rst b/doc/RTD/source/SubgridModels/GEAR/index.rst index 152056ef2eb60da189bf18b3b3c9909f88ace6de..4766ce5d104f6264aad3b18151480f798abbf905 100644 --- a/doc/RTD/source/SubgridModels/GEAR/index.rst +++ b/doc/RTD/source/SubgridModels/GEAR/index.rst @@ -19,7 +19,7 @@ where :math:`\rho` is the density, :math:`\gamma` the adiabatic index, :math:`G` :math:`\sigma` the velocity dispersion. -This must be directly implemented into the hydro schemes, therefore only a subset of schemes (Gadget-2 and Pressure-Energy) are currently implemented. +This must be directly implemented into the hydro schemes, therefore only a subset of schemes (Gadget-2, SPHENIX and Pressure-Energy) have the floor available. In order to implement it, you need equation 12 in `Hopkins 2013 <https://arxiv.org/abs/1206.5006>`_: .. math:: @@ -37,8 +37,8 @@ Grackle is a chemistry and cooling library presented in `B. Smith et al. 2016 <h equilibrium, 6 species network (H, H\\( ^+ \\), e\\( ^- \\), He, He\\( ^+ \\) and He\\( ^{++} \\)), 9 species network (adds H\\(^-\\), H\\(_2\\) and H\\(_2^+\\)) and 12 species (adds D, D\\(^+\\) and HD). Following the same -order, the swift cooling options are ``grackle``, ``grackle1``, ``grackle2`` -and ``grackle3`` (the numbers correspond to the value of +order, the swift cooling options are ``grackle_0``, ``grackle_1``, ``grackle_2`` +and ``grackle_3`` (the numbers correspond to the value of ``primordial_chemistry`` in Grackle). It also includes some self-shielding methods and UV background. In order to use the Grackle cooling, you will need to provide an HDF5 table computed by Cloudy. @@ -46,8 +46,8 @@ 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``. +In order to compile SWIFT with Grackle, you need to provide the options ``with-chemistry=GEAR`` and ``with-grackle=$GRACKLE_ROOT`` +where ``$GRACKLE_ROOT`` is the root of the install directory (not the ``lib``). You will need a Grackle version later than 3.1. To compile it, run the following commands from the root directory of Grackle: diff --git a/doc/RTD/source/TimeStepping/index.rst b/doc/RTD/source/TimeStepping/index.rst new file mode 100644 index 0000000000000000000000000000000000000000..5d8d547374a89c9fa3f9b882e110984d54d339c8 --- /dev/null +++ b/doc/RTD/source/TimeStepping/index.rst @@ -0,0 +1,19 @@ +.. Details of the time-stepping scheme + Matthieu Schaller 9th November 2019 + +.. _time_stepping: + +Time integration details +======================== + +This section of the documentation includes information on the time +stepping and time integration used in SWIFT. + +.. toctree:: + :maxdepth: 2 + :caption: Contents: + + integer_time_line + timestep_limiter + timestep_synchronization + diff --git a/doc/RTD/source/TimeStepping/integer_time_line.rst b/doc/RTD/source/TimeStepping/integer_time_line.rst new file mode 100644 index 0000000000000000000000000000000000000000..7bf0f9579062df46444d8b18d5e7ace4b22a1982 --- /dev/null +++ b/doc/RTD/source/TimeStepping/integer_time_line.rst @@ -0,0 +1,7 @@ +.. Integer time-line + Matthieu Schaller 9th November 2019 + +.. _integer_time_line: + +Integer time-line & time-bins +============================= diff --git a/doc/RTD/source/TimeStepping/timestep_limiter.rst b/doc/RTD/source/TimeStepping/timestep_limiter.rst new file mode 100644 index 0000000000000000000000000000000000000000..74021a1c609362fe99c315be26c586dab74230c6 --- /dev/null +++ b/doc/RTD/source/TimeStepping/timestep_limiter.rst @@ -0,0 +1,7 @@ +.. Time-step limiter + Matthieu Schaller 9th November 2019 + +.. _time_step_limiter: + +Time-step limiter +================= diff --git a/doc/RTD/source/TimeStepping/timestep_synchronization.rst b/doc/RTD/source/TimeStepping/timestep_synchronization.rst new file mode 100644 index 0000000000000000000000000000000000000000..4360cc30747b28432ee8bff6060e0db2b4c8a53d --- /dev/null +++ b/doc/RTD/source/TimeStepping/timestep_synchronization.rst @@ -0,0 +1,7 @@ +.. Time-step synchronization + Matthieu Schaller 9th November 2019 + +.. _time_step_sync: + +Time-step synchronization +========================= diff --git a/doc/RTD/source/conf.py b/doc/RTD/source/conf.py index 30780800e7829caccb5c443c4bfd97649479b590..99e9f82d956da26160d4a81368a9c3b9f290fee8 100644 --- a/doc/RTD/source/conf.py +++ b/doc/RTD/source/conf.py @@ -19,13 +19,13 @@ # -- Project information ----------------------------------------------------- project = 'SWIFT: SPH With Inter-dependent Fine-grained Tasking' -copyright = '2018, SWIFT Collaboration' +copyright = '2019, SWIFT Collaboration' author = 'SWIFT Team' # The short X.Y version version = '0.8' # The full version, including alpha/beta/rc tags -release = '0.8.4' +release = '0.8.5' # -- General configuration --------------------------------------------------- diff --git a/doc/RTD/source/index.rst b/doc/RTD/source/index.rst index 154ad36f2e2281314dc12f33872fa24f7284de95..6bc07cdf3a666cbf08cb56742c4a6928e40e07d6 100644 --- a/doc/RTD/source/index.rst +++ b/doc/RTD/source/index.rst @@ -20,6 +20,7 @@ difference is the parameter file that will need to be adapted for SWIFT. InitialConditions/index Snapshots/index HydroSchemes/index + TimeStepping/index SubgridModels/index random FriendsOfFriends/index @@ -29,3 +30,4 @@ difference is the parameter file that will need to be adapted for SWIFT. Task/index VELOCIraptorInterface/index AnalysisTools/index + Logger/index diff --git a/doc/RTD/source/random.rst b/doc/RTD/source/random.rst index 24e4c0da676aae706be9c5f1ff333b88a78f6860..4ca7e0b5bf6b50fdd6eabee36622a874efb01dd2 100644 --- a/doc/RTD/source/random.rst +++ b/doc/RTD/source/random.rst @@ -29,6 +29,11 @@ argument called the type of random number which is basically the nth random number for the specified seed, which is added to the particle ID, thus providing a distinct state per random number type. +If the user wishes to run a simulation with a different set of random number, +an option during the configuration (``--with-random-seed=INT``) is available. +This option simply flip some bits in the initial number composed of the ID and the +current simulation time through the binary operator XOR. + Implementation ~~~~~~~~~~~~~~ diff --git a/examples/Cooling/ConstantCosmoTempEvolution/plot_thermal_history.py b/examples/Cooling/ConstantCosmoTempEvolution/plot_thermal_history.py index 1f9ae6557d1a55bd75d3440679ae42d653da3399..4d24529b4590601325105964c094fd2e834cd6c6 100644 --- a/examples/Cooling/ConstantCosmoTempEvolution/plot_thermal_history.py +++ b/examples/Cooling/ConstantCosmoTempEvolution/plot_thermal_history.py @@ -1,184 +1,208 @@ import matplotlib + matplotlib.use("Agg") import matplotlib.pyplot as plt -import h5py as h5 import swiftsimio import sys import glob import unyt import numpy as np +try: + plt.style.use("../../../tools/stylesheets/mnras.mplstyle") +except: + print("Can't find Matplotlib stylesheet.") + ## read command line arguments snapshot_name = sys.argv[1] -params = {'axes.labelsize': 10, -'axes.titlesize': 10, -'font.size': 9, -'legend.fontsize': 9, -'xtick.labelsize': 10, -'ytick.labelsize': 10, -'text.usetex': False, -'figure.figsize' : (4.15,3.15), -'figure.subplot.left' : 0.12, -'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 -} -plt.rcParams.update(params) - ################# Read in observational data -data_schaye = np.genfromtxt("./datasets/schaye_et_al_2000_thermal_history.dat",skip_header = 2) -data_walther = np.genfromtxt("./datasets/walther_et_al_2019_thermal_history.dat",skip_header = 2) +data_schaye = np.genfromtxt( + "./datasets/schaye_et_al_2000_thermal_history.dat", skip_header=2 +) +data_walther = np.genfromtxt( + "./datasets/walther_et_al_2019_thermal_history.dat", skip_header=2 +) data_schaye = data_schaye.T data_walther = data_walther.T schaye_z_lower_error = data_schaye[0] - data_schaye[1] schaye_z_upper_error = data_schaye[2] - data_schaye[0] -schaye_T_lower_error = np.log10(data_schaye[3]*1.0e4) - np.log10(data_schaye[4]*1.0e4) -schaye_T_upper_error = np.log10(data_schaye[5]*1.0e4) - np.log10(data_schaye[3]*1.0e4) -walther_T_lower_error = np.log10(data_walther[1]*1.0e4) - np.log10(data_walther[2]*1.0e4) -walther_T_upper_error = np.log10(data_walther[3]*1.0e4) - np.log10(data_walther[1]*1.0e4) + +schaye_T_lower_error = np.log10(data_schaye[3] * 1.0e4) - np.log10( + data_schaye[4] * 1.0e4 +) +schaye_T_upper_error = np.log10(data_schaye[5] * 1.0e4) - np.log10( + data_schaye[3] * 1.0e4 +) +walther_T_lower_error = np.log10(data_walther[1] * 1.0e4) - np.log10( + data_walther[2] * 1.0e4 +) +walther_T_upper_error = np.log10(data_walther[3] * 1.0e4) - np.log10( + data_walther[1] * 1.0e4 +) ############### Read in simulation data +density_units = "Solar_Mass / Mpc**3" +temperature_units = "K" ## First, get list of all snapshots -reg_exp = "%s*.hdf5" %snapshot_name +reg_exp = "%s*.hdf5" % snapshot_name snap_list = glob.glob(reg_exp) +snap_data = sorted( + [swiftsimio.load(snap) for snap in snap_list], key=lambda x: x.metadata.z +) -z = [] -T_mean = [] -T_std = [] -rho_mean = [] -rho_std = [] +z = np.empty(len(snap_data), dtype=np.float32) +T_mean = unyt.unyt_array(np.empty_like(z), units=temperature_units) +T_std = unyt.unyt_array(np.empty_like(z), units=temperature_units) +rho_mean = unyt.unyt_array(np.empty_like(z), units=density_units) +rho_std = unyt.unyt_array(np.empty_like(z), units=density_units) ## loop through list -for snap in snap_list: - - # This loads all metadata but explicitly does _not_ read any particle data yet - data = swiftsimio.load(snap) +for index, data in enumerate(snap_data): + # Stick redshift in a list + z[index] = data.metadata.z - # Get the redshift - z = np.append(z, data.metadata.z) - - # Convert gas temperatures and densities to right units - data.gas.temperatures.convert_to_cgs() + # Convert units to something sensible so `np.mean` doesn't freak out + data.gas.temperatures.convert_to_units(temperature_units) + data.gas.densities.convert_to_units(density_units) # Get mean and standard deviation of temperature - T_mean.append(np.mean(data.gas.temperatures) * data.gas.temperatures.units) - T_std.append(np.std(data.gas.temperatures) * data.gas.temperatures.units) + T_mean[index] = np.mean(data.gas.temperatures) + T_std[index] = np.std(data.gas.temperatures) # Get mean and standard deviation of density - rho_mean.append(np.mean(data.gas.densities) * data.gas.densities.units) - rho_std.append(np.std(data.gas.densities) * data.gas.densities.units) - -## Turn into numpy arrays -T_mean = np.array(T_mean) * data.gas.temperatures.units -T_std = np.array(T_std) * data.gas.temperatures.units -rho_mean = np.array(rho_mean) * data.gas.densities.units -rho_std = np.array(rho_std) * data.gas.densities.units + rho_mean[index] = np.mean(data.gas.densities) + rho_std[index] = np.std(data.gas.densities) + ## Put Density into units of mean baryon density today # first calculate rho_bar_0 from snapshot metadata -### from the first snapshot, get cosmology information -d = swiftsimio.load(snap_list[0]) -cosmology = d.metadata.cosmology -H0 = cosmology["H0 [internal units]"] / (d.units.time) +data = snap_data[0] +cosmology = data.metadata.cosmology +H0 = cosmology["H0 [internal units]"] / (data.units.time) Omega_bar = cosmology["Omega_b"] ### now calculate rho_bar_0 and divide through -rho_bar_0 = 3.0 * H0**2 / (8. * np.pi * unyt.G) * Omega_bar +rho_bar_0 = 3.0 * H0 ** 2 / (8.0 * np.pi * unyt.G) * Omega_bar rho_mean /= rho_bar_0 rho_std /= rho_bar_0 -### sort arrays into redshift order -ind_sorted = np.argsort(z) -z = z[ind_sorted] -T_mean = T_mean[ind_sorted] -T_std = T_std[ind_sorted] -rho_mean = rho_mean[ind_sorted] -rho_std = rho_std[ind_sorted] - ### from the first snapshot, get code information -d = swiftsimio.load(snap_list[0]) -code_info = d.metadata.code -git_branch = code_info["Git Branch"].decode('UTF-8') -git_revision = code_info["Git Revision"].decode('UTF-8') -hydro_metadata = d.metadata.hydro_scheme -scheme = hydro_metadata["Scheme"].decode('UTF-8') -params = d.metadata.parameters - -subgrid_metadata = d.metadata.subgrid_scheme -cooling_model = subgrid_metadata["Cooling Model"].decode('UTF-8') -chemistry_model = subgrid_metadata["Chemistry Model"].decode('UTF-8') - -if cooling_model == 'EAGLE': - z_r_H = float(params['EAGLECooling:H_reion_z']) - H_heat_input = float(params['EAGLECooling:H_reion_eV_p_H']) - z_r_He_centre = float(params['EAGLECooling:He_reion_z_centre']) - z_r_He_sigma = float(params['EAGLECooling:He_reion_z_sigma']) - He_heat_input = float(params['EAGLECooling:He_reion_eV_p_H']) - -metallicity = "Unknown" -if chemistry_model == 'EAGLE': - metallicity = float(params['EAGLEChemistry:init_abundance_metal']) - +code_info = data.metadata.code +git_branch = code_info["Git Branch"].decode("UTF-8") +git_revision = code_info["Git Revision"].decode("UTF-8") + +hydro_metadata = data.metadata.hydro_scheme +scheme = hydro_metadata["Scheme"].decode("UTF-8") +params = data.metadata.parameters + +subgrid_metadata = data.metadata.subgrid_scheme +cooling_model = subgrid_metadata["Cooling Model"].decode("UTF-8") +chemistry_model = subgrid_metadata["Chemistry Model"].decode("UTF-8") + +if cooling_model == "EAGLE": + z_r_H = float(params["EAGLECooling:H_reion_z"]) + H_heat_input = float(params["EAGLECooling:H_reion_eV_p_H"]) + z_r_He_centre = float(params["EAGLECooling:He_reion_z_centre"]) + z_r_He_sigma = float(params["EAGLECooling:He_reion_z_sigma"]) + He_heat_input = float(params["EAGLECooling:He_reion_eV_p_H"]) + +if chemistry_model == "EAGLE": + metallicity = float(params["EAGLEChemistry:init_abundance_metal"]) +else: + metallicity = "Unknown" + # Make plot of temperature evolution -------------------------------- -fig = plt.figure() +fig, ax = plt.subplots(constrained_layout=True) # Plot sim properties -if cooling_model == 'EAGLE': - plt.plot([z_r_H, z_r_H], [3.4, 4.4], 'k--', alpha=0.5, lw=0.7) - plt.text(z_r_H + 0.1, 3.55, "H reion.", rotation=90, alpha=0.5, fontsize=7, va="bottom") - plt.plot([z_r_He_centre, z_r_He_centre], [3.4, 4.4], 'k--', alpha=0.5, lw=0.7) - plt.text(z_r_He_centre + 0.1, 3.55, "HeII reion.", rotation=90, alpha=0.5, fontsize=7, va="bottom") - +if cooling_model == "EAGLE": + ax.axvline(z_r_H, color="k", linestyle="--", alpha=0.5, lw=0.7, zorder=-1) + ax.text( + z_r_H + 0.1, 3.55, "H reion.", rotation=90, alpha=0.5, fontsize=7, va="bottom" + ) + ax.axvline(z_r_He_centre, color="k", linestyle="--", alpha=0.5, lw=0.7, zorder=-1) + ax.text( + z_r_He_centre + 0.1, + 3.55, + "HeII reion.", + rotation=90, + alpha=0.5, + fontsize=7, + va="bottom", + ) + # Plot observational data -plt.errorbar(data_schaye[0], - np.log10(data_schaye[3]*1.0e4), - xerr = [schaye_z_lower_error,schaye_z_upper_error], - yerr = [schaye_T_lower_error,schaye_T_upper_error], - fmt='s', mec='0.3', color='0.3', markersize=4, markeredgewidth=0.5, linewidth=0.5, mfc='w', label="Schaye et al. (2000)") -plt.errorbar(data_walther[0], - np.log10(data_walther[1]*1.0e4), - yerr = [walther_T_lower_error,walther_T_upper_error], - fmt='.', mec='0.3', color='0.3', markersize=7, markeredgewidth=0.5, linewidth=0.5, mfc='w', label = "Walther et al. (2019)") +ax.errorbar( + data_schaye[0], + np.log10(data_schaye[3] * 1.0e4), + xerr=[schaye_z_lower_error, schaye_z_upper_error], + yerr=[schaye_T_lower_error, schaye_T_upper_error], + fmt="s", + mec="0.3", + color="0.3", + markersize=4, + markeredgewidth=0.5, + linewidth=0.5, + mfc="w", + label="Schaye et al. (2000)", +) +ax.errorbar( + data_walther[0], + np.log10(data_walther[1] * 1.0e4), + yerr=[walther_T_lower_error, walther_T_upper_error], + fmt=".", + mec="0.3", + color="0.3", + markersize=7, + markeredgewidth=0.5, + linewidth=0.5, + mfc="w", + label="Walther et al. (2019)", +) # Plot simulation -plt.plot(z, np.log10(T_mean)) +ax.plot(z, np.log10(T_mean)) # Legend -plt.legend(loc="upper right", frameon=True, fontsize=8, handletextpad=0.1, facecolor="w", edgecolor="w", framealpha=1.) -plt.text(0.2, 4.8, "SWIFT %s \nCooling model: %s \n$\\rho=%.3f$ $\\Omega_{b}\\rho_{crit,0}$\n$Z=%s$"%(git_revision, cooling_model, rho_mean[-1], metallicity), va="top", ha="left", fontsize=8) - -plt.xlim(0, 12.2) -plt.ylim(3.5,4.85) -plt.xlabel("Redshift", labelpad=-0.5) -plt.ylabel(r"$\log_{10}(T/K)$", labelpad=0) -plt.savefig("Temperature_evolution.png", dpi=200) - - -# Make plot of denisty evolution -------------------------------- -plt.rcParams.update({'figure.subplot.left' : 0.14}) -fig = plt.figure() - -plt.text(0.2, 1.011, "SWIFT %s"%git_revision, va="top", ha="left", fontsize=8) - -plt.fill_between(z,rho_mean - rho_std,rho_mean + rho_std,alpha = 0.5) -plt.plot(z,rho_mean) - -plt.axhline(y = 1.0, linestyle = '--', color='k', alpha=0.5, lw=1.) - -plt.xlim(0.0,12.2) -plt.ylabel(r"$\delta_b = \rho / \Omega_b\rho_{crit,0}$", labelpad=0.) -plt.ylim(0.988,1.012) -plt.yticks([0.99, 1., 1.01]) -plt.xlabel("Redshift", labelpad=-0.5) -plt.savefig("Density_evolution.png", dpi=200) +ax.legend(loc="upper right", frameon=True) +ax.text( + 0.025, + 0.975, + "SWIFT %s \nCooling model: %s \n$\\rho=%.3f$ $\\Omega_{b}\\rho_{crit,0}$\n$Z=%s$" + % (git_revision, cooling_model, rho_mean[-1], metallicity), + va="top", + ha="left", + bbox={"fc": "white", "ec": "none"}, + transform=plt.gca().transAxes, + zorder=1, +) + +ax.set_xlim(0, 12.2) +ax.set_ylim(3.5, 4.85) +ax.set_xlabel("Redshift", labelpad=-0.5) +ax.set_ylabel(r"$\log_{10}(T/K)$", labelpad=0) +fig.savefig("Temperature_evolution.png") + + +# Make plot of density evolution -------------------------------- +fig, ax = plt.subplots(constrained_layout=True) + +ax.text(0.2, 1.011, "SWIFT %s" % git_revision, va="top", ha="left", fontsize=8) + +ax.fill_between(z, rho_mean - rho_std, rho_mean + rho_std, alpha=0.5) +ax.plot(z, rho_mean) + +ax.axhline(y=1.0, linestyle="--", color="k", alpha=0.5, lw=1.0) + +ax.set_xlim(0.0, 12.2) +ax.set_ylabel(r"$\delta_b = \rho / \Omega_b\rho_{crit,0}$", labelpad=0.0) +ax.set_ylim(0.988, 1.012) +ax.set_yticks([0.99, 1.0, 1.01]) +ax.set_xlabel("Redshift", labelpad=-0.5) +fig.savefig("Density_evolution.png") diff --git a/examples/Cooling/CoolingBox/coolingBox.yml b/examples/Cooling/CoolingBox/coolingBox.yml index ca97793aa9b4de43872db38f55c4060a2b27ddc9..f776823d1ba2b4703288913d4bf67f3e4851bebd 100644 --- a/examples/Cooling/CoolingBox/coolingBox.yml +++ b/examples/Cooling/CoolingBox/coolingBox.yml @@ -58,7 +58,7 @@ EAGLECooling: dir_name: ./coolingtables/ H_reion_z: 11.5 H_reion_eV_p_H: 2.0 - He_reion_z_center: 3.5 + He_reion_z_centre: 3.5 He_reion_z_sigma: 0.5 He_reion_eV_p_H: 2.0 diff --git a/examples/EAGLE_ICs/EAGLE_100/README b/examples/EAGLE_ICs/EAGLE_100/README new file mode 100644 index 0000000000000000000000000000000000000000..580ca383b36be99a704f627a3da5dacc151152fb --- /dev/null +++ b/examples/EAGLE_ICs/EAGLE_100/README @@ -0,0 +1,3 @@ +Initial conditions corresponding to the 100 Mpc volume +of the EAGLE suite. The ICs only contain DM particles. The +gas particles will be generated in SWIFT. diff --git a/examples/EAGLE_ICs/EAGLE_100/eagle_100.yml b/examples/EAGLE_ICs/EAGLE_100/eagle_100.yml new file mode 100644 index 0000000000000000000000000000000000000000..8210ff68199d4d67b1985add14f266cc602fe319 --- /dev/null +++ b/examples/EAGLE_ICs/EAGLE_100/eagle_100.yml @@ -0,0 +1,192 @@ +# Define some meta-data about the simulation +MetaData: + run_name: EAGLE-L0100N1504-Ref + +# 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 # km/s in centimeters per second + UnitCurrent_in_cgs: 1 # Amperes + UnitTemp_in_cgs: 1 # Kelvin + +# Cosmological parameters +Cosmology: + h: 0.6777 # Reduced Hubble constant + a_begin: 0.0078125 # Initial scale-factor of the simulation + a_end: 1.0 # Final scale factor of the simulation + Omega_m: 0.307 # Matter density parameter + Omega_lambda: 0.693 # Dark-energy density parameter + Omega_b: 0.0482519 # Baryon density parameter + +# Parameters governing the time integration +TimeIntegration: + dt_min: 1e-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 snapshots +Snapshots: + basename: eagle # Common part of the name of output files + output_list_on: 1 + output_list: ./output_list.txt + +# 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 # Constant dimensionless multiplier for time integration. + theta: 0.7 # Opening angle (Multipole acceptance criterion) + mesh_side_length: 512 + comoving_DM_softening: 0.003320 # Comoving softening for DM (3.32 ckpc) + max_physical_DM_softening: 0.001300 # Physical softening for DM (1.30 pkpc) + comoving_baryon_softening: 0.001790 # Comoving softening for baryons (1.79 ckpc) + max_physical_baryon_softening: 0.000700 # Physical softening for baryons (0.70 pkpc) + dithering: 0 + +# 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). + h_min_ratio: 0.1 # Minimal smoothing in units of softening. + h_max: 0.5 # Maximal softening in co-moving internal units. + CFL_condition: 0.1 # Courant-Friedrich-Levy condition for time integration. + minimal_temperature: 100.0 # (internal units) + initial_temperature: 268.7 # (internal units) + particle_splitting: 1 # Particle splitting is ON + particle_splitting_mass_threshold: 7e-4 # (internal units, i.e. 7e6 Msun ~ 4x initial gas particle mass) + +# Parameters of the stars neighbour search +Stars: + resolution_eta: 1.1642 # Target smoothing length in units of the mean inter-particle separation + h_tolerance: 7e-3 + +# Parameters for the Friends-Of-Friends algorithm +FOF: + basename: fof_output # Filename for the FOF outputs. + min_group_size: 256 # The minimum no. of particles required for a group. + linking_length_ratio: 0.2 # Linking length in units of the main inter-particle separation. + black_hole_seed_halo_mass_Msun: 1.5e10 # Minimal halo mass in which to seed a black hole (in solar masses). + scale_factor_first: 0.01 # Scale-factor of first FoF black hole seeding calls. + delta_time: 1.005 # Scale-factor ratio between consecutive FoF black hole seeding calls. + +Scheduler: + max_top_level_cells: 64 + tasks_per_cell: 5 + cell_split_size: 200 + +Restarts: + onexit: 1 + delta_hours: 1.0 + +# Parameters related to the initial conditions +InitialConditions: + file_name: EAGLE_L0100N1504_ICs.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 + 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. + +# Impose primoridal metallicity +EAGLEChemistry: + init_abundance_metal: 0. + init_abundance_Hydrogen: 0.752 + init_abundance_Helium: 0.248 + init_abundance_Carbon: 0.0 + init_abundance_Nitrogen: 0.0 + init_abundance_Oxygen: 0.0 + init_abundance_Neon: 0.0 + init_abundance_Magnesium: 0.0 + init_abundance_Silicon: 0.0 + init_abundance_Iron: 0.0 + +# EAGLE cooling parameters +EAGLECooling: + dir_name: ./coolingtables/ + H_reion_z: 7.5 # Planck 2018 + H_reion_eV_p_H: 2.0 + He_reion_z_centre: 3.5 + He_reion_z_sigma: 0.5 + He_reion_eV_p_H: 2.0 + +# EAGLE star formation parameters +EAGLEStarFormation: + EOS_density_norm_H_p_cm3: 0.1 # Physical density used for the normalisation of the EOS assumed for the star-forming gas in Hydrogen atoms per cm^3. + EOS_temperature_norm_K: 8000 # Temperature om the polytropic EOS assumed for star-forming gas at the density normalisation in Kelvin. + EOS_gamma_effective: 1.3333333 # Slope the of the polytropic EOS assumed for the star-forming gas. + KS_normalisation: 1.515e-4 # The normalization of the Kennicutt-Schmidt law in Msun / kpc^2 / yr. + KS_exponent: 1.4 # The exponent of the Kennicutt-Schmidt law. + min_over_density: 57.7 # The over-density above which star-formation is allowed. + KS_high_density_threshold_H_p_cm3: 1e3 # Hydrogen number density above which the Kennicut-Schmidt law changes slope in Hydrogen atoms per cm^3. + KS_high_density_exponent: 2.0 # Slope of the Kennicut-Schmidt law above the high-density threshold. + EOS_entropy_margin_dex: 0.5 # Logarithm base 10 of the maximal entropy above the EOS at which stars can form. + threshold_norm_H_p_cm3: 0.1 # Normalisation of the metal-dependant density threshold for star formation in Hydrogen atoms per cm^3. + threshold_Z0: 0.002 # Reference metallicity (metal mass fraction) for the metal-dependant threshold for star formation. + threshold_slope: -0.64 # Slope of the metal-dependant star formation threshold + threshold_max_density_H_p_cm3: 10.0 # Maximal density of the metal-dependant density threshold for star formation in Hydrogen atoms per cm^3. + +# Parameters for the EAGLE "equation of state" +EAGLEEntropyFloor: + Jeans_density_threshold_H_p_cm3: 0.1 # Physical density above which the EAGLE Jeans limiter entropy floor kicks in expressed in Hydrogen atoms per cm^3. + Jeans_over_density_threshold: 10. # Overdensity above which the EAGLE Jeans limiter entropy floor can kick in. + Jeans_temperature_norm_K: 8000 # Temperature of the EAGLE Jeans limiter entropy floor at the density threshold expressed in Kelvin. + Jeans_gamma_effective: 1.3333333 # Slope the of the EAGLE Jeans limiter entropy floor + Cool_density_threshold_H_p_cm3: 1e-5 # Physical density above which the EAGLE Cool limiter entropy floor kicks in expressed in Hydrogen atoms per cm^3. + Cool_over_density_threshold: 10. # Overdensity above which the EAGLE Cool limiter entropy floor can kick in. + Cool_temperature_norm_K: 8000 # Temperature of the EAGLE Cool limiter entropy floor at the density threshold expressed in Kelvin. + Cool_gamma_effective: 1. # Slope the of the EAGLE Cool limiter entropy floor + +# EAGLE feedback model +EAGLEFeedback: + use_SNII_feedback: 1 # Global switch for SNII thermal (stochastic) feedback. + use_SNIa_feedback: 1 # Global switch for SNIa thermal (continuous) feedback. + use_AGB_enrichment: 1 # Global switch for enrichement from AGB stars. + use_SNII_enrichment: 1 # Global switch for enrichement from SNII stars. + use_SNIa_enrichment: 1 # Global switch for enrichement from SNIa stars. + filename: ./yieldtables/ # Path to the directory containing the EAGLE yield tables. + IMF_min_mass_Msun: 0.1 # Minimal stellar mass considered for the Chabrier IMF in solar masses. + IMF_max_mass_Msun: 100.0 # Maximal stellar mass considered for the Chabrier IMF in solar masses. + SNII_min_mass_Msun: 8.0 # Minimal mass considered for SNII stars in solar masses. + SNII_max_mass_Msun: 100.0 # Maximal mass considered for SNII stars in solar masses. + SNII_sampled_delay: 1 # Sample the SNII lifetimes to do feedback. + SNII_wind_delay_Gyr: dummy # Time in Gyr between a star's birth and the SNII thermal feedback event when not sampling. + SNII_delta_T_K: 3.16228e7 # Change in temperature to apply to the gas particle in a SNII thermal feedback event in Kelvin. + SNII_energy_erg: 1.0e51 # Energy of one SNII explosion in ergs. + SNII_energy_fraction_min: 0.3 # Minimal fraction of energy applied in a SNII feedback event. + SNII_energy_fraction_max: 3.0 # Maximal fraction of energy applied in a SNII feedback event. + SNII_energy_fraction_Z_0: 0.0012663729 # Pivot point for the metallicity dependance of the SNII energy fraction (metal mass fraction). + SNII_energy_fraction_n_0_H_p_cm3: 1.4588 # Pivot point for the birth density dependance of the SNII energy fraction in cm^-3. + SNII_energy_fraction_n_Z: 0.8686 # Power-law for the metallicity dependance of the SNII energy fraction. + SNII_energy_fraction_n_n: 0.8686 # Power-law for the birth density dependance of the SNII energy fraction. + SNIa_DTD: PowerLaw # Functional form of the SNIa delay time distribution. + SNIa_DTD_delay_Gyr: 0.04 # Stellar age after which SNIa start in Gyr (40 Myr corresponds to stars ~ 8 Msun). + SNIa_DTD_power_law_norm_p_Msun: 0.0012 # Normalization of the SNIa delay time distribution (in Msun^-1). + SNIa_energy_erg: 1.0e51 # Energy of one SNIa explosion in ergs. + AGB_ejecta_velocity_km_p_s: 10.0 # Velocity of the AGB ejectas in km/s. + stellar_evolution_age_cut_Gyr: 0.1 # Stellar age in Gyr above which the enrichment is down-sampled. + stellar_evolution_sampling_rate: 10 # Number of time-steps in-between two enrichment events for a star above the age threshold. + SNII_yield_factor_Hydrogen: 1.0 # (Optional) Correction factor to apply to the Hydrogen yield from the SNII channel. + SNII_yield_factor_Helium: 1.0 # (Optional) Correction factor to apply to the Helium yield from the SNII channel. + SNII_yield_factor_Carbon: 0.5 # (Optional) Correction factor to apply to the Carbon yield from the SNII channel. + SNII_yield_factor_Nitrogen: 1.0 # (Optional) Correction factor to apply to the Nitrogen yield from the SNII channel. + SNII_yield_factor_Oxygen: 1.0 # (Optional) Correction factor to apply to the Oxygen yield from the SNII channel. + SNII_yield_factor_Neon: 1.0 # (Optional) Correction factor to apply to the Neon yield from the SNII channel. + SNII_yield_factor_Magnesium: 4.0 # (Optional) Correction factor to apply to the Magnesium yield from the SNII channel. + SNII_yield_factor_Silicon: 1.0 # (Optional) Correction factor to apply to the Silicon yield from the SNII channel. + SNII_yield_factor_Iron: 0.5 # (Optional) Correction factor to apply to the Iron yield from the SNII channel. + +# EAGLE AGN model +EAGLEAGN: + subgrid_seed_mass_Msun: 1.5e5 # Black hole subgrid mass at creation time in solar masses. + max_eddington_fraction: 1.0 # Maximal allowed accretion rate in units of the Eddington rate. + eddington_fraction_for_recording: 0.1 # Record the last time BHs reached an Eddington ratio above this threshold. + viscous_alpha: 1e6 # Normalisation constant of the Bondi viscuous time-scale accretion reduction term + radiative_efficiency: 0.1 # Fraction of the accreted mass that gets radiated. + coupling_efficiency: 0.15 # Fraction of the radiated energy that couples to the gas in feedback events. + AGN_delta_T_K: 3.16228e8 # Change in temperature to apply to the gas particle in an AGN feedback event in Kelvin. + AGN_num_ngb_to_heat: 1. # Target number of gas neighbours to heat in an AGN feedback event. + max_reposition_mass: 2e8 # Maximal BH mass considered for BH repositioning in solar masses. + threshold_major_merger: 0.333 # Mass ratio threshold to consider a BH merger as 'major' + threshold_minor_merger: 0.1 # Mass ratio threshold to consider a BH merger as 'minor' diff --git a/examples/EAGLE_ICs/EAGLE_100/getIC.sh b/examples/EAGLE_ICs/EAGLE_100/getIC.sh new file mode 100755 index 0000000000000000000000000000000000000000..8b60aea542befc829f4b7b6825402adf1eaa7205 --- /dev/null +++ b/examples/EAGLE_ICs/EAGLE_100/getIC.sh @@ -0,0 +1,2 @@ +#!/bin/bash +wget http://virgodb.cosma.dur.ac.uk/swift-webstorage/ICs/EAGLE_ICs/EAGLE_L0100N1504_ICs.hdf5 diff --git a/examples/EAGLE_ICs/EAGLE_100/output_list.txt b/examples/EAGLE_ICs/EAGLE_100/output_list.txt new file mode 100644 index 0000000000000000000000000000000000000000..592ab8483d015fe1bfafe5cc603fabc230b25589 --- /dev/null +++ b/examples/EAGLE_ICs/EAGLE_100/output_list.txt @@ -0,0 +1,38 @@ +# Redshift +18.08 +15.28 +13.06 +11.26 +9.79 +8.57 +7.54 +6.67 +5.92 +5.28 +4.72 +4.24 +3.81 +3.43 +3.09 +2.79 +2.52 +2.28 +2.06 +1.86 +1.68 +1.51 +1.36 +1.21 +1.08 +0.96 +0.85 +0.74 +0.64 +0.55 +0.46 +0.37 +0.29 +0.21 +0.14 +0.07 +0.00 diff --git a/examples/EAGLE_ICs/EAGLE_100/run.sh b/examples/EAGLE_ICs/EAGLE_100/run.sh new file mode 100755 index 0000000000000000000000000000000000000000..6a2f423cd91fef9fa215d261839758443a2e0756 --- /dev/null +++ b/examples/EAGLE_ICs/EAGLE_100/run.sh @@ -0,0 +1,35 @@ +#!/bin/bash + + # Generate the initial conditions if they are not present. +if [ ! -e EAGLE_L0100N1504_ICs.hdf5 ] +then + echo "Fetching initial conditions for the EAGLE 100Mpc example..." + ./getIC.sh +fi + +# Grab the cooling and yield tables if they are not present. +if [ ! -e yieldtables ] +then + echo "Fetching EAGLE yield tables..." + ../getEagleYieldtable.sh +fi + +if [ ! -e coolingtables ] +then + echo "Fetching EAGLE cooling tables..." + ../getEagleCoolingTable.sh +fi + +# The following run-time options are broken down by line as: +# Basic run-time options +# Create and run with stars +# Radiative options - run with cooling and stellar feedback +# Run with the time-step limiter required to capture feedback +# Run with black holes - fof is needed for the seeding +# Threading options - run with threads and pinning (latter not required but improves performance) +# The corresponding parameter file for this run + +../../swift \ + --cosmology --eagle \ + --threads=16 --pin \ + eagle_100.yml diff --git a/examples/EAGLE_ICs/EAGLE_12/vrconfig_6dfofbound_subhalos_SO_hydro.cfg b/examples/EAGLE_ICs/EAGLE_100/vrconfig_3dfof_subhalos_SO_hydro.cfg similarity index 85% rename from examples/EAGLE_ICs/EAGLE_12/vrconfig_6dfofbound_subhalos_SO_hydro.cfg rename to examples/EAGLE_ICs/EAGLE_100/vrconfig_3dfof_subhalos_SO_hydro.cfg index 45d6a8e7b7ecfeba7832e2dc19b5c11411374c81..8590cbf5bc77e8d7a956d210339cced4bbdc692c 100644 --- a/examples/EAGLE_ICs/EAGLE_12/vrconfig_6dfofbound_subhalos_SO_hydro.cfg +++ b/examples/EAGLE_ICs/EAGLE_100/vrconfig_3dfof_subhalos_SO_hydro.cfg @@ -1,42 +1,51 @@ -#Configuration file for analysing DM particles (in either DM only simulation or in full Hydro) -#runs 6DFOF + substructure algorithm, demands subhalos and FOF halos be self-bound, calculates many properties +#Configuration file for analysing Hydro +#runs 3DFOF + substructure algorithm, demands subhalos and FOF halos be self-bound, calculates many properties #Units currently set to take in as input, Mpc, 1e10 solar masses, km/s, output in same units #To set temporally unique halo ids, alter Snapshot_value=SNAP to appropriate value. Ie: for snapshot 12, change SNAP to 12 ################################ -#unit options, should always be provided +#input options +#set up to use SWIFT HDF input, load gas, star, bh and dark matter ################################ -#EDIT THIS SECTION!!!! - -#naming convention is EAGLE Hydro. This config will be generalised to allow specific naming conventions to be implemented besides predefined ones -HDF_name_convention=6 +HDF_name_convention=6 #HDF SWIFT naming convention +Input_includes_dm_particle=1 #include dark matter particles in hydro input +Input_includes_gas_particle=1 #include gas particles in hydro input Input_includes_star_particle=1 #include star particles in hydro input Input_includes_bh_particle=1 #include bh particles in hydro input Input_includes_wind_particle=0 #include wind particles in hydro input (used by Illustris and moves particle type 0 to particle type 3 when decoupled from hydro forces). Here shown as example Input_includes_tracer_particle=0 #include tracer particles in hydro input (used by Illustris). Here shown as example Input_includes_extradm_particle=0 #include extra dm particles stored in particle type 2 and type 3, useful for zooms +Halo_core_phase_merge_dist=0.25 #merge substructures if difference in dispersion normalised distance is < this value +Apply_phase_merge_to_host=1 #merge substructures with background if centrally located and phase-distance is small #units conversion from input input to desired internal unit -Length_unit=1.0 #default code unit, -Velocity_unit=1.0 #default velocity unit, -Mass_unit=1.0 #default mass unit, +Length_input_unit_conversion_to_output_unit=1.0 #default code unit, +Velocity_input_unit_conversion_to_output_unit=1.0 #default velocity unit, +Mass_input_unit_conversion_to_output_unit=1.0 #default mass unit, #assumes input is in 1e10 msun, Mpc and km/s and output units are the same Gravity=43.0211349 #for 1e10 Msun, km/s and Mpc Hubble_unit=100.0 # assuming units are km/s and Mpc, then value of Hubble in km/s/Mpc +#converting hydro quantities +Stellar_age_input_is_cosmological_scalefactor=1 +Metallicity_input_unit_conversion_to_output_unit=1.0 +Stellar_age_input_unit_conversion_to_output_unit=1.0 +Star_formation_rate_input_unit_conversion_to_output_unit=1.0 +#set the units of the output by providing conversion to a defined unit #conversion of output length units to kpc Length_unit_to_kpc=1000.0 #conversion of output velocity units to km/s Velocity_to_kms=1.0 #conversion of output mass units to solar masses Mass_to_solarmass=1.0e10 +#1 / 0.012 +Metallicity_to_solarmetallicity=83.33 +Star_formation_rate_to_solarmassperyear=97.78 +Stellar_age_to_yr=1.0 +#ensures that output is physical and not comoving distances per little h +Comoving_units=0 -################################ -#input related -################################ -#input is from a cosmological so can use parameters like box size, h, Omega_m to calculate length and density scales -Cosmological_input=1 #sets the total buffer size in bytes used to store temporary particle information #of mpi read threads before they are broadcast to the appropriate waiting non-read threads #if not set, default value is equivalent to 1e6 particles per mpi process, quite large @@ -61,11 +70,11 @@ Singlehalo_search=0 #if file is single halo in which one wishes to search for su Keep_FOF=0 #if field 6DFOF search is done, allows to keep structures found in 3DFOF (can be interpreted as the inter halo stellar mass when only stellar search is used).\n #minimum size for structures -Minimum_size=20 #min particles +Minimum_size=20 #min 20 particles Minimum_halo_size=32 #if field halos have different minimum sizes, otherwise set to -1. #for field fof halo search -FoF_Field_search_type=3 #5 3DFOF search for field halos, 4 for 6DFOF clean up of field halos, 3 for 6DFOF with velocity scale distinct for each initial 3D FOF candidate +FoF_Field_search_type=5 #5 3DFOF search for field halos, 4 for 6DFOF clean up of field halos, 3 for 6DFOF with velocity scale distinct for each initial 3D FOF candidate Halo_3D_linking_length=0.20 #for mean field estimates and local velocity density distribution funciton estimator related quantiites, rarely need to change this @@ -108,26 +117,26 @@ Halo_core_phase_significance=2.0 #how significant a core must be in terms of dis ################################ #Unbinding options (VELOCIraptor is able to accurately identify tidal debris so particles need not be bound to a structure) ################################ + #unbinding related items Unbind_flag=1 #run unbinding #objects must have particles that meet the allowed kinetic to potential ratio AND also have some total fraction that are completely bound. Unbinding_type=0 -#run unbinding of field structures, aka halos. This is useful for sams and 6DFOF halos but may not be useful if interested in 3DFOF mass functions. -Bound_halos=0 #alpha factor used to determine whether particle is "bound" alaph*T+W<0. For standard subhalo catalogues use >0.9 but if interested in tidal debris 0.2-0.5 Allowed_kinetic_potential_ratio=0.95 Min_bound_mass_frac=0.65 #minimum bound mass fraction -#don't keep background potential when unbinding, faster than recalculating +#run unbinding of field structures, aka halos. This is useful for sams and 6DFOF halos but may not be useful if interested in 3DFOF mass functions. +Bound_halos=0 +#don't keep background potential when unbinding Keep_background_potential=1 -Softening_length=0.0 +#use all particles to determine velocity frame for unbinding Frac_pot_ref=1.0 Min_npot_ref=20 +#reference frame only meaningful if calculating velocity frame using subset of particles in object. Can use radially sorted fraction of particles about minimum potential or centre of mass Kinetic_reference_frame_type=0 -#extra options in new unbinding optimisation Unbinding_max_unbound_removal_fraction_per_iteration=0.5 Unbinding_max_unbound_fraction=0.95 -Unbinding_max_unbound_fraction_allowed=0.025 - +Unbinding_max_unbound_fraction_allowed=0.005 ################################ #Calculation of properties related options @@ -139,6 +148,8 @@ Inclusive_halo_masses=3 #calculate inclusive masses for halos using full Spheric Comoving_units=0 #calculate more (sub)halo properties (like angular momentum in spherical overdensity apertures, both inclusive and exclusive) Extensive_halo_properties_output=1 +Extensive_gas_properties_output=1 +Extensive_star_properties_output=1 #calculate aperture masses Calculate_aperture_quantities=1 Number_of_apertures=5 @@ -175,12 +186,6 @@ Snapshot_value=SNAP ################################ #other options ################################ -Verbose=1 #how talkative do you want the code to be, 0 not much, 1 a lot, 2 chatterbox +Verbose=0 #how talkative do you want the code to be, 0 not much, 1 a lot, 2 chatterbox + -Metallicity_to_solarmetallicity=1.0 #conversion of output to solarmetallicity -Star_formation_rate_to_solarmassperyear=1.0 #similar but for star formation rates -Stellar_age_to_yr=1.0 #similar but for stellar ages -Stellar_age_input_is_cosmological_scalefactor=1 #indicates stars store formation scalefactor -Metallicity_input_unit_conversion_to_output_unit=1.0 -Stellar_age_input_unit_conversion_to_output_unit=1.0 -Star_formation_rate_input_unit_conversion_to_output_unit=1.0 diff --git a/examples/EAGLE_ICs/EAGLE_12/eagle_12.yml b/examples/EAGLE_ICs/EAGLE_12/eagle_12.yml index d3c4ff0e87f358038219efd620f7610883c139d0..864df962f0561a3a2284c75ccc485dbb2cafc4fe 100644 --- a/examples/EAGLE_ICs/EAGLE_12/eagle_12.yml +++ b/examples/EAGLE_ICs/EAGLE_12/eagle_12.yml @@ -38,20 +38,24 @@ Statistics: # Parameters for the self-gravity scheme Gravity: eta: 0.025 # Constant dimensionless multiplier for time integration. - theta: 0.5 # Opening angle (Multipole acceptance criterion) + theta: 0.7 # Opening angle (Multipole acceptance criterion) mesh_side_length: 64 - comoving_DM_softening: 0.0026994 # Comoving DM softening length (in internal units). - max_physical_DM_softening: 0.0007 # Max physical DM softening length (in internal units). - comoving_baryon_softening: 0.0026994 # Comoving DM softening length (in internal units). - max_physical_baryon_softening: 0.0007 # Max physical DM softening length (in internal units). + comoving_DM_softening: 0.003320 # Comoving softening for DM (3.32 ckpc) + max_physical_DM_softening: 0.001300 # Physical softening for DM (1.30 pkpc) + comoving_baryon_softening: 0.001790 # Comoving softening for baryons (1.79 ckpc) + max_physical_baryon_softening: 0.000700 # Physical softening for baryons (0.70 pkpc) + dithering: 0 # 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). - h_min_ratio: 0.1 # Minimal smoothing in units of softening. - CFL_condition: 0.1 # Courant-Friedrich-Levy condition for time integration. - minimal_temperature: 100.0 # (internal units) - initial_temperature: 268.7 + resolution_eta: 1.2348 # Target smoothing length in units of the mean inter-particle separation (1.2348 == 48Ngbs with the cubic spline kernel). + h_min_ratio: 0.1 # Minimal smoothing in units of softening. + h_max: 0.5 # Maximal softening in co-moving internal units. + CFL_condition: 0.1 # Courant-Friedrich-Levy condition for time integration. + minimal_temperature: 100.0 # (internal units) + initial_temperature: 268.7 # (internal units) + particle_splitting: 1 # Particle splitting is ON + particle_splitting_mass_threshold: 7e-4 # (internal units, i.e. 7e6 Msun ~ 4x initial gas particle mass) # Parameters of the stars neighbour search Stars: @@ -70,7 +74,8 @@ FOF: Scheduler: max_top_level_cells: 16 tasks_per_cell: 5 - + cell_split_size: 200 + Restarts: onexit: 1 delta_hours: 1.0 @@ -115,7 +120,7 @@ EAGLEStarFormation: min_over_density: 57.7 # The over-density above which star-formation is allowed. KS_high_density_threshold_H_p_cm3: 1e3 # Hydrogen number density above which the Kennicut-Schmidt law changes slope in Hydrogen atoms per cm^3. KS_high_density_exponent: 2.0 # Slope of the Kennicut-Schmidt law above the high-density threshold. - EOS_temperature_margin_dex: 0.5 # Logarithm base 10 of the maximal temperature difference above the EOS allowed to form stars. + EOS_entropy_margin_dex: 0.5 # Logarithm base 10 of the maximal entropy above the EOS at which stars can form. threshold_norm_H_p_cm3: 0.1 # Normalisation of the metal-dependant density threshold for star formation in Hydrogen atoms per cm^3. threshold_Z0: 0.002 # Reference metallicity (metal mass fraction) for the metal-dependant threshold for star formation. threshold_slope: -0.64 # Slope of the metal-dependant star formation threshold @@ -142,9 +147,10 @@ EAGLEFeedback: filename: ./yieldtables/ # Path to the directory containing the EAGLE yield tables. IMF_min_mass_Msun: 0.1 # Minimal stellar mass considered for the Chabrier IMF in solar masses. IMF_max_mass_Msun: 100.0 # Maximal stellar mass considered for the Chabrier IMF in solar masses. - SNII_min_mass_Msun: 6.0 # Minimal mass considered for SNII feedback (not SNII enrichment!) in solar masses. - SNII_max_mass_Msun: 100.0 # Maximal mass considered for SNII feedback (not SNII enrichment!) in solar masses. - SNII_wind_delay_Gyr: 0.03 # Time in Gyr between a star's birth and the SNII thermal feedback event. + SNII_min_mass_Msun: 8.0 # Minimal mass considered for SNII stars in solar masses. + SNII_max_mass_Msun: 100.0 # Maximal mass considered for SNII stars in solar masses. + SNII_sampled_delay: 1 # Sample the SNII lifetimes to do feedback. + SNII_wind_delay_Gyr: dummy # Time in Gyr between a star's birth and the SNII thermal feedback event when not sampling. SNII_delta_T_K: 3.16228e7 # Change in temperature to apply to the gas particle in a SNII thermal feedback event in Kelvin. SNII_energy_erg: 1.0e51 # Energy of one SNII explosion in ergs. SNII_energy_fraction_min: 0.3 # Minimal fraction of energy applied in a SNII feedback event. @@ -153,28 +159,33 @@ EAGLEFeedback: SNII_energy_fraction_n_0_H_p_cm3: 1.4588 # Pivot point for the birth density dependance of the SNII energy fraction in cm^-3. SNII_energy_fraction_n_Z: 0.8686 # Power-law for the metallicity dependance of the SNII energy fraction. SNII_energy_fraction_n_n: 0.8686 # Power-law for the birth density dependance of the SNII energy fraction. - SNIa_max_mass_Msun: 8.0 # Maximal mass considered for SNIa feedback and enrichment in solar masses. - SNIa_timescale_Gyr: 2.0 # Time-scale of the exponential decay of the SNIa rates in Gyr. - SNIa_efficiency_p_Msun: 0.002 # Normalisation of the SNIa rates in inverse solar masses. + SNIa_DTD: PowerLaw # Functional form of the SNIa delay time distribution. + SNIa_DTD_delay_Gyr: 0.04 # Stellar age after which SNIa start in Gyr (40 Myr corresponds to stars ~ 8 Msun). + SNIa_DTD_power_law_norm_p_Msun: 0.0012 # Normalization of the SNIa delay time distribution (in Msun^-1). SNIa_energy_erg: 1.0e51 # Energy of one SNIa explosion in ergs. AGB_ejecta_velocity_km_p_s: 10.0 # Velocity of the AGB ejectas in km/s. + stellar_evolution_age_cut_Gyr: 0.1 # Stellar age in Gyr above which the enrichment is down-sampled. + stellar_evolution_sampling_rate: 10 # Number of time-steps in-between two enrichment events for a star above the age threshold. SNII_yield_factor_Hydrogen: 1.0 # (Optional) Correction factor to apply to the Hydrogen yield from the SNII channel. SNII_yield_factor_Helium: 1.0 # (Optional) Correction factor to apply to the Helium yield from the SNII channel. SNII_yield_factor_Carbon: 0.5 # (Optional) Correction factor to apply to the Carbon yield from the SNII channel. SNII_yield_factor_Nitrogen: 1.0 # (Optional) Correction factor to apply to the Nitrogen yield from the SNII channel. SNII_yield_factor_Oxygen: 1.0 # (Optional) Correction factor to apply to the Oxygen yield from the SNII channel. SNII_yield_factor_Neon: 1.0 # (Optional) Correction factor to apply to the Neon yield from the SNII channel. - SNII_yield_factor_Magnesium: 2.0 # (Optional) Correction factor to apply to the Magnesium yield from the SNII channel. + SNII_yield_factor_Magnesium: 4.0 # (Optional) Correction factor to apply to the Magnesium yield from the SNII channel. SNII_yield_factor_Silicon: 1.0 # (Optional) Correction factor to apply to the Silicon yield from the SNII channel. SNII_yield_factor_Iron: 0.5 # (Optional) Correction factor to apply to the Iron yield from the SNII channel. # EAGLE AGN model EAGLEAGN: subgrid_seed_mass_Msun: 1.5e5 # Black hole subgrid mass at creation time in solar masses. - max_eddington_fraction: 1.5 # Maximal allowed accretion rate in units of the Eddington rate. + max_eddington_fraction: 1.0 # Maximal allowed accretion rate in units of the Eddington rate. + eddington_fraction_for_recording: 0.1 # Record the last time BHs reached an Eddington ratio above this threshold. viscous_alpha: 1e6 # Normalisation constant of the Bondi viscuous time-scale accretion reduction term radiative_efficiency: 0.1 # Fraction of the accreted mass that gets radiated. coupling_efficiency: 0.15 # Fraction of the radiated energy that couples to the gas in feedback events. AGN_delta_T_K: 3.16228e8 # Change in temperature to apply to the gas particle in an AGN feedback event in Kelvin. AGN_num_ngb_to_heat: 1. # Target number of gas neighbours to heat in an AGN feedback event. - max_reposition_mass: 2e8 # Maximal BH mass considered for BH repositioning in solar masses. \ No newline at end of file + max_reposition_mass: 2e8 # Maximal BH mass considered for BH repositioning in solar masses. + threshold_major_merger: 0.333 # Mass ratio threshold to consider a BH merger as 'major' + threshold_minor_merger: 0.1 # Mass ratio threshold to consider a BH merger as 'minor' diff --git a/examples/EAGLE_ICs/EAGLE_12/run.sh b/examples/EAGLE_ICs/EAGLE_12/run.sh index 86fe2b1db0a7725b617656d3b52f0dce89435ea3..e908b552de266a29b34bee18e462987c2f2bfffe 100755 --- a/examples/EAGLE_ICs/EAGLE_12/run.sh +++ b/examples/EAGLE_ICs/EAGLE_12/run.sh @@ -1,11 +1,36 @@ #!/bin/bash - # Generate the initial conditions if they are not present. +# Generate the initial conditions if they are not present. if [ ! -e EAGLE_L0012N0188_ICs.hdf5 ] then echo "Fetching initial conditions for the EAGLE 12Mpc example..." ./getIC.sh fi -../../swift --cosmology --hydro --self-gravity --stars --black-holes --cooling --star-formation --feedback --fof --threads=16 eagle_12.yml 2>&1 | tee output.log +# Grab the cooling and yield tables if they are not present. +if [ ! -e yieldtables ] +then + echo "Fetching EAGLE yield tables..." + ../getEagleYieldtable.sh +fi + +if [ ! -e coolingtables ] +then + echo "Fetching EAGLE cooling tables..." + ../getEagleCoolingTable.sh +fi + +# The following run-time options are broken down by line as: +# Basic run-time options +# Create and run with stars +# Radiative options - run with cooling and stellar feedback +# Run with the time-step limiter required to capture feedback +# Run with black holes - fof is needed for the seeding +# Threading options - run with threads and pinning (latter not required but improves performance) +# The corresponding parameter file for this run + +../../swift \ + --cosmology --eagle \ + --threads=16 --pin \ + eagle_12.yml diff --git a/examples/EAGLE_ICs/EAGLE_25/vrconfig_6dfofbound_subhalos_SO_hydro.cfg b/examples/EAGLE_ICs/EAGLE_12/vrconfig_3dfof_subhalos_SO_hydro.cfg similarity index 85% rename from examples/EAGLE_ICs/EAGLE_25/vrconfig_6dfofbound_subhalos_SO_hydro.cfg rename to examples/EAGLE_ICs/EAGLE_12/vrconfig_3dfof_subhalos_SO_hydro.cfg index 45d6a8e7b7ecfeba7832e2dc19b5c11411374c81..8590cbf5bc77e8d7a956d210339cced4bbdc692c 100644 --- a/examples/EAGLE_ICs/EAGLE_25/vrconfig_6dfofbound_subhalos_SO_hydro.cfg +++ b/examples/EAGLE_ICs/EAGLE_12/vrconfig_3dfof_subhalos_SO_hydro.cfg @@ -1,42 +1,51 @@ -#Configuration file for analysing DM particles (in either DM only simulation or in full Hydro) -#runs 6DFOF + substructure algorithm, demands subhalos and FOF halos be self-bound, calculates many properties +#Configuration file for analysing Hydro +#runs 3DFOF + substructure algorithm, demands subhalos and FOF halos be self-bound, calculates many properties #Units currently set to take in as input, Mpc, 1e10 solar masses, km/s, output in same units #To set temporally unique halo ids, alter Snapshot_value=SNAP to appropriate value. Ie: for snapshot 12, change SNAP to 12 ################################ -#unit options, should always be provided +#input options +#set up to use SWIFT HDF input, load gas, star, bh and dark matter ################################ -#EDIT THIS SECTION!!!! - -#naming convention is EAGLE Hydro. This config will be generalised to allow specific naming conventions to be implemented besides predefined ones -HDF_name_convention=6 +HDF_name_convention=6 #HDF SWIFT naming convention +Input_includes_dm_particle=1 #include dark matter particles in hydro input +Input_includes_gas_particle=1 #include gas particles in hydro input Input_includes_star_particle=1 #include star particles in hydro input Input_includes_bh_particle=1 #include bh particles in hydro input Input_includes_wind_particle=0 #include wind particles in hydro input (used by Illustris and moves particle type 0 to particle type 3 when decoupled from hydro forces). Here shown as example Input_includes_tracer_particle=0 #include tracer particles in hydro input (used by Illustris). Here shown as example Input_includes_extradm_particle=0 #include extra dm particles stored in particle type 2 and type 3, useful for zooms +Halo_core_phase_merge_dist=0.25 #merge substructures if difference in dispersion normalised distance is < this value +Apply_phase_merge_to_host=1 #merge substructures with background if centrally located and phase-distance is small #units conversion from input input to desired internal unit -Length_unit=1.0 #default code unit, -Velocity_unit=1.0 #default velocity unit, -Mass_unit=1.0 #default mass unit, +Length_input_unit_conversion_to_output_unit=1.0 #default code unit, +Velocity_input_unit_conversion_to_output_unit=1.0 #default velocity unit, +Mass_input_unit_conversion_to_output_unit=1.0 #default mass unit, #assumes input is in 1e10 msun, Mpc and km/s and output units are the same Gravity=43.0211349 #for 1e10 Msun, km/s and Mpc Hubble_unit=100.0 # assuming units are km/s and Mpc, then value of Hubble in km/s/Mpc +#converting hydro quantities +Stellar_age_input_is_cosmological_scalefactor=1 +Metallicity_input_unit_conversion_to_output_unit=1.0 +Stellar_age_input_unit_conversion_to_output_unit=1.0 +Star_formation_rate_input_unit_conversion_to_output_unit=1.0 +#set the units of the output by providing conversion to a defined unit #conversion of output length units to kpc Length_unit_to_kpc=1000.0 #conversion of output velocity units to km/s Velocity_to_kms=1.0 #conversion of output mass units to solar masses Mass_to_solarmass=1.0e10 +#1 / 0.012 +Metallicity_to_solarmetallicity=83.33 +Star_formation_rate_to_solarmassperyear=97.78 +Stellar_age_to_yr=1.0 +#ensures that output is physical and not comoving distances per little h +Comoving_units=0 -################################ -#input related -################################ -#input is from a cosmological so can use parameters like box size, h, Omega_m to calculate length and density scales -Cosmological_input=1 #sets the total buffer size in bytes used to store temporary particle information #of mpi read threads before they are broadcast to the appropriate waiting non-read threads #if not set, default value is equivalent to 1e6 particles per mpi process, quite large @@ -61,11 +70,11 @@ Singlehalo_search=0 #if file is single halo in which one wishes to search for su Keep_FOF=0 #if field 6DFOF search is done, allows to keep structures found in 3DFOF (can be interpreted as the inter halo stellar mass when only stellar search is used).\n #minimum size for structures -Minimum_size=20 #min particles +Minimum_size=20 #min 20 particles Minimum_halo_size=32 #if field halos have different minimum sizes, otherwise set to -1. #for field fof halo search -FoF_Field_search_type=3 #5 3DFOF search for field halos, 4 for 6DFOF clean up of field halos, 3 for 6DFOF with velocity scale distinct for each initial 3D FOF candidate +FoF_Field_search_type=5 #5 3DFOF search for field halos, 4 for 6DFOF clean up of field halos, 3 for 6DFOF with velocity scale distinct for each initial 3D FOF candidate Halo_3D_linking_length=0.20 #for mean field estimates and local velocity density distribution funciton estimator related quantiites, rarely need to change this @@ -108,26 +117,26 @@ Halo_core_phase_significance=2.0 #how significant a core must be in terms of dis ################################ #Unbinding options (VELOCIraptor is able to accurately identify tidal debris so particles need not be bound to a structure) ################################ + #unbinding related items Unbind_flag=1 #run unbinding #objects must have particles that meet the allowed kinetic to potential ratio AND also have some total fraction that are completely bound. Unbinding_type=0 -#run unbinding of field structures, aka halos. This is useful for sams and 6DFOF halos but may not be useful if interested in 3DFOF mass functions. -Bound_halos=0 #alpha factor used to determine whether particle is "bound" alaph*T+W<0. For standard subhalo catalogues use >0.9 but if interested in tidal debris 0.2-0.5 Allowed_kinetic_potential_ratio=0.95 Min_bound_mass_frac=0.65 #minimum bound mass fraction -#don't keep background potential when unbinding, faster than recalculating +#run unbinding of field structures, aka halos. This is useful for sams and 6DFOF halos but may not be useful if interested in 3DFOF mass functions. +Bound_halos=0 +#don't keep background potential when unbinding Keep_background_potential=1 -Softening_length=0.0 +#use all particles to determine velocity frame for unbinding Frac_pot_ref=1.0 Min_npot_ref=20 +#reference frame only meaningful if calculating velocity frame using subset of particles in object. Can use radially sorted fraction of particles about minimum potential or centre of mass Kinetic_reference_frame_type=0 -#extra options in new unbinding optimisation Unbinding_max_unbound_removal_fraction_per_iteration=0.5 Unbinding_max_unbound_fraction=0.95 -Unbinding_max_unbound_fraction_allowed=0.025 - +Unbinding_max_unbound_fraction_allowed=0.005 ################################ #Calculation of properties related options @@ -139,6 +148,8 @@ Inclusive_halo_masses=3 #calculate inclusive masses for halos using full Spheric Comoving_units=0 #calculate more (sub)halo properties (like angular momentum in spherical overdensity apertures, both inclusive and exclusive) Extensive_halo_properties_output=1 +Extensive_gas_properties_output=1 +Extensive_star_properties_output=1 #calculate aperture masses Calculate_aperture_quantities=1 Number_of_apertures=5 @@ -175,12 +186,6 @@ Snapshot_value=SNAP ################################ #other options ################################ -Verbose=1 #how talkative do you want the code to be, 0 not much, 1 a lot, 2 chatterbox +Verbose=0 #how talkative do you want the code to be, 0 not much, 1 a lot, 2 chatterbox + -Metallicity_to_solarmetallicity=1.0 #conversion of output to solarmetallicity -Star_formation_rate_to_solarmassperyear=1.0 #similar but for star formation rates -Stellar_age_to_yr=1.0 #similar but for stellar ages -Stellar_age_input_is_cosmological_scalefactor=1 #indicates stars store formation scalefactor -Metallicity_input_unit_conversion_to_output_unit=1.0 -Stellar_age_input_unit_conversion_to_output_unit=1.0 -Star_formation_rate_input_unit_conversion_to_output_unit=1.0 diff --git a/examples/EAGLE_ICs/EAGLE_25/eagle_25.yml b/examples/EAGLE_ICs/EAGLE_25/eagle_25.yml index 67850cdb5ec040c459aac281f6280c74d9a52fe5..9c99a164b364fa719c42f7d56d2c573a6190b26d 100644 --- a/examples/EAGLE_ICs/EAGLE_25/eagle_25.yml +++ b/examples/EAGLE_ICs/EAGLE_25/eagle_25.yml @@ -38,20 +38,24 @@ Statistics: # Parameters for the self-gravity scheme Gravity: eta: 0.025 # Constant dimensionless multiplier for time integration. - theta: 0.5 # Opening angle (Multipole acceptance criterion) + theta: 0.7 # Opening angle (Multipole acceptance criterion) mesh_side_length: 128 - comoving_DM_softening: 0.0026994 # Comoving DM softening length (in internal units). - max_physical_DM_softening: 0.0007 # Max physical DM softening length (in internal units). - comoving_baryon_softening: 0.0026994 # Comoving DM softening length (in internal units). - max_physical_baryon_softening: 0.0007 # Max physical DM softening length (in internal units). + comoving_DM_softening: 0.003320 # Comoving softening for DM (3.32 ckpc) + max_physical_DM_softening: 0.001300 # Physical softening for DM (1.30 pkpc) + comoving_baryon_softening: 0.001790 # Comoving softening for baryons (1.79 ckpc) + max_physical_baryon_softening: 0.000700 # Physical softening for baryons (0.70 pkpc) + dithering: 0 # 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). - h_min_ratio: 0.1 # Minimal smoothing in units of softening. - CFL_condition: 0.1 # Courant-Friedrich-Levy condition for time integration. - minimal_temperature: 100.0 # (internal units) - initial_temperature: 268.7 + resolution_eta: 1.2348 # Target smoothing length in units of the mean inter-particle separation (1.2348 == 48Ngbs with the cubic spline kernel). + h_min_ratio: 0.1 # Minimal smoothing in units of softening. + h_max: 0.5 # Maximal softening in co-moving internal units. + CFL_condition: 0.1 # Courant-Friedrich-Levy condition for time integration. + minimal_temperature: 100.0 # (internal units) + initial_temperature: 268.7 # (internal units) + particle_splitting: 1 # Particle splitting is ON + particle_splitting_mass_threshold: 7e-4 # (internal units, i.e. 7e6 Msun ~ 4x initial gas particle mass) # Parameters of the stars neighbour search Stars: @@ -70,7 +74,8 @@ FOF: Scheduler: max_top_level_cells: 16 tasks_per_cell: 5 - + cell_split_size: 200 + Restarts: onexit: 1 delta_hours: 1.0 @@ -116,7 +121,7 @@ EAGLEStarFormation: min_over_density: 57.7 # The over-density above which star-formation is allowed. KS_high_density_threshold_H_p_cm3: 1e3 # Hydrogen number density above which the Kennicut-Schmidt law changes slope in Hydrogen atoms per cm^3. KS_high_density_exponent: 2.0 # Slope of the Kennicut-Schmidt law above the high-density threshold. - EOS_temperature_margin_dex: 0.5 # Logarithm base 10 of the maximal temperature difference above the EOS allowed to form stars. + EOS_entropy_margin_dex: 0.5 # Logarithm base 10 of the maximal entropy above the EOS at which stars can form. threshold_norm_H_p_cm3: 0.1 # Normalisation of the metal-dependant density threshold for star formation in Hydrogen atoms per cm^3. threshold_Z0: 0.002 # Reference metallicity (metal mass fraction) for the metal-dependant threshold for star formation. threshold_slope: -0.64 # Slope of the metal-dependant star formation threshold @@ -143,9 +148,10 @@ EAGLEFeedback: filename: ./yieldtables/ # Path to the directory containing the EAGLE yield tables. IMF_min_mass_Msun: 0.1 # Minimal stellar mass considered for the Chabrier IMF in solar masses. IMF_max_mass_Msun: 100.0 # Maximal stellar mass considered for the Chabrier IMF in solar masses. - SNII_min_mass_Msun: 6.0 # Minimal mass considered for SNII feedback (not SNII enrichment!) in solar masses. - SNII_max_mass_Msun: 100.0 # Maximal mass considered for SNII feedback (not SNII enrichment!) in solar masses. - SNII_wind_delay_Gyr: 0.03 # Time in Gyr between a star's birth and the SNII thermal feedback event. + SNII_min_mass_Msun: 8.0 # Minimal mass considered for SNII stars in solar masses. + SNII_max_mass_Msun: 100.0 # Maximal mass considered for SNII stars in solar masses. + SNII_sampled_delay: 1 # Sample the SNII lifetimes to do feedback. + SNII_wind_delay_Gyr: dummy # Time in Gyr between a star's birth and the SNII thermal feedback event when not sampling. SNII_delta_T_K: 3.16228e7 # Change in temperature to apply to the gas particle in a SNII thermal feedback event in Kelvin. SNII_energy_erg: 1.0e51 # Energy of one SNII explosion in ergs. SNII_energy_fraction_min: 0.3 # Minimal fraction of energy applied in a SNII feedback event. @@ -154,28 +160,33 @@ EAGLEFeedback: SNII_energy_fraction_n_0_H_p_cm3: 1.4588 # Pivot point for the birth density dependance of the SNII energy fraction in cm^-3. SNII_energy_fraction_n_Z: 0.8686 # Power-law for the metallicity dependance of the SNII energy fraction. SNII_energy_fraction_n_n: 0.8686 # Power-law for the birth density dependance of the SNII energy fraction. - SNIa_max_mass_Msun: 8.0 # Maximal mass considered for SNIa feedback and enrichment in solar masses. - SNIa_timescale_Gyr: 2.0 # Time-scale of the exponential decay of the SNIa rates in Gyr. - SNIa_efficiency_p_Msun: 0.002 # Normalisation of the SNIa rates in inverse solar masses. + SNIa_DTD: PowerLaw # Functional form of the SNIa delay time distribution. + SNIa_DTD_delay_Gyr: 0.04 # Stellar age after which SNIa start in Gyr (40 Myr corresponds to stars ~ 8 Msun). + SNIa_DTD_power_law_norm_p_Msun: 0.0012 # Normalization of the SNIa delay time distribution (in Msun^-1). SNIa_energy_erg: 1.0e51 # Energy of one SNIa explosion in ergs. AGB_ejecta_velocity_km_p_s: 10.0 # Velocity of the AGB ejectas in km/s. + stellar_evolution_age_cut_Gyr: 0.1 # Stellar age in Gyr above which the enrichment is down-sampled. + stellar_evolution_sampling_rate: 10 # Number of time-steps in-between two enrichment events for a star above the age threshold. SNII_yield_factor_Hydrogen: 1.0 # (Optional) Correction factor to apply to the Hydrogen yield from the SNII channel. SNII_yield_factor_Helium: 1.0 # (Optional) Correction factor to apply to the Helium yield from the SNII channel. SNII_yield_factor_Carbon: 0.5 # (Optional) Correction factor to apply to the Carbon yield from the SNII channel. SNII_yield_factor_Nitrogen: 1.0 # (Optional) Correction factor to apply to the Nitrogen yield from the SNII channel. SNII_yield_factor_Oxygen: 1.0 # (Optional) Correction factor to apply to the Oxygen yield from the SNII channel. SNII_yield_factor_Neon: 1.0 # (Optional) Correction factor to apply to the Neon yield from the SNII channel. - SNII_yield_factor_Magnesium: 2.0 # (Optional) Correction factor to apply to the Magnesium yield from the SNII channel. + SNII_yield_factor_Magnesium: 4.0 # (Optional) Correction factor to apply to the Magnesium yield from the SNII channel. SNII_yield_factor_Silicon: 1.0 # (Optional) Correction factor to apply to the Silicon yield from the SNII channel. SNII_yield_factor_Iron: 0.5 # (Optional) Correction factor to apply to the Iron yield from the SNII channel. # EAGLE AGN model EAGLEAGN: subgrid_seed_mass_Msun: 1.5e5 # Black hole subgrid mass at creation time in solar masses. - max_eddington_fraction: 1.5 # Maximal allowed accretion rate in units of the Eddington rate. + max_eddington_fraction: 1.0 # Maximal allowed accretion rate in units of the Eddington rate. + eddington_fraction_for_recording: 0.1 # Record the last time BHs reached an Eddington ratio above this threshold. viscous_alpha: 1e6 # Normalisation constant of the Bondi viscuous time-scale accretion reduction term radiative_efficiency: 0.1 # Fraction of the accreted mass that gets radiated. coupling_efficiency: 0.15 # Fraction of the radiated energy that couples to the gas in feedback events. AGN_delta_T_K: 3.16228e8 # Change in temperature to apply to the gas particle in an AGN feedback event in Kelvin. AGN_num_ngb_to_heat: 1. # Target number of gas neighbours to heat in an AGN feedback event. - max_reposition_mass: 2e8 # Maximal BH mass considered for BH repositioning in solar masses. \ No newline at end of file + max_reposition_mass: 2e8 # Maximal BH mass considered for BH repositioning in solar masses. + threshold_major_merger: 0.333 # Mass ratio threshold to consider a BH merger as 'major' + threshold_minor_merger: 0.1 # Mass ratio threshold to consider a BH merger as 'minor' diff --git a/examples/EAGLE_ICs/EAGLE_25/run.sh b/examples/EAGLE_ICs/EAGLE_25/run.sh index 11e93971767690c84921396842924853fa69ab23..17dcb98069ced54348b9c4050fa68462c1c41c18 100755 --- a/examples/EAGLE_ICs/EAGLE_25/run.sh +++ b/examples/EAGLE_ICs/EAGLE_25/run.sh @@ -7,5 +7,29 @@ then ./getIC.sh fi -../../swift --cosmology --hydro --self-gravity --stars --black-holes --cooling --star-formation --feedback --fof --threads=16 eagle_25.yml 2>&1 | tee output.log +# Grab the cooling and yield tables if they are not present. +if [ ! -e yieldtables ] +then + echo "Fetching EAGLE yield tables..." + ../getEagleYieldtable.sh +fi + +if [ ! -e coolingtables ] +then + echo "Fetching EAGLE cooling tables..." + ../getEagleCoolingTable.sh +fi + +# The following run-time options are broken down by line as: +# Basic run-time options +# Create and run with stars +# Radiative options - run with cooling and stellar feedback +# Run with the time-step limiter required to capture feedback +# Run with black holes - fof is needed for the seeding +# Threading options - run with threads and pinning (latter not required but improves performance) +# The corresponding parameter file for this run +../../swift \ + --cosmology --eagle \ + --threads=16 --pin \ + eagle_25.yml diff --git a/examples/EAGLE_ICs/EAGLE_50/vrconfig_6dfofbound_subhalos_SO_hydro.cfg b/examples/EAGLE_ICs/EAGLE_25/vrconfig_3dfof_subhalos_SO_hydro.cfg similarity index 85% rename from examples/EAGLE_ICs/EAGLE_50/vrconfig_6dfofbound_subhalos_SO_hydro.cfg rename to examples/EAGLE_ICs/EAGLE_25/vrconfig_3dfof_subhalos_SO_hydro.cfg index 45d6a8e7b7ecfeba7832e2dc19b5c11411374c81..8590cbf5bc77e8d7a956d210339cced4bbdc692c 100644 --- a/examples/EAGLE_ICs/EAGLE_50/vrconfig_6dfofbound_subhalos_SO_hydro.cfg +++ b/examples/EAGLE_ICs/EAGLE_25/vrconfig_3dfof_subhalos_SO_hydro.cfg @@ -1,42 +1,51 @@ -#Configuration file for analysing DM particles (in either DM only simulation or in full Hydro) -#runs 6DFOF + substructure algorithm, demands subhalos and FOF halos be self-bound, calculates many properties +#Configuration file for analysing Hydro +#runs 3DFOF + substructure algorithm, demands subhalos and FOF halos be self-bound, calculates many properties #Units currently set to take in as input, Mpc, 1e10 solar masses, km/s, output in same units #To set temporally unique halo ids, alter Snapshot_value=SNAP to appropriate value. Ie: for snapshot 12, change SNAP to 12 ################################ -#unit options, should always be provided +#input options +#set up to use SWIFT HDF input, load gas, star, bh and dark matter ################################ -#EDIT THIS SECTION!!!! - -#naming convention is EAGLE Hydro. This config will be generalised to allow specific naming conventions to be implemented besides predefined ones -HDF_name_convention=6 +HDF_name_convention=6 #HDF SWIFT naming convention +Input_includes_dm_particle=1 #include dark matter particles in hydro input +Input_includes_gas_particle=1 #include gas particles in hydro input Input_includes_star_particle=1 #include star particles in hydro input Input_includes_bh_particle=1 #include bh particles in hydro input Input_includes_wind_particle=0 #include wind particles in hydro input (used by Illustris and moves particle type 0 to particle type 3 when decoupled from hydro forces). Here shown as example Input_includes_tracer_particle=0 #include tracer particles in hydro input (used by Illustris). Here shown as example Input_includes_extradm_particle=0 #include extra dm particles stored in particle type 2 and type 3, useful for zooms +Halo_core_phase_merge_dist=0.25 #merge substructures if difference in dispersion normalised distance is < this value +Apply_phase_merge_to_host=1 #merge substructures with background if centrally located and phase-distance is small #units conversion from input input to desired internal unit -Length_unit=1.0 #default code unit, -Velocity_unit=1.0 #default velocity unit, -Mass_unit=1.0 #default mass unit, +Length_input_unit_conversion_to_output_unit=1.0 #default code unit, +Velocity_input_unit_conversion_to_output_unit=1.0 #default velocity unit, +Mass_input_unit_conversion_to_output_unit=1.0 #default mass unit, #assumes input is in 1e10 msun, Mpc and km/s and output units are the same Gravity=43.0211349 #for 1e10 Msun, km/s and Mpc Hubble_unit=100.0 # assuming units are km/s and Mpc, then value of Hubble in km/s/Mpc +#converting hydro quantities +Stellar_age_input_is_cosmological_scalefactor=1 +Metallicity_input_unit_conversion_to_output_unit=1.0 +Stellar_age_input_unit_conversion_to_output_unit=1.0 +Star_formation_rate_input_unit_conversion_to_output_unit=1.0 +#set the units of the output by providing conversion to a defined unit #conversion of output length units to kpc Length_unit_to_kpc=1000.0 #conversion of output velocity units to km/s Velocity_to_kms=1.0 #conversion of output mass units to solar masses Mass_to_solarmass=1.0e10 +#1 / 0.012 +Metallicity_to_solarmetallicity=83.33 +Star_formation_rate_to_solarmassperyear=97.78 +Stellar_age_to_yr=1.0 +#ensures that output is physical and not comoving distances per little h +Comoving_units=0 -################################ -#input related -################################ -#input is from a cosmological so can use parameters like box size, h, Omega_m to calculate length and density scales -Cosmological_input=1 #sets the total buffer size in bytes used to store temporary particle information #of mpi read threads before they are broadcast to the appropriate waiting non-read threads #if not set, default value is equivalent to 1e6 particles per mpi process, quite large @@ -61,11 +70,11 @@ Singlehalo_search=0 #if file is single halo in which one wishes to search for su Keep_FOF=0 #if field 6DFOF search is done, allows to keep structures found in 3DFOF (can be interpreted as the inter halo stellar mass when only stellar search is used).\n #minimum size for structures -Minimum_size=20 #min particles +Minimum_size=20 #min 20 particles Minimum_halo_size=32 #if field halos have different minimum sizes, otherwise set to -1. #for field fof halo search -FoF_Field_search_type=3 #5 3DFOF search for field halos, 4 for 6DFOF clean up of field halos, 3 for 6DFOF with velocity scale distinct for each initial 3D FOF candidate +FoF_Field_search_type=5 #5 3DFOF search for field halos, 4 for 6DFOF clean up of field halos, 3 for 6DFOF with velocity scale distinct for each initial 3D FOF candidate Halo_3D_linking_length=0.20 #for mean field estimates and local velocity density distribution funciton estimator related quantiites, rarely need to change this @@ -108,26 +117,26 @@ Halo_core_phase_significance=2.0 #how significant a core must be in terms of dis ################################ #Unbinding options (VELOCIraptor is able to accurately identify tidal debris so particles need not be bound to a structure) ################################ + #unbinding related items Unbind_flag=1 #run unbinding #objects must have particles that meet the allowed kinetic to potential ratio AND also have some total fraction that are completely bound. Unbinding_type=0 -#run unbinding of field structures, aka halos. This is useful for sams and 6DFOF halos but may not be useful if interested in 3DFOF mass functions. -Bound_halos=0 #alpha factor used to determine whether particle is "bound" alaph*T+W<0. For standard subhalo catalogues use >0.9 but if interested in tidal debris 0.2-0.5 Allowed_kinetic_potential_ratio=0.95 Min_bound_mass_frac=0.65 #minimum bound mass fraction -#don't keep background potential when unbinding, faster than recalculating +#run unbinding of field structures, aka halos. This is useful for sams and 6DFOF halos but may not be useful if interested in 3DFOF mass functions. +Bound_halos=0 +#don't keep background potential when unbinding Keep_background_potential=1 -Softening_length=0.0 +#use all particles to determine velocity frame for unbinding Frac_pot_ref=1.0 Min_npot_ref=20 +#reference frame only meaningful if calculating velocity frame using subset of particles in object. Can use radially sorted fraction of particles about minimum potential or centre of mass Kinetic_reference_frame_type=0 -#extra options in new unbinding optimisation Unbinding_max_unbound_removal_fraction_per_iteration=0.5 Unbinding_max_unbound_fraction=0.95 -Unbinding_max_unbound_fraction_allowed=0.025 - +Unbinding_max_unbound_fraction_allowed=0.005 ################################ #Calculation of properties related options @@ -139,6 +148,8 @@ Inclusive_halo_masses=3 #calculate inclusive masses for halos using full Spheric Comoving_units=0 #calculate more (sub)halo properties (like angular momentum in spherical overdensity apertures, both inclusive and exclusive) Extensive_halo_properties_output=1 +Extensive_gas_properties_output=1 +Extensive_star_properties_output=1 #calculate aperture masses Calculate_aperture_quantities=1 Number_of_apertures=5 @@ -175,12 +186,6 @@ Snapshot_value=SNAP ################################ #other options ################################ -Verbose=1 #how talkative do you want the code to be, 0 not much, 1 a lot, 2 chatterbox +Verbose=0 #how talkative do you want the code to be, 0 not much, 1 a lot, 2 chatterbox + -Metallicity_to_solarmetallicity=1.0 #conversion of output to solarmetallicity -Star_formation_rate_to_solarmassperyear=1.0 #similar but for star formation rates -Stellar_age_to_yr=1.0 #similar but for stellar ages -Stellar_age_input_is_cosmological_scalefactor=1 #indicates stars store formation scalefactor -Metallicity_input_unit_conversion_to_output_unit=1.0 -Stellar_age_input_unit_conversion_to_output_unit=1.0 -Star_formation_rate_input_unit_conversion_to_output_unit=1.0 diff --git a/examples/EAGLE_ICs/EAGLE_50/eagle_50.yml b/examples/EAGLE_ICs/EAGLE_50/eagle_50.yml index 5877b81afebe5c622b2142cd4b0d16c391aa9771..3d75c944396bcc6b667a830047a9eeb24cc9cdff 100644 --- a/examples/EAGLE_ICs/EAGLE_50/eagle_50.yml +++ b/examples/EAGLE_ICs/EAGLE_50/eagle_50.yml @@ -38,20 +38,24 @@ Statistics: # Parameters for the self-gravity scheme Gravity: eta: 0.025 # Constant dimensionless multiplier for time integration. - theta: 0.5 # Opening angle (Multipole acceptance criterion) + theta: 0.7 # Opening angle (Multipole acceptance criterion) mesh_side_length: 256 - comoving_DM_softening: 0.0026994 # Comoving DM softening length (in internal units). - max_physical_DM_softening: 0.0007 # Max physical DM softening length (in internal units). - comoving_baryon_softening: 0.0026994 # Comoving DM softening length (in internal units). - max_physical_baryon_softening: 0.0007 # Max physical DM softening length (in internal units). - + comoving_DM_softening: 0.003320 # Comoving softening for DM (3.32 ckpc) + max_physical_DM_softening: 0.001300 # Physical softening for DM (1.30 pkpc) + comoving_baryon_softening: 0.001790 # Comoving softening for baryons (1.79 ckpc) + max_physical_baryon_softening: 0.000700 # Physical softening for baryons (0.70 pkpc) + dithering: 0 + # 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). - h_min_ratio: 0.1 # Minimal smoothing in units of softening. - CFL_condition: 0.1 # Courant-Friedrich-Levy condition for time integration. - minimal_temperature: 100.0 # (internal units) - initial_temperature: 268.7 + resolution_eta: 1.2348 # Target smoothing length in units of the mean inter-particle separation (1.2348 == 48Ngbs with the cubic spline kernel). + h_min_ratio: 0.1 # Minimal smoothing in units of softening. + h_max: 0.5 # Maximal softening in co-moving internal units. + CFL_condition: 0.1 # Courant-Friedrich-Levy condition for time integration. + minimal_temperature: 100.0 # (internal units) + initial_temperature: 268.7 # (internal units) + particle_splitting: 1 # Particle splitting is ON + particle_splitting_mass_threshold: 7e-4 # (internal units, i.e. 7e6 Msun ~ 4x initial gas particle mass) # Parameters of the stars neighbour search Stars: @@ -70,7 +74,8 @@ FOF: Scheduler: max_top_level_cells: 32 tasks_per_cell: 5 - + cell_split_size: 200 + Restarts: onexit: 1 delta_hours: 1.0 @@ -116,7 +121,7 @@ EAGLEStarFormation: min_over_density: 57.7 # The over-density above which star-formation is allowed. KS_high_density_threshold_H_p_cm3: 1e3 # Hydrogen number density above which the Kennicut-Schmidt law changes slope in Hydrogen atoms per cm^3. KS_high_density_exponent: 2.0 # Slope of the Kennicut-Schmidt law above the high-density threshold. - EOS_temperature_margin_dex: 0.5 # Logarithm base 10 of the maximal temperature difference above the EOS allowed to form stars. + EOS_entropy_margin_dex: 0.5 # Logarithm base 10 of the maximal entropy above the EOS at which stars can form. threshold_norm_H_p_cm3: 0.1 # Normalisation of the metal-dependant density threshold for star formation in Hydrogen atoms per cm^3. threshold_Z0: 0.002 # Reference metallicity (metal mass fraction) for the metal-dependant threshold for star formation. threshold_slope: -0.64 # Slope of the metal-dependant star formation threshold @@ -143,9 +148,10 @@ EAGLEFeedback: filename: ./yieldtables/ # Path to the directory containing the EAGLE yield tables. IMF_min_mass_Msun: 0.1 # Minimal stellar mass considered for the Chabrier IMF in solar masses. IMF_max_mass_Msun: 100.0 # Maximal stellar mass considered for the Chabrier IMF in solar masses. - SNII_min_mass_Msun: 6.0 # Minimal mass considered for SNII feedback (not SNII enrichment!) in solar masses. - SNII_max_mass_Msun: 100.0 # Maximal mass considered for SNII feedback (not SNII enrichment!) in solar masses. - SNII_wind_delay_Gyr: 0.03 # Time in Gyr between a star's birth and the SNII thermal feedback event. + SNII_min_mass_Msun: 8.0 # Minimal mass considered for SNII stars in solar masses. + SNII_max_mass_Msun: 100.0 # Maximal mass considered for SNII stars in solar masses. + SNII_sampled_delay: 1 # Sample the SNII lifetimes to do feedback. + SNII_wind_delay_Gyr: dummy # Time in Gyr between a star's birth and the SNII thermal feedback event when not sampling. SNII_delta_T_K: 3.16228e7 # Change in temperature to apply to the gas particle in a SNII thermal feedback event in Kelvin. SNII_energy_erg: 1.0e51 # Energy of one SNII explosion in ergs. SNII_energy_fraction_min: 0.3 # Minimal fraction of energy applied in a SNII feedback event. @@ -154,28 +160,33 @@ EAGLEFeedback: SNII_energy_fraction_n_0_H_p_cm3: 1.4588 # Pivot point for the birth density dependance of the SNII energy fraction in cm^-3. SNII_energy_fraction_n_Z: 0.8686 # Power-law for the metallicity dependance of the SNII energy fraction. SNII_energy_fraction_n_n: 0.8686 # Power-law for the birth density dependance of the SNII energy fraction. - SNIa_max_mass_Msun: 8.0 # Maximal mass considered for SNIa feedback and enrichment in solar masses. - SNIa_timescale_Gyr: 2.0 # Time-scale of the exponential decay of the SNIa rates in Gyr. - SNIa_efficiency_p_Msun: 0.002 # Normalisation of the SNIa rates in inverse solar masses. + SNIa_DTD: PowerLaw # Functional form of the SNIa delay time distribution. + SNIa_DTD_delay_Gyr: 0.04 # Stellar age after which SNIa start in Gyr (40 Myr corresponds to stars ~ 8 Msun). + SNIa_DTD_power_law_norm_p_Msun: 0.0012 # Normalization of the SNIa delay time distribution (in Msun^-1). SNIa_energy_erg: 1.0e51 # Energy of one SNIa explosion in ergs. AGB_ejecta_velocity_km_p_s: 10.0 # Velocity of the AGB ejectas in km/s. + stellar_evolution_age_cut_Gyr: 0.1 # Stellar age in Gyr above which the enrichment is down-sampled. + stellar_evolution_sampling_rate: 10 # Number of time-steps in-between two enrichment events for a star above the age threshold. SNII_yield_factor_Hydrogen: 1.0 # (Optional) Correction factor to apply to the Hydrogen yield from the SNII channel. SNII_yield_factor_Helium: 1.0 # (Optional) Correction factor to apply to the Helium yield from the SNII channel. SNII_yield_factor_Carbon: 0.5 # (Optional) Correction factor to apply to the Carbon yield from the SNII channel. SNII_yield_factor_Nitrogen: 1.0 # (Optional) Correction factor to apply to the Nitrogen yield from the SNII channel. SNII_yield_factor_Oxygen: 1.0 # (Optional) Correction factor to apply to the Oxygen yield from the SNII channel. SNII_yield_factor_Neon: 1.0 # (Optional) Correction factor to apply to the Neon yield from the SNII channel. - SNII_yield_factor_Magnesium: 2.0 # (Optional) Correction factor to apply to the Magnesium yield from the SNII channel. + SNII_yield_factor_Magnesium: 4.0 # (Optional) Correction factor to apply to the Magnesium yield from the SNII channel. SNII_yield_factor_Silicon: 1.0 # (Optional) Correction factor to apply to the Silicon yield from the SNII channel. SNII_yield_factor_Iron: 0.5 # (Optional) Correction factor to apply to the Iron yield from the SNII channel. # EAGLE AGN model EAGLEAGN: subgrid_seed_mass_Msun: 1.5e5 # Black hole subgrid mass at creation time in solar masses. - max_eddington_fraction: 1.5 # Maximal allowed accretion rate in units of the Eddington rate. + max_eddington_fraction: 1.0 # Maximal allowed accretion rate in units of the Eddington rate. + eddington_fraction_for_recording: 0.1 # Record the last time BHs reached an Eddington ratio above this threshold. viscous_alpha: 1e6 # Normalisation constant of the Bondi viscuous time-scale accretion reduction term radiative_efficiency: 0.1 # Fraction of the accreted mass that gets radiated. coupling_efficiency: 0.15 # Fraction of the radiated energy that couples to the gas in feedback events. AGN_delta_T_K: 3.16228e8 # Change in temperature to apply to the gas particle in an AGN feedback event in Kelvin. AGN_num_ngb_to_heat: 1. # Target number of gas neighbours to heat in an AGN feedback event. max_reposition_mass: 2e8 # Maximal BH mass considered for BH repositioning in solar masses. + threshold_major_merger: 0.333 # Mass ratio threshold to consider a BH merger as 'major' + threshold_minor_merger: 0.1 # Mass ratio threshold to consider a BH merger as 'minor' diff --git a/examples/EAGLE_ICs/EAGLE_50/run.sh b/examples/EAGLE_ICs/EAGLE_50/run.sh index 492ac35ebe1af20392aff879aef078c0f9bd264f..18e8f5cfce0600fad349a66f650d9b1557e9d5ff 100755 --- a/examples/EAGLE_ICs/EAGLE_50/run.sh +++ b/examples/EAGLE_ICs/EAGLE_50/run.sh @@ -7,5 +7,29 @@ then ./getIC.sh fi -../../swift --cosmology --hydro --self-gravity --stars --black-holes --cooling --star-formation --feedback --fof --threads=16 eagle_50.yml 2>&1 | tee output.log +# Grab the cooling and yield tables if they are not present. +if [ ! -e yieldtables ] +then + echo "Fetching EAGLE yield tables..." + ../getEagleYieldtable.sh +fi + +if [ ! -e coolingtables ] +then + echo "Fetching EAGLE cooling tables..." + ../getEagleCoolingTable.sh +fi + +# The following run-time options are broken down by line as: +# Basic run-time options +# Create and run with stars +# Radiative options - run with cooling and stellar feedback +# Run with the time-step limiter required to capture feedback +# Run with black holes - fof is needed for the seeding +# Threading options - run with threads and pinning (latter not required but improves performance) +# The corresponding parameter file for this run +../../swift \ + --cosmology --eagle \ + --threads=16 --pin \ + eagle_50.yml diff --git a/examples/SmallCosmoVolume/SmallCosmoVolume_VELOCIraptor/stfconfig_input.cfg b/examples/EAGLE_ICs/EAGLE_50/vrconfig_3dfof_subhalos_SO_hydro.cfg similarity index 54% rename from examples/SmallCosmoVolume/SmallCosmoVolume_VELOCIraptor/stfconfig_input.cfg rename to examples/EAGLE_ICs/EAGLE_50/vrconfig_3dfof_subhalos_SO_hydro.cfg index 4306bae3d23aab924ce8fa3a5c50e839823fbc2f..8590cbf5bc77e8d7a956d210339cced4bbdc692c 100644 --- a/examples/SmallCosmoVolume/SmallCosmoVolume_VELOCIraptor/stfconfig_input.cfg +++ b/examples/EAGLE_ICs/EAGLE_50/vrconfig_3dfof_subhalos_SO_hydro.cfg @@ -1,10 +1,50 @@ -#suggested configuration file for hydro run and subhalo (and galaxy ie: associated baryons) catalog +#Configuration file for analysing Hydro +#runs 3DFOF + substructure algorithm, demands subhalos and FOF halos be self-bound, calculates many properties +#Units currently set to take in as input, Mpc, 1e10 solar masses, km/s, output in same units +#To set temporally unique halo ids, alter Snapshot_value=SNAP to appropriate value. Ie: for snapshot 12, change SNAP to 12 ################################ -#input related +#input options +#set up to use SWIFT HDF input, load gas, star, bh and dark matter ################################ -#input is from a cosmological so can use parameters like box size, h, Omega_m to calculate length and density scales -Cosmological_input=1 +HDF_name_convention=6 #HDF SWIFT naming convention +Input_includes_dm_particle=1 #include dark matter particles in hydro input +Input_includes_gas_particle=1 #include gas particles in hydro input +Input_includes_star_particle=1 #include star particles in hydro input +Input_includes_bh_particle=1 #include bh particles in hydro input +Input_includes_wind_particle=0 #include wind particles in hydro input (used by Illustris and moves particle type 0 to particle type 3 when decoupled from hydro forces). Here shown as example +Input_includes_tracer_particle=0 #include tracer particles in hydro input (used by Illustris). Here shown as example +Input_includes_extradm_particle=0 #include extra dm particles stored in particle type 2 and type 3, useful for zooms + +Halo_core_phase_merge_dist=0.25 #merge substructures if difference in dispersion normalised distance is < this value +Apply_phase_merge_to_host=1 #merge substructures with background if centrally located and phase-distance is small + +#units conversion from input input to desired internal unit +Length_input_unit_conversion_to_output_unit=1.0 #default code unit, +Velocity_input_unit_conversion_to_output_unit=1.0 #default velocity unit, +Mass_input_unit_conversion_to_output_unit=1.0 #default mass unit, +#assumes input is in 1e10 msun, Mpc and km/s and output units are the same +Gravity=43.0211349 #for 1e10 Msun, km/s and Mpc +Hubble_unit=100.0 # assuming units are km/s and Mpc, then value of Hubble in km/s/Mpc +#converting hydro quantities +Stellar_age_input_is_cosmological_scalefactor=1 +Metallicity_input_unit_conversion_to_output_unit=1.0 +Stellar_age_input_unit_conversion_to_output_unit=1.0 +Star_formation_rate_input_unit_conversion_to_output_unit=1.0 + +#set the units of the output by providing conversion to a defined unit +#conversion of output length units to kpc +Length_unit_to_kpc=1000.0 +#conversion of output velocity units to km/s +Velocity_to_kms=1.0 +#conversion of output mass units to solar masses +Mass_to_solarmass=1.0e10 +#1 / 0.012 +Metallicity_to_solarmetallicity=83.33 +Star_formation_rate_to_solarmassperyear=97.78 +Stellar_age_to_yr=1.0 +#ensures that output is physical and not comoving distances per little h +Comoving_units=0 #sets the total buffer size in bytes used to store temporary particle information #of mpi read threads before they are broadcast to the appropriate waiting non-read threads @@ -14,67 +54,31 @@ Cosmological_input=1 #for 100 mpi processes MPI_particle_total_buf_size=100000000 -#gadget input related -#NSPH_extra_blocks=0 #read extra sph blocks -#NStar_extra_blocks=0 #read extra star blocks -#NBH_extra_blocks=0 #read extra black hole blocks - -#HDF related input -#Set the HDF name convection, 0 is illustris, 1 is gadget x, 2 is Eagle, 3 is gizmo -HDF_name_convention=0 -#whether star particles are present in the input -Input_includes_star_particle=1 -#bhs present -Input_includes_bh_particle=1 -#no wind present -Input_includes_wind_particle=0 -#no tracers present -Input_includes_tracer_particle=0 -#no low res/extra dm particle types present -Input_includes_extradm_particle=0 - -################################ -#unit options, should always be provided -################################ -#EDIT THIS SECTION!!!! -#conversion of output length units to kpc -Length_unit_to_kpc=1.0 -#conversion of output velocity units to km/s -Velocity_to_kms=1.0 -#conversion of output mass units to solar masses -Mass_to_solarmass=1.0 -#units conversion from input input to desired internal unit -Length_unit=1.0 #default code unit, -Velocity_unit=1.0 #default velocity unit, -Mass_unit=1.0 #default mass unit, -Gravity=43.0211349 #for 1e10 Msun, km/s and Mpc -Hubble_unit=100.0 # assuming units are km/s and Mpc, then value of Hubble in km/s/Mpc - ################################ #search related options ################################ #how to search a simulation -Particle_search_type=1 #search all particles, see allvars for other types +Particle_search_type=1 #search dark matter particles only #for baryon search Baryon_searchflag=2 #if 1 search for baryons separately using phase-space search when identifying substructures, 2 allows special treatment in field FOF linking and phase-space substructure search, 0 treat the same as dark matter particles #for search for substruture Search_for_substructure=1 #if 0, end search once field objects are found #also useful for zoom simulations or simulations of individual objects, setting this flag means no field structure search is run -Singlehalo_search=0 #if file is single halo in which one wishes to search for substructure +Singlehalo_search=0 #if file is single halo in which one wishes to search for substructure. Here disabled. #additional option for field haloes Keep_FOF=0 #if field 6DFOF search is done, allows to keep structures found in 3DFOF (can be interpreted as the inter halo stellar mass when only stellar search is used).\n #minimum size for structures Minimum_size=20 #min 20 particles -Minimum_halo_size=-1 #if field halos have different minimum sizes, otherwise set to -1. +Minimum_halo_size=32 #if field halos have different minimum sizes, otherwise set to -1. #for field fof halo search -FoF_Field_search_type=3 #5 3DFOF search for field halos, 4 for 6DFOF clean up of field halos, 3 for 6DFOF with velocity scale distinct for each halo -Halo_linking_length_factor=2.0 #factor by which Physical_linking_length is changed when searching for field halos. Typical values are ~2 when using iterative substructure search. -Halo_velocity_linking_length_factor=5.0 #for 6d fof halo search increase ellv from substructure search +FoF_Field_search_type=5 #5 3DFOF search for field halos, 4 for 6DFOF clean up of field halos, 3 for 6DFOF with velocity scale distinct for each initial 3D FOF candidate +Halo_3D_linking_length=0.20 #for mean field estimates and local velocity density distribution funciton estimator related quantiites, rarely need to change this +Local_velocity_density_approximate_calculation=1 #calculates velocity density using approximative (and quicker) near neighbour search Cell_fraction = 0.01 #fraction of field fof halo used to determine mean velocity distribution function. Typical values are ~0.005-0.02 Grid_type=1 #normal entropy based grid, shouldn't have to change Nsearch_velocity=32 #number of velocity neighbours used to calculate local velocity distribution function. Typial values are ~32 @@ -84,15 +88,15 @@ Nsearch_physical=256 #numerof physical neighbours from which the nearest velocit FoF_search_type=1 #default phase-space FOF search. Don't really need to change Iterative_searchflag=1 #iterative substructure search, for substructure find initial candidate substructures with smaller linking lengths then expand search region Outlier_threshold=2.5 #outlier threshold for a particle to be considered residing in substructure, that is how dynamically distinct a particle is. Typical values are >2 +Substructure_physical_linking_length=0.10 Velocity_ratio=2.0 #ratio of speeds used in phase-space FOF Velocity_opening_angle=0.10 #angle between velocities. 18 degrees here, typical values are ~10-30 -Physical_linking_length=0.10 #physical linking length. IF reading periodic volumes in gadget/hdf/ramses, in units of the effective inter-particle spacing. Otherwise in user defined code units. Here set to 0.10 as iterative flag one, values of 0.1-0.3 are typical. Velocity_linking_length=0.20 #where scaled by structure dispersion Significance_level=1.0 #how significant a substructure is relative to Poisson noise. Values >= 1 are fine. #for iterative substructure search, rarely ever need to change this Iterative_threshold_factor=1.0 #change in threshold value when using iterative search. Here no increase in threshold if iterative or not -Iterative_linking_length_factor=2.0 #increase in final linking final iterative substructure search will be sqrt(2.25)*this factor +Iterative_linking_length_factor=2.0 #increase in final linking final iterative substructure search Iterative_Vratio_factor=1.0 #change in Vratio when using iterative search. no change in vratio Iterative_ThetaOp_factor=1.0 #change in velocity opening angle. no change in velocity opening angle @@ -116,41 +120,61 @@ Halo_core_phase_significance=2.0 #how significant a core must be in terms of dis #unbinding related items Unbind_flag=1 #run unbinding +#objects must have particles that meet the allowed kinetic to potential ratio AND also have some total fraction that are completely bound. +Unbinding_type=0 #alpha factor used to determine whether particle is "bound" alaph*T+W<0. For standard subhalo catalogues use >0.9 but if interested in tidal debris 0.2-0.5 Allowed_kinetic_potential_ratio=0.95 -#run unbinding of field structures, aka halos +Min_bound_mass_frac=0.65 #minimum bound mass fraction +#run unbinding of field structures, aka halos. This is useful for sams and 6DFOF halos but may not be useful if interested in 3DFOF mass functions. Bound_halos=0 -#simple Plummer softening length when calculating gravitational energy. If cosmological simulation with period, is fraction of interparticle spacing -Softening_length=0. #don't keep background potential when unbinding -Keep_background_potential=0 - -################################ -#Cosmological parameters -#this is typically overwritten by information in the gadget/hdf header if those input file types are read -################################ -h_val=1.0 -Omega_m=0.3 -Omega_Lambda=0.7 -Critical_density=1.0 -Virial_density=200 #so-called virial overdensity value -Omega_b=0. #no baryons +Keep_background_potential=1 +#use all particles to determine velocity frame for unbinding +Frac_pot_ref=1.0 +Min_npot_ref=20 +#reference frame only meaningful if calculating velocity frame using subset of particles in object. Can use radially sorted fraction of particles about minimum potential or centre of mass +Kinetic_reference_frame_type=0 +Unbinding_max_unbound_removal_fraction_per_iteration=0.5 +Unbinding_max_unbound_fraction=0.95 +Unbinding_max_unbound_fraction_allowed=0.005 ################################ #Calculation of properties related options ################################ +Virial_density=500 #user defined virial overdensity. Note that 200 rho_c, 200 rho_m and BN98 are already calculated. #when calculating properties, for field objects calculate inclusive masses -Inclusive_halo_masses=1 #calculate inclusive masses -#ensures that output is comoving distances per little h +Inclusive_halo_masses=3 #calculate inclusive masses for halos using full Spherical overdensity apertures +#ensures that output is physical and not comoving distances per little h Comoving_units=0 +#calculate more (sub)halo properties (like angular momentum in spherical overdensity apertures, both inclusive and exclusive) +Extensive_halo_properties_output=1 +Extensive_gas_properties_output=1 +Extensive_star_properties_output=1 +#calculate aperture masses +Calculate_aperture_quantities=1 +Number_of_apertures=5 +Aperture_values_in_kpc=5,10,30,50,100, +Number_of_projected_apertures=5 +Projected_aperture_values_in_kpc=5,10,30,50,100, +#calculate radial profiles +Calculate_radial_profiles=1 +Number_of_radial_profile_bin_edges=20 +#default radial normalisation log rad bins, normed by R200crit, Integer flag of 0 is log bins and R200crit norm. +Radial_profile_norm=0 +Radial_profile_bin_edges=-2.,-1.87379263,-1.74758526,-1.62137789,-1.49517052,-1.36896316,-1.24275579,-1.11654842,-0.99034105,-0.86413368,-0.73792631,-0.61171894,-0.48551157,-0.3593042,-0.23309684,-0.10688947,0.0193179,0.14552527,0.27173264,0.39794001, +Iterate_cm_flag=0 #do not interate to determine centre-of-mass +Sort_by_binding_energy=1 #sort particles by binding energy +Reference_frame_for_properties=2 #use the minimum potential as reference frame about which to calculate properties ################################ #output related ################################ -Write_group_array_file=0 #write a group array file -Separate_output_files=0 #separate output into field and substructure files similar to subfind -Binary_output=2 #binary output 1, ascii 0, and HDF 2 +Write_group_array_file=0 #do not write a group array file +Separate_output_files=0 #do not separate output into field and substructure files similar to subfind +Binary_output=2 #Use HDF5 output (binary output 1, ascii 0, and HDF 2) +#output particles residing in the spherical overdensity apertures of halos, only the particles exclusively belonging to halos +Spherical_overdensity_halo_particle_list_output=1 #halo ids are adjusted by this value * 1000000000000 (or 1000000 if code compiled with the LONGINTS option turned off) #to ensure that halo ids are temporally unique. So if you had 100 snapshots, for snap 100 set this to 100 and 100*1000000000000 will @@ -163,3 +187,5 @@ Snapshot_value=SNAP #other options ################################ Verbose=0 #how talkative do you want the code to be, 0 not much, 1 a lot, 2 chatterbox + + diff --git a/examples/EAGLE_ICs/README b/examples/EAGLE_ICs/README index 2ea665219ad126f08128f561fff6db1f10b5667e..ea352da4e1799bedfad89b9a7874890eef5ab0d2 100644 --- a/examples/EAGLE_ICs/README +++ b/examples/EAGLE_ICs/README @@ -3,6 +3,42 @@ the EAGLE suite of simulations. The cosmology, resolution and phases are the same as used in the original suite. The only difference is the file format, adapted for SWIFT. +Compared to the original EAGLE runs of Schaye et al. 2015), +the following changes have been made: + + - The dark matter softening lengths have been increased to 1.3 + pkpc and 3.32 ckpc. The comoving baryon softening lengths have + been changed to 1.79 ckpc. This follows the recommendations of + Ludlow et al. 2019. Old values were 0.7 pkpc and 2.69 ckpc for + all the particle species. + - SPH particles with a mass larger than 7*10^6 Msun (~4x the initial + gas particle mass) are now split into 2 equal mass particles + within the smoothing length of the original particle. + - The metallicity-dependent density threshold for star formation + uses the smoothed metallicities and not the raw metallicities + any more. + - The redshift of H reionization has been lowered to 7.5 (from 11.5). + - The minimal mass of SNII stars has been raised to 8 Msun (from 6). + - The SNII feedback delay is done by sampling the stellar age + distribution and not using a fixed delay of 30 Myr any more. + - The Magnesium yields from SNII stars have been boosted by a + factor of 2. + - The delay time distribution of the SNIa has been changed to a + power-law of slope -1 (instead of the exponential model) and + the rates have been renormalized. + - The black hole accretion rate is now limited to 100% of the + Eddington rate (from 100/h = 150 %). + The scripts in this directory download the tables required to run the EAGLE model. Plotting scripts are also provided for basic quantities. + +VELOCIraptor can be run on the output. The code is compiled +using + +cmake -DVR_USE_GAS=ON -DVR_USE_STAR=ON -DV_USE_BH=ON + +and run using + +stf -C vrconfig_3dfof_subhalos_SO_hydro.cfg -i eagle_0035 -o halos_0035 -I 2 + diff --git a/examples/EAGLE_low_z/EAGLE_100/eagle_100.yml b/examples/EAGLE_low_z/EAGLE_100/eagle_100.yml index 0cc97babbd2b89a7507808bfcad2648e0c03ce47..5d1201786a5efbe803231edea78cfd2593641347 100644 --- a/examples/EAGLE_low_z/EAGLE_100/eagle_100.yml +++ b/examples/EAGLE_low_z/EAGLE_100/eagle_100.yml @@ -46,6 +46,7 @@ Gravity: eta: 0.025 # Constant dimensionless multiplier for time integration. theta: 0.85 # Opening angle (Multipole acceptance criterion) mesh_side_length: 256 + dithering: 0 comoving_DM_softening: 0.0026994 # Comoving DM softening length (in internal units). max_physical_DM_softening: 0.0007 # Max physical DM softening length (in internal units). comoving_baryon_softening: 0.0026994 # Comoving DM softening length (in internal units). @@ -55,6 +56,7 @@ 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). h_min_ratio: 0.1 # Minimal smoothing in units of softening. + h_max: 0.5 # Maximal softening in co-moving internal units. CFL_condition: 0.1 # Courant-Friedrich-Levy condition for time integration. minimal_temperature: 100 # (internal units) overwrite_birth_time: 1 diff --git a/examples/EAGLE_low_z/EAGLE_12/eagle_12.yml b/examples/EAGLE_low_z/EAGLE_12/eagle_12.yml index 734b25399c2975d9d52369a54496c323b9f99f1b..5dd89214eb877e1991bc718e48b8a54ad5a887e6 100644 --- a/examples/EAGLE_low_z/EAGLE_12/eagle_12.yml +++ b/examples/EAGLE_low_z/EAGLE_12/eagle_12.yml @@ -47,17 +47,22 @@ Gravity: eta: 0.025 # Constant dimensionless multiplier for time integration. theta: 0.7 # Opening angle (Multipole acceptance criterion) mesh_side_length: 32 + dithering: 0 comoving_DM_softening: 0.0026994 # Comoving DM softening length (in internal units). max_physical_DM_softening: 0.0007 # Max physical DM softening length (in internal units). comoving_baryon_softening: 0.0026994 # Comoving DM softening length (in internal units). max_physical_baryon_softening: 0.0007 # Max physical DM softening length (in internal units). + # Parameters for the hydrodynamics scheme SPH: - resolution_eta: 1.2348 # Target smoothing length in units of the mean inter-particle separation (1.2348 == 48Ngbs with the cubic spline kernel). - h_min_ratio: 0.1 # Minimal smoothing in units of softening. - CFL_condition: 0.1 # Courant-Friedrich-Levy condition for time integration. - minimal_temperature: 100 # (internal units) + resolution_eta: 1.2348 # Target smoothing length in units of the mean inter-particle separation (1.2348 == 48Ngbs with the cubic spline kernel). + h_min_ratio: 0.1 # Minimal smoothing in units of softening. + h_max: 0.5 # Maximal softening in co-moving internal units. + CFL_condition: 0.1 # Courant-Friedrich-Levy condition for time integration. + minimal_temperature: 100 # (internal units) + particle_splitting: 1 + particle_splitting_mass_threshold: 7e-4 # Internal units (i.e. 7e6 Msun ~ 4 times the initial gas mass) # Parameters of the stars neighbour search Stars: @@ -112,7 +117,7 @@ EAGLEStarFormation: min_over_density: 57.7 # The over-density above which star-formation is allowed. KS_high_density_threshold_H_p_cm3: 1e3 # Hydrogen number density above which the Kennicut-Schmidt law changes slope in Hydrogen atoms per cm^3. KS_high_density_exponent: 2.0 # Slope of the Kennicut-Schmidt law above the high-density threshold. - EOS_temperature_margin_dex: 0.5 # Logarithm base 10 of the maximal temperature difference above the EOS allowed to form stars. + EOS_entropy_margin_dex: 0.5 # Logarithm base 10 of the maximal entropy above the EOS at which stars can form. threshold_norm_H_p_cm3: 0.1 # Normalisation of the metal-dependant density threshold for star formation in Hydrogen atoms per cm^3. threshold_Z0: 0.002 # Reference metallicity (metal mass fraction) for the metal-dependant threshold for star formation. threshold_slope: -0.64 # Slope of the metal-dependant star formation threshold @@ -139,9 +144,10 @@ EAGLEFeedback: filename: ./yieldtables/ # Path to the directory containing the EAGLE yield tables. IMF_min_mass_Msun: 0.1 # Minimal stellar mass considered for the Chabrier IMF in solar masses. IMF_max_mass_Msun: 100.0 # Maximal stellar mass considered for the Chabrier IMF in solar masses. - SNII_min_mass_Msun: 6.0 # Minimal mass considered for SNII feedback (not SNII enrichment!) in solar masses. - SNII_max_mass_Msun: 100.0 # Maximal mass considered for SNII feedback (not SNII enrichment!) in solar masses. - SNII_wind_delay_Gyr: 0.03 # Time in Gyr between a star's birth and the SNII thermal feedback event. + SNII_min_mass_Msun: 6.0 # Minimal mass considered for SNII stars in solar masses. + SNII_max_mass_Msun: 100.0 # Maximal mass considered for SNII stars in solar masses. + SNII_sampled_delay: 0 # Sample the SNII lifetimes to do feedback. + SNII_wind_delay_Gyr: 0.03 # Time in Gyr between a star's birth and the SNII thermal feedback event when not sampling. SNII_delta_T_K: 3.16228e7 # Change in temperature to apply to the gas particle in a SNII thermal feedback event in Kelvin. SNII_energy_erg: 1.0e51 # Energy of one SNII explosion in ergs. SNII_energy_fraction_min: 0.3 # Minimal fraction of energy applied in a SNII feedback event. @@ -150,11 +156,13 @@ EAGLEFeedback: SNII_energy_fraction_n_0_H_p_cm3: 1.4588 # Pivot point for the birth density dependance of the SNII energy fraction in cm^-3. SNII_energy_fraction_n_Z: 0.8686 # Power-law for the metallicity dependance of the SNII energy fraction. SNII_energy_fraction_n_n: 0.8686 # Power-law for the birth density dependance of the SNII energy fraction. - SNIa_max_mass_Msun: 8.0 # Maximal mass considered for SNIa feedback and enrichment in solar masses. - SNIa_timescale_Gyr: 2.0 # Time-scale of the exponential decay of the SNIa rates in Gyr. - SNIa_efficiency_p_Msun: 0.002 # Normalisation of the SNIa rates in inverse solar masses. + SNIa_DTD: PowerLaw # Functional form of the SNIa delay time distribution. + SNIa_DTD_delay_Gyr: 0.04 # Stellar age after which SNIa start in Gyr (40 Myr corresponds to stars ~ 8 Msun). + SNIa_DTD_power_law_norm_p_Msun: 0.0012 # Normalization of the SNIa delay time distribution (in Msun^-1). SNIa_energy_erg: 1.0e51 # Energy of one SNIa explosion in ergs. AGB_ejecta_velocity_km_p_s: 10.0 # Velocity of the AGB ejectas in km/s. + stellar_evolution_age_cut_Gyr: 0.1 # Stellar age in Gyr above which the enrichment is down-sampled. + stellar_evolution_sampling_rate: 10 # Number of time-steps in-between two enrichment events for a star above the age threshold. SNII_yield_factor_Hydrogen: 1.0 # (Optional) Correction factor to apply to the Hydrogen yield from the SNII channel. SNII_yield_factor_Helium: 1.0 # (Optional) Correction factor to apply to the Helium yield from the SNII channel. SNII_yield_factor_Carbon: 0.5 # (Optional) Correction factor to apply to the Carbon yield from the SNII channel. @@ -169,9 +177,12 @@ EAGLEFeedback: EAGLEAGN: subgrid_seed_mass_Msun: 1.5e5 # Black hole subgrid mass at creation time in solar masses. max_eddington_fraction: 1.5 # Maximal allowed accretion rate in units of the Eddington rate. + eddington_fraction_for_recording: 0.1 # Record the last time BHs reached an Eddington ratio above this threshold. viscous_alpha: 1e6 # Normalisation constant of the Bondi viscuous time-scale accretion reduction term radiative_efficiency: 0.1 # Fraction of the accreted mass that gets radiated. coupling_efficiency: 0.15 # Fraction of the radiated energy that couples to the gas in feedback events. AGN_delta_T_K: 3.16228e8 # Change in temperature to apply to the gas particle in an AGN feedback event in Kelvin. AGN_num_ngb_to_heat: 1. # Target number of gas neighbours to heat in an AGN feedback event. - max_reposition_mass: 2e8 # Maximal BH mass considered for BH repositioning in solar masses. \ No newline at end of file + max_reposition_mass: 2e8 # Maximal BH mass considered for BH repositioning in solar masses. + threshold_major_merger: 0.333 # Mass ratio threshold to consider a BH merger as 'major' + threshold_minor_merger: 0.1 # Mass ratio threshold to consider a BH merger as 'minor' diff --git a/examples/EAGLE_low_z/EAGLE_25/eagle_25.yml b/examples/EAGLE_low_z/EAGLE_25/eagle_25.yml index 29e0af03e8f58374a7f9aa02317cf639eae0e269..fe1aeb358df31f785897e5ce9e3463fab96497a5 100644 --- a/examples/EAGLE_low_z/EAGLE_25/eagle_25.yml +++ b/examples/EAGLE_low_z/EAGLE_25/eagle_25.yml @@ -54,6 +54,7 @@ Gravity: eta: 0.025 # Constant dimensionless multiplier for time integration. theta: 0.7 # Opening angle (Multipole acceptance criterion) mesh_side_length: 64 + dithering: 0 comoving_DM_softening: 0.0026994 # Comoving DM softening length (in internal units). max_physical_DM_softening: 0.0007 # Max physical DM softening length (in internal units). comoving_baryon_softening: 0.0026994 # Comoving DM softening length (in internal units). @@ -62,10 +63,13 @@ Gravity: # 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). - h_min_ratio: 0.1 # Minimal smoothing in units of softening. - CFL_condition: 0.1 # Courant-Friedrich-Levy condition for time integration. - minimal_temperature: 100 # (internal units) + resolution_eta: 1.2348 # Target smoothing length in units of the mean inter-particle separation (1.2348 == 48Ngbs with the cubic spline kernel). + h_min_ratio: 0.1 # Minimal smoothing in units of softening. + h_max: 0.5 # Maximal softening in co-moving internal units. + CFL_condition: 0.1 # Courant-Friedrich-Levy condition for time integration. + minimal_temperature: 100 # (internal units) + particle_splitting: 1 + particle_splitting_mass_threshold: 7e-4 # Internal units (i.e. 7e6 Msun ~ 4 times the initial gas mass) # Parameters of the stars neighbour search Stars: @@ -120,7 +124,7 @@ EAGLEStarFormation: min_over_density: 57.7 # The over-density above which star-formation is allowed. KS_high_density_threshold_H_p_cm3: 1e3 # Hydrogen number density above which the Kennicut-Schmidt law changes slope in Hydrogen atoms per cm^3. KS_high_density_exponent: 2.0 # Slope of the Kennicut-Schmidt law above the high-density threshold. - EOS_temperature_margin_dex: 0.5 # Logarithm base 10 of the maximal temperature difference above the EOS allowed to form stars. + EOS_entropy_margin_dex: 0.5 # Logarithm base 10 of the maximal entropy above the EOS at which stars can form. threshold_norm_H_p_cm3: 0.1 # Normalisation of the metal-dependant density threshold for star formation in Hydrogen atoms per cm^3. threshold_Z0: 0.002 # Reference metallicity (metal mass fraction) for the metal-dependant threshold for star formation. threshold_slope: -0.64 # Slope of the metal-dependant star formation threshold @@ -147,9 +151,10 @@ EAGLEFeedback: filename: ./yieldtables/ # Path to the directory containing the EAGLE yield tables. IMF_min_mass_Msun: 0.1 # Minimal stellar mass considered for the Chabrier IMF in solar masses. IMF_max_mass_Msun: 100.0 # Maximal stellar mass considered for the Chabrier IMF in solar masses. - SNII_min_mass_Msun: 6.0 # Minimal mass considered for SNII feedback (not SNII enrichment!) in solar masses. - SNII_max_mass_Msun: 100.0 # Maximal mass considered for SNII feedback (not SNII enrichment!) in solar masses. - SNII_wind_delay_Gyr: 0.03 # Time in Gyr between a star's birth and the SNII thermal feedback event. + SNII_min_mass_Msun: 6.0 # Minimal mass considered for SNII stars in solar masses. + SNII_max_mass_Msun: 100.0 # Maximal mass considered for SNII stars in solar masses. + SNII_sampled_delay: 0 # Sample the SNII lifetimes to do feedback. + SNII_wind_delay_Gyr: 0.03 # Time in Gyr between a star's birth and the SNII thermal feedback event when not sampling. SNII_delta_T_K: 3.16228e7 # Change in temperature to apply to the gas particle in a SNII thermal feedback event in Kelvin. SNII_energy_erg: 1.0e51 # Energy of one SNII explosion in ergs. SNII_energy_fraction_min: 0.3 # Minimal fraction of energy applied in a SNII feedback event. @@ -158,11 +163,13 @@ EAGLEFeedback: SNII_energy_fraction_n_0_H_p_cm3: 1.4588 # Pivot point for the birth density dependance of the SNII energy fraction in cm^-3. SNII_energy_fraction_n_Z: 0.8686 # Power-law for the metallicity dependance of the SNII energy fraction. SNII_energy_fraction_n_n: 0.8686 # Power-law for the birth density dependance of the SNII energy fraction. - SNIa_max_mass_Msun: 8.0 # Maximal mass considered for SNIa feedback and enrichment in solar masses. - SNIa_timescale_Gyr: 2.0 # Time-scale of the exponential decay of the SNIa rates in Gyr. - SNIa_efficiency_p_Msun: 0.002 # Normalisation of the SNIa rates in inverse solar masses. + SNIa_DTD: PowerLaw # Functional form of the SNIa delay time distribution. + SNIa_DTD_delay_Gyr: 0.04 # Stellar age after which SNIa start in Gyr (40 Myr corresponds to stars ~ 8 Msun). + SNIa_DTD_power_law_norm_p_Msun: 0.0012 # Normalization of the SNIa delay time distribution (in Msun^-1). SNIa_energy_erg: 1.0e51 # Energy of one SNIa explosion in ergs. AGB_ejecta_velocity_km_p_s: 10.0 # Velocity of the AGB ejectas in km/s. + stellar_evolution_age_cut_Gyr: 0.1 # Stellar age in Gyr above which the enrichment is down-sampled. + stellar_evolution_sampling_rate: 10 # Number of time-steps in-between two enrichment events for a star above the age threshold. SNII_yield_factor_Hydrogen: 1.0 # (Optional) Correction factor to apply to the Hydrogen yield from the SNII channel. SNII_yield_factor_Helium: 1.0 # (Optional) Correction factor to apply to the Helium yield from the SNII channel. SNII_yield_factor_Carbon: 0.5 # (Optional) Correction factor to apply to the Carbon yield from the SNII channel. @@ -177,9 +184,12 @@ EAGLEFeedback: EAGLEAGN: subgrid_seed_mass_Msun: 1.5e5 # Black hole subgrid mass at creation time in solar masses. max_eddington_fraction: 1.5 # Maximal allowed accretion rate in units of the Eddington rate. + eddington_fraction_for_recording: 0.1 # Record the last time BHs reached an Eddington ratio above this threshold. viscous_alpha: 1e6 # Normalisation constant of the Bondi viscuous time-scale accretion reduction term radiative_efficiency: 0.1 # Fraction of the accreted mass that gets radiated. coupling_efficiency: 0.15 # Fraction of the radiated energy that couples to the gas in feedback events. AGN_delta_T_K: 3.16228e8 # Change in temperature to apply to the gas particle in an AGN feedback event in Kelvin. AGN_num_ngb_to_heat: 1. # Target number of gas neighbours to heat in an AGN feedback event. - max_reposition_mass: 2e8 # Maximal BH mass considered for BH repositioning in solar masses. \ No newline at end of file + max_reposition_mass: 2e8 # Maximal BH mass considered for BH repositioning in solar masses. + threshold_major_merger: 0.333 # Mass ratio threshold to consider a BH merger as 'major' + threshold_minor_merger: 0.1 # Mass ratio threshold to consider a BH merger as 'minor' diff --git a/examples/EAGLE_low_z/EAGLE_50/eagle_50.yml b/examples/EAGLE_low_z/EAGLE_50/eagle_50.yml index 33ac98abc5e92aa2ccb33bd3d749cbb788cec43f..a1022673263ff90d319922916c2a7acee6d79723 100644 --- a/examples/EAGLE_low_z/EAGLE_50/eagle_50.yml +++ b/examples/EAGLE_low_z/EAGLE_50/eagle_50.yml @@ -46,6 +46,7 @@ Gravity: eta: 0.025 # Constant dimensionless multiplier for time integration. theta: 0.7 # Opening angle (Multipole acceptance criterion) mesh_side_length: 128 + dithering: 0 comoving_DM_softening: 0.0026994 # Comoving DM softening length (in internal units). max_physical_DM_softening: 0.0007 # Max physical DM softening length (in internal units). comoving_baryon_softening: 0.0026994 # Comoving DM softening length (in internal units). @@ -53,10 +54,13 @@ Gravity: # 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). - h_min_ratio: 0.1 # Minimal smoothing in units of softening. - CFL_condition: 0.1 # Courant-Friedrich-Levy condition for time integration. - minimal_temperature: 100 # (internal units) + resolution_eta: 1.2348 # Target smoothing length in units of the mean inter-particle separation (1.2348 == 48Ngbs with the cubic spline kernel). + h_min_ratio: 0.1 # Minimal smoothing in units of softening. + h_max: 0.5 # Maximal softening in co-moving internal units. + CFL_condition: 0.1 # Courant-Friedrich-Levy condition for time integration. + minimal_temperature: 100 # (internal units) + particle_splitting: 1 + particle_splitting_mass_threshold: 7e-4 # Internal units (i.e. 7e6 Msun ~ 4 times the initial gas mass) # Parameters of the stars neighbour search Stars: @@ -111,7 +115,7 @@ EAGLEStarFormation: min_over_density: 57.7 # The over-density above which star-formation is allowed. KS_high_density_threshold_H_p_cm3: 1e3 # Hydrogen number density above which the Kennicut-Schmidt law changes slope in Hydrogen atoms per cm^3. KS_high_density_exponent: 2.0 # Slope of the Kennicut-Schmidt law above the high-density threshold. - EOS_temperature_margin_dex: 0.5 # Logarithm base 10 of the maximal temperature difference above the EOS allowed to form stars. + EOS_entropy_margin_dex: 0.5 # Logarithm base 10 of the maximal entropy above the EOS at which stars can form. threshold_norm_H_p_cm3: 0.1 # Normalisation of the metal-dependant density threshold for star formation in Hydrogen atoms per cm^3. threshold_Z0: 0.002 # Reference metallicity (metal mass fraction) for the metal-dependant threshold for star formation. threshold_slope: -0.64 # Slope of the metal-dependant star formation threshold @@ -138,9 +142,10 @@ EAGLEFeedback: filename: ./yieldtables/ # Path to the directory containing the EAGLE yield tables. IMF_min_mass_Msun: 0.1 # Minimal stellar mass considered for the Chabrier IMF in solar masses. IMF_max_mass_Msun: 100.0 # Maximal stellar mass considered for the Chabrier IMF in solar masses. - SNII_min_mass_Msun: 6.0 # Minimal mass considered for SNII feedback (not SNII enrichment!) in solar masses. - SNII_max_mass_Msun: 100.0 # Maximal mass considered for SNII feedback (not SNII enrichment!) in solar masses. - SNII_wind_delay_Gyr: 0.03 # Time in Gyr between a star's birth and the SNII thermal feedback event. + SNII_min_mass_Msun: 6.0 # Minimal mass considered for SNII stars in solar masses. + SNII_max_mass_Msun: 100.0 # Maximal mass considered for SNII stars in solar masses. + SNII_sampled_delay: 0 # Sample the SNII lifetimes to do feedback. + SNII_wind_delay_Gyr: 0.03 # Time in Gyr between a star's birth and the SNII thermal feedback event when not sampling. SNII_delta_T_K: 3.16228e7 # Change in temperature to apply to the gas particle in a SNII thermal feedback event in Kelvin. SNII_energy_erg: 1.0e51 # Energy of one SNII explosion in ergs. SNII_energy_fraction_min: 0.3 # Minimal fraction of energy applied in a SNII feedback event. @@ -149,11 +154,13 @@ EAGLEFeedback: SNII_energy_fraction_n_0_H_p_cm3: 1.4588 # Pivot point for the birth density dependance of the SNII energy fraction in cm^-3. SNII_energy_fraction_n_Z: 0.8686 # Power-law for the metallicity dependance of the SNII energy fraction. SNII_energy_fraction_n_n: 0.8686 # Power-law for the birth density dependance of the SNII energy fraction. - SNIa_max_mass_Msun: 8.0 # Maximal mass considered for SNIa feedback and enrichment in solar masses. - SNIa_timescale_Gyr: 2.0 # Time-scale of the exponential decay of the SNIa rates in Gyr. - SNIa_efficiency_p_Msun: 0.002 # Normalisation of the SNIa rates in inverse solar masses. + SNIa_DTD: PowerLaw # Functional form of the SNIa delay time distribution. + SNIa_DTD_delay_Gyr: 0.04 # Stellar age after which SNIa start in Gyr (40 Myr corresponds to stars ~ 8 Msun). + SNIa_DTD_power_law_norm_p_Msun: 0.0012 # Normalization of the SNIa delay time distribution (in Msun^-1). SNIa_energy_erg: 1.0e51 # Energy of one SNIa explosion in ergs. AGB_ejecta_velocity_km_p_s: 10.0 # Velocity of the AGB ejectas in km/s. + stellar_evolution_age_cut_Gyr: 0.1 # Stellar age in Gyr above which the enrichment is down-sampled. + stellar_evolution_sampling_rate: 10 # Number of time-steps in-between two enrichment events for a star above the age threshold. SNII_yield_factor_Hydrogen: 1.0 # (Optional) Correction factor to apply to the Hydrogen yield from the SNII channel. SNII_yield_factor_Helium: 1.0 # (Optional) Correction factor to apply to the Helium yield from the SNII channel. SNII_yield_factor_Carbon: 0.5 # (Optional) Correction factor to apply to the Carbon yield from the SNII channel. @@ -168,9 +175,12 @@ EAGLEFeedback: EAGLEAGN: subgrid_seed_mass_Msun: 1.5e5 # Black hole subgrid mass at creation time in solar masses. max_eddington_fraction: 1.5 # Maximal allowed accretion rate in units of the Eddington rate. + eddington_fraction_for_recording: 0.1 # Record the last time BHs reached an Eddington ratio above this threshold. viscous_alpha: 1e6 # Normalisation constant of the Bondi viscuous time-scale accretion reduction term radiative_efficiency: 0.1 # Fraction of the accreted mass that gets radiated. coupling_efficiency: 0.15 # Fraction of the radiated energy that couples to the gas in feedback events. AGN_delta_T_K: 3.16228e8 # Change in temperature to apply to the gas particle in an AGN feedback event in Kelvin. AGN_num_ngb_to_heat: 1. # Target number of gas neighbours to heat in an AGN feedback event. - max_reposition_mass: 2e8 # Maximal BH mass considered for BH repositioning in solar masses. \ No newline at end of file + max_reposition_mass: 2e8 # Maximal BH mass considered for BH repositioning in solar masses. + threshold_major_merger: 0.333 # Mass ratio threshold to consider a BH merger as 'major' + threshold_minor_merger: 0.1 # Mass ratio threshold to consider a BH merger as 'minor' diff --git a/examples/EAGLE_low_z/EAGLE_6/eagle_6.yml b/examples/EAGLE_low_z/EAGLE_6/eagle_6.yml index ad6e78bb8b7a80b51da09cbc4eaeb9d8619d59c2..1b06f7096957f132c61d669d1c24e529e78b4215 100644 --- a/examples/EAGLE_low_z/EAGLE_6/eagle_6.yml +++ b/examples/EAGLE_low_z/EAGLE_6/eagle_6.yml @@ -56,6 +56,7 @@ Gravity: eta: 0.025 # Constant dimensionless multiplier for time integration. theta: 0.7 # Opening angle (Multipole acceptance criterion) mesh_side_length: 16 + dithering: 0 comoving_DM_softening: 0.0026994 # Comoving DM softening length (in internal units). max_physical_DM_softening: 0.0007 # Max physical DM softening length (in internal units). comoving_baryon_softening: 0.0026994 # Comoving DM softening length (in internal units). @@ -63,10 +64,13 @@ Gravity: # 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). - h_min_ratio: 0.1 # Minimal smoothing in units of softening. - CFL_condition: 0.1 # Courant-Friedrich-Levy condition for time integration. - minimal_temperature: 100 # (internal units) + resolution_eta: 1.2348 # Target smoothing length in units of the mean inter-particle separation (1.2348 == 48Ngbs with the cubic spline kernel). + h_min_ratio: 0.1 # Minimal smoothing in units of softening. + h_max: 0.5 # Maximal softening in co-moving internal units. + CFL_condition: 0.1 # Courant-Friedrich-Levy condition for time integration. + minimal_temperature: 100 # (internal units) + particle_splitting: 1 + particle_splitting_mass_threshold: 7e-4 # Internal units (i.e. 7e6 Msun ~ 4 times the initial gas mass) # Parameters of the stars neighbour search Stars: @@ -121,7 +125,7 @@ EAGLEStarFormation: min_over_density: 57.7 # The over-density above which star-formation is allowed. KS_high_density_threshold_H_p_cm3: 1e3 # Hydrogen number density above which the Kennicut-Schmidt law changes slope in Hydrogen atoms per cm^3. KS_high_density_exponent: 2.0 # Slope of the Kennicut-Schmidt law above the high-density threshold. - EOS_temperature_margin_dex: 0.5 # Logarithm base 10 of the maximal temperature difference above the EOS allowed to form stars. + EOS_entropy_margin_dex: 0.5 # Logarithm base 10 of the maximal entropy above the EOS at which stars can form. threshold_norm_H_p_cm3: 0.1 # Normalisation of the metal-dependant density threshold for star formation in Hydrogen atoms per cm^3. threshold_Z0: 0.002 # Reference metallicity (metal mass fraction) for the metal-dependant threshold for star formation. threshold_slope: -0.64 # Slope of the metal-dependant star formation threshold @@ -148,9 +152,10 @@ EAGLEFeedback: filename: ./yieldtables/ # Path to the directory containing the EAGLE yield tables. IMF_min_mass_Msun: 0.1 # Minimal stellar mass considered for the Chabrier IMF in solar masses. IMF_max_mass_Msun: 100.0 # Maximal stellar mass considered for the Chabrier IMF in solar masses. - SNII_min_mass_Msun: 6.0 # Minimal mass considered for SNII feedback (not SNII enrichment!) in solar masses. - SNII_max_mass_Msun: 100.0 # Maximal mass considered for SNII feedback (not SNII enrichment!) in solar masses. - SNII_wind_delay_Gyr: 0.03 # Time in Gyr between a star's birth and the SNII thermal feedback event. + SNII_min_mass_Msun: 6.0 # Minimal mass considered for SNII stars in solar masses. + SNII_max_mass_Msun: 100.0 # Maximal mass considered for SNII stars in solar masses. + SNII_sampled_delay: 0 # Sample the SNII lifetimes to do feedback. + SNII_wind_delay_Gyr: 0.03 # Time in Gyr between a star's birth and the SNII thermal feedback event when not sampling. SNII_delta_T_K: 3.16228e7 # Change in temperature to apply to the gas particle in a SNII thermal feedback event in Kelvin. SNII_energy_erg: 1.0e51 # Energy of one SNII explosion in ergs. SNII_energy_fraction_min: 0.3 # Minimal fraction of energy applied in a SNII feedback event. @@ -159,11 +164,13 @@ EAGLEFeedback: SNII_energy_fraction_n_0_H_p_cm3: 1.4588 # Pivot point for the birth density dependance of the SNII energy fraction in cm^-3. SNII_energy_fraction_n_Z: 0.8686 # Power-law for the metallicity dependance of the SNII energy fraction. SNII_energy_fraction_n_n: 0.8686 # Power-law for the birth density dependance of the SNII energy fraction. - SNIa_max_mass_Msun: 8.0 # Maximal mass considered for SNIa feedback and enrichment in solar masses. - SNIa_timescale_Gyr: 2.0 # Time-scale of the exponential decay of the SNIa rates in Gyr. - SNIa_efficiency_p_Msun: 0.002 # Normalisation of the SNIa rates in inverse solar masses. + SNIa_DTD: PowerLaw # Functional form of the SNIa delay time distribution. + SNIa_DTD_delay_Gyr: 0.04 # Stellar age after which SNIa start in Gyr (40 Myr corresponds to stars ~ 8 Msun). + SNIa_DTD_power_law_norm_p_Msun: 0.0012 # Normalization of the SNIa delay time distribution (in Msun^-1). SNIa_energy_erg: 1.0e51 # Energy of one SNIa explosion in ergs. AGB_ejecta_velocity_km_p_s: 10.0 # Velocity of the AGB ejectas in km/s. + stellar_evolution_age_cut_Gyr: 0.1 # Stellar age in Gyr above which the enrichment is down-sampled. + stellar_evolution_sampling_rate: 10 # Number of time-steps in-between two enrichment events for a star above the age threshold. SNII_yield_factor_Hydrogen: 1.0 # (Optional) Correction factor to apply to the Hydrogen yield from the SNII channel. SNII_yield_factor_Helium: 1.0 # (Optional) Correction factor to apply to the Helium yield from the SNII channel. SNII_yield_factor_Carbon: 0.5 # (Optional) Correction factor to apply to the Carbon yield from the SNII channel. @@ -178,9 +185,12 @@ EAGLEFeedback: EAGLEAGN: subgrid_seed_mass_Msun: 1.5e5 # Black hole subgrid mass at creation time in solar masses. max_eddington_fraction: 1.5 # Maximal allowed accretion rate in units of the Eddington rate. + eddington_fraction_for_recording: 0.1 # Record the last time BHs reached an Eddington ratio above this threshold. viscous_alpha: 1e6 # Normalisation constant of the Bondi viscuous time-scale accretion reduction term radiative_efficiency: 0.1 # Fraction of the accreted mass that gets radiated. coupling_efficiency: 0.15 # Fraction of the radiated energy that couples to the gas in feedback events. AGN_delta_T_K: 3.16228e8 # Change in temperature to apply to the gas particle in an AGN feedback event in Kelvin. AGN_num_ngb_to_heat: 1. # Target number of gas neighbours to heat in an AGN feedback event. - max_reposition_mass: 2e8 # Maximal BH mass considered for BH repositioning in solar masses. \ No newline at end of file + max_reposition_mass: 2e8 # Maximal BH mass considered for BH repositioning in solar masses. + threshold_major_merger: 0.333 # Mass ratio threshold to consider a BH merger as 'major' + threshold_minor_merger: 0.1 # Mass ratio threshold to consider a BH merger as 'minor' diff --git a/examples/EAGLE_low_z/EAGLE_6/run.sh b/examples/EAGLE_low_z/EAGLE_6/run.sh index 47dbd952549137d8c2baab8c22361a227eb35ca9..9786d8062e12a8292f1967e122bb1f8b94354074 100755 --- a/examples/EAGLE_low_z/EAGLE_6/run.sh +++ b/examples/EAGLE_low_z/EAGLE_6/run.sh @@ -7,5 +7,5 @@ then ./getIC.sh fi -../../swift --cosmology --hydro --self-gravity --stars --threads=16 eagle_6.yml 2>&1 | tee output.log +../../swift --hydro --threads=4 -n 16 -y 1 eagle_6.yml 2>&1 | tee output.log diff --git a/examples/GEAR/AgoraDisk/agora_disk.yml b/examples/GEAR/AgoraDisk/agora_disk.yml index 92f2532b3132c0f6314b7697f0b9b65f1afedb3b..839e969a746e6739f1b14777fa334b70bc5782ee 100644 --- a/examples/GEAR/AgoraDisk/agora_disk.yml +++ b/examples/GEAR/AgoraDisk/agora_disk.yml @@ -7,15 +7,25 @@ InternalUnitSystem: UnitTemp_in_cgs: 1 # Kelvin Scheduler: - max_top_level_cells: 8 + max_top_level_cells: 16 + cell_extra_sparts: 5000 # (Optional) Number of spare sparts per top-level allocated at rebuild time for on-the-fly creation. + cell_max_size: 8000 # (Optional) Maximal number of interactions per task if we force the split (this is the default value). + cell_sub_size_pair_hydro: 2560 # (Optional) Maximal number of hydro-hydro interactions per sub-pair hydro/star task (this is the default value). + cell_sub_size_self_hydro: 3200 # (Optional) Maximal number of hydro-hydro interactions per sub-self hydro/star task (this is the default value). + cell_sub_size_pair_stars: 2560 # (Optional) Maximal number of hydro-star interactions per sub-pair hydro/star task (this is the default value). + cell_sub_size_self_stars: 3200 # (Optional) Maximal number of hydro-star interactions per sub-self hydro/star task (this is the default value). + cell_sub_size_pair_grav: 2560 # (Optional) Maximal number of interactions per sub-pair gravity task (this is the default value). + cell_sub_size_self_grav: 3200 # (Optional) Maximal number of interactions per sub-self gravity task (this is the default value). + cell_split_size: 100 # (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: 0.5 # The end time of the simulation (in internal units). dt_min: 1e-10 # The minimal time-step size of the simulation (in internal units). - dt_max: 1e-4 # The maximal time-step size of the simulation (in internal units). - + dt_max: 0.1 # The maximal time-step size of the simulation (in internal units). + max_dt_RMS_factor: 0.25 # (Optional) Dimensionless factor for the maximal displacement allowed based on the RMS velocities. + # Parameters governing the snapshots Snapshots: basename: agora_disk # Common part of the name of output files @@ -29,10 +39,12 @@ Statistics: # Parameters for the self-gravity scheme Gravity: - eta: 0.025 # Constant dimensionless multiplier for time integration. + eta: 0.05 # Constant dimensionless multiplier for time integration. theta: 0.7 # Opening angle (Multipole acceptance criterion) - comoving_softening: 0.08 # Comoving softening length (in internal units). - max_physical_softening: 0.08 # Physical softening length (in internal units). + comoving_DM_softening: 0.08 # Comoving softening length (in internal units). + max_physical_DM_softening: 0.08 # Physical softening length (in internal units). + comoving_baryon_softening: 0.08 # Comoving softening length (in internal units). + max_physical_baryon_softening: 0.08 # Physical softening length (in internal units). mesh_side_length: 32 # Number of cells along each axis for the periodic gravity mesh. # Parameters for the hydrodynamics scheme @@ -40,6 +52,8 @@ 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. # Kelvin + h_min_ratio: 0.1095 # (Optional) Minimal allowed smoothing length in units of the softening. Defaults to 0 if unspecified. + h_max: 10. # (Optional) Maximal allowed smoothing length in internal units. Defaults to FLT_MAX if unspecified. # Parameters related to the initial conditions InitialConditions: @@ -55,13 +69,34 @@ LambdaCooling: # Cooling with Grackle 2.0 GrackleCooling: - CloudyTable: CloudyData_UVB=HM2012.h5 # Name of the Cloudy Table (available on the grackle bitbucket repository) - WithUVbackground: 1 # Enable or not the UV background - Redshift: 0 # Redshift to use (-1 means time based redshift) - WithMetalCooling: 1 # Enable or not the metal cooling - ProvideVolumetricHeatingRates: 0 # User provide volumetric heating rates - ProvideSpecificHeatingRates: 0 # User provide specific heating rates - SelfShieldingMethod: 0 # Grackle (<= 3) or Gear self shielding method - OutputMode: 1 # Write in output corresponding primordial chemistry mode - MaxSteps: 1000 - ConvergenceLimit: 1e-2 + cloudy_table: CloudyData_UVB=HM2012.h5 # Name of the Cloudy Table (available on the grackle bitbucket repository) + with_UV_background: 1 # Enable or not the UV background + redshift: 0 # Redshift to use (-1 means time based redshift) + with_metal_cooling: 1 # Enable or not the metal cooling + provide_volumetric_heating_rates: 0 # User provide volumetric heating rates + provide_specific_heating_rates: 0 # User provide specific heating rates + self_shielding_method: -1 # Grackle (<= 3) or Gear self shielding method + self_shielding_threshold_atom_per_cm3: 0.007 # Required only with GEAR's self shielding. Density threshold of the self shielding + max_steps: 1000 + convergence_limit: 1e-2 + thermal_time_myr: 5 + + +GEARStarFormation: + star_formation_efficiency: 0.01 # star formation efficiency (c_*) + maximal_temperature: 1e10 # Upper limit to the temperature of a star forming particle + +GEARPressureFloor: + jeans_factor: 10 + +GEARFeedback: + supernovae_energy_erg: 0.1e51 + yields_table: chemistry-AGB+OMgSFeZnSrYBaEu-16072013.h5 + discrete_yields: 0 + +GEARChemistry: + initial_metallicity: 1 + scale_initial_metallicity: 1 + +Restarts: + delta_hours: 72 # (Optional) decimal hours between dumps of restart files. diff --git a/examples/GEAR/AgoraDisk/cleanupSwift.py b/examples/GEAR/AgoraDisk/cleanupSwift.py index 31e6ed8ab0ce6650bad861ac39462cab8e4a0f4b..865b0cd6d7f8dc18d2bbf6dec90c65846970c91f 100644 --- a/examples/GEAR/AgoraDisk/cleanupSwift.py +++ b/examples/GEAR/AgoraDisk/cleanupSwift.py @@ -14,7 +14,7 @@ copyfile(filename, out) f = File(out) for i in range(6): - name = "PartType{}/ElementAbundance".format(i) + name = "PartType{}/ElementAbundances".format(i) if name in f: del f[name] @@ -23,13 +23,27 @@ for i in range(NPartType): if name not in f: continue - grp = f[name + "/SmoothingLength"] + grp = f[name + "/SmoothingLengths"] grp[:] *= 1.823 + # fix issue due to the name of densities + fields = [("Density", "Densities"), + ("Entropies", "Entropies"), + ("InternalEnergy", "InternalEnergies"), + ("SmoothingLength", "SmoothingLengths")] + + for field in fields: + if field[1] in f[name] and field[0] not in f[name]: + f[name + "/" + field[0]] = f[name + "/" + field[1]] + + + + cosmo = f["Cosmology"].attrs head = f["Header"].attrs head["OmegaLambda"] = cosmo["Omega_lambda"] head["Omega0"] = cosmo["Omega_b"] head["HubbleParam"] = cosmo["H0 [internal units]"] +head["Time"] = head["Time"][0] f.close() diff --git a/examples/GEAR/AgoraDisk/getIC.sh b/examples/GEAR/AgoraDisk/getIC.sh index c234b52b943ccb8d6dededed7d0f5070cd9fe5b2..ca7fe3b251d568c58976650d158967214aa3e387 100755 --- a/examples/GEAR/AgoraDisk/getIC.sh +++ b/examples/GEAR/AgoraDisk/getIC.sh @@ -6,4 +6,4 @@ if [ "$#" -ne 1 ]; then exit fi -wget https://obswww.unige.ch/~lhausamm/swift/IC/AgoraDisk/$1.hdf5 +wget http://virgodb.cosma.dur.ac.uk/swift-webstorage/ICs/AgoraDisk/$1.hdf5 diff --git a/examples/GEAR/AgoraDisk/getSolution.sh b/examples/GEAR/AgoraDisk/getSolution.sh index 37b7f8031b90a5612d8fd3e88b1ecffbc02451a6..681786a76c460f81be2a8c9379c4873648bfa277 100755 --- a/examples/GEAR/AgoraDisk/getSolution.sh +++ b/examples/GEAR/AgoraDisk/getSolution.sh @@ -1,12 +1,4 @@ #!/bin/bash -# cleanup work space -rm snapshot_0000.hdf5 snapshot_0500.hdf5 - -wget https://obswww.unige.ch/~lhausamm/swift/IC/AgoraDisk/Gear/with_cooling/snapshot_0000.hdf5 -wget https://obswww.unige.ch/~lhausamm/swift/IC/AgoraDisk/Gear/with_cooling/snapshot_0500.hdf5 - -# wget https://obswww.unige.ch/~lhausamm/swift/IC/AgoraDisk/Gear/without_cooling/snapshot_0000.hdf5 -# wget https://obswww.unige.ch/~lhausamm/swift/IC/AgoraDisk/Gear/without_cooling/snapshot_0500.hdf5 - - +wget http://virgodb.cosma.dur.ac.uk/swift-webstorage/ICs/AgoraDisk/Gear/snapshot_0000.hdf5 +wget http://virgodb.cosma.dur.ac.uk/swift-webstorage/ICs/AgoraDisk/Gear/snapshot_0050.hdf5 diff --git a/examples/GEAR/AgoraDisk/plotSolution.py b/examples/GEAR/AgoraDisk/plotSolution.py index 8db2c98dbca87104bb119845edcbb934af08195e..b3a831b2d902c901f3e06c968c7fef28d4db3429 100644 --- a/examples/GEAR/AgoraDisk/plotSolution.py +++ b/examples/GEAR/AgoraDisk/plotSolution.py @@ -34,7 +34,7 @@ from yt.analysis_modules.halo_analysis.api import * from yt.data_objects.particle_filters import add_particle_filter from scipy.stats import kde from subprocess import call -#mylog.setLevel(1) +# mylog.setLevel(1) from yt.utilities.math_utils import get_cyl_r, get_cyl_theta, get_cyl_z @@ -53,7 +53,7 @@ draw_PDF = 2###2 # 0/1/2/3 = OFF/ON/ON with draw_pos_vel_PDF = 4##4 # 0/1/2/3/4 = OFF/ON/ON with 1D profile/ON also with 1D dispersion profile/ON also with separate 1D vertical dispersion profiles draw_star_pos_vel_PDF = 4##4 # 0/1/2/3/4 = OFF/ON/ON with 1D profile/ON also with 1D dispersion profile/ON also with separate 1D vertical dispersion profiles draw_rad_height_PDF = 2##2 # 0/1/2/3 = OFF/ON/ON with 1D profile/ON with analytic ftn subtracted -draw_metal_PDF = 0##0 # 0/1 = OFF/ON +draw_metal_PDF = 1##1 # 0/1 = OFF/ON draw_density_DF = 2#2 # 0/1/2 = OFF/ON/ON with difference plot between 1st and 2nd datasets (when 2, dataset_num should be set to 2) draw_radius_DF = 1#1 # 0/1 = OFF/ON draw_star_radius_DF = 2#2 # 0/1/2 = OFF/ON/ON with SFR profile and K-S plot (when 2, this automatically turns on draw_radius_DF) @@ -110,9 +110,9 @@ marker_names = ['s', 'o', 'p', 'v', '^', '<', '>', 'h', '*'] # [file_location[1]+'GIZMO/snapshot_temp_000', file_location[1]+'GIZMO/snapshot_temp_100']]] codes = ['SWIFT', 'GEAR'] filenames = [[["./agora_disk_IC.hdf5", "./agora_disk_500Myr.hdf5"], # Sim-noSFF - ["./snapshot_0000.hdf5", "./snapshot_0500.hdf5"]], + ["./snapshot_0000.hdf5", "./snapshot_0050.hdf5"]], [["./agora_disk_IC.hdf5", "./agora_disk_500Myr.hdf5"], # Sim-SFF (with star formation and feedback) - ["./snapshot_0000.hdf5", "./snapshot_0500.hdf5"]]] # I did not check the order, they can be switched + ["./snapshot_0000.hdf5", "./snapshot_0050.hdf5"]]] # I did not check the order, they can be switched # codes = ["SWIFT"] # filenames = [[["./agora_disk_0000.hdf5", "./agora_disk_0050.hdf5"]], @@ -139,8 +139,8 @@ filenames = [[["./agora_disk_IC.hdf5", "./agora_disk_500Myr.hdf5"], # Sim-noSFF # filenames = [[[file_location[0]+'GADGET-3/AGORA_ISO_LOW_DRY/snap_iso_dry_000.hdf5', file_location[0]+'GADGET-3/AGORA_ISO_LOW_DRY/snap_iso_dry_010.hdf5']], # [[file_location[1]+'GADGET-3/AGORA_ISO_LOW_SF_SNII_Thermal_Chevalier_SFT10/snap_iso_sf_000.hdf5', file_location[1]+'GADGET-3/AGORA_ISO_LOW_SF_SNII_Thermal_Chevalier_SFT10/snap_iso_sf_010.hdf5']]] # codes = ['GEAR'] -# filenames = [[['snapshot_0000', 'snapshot_0500']], -# [['snapshot_0000', 'snapshot_0500']]] +# filenames = [[['snapshot_0000.hdf5', 'snapshot_0500.hdf5']], +# [['snapshot_0000.hdf5', 'snapshot_0500']]] # codes = ['GIZMO'] # filenames = [[[file_location[0]+'GIZMO/snapshot_temp_000', file_location[0]+'GIZMO/snapshot_temp_100']], # [[file_location[1]+'GIZMO/snapshot_temp_000', file_location[1]+'GIZMO/snapshot_temp_100']]] @@ -439,7 +439,7 @@ for time in range(len(times)): yield line if draw_PDF >= 1: fig_PDF += [plt.figure(figsize=(50, 80))] - grid_PDF += [AxesGrid(fig_PDF[time], (0.01,0.01,0.99,0.99), nrows_ncols = (3, int(math.ceil(len(codes)/3.0))), axes_pad = 0.05, add_all = True, share_all = True, + grid_PDF += [AxesGrid(fig_PDF[time], (0.01,0.01,0.99,0.99), nrows_ncols = (2, int(math.ceil(len(codes)/2.0))), axes_pad = 0.05, add_all = True, share_all = True, label_mode = "1", cbar_mode = "single", cbar_location = "right", cbar_size = "2%", cbar_pad = 0.05, aspect = False)] if draw_pos_vel_PDF >= 1: fig_pos_vel_PDF += [plt.figure(figsize=(50, 80))] @@ -469,7 +469,7 @@ for time in range(len(times)): rad_height_profiles.append([]) if draw_metal_PDF == 1: fig_metal_PDF += [plt.figure(figsize=(50, 80))] - grid_metal_PDF += [AxesGrid(fig_metal_PDF[time], (0.01,0.01,0.99,0.99), nrows_ncols = (3, int(math.ceil(len(codes)/3.0))), axes_pad = 0.05, add_all = True, share_all = True, + grid_metal_PDF += [AxesGrid(fig_metal_PDF[time], (0.01,0.01,0.99,0.99), nrows_ncols = (2, int(math.ceil(len(codes)/2.0))), axes_pad = 0.05, add_all = True, share_all = True, label_mode = "1", cbar_mode = "single", cbar_location = "right", cbar_size = "2%", cbar_pad = 0.05, aspect = False)] if draw_density_DF >= 1: density_DF_xs.append([]) @@ -576,9 +576,9 @@ for time in range(len(times)): PartType_StarBeforeFiltered_to_use = "PartType4" if time != 0: def _FormationTime(field, data): - return pf.arr(data["PartType4", "BirthTime"].d, 'code_time') + return pf.arr(data["PartType4", "BirthTimes"].d, 'code_time') pf.add_field(("PartType4", FormationTimeType_to_use), function=_FormationTime, particle_type=True, take_log=False, units="code_time") - + MassType_to_use = "Masses" elif codes[code] == "GEAR": PartType_Gas_to_use = "PartType0" @@ -715,6 +715,20 @@ for time in range(len(times)): def _metallicity_3(field, data): return data["deposit", PartType_Gas_to_use+"_smoothed_"+MetallicityType_to_use] pf.add_field(("gas", "metallicity"), function=_metallicity_3, force_override=True, display_name="Metallicity", particle_type=False, take_log=True, units="") + elif codes[code] == 'SWIFT': # "Metals" in SWIFT is 10-species field ([:,9] is the total metal fraction), so requires a change in _vector_fields in frontends/gadget/io.py: added ("Metals", 10) + def _metallicity_2(field, data): + if len(data[PartType_Gas_to_use, "SmoothedElementAbundances"].shape) == 1: + return data[PartType_Gas_to_use, "SmoothedElementAbundances"] + else: + return data[PartType_Gas_to_use, "SmoothedElementAbundances"][:,9].in_units("") # in_units("") turned out to be crucial!; otherwise code_metallicity will be used and it will mess things up + # We are creating ("Gas", "Metallicity") here, different from ("Gas", "metallicity") which is auto-generated by yt but doesn't work properly + pf.add_field((PartType_Gas_to_use, MetallicityType_to_use), function=_metallicity_2, display_name="Metallicity", particle_type=True, take_log=True, units="") + # Also creating smoothed field following an example in yt-project.org/docs/dev/cookbook/calculating_information.html; use hardcoded num_neighbors as in frontends/gadget/fields.py + fn = add_volume_weighted_smoothed_field(PartType_Gas_to_use, "Coordinates", MassType_to_use, "SmoothingLength", "Density", MetallicityType_to_use, pf.field_info, nneighbors=64) + # Alias doesn't work -- e.g. pf.field_info.alias(("gas", "metallicity"), fn[0]) -- probably because pf=GadgetDataset()?, not load()?; so I add and replace existing ("gas", "metallicity") + def _metallicity_3(field, data): + return data["deposit", PartType_Gas_to_use+"_smoothed_"+MetallicityType_to_use] + pf.add_field(("gas", "metallicity"), function=_metallicity_3, force_override=True, display_name="Metallicity", particle_type=False, take_log=True, units="") if draw_metal_map >= 2: def _metal_mass(field, data): return data["gas", "cell_mass"] * data["gas", "metallicity"] @@ -745,7 +759,7 @@ for time in range(len(times)): if draw_metal_map >= 1 or draw_metal_PDF == 1: def _Metallicity_2(field, data): return data[(PartType_Gas_to_use, MetallicityType_to_use)] - pf.add_field((PartType_Gas_to_use, "Metallicity_2"), function=_Metallicity_2, take_log=True, particle_type=False, display_name="Metallicity", units="") + pf.add_field((PartType_Gas_to_use, "Metallicity_2"), function=_Metallicity_2, take_log=True, particle_type=True, display_name="Metallicity", units="") def _Density_2_minus_analytic(field, data): return data[(PartType_Gas_to_use, "density")] - rho_agora_disk(data[(PartType_Gas_to_use, "radius")], data[(PartType_Gas_to_use, "particle_position_cylindrical_z_abs")]) pf.add_field((PartType_Gas_to_use, "Density_2_minus_analytic"), function=_Density_2_minus_analytic, take_log=False, particle_type=False, display_name="Density Residual", units="g/cm**3") @@ -1565,13 +1579,18 @@ for time in range(len(times)): else: # Because ParticlePhasePlot doesn't yet work for a log-log PDF for some reason, I will do the following trick. pf.field_info[(PartType_Gas_to_use, "Metallicity_2")].take_log = False - p3 = PhasePlot(sp, (PartType_Gas_to_use, "density"), (PartType_Gas_to_use, "temperature"), (PartType_Gas_to_use, "Metallicity_2"), weight_field=(PartType_Gas_to_use, MassType_to_use), fontsize=12, x_bins=300, y_bins=300) + p3 = ParticlePhasePlot(sp, (PartType_Gas_to_use, "density"), (PartType_Gas_to_use, "temperature"), (PartType_Gas_to_use, "Metallicity_2"), + weight_field=(PartType_Gas_to_use, MassType_to_use), fontsize=12, x_bins=300, y_bins=300) p3.set_zlim((PartType_Gas_to_use, "Metallicity_2"), 0.01, 0.04) p3.set_cmap((PartType_Gas_to_use, "Metallicity_2"), my_cmap2) plot3 = p3.plots[(PartType_Gas_to_use, "Metallicity_2")] + p3.set_unit("density", "g/cm**3") p3.set_xlim(1e-29, 1e-21) + p3.set_unit("temperature", "K") p3.set_ylim(10, 1e7) + p3.set_log("density", True) + p3.set_log("temperature", True) plot3.figure = fig_metal_PDF[time] plot3.axes = grid_metal_PDF[time][code].axes @@ -2271,7 +2290,7 @@ for time in range(len(times)): if draw_metal_PDF == 1: fig_metal_PDF[time].savefig("metal_PDF_%dMyr" % times[time], bbox_inches='tight', pad_inches=0.03, dpi=300) if draw_density_DF >= 1: - plt.clf() +# plt.clf() # plt.subplot(111, aspect=1) fig = plt.figure(figsize=(8, 8)) gridspec.GridSpec(4, 1) diff --git a/examples/GEAR/AgoraDisk/run.sh b/examples/GEAR/AgoraDisk/run.sh index 8284098a1a71093a4de269ddd0189c8f047c90f9..b2956e086d61a5042fb131bdc061c9b8950899fc 100755 --- a/examples/GEAR/AgoraDisk/run.sh +++ b/examples/GEAR/AgoraDisk/run.sh @@ -5,6 +5,8 @@ # currently only the low resolution is available sim=low +rm agora_disk_0*.hdf5 + # make run.sh fail if a subcommand fails set -e @@ -19,7 +21,13 @@ fi if [ ! -e CloudyData_UVB=HM2012.h5 ] then echo "Fetching the Cloudy tables required by Grackle..." - ../../Cooling/getGrackleCoolingTable.sh + ../../Cooling/getGrackleCoolingTable.sh +fi + +if [ ! -e chemistry-AGB+OMgSFeZnSrYBaEu-16072013.h5 ] +then + echo "Fetching the chemistry tables..." + ../getChemistryTable.sh fi # copy the initial conditions @@ -28,7 +36,7 @@ cp $sim.hdf5 agora_disk.hdf5 python3 changeType.py agora_disk.hdf5 # Run SWIFT -../../swift --cooling --hydro --self-gravity --threads=4 agora_disk.yml 2>&1 | tee output.log +../../swift --sync --limiter --cooling --hydro --self-gravity --star-formation --feedback --stars --threads=8 agora_disk.yml 2>&1 | tee output.log echo "Changing smoothing length to be Gadget compatible" diff --git a/examples/GEAR/DwarfGalaxy/dwarf_galaxy.yml b/examples/GEAR/DwarfGalaxy/dwarf_galaxy.yml index 00fd889d4f58a4dadccc52ef5c6d8315ac2a4012..d3770315851ea43137fd2b60eea820f18fb81bb7 100644 --- a/examples/GEAR/DwarfGalaxy/dwarf_galaxy.yml +++ b/examples/GEAR/DwarfGalaxy/dwarf_galaxy.yml @@ -68,3 +68,31 @@ InitialConditions: 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 + +# Cooling with Grackle 3.0 +GrackleCooling: + cloudy_table: CloudyData_UVB=HM2012.h5 # Name of the Cloudy Table (available on the grackle bitbucket repository) + with_UV_background: 1 # Enable or not the UV background + redshift: -1 # Redshift to use (-1 means time based redshift) + with_metal_cooling: 1 # Enable or not the metal cooling + provide_volumetric_heating_rates: 0 # (optional) User provide volumetric heating rates + provide_specific_heating_rates: 0 # (optional) User provide specific heating rates + self_shielding_method: 0 # (optional) Grackle (<= 3) or Gear self shielding method + max_steps: 10000 # (optional) Max number of step when computing the initial composition + convergence_limit: 1e-2 # (optional) Convergence threshold (relative) for initial composition + thermal_time_Myr: 5 + +GearChemistry: + initial_metallicity: 0.01295 + +GEARFeedback: + supernovae_energy_erg: 1e50 + yields_table: chemistry-AGB+OMgSFeZnSrYBaEu-16072013.h5 + +GearPressureFloor: + jeans_factor: 10. # Number of particles required to suppose a resolved clump and avoid the pressure floor. + + +GEARStarFormation: + star_formation_efficiency: 0.01 # star formation efficiency (c_*) + maximal_temperature: 3e4 # Upper limit to the temperature of a star forming particle diff --git a/examples/GEAR/DwarfGalaxy/run.sh b/examples/GEAR/DwarfGalaxy/run.sh index 1f63556e7f7af57885606c08fc8e1a923c2e440d..11be3465d242b207b6b7c294bec42db16aa24656 100755 --- a/examples/GEAR/DwarfGalaxy/run.sh +++ b/examples/GEAR/DwarfGalaxy/run.sh @@ -7,5 +7,5 @@ then ./getIC.sh fi -../../swift --feedback --self-gravity --hydro --stars --threads=8 $@ dwarf_galaxy.yml 2>&1 | tee output.log +../../swift --feedback --limiter --sync --self-gravity --hydro --stars --cooling --star-formation --threads=8 $@ dwarf_galaxy.yml 2>&1 | tee output.log diff --git a/examples/GEAR/ZoomIn/run.sh b/examples/GEAR/ZoomIn/run.sh index 59c8ff0d63b504978e4d74abbce8680f65695ffa..58961e02539f83ad8e76eb557d440c2095cc02d7 100755 --- a/examples/GEAR/ZoomIn/run.sh +++ b/examples/GEAR/ZoomIn/run.sh @@ -7,5 +7,5 @@ then ./getIC.sh fi -../../swift --feedback --cosmology --self-gravity --hydro --stars --threads=8 zoom_in.yml 2>&1 | tee output.log +../../swift --feedback --cosmology --limiter --sync --self-gravity --hydro --stars --star-formation --threads=8 zoom_in.yml 2>&1 | tee output.log diff --git a/examples/GEAR/ZoomIn/zoom_in.yml b/examples/GEAR/ZoomIn/zoom_in.yml index 8e5763c4af700b7fd95beb6188ed886198b559b3..1d01e6abd33454c4682bb2adfbfdb76a64e4948a 100644 --- a/examples/GEAR/ZoomIn/zoom_in.yml +++ b/examples/GEAR/ZoomIn/zoom_in.yml @@ -60,3 +60,30 @@ InitialConditions: 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 + +# Cooling with Grackle 3.0 +GrackleCooling: + cloudy_table: CloudyData_UVB=HM2012.h5 # Name of the Cloudy Table (available on the grackle bitbucket repository) + with_UV_background: 1 # Enable or not the UV background + redshift: -1 # Redshift to use (-1 means time based redshift) + with_metal_cooling: 1 # Enable or not the metal cooling + provide_volumetric_heating_rates: 0 # (optional) User provide volumetric heating rates + provide_specific_heating_rates: 0 # (optional) User provide specific heating rates + self_shielding_method: 0 # (optional) Grackle (<= 3) or Gear self shielding method + max_steps: 10000 # (optional) Max number of step when computing the initial composition + convergence_limit: 1e-2 # (optional) Convergence threshold (relative) for initial composition + thermal_time_Myr: 5 + +GearChemistry: + initial_metallicity: 0.01295 + +GEARFeedback: + supernovae_energy_erg: 1e50 + yields_table: chemistry-AGB+OMgSFeZnSrYBaEu-16072013.h5 + +GEARStarFormation: + star_formation_efficiency: 0.01 # star formation efficiency (c_*) + maximal_temperature: 3e4 # Upper limit to the temperature of a star forming particle + +GEARPressureFloor: + jeans_factor: 10. # Number of particles required to suppose a resolved clump and avoid the pressure floor. diff --git a/examples/GEAR/getChemistryTable.sh b/examples/GEAR/getChemistryTable.sh new file mode 100644 index 0000000000000000000000000000000000000000..b8f8ac7886e568c914ecad6db97257196cc4c23d --- /dev/null +++ b/examples/GEAR/getChemistryTable.sh @@ -0,0 +1,2 @@ +#!/bin/bash +wget https://obswww.unige.ch/lastro/projects/Clastro/PySWIFTsim/chemistry-AGB+OMgSFeZnSrYBaEu-16072013.h5 diff --git a/examples/GiantImpacts/GiantImpact/README.md b/examples/GiantImpacts/GiantImpact/README.md deleted file mode 100644 index 5c72f1bb37717e4e08b90cdd8c2ccc2da8fe3c59..0000000000000000000000000000000000000000 --- a/examples/GiantImpacts/GiantImpact/README.md +++ /dev/null @@ -1,6 +0,0 @@ -An example planetary simulation of a giant impact onto the young Uranus with -~10^6 SPH particles, as described in Kegerreis et al. (2018), ApJ, 861, 52. - -This example requires the code to be configured to use the Planetary -hydrodynamics and equation of state: - --with-hydro=planetary --with-equation-of-state=planetary diff --git a/examples/GiantImpacts/GiantImpact/get_init_cond.sh b/examples/GiantImpacts/GiantImpact/get_init_cond.sh deleted file mode 100755 index e81035ead7e50ef204bb6bb476e94c7fe0eae0f6..0000000000000000000000000000000000000000 --- a/examples/GiantImpacts/GiantImpact/get_init_cond.sh +++ /dev/null @@ -1,2 +0,0 @@ -#!/bin/bash -wget http://virgodb.cosma.dur.ac.uk/swift-webstorage/ICs/GiantImpacts/uranus_1e6.hdf5 diff --git a/examples/GiantImpacts/GiantImpact/output_list.txt b/examples/GiantImpacts/GiantImpact/output_list.txt deleted file mode 100644 index 0d233fb11ceea02e40c42b8d512e9c1afbe6e835..0000000000000000000000000000000000000000 --- a/examples/GiantImpacts/GiantImpact/output_list.txt +++ /dev/null @@ -1,7 +0,0 @@ -# Time -4000 -9000 -14000 -20000 -30000 -40000 \ No newline at end of file diff --git a/examples/GiantImpacts/GiantImpact/plot_solution.py b/examples/GiantImpacts/GiantImpact/plot_solution.py deleted file mode 100644 index faeb071487adc04f0ba37d20967f693ed84652ec..0000000000000000000000000000000000000000 --- a/examples/GiantImpacts/GiantImpact/plot_solution.py +++ /dev/null @@ -1,144 +0,0 @@ -############################################################################### - # This file is part of SWIFT. - # Copyright (c) 2019 Jacob Kegerreis (jacob.kegerreis@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/>. - # - ############################################################################## - -# Plot the snapshots from the example giant impact on Uranus, showing the -# particles in a thin slice near z=0, coloured by their material, similarish -# (but not identical) to Fig. 2 in Kegerreis et al. (2018). - -import matplotlib -matplotlib.use("Agg") -import matplotlib.pyplot as plt -import numpy as np -# import swiftsimio as sw -import h5py - -font_size = 20 -params = { - 'axes.labelsize' : font_size, - 'font.size' : font_size, - 'xtick.labelsize' : font_size, - 'ytick.labelsize' : font_size, - 'text.usetex' : True, - 'font.family' : 'serif', - } -matplotlib.rcParams.update(params) - -# Snapshot output times -output_list = [4000, 9000, 14000, 20000, 30000, 40000] - -# Material IDs ( = type_id * type_factor + unit_id ) -type_factor = 100 -type_HM80 = 2 -id_body = 10000 -# Name and ID -Di_mat_id = { - 'HM80_HHe' : type_HM80 * type_factor, # Hydrogen-helium atmosphere - 'HM80_ice' : type_HM80 * type_factor + 1, # H20-CH4-NH3 ice mix - 'HM80_ice_2' : type_HM80 * type_factor + 1 + id_body, - 'HM80_rock' : type_HM80 * type_factor + 2, # SiO2-MgO-FeS-FeO rock mix - 'HM80_rock_2' : type_HM80 * type_factor + 2 + id_body, - } -# ID and colour -Di_id_colour = { - Di_mat_id['HM80_HHe'] : '#33DDFF', - Di_mat_id['HM80_ice'] : 'lightsteelblue', - Di_mat_id['HM80_ice_2'] : '#A080D0', - Di_mat_id['HM80_rock'] : 'slategrey', - Di_mat_id['HM80_rock_2'] : '#706050', - } - -def get_snapshot_slice(snapshot): - """ Load and select the particles to plot. """ - # Load particle data - # data = load("uranus_1e6_%06d.hdf5" % snapshot) - # id = data.gas.particle_ids - # pos = data.gas.coordinates - # mat_id = data.gas.material - with h5py.File("uranus_1e6_%06d.hdf5" % snapshot, 'r') as f: - id = f['PartType0/ParticleIDs'].value - pos = (f['PartType0/Coordinates'].value - - 0.5 * f['Header'].attrs['BoxSize']) - mat_id = f['PartType0/MaterialID'].value - - # Edit the material ID of particles in the impactor - num_in_target = 869104 - sel_id = np.where(num_in_target < id)[0] - mat_id[sel_id] += id_body - - # Select particles in a thin slice around z=0 - z_min = -0.1 - z_max = 0.1 - sel_z = np.where((z_min < pos[:, 2]) & (pos[:, 2] < z_max))[0] - pos = pos[sel_z] - mat_id = mat_id[sel_z] - - return pos, mat_id - -def plot_snapshot_slice(pos, mat_id): - """ Plot the particles, coloured by their material. """ - colour = np.empty(len(pos), dtype=object) - for id, c in Di_id_colour.items(): - sel_c = np.where(mat_id == id)[0] - colour[sel_c] = c - - ax.scatter(pos[:, 0], pos[:, 1], c=colour, edgecolors='none', marker='.', - s=10, alpha=0.5, zorder=0) - -# Set up the figure -fig = plt.figure(figsize=(12, 8)) -gs = matplotlib.gridspec.GridSpec(2, 3) -axes = [plt.subplot(gs[i_y, i_x]) for i_y in range(2) for i_x in range(3)] - -# Plot each snapshot -for i_ax, ax in enumerate(axes): - plt.sca(ax) - ax.set_rasterization_zorder(1) - - # Load and select the particles to plot - pos, mat_id = get_snapshot_slice(output_list[i_ax]) - - # Plot the particles, coloured by their material - plot_snapshot_slice(pos, mat_id) - - # Axes etc. - ax.set_aspect('equal') - ax.set_facecolor('k') - - ax.set_xlim(-13, 13) - ax.set_ylim(-13, 13) - - if i_ax in [0, 3]: - ax.set_ylabel(r"y Postion $(R_\oplus)$") - else: - ax.set_yticklabels([]) - if 2 < i_ax: - ax.set_xlabel(r"x Postion $(R_\oplus)$") - else: - ax.set_xticklabels([]) - - # Corner time labels - x = ax.get_xlim()[0] + 0.04 * (ax.get_xlim()[1] - ax.get_xlim()[0]) - y = ax.get_ylim()[0] + 0.89 * (ax.get_ylim()[1] - ax.get_ylim()[0]) - ax.text(x, y, "%.1f h" % (output_list[i_ax] / 60**2), color='w') - -plt.subplots_adjust(wspace=0, hspace=0) -plt.tight_layout() - -# Save -plt.savefig("uranus_1e6.pdf", dpi=200) \ No newline at end of file diff --git a/examples/GiantImpacts/GiantImpact/run.sh b/examples/GiantImpacts/GiantImpact/run.sh deleted file mode 100755 index 5a4f0a74dd098b1fff4659a7d72be3845ad47fc6..0000000000000000000000000000000000000000 --- a/examples/GiantImpacts/GiantImpact/run.sh +++ /dev/null @@ -1,23 +0,0 @@ -#!/bin/bash - -# Get the initial conditions if they are not present. -if [ ! -e uranus_1e6.hdf5 ] -then - echo "Fetching initial conditions file for the Uranus impact example..." - ./get_init_cond.sh -fi - -# Get the EoS tables if they are not present. -cd ../EoSTables -if [ ! -e HM80_HHe.txt ] || [ ! -e HM80_ice.txt ] || [ ! -e HM80_rock.txt ] -then - echo "Fetching equations of state tables for the Uranus impact example..." - ./get_eos_tables.sh -fi -cd ../GiantImpact - -# Run SWIFT -../../swift -s -G -t 8 uranus_1e6.yml 2>&1 | tee output.log - -# Plot the solution -python3 plot_solution.py diff --git a/examples/GiantImpacts/GiantImpact/system.yml b/examples/GiantImpacts/GiantImpact/system.yml deleted file mode 100644 index c99fc7158854ec538e68c44ff74bbb0ba1adfb48..0000000000000000000000000000000000000000 --- a/examples/GiantImpacts/GiantImpact/system.yml +++ /dev/null @@ -1,9 +0,0 @@ -input: - - uranus_1e6.yml - - output_list.txt - -output: - - uranus_1e6.pdf - -swift_parameters: -s -G -swift_threads: 8 diff --git a/examples/HydroTests/KelvinHelmholtz_2D/makeMovieSwiftsimIO.py b/examples/HydroTests/KelvinHelmholtz_2D/makeMovieSwiftsimIO.py index a86445e0a369bb3697793be72a3053d20f597e45..b754aeda7b515791217ddef3c89dbdadf0cf8eca 100644 --- a/examples/HydroTests/KelvinHelmholtz_2D/makeMovieSwiftsimIO.py +++ b/examples/HydroTests/KelvinHelmholtz_2D/makeMovieSwiftsimIO.py @@ -17,11 +17,12 @@ import scipy.interpolate as si from swiftsimio import load from swiftsimio.visualisation import project_gas_pixel_grid + def load_and_extract(filename): """ Load the data and extract relevant info. """ - + return load(filename) @@ -34,11 +35,11 @@ def make_plot(filename, array, nx, ny, dx, dy): data = load_and_extract(filename) - mesh = project_gas_pixel_grid(data, nx) + mesh = project_gas_pixel_grid(data, nx).T array.set_array(mesh) - return array, + return (array,) def frame(n, *args): @@ -55,6 +56,7 @@ def frame(n, *args): if __name__ == "__main__": import matplotlib + matplotlib.use("Agg") from tqdm import tqdm @@ -66,7 +68,6 @@ if __name__ == "__main__": filename = "kelvinHelmholtz" dpi = 512 - # Look for the number of files in the directory. i = 0 while True: @@ -76,8 +77,7 @@ if __name__ == "__main__": break if i > 10000: - raise FileNotFoundError( - "Could not find the snapshots in the directory") + raise FileNotFoundError("Could not find the snapshots in the directory") frames = tqdm(np.arange(0, i)) @@ -87,11 +87,18 @@ if __name__ == "__main__": data = load_and_extract("kelvinHelmholtz_0000.hdf5") - mesh = project_gas_pixel_grid(data, dpi) - + # Global variable for set_array - plot = ax.imshow(mesh, extent=[0, 1, 0, 1], animated=True, interpolation="none") + plot = ax.imshow( + mesh, + extent=[0, 1, 0, 1], + animated=True, + interpolation="none", + vmin=1, + vmax=2, + cmap="RdBu_r", + ) anim = FuncAnimation(fig, frame, frames, interval=40, blit=False) @@ -99,4 +106,4 @@ if __name__ == "__main__": fig.subplots_adjust(left=0, bottom=0, right=1, top=1, wspace=None, hspace=None) # Actually make the movie - anim.save("khmovie.mp4", dpi=dpi, bitrate=4096) + anim.save("khmovie.mp4", dpi=dpi) diff --git a/examples/HydroTests/SedovBlast_1D/plotSolution.py b/examples/HydroTests/SedovBlast_1D/plotSolution.py index d82ad9e94610a916d900ea93863b2881757e73b3..231d32ab02adac8a2b785651a149a7f00101ebf2 100644 --- a/examples/HydroTests/SedovBlast_1D/plotSolution.py +++ b/examples/HydroTests/SedovBlast_1D/plotSolution.py @@ -1,31 +1,31 @@ ############################################################################### - # This file is part of SWIFT. - # Copyright (c) 2015 Bert Vandenbroucke (bert.vandenbroucke@ugent.be) - # 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/>. - # - ############################################################################## +# This file is part of SWIFT. +# Copyright (c) 2015 Bert Vandenbroucke (bert.vandenbroucke@ugent.be) +# 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 analytical solution of the 2D Sedov blast wave. # The script works for a given initial box and dumped energy and computes the solution at a later time t. # Parameters -rho_0 = 1. # Background Density -P_0 = 1.e-6 # Background Pressure -E_0 = 1. # Energy of the explosion -gas_gamma = 5./3. # Gas polytropic index +rho_0 = 1.0 # Background Density +P_0 = 1.0e-6 # Background Pressure +E_0 = 1.0 # Energy of the explosion +gas_gamma = 5.0 / 3.0 # Gas polytropic index # --------------------------------------------------------------- @@ -33,38 +33,19 @@ gas_gamma = 5./3. # Gas polytropic index # --------------------------------------------------------------- import matplotlib + matplotlib.use("Agg") from pylab import * import h5py # Plot parameters -params = {'axes.labelsize': 10, -'axes.titlesize': 10, -'font.size': 12, -'legend.fontsize': 12, -'xtick.labelsize': 10, -'ytick.labelsize': 10, -'text.usetex': True, - 'figure.figsize' : (9.90,6.45), -'figure.subplot.left' : 0.045, -'figure.subplot.right' : 0.99, -'figure.subplot.bottom' : 0.05, -'figure.subplot.top' : 0.99, -'figure.subplot.wspace' : 0.15, -'figure.subplot.hspace' : 0.12, -'lines.markersize' : 6, -'lines.linewidth' : 3., -'text.latex.unicode': True -} -rcParams.update(params) -rc('font',**{'family':'sans-serif','sans-serif':['Times']}) - +style.use("../../../tools/stylesheets/mnras.mplstyle") snap = int(sys.argv[1]) # Read the simulation data -sim = h5py.File("sedov_%04d.hdf5"%snap, "r") +sim = h5py.File("sedov_%04d.hdf5" % snap, "r") boxSize = sim["/Header"].attrs["BoxSize"][0] time = sim["/Header"].attrs["Time"][0] scheme = sim["/HydroScheme"].attrs["Scheme"] @@ -73,21 +54,28 @@ neighbours = sim["/HydroScheme"].attrs["Kernel target N_ngb"] eta = sim["/HydroScheme"].attrs["Kernel eta"] git = sim["Code"].attrs["Git Revision"] -pos = sim["/PartType0/Coordinates"][:,:] -x = pos[:,0] - boxSize / 2 -vel = sim["/PartType0/Velocities"][:,:] +pos = sim["/PartType0/Coordinates"][:, :] +x = pos[:, 0] - boxSize / 2 +vel = sim["/PartType0/Velocities"][:, :] r = abs(x) -v_r = x * vel[:,0] / r +v_r = x * vel[:, 0] / r u = sim["/PartType0/InternalEnergies"][:] S = sim["/PartType0/Entropies"][:] P = sim["/PartType0/Pressures"][:] rho = sim["/PartType0/Densities"][:] + +try: + diffusion = sim["/PartType0/DiffusionParameters"][:] + plot_diffusion = True +except: + plot_diffusion = False + try: - alpha = sim["/PartType0/ViscosityParameters"][:] - plot_alpha = True + viscosity = sim["/PartType0/ViscosityParameters"][:] + plot_viscosity = True except: - plot_alpha = False + plot_viscosity = False # Now, work our the solution.... @@ -95,25 +83,29 @@ except: from scipy.special import gamma as Gamma from numpy import * -def calc_a(g,nu=3): + +def calc_a(g, nu=3): """ exponents of the polynomials of the sedov solution g - the polytropic gamma nu - the dimension """ - a = [0]*8 - + a = [0] * 8 + a[0] = 2.0 / (nu + 2) - a[2] = (1-g) / (2*(g-1) + nu) - a[3] = nu / (2*(g-1) + nu) - a[5] = 2 / (g-2) - a[6] = g / (2*(g-1) + nu) - - a[1] = (((nu+2)*g)/(2.0+nu*(g-1.0)) ) * ( (2.0*nu*(2.0-g))/(g*(nu+2.0)**2) - a[2]) - a[4] = a[1]*(nu+2) / (2-g) - a[7] = (2 + nu*(g-1))*a[1]/(nu*(2-g)) + a[2] = (1 - g) / (2 * (g - 1) + nu) + a[3] = nu / (2 * (g - 1) + nu) + a[5] = 2 / (g - 2) + a[6] = g / (2 * (g - 1) + nu) + + a[1] = (((nu + 2) * g) / (2.0 + nu * (g - 1.0))) * ( + (2.0 * nu * (2.0 - g)) / (g * (nu + 2.0) ** 2) - a[2] + ) + a[4] = a[1] * (nu + 2) / (2 - g) + a[7] = (2 + nu * (g - 1)) * a[1] / (nu * (2 - g)) return a + def calc_beta(v, g, nu=3): """ beta values for the sedov solution (coefficients of the polynomials of the similarity variables) @@ -122,15 +114,33 @@ def calc_beta(v, g, nu=3): nu- the dimension """ - beta = (nu+2) * (g+1) * array((0.25, (g/(g-1))*0.5, - -(2 + nu*(g-1))/2.0 / ((nu+2)*(g+1) -2*(2 + nu*(g-1))), - -0.5/(g-1)), dtype=float64) + beta = ( + (nu + 2) + * (g + 1) + * array( + ( + 0.25, + (g / (g - 1)) * 0.5, + -(2 + nu * (g - 1)) + / 2.0 + / ((nu + 2) * (g + 1) - 2 * (2 + nu * (g - 1))), + -0.5 / (g - 1), + ), + dtype=float64, + ) + ) beta = outer(beta, v) - beta += (g+1) * array((0.0, -1.0/(g-1), - (nu+2) / ((nu+2)*(g+1) -2.0*(2 + nu*(g-1))), - 1.0/(g-1)), dtype=float64).reshape((4,1)) + beta += (g + 1) * array( + ( + 0.0, + -1.0 / (g - 1), + (nu + 2) / ((nu + 2) * (g + 1) - 2.0 * (2 + nu * (g - 1))), + 1.0 / (g - 1), + ), + dtype=float64, + ).reshape((4, 1)) return beta @@ -154,9 +164,11 @@ def sedov(t, E0, rho0, g, n=1000, nu=3): a = calc_a(g, nu) beta = calc_beta(v, g=g, nu=nu) lbeta = log(beta) - + r = exp(-a[0] * lbeta[0] - a[2] * lbeta[1] - a[1] * lbeta[2]) - rho = ((g + 1.0) / (g - 1.0)) * exp(a[3] * lbeta[1] + a[5] * lbeta[3] + a[4] * lbeta[2]) + rho = ((g + 1.0) / (g - 1.0)) * exp( + a[3] * lbeta[1] + a[5] * lbeta[3] + a[4] * lbeta[2] + ) p = exp(nu * a[0] * lbeta[0] + (a[5] + 1) * lbeta[3] + (a[4] - 2 * a[1]) * lbeta[2]) u = beta[0] * r * 4.0 / ((g + 1) * (nu + 2)) p *= 8.0 / ((g + 1) * (nu + 2) * (nu + 2)) @@ -165,14 +177,17 @@ def sedov(t, E0, rho0, g, n=1000, nu=3): # It is not a singularity, however, the gradients of our variables (wrt v) are. # r -> 0, u -> 0, rho -> 0, p-> constant - u[0] = 0.0; rho[0] = 0.0; r[0] = 0.0; p[0] = p[1] + u[0] = 0.0 + rho[0] = 0.0 + r[0] = 0.0 + p[0] = p[1] # volume of an n-sphere vol = (pi ** (nu / 2.0) / Gamma(nu / 2.0 + 1)) * power(r, nu) # note we choose to evaluate the integral in this way because the - # volumes of the first few elements (i.e near v=vmin) are shrinking - # very slowly, so we dramatically improve the error convergence by + # volumes of the first few elements (i.e near v=vmin) are shrinking + # very slowly, so we dramatically improve the error convergence by # finding the volumes exactly. This is most important for the # pressure integral, as this is on the order of the volume. @@ -186,11 +201,11 @@ def sedov(t, E0, rho0, g, n=1000, nu=3): # shock speed shock_speed = fac * (2.0 / (nu + 2)) - rho_s = ((g + 1) / (g - 1)) * rho0 + rho_s = ((g + 1) / (g - 1)) * rho0 r_s = shock_speed * t * (nu + 2) / 2.0 p_s = (2.0 * rho0 * shock_speed * shock_speed) / (g + 1) u_s = (2.0 * shock_speed) / (g + 1) - + r *= fac * t u *= fac p *= fac * fac * rho0 @@ -202,93 +217,115 @@ def sedov(t, E0, rho0, g, n=1000, nu=3): r_s, P_s, rho_s, v_s, r_shock, _, _, _, _ = sedov(time, E_0, rho_0, gas_gamma, 1000, 1) # Append points for after the shock -r_s = np.insert(r_s, np.size(r_s), [r_shock, r_shock*1.5]) +r_s = np.insert(r_s, np.size(r_s), [r_shock, r_shock * 1.5]) rho_s = np.insert(rho_s, np.size(rho_s), [rho_0, rho_0]) P_s = np.insert(P_s, np.size(P_s), [P_0, P_0]) v_s = np.insert(v_s, np.size(v_s), [0, 0]) # Additional arrays -u_s = P_s / (rho_s * (gas_gamma - 1.)) #internal energy -s_s = P_s / rho_s**gas_gamma # entropic function - +u_s = P_s / (rho_s * (gas_gamma - 1.0)) # internal energy +s_s = P_s / rho_s ** gas_gamma # entropic function # Plot the interesting quantities -figure() +figure(figsize=(7, 7 / 1.6)) + +line_color = "C4" + +scatter_props = dict( + marker=".", + ms=1, + markeredgecolor="none", + alpha=1.0, + zorder=-1, + rasterized=True, + linestyle="none", +) # Velocity profile -------------------------------- subplot(231) -plot(r, v_r, '.', color='r', ms=2.) -plot(r_s, v_s, '--', color='k', alpha=0.8, lw=1.2) -xlabel("${\\rm{Radius}}~r$", labelpad=0) -ylabel("${\\rm{Radial~velocity}}~v_r$", labelpad=0) +plot(r, v_r, **scatter_props) +plot(r_s, v_s, "--", color=line_color, alpha=0.8, lw=1.2) +xlabel("Radius $r$") +ylabel("Radialvelocity $v_r$") xlim(0, 1.3 * r_shock) ylim(-0.2, 3.8) # Density profile -------------------------------- subplot(232) -plot(r, rho, '.', color='r', ms=2.) -plot(r_s, rho_s, '--', color='k', alpha=0.8, lw=1.2) -xlabel("${\\rm{Radius}}~r$", labelpad=0) -ylabel("${\\rm{Density}}~\\rho$", labelpad=2) +plot(r, rho, **scatter_props) +plot(r_s, rho_s, "--", color=line_color, alpha=0.8, lw=1.2) +xlabel("Radius $r$") +ylabel("Density $\\rho$") xlim(0, 1.3 * r_shock) ylim(-0.2, 5.2) # Pressure profile -------------------------------- subplot(233) -plot(r, P, '.', color='r', ms=2.) -plot(r_s, P_s, '--', color='k', alpha=0.8, lw=1.2) -xlabel("${\\rm{Radius}}~r$", labelpad=0) -ylabel("${\\rm{Pressure}}~P$", labelpad=0) +plot(r, P, **scatter_props) +plot(r_s, P_s, "--", color=line_color, alpha=0.8, lw=1.2) +xlabel("Radius $r$") +ylabel("Pressure $P$") xlim(0, 1.3 * r_shock) ylim(-1, 12.5) # Internal energy profile ------------------------- subplot(234) -plot(r, u, '.', color='r', ms=2.) -plot(r_s, u_s, '--', color='k', alpha=0.8, lw=1.2) -xlabel("${\\rm{Radius}}~r$", labelpad=0) -ylabel("${\\rm{Internal~Energy}}~u$", labelpad=0) +plot(r, u, **scatter_props) +plot(r_s, u_s, "--", color=line_color, alpha=0.8, lw=1.2) +xlabel("Radius $r$") +ylabel("Internal Energy $u$") xlim(0, 1.3 * r_shock) ylim(-2, 22) -# Entropy/alpha profile --------------------------------- +# Entropy profile --------------------------------- subplot(235) +xlabel("Radius $r$") +if plot_diffusion or plot_viscosity: + if plot_diffusion: + plot(r, diffusion, **scatter_props) + + if plot_viscosity: + plot(r, viscosity, **scatter_props) -if plot_alpha: - plot(r, alpha, '.', color='r', ms=2.0) - plot([r_shock, r_shock], [-1, 2], "--", color="k", alpha=0.8, lw=1.2) - ylabel(r"${\rm{Viscosity}}~\alpha$", labelpad=0) - # Show location of shock - ylim(0, 2) + ylabel(r"Rate Coefficient $\alpha$", labelpad=0) + legend() else: - plot(r, S, '.', color='r', ms=2.0) - plot(r_s, s_s, '--', color='k', alpha=0.8, lw=1.2) - ylabel("${\\rm{Entropy}}~S$", labelpad=0) + plot(r, S, **scatter_props) + plot(r_s, s_s, "--", color=line_color, alpha=0.8, lw=1.2) + ylabel("Entropy $S$", labelpad=0) ylim(-5, 50) -xlabel("${\\rm{Radius}}~r$", labelpad=0) xlim(0, 1.3 * r_shock) - # Information ------------------------------------- subplot(236, frameon=False) -text(-0.49, 0.9, "Sedov blast with $\\gamma=%.3f$ in 1D at $t=%.2f$"%(gas_gamma,time), fontsize=10) -text(-0.49, 0.8, "Background $\\rho_0=%.2f$"%(rho_0), fontsize=10) -text(-0.49, 0.7, "Energy injected $E_0=%.2f$"%(E_0), fontsize=10) -plot([-0.49, 0.1], [0.62, 0.62], 'k-', lw=1) -text(-0.49, 0.5, "$\\textsc{Swift}$ %s"%git, fontsize=10) -text(-0.49, 0.4, scheme, fontsize=10) -text(-0.49, 0.3, kernel, fontsize=10) -text(-0.49, 0.2, "$%.2f$ neighbours ($\\eta=%.3f$)"%(neighbours, eta), fontsize=10) +text_fontsize = 5 + +text( + -0.45, + 0.9, + "Sedov blast with $\\gamma=%.3f$ in 3D at $t=%.2f$" % (gas_gamma, time), + fontsize=text_fontsize, +) +text(-0.45, 0.8, "Background $\\rho_0=%.2f$" % (rho_0), fontsize=text_fontsize) +text(-0.45, 0.7, "Energy injected $E_0=%.2f$" % (E_0), fontsize=text_fontsize) +plot([-0.45, 0.1], [0.62, 0.62], "k-", lw=1) +text(-0.45, 0.5, "SWIFT %s" % git.decode("utf-8"), fontsize=text_fontsize) +text(-0.45, 0.4, scheme.decode("utf-8"), fontsize=text_fontsize) +text(-0.45, 0.3, kernel.decode("utf-8"), fontsize=text_fontsize) +text( + -0.45, + 0.2, + "$%.2f$ neighbours ($\\eta=%.3f$)" % (neighbours, eta), + fontsize=text_fontsize, +) xlim(-0.5, 0.5) ylim(0, 1) xticks([]) yticks([]) +tight_layout() -savefig("Sedov.png", dpi=200) - - - +savefig("Sedov.png") diff --git a/examples/HydroTests/SedovBlast_2D/plotSolution.py b/examples/HydroTests/SedovBlast_2D/plotSolution.py index 6f504a09c9432368ce141ec0d28c28699f5ba7f3..d18b9de84dcce969d203fdf34dd1e08406e12cd0 100644 --- a/examples/HydroTests/SedovBlast_2D/plotSolution.py +++ b/examples/HydroTests/SedovBlast_2D/plotSolution.py @@ -1,31 +1,31 @@ ############################################################################### - # This file is part of SWIFT. - # Copyright (c) 2015 Bert Vandenbroucke (bert.vandenbroucke@ugent.be) - # 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/>. - # - ############################################################################## +# This file is part of SWIFT. +# Copyright (c) 2015 Bert Vandenbroucke (bert.vandenbroucke@ugent.be) +# 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 analytical solution of the 2D Sedov blast wave. # The script works for a given initial box and dumped energy and computes the solution at a later time t. # Parameters -rho_0 = 1. # Background Density -P_0 = 1.e-6 # Background Pressure -E_0 = 1. # Energy of the explosion -gas_gamma = 5./3. # Gas polytropic index +rho_0 = 1.0 # Background Density +P_0 = 1.0e-6 # Background Pressure +E_0 = 1.0 # Energy of the explosion +gas_gamma = 5.0 / 3.0 # Gas polytropic index # --------------------------------------------------------------- @@ -33,39 +33,18 @@ gas_gamma = 5./3. # Gas polytropic index # --------------------------------------------------------------- import matplotlib + matplotlib.use("Agg") from pylab import * from scipy import stats import h5py -# Plot parameters -params = {'axes.labelsize': 10, -'axes.titlesize': 10, -'font.size': 12, -'legend.fontsize': 12, -'xtick.labelsize': 10, -'ytick.labelsize': 10, -'text.usetex': True, - 'figure.figsize' : (9.90,6.45), -'figure.subplot.left' : 0.045, -'figure.subplot.right' : 0.99, -'figure.subplot.bottom' : 0.05, -'figure.subplot.top' : 0.99, -'figure.subplot.wspace' : 0.15, -'figure.subplot.hspace' : 0.12, -'lines.markersize' : 6, -'lines.linewidth' : 3., -'text.latex.unicode': True -} -rcParams.update(params) -rc('font',**{'family':'sans-serif','sans-serif':['Times']}) - +style.use("../../../tools/stylesheets/mnras.mplstyle") snap = int(sys.argv[1]) - # Read the simulation data -sim = h5py.File("sedov_%04d.hdf5"%snap, "r") +sim = h5py.File("sedov_%04d.hdf5" % snap, "r") boxSize = sim["/Header"].attrs["BoxSize"][0] time = sim["/Header"].attrs["Time"][0] scheme = sim["/HydroScheme"].attrs["Scheme"] @@ -74,60 +53,94 @@ neighbours = sim["/HydroScheme"].attrs["Kernel target N_ngb"] eta = sim["/HydroScheme"].attrs["Kernel eta"] git = sim["Code"].attrs["Git Revision"] -pos = sim["/PartType0/Coordinates"][:,:] -x = pos[:,0] - boxSize / 2 -y = pos[:,1] - boxSize / 2 -vel = sim["/PartType0/Velocities"][:,:] -r = sqrt(x**2 + y**2) -v_r = (x * vel[:,0] + y * vel[:,1]) / r +pos = sim["/PartType0/Coordinates"][:, :] +x = pos[:, 0] - boxSize / 2 +y = pos[:, 1] - boxSize / 2 +vel = sim["/PartType0/Velocities"][:, :] +r = sqrt(x ** 2 + y ** 2) +v_r = (x * vel[:, 0] + y * vel[:, 1]) / r u = sim["/PartType0/InternalEnergies"][:] S = sim["/PartType0/Entropies"][:] P = sim["/PartType0/Pressures"][:] rho = sim["/PartType0/Densities"][:] +try: + diffusion = sim["/PartType0/DiffusionParameters"][:] + plot_diffusion = True +except: + plot_diffusion = False + +try: + viscosity = sim["/PartType0/ViscosityParameters"][:] + plot_viscosity = True +except: + plot_viscosity = False + # Bin te data -r_bin_edge = np.arange(0., 0.5, 0.01) -r_bin = 0.5*(r_bin_edge[1:] + r_bin_edge[:-1]) -rho_bin,_,_ = stats.binned_statistic(r, rho, statistic='mean', bins=r_bin_edge) -v_bin,_,_ = stats.binned_statistic(r, v_r, statistic='mean', bins=r_bin_edge) -P_bin,_,_ = stats.binned_statistic(r, P, statistic='mean', bins=r_bin_edge) -S_bin,_,_ = stats.binned_statistic(r, S, statistic='mean', bins=r_bin_edge) -u_bin,_,_ = stats.binned_statistic(r, u, statistic='mean', bins=r_bin_edge) -rho2_bin,_,_ = stats.binned_statistic(r, rho**2, statistic='mean', bins=r_bin_edge) -v2_bin,_,_ = stats.binned_statistic(r, v_r**2, statistic='mean', bins=r_bin_edge) -P2_bin,_,_ = stats.binned_statistic(r, P**2, statistic='mean', bins=r_bin_edge) -S2_bin,_,_ = stats.binned_statistic(r, S**2, statistic='mean', bins=r_bin_edge) -u2_bin,_,_ = stats.binned_statistic(r, u**2, statistic='mean', bins=r_bin_edge) -rho_sigma_bin = np.sqrt(rho2_bin - rho_bin**2) -v_sigma_bin = np.sqrt(v2_bin - v_bin**2) -P_sigma_bin = np.sqrt(P2_bin - P_bin**2) -S_sigma_bin = np.sqrt(S2_bin - S_bin**2) -u_sigma_bin = np.sqrt(u2_bin - u_bin**2) +r_bin_edge = np.arange(0.0, 0.5, 0.01) +r_bin = 0.5 * (r_bin_edge[1:] + r_bin_edge[:-1]) +rho_bin, _, _ = stats.binned_statistic(r, rho, statistic="mean", bins=r_bin_edge) +v_bin, _, _ = stats.binned_statistic(r, v_r, statistic="mean", bins=r_bin_edge) +P_bin, _, _ = stats.binned_statistic(r, P, statistic="mean", bins=r_bin_edge) +S_bin, _, _ = stats.binned_statistic(r, S, statistic="mean", bins=r_bin_edge) +u_bin, _, _ = stats.binned_statistic(r, u, statistic="mean", bins=r_bin_edge) +rho2_bin, _, _ = stats.binned_statistic(r, rho ** 2, statistic="mean", bins=r_bin_edge) +v2_bin, _, _ = stats.binned_statistic(r, v_r ** 2, statistic="mean", bins=r_bin_edge) +P2_bin, _, _ = stats.binned_statistic(r, P ** 2, statistic="mean", bins=r_bin_edge) +S2_bin, _, _ = stats.binned_statistic(r, S ** 2, statistic="mean", bins=r_bin_edge) +u2_bin, _, _ = stats.binned_statistic(r, u ** 2, statistic="mean", bins=r_bin_edge) +rho_sigma_bin = np.sqrt(rho2_bin - rho_bin ** 2) +v_sigma_bin = np.sqrt(v2_bin - v_bin ** 2) +P_sigma_bin = np.sqrt(P2_bin - P_bin ** 2) +S_sigma_bin = np.sqrt(S2_bin - S_bin ** 2) +u_sigma_bin = np.sqrt(u2_bin - u_bin ** 2) + +if plot_diffusion: + alpha_diff_bin, _, _ = stats.binned_statistic( + r, diffusion, statistic="mean", bins=r_bin_edge + ) + alpha2_diff_bin, _, _ = stats.binned_statistic( + r, diffusion ** 2, statistic="mean", bins=r_bin_edge + ) + alpha_diff_sigma_bin = np.sqrt(alpha2_diff_bin - alpha_diff_bin ** 2) + +if plot_viscosity: + alpha_visc_bin, _, _ = stats.binned_statistic( + r, viscosity, statistic="mean", bins=r_bin_edge + ) + alpha2_visc_bin, _, _ = stats.binned_statistic( + r, viscosity ** 2, statistic="mean", bins=r_bin_edge + ) + alpha_visc_sigma_bin = np.sqrt(alpha2_visc_bin - alpha_visc_bin ** 2) # Now, work our the solution.... from scipy.special import gamma as Gamma from numpy import * -def calc_a(g,nu=3): + +def calc_a(g, nu=3): """ exponents of the polynomials of the sedov solution g - the polytropic gamma nu - the dimension """ - a = [0]*8 - + a = [0] * 8 + a[0] = 2.0 / (nu + 2) - a[2] = (1-g) / (2*(g-1) + nu) - a[3] = nu / (2*(g-1) + nu) - a[5] = 2 / (g-2) - a[6] = g / (2*(g-1) + nu) - - a[1] = (((nu+2)*g)/(2.0+nu*(g-1.0)) ) * ( (2.0*nu*(2.0-g))/(g*(nu+2.0)**2) - a[2]) - a[4] = a[1]*(nu+2) / (2-g) - a[7] = (2 + nu*(g-1))*a[1]/(nu*(2-g)) + a[2] = (1 - g) / (2 * (g - 1) + nu) + a[3] = nu / (2 * (g - 1) + nu) + a[5] = 2 / (g - 2) + a[6] = g / (2 * (g - 1) + nu) + + a[1] = (((nu + 2) * g) / (2.0 + nu * (g - 1.0))) * ( + (2.0 * nu * (2.0 - g)) / (g * (nu + 2.0) ** 2) - a[2] + ) + a[4] = a[1] * (nu + 2) / (2 - g) + a[7] = (2 + nu * (g - 1)) * a[1] / (nu * (2 - g)) return a + def calc_beta(v, g, nu=3): """ beta values for the sedov solution (coefficients of the polynomials of the similarity variables) @@ -136,15 +149,33 @@ def calc_beta(v, g, nu=3): nu- the dimension """ - beta = (nu+2) * (g+1) * array((0.25, (g/(g-1))*0.5, - -(2 + nu*(g-1))/2.0 / ((nu+2)*(g+1) -2*(2 + nu*(g-1))), - -0.5/(g-1)), dtype=float64) + beta = ( + (nu + 2) + * (g + 1) + * array( + ( + 0.25, + (g / (g - 1)) * 0.5, + -(2 + nu * (g - 1)) + / 2.0 + / ((nu + 2) * (g + 1) - 2 * (2 + nu * (g - 1))), + -0.5 / (g - 1), + ), + dtype=float64, + ) + ) beta = outer(beta, v) - beta += (g+1) * array((0.0, -1.0/(g-1), - (nu+2) / ((nu+2)*(g+1) -2.0*(2 + nu*(g-1))), - 1.0/(g-1)), dtype=float64).reshape((4,1)) + beta += (g + 1) * array( + ( + 0.0, + -1.0 / (g - 1), + (nu + 2) / ((nu + 2) * (g + 1) - 2.0 * (2 + nu * (g - 1))), + 1.0 / (g - 1), + ), + dtype=float64, + ).reshape((4, 1)) return beta @@ -168,9 +199,11 @@ def sedov(t, E0, rho0, g, n=1000, nu=3): a = calc_a(g, nu) beta = calc_beta(v, g=g, nu=nu) lbeta = log(beta) - + r = exp(-a[0] * lbeta[0] - a[2] * lbeta[1] - a[1] * lbeta[2]) - rho = ((g + 1.0) / (g - 1.0)) * exp(a[3] * lbeta[1] + a[5] * lbeta[3] + a[4] * lbeta[2]) + rho = ((g + 1.0) / (g - 1.0)) * exp( + a[3] * lbeta[1] + a[5] * lbeta[3] + a[4] * lbeta[2] + ) p = exp(nu * a[0] * lbeta[0] + (a[5] + 1) * lbeta[3] + (a[4] - 2 * a[1]) * lbeta[2]) u = beta[0] * r * 4.0 / ((g + 1) * (nu + 2)) p *= 8.0 / ((g + 1) * (nu + 2) * (nu + 2)) @@ -179,14 +212,17 @@ def sedov(t, E0, rho0, g, n=1000, nu=3): # It is not a singularity, however, the gradients of our variables (wrt v) are. # r -> 0, u -> 0, rho -> 0, p-> constant - u[0] = 0.0; rho[0] = 0.0; r[0] = 0.0; p[0] = p[1] + u[0] = 0.0 + rho[0] = 0.0 + r[0] = 0.0 + p[0] = p[1] # volume of an n-sphere vol = (pi ** (nu / 2.0) / Gamma(nu / 2.0 + 1)) * power(r, nu) # note we choose to evaluate the integral in this way because the - # volumes of the first few elements (i.e near v=vmin) are shrinking - # very slowly, so we dramatically improve the error convergence by + # volumes of the first few elements (i.e near v=vmin) are shrinking + # very slowly, so we dramatically improve the error convergence by # finding the volumes exactly. This is most important for the # pressure integral, as this is on the order of the volume. @@ -200,11 +236,11 @@ def sedov(t, E0, rho0, g, n=1000, nu=3): # shock speed shock_speed = fac * (2.0 / (nu + 2)) - rho_s = ((g + 1) / (g - 1)) * rho0 + rho_s = ((g + 1) / (g - 1)) * rho0 r_s = shock_speed * t * (nu + 2) / 2.0 p_s = (2.0 * rho0 * shock_speed * shock_speed) / (g + 1) u_s = (2.0 * shock_speed) / (g + 1) - + r *= fac * t u *= fac p *= fac * fac * rho0 @@ -216,89 +252,140 @@ def sedov(t, E0, rho0, g, n=1000, nu=3): r_s, P_s, rho_s, v_s, r_shock, _, _, _, _ = sedov(time, E_0, rho_0, gas_gamma, 1000, 2) # Append points for after the shock -r_s = np.insert(r_s, np.size(r_s), [r_shock, r_shock*1.5]) +r_s = np.insert(r_s, np.size(r_s), [r_shock, r_shock * 1.5]) rho_s = np.insert(rho_s, np.size(rho_s), [rho_0, rho_0]) P_s = np.insert(P_s, np.size(P_s), [P_0, P_0]) v_s = np.insert(v_s, np.size(v_s), [0, 0]) # Additional arrays -u_s = P_s / (rho_s * (gas_gamma - 1.)) #internal energy -s_s = P_s / rho_s**gas_gamma # entropic function - +u_s = P_s / (rho_s * (gas_gamma - 1.0)) # internal energy +s_s = P_s / rho_s ** gas_gamma # entropic function # Plot the interesting quantities -figure() +figure(figsize=(7, 7 / 1.6)) + +line_color = "C4" +binned_color = "C2" +binned_marker_size = 4 + +scatter_props = dict( + marker=".", + ms=1, + markeredgecolor="none", + alpha=0.5, + zorder=-1, + rasterized=True, + linestyle="none", +) + +errorbar_props = dict(color=binned_color, ms=binned_marker_size, fmt=".", lw=1.2) # Velocity profile -------------------------------- subplot(231) -plot(r, v_r, '.', color='r', ms=0.5, alpha=0.2) -plot(r_s, v_s, '--', color='k', alpha=0.8, lw=1.2) -errorbar(r_bin, v_bin, yerr=v_sigma_bin, fmt='.', ms=8.0, color='b', lw=1.2) -xlabel("${\\rm{Radius}}~r$", labelpad=0) -ylabel("${\\rm{Radial~velocity}}~v_r$", labelpad=0) +plot(r, v_r, **scatter_props) +plot(r_s, v_s, "--", color=line_color, alpha=0.8, lw=1.2) +errorbar(r_bin, v_bin, yerr=v_sigma_bin, **errorbar_props) +xlabel("Radius $r$") +ylabel("Radialvelocity $v_r$") xlim(0, 1.3 * r_shock) ylim(-0.2, 3.8) # Density profile -------------------------------- subplot(232) -plot(r, rho, '.', color='r', ms=0.5, alpha=0.2) -plot(r_s, rho_s, '--', color='k', alpha=0.8, lw=1.2) -errorbar(r_bin, rho_bin, yerr=rho_sigma_bin, fmt='.', ms=8.0, color='b', lw=1.2) -xlabel("${\\rm{Radius}}~r$", labelpad=0) -ylabel("${\\rm{Density}}~\\rho$", labelpad=2) +plot(r, rho, **scatter_props) +plot(r_s, rho_s, "--", color=line_color, alpha=0.8, lw=1.2) +errorbar(r_bin, rho_bin, yerr=rho_sigma_bin, **errorbar_props) +xlabel("Radius $r$") +ylabel("Density $\\rho$") xlim(0, 1.3 * r_shock) ylim(-0.2, 5.2) # Pressure profile -------------------------------- subplot(233) -plot(r, P, '.', color='r', ms=0.5, alpha=0.2) -plot(r_s, P_s, '--', color='k', alpha=0.8, lw=1.2) -errorbar(r_bin, P_bin, yerr=P_sigma_bin, fmt='.', ms=8.0, color='b', lw=1.2) -xlabel("${\\rm{Radius}}~r$", labelpad=0) -ylabel("${\\rm{Pressure}}~P$", labelpad=0) +plot(r, P, **scatter_props) +plot(r_s, P_s, "--", color=line_color, alpha=0.8, lw=1.2) +errorbar(r_bin, P_bin, yerr=P_sigma_bin, **errorbar_props) +xlabel("Radius $r$") +ylabel("Pressure $P$") xlim(0, 1.3 * r_shock) ylim(-1, 12.5) # Internal energy profile ------------------------- subplot(234) -plot(r, u, '.', color='r', ms=0.5, alpha=0.2) -plot(r_s, u_s, '--', color='k', alpha=0.8, lw=1.2) -errorbar(r_bin, u_bin, yerr=u_sigma_bin, fmt='.', ms=8.0, color='b', lw=1.2) -xlabel("${\\rm{Radius}}~r$", labelpad=0) -ylabel("${\\rm{Internal~Energy}}~u$", labelpad=0) +plot(r, u, **scatter_props) +plot(r_s, u_s, "--", color=line_color, alpha=0.8, lw=1.2) +errorbar(r_bin, u_bin, yerr=u_sigma_bin, **errorbar_props) +xlabel("Radius $r$") +ylabel("Internal Energy $u$") xlim(0, 1.3 * r_shock) ylim(-2, 22) # Entropy profile --------------------------------- subplot(235) -plot(r, S, '.', color='r', ms=0.5, alpha=0.2) -plot(r_s, s_s, '--', color='k', alpha=0.8, lw=1.2) -errorbar(r_bin, S_bin, yerr=S_sigma_bin, fmt='.', ms=8.0, color='b', lw=1.2) -xlabel("${\\rm{Radius}}~r$", labelpad=0) -ylabel("${\\rm{Entropy}}~S$", labelpad=0) -xlim(0, 1.3 * r_shock) -ylim(-5, 50) +xlabel("Radius $r$") +if plot_diffusion or plot_viscosity: + if plot_diffusion: + plot(r, diffusion, **scatter_props) + errorbar( + r_bin, + alpha_diff_bin, + yerr=alpha_diff_sigma_bin, + **errorbar_props, + label="Diffusion", + ) + + if plot_viscosity: + plot(r, viscosity, **scatter_props) + errorbar( + r_bin, + alpha_visc_bin, + yerr=alpha_visc_sigma_bin, + label="Viscosity", + color="C4", + ms=binned_marker_size, + fmt=".", + lw=1.2, + ) + + ylabel(r"Rate Coefficient $\alpha$", labelpad=0) + legend() +else: + plot(r, S, **scatter_props) + plot(r_s, s_s, "--", color=line_color, alpha=0.8, lw=1.2) + errorbar(r_bin, S_bin, yerr=S_sigma_bin, **errorbar_props) + ylabel("Entropy $S$", labelpad=0) + ylim(-5, 50) +xlim(0, 1.3 * r_shock) # Information ------------------------------------- subplot(236, frameon=False) -text(-0.49, 0.9, "Sedov blast with $\\gamma=%.3f$ in 2D at $t=%.2f$"%(gas_gamma,time), fontsize=10) -text(-0.49, 0.8, "Background $\\rho_0=%.2f$"%(rho_0), fontsize=10) -text(-0.49, 0.7, "Energy injected $E_0=%.2f$"%(E_0), fontsize=10) -plot([-0.49, 0.1], [0.62, 0.62], 'k-', lw=1) -text(-0.49, 0.5, "$\\textsc{Swift}$ %s"%git, fontsize=10) -text(-0.49, 0.4, scheme, fontsize=10) -text(-0.49, 0.3, kernel, fontsize=10) -text(-0.49, 0.2, "$%.2f$ neighbours ($\\eta=%.3f$)"%(neighbours, eta), fontsize=10) +text_fontsize = 5 + +text( + -0.45, + 0.9, + "Sedov blast with $\\gamma=%.3f$ in 3D at $t=%.2f$" % (gas_gamma, time), + fontsize=text_fontsize, +) +text(-0.45, 0.8, "Background $\\rho_0=%.2f$" % (rho_0), fontsize=text_fontsize) +text(-0.45, 0.7, "Energy injected $E_0=%.2f$" % (E_0), fontsize=text_fontsize) +plot([-0.45, 0.1], [0.62, 0.62], "k-", lw=1) +text(-0.45, 0.5, "SWIFT %s" % git.decode("utf-8"), fontsize=text_fontsize) +text(-0.45, 0.4, scheme.decode("utf-8"), fontsize=text_fontsize) +text(-0.45, 0.3, kernel.decode("utf-8"), fontsize=text_fontsize) +text( + -0.45, + 0.2, + "$%.2f$ neighbours ($\\eta=%.3f$)" % (neighbours, eta), + fontsize=text_fontsize, +) xlim(-0.5, 0.5) ylim(0, 1) xticks([]) yticks([]) +tight_layout() -savefig("Sedov.png", dpi=200) - - - - +savefig("Sedov.png") diff --git a/examples/HydroTests/SedovBlast_3D/plotSolution.py b/examples/HydroTests/SedovBlast_3D/plotSolution.py index fec4f1101406be5803a3f1601812d1cb85275409..b1c2278f800c89fa6d7190cafc6b79cdefd57443 100644 --- a/examples/HydroTests/SedovBlast_3D/plotSolution.py +++ b/examples/HydroTests/SedovBlast_3D/plotSolution.py @@ -1,31 +1,31 @@ ############################################################################### - # This file is part of SWIFT. - # Copyright (c) 2015 Bert Vandenbroucke (bert.vandenbroucke@ugent.be) - # 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/>. - # - ############################################################################## +# This file is part of SWIFT. +# Copyright (c) 2015 Bert Vandenbroucke (bert.vandenbroucke@ugent.be) +# 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 analytical solution of the 3D Sedov blast wave. # The script works for a given initial box and dumped energy and computes the solution at a later time t. # Parameters -rho_0 = 1. # Background Density -P_0 = 1.e-6 # Background Pressure -E_0 = 1.0 # Energy of the explosion -gas_gamma = 5./3. # Gas polytropic index +rho_0 = 1.0 # Background Density +P_0 = 1.0e-6 # Background Pressure +E_0 = 1.0 # Energy of the explosion +gas_gamma = 5.0 / 3.0 # Gas polytropic index # --------------------------------------------------------------- @@ -33,39 +33,19 @@ gas_gamma = 5./3. # Gas polytropic index # --------------------------------------------------------------- import matplotlib + matplotlib.use("Agg") from pylab import * +from numpy import power from scipy import stats import h5py -# Plot parameters -params = {'axes.labelsize': 10, -'axes.titlesize': 10, -'font.size': 12, -'legend.fontsize': 12, -'xtick.labelsize': 10, -'ytick.labelsize': 10, -'text.usetex': True, - 'figure.figsize' : (9.90,6.45), -'figure.subplot.left' : 0.045, -'figure.subplot.right' : 0.99, -'figure.subplot.bottom' : 0.05, -'figure.subplot.top' : 0.99, -'figure.subplot.wspace' : 0.15, -'figure.subplot.hspace' : 0.12, -'lines.markersize' : 6, -'lines.linewidth' : 3., -'text.latex.unicode': True -} -rcParams.update(params) -rc('font',**{'family':'sans-serif','sans-serif':['Times']}) - +style.use("../../../tools/stylesheets/mnras.mplstyle") snap = int(sys.argv[1]) - # Read the simulation data -sim = h5py.File("sedov_%04d.hdf5"%snap, "r") +sim = h5py.File("sedov_%04d.hdf5" % snap, "r") boxSize = sim["/Header"].attrs["BoxSize"][0] time = sim["/Header"].attrs["Time"][0] scheme = sim["/HydroScheme"].attrs["Scheme"] @@ -74,13 +54,13 @@ neighbours = sim["/HydroScheme"].attrs["Kernel target N_ngb"] eta = sim["/HydroScheme"].attrs["Kernel eta"] git = sim["Code"].attrs["Git Revision"] -pos = sim["/PartType0/Coordinates"][:,:] -x = pos[:,0] - boxSize / 2 -y = pos[:,1] - boxSize / 2 -z = pos[:,2] - boxSize / 2 -vel = sim["/PartType0/Velocities"][:,:] -r = sqrt(x**2 + y**2 + z**2) -v_r = (x * vel[:,0] + y * vel[:,1] + z * vel[:,2]) / r +pos = sim["/PartType0/Coordinates"][:, :] +x = pos[:, 0] - boxSize / 2 +y = pos[:, 1] - boxSize / 2 +z = pos[:, 2] - boxSize / 2 +vel = sim["/PartType0/Velocities"][:, :] +r = sqrt(x ** 2 + y ** 2 + z ** 2) +v_r = (x * vel[:, 0] + y * vel[:, 1] + z * vel[:, 2]) / r u = sim["/PartType0/InternalEnergies"][:] S = sim["/PartType0/Entropies"][:] P = sim["/PartType0/Pressures"][:] @@ -99,59 +79,70 @@ except: plot_viscosity = False # Bin te data -r_bin_edge = np.arange(0., 0.5, 0.01) -r_bin = 0.5*(r_bin_edge[1:] + r_bin_edge[:-1]) -rho_bin,_,_ = stats.binned_statistic(r, rho, statistic='mean', bins=r_bin_edge) -v_bin,_,_ = stats.binned_statistic(r, v_r, statistic='mean', bins=r_bin_edge) -P_bin,_,_ = stats.binned_statistic(r, P, statistic='mean', bins=r_bin_edge) -S_bin,_,_ = stats.binned_statistic(r, S, statistic='mean', bins=r_bin_edge) -u_bin,_,_ = stats.binned_statistic(r, u, statistic='mean', bins=r_bin_edge) -rho2_bin,_,_ = stats.binned_statistic(r, rho**2, statistic='mean', bins=r_bin_edge) -v2_bin,_,_ = stats.binned_statistic(r, v_r**2, statistic='mean', bins=r_bin_edge) -P2_bin,_,_ = stats.binned_statistic(r, P**2, statistic='mean', bins=r_bin_edge) -S2_bin,_,_ = stats.binned_statistic(r, S**2, statistic='mean', bins=r_bin_edge) -u2_bin,_,_ = stats.binned_statistic(r, u**2, statistic='mean', bins=r_bin_edge) -rho_sigma_bin = np.sqrt(rho2_bin - rho_bin**2) -v_sigma_bin = np.sqrt(v2_bin - v_bin**2) -P_sigma_bin = np.sqrt(P2_bin - P_bin**2) -S_sigma_bin = np.sqrt(S2_bin - S_bin**2) -u_sigma_bin = np.sqrt(u2_bin - u_bin**2) +r_bin_edge = np.arange(0.0, 0.5, 0.01) +r_bin = 0.5 * (r_bin_edge[1:] + r_bin_edge[:-1]) +rho_bin, _, _ = stats.binned_statistic(r, rho, statistic="mean", bins=r_bin_edge) +v_bin, _, _ = stats.binned_statistic(r, v_r, statistic="mean", bins=r_bin_edge) +P_bin, _, _ = stats.binned_statistic(r, P, statistic="mean", bins=r_bin_edge) +S_bin, _, _ = stats.binned_statistic(r, S, statistic="mean", bins=r_bin_edge) +u_bin, _, _ = stats.binned_statistic(r, u, statistic="mean", bins=r_bin_edge) +rho2_bin, _, _ = stats.binned_statistic(r, rho ** 2, statistic="mean", bins=r_bin_edge) +v2_bin, _, _ = stats.binned_statistic(r, v_r ** 2, statistic="mean", bins=r_bin_edge) +P2_bin, _, _ = stats.binned_statistic(r, P ** 2, statistic="mean", bins=r_bin_edge) +S2_bin, _, _ = stats.binned_statistic(r, S ** 2, statistic="mean", bins=r_bin_edge) +u2_bin, _, _ = stats.binned_statistic(r, u ** 2, statistic="mean", bins=r_bin_edge) +rho_sigma_bin = np.sqrt(rho2_bin - rho_bin ** 2) +v_sigma_bin = np.sqrt(v2_bin - v_bin ** 2) +P_sigma_bin = np.sqrt(P2_bin - P_bin ** 2) +S_sigma_bin = np.sqrt(S2_bin - S_bin ** 2) +u_sigma_bin = np.sqrt(u2_bin - u_bin ** 2) if plot_diffusion: - alpha_diff_bin,_,_ = stats.binned_statistic(r, diffusion, statistic='mean', bins=r_bin_edge) - alpha2_diff_bin,_,_ = stats.binned_statistic(r, diffusion**2, statistic='mean', bins=r_bin_edge) - alpha_diff_sigma_bin = np.sqrt(alpha2_diff_bin - alpha_diff_bin**2) + alpha_diff_bin, _, _ = stats.binned_statistic( + r, diffusion, statistic="mean", bins=r_bin_edge + ) + alpha2_diff_bin, _, _ = stats.binned_statistic( + r, diffusion ** 2, statistic="mean", bins=r_bin_edge + ) + alpha_diff_sigma_bin = np.sqrt(alpha2_diff_bin - alpha_diff_bin ** 2) if plot_viscosity: - alpha_visc_bin,_,_ = stats.binned_statistic(r, viscosity, statistic='mean', bins=r_bin_edge) - alpha2_visc_bin,_,_ = stats.binned_statistic(r, viscosity**2, statistic='mean', bins=r_bin_edge) - alpha_visc_sigma_bin = np.sqrt(alpha2_visc_bin - alpha_visc_bin**2) + alpha_visc_bin, _, _ = stats.binned_statistic( + r, viscosity, statistic="mean", bins=r_bin_edge + ) + alpha2_visc_bin, _, _ = stats.binned_statistic( + r, viscosity ** 2, statistic="mean", bins=r_bin_edge + ) + alpha_visc_sigma_bin = np.sqrt(alpha2_visc_bin - alpha_visc_bin ** 2) # Now, work our the solution.... from scipy.special import gamma as Gamma -from numpy import * -def calc_a(g,nu=3): + +def calc_a(g, nu=3): """ exponents of the polynomials of the sedov solution g - the polytropic gamma nu - the dimension """ - a = [0]*8 - + a = [0] * 8 + a[0] = 2.0 / (nu + 2) - a[2] = (1-g) / (2*(g-1) + nu) - a[3] = nu / (2*(g-1) + nu) - a[5] = 2 / (g-2) - a[6] = g / (2*(g-1) + nu) - - a[1] = (((nu+2)*g)/(2.0+nu*(g-1.0)) ) * ( (2.0*nu*(2.0-g))/(g*(nu+2.0)**2) - a[2]) - a[4] = a[1]*(nu+2) / (2-g) - a[7] = (2 + nu*(g-1))*a[1]/(nu*(2-g)) + a[2] = (1 - g) / (2 * (g - 1) + nu) + a[3] = nu / (2 * (g - 1) + nu) + a[5] = 2 / (g - 2) + a[6] = g / (2 * (g - 1) + nu) + + a[1] = (((nu + 2) * g) / (2.0 + nu * (g - 1.0))) * ( + (2.0 * nu * (2.0 - g)) / (g * (nu + 2.0) ** 2) - a[2] + ) + a[4] = a[1] * (nu + 2) / (2 - g) + a[7] = (2 + nu * (g - 1)) * a[1] / (nu * (2 - g)) return a + def calc_beta(v, g, nu=3): """ beta values for the sedov solution (coefficients of the polynomials of the similarity variables) @@ -160,15 +151,33 @@ def calc_beta(v, g, nu=3): nu- the dimension """ - beta = (nu+2) * (g+1) * array((0.25, (g/(g-1))*0.5, - -(2 + nu*(g-1))/2.0 / ((nu+2)*(g+1) -2*(2 + nu*(g-1))), - -0.5/(g-1)), dtype=float64) + beta = ( + (nu + 2) + * (g + 1) + * array( + ( + 0.25, + (g / (g - 1)) * 0.5, + -(2 + nu * (g - 1)) + / 2.0 + / ((nu + 2) * (g + 1) - 2 * (2 + nu * (g - 1))), + -0.5 / (g - 1), + ), + dtype=float64, + ) + ) beta = outer(beta, v) - beta += (g+1) * array((0.0, -1.0/(g-1), - (nu+2) / ((nu+2)*(g+1) -2.0*(2 + nu*(g-1))), - 1.0/(g-1)), dtype=float64).reshape((4,1)) + beta += (g + 1) * array( + ( + 0.0, + -1.0 / (g - 1), + (nu + 2) / ((nu + 2) * (g + 1) - 2.0 * (2 + nu * (g - 1))), + 1.0 / (g - 1), + ), + dtype=float64, + ).reshape((4, 1)) return beta @@ -192,9 +201,11 @@ def sedov(t, E0, rho0, g, n=1000, nu=3): a = calc_a(g, nu) beta = calc_beta(v, g=g, nu=nu) lbeta = log(beta) - + r = exp(-a[0] * lbeta[0] - a[2] * lbeta[1] - a[1] * lbeta[2]) - rho = ((g + 1.0) / (g - 1.0)) * exp(a[3] * lbeta[1] + a[5] * lbeta[3] + a[4] * lbeta[2]) + rho = ((g + 1.0) / (g - 1.0)) * exp( + a[3] * lbeta[1] + a[5] * lbeta[3] + a[4] * lbeta[2] + ) p = exp(nu * a[0] * lbeta[0] + (a[5] + 1) * lbeta[3] + (a[4] - 2 * a[1]) * lbeta[2]) u = beta[0] * r * 4.0 / ((g + 1) * (nu + 2)) p *= 8.0 / ((g + 1) * (nu + 2) * (nu + 2)) @@ -203,14 +214,17 @@ def sedov(t, E0, rho0, g, n=1000, nu=3): # It is not a singularity, however, the gradients of our variables (wrt v) are. # r -> 0, u -> 0, rho -> 0, p-> constant - u[0] = 0.0; rho[0] = 0.0; r[0] = 0.0; p[0] = p[1] + u[0] = 0.0 + rho[0] = 0.0 + r[0] = 0.0 + p[0] = p[1] # volume of an n-sphere vol = (pi ** (nu / 2.0) / Gamma(nu / 2.0 + 1)) * power(r, nu) # note we choose to evaluate the integral in this way because the - # volumes of the first few elements (i.e near v=vmin) are shrinking - # very slowly, so we dramatically improve the error convergence by + # volumes of the first few elements (i.e near v=vmin) are shrinking + # very slowly, so we dramatically improve the error convergence by # finding the volumes exactly. This is most important for the # pressure integral, as this is on the order of the volume. @@ -224,11 +238,11 @@ def sedov(t, E0, rho0, g, n=1000, nu=3): # shock speed shock_speed = fac * (2.0 / (nu + 2)) - rho_s = ((g + 1) / (g - 1)) * rho0 + rho_s = ((g + 1) / (g - 1)) * rho0 r_s = shock_speed * t * (nu + 2) / 2.0 p_s = (2.0 * rho0 * shock_speed * shock_speed) / (g + 1) u_s = (2.0 * shock_speed) / (g + 1) - + r *= fac * t u *= fac p *= fac * fac * rho0 @@ -240,103 +254,141 @@ def sedov(t, E0, rho0, g, n=1000, nu=3): r_s, P_s, rho_s, v_s, r_shock, _, _, _, _ = sedov(time, E_0, rho_0, gas_gamma, 1000, 3) # Append points for after the shock -r_s = np.insert(r_s, np.size(r_s), [r_shock, r_shock*1.5]) +r_s = np.insert(r_s, np.size(r_s), [r_shock, r_shock * 1.5]) rho_s = np.insert(rho_s, np.size(rho_s), [rho_0, rho_0]) P_s = np.insert(P_s, np.size(P_s), [P_0, P_0]) v_s = np.insert(v_s, np.size(v_s), [0, 0]) # Additional arrays -u_s = P_s / (rho_s * (gas_gamma - 1.)) #internal energy -s_s = P_s / rho_s**gas_gamma # entropic function - +u_s = P_s / (rho_s * (gas_gamma - 1.0)) # internal energy +s_s = P_s / rho_s ** gas_gamma # entropic function # Plot the interesting quantities -figure() +figure(figsize=(7, 7 / 1.6)) + +line_color = "C4" +binned_color = "C2" +binned_marker_size = 4 + +scatter_props = dict( + marker=".", + ms=1, + markeredgecolor="none", + alpha=0.2, + zorder=-1, + rasterized=True, + linestyle="none", +) + +errorbar_props = dict(color=binned_color, ms=binned_marker_size, fmt=".", lw=1.2) # Velocity profile -------------------------------- subplot(231) -plot(r, v_r, '.', color='r', ms=0.5, alpha=0.2) -plot(r_s, v_s, '--', color='k', alpha=0.8, lw=1.2) -errorbar(r_bin, v_bin, yerr=v_sigma_bin, fmt='.', ms=8.0, color='b', lw=1.2) -xlabel("${\\rm{Radius}}~r$", labelpad=0) -ylabel("${\\rm{Radial~velocity}}~v_r$", labelpad=0) +plot(r, v_r, **scatter_props) +plot(r_s, v_s, "--", color=line_color, alpha=0.8, lw=1.2) +errorbar(r_bin, v_bin, yerr=v_sigma_bin, **errorbar_props) +xlabel("Radius $r$") +ylabel("Radialvelocity $v_r$") xlim(0, 1.3 * r_shock) ylim(-0.2, 3.8) # Density profile -------------------------------- subplot(232) -plot(r, rho, '.', color='r', ms=0.5, alpha=0.2) -plot(r_s, rho_s, '--', color='k', alpha=0.8, lw=1.2) -errorbar(r_bin, rho_bin, yerr=rho_sigma_bin, fmt='.', ms=8.0, color='b', lw=1.2) -xlabel("${\\rm{Radius}}~r$", labelpad=0) -ylabel("${\\rm{Density}}~\\rho$", labelpad=2) +plot(r, rho, **scatter_props) +plot(r_s, rho_s, "--", color=line_color, alpha=0.8, lw=1.2) +errorbar(r_bin, rho_bin, yerr=rho_sigma_bin, **errorbar_props) +xlabel("Radius $r$") +ylabel("Density $\\rho$") xlim(0, 1.3 * r_shock) ylim(-0.2, 5.2) # Pressure profile -------------------------------- subplot(233) -plot(r, P, '.', color='r', ms=0.5, alpha=0.2) -plot(r_s, P_s, '--', color='k', alpha=0.8, lw=1.2) -errorbar(r_bin, P_bin, yerr=P_sigma_bin, fmt='.', ms=8.0, color='b', lw=1.2) -xlabel("${\\rm{Radius}}~r$", labelpad=0) -ylabel("${\\rm{Pressure}}~P$", labelpad=0) +plot(r, P, **scatter_props) +plot(r_s, P_s, "--", color=line_color, alpha=0.8, lw=1.2) +errorbar(r_bin, P_bin, yerr=P_sigma_bin, **errorbar_props) +xlabel("Radius $r$") +ylabel("Pressure $P$") xlim(0, 1.3 * r_shock) ylim(-1, 12.5) # Internal energy profile ------------------------- subplot(234) -plot(r, u, '.', color='r', ms=0.5, alpha=0.2) -plot(r_s, u_s, '--', color='k', alpha=0.8, lw=1.2) -errorbar(r_bin, u_bin, yerr=u_sigma_bin, fmt='.', ms=8.0, color='b', lw=1.2) -xlabel("${\\rm{Radius}}~r$", labelpad=0) -ylabel("${\\rm{Internal~Energy}}~u$", labelpad=0) +plot(r, u, **scatter_props) +plot(r_s, u_s, "--", color=line_color, alpha=0.8, lw=1.2) +errorbar(r_bin, u_bin, yerr=u_sigma_bin, **errorbar_props) +xlabel("Radius $r$") +ylabel("Internal Energy $u$") xlim(0, 1.3 * r_shock) ylim(-2, 22) # Entropy profile --------------------------------- subplot(235) -xlabel("${\\rm{Radius}}~r$", labelpad=0) - - +xlabel("Radius $r$") if plot_diffusion or plot_viscosity: if plot_diffusion: - plot(r, diffusion, ".", color='r', ms=0.5, alpha=0.2) - errorbar(r_bin, alpha_diff_bin, yerr=alpha_diff_sigma_bin, fmt=".", ms=8.0, color='b', lw=1.2, label="Diffusion") + plot(r, diffusion, **scatter_props) + errorbar( + r_bin, + alpha_diff_bin, + yerr=alpha_diff_sigma_bin, + **errorbar_props, + label="Diffusion", + ) if plot_viscosity: - plot(r, viscosity, ".", color='g', ms=0.5, alpha=0.2) - errorbar(r_bin, alpha_visc_bin, yerr=alpha_visc_sigma_bin, fmt=".", ms=8.0, color='y', lw=1.2, label="Viscosity") - - ylabel("${\\rm{Rate~Coefficient}}~\\alpha$", labelpad=0) + plot(r, viscosity, **scatter_props) + errorbar( + r_bin, + alpha_visc_bin, + yerr=alpha_visc_sigma_bin, + label="Viscosity", + color="C4", + ms=binned_marker_size, + fmt=".", + lw=1.2, + ) + + ylabel(r"Rate Coefficient $\alpha$", labelpad=0) legend() else: - plot(r, S, '.', color='r', ms=0.5, alpha=0.2) - plot(r_s, s_s, '--', color='k', alpha=0.8, lw=1.2) - errorbar(r_bin, S_bin, yerr=S_sigma_bin, fmt='.', ms=8.0, color='b', lw=1.2) - ylabel("${\\rm{Entropy}}~S$", labelpad=0) + plot(r, S, **scatter_props) + plot(r_s, s_s, "--", color=line_color, alpha=0.8, lw=1.2) + errorbar(r_bin, S_bin, yerr=S_sigma_bin, **errorbar_props) + ylabel("Entropy $S$", labelpad=0) ylim(-5, 50) xlim(0, 1.3 * r_shock) # Information ------------------------------------- subplot(236, frameon=False) -text(-0.49, 0.9, "Sedov blast with $\\gamma=%.3f$ in 3D at $t=%.2f$"%(gas_gamma,time), fontsize=10) -text(-0.49, 0.8, "Background $\\rho_0=%.2f$"%(rho_0), fontsize=10) -text(-0.49, 0.7, "Energy injected $E_0=%.2f$"%(E_0), fontsize=10) -plot([-0.49, 0.1], [0.62, 0.62], 'k-', lw=1) -text(-0.49, 0.5, "$\\textsc{Swift}$ %s"%git, fontsize=10) -text(-0.49, 0.4, scheme, fontsize=10) -text(-0.49, 0.3, kernel, fontsize=10) -text(-0.49, 0.2, "$%.2f$ neighbours ($\\eta=%.3f$)"%(neighbours, eta), fontsize=10) +text_fontsize = 5 + +text( + -0.45, + 0.9, + "Sedov blast with $\\gamma=%.3f$ in 3D at $t=%.2f$" % (gas_gamma, time), + fontsize=text_fontsize, +) +text(-0.45, 0.8, "Background $\\rho_0=%.2f$" % (rho_0), fontsize=text_fontsize) +text(-0.45, 0.7, "Energy injected $E_0=%.2f$" % (E_0), fontsize=text_fontsize) +plot([-0.45, 0.1], [0.62, 0.62], "k-", lw=1) +text(-0.45, 0.5, "SWIFT %s" % git.decode("utf-8"), fontsize=text_fontsize) +text(-0.45, 0.4, scheme.decode("utf-8"), fontsize=text_fontsize) +text(-0.45, 0.3, kernel.decode("utf-8"), fontsize=text_fontsize) +text( + -0.45, + 0.2, + "$%.2f$ neighbours ($\\eta=%.3f$)" % (neighbours, eta), + fontsize=text_fontsize, +) xlim(-0.5, 0.5) ylim(0, 1) xticks([]) yticks([]) +tight_layout() -savefig("Sedov.png", dpi=200) - - - +savefig("Sedov.png") diff --git a/examples/HydroTests/SedovBlast_3D/sedov.yml b/examples/HydroTests/SedovBlast_3D/sedov.yml index 00419ba94b262a1c94c0d3cd31acf70c949b9164..df7a2526b74e01d24ab7d7e164f2f54ef6437680 100644 --- a/examples/HydroTests/SedovBlast_3D/sedov.yml +++ b/examples/HydroTests/SedovBlast_3D/sedov.yml @@ -34,3 +34,12 @@ InitialConditions: file_name: ./sedov.hdf5 periodic: 1 smoothing_length_scaling: 3.33 + +# Parameters governing the logger snapshot system +Logger: + delta_step: 10 # Update the particle log every this many updates + basename: index # Common part of the filenames + initial_buffer_size: 0.01 # (Optional) Buffer size in GB + buffer_scale: 10 # (Optional) When buffer size is too small, update it with required memory times buffer_scale + time_first_index: 0. # Time of the first output (in internal units) + delta_time_index: 1e-2 # Time difference between consecutive outputs (in internal units) diff --git a/examples/IsolatedGalaxy/IsolatedGalaxy_feedback/isolated_galaxy.yml b/examples/IsolatedGalaxy/IsolatedGalaxy_feedback/isolated_galaxy.yml index b5ed93c3d3b60d9efd2c091e60dedf138d3dc91f..0642e9312f0926cc0d005f9ec4b6d3f5215ea7d4 100644 --- a/examples/IsolatedGalaxy/IsolatedGalaxy_feedback/isolated_galaxy.yml +++ b/examples/IsolatedGalaxy/IsolatedGalaxy_feedback/isolated_galaxy.yml @@ -17,14 +17,15 @@ Gravity: TimeIntegration: time_begin: 0. # The starting time of the simulation (in internal units). time_end: 0.1 # The end time of the simulation (in internal units). - dt_min: 1e-14 # The minimal time-step size of the simulation (in internal units). + dt_min: 1e-9 # The minimal time-step size of the simulation (in internal units). dt_max: 1e-2 # The maximal time-step size of the simulation (in internal units). # Parameters governing the snapshots Snapshots: - basename: output # Common part of the name of output files - time_first: 0. # (Optional) Time of the first output if non-cosmological time-integration (in internal units) - delta_time: 0.001 # Time difference between consecutive outputs (in internal units) + basename: output # Common part of the name of output files + time_first: 0. # Time of the first output if non-cosmological time-integration (in internal units) + delta_time: 0.001 # Time difference between consecutive outputs (in internal units) + compression: 4 # Compress the snapshots # Parameters governing the conserved quantities statistics Statistics: @@ -93,10 +94,10 @@ EAGLEStarFormation: gas_fraction: 0.3 # The gas fraction used internally by the model. KS_normalisation: 1.515e-4 # The normalization of the Kennicutt-Schmidt law in Msun / kpc^2 / yr. KS_exponent: 1.4 # The exponent of the Kennicutt-Schmidt law. - min_over_density: 57.7 # The over-density above which star-formation is allowed. + min_over_density: 57.7 # The over-density above which star-formation is allowed. KS_high_density_threshold_H_p_cm3: 1e3 # Hydrogen number density above which the Kennicut-Schmidt law changes slope in Hydrogen atoms per cm^3. KS_high_density_exponent: 2.0 # Slope of the Kennicut-Schmidt law above the high-density threshold. - EOS_temperature_margin_dex: 0.5 # Logarithm base 10 of the maximal temperature difference above the EOS allowed to form stars. + EOS_entropy_margin_dex: 0.5 # Logarithm base 10 of the maximal entropy above the EOS at which stars can form. threshold_norm_H_p_cm3: 0.1 # Normalisation of the metal-dependant density threshold for star formation in Hydrogen atoms per cm^3. threshold_Z0: 0.002 # Reference metallicity (metal mass fraction) for the metal-dependant threshold for star formation. threshold_slope: -0.64 # Slope of the metal-dependant star formation threshold @@ -123,9 +124,10 @@ EAGLEFeedback: filename: ./yieldtables/ # Path to the directory containing the EAGLE yield tables. IMF_min_mass_Msun: 0.1 # Minimal stellar mass considered for the Chabrier IMF in solar masses. IMF_max_mass_Msun: 100.0 # Maximal stellar mass considered for the Chabrier IMF in solar masses. - SNII_min_mass_Msun: 6.0 # Minimal mass considered for SNII feedback (not SNII enrichment!) in solar masses. - SNII_max_mass_Msun: 100.0 # Maximal mass considered for SNII feedback (not SNII enrichment!) in solar masses. - SNII_wind_delay_Gyr: 0.03 # Time in Gyr between a star's birth and the SNII thermal feedback event. + SNII_min_mass_Msun: 6.0 # Minimal mass considered for SNII stars in solar masses. + SNII_max_mass_Msun: 100.0 # Maximal mass considered for SNII stars in solar masses. + SNII_sampled_delay: 0 # Sample the SNII lifetimes to do feedback. + SNII_wind_delay_Gyr: 0.03 # Time in Gyr between a star's birth and the SNII thermal feedback event when not sampling. SNII_delta_T_K: 3.16228e7 # Change in temperature to apply to the gas particle in a SNII thermal feedback event in Kelvin. SNII_energy_erg: 1.0e51 # Energy of one SNII explosion in ergs. SNII_energy_fraction_min: 1.0 # Minimal fraction of energy applied in a SNII feedback event. @@ -134,11 +136,13 @@ EAGLEFeedback: SNII_energy_fraction_n_0_H_p_cm3: 1.4588 # Pivot point for the birth density dependance of the SNII energy fraction in cm^-3. SNII_energy_fraction_n_Z: 0.8686 # Power-law for the metallicity dependance of the SNII energy fraction. SNII_energy_fraction_n_n: 0.8686 # Power-law for the birth density dependance of the SNII energy fraction. - SNIa_max_mass_Msun: 8.0 # Maximal mass considered for SNIa feedback and enrichment in solar masses. - SNIa_timescale_Gyr: 2.0 # Time-scale of the exponential decay of the SNIa rates in Gyr. - SNIa_efficiency_p_Msun: 0.002 # Normalisation of the SNIa rates in inverse solar masses. + SNIa_DTD: PowerLaw # Functional form of the SNIa delay time distribution. + SNIa_DTD_delay_Gyr: 0.04 # Stellar age after which SNIa start in Gyr (40 Myr corresponds to stars ~ 8 Msun). + SNIa_DTD_power_law_norm_p_Msun: 0.0012 # Normalization of the SNIa delay time distribution (in Msun^-1). SNIa_energy_erg: 1.0e51 # Energy of one SNIa explosion in ergs. AGB_ejecta_velocity_km_p_s: 10.0 # Velocity of the AGB ejectas in km/s. + stellar_evolution_age_cut_Gyr: 0.1 # Age in Gyr above which the enrichment is downsampled. + stellar_evolution_sampling_rate: 10 # Number of time-steps in-between two enrichment events for a star above the age threshold. SNII_yield_factor_Hydrogen: 1.0 # (Optional) Correction factor to apply to the Hydrogen yield from the SNII channel. SNII_yield_factor_Helium: 1.0 # (Optional) Correction factor to apply to the Helium yield from the SNII channel. SNII_yield_factor_Carbon: 0.5 # (Optional) Correction factor to apply to the Carbon yield from the SNII channel. diff --git a/examples/IsolatedGalaxy/IsolatedGalaxy_feedback/plotSolution.py b/examples/IsolatedGalaxy/IsolatedGalaxy_feedback/plotSolution.py index 1ff8df3569f25590e5acb8046edeca0a1333d556..7d1dd624586d814eac4242f95b5130ecbe2b95e8 100644 --- a/examples/IsolatedGalaxy/IsolatedGalaxy_feedback/plotSolution.py +++ b/examples/IsolatedGalaxy/IsolatedGalaxy_feedback/plotSolution.py @@ -119,18 +119,18 @@ SF_thresh = KS_thresh_norm * (EAGLE_Z / KS_thresh_Z0) ** (KS_thresh_slope) gas_pos = f["/PartType0/Coordinates"][:, :] gas_mass = f["/PartType0/Masses"][:] gas_rho = f["/PartType0/Densities"][:] -gas_T = f["/PartType0/Temperature"][:] -gas_SFR = f["/PartType0/SFR"][:] +gas_T = f["/PartType0/Temperatures"][:] +gas_SFR = f["/PartType0/StarFormationRates"][:] gas_XH = f["/PartType0/ElementMassFractions"][:, 0] -gas_Z = f["/PartType0/Metallicities"][:] +gas_Z = f["/PartType0/MetalMassFractions"][:] gas_hsml = f["/PartType0/SmoothingLengths"][:] gas_sSFR = gas_SFR / gas_mass # Read the Star properties stars_pos = f["/PartType4/Coordinates"][:, :] -stars_BirthDensity = f["/PartType4/BirthDensity"][:] -stars_BirthTime = f["/PartType4/BirthTime"][:] -stars_XH = f["/PartType4/ElementAbundance"][:, 0] +stars_BirthDensity = f["/PartType4/BirthDensities"][:] +stars_BirthTime = f["/PartType4/BirthTimes"][:] +stars_XH = f["/PartType4/ElementMassFractions"][:, 0] # Centre the box gas_pos[:, 0] -= centre[0] diff --git a/examples/IsolatedGalaxy/IsolatedGalaxy_feedback/run.sh b/examples/IsolatedGalaxy/IsolatedGalaxy_feedback/run.sh index f0f8e262fc967011d4f7094d068f4dabe23948b1..b5ccf82b4a5078dd80c1c27c5a2fcac2e4f0a8fb 100755 --- a/examples/IsolatedGalaxy/IsolatedGalaxy_feedback/run.sh +++ b/examples/IsolatedGalaxy/IsolatedGalaxy_feedback/run.sh @@ -18,7 +18,7 @@ then ./getYieldTable.sh fi -../../swift --threads=16 --feedback --external-gravity --self-gravity --stars --star-formation --cooling --hydro isolated_galaxy.yml 2>&1 | tee output.log +../../swift --threads=16 --feedback --external-gravity --self-gravity --stars --star-formation --cooling --hydro --limiter --sync isolated_galaxy.yml 2>&1 | tee output.log # Kennicutt-Schmidt law plot python3 plotSolution.py diff --git a/examples/IsolatedGalaxy/IsolatedGalaxy_starformation/isolated_galaxy.yml b/examples/IsolatedGalaxy/IsolatedGalaxy_starformation/isolated_galaxy.yml index 86c3a469bdf0918eacefe6b155be39e636d87f8d..1403e13afd27122568fac083eb5cecef96ed330d 100644 --- a/examples/IsolatedGalaxy/IsolatedGalaxy_starformation/isolated_galaxy.yml +++ b/examples/IsolatedGalaxy/IsolatedGalaxy_starformation/isolated_galaxy.yml @@ -93,10 +93,10 @@ EAGLEStarFormation: gas_fraction: 0.3 # The gas fraction used internally by the model. KS_normalisation: 1.515e-4 # The normalization of the Kennicutt-Schmidt law in Msun / kpc^2 / yr. KS_exponent: 1.4 # The exponent of the Kennicutt-Schmidt law. - min_over_density: 57.7 # The over-density above which star-formation is allowed. + min_over_density: 57.7 # The over-density above which star-formation is allowed. KS_high_density_threshold_H_p_cm3: 1e3 # Hydrogen number density above which the Kennicut-Schmidt law changes slope in Hydrogen atoms per cm^3. KS_high_density_exponent: 2.0 # Slope of the Kennicut-Schmidt law above the high-density threshold. - EOS_temperature_margin_dex: 0.5 # Logarithm base 10 of the maximal temperature difference above the EOS allowed to form stars. + EOS_entropy_margin_dex: 0.5 # Logarithm base 10 of the maximal entropy above the EOS at which stars can form. threshold_norm_H_p_cm3: 0.1 # Normalisation of the metal-dependant density threshold for star formation in Hydrogen atoms per cm^3. threshold_Z0: 0.002 # Reference metallicity (metal mass fraction) for the metal-dependant threshold for star formation. threshold_slope: -0.64 # Slope of the metal-dependant star formation threshold diff --git a/examples/Makefile.am b/examples/Makefile.am index d8161ec28ec4b6ffc14ce0b0f9861c1b8fde2ce2..3de490970d27ef91eda85ccc1d2c57aba2fff0fe 100644 --- a/examples/Makefile.am +++ b/examples/Makefile.am @@ -89,6 +89,10 @@ EXTRA_DIST = Cooling/CoolingBox/coolingBox.yml Cooling/CoolingBox/plotEnergy.py EAGLE_DMO_low_z/EAGLE_DMO_25/eagle_25.yml EAGLE_DMO_low_z/EAGLE_DMO_25/getIC.sh EAGLE_DMO_low_z/EAGLE_DMO_25/README EAGLE_DMO_low_z/EAGLE_DMO_25/run.sh \ EAGLE_DMO_low_z/EAGLE_DMO_50/eagle_50.yml EAGLE_DMO_low_z/EAGLE_DMO_50/getIC.sh EAGLE_DMO_low_z/EAGLE_DMO_50/README EAGLE_DMO_low_z/EAGLE_DMO_50/run.sh \ EAGLE_DMO_low_z/EAGLE_DMO_100/eagle_100.yml EAGLE_DMO_low_z/EAGLE_DMO_100/getIC.sh EAGLE_DMO_low_z/EAGLE_DMO_100/README EAGLE_DMO_low_z/EAGLE_DMO_100/run.sh \ + EAGLE_ICs/getEagleCoolingTable.sh EAGLE_ICs/getEagleYieldTable.sh EAGLE_ICs/README \ + EAGLE_ICs/EAGLE_12/eagle_12.yml EAGLE_ICs/EAGLE_12/getIC.sh EAGLE_ICs/EAGLE_12/output_list.txt EAGLE_ICs/EAGLE_12/run.sh EAGLE_ICs/EAGLE_12/README EAGLE_ICs/EAGLE_12/vrconfig_3dfof_subhalos_SO_hydro.cfg \ + EAGLE_ICs/EAGLE_25/eagle_25.yml EAGLE_ICs/EAGLE_25/getIC.sh EAGLE_ICs/EAGLE_25/output_list.txt EAGLE_ICs/EAGLE_25/run.sh EAGLE_ICs/EAGLE_25/README EAGLE_ICs/EAGLE_25/vrconfig_3dfof_subhalos_SO_hydro.cfg \ + EAGLE_ICs/EAGLE_50/eagle_50.yml EAGLE_ICs/EAGLE_50/getIC.sh EAGLE_ICs/EAGLE_50/output_list.txt EAGLE_ICs/EAGLE_50/run.sh EAGLE_ICs/EAGLE_50/README EAGLE_ICs/EAGLE_50/vrconfig_3dfof_subhalos_SO_hydro.cfg \ GravityTests/ExternalPointMass/externalPointMass.yml GravityTests/ExternalPointMass/makeIC.py GravityTests/ExternalPointMass/run.sh GravityTests/ExternalPointMass/energy_plot.py \ GravityTests/HydrostaticHalo/README GravityTests/HydrostaticHalo/hydrostatic.yml GravityTests/HydrostaticHalo/makeIC.py GravityTests/HydrostaticHalo/run.sh \ GravityTests/HydrostaticHalo/density_profile.py GravityTests/HydrostaticHalo/velocity_profile.py GravityTests/HydrostaticHalo/internal_energy_profile.py GravityTests/HydrostaticHalo/test_energy_conservation.py \ @@ -116,7 +120,7 @@ EXTRA_DIST = Cooling/CoolingBox/coolingBox.yml Cooling/CoolingBox/plotEnergy.py HydroTests/UniformBox_2D/makeIC.py HydroTests/UniformBox_2D/run.sh HydroTests/UniformBox_2D/uniformPlane.yml \ HydroTests/UniformBox_3D/makeICbig.py HydroTests/UniformBox_3D/makeIC.py HydroTests/UniformBox_3D/run.sh HydroTests/UniformBox_3D/uniformBox.yml \ SmallCosmoVolume/SmallCosmoVolume_hydro/README SmallCosmoVolume/SmallCosmoVolume_hydro/getIC.sh SmallCosmoVolume/SmallCosmoVolume_hydro/run.sh SmallCosmoVolume/SmallCosmoVolume_hydro/small_cosmo_volume.yml SmallCosmoVolume/SmallCosmoVolume_hydro/plotTempEvolution.py \ - SmallCosmoVolume/SmallCosmoVolume_DM/README SmallCosmoVolume/SmallCosmoVolume_DM/getIC.sh SmallCosmoVolume/SmallCosmoVolume_DM/run.sh SmallCosmoVolume/SmallCosmoVolume_DM/small_cosmo_volume_dm.yml SmallCosmoVolume/SmallCosmoVolume_DM/stf_input_6dfof_dmonly_sub.cfg \ + SmallCosmoVolume/SmallCosmoVolume_DM/README SmallCosmoVolume/SmallCosmoVolume_DM/getIC.sh SmallCosmoVolume/SmallCosmoVolume_DM/run.sh SmallCosmoVolume/SmallCosmoVolume_DM/small_cosmo_volume_dm.yml SmallCosmoVolume/SmallCosmoVolume_DM/vrconfig_3dfof_subhalos_SO_hydro.cfg \ PMillennium/PMillennium-384/p-mill-384.yml \ PMillennium/PMillennium-768/p-mill-768.yml \ PMillennium/PMillennium-1536/p-mill-1536.yml \ diff --git a/examples/Planetary/EarthImpact/README.md b/examples/Planetary/EarthImpact/README.md new file mode 100644 index 0000000000000000000000000000000000000000..b49289f105332fcc621b2b2e95058e4e332d2bb8 --- /dev/null +++ b/examples/Planetary/EarthImpact/README.md @@ -0,0 +1,12 @@ +An example planetary simulation of the first 10 hours of a grazing giant impact +onto the proto-Earth (a roughly canonical Moon-forming impact) with the simple +Tillotson equation of state and 10^5 SPH particles. + +See Kegerreis et al. (2019), Mon. Not. R. Astron. Soc., 487:4 for more about +using SWIFT for planetary simulations. + +More examples and planetary-specific documentation coming soon! + +This example requires the code to be configured to use the planetary +hydrodynamics scheme and equations of state: + --with-hydro=planetary --with-equation-of-state=planetary diff --git a/examples/GiantImpacts/GiantImpact/configuration.yml b/examples/Planetary/EarthImpact/configuration.yml similarity index 100% rename from examples/GiantImpacts/GiantImpact/configuration.yml rename to examples/Planetary/EarthImpact/configuration.yml diff --git a/examples/GiantImpacts/GiantImpact/uranus_1e6.yml b/examples/Planetary/EarthImpact/earth_impact.yml similarity index 75% rename from examples/GiantImpacts/GiantImpact/uranus_1e6.yml rename to examples/Planetary/EarthImpact/earth_impact.yml index b98467616f659babb488352c87697a43fedcc0db..b1df0a6974e060074b66b2ab9c3021aa02d65190 100644 --- a/examples/GiantImpacts/GiantImpact/uranus_1e6.yml +++ b/examples/Planetary/EarthImpact/earth_impact.yml @@ -8,24 +8,22 @@ InternalUnitSystem: # Parameters related to the initial conditions InitialConditions: - file_name: uranus_1e6.hdf5 # The initial conditions file to read + file_name: earth_impact.hdf5 # The initial conditions file to read periodic: 0 # Are we running with periodic ICs? # Parameters governing the time integration TimeIntegration: time_begin: 0 # The starting time of the simulation (in internal units). - time_end: 40000 # The end time of the simulation (in internal units). + time_end: 36000 # The end time of the simulation (in internal units). dt_min: 0.0001 # The minimal time-step size of the simulation (in internal units). - dt_max: 100 # The maximal time-step size of the simulation (in internal units). + dt_max: 1000 # The maximal time-step size of the simulation (in internal units). # Parameters governing the snapshots Snapshots: - basename: uranus_1e6 # Common part of the name of output files + basename: earth_impact # Common part of the name of output files time_first: 0 # Time of the first output (in internal units) delta_time: 1000 # Time difference between consecutive outputs (in internal units) int_time_label_on: 1 # Enable to label the snapshots using the time rounded to an integer (in internal units) - output_list_on: 1 # Enable the output list - output_list: output_list.txt # File containing the output times (see documentation in "Parameter File" section) # Parameters governing the conserved quantities statistics Statistics: @@ -41,7 +39,7 @@ SPH: resolution_eta: 1.2348 # Target smoothing length in units of the mean inter-particle separation (1.2348 == 48Ngbs with the cubic spline kernel). delta_neighbours: 0.1 # The tolerance for the targetted number of neighbours. CFL_condition: 0.2 # Courant-Friedrich-Levy condition for time integration. - h_max: 0.5 # Maximal allowed smoothing length (in internal units). + h_max: 0.2 # Maximal allowed smoothing length (in internal units). viscosity_alpha: 1.5 # Override for the initial value of the artificial viscosity. # Parameters for the self-gravity scheme @@ -53,11 +51,8 @@ Gravity: # Parameters for the task scheduling Scheduler: - max_top_level_cells: 64 # Maximal number of top-level cells in any dimension. The nu + max_top_level_cells: 16 # Maximal number of top-level cells in any dimension. The nu # Parameters related to the equation of state EoS: - planetary_use_HM80: 1 # Whether to initialise the Hubbard & MacFarlane (1980) EOS - planetary_HM80_HHe_table_file: ../EoSTables/HM80_HHe.txt - planetary_HM80_ice_table_file: ../EoSTables/HM80_ice.txt - planetary_HM80_rock_table_file: ../EoSTables/HM80_rock.txt + planetary_use_Til: 1 # Whether to initialise the Tillotson EOS \ No newline at end of file diff --git a/examples/Planetary/EarthImpact/get_init_cond.sh b/examples/Planetary/EarthImpact/get_init_cond.sh new file mode 100755 index 0000000000000000000000000000000000000000..c8428c528afd61f7d25f0f0ccf4305eced63e429 --- /dev/null +++ b/examples/Planetary/EarthImpact/get_init_cond.sh @@ -0,0 +1,2 @@ +#!/bin/bash +wget http://virgodb.cosma.dur.ac.uk/swift-webstorage/ICs/Planetary/earth_impact.hdf5 diff --git a/examples/Planetary/EarthImpact/make_anim.sh b/examples/Planetary/EarthImpact/make_anim.sh new file mode 100755 index 0000000000000000000000000000000000000000..6331c0d1c9da6830e7dc649a21503c1fef2b7663 --- /dev/null +++ b/examples/Planetary/EarthImpact/make_anim.sh @@ -0,0 +1,7 @@ +#!/bin/bash + +# Make a simple animation of the snapshots +out="earth_impact.mp4" +ffmpeg -framerate 5 -i earth_impact_%?%?%?%?%?%?.png $out -y + +echo Saved $out \ No newline at end of file diff --git a/examples/Planetary/EarthImpact/plot_solution.py b/examples/Planetary/EarthImpact/plot_solution.py new file mode 100644 index 0000000000000000000000000000000000000000..faf6612bada9f8d5f11c3c1f93843d3d8224ae90 --- /dev/null +++ b/examples/Planetary/EarthImpact/plot_solution.py @@ -0,0 +1,147 @@ +############################################################################### +# This file is part of SWIFT. +# Copyright (c) 2019 Jacob Kegerreis (jacob.kegerreis@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/>. +# +############################################################################## + +# Plot the snapshots from the example giant impact on the proto-Earth, showing +# the particles in a thin slice near z=0, coloured by their material. + +import matplotlib +import matplotlib.pyplot as plt +import numpy as np +import swiftsimio as sw +import unyt + +font_size = 20 +params = { + "axes.labelsize": font_size, + "font.size": font_size, + "xtick.labelsize": font_size, + "ytick.labelsize": font_size, + "font.family": "serif", +} +matplotlib.rcParams.update(params) + +# Material IDs ( = type_id * type_factor + unit_id ) +type_factor = 100 +type_Til = 1 +id_body = 10000 +# Name and ID +Di_mat_id = { + "Til_iron": type_Til * type_factor, + "Til_iron_2": type_Til * type_factor + id_body, + "Til_granite": type_Til * type_factor + 1, + "Til_granite_2": type_Til * type_factor + 1 + id_body, +} +# Colour +Di_mat_colour = { + "Til_iron": "darkgray", + "Til_granite": "orangered", + "Til_iron_2": "saddlebrown", + "Til_granite_2": "gold", +} +Di_id_colour = {Di_mat_id[mat]: colour for mat, colour in Di_mat_colour.items()} + + +def load_snapshot(snapshot_time, ax_lim): + """ Select and load the particles to plot. """ + # Snapshot to load + snapshot = "earth_impact_%06d.hdf5" % snapshot_time + + # Only load data with the axis limits and below z=0 + ax_lim = 0.1 + mask = sw.mask(snapshot) + box_mid = 0.5 * mask.metadata.boxsize[0].to(unyt.Rearth) + x_min = box_mid - ax_lim * unyt.Rearth + x_max = box_mid + ax_lim * unyt.Rearth + load_region = [[x_min, x_max], [x_min, x_max], [x_min, box_mid]] + mask.constrain_spatial(load_region) + + # Load + data = sw.load(snapshot, mask=mask) + pos = data.gas.coordinates.to(unyt.Rearth) - box_mid + id = data.gas.particle_ids + mat_id = data.gas.material_ids.value + + # Restrict to z < 0 + sel = np.where(pos[:, 2] < 0)[0] + pos = pos[sel] + id = id[sel] + mat_id = mat_id[sel] + + # Sort in z order so higher particles are plotted on top + sort = np.argsort(pos[:, 2]) + pos = pos[sort] + id = id[sort] + mat_id = mat_id[sort] + + # Edit material IDs for particles in the impactor + num_in_target = 99740 + mat_id[num_in_target <= id] += id_body + + return pos, mat_id + + +def plot_snapshot(pos, mat_id, ax_lim): + """ Plot the particles, coloured by their material. """ + plt.figure(figsize=(7, 7)) + ax = plt.gca() + ax.set_aspect("equal") + + colour = np.empty(len(pos), dtype=object) + for id_c, c in Di_id_colour.items(): + colour[mat_id == id_c] = c + + ax.scatter( + pos[:, 0], + pos[:, 1], + c=colour, + edgecolors="none", + marker=".", + s=10, + alpha=0.5, + ) + + ax.set_xlim(-ax_lim, ax_lim) + ax.set_yticks(ax.get_xticks()) + ax.set_ylim(-ax_lim, ax_lim) + ax.set_xlabel(r"x Position ($R_\oplus$)") + ax.set_ylabel(r"y Position ($R_\oplus$)") + + plt.tight_layout() + + +if __name__ == "__main__": + print() + # Axis limits (Earth radii) + ax_lim = 3.4 + + # Plot each snapshot + for snapshot_time in range(0, 36000 + 1, 1000): + # Load the data + pos, mat_id = load_snapshot(snapshot_time, ax_lim) + + # Plot the data + plot_snapshot(pos, mat_id, ax_lim) + + # Save the figure + save = "earth_impact_%06d.png" % snapshot_time + plt.savefig(save, dpi=100) + + print("\rSaved %s" % save) + + print() diff --git a/examples/Planetary/EarthImpact/run.sh b/examples/Planetary/EarthImpact/run.sh new file mode 100755 index 0000000000000000000000000000000000000000..40ddcbb63a74751fc9a623e17a0d9bbe94360cb2 --- /dev/null +++ b/examples/Planetary/EarthImpact/run.sh @@ -0,0 +1,17 @@ +#!/bin/bash + +# Get the initial conditions if they are not present. +if [ ! -e earth_impact.hdf5 ] +then + echo "Fetching initial conditions file for the Earth impact example..." + ./get_init_cond.sh +fi + +# Run SWIFT +../../swift -s -G -t 8 earth_impact.yml 2>&1 | tee output.log + +# Plot the snapshots +python3 plot_solution.py + +# Make a simple animation +./make_anim.sh diff --git a/examples/Planetary/EarthImpact/system.yml b/examples/Planetary/EarthImpact/system.yml new file mode 100644 index 0000000000000000000000000000000000000000..8e942aa1fcc99da28f15d212fc1792cfcd99c417 --- /dev/null +++ b/examples/Planetary/EarthImpact/system.yml @@ -0,0 +1,8 @@ +input: + - earth_impact.yml + +output: + - earth_impact.pdf + +swift_parameters: -s -G +swift_threads: 8 diff --git a/examples/GiantImpacts/EoSTables/get_eos_tables.sh b/examples/Planetary/EoSTables/get_eos_tables.sh similarity index 100% rename from examples/GiantImpacts/EoSTables/get_eos_tables.sh rename to examples/Planetary/EoSTables/get_eos_tables.sh diff --git a/examples/SmallCosmoVolume/SmallCosmoVolume_DM/small_cosmo_volume_dm.yml b/examples/SmallCosmoVolume/SmallCosmoVolume_DM/small_cosmo_volume_dm.yml index 975ceac9c3c9404dc2c194abc4de40bf7d529a11..82e2569f9bdb7742305894562ce79efc3f88bbbc 100644 --- a/examples/SmallCosmoVolume/SmallCosmoVolume_DM/small_cosmo_volume_dm.yml +++ b/examples/SmallCosmoVolume/SmallCosmoVolume_DM/small_cosmo_volume_dm.yml @@ -6,13 +6,6 @@ InternalUnitSystem: UnitCurrent_in_cgs: 1 # Amperes UnitTemp_in_cgs: 1 # Kelvin -# Structure finding options -StructureFinding: - config_file_name: stf_input_6dfof_dmonly_sub.cfg - basename: ./stf - scale_factor_first: 0.02 - delta_time: 1.02 - Cosmology: # WMAP9 cosmology Omega_m: 0.276 Omega_lambda: 0.724 @@ -37,8 +30,9 @@ Gravity: # Parameters governing the snapshots Snapshots: basename: snap - delta_time: 1.02 - scale_factor_first: 0.02 + delta_time: 1.0816 # Only every second VELOCIraptor invoke gets a full snapshot dump. + scale_factor_first: 0.1 # z = 9 + compression: 4 # Parameters governing the conserved quantities statistics Statistics: @@ -51,7 +45,14 @@ Scheduler: # Parameters related to the initial conditions InitialConditions: - file_name: small_cosmo_volume.hdf5 + file_name: small_cosmo_volume.hdf5 periodic: 1 cleanup_h_factors: 1 cleanup_velocity_factors: 1 + +# Structure finding options +StructureFinding: + config_file_name: vrconfig_3dfof_subhalos_SO_hydro.cfg + basename: ./stf + scale_factor_first: 0.1 # z = 9 + delta_time: 1.04 diff --git a/examples/SmallCosmoVolume/SmallCosmoVolume_DM/stf_input_6dfof_dmonly_sub.cfg b/examples/SmallCosmoVolume/SmallCosmoVolume_DM/stf_input_6dfof_dmonly_sub.cfg deleted file mode 100644 index 7368e5654204ad600192eff3defdd5f96e986ce5..0000000000000000000000000000000000000000 --- a/examples/SmallCosmoVolume/SmallCosmoVolume_DM/stf_input_6dfof_dmonly_sub.cfg +++ /dev/null @@ -1,135 +0,0 @@ -#configuration file. -#It is suggested that you alter this file as necessary as not all options will be desired and some conflict. -#This file is simply meant to show options available. - -################################ -#input related -################################ -#input is from a cosmological so can use parameters like box size, h, Omega_m to calculate length and density scales -Cosmological_input=1 - -#Type of snapshot to read. Ignored when using within SWIFT. -HDF_name_convention=6 # ILLUSTRIS 0, GADGETX 1, EAGLE 2, GIZMO 3, SIMBA 4, MUFASA 5, SWIFTEAGLE 6 - -Particle_search_type=2 #search all particles, see allvars for other types -Baryon_searchflag=0 #if 1 search for baryons separately using phase-space search when identifying substructures, 2 allows special treatment in field FOF linking and phase-space substructure search, 0 treat the same as dark matter particles -Search_for_substructure=1 #if 0, end search once field objects are found -FoF_Field_search_type=3 #5 3DFOF search for field halos, 4 for 6DFOF clean up of field halos, 3 for 6DFOF with velocity scale distinct for each halo -Unbind_flag=1 #run unbinding -Halo_core_search=1 -Significance_level=1.0 #how significant a substructure is relative to Poisson noise. Values >= 1 are fine. - -################################ -# unit options, should always be provided -################################ - -# This is only for i/o. Specifies what units the code was running in. -# These should be set to whatever internal units we use. -# They have no impact on the way the code runs. -Length_unit_to_kpc=1000. #conversion of output length units to kpc -Velocity_to_kms=1.0 #conversion of output velocity units to km/s -Mass_to_solarmass=1e+10 #conversion of output mass units to solar masses - -# units conversion from input to desired internal unit. -# These should be set to 1 unless a conversion is expected. -Length_unit=1.0 #default length unit -Velocity_unit=1.0 #default velocity unit -Mass_unit=1.0 #default mass unit - -# These are ignored when running within SWIFT. -# When using standalone code, G and H must match the value used in the run. -Gravity=4.300927e+01 # In internal units (here 10^10 Msun, km/s, Mpc) -Hubble_unit=100.0 # This is H0 / h in internal units. - -################################ -#search related options -################################ - -#how to search a simulation -# searches for separate 6dfof cores in field haloes, and then more than just flags halo as merging, assigns particles to each merging "halo". 2 is full separation, 1 is flagging, 0 is off -#also useful for zoom simulations or simulations of individual objects, setting this flag means no field structure search is run -Singlehalo_search=0 #if file is single halo in which one wishes to search for substructure -#additional option for field haloes -Keep_FOF=0 #if field 6DFOF search is done, allows to keep structures found in 3DFOF (can be interpreted as the inter halo stellar mass when only stellar search is used).\n - -#minimum size for structures -Minimum_size=20 #min 20 particles -Minimum_halo_size=-1 #if field halos have different minimum sizes, otherwise set to -1. - -#for field fof halo search -Halo_linking_length_factor=2.0 #factor by which Physical_linking_length is changed when searching for field halos. Typical values are ~2 when using iterative substructure search. -Halo_velocity_linking_length_factor=5.0 #for 6d fof halo search increase ellv from substructure search - -#for mean field estimates and local velocity density distribution funciton estimator related quantiites, rarely need to change this -Cell_fraction = 0.01 #fraction of field fof halo used to determine mean velocity distribution function. Typical values are ~0.005-0.02 -Grid_type=1 #normal entropy based grid, shouldn't have to change -Nsearch_velocity=32 #number of velocity neighbours used to calculate local velocity distribution function. Typial values are ~32 -Nsearch_physical=256 #numerof physical neighbours from which the nearest velocity neighbour set is based. Typical values are 128-512 - -#for substructure search, rarely ever need to change this -FoF_search_type=1 #default phase-space FOF search. Don't really need to change -Iterative_searchflag=1 #iterative substructure search, for substructure find initial candidate substructures with smaller linking lengths then expand search region -Outlier_threshold=2.5 #outlier threshold for a particle to be considered residing in substructure, that is how dynamically distinct a particle is. Typical values are >2 -Velocity_ratio=2.0 #ratio of speeds used in phase-space FOF -Velocity_opening_angle=0.10 #angle between velocities. 18 degrees here, typical values are ~10-30 -Physical_linking_length=0.10 #physical linking length. IF reading periodic volumes in gadget/hdf/ramses, in units of the effective inter-particle spacing. Otherwise in user defined code units. Here set to 0.10 as iterative flag one, values of 0.1-0.3 are typical. -Velocity_linking_length=0.20 #where scaled by structure dispersion - -#for iterative substructure search, rarely ever need to change this -Iterative_threshold_factor=1.0 #change in threshold value when using iterative search. Here no increase in threshold if iterative or not -Iterative_linking_length_factor=2.0 #increase in final linking final iterative substructure search will be sqrt(2.25)*this factor -Iterative_Vratio_factor=1.0 #change in Vratio when using iterative search. no change in vratio -Iterative_ThetaOp_factor=1.0 #change in velocity opening angle. no change in velocity opening angle - -#for checking for halo merger remnants, which are defined as large, well separated phase-space density maxima - -#if searching for cores, linking lengths. likely does not need to change much -Use_adaptive_core_search=2 #calculate dispersions in configuration & vel space to determine linking lengths -Halo_core_ellx_fac=1.0 #how linking lengths are changed when searching for local 6DFOF cores, -Halo_core_ellv_fac=1.0 #how velocity lengths based on dispersions are changed when searching for local 6DFOF cores -Halo_core_ncellfac=0.05 #fraction of total halo particle number setting min size of a local 6DFOF core -Halo_core_adaptive_sigma_fac=2.0 #used when running fully adaptive core search with phase-space tensors, specifies the width of the physical linking length in configuration space dispersion (think of this as how many sigma to include). Typically values are 2 -Halo_core_num_loops=3 #allows the core search to iterate, shrinking the velocity linking length to used till the number of cores identified decreases or this limit is reached. Allows apative search with larger linking length to be robust. Typically values are 3-5 -Halo_core_loop_ellv_fac=0.75 #Factor by which velocity linking length is decreased when running loops for core search. Typically values are 0.75 - -################################ -#Unbinding options (VELOCIraptor is able to accurately identify tidal debris so particles need not be bound to a structure) -################################ - -#unbinding related items - -Min_bound_mass_frac=0.2 #minimum bound mass fraction, not yet implemented -#alpha factor used to determine whether particle is "bound" alaph*T+W<0. For standard subhalo catalogues use >0.9 but if interested in tidal debris 0.2-0.5 -Allowed_kinetic_potential_ratio=0.2 -#run unbinding of field structures, aka halos -Bound_halos=0 -#simple Plummer softening length when calculating gravitational energy. If cosmological simulation with period, is fraction of interparticle spacing -Softening_length=0.04 -#don't keep background potential when unbinding -Keep_background_potential=0 - -################################ -#Calculation of properties related options -################################ -#when calculating properties, for field objects calculate inclusive masses -Inclusive_halo_masses=1 #calculate inclusive masses -#ensures that output is comoving distances per little h -Comoving_units=0 - -################################ -#output related -################################ - -Write_group_array_file=0 #write a group array file -Separate_output_files=0 #separate output into field and substructure files similar to subfind -Binary_output=2 #binary output 1, ascii 0, and HDF 2 - -#halo ids are adjusted by this value * 1000000000000 (or 1000000 if code compiled with the LONGINTS option turned off) -#to ensure that halo ids are temporally unique. So if you had 100 snapshots, for snap 100 set this to 100 and 100*1000000000000 will -#be added to the halo id as set for this snapshot, so halo 1 becomes halo 100*1000000000000+1 and halo 1 of snap 0 would just have ID=1 -Snapshot_value=1 - -################################ -#other options -################################ -Verbose=0 #how talkative do you want the code to be, 0 not much, 1 a lot, 2 chatterbox diff --git a/examples/SmallCosmoVolume/SmallCosmoVolume_DM/vrconfig_3dfof_subhalos_SO_hydro.cfg b/examples/SmallCosmoVolume/SmallCosmoVolume_DM/vrconfig_3dfof_subhalos_SO_hydro.cfg new file mode 100644 index 0000000000000000000000000000000000000000..8590cbf5bc77e8d7a956d210339cced4bbdc692c --- /dev/null +++ b/examples/SmallCosmoVolume/SmallCosmoVolume_DM/vrconfig_3dfof_subhalos_SO_hydro.cfg @@ -0,0 +1,191 @@ +#Configuration file for analysing Hydro +#runs 3DFOF + substructure algorithm, demands subhalos and FOF halos be self-bound, calculates many properties +#Units currently set to take in as input, Mpc, 1e10 solar masses, km/s, output in same units +#To set temporally unique halo ids, alter Snapshot_value=SNAP to appropriate value. Ie: for snapshot 12, change SNAP to 12 + +################################ +#input options +#set up to use SWIFT HDF input, load gas, star, bh and dark matter +################################ +HDF_name_convention=6 #HDF SWIFT naming convention +Input_includes_dm_particle=1 #include dark matter particles in hydro input +Input_includes_gas_particle=1 #include gas particles in hydro input +Input_includes_star_particle=1 #include star particles in hydro input +Input_includes_bh_particle=1 #include bh particles in hydro input +Input_includes_wind_particle=0 #include wind particles in hydro input (used by Illustris and moves particle type 0 to particle type 3 when decoupled from hydro forces). Here shown as example +Input_includes_tracer_particle=0 #include tracer particles in hydro input (used by Illustris). Here shown as example +Input_includes_extradm_particle=0 #include extra dm particles stored in particle type 2 and type 3, useful for zooms + +Halo_core_phase_merge_dist=0.25 #merge substructures if difference in dispersion normalised distance is < this value +Apply_phase_merge_to_host=1 #merge substructures with background if centrally located and phase-distance is small + +#units conversion from input input to desired internal unit +Length_input_unit_conversion_to_output_unit=1.0 #default code unit, +Velocity_input_unit_conversion_to_output_unit=1.0 #default velocity unit, +Mass_input_unit_conversion_to_output_unit=1.0 #default mass unit, +#assumes input is in 1e10 msun, Mpc and km/s and output units are the same +Gravity=43.0211349 #for 1e10 Msun, km/s and Mpc +Hubble_unit=100.0 # assuming units are km/s and Mpc, then value of Hubble in km/s/Mpc +#converting hydro quantities +Stellar_age_input_is_cosmological_scalefactor=1 +Metallicity_input_unit_conversion_to_output_unit=1.0 +Stellar_age_input_unit_conversion_to_output_unit=1.0 +Star_formation_rate_input_unit_conversion_to_output_unit=1.0 + +#set the units of the output by providing conversion to a defined unit +#conversion of output length units to kpc +Length_unit_to_kpc=1000.0 +#conversion of output velocity units to km/s +Velocity_to_kms=1.0 +#conversion of output mass units to solar masses +Mass_to_solarmass=1.0e10 +#1 / 0.012 +Metallicity_to_solarmetallicity=83.33 +Star_formation_rate_to_solarmassperyear=97.78 +Stellar_age_to_yr=1.0 +#ensures that output is physical and not comoving distances per little h +Comoving_units=0 + +#sets the total buffer size in bytes used to store temporary particle information +#of mpi read threads before they are broadcast to the appropriate waiting non-read threads +#if not set, default value is equivalent to 1e6 particles per mpi process, quite large +#but significantly minimises the number of send/receives +#in this example the buffer size is roughly that for a send/receive of 10000 particles +#for 100 mpi processes +MPI_particle_total_buf_size=100000000 + +################################ +#search related options +################################ + +#how to search a simulation +Particle_search_type=1 #search dark matter particles only +#for baryon search +Baryon_searchflag=2 #if 1 search for baryons separately using phase-space search when identifying substructures, 2 allows special treatment in field FOF linking and phase-space substructure search, 0 treat the same as dark matter particles +#for search for substruture +Search_for_substructure=1 #if 0, end search once field objects are found +#also useful for zoom simulations or simulations of individual objects, setting this flag means no field structure search is run +Singlehalo_search=0 #if file is single halo in which one wishes to search for substructure. Here disabled. +#additional option for field haloes +Keep_FOF=0 #if field 6DFOF search is done, allows to keep structures found in 3DFOF (can be interpreted as the inter halo stellar mass when only stellar search is used).\n + +#minimum size for structures +Minimum_size=20 #min 20 particles +Minimum_halo_size=32 #if field halos have different minimum sizes, otherwise set to -1. + +#for field fof halo search +FoF_Field_search_type=5 #5 3DFOF search for field halos, 4 for 6DFOF clean up of field halos, 3 for 6DFOF with velocity scale distinct for each initial 3D FOF candidate +Halo_3D_linking_length=0.20 + +#for mean field estimates and local velocity density distribution funciton estimator related quantiites, rarely need to change this +Local_velocity_density_approximate_calculation=1 #calculates velocity density using approximative (and quicker) near neighbour search +Cell_fraction = 0.01 #fraction of field fof halo used to determine mean velocity distribution function. Typical values are ~0.005-0.02 +Grid_type=1 #normal entropy based grid, shouldn't have to change +Nsearch_velocity=32 #number of velocity neighbours used to calculate local velocity distribution function. Typial values are ~32 +Nsearch_physical=256 #numerof physical neighbours from which the nearest velocity neighbour set is based. Typical values are 128-512 + +#for substructure search, rarely ever need to change this +FoF_search_type=1 #default phase-space FOF search. Don't really need to change +Iterative_searchflag=1 #iterative substructure search, for substructure find initial candidate substructures with smaller linking lengths then expand search region +Outlier_threshold=2.5 #outlier threshold for a particle to be considered residing in substructure, that is how dynamically distinct a particle is. Typical values are >2 +Substructure_physical_linking_length=0.10 +Velocity_ratio=2.0 #ratio of speeds used in phase-space FOF +Velocity_opening_angle=0.10 #angle between velocities. 18 degrees here, typical values are ~10-30 +Velocity_linking_length=0.20 #where scaled by structure dispersion +Significance_level=1.0 #how significant a substructure is relative to Poisson noise. Values >= 1 are fine. + +#for iterative substructure search, rarely ever need to change this +Iterative_threshold_factor=1.0 #change in threshold value when using iterative search. Here no increase in threshold if iterative or not +Iterative_linking_length_factor=2.0 #increase in final linking final iterative substructure search +Iterative_Vratio_factor=1.0 #change in Vratio when using iterative search. no change in vratio +Iterative_ThetaOp_factor=1.0 #change in velocity opening angle. no change in velocity opening angle + +#for checking for halo merger remnants, which are defined as large, well separated phase-space density maxima +Halo_core_search=2 # searches for separate 6dfof cores in field haloes, and then more than just flags halo as merging, assigns particles to each merging "halo". 2 is full separation, 1 is flagging, 0 is off +#if searching for cores, linking lengths. likely does not need to change much +Use_adaptive_core_search=0 #calculate dispersions in configuration & vel space to determine linking lengths +Use_phase_tensor_core_growth=2 #use full stepped phase-space tensor assignment +Halo_core_ellx_fac=0.7 #how linking lengths are changed when searching for local 6DFOF cores, +Halo_core_ellv_fac=2.0 #how velocity lengths based on dispersions are changed when searching for local 6DFOF cores +Halo_core_ncellfac=0.005 #fraction of total halo particle number setting min size of a local 6DFOF core +Halo_core_num_loops=8 #number of loops to iteratively search for cores +Halo_core_loop_ellx_fac=0.75 #how much to change the configuration space linking per iteration +Halo_core_loop_ellv_fac=1.0 #how much to change the velocity space linking per iteration +Halo_core_loop_elln_fac=1.2 #how much to change the min number of particles per iteration +Halo_core_phase_significance=2.0 #how significant a core must be in terms of dispersions (sigma) significance + +################################ +#Unbinding options (VELOCIraptor is able to accurately identify tidal debris so particles need not be bound to a structure) +################################ + +#unbinding related items +Unbind_flag=1 #run unbinding +#objects must have particles that meet the allowed kinetic to potential ratio AND also have some total fraction that are completely bound. +Unbinding_type=0 +#alpha factor used to determine whether particle is "bound" alaph*T+W<0. For standard subhalo catalogues use >0.9 but if interested in tidal debris 0.2-0.5 +Allowed_kinetic_potential_ratio=0.95 +Min_bound_mass_frac=0.65 #minimum bound mass fraction +#run unbinding of field structures, aka halos. This is useful for sams and 6DFOF halos but may not be useful if interested in 3DFOF mass functions. +Bound_halos=0 +#don't keep background potential when unbinding +Keep_background_potential=1 +#use all particles to determine velocity frame for unbinding +Frac_pot_ref=1.0 +Min_npot_ref=20 +#reference frame only meaningful if calculating velocity frame using subset of particles in object. Can use radially sorted fraction of particles about minimum potential or centre of mass +Kinetic_reference_frame_type=0 +Unbinding_max_unbound_removal_fraction_per_iteration=0.5 +Unbinding_max_unbound_fraction=0.95 +Unbinding_max_unbound_fraction_allowed=0.005 + +################################ +#Calculation of properties related options +################################ +Virial_density=500 #user defined virial overdensity. Note that 200 rho_c, 200 rho_m and BN98 are already calculated. +#when calculating properties, for field objects calculate inclusive masses +Inclusive_halo_masses=3 #calculate inclusive masses for halos using full Spherical overdensity apertures +#ensures that output is physical and not comoving distances per little h +Comoving_units=0 +#calculate more (sub)halo properties (like angular momentum in spherical overdensity apertures, both inclusive and exclusive) +Extensive_halo_properties_output=1 +Extensive_gas_properties_output=1 +Extensive_star_properties_output=1 +#calculate aperture masses +Calculate_aperture_quantities=1 +Number_of_apertures=5 +Aperture_values_in_kpc=5,10,30,50,100, +Number_of_projected_apertures=5 +Projected_aperture_values_in_kpc=5,10,30,50,100, +#calculate radial profiles +Calculate_radial_profiles=1 +Number_of_radial_profile_bin_edges=20 +#default radial normalisation log rad bins, normed by R200crit, Integer flag of 0 is log bins and R200crit norm. +Radial_profile_norm=0 +Radial_profile_bin_edges=-2.,-1.87379263,-1.74758526,-1.62137789,-1.49517052,-1.36896316,-1.24275579,-1.11654842,-0.99034105,-0.86413368,-0.73792631,-0.61171894,-0.48551157,-0.3593042,-0.23309684,-0.10688947,0.0193179,0.14552527,0.27173264,0.39794001, +Iterate_cm_flag=0 #do not interate to determine centre-of-mass +Sort_by_binding_energy=1 #sort particles by binding energy +Reference_frame_for_properties=2 #use the minimum potential as reference frame about which to calculate properties + +################################ +#output related +################################ + +Write_group_array_file=0 #do not write a group array file +Separate_output_files=0 #do not separate output into field and substructure files similar to subfind +Binary_output=2 #Use HDF5 output (binary output 1, ascii 0, and HDF 2) +#output particles residing in the spherical overdensity apertures of halos, only the particles exclusively belonging to halos +Spherical_overdensity_halo_particle_list_output=1 + +#halo ids are adjusted by this value * 1000000000000 (or 1000000 if code compiled with the LONGINTS option turned off) +#to ensure that halo ids are temporally unique. So if you had 100 snapshots, for snap 100 set this to 100 and 100*1000000000000 will +#be added to the halo id as set for this snapshot, so halo 1 becomes halo 100*1000000000000+1 and halo 1 of snap 0 would just have ID=1 + +#ALTER THIS as part of a script to get temporally unique ids +Snapshot_value=SNAP + +################################ +#other options +################################ +Verbose=0 #how talkative do you want the code to be, 0 not much, 1 a lot, 2 chatterbox + + diff --git a/examples/SmallCosmoVolume/SmallCosmoVolume_VELOCIraptor/haloevol.py b/examples/SmallCosmoVolume/SmallCosmoVolume_VELOCIraptor/haloevol.py index 94e206cdf686ef5d2d3676d6fc36d6dfe8aea558..f0cb3aabd2bb7b7e0b170540562deb0bfa46b56d 100755 --- a/examples/SmallCosmoVolume/SmallCosmoVolume_VELOCIraptor/haloevol.py +++ b/examples/SmallCosmoVolume/SmallCosmoVolume_VELOCIraptor/haloevol.py @@ -24,9 +24,10 @@ from getHMF import getHMFz, getHMFztinker dlogm = 0.2 bins = 10 ** (np.arange(12, 15.2, dlogm)) -V = 142.0 ** 3 +h = 0.703 +V = (100.0 / h) ** 3 -itervalues = np.array([175, 185, 192, 198]) +itervalues = np.array([41, 49, 53, 60]) for j in itervalues: # Load the data @@ -38,15 +39,15 @@ for j in itervalues: for i in range(0, len(massnlarger)): massnlarger[i] = np.sum(binnedmass[i:]) - f = h5py.File("snap_%04d.hdf5" % (j + 1)) + f = h5py.File("snap_%04d.hdf5" % j) cosmo = f["Cosmology"] redshift = cosmo.attrs["Redshift"][0] a = cosmo.attrs["Scale-factor"][0] # Determine the HMF errormassn = massnlarger ** 0.5 - numbden = massnlarger / V / a ** 3 - numbdenerr = errormassn / V / a ** 3 + numbden = massnlarger / V + numbdenerr = errormassn / V massplot = (massrange[0:15] + massrange[1:16]) / 2 dernumbden = -np.diff(numbden) / np.diff(np.log10(massplot)) dererr = 2 ** 0.5 / dlogm * (numbdenerr[0:14] + numbdenerr[1:15]) / 2 @@ -72,10 +73,10 @@ for j in itervalues: plt.text(xplace, 10 ** -3.5, "$z=%2.2f$" % redshift) m, dndlogm = getHMFz(redshift) - plt.plot(m / 0.7, dndlogm * 0.7 ** 3, label="Sheth et al. 2001") + plt.plot(m / h, dndlogm * h ** 3, label="Sheth et al. 2001") m, dndlogm = getHMFztinker(redshift) - plt.plot(m / 0.7, dndlogm * 0.7 ** 3, label="Tinker et al. 2008") + plt.plot(m / h, dndlogm * h ** 3, label="Tinker et al. 2008") plt.xlabel("M${}_{200}$ ($M_\odot$)") plt.ylabel("dn/d($\log$10(M${}_{200}$) ($Mpc^{-3}$)") diff --git a/examples/SmallCosmoVolume/SmallCosmoVolume_VELOCIraptor/small_cosmo_volume.yml b/examples/SmallCosmoVolume/SmallCosmoVolume_VELOCIraptor/small_cosmo_volume.yml index f81c38a85f04b074f4cf5598bc3d09716b49f790..b2a6781acf7ed99792dd0e83b7bbf5027ce6ec5f 100644 --- a/examples/SmallCosmoVolume/SmallCosmoVolume_VELOCIraptor/small_cosmo_volume.yml +++ b/examples/SmallCosmoVolume/SmallCosmoVolume_VELOCIraptor/small_cosmo_volume.yml @@ -40,9 +40,10 @@ SPH: # Parameters governing the snapshots Snapshots: basename: snap - delta_time: 1.05 - scale_factor_first: 0.02 + delta_time: 1.0816 # Only every second VELOCIraptor invoke gets a full snapshot dump. + scale_factor_first: 0.1 # z = 9 invoke_stf: 1 + compression: 4 # Parameters governing the conserved quantities statistics Statistics: @@ -64,8 +65,8 @@ InitialConditions: # Structure finding options (requires velociraptor) StructureFinding: - config_file_name: stfconfig_input.cfg + config_file_name: vrconfig_3dfof_subhalos_SO_hydro.cfg basename: ./stf - scale_factor_first: 0.02 - delta_time: 1.02 + scale_factor_first: 0.1 # z = 9 + delta_time: 1.04 diff --git a/examples/SmallCosmoVolume/SmallCosmoVolume_VELOCIraptor/vrconfig_3dfof_subhalos_SO_hydro.cfg b/examples/SmallCosmoVolume/SmallCosmoVolume_VELOCIraptor/vrconfig_3dfof_subhalos_SO_hydro.cfg new file mode 100644 index 0000000000000000000000000000000000000000..8590cbf5bc77e8d7a956d210339cced4bbdc692c --- /dev/null +++ b/examples/SmallCosmoVolume/SmallCosmoVolume_VELOCIraptor/vrconfig_3dfof_subhalos_SO_hydro.cfg @@ -0,0 +1,191 @@ +#Configuration file for analysing Hydro +#runs 3DFOF + substructure algorithm, demands subhalos and FOF halos be self-bound, calculates many properties +#Units currently set to take in as input, Mpc, 1e10 solar masses, km/s, output in same units +#To set temporally unique halo ids, alter Snapshot_value=SNAP to appropriate value. Ie: for snapshot 12, change SNAP to 12 + +################################ +#input options +#set up to use SWIFT HDF input, load gas, star, bh and dark matter +################################ +HDF_name_convention=6 #HDF SWIFT naming convention +Input_includes_dm_particle=1 #include dark matter particles in hydro input +Input_includes_gas_particle=1 #include gas particles in hydro input +Input_includes_star_particle=1 #include star particles in hydro input +Input_includes_bh_particle=1 #include bh particles in hydro input +Input_includes_wind_particle=0 #include wind particles in hydro input (used by Illustris and moves particle type 0 to particle type 3 when decoupled from hydro forces). Here shown as example +Input_includes_tracer_particle=0 #include tracer particles in hydro input (used by Illustris). Here shown as example +Input_includes_extradm_particle=0 #include extra dm particles stored in particle type 2 and type 3, useful for zooms + +Halo_core_phase_merge_dist=0.25 #merge substructures if difference in dispersion normalised distance is < this value +Apply_phase_merge_to_host=1 #merge substructures with background if centrally located and phase-distance is small + +#units conversion from input input to desired internal unit +Length_input_unit_conversion_to_output_unit=1.0 #default code unit, +Velocity_input_unit_conversion_to_output_unit=1.0 #default velocity unit, +Mass_input_unit_conversion_to_output_unit=1.0 #default mass unit, +#assumes input is in 1e10 msun, Mpc and km/s and output units are the same +Gravity=43.0211349 #for 1e10 Msun, km/s and Mpc +Hubble_unit=100.0 # assuming units are km/s and Mpc, then value of Hubble in km/s/Mpc +#converting hydro quantities +Stellar_age_input_is_cosmological_scalefactor=1 +Metallicity_input_unit_conversion_to_output_unit=1.0 +Stellar_age_input_unit_conversion_to_output_unit=1.0 +Star_formation_rate_input_unit_conversion_to_output_unit=1.0 + +#set the units of the output by providing conversion to a defined unit +#conversion of output length units to kpc +Length_unit_to_kpc=1000.0 +#conversion of output velocity units to km/s +Velocity_to_kms=1.0 +#conversion of output mass units to solar masses +Mass_to_solarmass=1.0e10 +#1 / 0.012 +Metallicity_to_solarmetallicity=83.33 +Star_formation_rate_to_solarmassperyear=97.78 +Stellar_age_to_yr=1.0 +#ensures that output is physical and not comoving distances per little h +Comoving_units=0 + +#sets the total buffer size in bytes used to store temporary particle information +#of mpi read threads before they are broadcast to the appropriate waiting non-read threads +#if not set, default value is equivalent to 1e6 particles per mpi process, quite large +#but significantly minimises the number of send/receives +#in this example the buffer size is roughly that for a send/receive of 10000 particles +#for 100 mpi processes +MPI_particle_total_buf_size=100000000 + +################################ +#search related options +################################ + +#how to search a simulation +Particle_search_type=1 #search dark matter particles only +#for baryon search +Baryon_searchflag=2 #if 1 search for baryons separately using phase-space search when identifying substructures, 2 allows special treatment in field FOF linking and phase-space substructure search, 0 treat the same as dark matter particles +#for search for substruture +Search_for_substructure=1 #if 0, end search once field objects are found +#also useful for zoom simulations or simulations of individual objects, setting this flag means no field structure search is run +Singlehalo_search=0 #if file is single halo in which one wishes to search for substructure. Here disabled. +#additional option for field haloes +Keep_FOF=0 #if field 6DFOF search is done, allows to keep structures found in 3DFOF (can be interpreted as the inter halo stellar mass when only stellar search is used).\n + +#minimum size for structures +Minimum_size=20 #min 20 particles +Minimum_halo_size=32 #if field halos have different minimum sizes, otherwise set to -1. + +#for field fof halo search +FoF_Field_search_type=5 #5 3DFOF search for field halos, 4 for 6DFOF clean up of field halos, 3 for 6DFOF with velocity scale distinct for each initial 3D FOF candidate +Halo_3D_linking_length=0.20 + +#for mean field estimates and local velocity density distribution funciton estimator related quantiites, rarely need to change this +Local_velocity_density_approximate_calculation=1 #calculates velocity density using approximative (and quicker) near neighbour search +Cell_fraction = 0.01 #fraction of field fof halo used to determine mean velocity distribution function. Typical values are ~0.005-0.02 +Grid_type=1 #normal entropy based grid, shouldn't have to change +Nsearch_velocity=32 #number of velocity neighbours used to calculate local velocity distribution function. Typial values are ~32 +Nsearch_physical=256 #numerof physical neighbours from which the nearest velocity neighbour set is based. Typical values are 128-512 + +#for substructure search, rarely ever need to change this +FoF_search_type=1 #default phase-space FOF search. Don't really need to change +Iterative_searchflag=1 #iterative substructure search, for substructure find initial candidate substructures with smaller linking lengths then expand search region +Outlier_threshold=2.5 #outlier threshold for a particle to be considered residing in substructure, that is how dynamically distinct a particle is. Typical values are >2 +Substructure_physical_linking_length=0.10 +Velocity_ratio=2.0 #ratio of speeds used in phase-space FOF +Velocity_opening_angle=0.10 #angle between velocities. 18 degrees here, typical values are ~10-30 +Velocity_linking_length=0.20 #where scaled by structure dispersion +Significance_level=1.0 #how significant a substructure is relative to Poisson noise. Values >= 1 are fine. + +#for iterative substructure search, rarely ever need to change this +Iterative_threshold_factor=1.0 #change in threshold value when using iterative search. Here no increase in threshold if iterative or not +Iterative_linking_length_factor=2.0 #increase in final linking final iterative substructure search +Iterative_Vratio_factor=1.0 #change in Vratio when using iterative search. no change in vratio +Iterative_ThetaOp_factor=1.0 #change in velocity opening angle. no change in velocity opening angle + +#for checking for halo merger remnants, which are defined as large, well separated phase-space density maxima +Halo_core_search=2 # searches for separate 6dfof cores in field haloes, and then more than just flags halo as merging, assigns particles to each merging "halo". 2 is full separation, 1 is flagging, 0 is off +#if searching for cores, linking lengths. likely does not need to change much +Use_adaptive_core_search=0 #calculate dispersions in configuration & vel space to determine linking lengths +Use_phase_tensor_core_growth=2 #use full stepped phase-space tensor assignment +Halo_core_ellx_fac=0.7 #how linking lengths are changed when searching for local 6DFOF cores, +Halo_core_ellv_fac=2.0 #how velocity lengths based on dispersions are changed when searching for local 6DFOF cores +Halo_core_ncellfac=0.005 #fraction of total halo particle number setting min size of a local 6DFOF core +Halo_core_num_loops=8 #number of loops to iteratively search for cores +Halo_core_loop_ellx_fac=0.75 #how much to change the configuration space linking per iteration +Halo_core_loop_ellv_fac=1.0 #how much to change the velocity space linking per iteration +Halo_core_loop_elln_fac=1.2 #how much to change the min number of particles per iteration +Halo_core_phase_significance=2.0 #how significant a core must be in terms of dispersions (sigma) significance + +################################ +#Unbinding options (VELOCIraptor is able to accurately identify tidal debris so particles need not be bound to a structure) +################################ + +#unbinding related items +Unbind_flag=1 #run unbinding +#objects must have particles that meet the allowed kinetic to potential ratio AND also have some total fraction that are completely bound. +Unbinding_type=0 +#alpha factor used to determine whether particle is "bound" alaph*T+W<0. For standard subhalo catalogues use >0.9 but if interested in tidal debris 0.2-0.5 +Allowed_kinetic_potential_ratio=0.95 +Min_bound_mass_frac=0.65 #minimum bound mass fraction +#run unbinding of field structures, aka halos. This is useful for sams and 6DFOF halos but may not be useful if interested in 3DFOF mass functions. +Bound_halos=0 +#don't keep background potential when unbinding +Keep_background_potential=1 +#use all particles to determine velocity frame for unbinding +Frac_pot_ref=1.0 +Min_npot_ref=20 +#reference frame only meaningful if calculating velocity frame using subset of particles in object. Can use radially sorted fraction of particles about minimum potential or centre of mass +Kinetic_reference_frame_type=0 +Unbinding_max_unbound_removal_fraction_per_iteration=0.5 +Unbinding_max_unbound_fraction=0.95 +Unbinding_max_unbound_fraction_allowed=0.005 + +################################ +#Calculation of properties related options +################################ +Virial_density=500 #user defined virial overdensity. Note that 200 rho_c, 200 rho_m and BN98 are already calculated. +#when calculating properties, for field objects calculate inclusive masses +Inclusive_halo_masses=3 #calculate inclusive masses for halos using full Spherical overdensity apertures +#ensures that output is physical and not comoving distances per little h +Comoving_units=0 +#calculate more (sub)halo properties (like angular momentum in spherical overdensity apertures, both inclusive and exclusive) +Extensive_halo_properties_output=1 +Extensive_gas_properties_output=1 +Extensive_star_properties_output=1 +#calculate aperture masses +Calculate_aperture_quantities=1 +Number_of_apertures=5 +Aperture_values_in_kpc=5,10,30,50,100, +Number_of_projected_apertures=5 +Projected_aperture_values_in_kpc=5,10,30,50,100, +#calculate radial profiles +Calculate_radial_profiles=1 +Number_of_radial_profile_bin_edges=20 +#default radial normalisation log rad bins, normed by R200crit, Integer flag of 0 is log bins and R200crit norm. +Radial_profile_norm=0 +Radial_profile_bin_edges=-2.,-1.87379263,-1.74758526,-1.62137789,-1.49517052,-1.36896316,-1.24275579,-1.11654842,-0.99034105,-0.86413368,-0.73792631,-0.61171894,-0.48551157,-0.3593042,-0.23309684,-0.10688947,0.0193179,0.14552527,0.27173264,0.39794001, +Iterate_cm_flag=0 #do not interate to determine centre-of-mass +Sort_by_binding_energy=1 #sort particles by binding energy +Reference_frame_for_properties=2 #use the minimum potential as reference frame about which to calculate properties + +################################ +#output related +################################ + +Write_group_array_file=0 #do not write a group array file +Separate_output_files=0 #do not separate output into field and substructure files similar to subfind +Binary_output=2 #Use HDF5 output (binary output 1, ascii 0, and HDF 2) +#output particles residing in the spherical overdensity apertures of halos, only the particles exclusively belonging to halos +Spherical_overdensity_halo_particle_list_output=1 + +#halo ids are adjusted by this value * 1000000000000 (or 1000000 if code compiled with the LONGINTS option turned off) +#to ensure that halo ids are temporally unique. So if you had 100 snapshots, for snap 100 set this to 100 and 100*1000000000000 will +#be added to the halo id as set for this snapshot, so halo 1 becomes halo 100*1000000000000+1 and halo 1 of snap 0 would just have ID=1 + +#ALTER THIS as part of a script to get temporally unique ids +Snapshot_value=SNAP + +################################ +#other options +################################ +Verbose=0 #how talkative do you want the code to be, 0 not much, 1 a lot, 2 chatterbox + + diff --git a/examples/SmallCosmoVolume/SmallCosmoVolume_hydro/small_cosmo_volume.yml b/examples/SmallCosmoVolume/SmallCosmoVolume_hydro/small_cosmo_volume.yml index 5904a412f7bf63336de976baa6da4506bae4e36c..36ac8678d2ff174fd74357fb5c20fad73bb9e6cc 100644 --- a/examples/SmallCosmoVolume/SmallCosmoVolume_hydro/small_cosmo_volume.yml +++ b/examples/SmallCosmoVolume/SmallCosmoVolume_hydro/small_cosmo_volume.yml @@ -40,8 +40,9 @@ SPH: # Parameters governing the snapshots Snapshots: basename: snap - delta_time: 1.02 - scale_factor_first: 0.02 + delta_time: 1.05 + scale_factor_first: 0.05 + compression: 4 # Parameters governing the conserved quantities statistics Statistics: diff --git a/examples/SmallCosmoVolume/SmallCosmoVolume_hydro/vrconfig_3dfof_subhalos_SO_hydro.cfg b/examples/SmallCosmoVolume/SmallCosmoVolume_hydro/vrconfig_3dfof_subhalos_SO_hydro.cfg new file mode 100644 index 0000000000000000000000000000000000000000..8590cbf5bc77e8d7a956d210339cced4bbdc692c --- /dev/null +++ b/examples/SmallCosmoVolume/SmallCosmoVolume_hydro/vrconfig_3dfof_subhalos_SO_hydro.cfg @@ -0,0 +1,191 @@ +#Configuration file for analysing Hydro +#runs 3DFOF + substructure algorithm, demands subhalos and FOF halos be self-bound, calculates many properties +#Units currently set to take in as input, Mpc, 1e10 solar masses, km/s, output in same units +#To set temporally unique halo ids, alter Snapshot_value=SNAP to appropriate value. Ie: for snapshot 12, change SNAP to 12 + +################################ +#input options +#set up to use SWIFT HDF input, load gas, star, bh and dark matter +################################ +HDF_name_convention=6 #HDF SWIFT naming convention +Input_includes_dm_particle=1 #include dark matter particles in hydro input +Input_includes_gas_particle=1 #include gas particles in hydro input +Input_includes_star_particle=1 #include star particles in hydro input +Input_includes_bh_particle=1 #include bh particles in hydro input +Input_includes_wind_particle=0 #include wind particles in hydro input (used by Illustris and moves particle type 0 to particle type 3 when decoupled from hydro forces). Here shown as example +Input_includes_tracer_particle=0 #include tracer particles in hydro input (used by Illustris). Here shown as example +Input_includes_extradm_particle=0 #include extra dm particles stored in particle type 2 and type 3, useful for zooms + +Halo_core_phase_merge_dist=0.25 #merge substructures if difference in dispersion normalised distance is < this value +Apply_phase_merge_to_host=1 #merge substructures with background if centrally located and phase-distance is small + +#units conversion from input input to desired internal unit +Length_input_unit_conversion_to_output_unit=1.0 #default code unit, +Velocity_input_unit_conversion_to_output_unit=1.0 #default velocity unit, +Mass_input_unit_conversion_to_output_unit=1.0 #default mass unit, +#assumes input is in 1e10 msun, Mpc and km/s and output units are the same +Gravity=43.0211349 #for 1e10 Msun, km/s and Mpc +Hubble_unit=100.0 # assuming units are km/s and Mpc, then value of Hubble in km/s/Mpc +#converting hydro quantities +Stellar_age_input_is_cosmological_scalefactor=1 +Metallicity_input_unit_conversion_to_output_unit=1.0 +Stellar_age_input_unit_conversion_to_output_unit=1.0 +Star_formation_rate_input_unit_conversion_to_output_unit=1.0 + +#set the units of the output by providing conversion to a defined unit +#conversion of output length units to kpc +Length_unit_to_kpc=1000.0 +#conversion of output velocity units to km/s +Velocity_to_kms=1.0 +#conversion of output mass units to solar masses +Mass_to_solarmass=1.0e10 +#1 / 0.012 +Metallicity_to_solarmetallicity=83.33 +Star_formation_rate_to_solarmassperyear=97.78 +Stellar_age_to_yr=1.0 +#ensures that output is physical and not comoving distances per little h +Comoving_units=0 + +#sets the total buffer size in bytes used to store temporary particle information +#of mpi read threads before they are broadcast to the appropriate waiting non-read threads +#if not set, default value is equivalent to 1e6 particles per mpi process, quite large +#but significantly minimises the number of send/receives +#in this example the buffer size is roughly that for a send/receive of 10000 particles +#for 100 mpi processes +MPI_particle_total_buf_size=100000000 + +################################ +#search related options +################################ + +#how to search a simulation +Particle_search_type=1 #search dark matter particles only +#for baryon search +Baryon_searchflag=2 #if 1 search for baryons separately using phase-space search when identifying substructures, 2 allows special treatment in field FOF linking and phase-space substructure search, 0 treat the same as dark matter particles +#for search for substruture +Search_for_substructure=1 #if 0, end search once field objects are found +#also useful for zoom simulations or simulations of individual objects, setting this flag means no field structure search is run +Singlehalo_search=0 #if file is single halo in which one wishes to search for substructure. Here disabled. +#additional option for field haloes +Keep_FOF=0 #if field 6DFOF search is done, allows to keep structures found in 3DFOF (can be interpreted as the inter halo stellar mass when only stellar search is used).\n + +#minimum size for structures +Minimum_size=20 #min 20 particles +Minimum_halo_size=32 #if field halos have different minimum sizes, otherwise set to -1. + +#for field fof halo search +FoF_Field_search_type=5 #5 3DFOF search for field halos, 4 for 6DFOF clean up of field halos, 3 for 6DFOF with velocity scale distinct for each initial 3D FOF candidate +Halo_3D_linking_length=0.20 + +#for mean field estimates and local velocity density distribution funciton estimator related quantiites, rarely need to change this +Local_velocity_density_approximate_calculation=1 #calculates velocity density using approximative (and quicker) near neighbour search +Cell_fraction = 0.01 #fraction of field fof halo used to determine mean velocity distribution function. Typical values are ~0.005-0.02 +Grid_type=1 #normal entropy based grid, shouldn't have to change +Nsearch_velocity=32 #number of velocity neighbours used to calculate local velocity distribution function. Typial values are ~32 +Nsearch_physical=256 #numerof physical neighbours from which the nearest velocity neighbour set is based. Typical values are 128-512 + +#for substructure search, rarely ever need to change this +FoF_search_type=1 #default phase-space FOF search. Don't really need to change +Iterative_searchflag=1 #iterative substructure search, for substructure find initial candidate substructures with smaller linking lengths then expand search region +Outlier_threshold=2.5 #outlier threshold for a particle to be considered residing in substructure, that is how dynamically distinct a particle is. Typical values are >2 +Substructure_physical_linking_length=0.10 +Velocity_ratio=2.0 #ratio of speeds used in phase-space FOF +Velocity_opening_angle=0.10 #angle between velocities. 18 degrees here, typical values are ~10-30 +Velocity_linking_length=0.20 #where scaled by structure dispersion +Significance_level=1.0 #how significant a substructure is relative to Poisson noise. Values >= 1 are fine. + +#for iterative substructure search, rarely ever need to change this +Iterative_threshold_factor=1.0 #change in threshold value when using iterative search. Here no increase in threshold if iterative or not +Iterative_linking_length_factor=2.0 #increase in final linking final iterative substructure search +Iterative_Vratio_factor=1.0 #change in Vratio when using iterative search. no change in vratio +Iterative_ThetaOp_factor=1.0 #change in velocity opening angle. no change in velocity opening angle + +#for checking for halo merger remnants, which are defined as large, well separated phase-space density maxima +Halo_core_search=2 # searches for separate 6dfof cores in field haloes, and then more than just flags halo as merging, assigns particles to each merging "halo". 2 is full separation, 1 is flagging, 0 is off +#if searching for cores, linking lengths. likely does not need to change much +Use_adaptive_core_search=0 #calculate dispersions in configuration & vel space to determine linking lengths +Use_phase_tensor_core_growth=2 #use full stepped phase-space tensor assignment +Halo_core_ellx_fac=0.7 #how linking lengths are changed when searching for local 6DFOF cores, +Halo_core_ellv_fac=2.0 #how velocity lengths based on dispersions are changed when searching for local 6DFOF cores +Halo_core_ncellfac=0.005 #fraction of total halo particle number setting min size of a local 6DFOF core +Halo_core_num_loops=8 #number of loops to iteratively search for cores +Halo_core_loop_ellx_fac=0.75 #how much to change the configuration space linking per iteration +Halo_core_loop_ellv_fac=1.0 #how much to change the velocity space linking per iteration +Halo_core_loop_elln_fac=1.2 #how much to change the min number of particles per iteration +Halo_core_phase_significance=2.0 #how significant a core must be in terms of dispersions (sigma) significance + +################################ +#Unbinding options (VELOCIraptor is able to accurately identify tidal debris so particles need not be bound to a structure) +################################ + +#unbinding related items +Unbind_flag=1 #run unbinding +#objects must have particles that meet the allowed kinetic to potential ratio AND also have some total fraction that are completely bound. +Unbinding_type=0 +#alpha factor used to determine whether particle is "bound" alaph*T+W<0. For standard subhalo catalogues use >0.9 but if interested in tidal debris 0.2-0.5 +Allowed_kinetic_potential_ratio=0.95 +Min_bound_mass_frac=0.65 #minimum bound mass fraction +#run unbinding of field structures, aka halos. This is useful for sams and 6DFOF halos but may not be useful if interested in 3DFOF mass functions. +Bound_halos=0 +#don't keep background potential when unbinding +Keep_background_potential=1 +#use all particles to determine velocity frame for unbinding +Frac_pot_ref=1.0 +Min_npot_ref=20 +#reference frame only meaningful if calculating velocity frame using subset of particles in object. Can use radially sorted fraction of particles about minimum potential or centre of mass +Kinetic_reference_frame_type=0 +Unbinding_max_unbound_removal_fraction_per_iteration=0.5 +Unbinding_max_unbound_fraction=0.95 +Unbinding_max_unbound_fraction_allowed=0.005 + +################################ +#Calculation of properties related options +################################ +Virial_density=500 #user defined virial overdensity. Note that 200 rho_c, 200 rho_m and BN98 are already calculated. +#when calculating properties, for field objects calculate inclusive masses +Inclusive_halo_masses=3 #calculate inclusive masses for halos using full Spherical overdensity apertures +#ensures that output is physical and not comoving distances per little h +Comoving_units=0 +#calculate more (sub)halo properties (like angular momentum in spherical overdensity apertures, both inclusive and exclusive) +Extensive_halo_properties_output=1 +Extensive_gas_properties_output=1 +Extensive_star_properties_output=1 +#calculate aperture masses +Calculate_aperture_quantities=1 +Number_of_apertures=5 +Aperture_values_in_kpc=5,10,30,50,100, +Number_of_projected_apertures=5 +Projected_aperture_values_in_kpc=5,10,30,50,100, +#calculate radial profiles +Calculate_radial_profiles=1 +Number_of_radial_profile_bin_edges=20 +#default radial normalisation log rad bins, normed by R200crit, Integer flag of 0 is log bins and R200crit norm. +Radial_profile_norm=0 +Radial_profile_bin_edges=-2.,-1.87379263,-1.74758526,-1.62137789,-1.49517052,-1.36896316,-1.24275579,-1.11654842,-0.99034105,-0.86413368,-0.73792631,-0.61171894,-0.48551157,-0.3593042,-0.23309684,-0.10688947,0.0193179,0.14552527,0.27173264,0.39794001, +Iterate_cm_flag=0 #do not interate to determine centre-of-mass +Sort_by_binding_energy=1 #sort particles by binding energy +Reference_frame_for_properties=2 #use the minimum potential as reference frame about which to calculate properties + +################################ +#output related +################################ + +Write_group_array_file=0 #do not write a group array file +Separate_output_files=0 #do not separate output into field and substructure files similar to subfind +Binary_output=2 #Use HDF5 output (binary output 1, ascii 0, and HDF 2) +#output particles residing in the spherical overdensity apertures of halos, only the particles exclusively belonging to halos +Spherical_overdensity_halo_particle_list_output=1 + +#halo ids are adjusted by this value * 1000000000000 (or 1000000 if code compiled with the LONGINTS option turned off) +#to ensure that halo ids are temporally unique. So if you had 100 snapshots, for snap 100 set this to 100 and 100*1000000000000 will +#be added to the halo id as set for this snapshot, so halo 1 becomes halo 100*1000000000000+1 and halo 1 of snap 0 would just have ID=1 + +#ALTER THIS as part of a script to get temporally unique ids +Snapshot_value=SNAP + +################################ +#other options +################################ +Verbose=0 #how talkative do you want the code to be, 0 not much, 1 a lot, 2 chatterbox + + diff --git a/examples/SubgridTests/CosmologicalStellarEvolution/stellar_evolution.yml b/examples/SubgridTests/CosmologicalStellarEvolution/stellar_evolution.yml index b3d318d68b69d0940d7a37b17ae5331a711b140f..b6188cd20deb7f26dca4625981e8f1cd26d557af 100644 --- a/examples/SubgridTests/CosmologicalStellarEvolution/stellar_evolution.yml +++ b/examples/SubgridTests/CosmologicalStellarEvolution/stellar_evolution.yml @@ -84,7 +84,7 @@ EAGLECooling: He_reion_z_sigma: 0.5 # Spread in redshift of the Helium re-ionization Gaussian He_reion_eV_p_H: 2.0 # Energy inject by Helium re-ionization in electron-volt per Hydrogen atom -# Properties of the EAGLE feedback and enrichment model. +# Properties of the EAGLE feedback and enrichment model. This matches the EAGLE-Ref (Schaye+2015) model. EAGLEFeedback: use_SNII_feedback: 0 # Global switch for SNII thermal (stochastic) feedback. use_SNIa_feedback: 0 # Global switch for SNIa thermal (continuous) feedback. @@ -94,9 +94,10 @@ EAGLEFeedback: filename: ./yieldtables/ # Path to the directory containing the EAGLE yield tables. IMF_min_mass_Msun: 0.1 # Minimal stellar mass considered for the Chabrier IMF in solar masses. IMF_max_mass_Msun: 100.0 # Maximal stellar mass considered for the Chabrier IMF in solar masses. - SNII_min_mass_Msun: 6.0 # Minimal mass considered for SNII feedback (not SNII enrichment!) in solar masses. - SNII_max_mass_Msun: 100.0 # Maximal mass considered for SNII feedback (not SNII enrichment!) in solar masses. - SNII_wind_delay_Gyr: 0.03 # Time in Gyr between a star's birth and the SNII thermal feedback event. + SNII_min_mass_Msun: 6.0 # Minimal mass considered for SNII stars in solar masses. + SNII_max_mass_Msun: 100.0 # Maximal mass considered for SNII stars in solar masses. + SNII_sampled_delay: 0 # Sample the SNII lifetimes to do feedback. + SNII_wind_delay_Gyr: 0.03 # Time in Gyr between a star's birth and the SNII thermal feedback event when not sampling. SNII_delta_T_K: 3.16228e7 # Change in temperature to apply to the gas particle in a SNII thermal feedback event in Kelvin. SNII_energy_erg: 1.0e51 # Energy of one SNII explosion in ergs. SNII_energy_fraction_min: 0.3 # Minimal fraction of energy applied in a SNII feedback event. @@ -105,9 +106,10 @@ EAGLEFeedback: SNII_energy_fraction_n_0_H_p_cm3: 0.67 # Pivot point for the birth density dependance of the SNII energy fraction in cm^-3. SNII_energy_fraction_n_Z: 0.8686 # Power-law for the metallicity dependance of the SNII energy fraction. SNII_energy_fraction_n_n: 0.8686 # Power-law for the birth density dependance of the SNII energy fraction. - SNIa_max_mass_Msun: 8.0 # Maximal mass considered for SNIa feedback and enrichment in solar masses. - SNIa_timescale_Gyr: 2.0 # Time-scale of the exponential decay of the SNIa rates in Gyr. - SNIa_efficiency_p_Msun: 0.002 # Normalisation of the SNIa rates in inverse solar masses. + SNIa_DTD_delay_Gyr: 0.04 # Age of the most massive SNIa in Gyr. + SNIa_DTD: Exponential # Use the EAGLE-Ref SNIa DTD. + SNIa_DTD_exp_timescale_Gyr: 2.0 # Time-scale of the exponential decay of the SNIa rates in Gyr. + SNIa_DTD_exp_norm_p_Msun: 0.002 # Normalisation of the SNIa rates in inverse solar masses. SNIa_energy_erg: 1.0e51 # Energy of one SNIa explosion in ergs. AGB_ejecta_velocity_km_p_s: 10.0 # Velocity of the AGB ejectas in km/s. SNII_yield_factor_Hydrogen: 1.0 # (Optional) Correction factor to apply to the Hydrogen yield from the SNII channel. diff --git a/examples/SubgridTests/PressureFloor/README b/examples/SubgridTests/PressureFloor/README new file mode 100644 index 0000000000000000000000000000000000000000..cef6623204ccaa06642bb1385f771dd979a951b6 --- /dev/null +++ b/examples/SubgridTests/PressureFloor/README @@ -0,0 +1,6 @@ +This example consists in a uniform box of particles. +Using the cooling and gravity, the temperature of the gas will decrease +slowly and the gas will start to collapse due to the numerical noise. +If a pressure / energy floor is applied, the box should remain uniform. + +At the end, a plot containing the distribution of densities is generated. \ No newline at end of file diff --git a/examples/SubgridTests/SupernovaeFeedback/getGlass.sh b/examples/SubgridTests/PressureFloor/getGlass.sh old mode 100755 new mode 100644 similarity index 87% rename from examples/SubgridTests/SupernovaeFeedback/getGlass.sh rename to examples/SubgridTests/PressureFloor/getGlass.sh index d5c5f590ac37c9c9431d626a2ea61b0c12c1513c..81c2cc6ff2b3aa07cac3a6ee7a225f9e9a6b740a --- a/examples/SubgridTests/SupernovaeFeedback/getGlass.sh +++ b/examples/SubgridTests/PressureFloor/getGlass.sh @@ -1,2 +1,2 @@ #!/bin/bash -wget http://virgodb.cosma.dur.ac.uk/swift-webstorage/ICs/glassCube_64.hdf5 +wget http://virgodb.cosma.dur.ac.uk/swift-webstorage/ICs/glassCube_16.hdf5 diff --git a/examples/SubgridTests/PressureFloor/makeIC.py b/examples/SubgridTests/PressureFloor/makeIC.py new file mode 100644 index 0000000000000000000000000000000000000000..5cf225538fa9c16237fa476fd55501a5a15eaaed --- /dev/null +++ b/examples/SubgridTests/PressureFloor/makeIC.py @@ -0,0 +1,113 @@ +############################################################################### +# This file is part of SWIFT. +# Copyright (c) 2020 loic hausammann (loic.hausammann@epfl.ch) +# +# 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 numpy as np + +# Generates a SWIFT IC file with a constant density and pressure + +# Parameters +periodic = 1 # 1 For periodic box +boxSize = 200 # 200 kiloparsec +rho = 200 # Density in code units +T = 3000 # Initial Temperature +gamma = 5./3. # Gas adiabatic index +fileName = "pressureFloor.hdf5" +# --------------------------------------------------- + +# defines some constants +# need to be changed in plotTemperature.py too +h_frac = 0.76 +mu = 4. / (1. + 3. * h_frac) + +m_h_cgs = 1.67e-24 +k_b_cgs = 1.38e-16 + +# defines units +unit_length = 3.0857e21 # kpc +unit_mass = 2.0e33 # solar mass +unit_time = 3.0857e16 # ~ Gyr + +# Read id, position and h from glass +glass = h5py.File("glassCube_16.hdf5", "r") +ids = glass["/PartType0/ParticleIDs"][:] +pos = glass["/PartType0/Coordinates"][:, :] * boxSize +h = glass["/PartType0/SmoothingLength"][:] * boxSize + +# Compute basic properties +numPart = np.size(pos) // 3 +mass = boxSize**3 * rho / numPart +internalEnergy = k_b_cgs * T * mu / ((gamma - 1.) * m_h_cgs) +internalEnergy *= (unit_time / unit_length)**2 + +# File +f = h5py.File(fileName, 'w') + +# Header +grp = f.create_group("/Header") +grp.attrs["BoxSize"] = boxSize +grp.attrs["NumPart_Total"] = [numPart, 0, 0, 0, 0, 0] +grp.attrs["NumPart_Total_HighWord"] = [0, 0, 0, 0, 0, 0] +grp.attrs["NumPart_ThisFile"] = [numPart, 0, 0, 0, 0, 0] +grp.attrs["Time"] = 0.0 +grp.attrs["NumFilesPerSnapshot"] = 1 +grp.attrs["MassTable"] = [0.0, 0.0, 0.0, 0.0, 0.0, 0.0] +grp.attrs["Flag_Entropy_ICs"] = 0 + +# Runtime parameters +grp = f.create_group("/RuntimePars") +grp.attrs["PeriodicBoundariesOn"] = periodic + +# Units +grp = f.create_group("/Units") +grp.attrs["Unit length in cgs (U_L)"] = unit_length +grp.attrs["Unit mass in cgs (U_M)"] = unit_mass +grp.attrs["Unit time in cgs (U_t)"] = unit_time +grp.attrs["Unit current in cgs (U_I)"] = 1. +grp.attrs["Unit temperature in cgs (U_T)"] = 1. + +# Particle group +grp = f.create_group("/PartType0") + +v = np.zeros((numPart, 3)) +ds = grp.create_dataset('Velocities', (numPart, 3), 'f') +ds[()] = v + +m = np.full((numPart, 1), mass) +ds = grp.create_dataset('Masses', (numPart, 1), 'f') +ds[()] = m + +h = np.reshape(h, (numPart, 1)) +ds = grp.create_dataset('SmoothingLength', (numPart, 1), 'f') +ds[()] = h + +u = np.full((numPart, 1), internalEnergy) +ds = grp.create_dataset('InternalEnergy', (numPart, 1), 'f') +ds[()] = u + +ids = np.reshape(ids, (numPart, 1)) +ds = grp.create_dataset('ParticleIDs', (numPart, 1), 'L') +ds[()] = ids + +ds = grp.create_dataset('Coordinates', (numPart, 3), 'd') +ds[()] = pos + +f.close() + +print("Initial condition generated") diff --git a/examples/SubgridTests/PressureFloor/plotDensity.py b/examples/SubgridTests/PressureFloor/plotDensity.py new file mode 100644 index 0000000000000000000000000000000000000000..e9f15d962a51a2adf404be5c3d419a8b0a26d90d --- /dev/null +++ b/examples/SubgridTests/PressureFloor/plotDensity.py @@ -0,0 +1,35 @@ +#!/usr/bin/env python +############################################################################### +# This file is part of SWIFT. +# Copyright (c) 2020 Loic Hausammann (loic.hausammann@epfl.ch) +# +# 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 matplotlib.pyplot as plt +from h5py import File +import sys + +N = 100 +filename = "pressureFloor_%04i.hdf5" % int(sys.argv[-1]) + +f = File(filename, "r") + +rho = f["PartType0"]["Densities"][:] + +plt.hist(rho, 100, log=True) +plt.xlabel("Density [M$_\odot$ kpc$^{-3}$]") +plt.ylabel("Number of particles") +plt.savefig("density.png", dpi=200) diff --git a/examples/SubgridTests/PressureFloor/pressureFloor.yml b/examples/SubgridTests/PressureFloor/pressureFloor.yml new file mode 100644 index 0000000000000000000000000000000000000000..f9df74dcefb14204264a4ffc9a7326d3453f718d --- /dev/null +++ b/examples/SubgridTests/PressureFloor/pressureFloor.yml @@ -0,0 +1,53 @@ +# Define the system of units to use internally. +InternalUnitSystem: + UnitMass_in_cgs: 2.0e33 # Solar masses + UnitLength_in_cgs: 3.0857e21 # parsecs + UnitVelocity_in_cgs: 1.0e5 # megameters per second + UnitCurrent_in_cgs: 1 # Amperes + UnitTemp_in_cgs: 1 # Kelvin + +# Parameters governing the time integration +TimeIntegration: + time_begin: 0. # The starting time of the simulation (in internal units). + time_end: 8e1 # 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: 1e1 # The maximal time-step size of the simulation (in internal units). + +# Parameters governing the snapshots +Snapshots: + basename: pressureFloor # Common part of the name of output files + time_first: 0. # Time of the first output (in internal units) + delta_time: 1e0 # Time difference between consecutive outputs (in internal units) + +# Parameters governing the conserved quantities statistics +Statistics: + delta_time: 1e0 # Time between statistics output + +# Parameters for the hydrodynamics scheme +SPH: + resolution_eta: 1.2348 # Target smoothing length in units of the mean inter-particle separation (1.2348 == 48Ngbs with the cubic spline kernel). + CFL_condition: 0.5 # Courant-Friedrich-Levy condition for time integration. + minimal_temperature: 10. # Kelvin + +# Parameters related to the initial conditions +InitialConditions: + file_name: ./pressureFloor.hdf5 # The file to read + periodic: 1 + +# Dimensionless pre-factor for the time-step condition +LambdaCooling: + lambda_nH2_cgs: 1e-15 # Cooling rate divided by square Hydrogen number density (in cgs units [erg * s^-1 * cm^3]) + cooling_tstep_mult: 1e5 # Dimensionless pre-factor for the time-step condition + +# Parameters related to pressure floors ---------------------------------------------- +GEARPressureFloor: + Jeans_factor: 10 + + # Parameters for the self-gravity scheme +Gravity: + mesh_side_length: 12 # Number of cells along each axis for the periodic gravity mesh. + eta: 2.5 # Constant dimensionless multiplier for time integration. + theta: 0.7 # Opening angle (Multipole acceptance criterion). + max_physical_DM_softening: 0.5 # Maximal Plummer-equivalent softening length in physical coordinates for DM particles (in internal units). + max_physical_baryon_softening: 0.5 # Maximal Plummer-equivalent softening length in physical coordinates for baryon particles (in internal units). + softening_ratio_background: 0.04 # Fraction of the mean inter-particle separation to use as Plummer-equivalent softening for the background DM particles. diff --git a/examples/SubgridTests/PressureFloor/run.sh b/examples/SubgridTests/PressureFloor/run.sh new file mode 100644 index 0000000000000000000000000000000000000000..6d90f8345bfd25fbe826ad992313fa28bfda22c3 --- /dev/null +++ b/examples/SubgridTests/PressureFloor/run.sh @@ -0,0 +1,21 @@ + +#!/bin/bash + +# Generate the initial conditions if they are not present. +if [ ! -e glassCube_32.hdf5 ] +then + echo "Fetching initial glass file for the cooling box example..." + ./getGlass.sh +fi +if [ ! -e coolingBox.hdf5 ] +then + echo "Generating initial conditions for the cooling box example..." + python makeIC.py +fi + +rm pressureFloor_* +# Run SWIFT +../../swift --self-gravity --hydro --cooling --threads=8 pressureFloor.yml + +# Check if the simulation collapsed +python plotDensity.py 80 diff --git a/examples/SubgridTests/StellarEvolution/plot_box_evolution.py b/examples/SubgridTests/StellarEvolution/plot_box_evolution.py index a4f601875beb40c8f264cda385815f2d6dd81a41..aa1f07f98ecede241423bc72a3e0cf7d76963979 100644 --- a/examples/SubgridTests/StellarEvolution/plot_box_evolution.py +++ b/examples/SubgridTests/StellarEvolution/plot_box_evolution.py @@ -107,12 +107,12 @@ t = zeros(n_snapshots) # Read data from snapshots for i in range(n_snapshots): - #print("reading snapshot "+str(i)) - sim = h5py.File("stellar_evolution_%04d.hdf5"%i, "r") - t[i] = sim["/Header"].attrs["Time"][0] + #print("reading snapshot "+str(i)) + sim = h5py.File("stellar_evolution_%04d.hdf5"%i, "r") + t[i] = sim["/Header"].attrs["Time"][0] - masses = sim["/PartType0/Masses"][:] - swift_box_gas_mass[i] = np.sum(masses) + masses = sim["/PartType0/Masses"][:] + swift_box_gas_mass[i] = np.sum(masses) AGB_mass = sim["/PartType0/MassesFromAGB"][:] SNII_mass = sim["/PartType0/MassesFromSNII"][:] @@ -121,13 +121,13 @@ for i in range(n_snapshots): swift_box_gas_mass_AGB[i] = np.sum(AGB_mass) swift_box_gas_mass_SNII[i] = np.sum(SNII_mass) swift_box_gas_mass_SNIa[i] = np.sum(SNIa_mass) - + Z_star = sim["/PartType4/MetalMassFractions"][0] - star_masses = sim["/PartType4/Masses"][:] - swift_box_star_mass[i] = np.sum(star_masses) + star_masses = sim["/PartType4/Masses"][:] + swift_box_star_mass[i] = np.sum(star_masses) - metallicities = sim["/PartType0/MetalMassFractions"][:] - swift_box_gas_metal_mass[i] = np.sum(metallicities * masses) + metallicities = sim["/PartType0/MetalMassFractions"][:] + swift_box_gas_metal_mass[i] = np.sum(metallicities * masses) AGB_Z_frac = sim["/PartType0/MetalMassFractionsFromAGB"][:] SNII_Z_frac = sim["/PartType0/MetalMassFractionsFromSNII"][:] @@ -136,10 +136,10 @@ for i in range(n_snapshots): swift_box_gas_metal_mass_AGB[i] = np.sum(AGB_Z_frac * masses) swift_box_gas_metal_mass_SNII[i] = np.sum(SNII_Z_frac * masses) swift_box_gas_metal_mass_SNIa[i] = np.sum(SNIa_Z_frac * masses) - - element_abundances = sim["/PartType0/ElementMassFractions"][:][:] - for j in range(n_elements): - swift_element_mass[i,j] = np.sum(element_abundances[:,j] * masses) + + element_abundances = sim["/PartType0/ElementMassFractions"][:][:] + for j in range(n_elements): + swift_element_mass[i,j] = np.sum(element_abundances[:,j] * masses) v = sim["/PartType0/Velocities"][:,:] v2 = v[:,0]**2 + v[:,1]**2 + v[:,2]**2 @@ -218,8 +218,8 @@ colours = ['k','r','g','b','c','y','m','skyblue','plum'] element_names = ['H','He','C','N','O','Ne','Mg','Si','Fe'] subplot(223) for j in range(n_elements): - plot(t[1:] * unit_time_in_cgs / Gyr_in_cgs, (swift_element_mass[1:,j] - swift_element_mass[0,j]) * unit_mass_in_cgs / Msun_in_cgs, linewidth=0.5, color=colours[j], ms=0.5, label=element_names[j]) - plot(eagle_time_Gyr[1:],eagle_total_element_mass[:-1,j],linewidth=1,color=colours[j],linestyle='--') + plot(t[1:] * unit_time_in_cgs / Gyr_in_cgs, (swift_element_mass[1:,j] - swift_element_mass[0,j]) * unit_mass_in_cgs / Msun_in_cgs, linewidth=0.5, color=colours[j], ms=0.5, label=element_names[j]) + plot(eagle_time_Gyr[1:],eagle_total_element_mass[:-1,j],linewidth=1,color=colours[j],linestyle='--') xlabel("${\\rm Time~[Gyr]}$", labelpad=0) ylabel("Change in element mass of gas particles ${[\\rm M_\\odot]}$", labelpad=2) xscale("log") diff --git a/examples/SubgridTests/StellarEvolution/run.sh b/examples/SubgridTests/StellarEvolution/run.sh index 2f650146394e5d0d5ea93a0d415f471452b685e8..032083db5055dadac8c1bdcdc6cad3e2e03498a1 100755 --- a/examples/SubgridTests/StellarEvolution/run.sh +++ b/examples/SubgridTests/StellarEvolution/run.sh @@ -26,11 +26,11 @@ then ./getSolutions.sh fi -../../swift --temperature --feedback --stars --hydro --external-gravity --threads=4 stellar_evolution.yml -P EAGLEChemistry:init_abundance_metal:0.08 2>&1 | tee output_0p08.log +../../swift --temperature --feedback --stars --hydro --external-gravity --threads=4 stellar_evolution.yml -P EAGLEChemistry:init_abundance_metal:0.08 -P EAGLEChemistry:init_abundance_Hydrogen:0.71 -P EAGLEChemistry:init_abundance_Helium:0.21 2>&1 | tee output_0p08.log python plot_box_evolution.py -../../swift --temperature --feedback --stars --hydro --external-gravity --threads=4 stellar_evolution.yml -P EAGLEChemistry:init_abundance_metal:0.04 2>&1 | tee output_0p04.log +../../swift --temperature --feedback --stars --hydro --external-gravity --threads=4 stellar_evolution.yml -P EAGLEChemistry:init_abundance_metal:0.04 -P EAGLEChemistry:init_abundance_Hydrogen:0.74 -P EAGLEChemistry:init_abundance_Helium:0.23 2>&1 | tee output_0p04.log python plot_box_evolution.py diff --git a/examples/SubgridTests/StellarEvolution/stellar_evolution.yml b/examples/SubgridTests/StellarEvolution/stellar_evolution.yml index 63c7a4d2624793af26bdbaf628715243e2ab511d..fb0b385bc9345920e478846f2bfccc07416a2932 100644 --- a/examples/SubgridTests/StellarEvolution/stellar_evolution.yml +++ b/examples/SubgridTests/StellarEvolution/stellar_evolution.yml @@ -16,8 +16,8 @@ TimeIntegration: # Parameters governing the snapshots Snapshots: basename: stellar_evolution # Common part of the name of output files - time_first: 0. # Time of the first output (in internal units) - delta_time: 3.e-5 # Time difference between consecutive outputs without cosmology (internal units) + time_first: 0. # Time of the first output (in internal units) + delta_time: 3.e-5 # Time difference between consecutive outputs (internal units) compression: 4 # Parameters governing the conserved quantities statistics @@ -78,7 +78,7 @@ EAGLECooling: He_reion_z_sigma: 0.5 # Spread in redshift of the Helium re-ionization Gaussian He_reion_eV_p_H: 2.0 # Energy inject by Helium re-ionization in electron-volt per Hydrogen atom -# Properties of the EAGLE feedback and enrichment model. +# Properties of the EAGLE feedback and enrichment model. This matches the EAGLE-Ref (Schaye+2015) model. EAGLEFeedback: use_SNII_feedback: 0 # Global switch for SNII thermal (stochastic) feedback. use_SNIa_feedback: 0 # Global switch for SNIa thermal (continuous) feedback. @@ -88,9 +88,10 @@ EAGLEFeedback: filename: ./yieldtables/ # Path to the directory containing the EAGLE yield tables. IMF_min_mass_Msun: 0.1 # Minimal stellar mass considered for the Chabrier IMF in solar masses. IMF_max_mass_Msun: 100.0 # Maximal stellar mass considered for the Chabrier IMF in solar masses. - SNII_min_mass_Msun: 6.0 # Minimal mass considered for SNII feedback (not SNII enrichment!) in solar masses. - SNII_max_mass_Msun: 100.0 # Maximal mass considered for SNII feedback (not SNII enrichment!) in solar masses. - SNII_wind_delay_Gyr: 0.03 # Time in Gyr between a star's birth and the SNII thermal feedback event. + SNII_min_mass_Msun: 6.0 # Minimal mass considered for SNII stars in solar masses. + SNII_max_mass_Msun: 100.0 # Maximal mass considered for SNII stars in solar masses. + SNII_sampled_delay: 0 # Sample the SNII lifetimes to do feedback. + SNII_wind_delay_Gyr: 0.03 # Time in Gyr between a star's birth and the SNII thermal feedback event when not sampling. SNII_delta_T_K: 3.16228e7 # Change in temperature to apply to the gas particle in a SNII thermal feedback event in Kelvin. SNII_energy_erg: 1.0e51 # Energy of one SNII explosion in ergs. SNII_energy_fraction_min: 0.3 # Minimal fraction of energy applied in a SNII feedback event. @@ -99,11 +100,14 @@ EAGLEFeedback: SNII_energy_fraction_n_0_H_p_cm3: 0.67 # Pivot point for the birth density dependance of the SNII energy fraction in cm^-3. SNII_energy_fraction_n_Z: 0.8686 # Power-law for the metallicity dependance of the SNII energy fraction. SNII_energy_fraction_n_n: 0.8686 # Power-law for the birth density dependance of the SNII energy fraction. - SNIa_max_mass_Msun: 8.0 # Maximal mass considered for SNIa feedback and enrichment in solar masses. - SNIa_timescale_Gyr: 2.0 # Time-scale of the exponential decay of the SNIa rates in Gyr. - SNIa_efficiency_p_Msun: 0.002 # Normalisation of the SNIa rates in inverse solar masses. + SNIa_DTD_delay_Gyr: 0.04 # Age of the most massive SNIa in Gyr. + SNIa_DTD: Exponential # Use the EAGLE-Ref SNIa DTD. + SNIa_DTD_exp_timescale_Gyr: 2.0 # Time-scale of the exponential decay of the SNIa rates in Gyr. + SNIa_DTD_exp_norm_p_Msun: 0.002 # Normalisation of the SNIa rates in inverse solar masses. SNIa_energy_erg: 1.0e51 # Energy of one SNIa explosion in ergs. AGB_ejecta_velocity_km_p_s: 10.0 # Velocity of the AGB ejectas in km/s. + stellar_evolution_age_cut_Gyr: 0.1 # Age in Gyr above which the enrichment is downsampled. + stellar_evolution_sampling_rate: 10 # Number of time-steps in-between two enrichment events for a star above the age threshold. SNII_yield_factor_Hydrogen: 1.0 # (Optional) Correction factor to apply to the Hydrogen yield from the SNII channel. SNII_yield_factor_Helium: 1.0 # (Optional) Correction factor to apply to the Helium yield from the SNII channel. SNII_yield_factor_Carbon: 0.5 # (Optional) Correction factor to apply to the Carbon yield from the SNII channel. diff --git a/examples/SubgridTests/SupernovaeFeedback/SN_feedback.yml b/examples/SubgridTests/SupernovaeFeedback/SN_feedback.yml deleted file mode 100644 index a59ae302ff4052a3daf0535e93a0c2cd5e9904f5..0000000000000000000000000000000000000000 --- a/examples/SubgridTests/SupernovaeFeedback/SN_feedback.yml +++ /dev/null @@ -1,44 +0,0 @@ -# Define the system of units to use internally. -InternalUnitSystem: - UnitMass_in_cgs: 1 # Grams - UnitLength_in_cgs: 1 # Centimeters - UnitVelocity_in_cgs: 1 # Centimeters per second - UnitCurrent_in_cgs: 1 # Amperes - UnitTemp_in_cgs: 1 # Kelvin - -# Values of some physical constants -PhysicalConstants: - G: 0 # (Optional) Overwrite the value of Newton's constant used internally by the code. - -# Parameters governing the time integration -TimeIntegration: - time_begin: 0. # The starting time of the simulation (in internal units). - time_end: 5e-2 # The end time of the simulation (in internal units). - dt_min: 1e-7 # The minimal time-step size of the simulation (in internal units). - dt_max: 1e-4 # The maximal time-step size of the simulation (in internal units). - -# Parameters governing the snapshots -Snapshots: - basename: SN_feedback # Common part of the name of output files - time_first: 0. # Time of the first output (in internal units) - delta_time: 1e-2 # Time difference between consecutive outputs (in internal units) - compression: 1 - -# Parameters governing the conserved quantities statistics -Statistics: - delta_time: 1e-3 # Time between statistics output - -# Parameters for the hydrodynamics scheme -SPH: - resolution_eta: 1.2348 # Target smoothing length in units of the mean inter-particle separation (1.2348 == 48Ngbs with the cubic spline kernel). - CFL_condition: 0.1 # Courant-Friedrich-Levy condition for time integration. - -# Parameters related to the initial conditions -InitialConditions: - file_name: ./SN_feedback.hdf5 - smoothing_length_scaling: 1. - periodic: 1 # Are we running with periodic ICs? - -# Parameters for the stellar models -Stars: - resolution_eta: 1.2348 # Target smoothing length in units of the mean inter-particle separation (1.2348 == 48Ngbs with the cubic spline kernel). diff --git a/examples/SubgridTests/SupernovaeFeedback/makeIC.py b/examples/SubgridTests/SupernovaeFeedback/makeIC.py deleted file mode 100644 index 8a0fca2bfd21f2cf1d5052660581d97184705480..0000000000000000000000000000000000000000 --- a/examples/SubgridTests/SupernovaeFeedback/makeIC.py +++ /dev/null @@ -1,117 +0,0 @@ -############################################################################### - # This file is part of SWIFT. - # Copyright (c) 2016 Matthieu Schaller (matthieu.schaller@durham.ac.uk) - # - # This program is free software: you can redistribute it and/or modify - # it under the terms of the GNU Lesser General Public License as published - # by the Free Software Foundation, either version 3 of the License, or - # (at your option) any later version. - # - # This program is distributed in the hope that it will be useful, - # but WITHOUT ANY WARRANTY; without even the implied warranty of - # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - # GNU General Public License for more details. - # - # You should have received a copy of the GNU Lesser General Public License - # along with this program. If not, see <http://www.gnu.org/licenses/>. - # - ############################################################################## - -import h5py -from numpy import * - -# Generates a swift IC file for the Sedov blast test in a periodic cubic box - -# Parameters -gamma = 5./3. # Gas adiabatic index -rho0 = 1. # Background density -P0 = 1.e-6 # Background pressure -E0= 1. # Energy of the explosion -N_inject = 15 # Number of particles in which to inject energy -fileName = "SN_feedback.hdf5" - -#--------------------------------------------------- -glass = h5py.File("glassCube_64.hdf5", "r") - -# Read particle positions and h from the glass -pos = glass["/PartType0/Coordinates"][:,:] -eps = 1e-6 -pos = (pos - pos.min()) / (pos.max() - pos.min() + eps) -h = glass["/PartType0/SmoothingLength"][:] * 0.3 * 3.3 - -numPart = size(h) -vol = 1. -Boxsize = 1. - -# Generate extra arrays -v = zeros((numPart, 3)) -ids = linspace(1, numPart, numPart) -m = zeros(numPart) -u = zeros(numPart) -r = zeros(numPart) - -r = sqrt((pos[:,0] - 0.5)**2 + (pos[:,1] - 0.5)**2 + (pos[:,2] - 0.5)**2) -m[:] = rho0 * vol / numPart -u[:] = P0 / (rho0 * (gamma - 1)) - -#-------------------------------------------------- - -star_pos = zeros((1, 3)) -star_pos[:,:] = 0.5 * Boxsize - -star_v = zeros((1, 3)) -star_v[:,:] = 0. - -# increase mass to keep it at center -star_m = 1e3 * array([rho0 * vol / numPart]) -star_ids = array([numPart + 1]) -star_h = array([h.max()]) - -#-------------------------------------------------- - -#File -file = h5py.File(fileName, 'w') - -# Header -grp = file.create_group("/Header") -grp.attrs["BoxSize"] = [Boxsize]*3 -grp.attrs["NumPart_Total"] = [numPart, 0, 0, 0, 1, 0] -grp.attrs["NumPart_Total_HighWord"] = [0, 0, 0, 0, 0, 0] -grp.attrs["NumPart_ThisFile"] = [numPart, 0, 0, 0, 1, 0] -grp.attrs["Time"] = 0.0 -grp.attrs["NumFilesPerSnapshot"] = 1 -grp.attrs["MassTable"] = [0.0, 0.0, 0.0, 0.0, 0.0, 0.0] -grp.attrs["Flag_Entropy_ICs"] = 0 -grp.attrs["Dimension"] = 3 - -#Runtime parameters -grp = file.create_group("/RuntimePars") -grp.attrs["PeriodicBoundariesOn"] = 0 - -#Units -grp = file.create_group("/Units") -grp.attrs["Unit length in cgs (U_L)"] = 1. -grp.attrs["Unit mass in cgs (U_M)"] = 1. -grp.attrs["Unit time in cgs (U_t)"] = 1. -grp.attrs["Unit current in cgs (U_I)"] = 1. -grp.attrs["Unit temperature in cgs (U_T)"] = 1. - -#Particle group -grp = file.create_group("/PartType0") -grp.create_dataset('Coordinates', data=pos, dtype='d') -grp.create_dataset('Velocities', data=v, dtype='f') -grp.create_dataset('Masses', data=m, dtype='f') -grp.create_dataset('SmoothingLength', data=h, dtype='f') -grp.create_dataset('InternalEnergy', data=u, dtype='f') -grp.create_dataset('ParticleIDs', data=ids, dtype='L') - -# stellar group -grp = file.create_group("/PartType4") -grp.create_dataset("Coordinates", data=star_pos, dtype="d") -grp.create_dataset('Velocities', data=star_v, dtype='f') -grp.create_dataset('Masses', data=star_m, dtype='f') -grp.create_dataset('SmoothingLength', data=star_h, dtype='f') -grp.create_dataset('ParticleIDs', data=star_ids, dtype='L') - - -file.close() diff --git a/examples/SubgridTests/SupernovaeFeedback/run.sh b/examples/SubgridTests/SupernovaeFeedback/run.sh deleted file mode 100644 index af8802164c528fe14b3d525827107868a8ac5720..0000000000000000000000000000000000000000 --- a/examples/SubgridTests/SupernovaeFeedback/run.sh +++ /dev/null @@ -1,19 +0,0 @@ -#!/bin/bash - - # Generate the initial conditions if they are not present. -if [ ! -e glassCube_64.hdf5 ] -then - echo "Fetching initial glass file for the Supernovae feedback example..." - ./getGlass.sh -fi -if [ ! -e SN_feedback.hdf5 ] -then - echo "Generating initial conditions for the Supernovae feedback example..." - python makeIC.py -fi - -# Run SWIFT -../../swift --external-gravity --feedback --hydro --stars --threads=4 SN_feedback.yml 2>&1 | tee output.log - -# Plot the solution -# TODO diff --git a/examples/main.c b/examples/main.c index 8429838cf5c78c70bc65f19c6b1c963a544c9166..9a61f0bae1271f7a34d770a4b6868c2721e9db93 100644 --- a/examples/main.c +++ b/examples/main.c @@ -163,11 +163,13 @@ int main(int argc, char *argv[]) { int with_star_formation = 0; int with_feedback = 0; int with_black_holes = 0; - int with_limiter = 0; + int with_timestep_limiter = 0; + int with_timestep_sync = 0; int with_fp_exceptions = 0; int with_drift_all = 0; int with_mpole_reconstruction = 0; int with_structure_finding = 0; + int with_eagle = 0; int verbose = 0; int nr_threads = 1; int with_verbose_timers = 0; @@ -219,9 +221,21 @@ int main(int argc, char *argv[]) { NULL, 0, 0), OPT_BOOLEAN('x', "velociraptor", &with_structure_finding, "Run with structure finding.", NULL, 0, 0), - OPT_BOOLEAN(0, "limiter", &with_limiter, "Run with time-step limiter.", + OPT_BOOLEAN(0, "limiter", &with_timestep_limiter, + "Run with time-step limiter.", NULL, 0, 0), + OPT_BOOLEAN(0, "sync", &with_timestep_sync, + "Run with time-step synchronization of particles hit by " + "feedback events.", NULL, 0, 0), + OPT_GROUP(" Simulation meta-options:\n"), + OPT_BOOLEAN( + 0, "eagle", &with_eagle, + "Run with all the options needed for the EAGLE model. This is " + "equivalent to --hydro --limiter --sync --self-gravity --stars " + "--star-formation --cooling --feedback --black-holes --fof.", + NULL, 0, 0), + OPT_GROUP(" Control options:\n"), OPT_BOOLEAN('a', "pin", &with_aff, "Pin runners using processor affinity.", NULL, 0, 0), @@ -279,6 +293,20 @@ int main(int argc, char *argv[]) { "example of parameter file."); int nargs = argparse_parse(&argparse, argc, (const char **)argv); + /* Deal with meta options */ + if (with_eagle) { + with_hydro = 1; + with_timestep_limiter = 1; + with_timestep_sync = 1; + with_self_gravity = 1; + with_stars = 1; + with_star_formation = 1; + with_cooling = 1; + with_feedback = 1; + with_black_holes = 1; + with_fof = 1; + } + /* Write output parameter file */ if (myrank == 0 && output_parameters_filename != NULL) { io_write_output_field_parameter(output_parameters_filename); @@ -555,7 +583,6 @@ int main(int argc, char *argv[]) { #ifdef WITH_MPI if (with_mpole_reconstruction && nr_nodes > 1) error("Cannot reconstruct m-poles every step over MPI (yet)."); - if (with_limiter) error("Can't run with time-step limiter over MPI (yet)"); #ifdef WITH_LOGGER error("Can't run with the particle logger over MPI (yet)"); #endif @@ -827,9 +854,9 @@ int main(int argc, char *argv[]) { /* Initialise the cooling function properties */ #ifdef COOLING_NONE - if (with_cooling || with_temperature) { + if (with_cooling) { error( - "ERROR: Running with cooling / temperature calculation" + "ERROR: Running with cooling calculation" " but compiled without it."); } #else @@ -1005,9 +1032,9 @@ int main(int argc, char *argv[]) { bzero(&gravity_properties, sizeof(struct gravity_props)); if (with_self_gravity) gravity_props_init(&gravity_properties, params, &prog_const, &cosmo, - with_cosmology, with_baryon_particles, - with_DM_particles, with_DM_background_particles, - periodic); + with_cosmology, with_external_gravity, + with_baryon_particles, with_DM_particles, + with_DM_background_particles, periodic); /* Initialise the external potential properties */ bzero(&potential, sizeof(struct external_potential)); @@ -1105,7 +1132,9 @@ int main(int argc, char *argv[]) { engine_policies |= engine_policy_external_gravity; if (with_cosmology) engine_policies |= engine_policy_cosmology; if (with_temperature) engine_policies |= engine_policy_temperature; - if (with_limiter) engine_policies |= engine_policy_limiter; + if (with_timestep_limiter) + engine_policies |= engine_policy_timestep_limiter; + if (with_timestep_sync) engine_policies |= engine_policy_timestep_sync; if (with_cooling) engine_policies |= engine_policy_cooling; if (with_stars) engine_policies |= engine_policy_stars; if (with_star_formation) engine_policies |= engine_policy_star_formation; @@ -1187,8 +1216,11 @@ int main(int argc, char *argv[]) { logger_log_all(e.logger, &e); engine_dump_index(&e); #endif - engine_dump_snapshot(&e); - engine_print_stats(&e); + /* Dump initial state snapshot, if not working with an output list */ + if (!e.output_list_snapshots) engine_dump_snapshot(&e); + + /* Dump initial state statistics, if not working with an output list */ + if (!e.output_list_stats) engine_print_stats(&e); /* Is there a dump before the end of the first time-step? */ engine_check_for_dumps(&e); @@ -1374,23 +1406,43 @@ int main(int argc, char *argv[]) { engine_current_step = e.step; engine_drift_all(&e, /*drift_mpole=*/0); - engine_print_stats(&e); + + /* Write final statistics? */ + if (e.output_list_stats) { + if (e.output_list_stats->final_step_dump) engine_print_stats(&e); + } else { + engine_print_stats(&e); + } #ifdef WITH_LOGGER logger_log_all(e.logger, &e); - engine_dump_index(&e); + + /* Write a sentinel timestamp */ + logger_log_timestamp(e.logger, e.ti_current, e.time, + &e.logger->timestamp_offset); #endif + /* Write final snapshot? */ + if ((e.output_list_snapshots && e.output_list_snapshots->final_step_dump) || + !e.output_list_snapshots) { #ifdef HAVE_VELOCIRAPTOR - if (with_structure_finding && e.snapshot_invoke_stf) - velociraptor_invoke(&e, /*linked_with_snap=*/1); + if (with_structure_finding && e.snapshot_invoke_stf && + !e.stf_this_timestep) + velociraptor_invoke(&e, /*linked_with_snap=*/1); #endif + engine_dump_snapshot(&e); +#ifdef HAVE_VELOCIRAPTOR + if (with_structure_finding && e.snapshot_invoke_stf && + e.s->gpart_group_data) + swift_free("gpart_group_data", e.s->gpart_group_data); +#endif + } - /* write a final snapshot */ - engine_dump_snapshot(&e); - + /* Write final stf? */ #ifdef HAVE_VELOCIRAPTOR - if (with_structure_finding && e.snapshot_invoke_stf) - free(e.s->gpart_group_data); + if (with_structure_finding && e.output_list_stf) { + if (e.output_list_stf->final_step_dump && !e.stf_this_timestep) + velociraptor_invoke(&e, /*linked_with_snap=*/0); + } #endif } @@ -1411,7 +1463,8 @@ int main(int argc, char *argv[]) { if (with_verbose_timers) timers_close_file(); if (with_cosmology) cosmology_clean(e.cosmology); if (with_self_gravity) pm_mesh_clean(e.mesh); - if (with_cooling || with_temperature) cooling_clean(&cooling_func); + if (with_cooling || with_temperature) cooling_clean(e.cooling_func); + if (with_feedback) feedback_clean(e.feedback_props); engine_clean(&e, /*fof=*/0); free(params); diff --git a/examples/main_fof.c b/examples/main_fof.c index e4b13187435e1eb600cae4ce05e9332650c4fddb..4f12cba5a792cc538c9c096cdd481b92d2613610 100644 --- a/examples/main_fof.c +++ b/examples/main_fof.c @@ -524,8 +524,9 @@ int main(int argc, char *argv[]) { /* Initialise the gravity scheme */ bzero(&gravity_properties, sizeof(struct gravity_props)); gravity_props_init(&gravity_properties, params, &prog_const, &cosmo, - /*with_cosmology=*/1, with_baryon_particles, - with_DM_particles, with_DM_background_particles, periodic); + /*with_cosmology=*/1, /*with_external_gravity=*/0, + with_baryon_particles, with_DM_particles, + with_DM_background_particles, periodic); /* Initialise the long-range gravity mesh */ if (periodic) { diff --git a/examples/nIFTyCluster/Baryonic/data/README b/examples/nIFTyCluster/Baryonic/data/README new file mode 100644 index 0000000000000000000000000000000000000000..9c0ca0b643207cce6b597ffa38e8abcdf85ed8a7 --- /dev/null +++ b/examples/nIFTyCluster/Baryonic/data/README @@ -0,0 +1,3 @@ +Data extracted by hand using WebPlotDigitizer +(https://automeris.io/WebPlotDigitizer/) from the original +nIFTY paper (2016MNRAS.457.4063S). diff --git a/examples/nIFTyCluster/Baryonic/data/S/AREPO.csv b/examples/nIFTyCluster/Baryonic/data/S/AREPO.csv new file mode 100644 index 0000000000000000000000000000000000000000..df0ce396911495debecaa035f4bff93d57c14476 --- /dev/null +++ b/examples/nIFTyCluster/Baryonic/data/S/AREPO.csv @@ -0,0 +1,125 @@ +# R [h^-1 Mpc], S [keV h^-2 cm^2] +0.023656128029452744, 197.30575971432492 +0.024515266555991365, 199.37588425081265 +0.025405607103708764, 201.58458343126222 +0.026328282861369703, 203.7389767794876 +0.02728446817266185, 205.99601058640653 +0.028275380030852074, 208.15731290495506 +0.029302279627725258, 207.75536795372992 +0.030366473958777382, 206.5142643272681 +0.03146931748670533, 205.2805748929248 +0.03261221386531146, 203.9753900048567 +0.03379661772601604, 202.7960607999093 +0.03502403652925248, 201.62355014975722 +0.036296032483100586, 200.7292183648817 +0.037614224531600855, 199.87748278933032 +0.03898029041527962, 199.0678340926805 +0.04039596880650811, 198.26146506016715 +0.04186306152241299, 197.4202006721108 +0.04338343581815498, 196.65851290129496 +0.04495902676349428, 196.6205057493216 +0.04659183970566755, 196.6205057493216 +0.048283952821711475, 196.6205057493216 +0.05003751976348054, 196.6205057493216 +0.05185477239872673, 196.5825059427901 +0.053738023651728514, 196.848658892489 +0.05568967044708582, 197.72570117807027 +0.05771219676042677, 198.60665105019555 +0.05980817677990957, 199.53008804491353 +0.061980278182543105, 200.41907720768307 +0.06423126552949635, 201.3120271852814 +0.06656400378471788, 201.70150618524664 +0.06898146196134392, 201.70150618524664 +0.07148671690053612, 201.70150618524664 +0.07408295718755786, 201.70150618524664 +0.07677348721007463, 201.70150618524664 +0.07956173136384204, 202.32624052608202 +0.08245123841113604, 204.44903975654947 +0.0854456859974711, 206.7538979216158 +0.08854888533235596, 208.92315196529785 +0.09176478604004407, 211.27844907626476 +0.09509748118645256, 213.57772063716527 +0.09855121248864795, 215.19376395107116 +0.10213037571352886, 216.1107666160845 +0.10583952627257691, 216.94779586869444 +0.10968338501979692, 217.87227296936706 +0.11366684426022514, 218.75840307998902 +0.11779497397665378, 219.7330623482146 +0.1220730282824961, 222.59710741005512 +0.12650645210900544, 226.45939705661849 +0.1311008881353594, 230.34417540905585 +0.13586218397042943, 234.3408846843013 +0.1407963995953765, 238.36086534195974 +0.14590981507654527, 242.54354757507133 +0.151208938558474, 247.08600585747973 +0.1567005145471926, 251.7135372224491 +0.1623915324943522, 256.4773029682466 +0.1682892356931108, 261.33122462830795 +0.1744011304970989, 266.3284803330491 +0.18073499587419686, 271.2115312715363 +0.18729889330728464, 275.544272124096 +0.19410117705456523, 279.8380336925424 +0.20115050478252006, 284.52848077671246 +0.2084558485850304, 289.0739666068992 +0.21602650640268864, 293.69206886330807 +0.223872113856834, 297.6351441631316 +0.2320026565133744, 301.048718844887 +0.24042848259200325, 304.560304543979 +0.2491603161369873, 307.99376799051356 +0.2582092706662878, 311.5261456319614 +0.26758686331638887, 315.0381385532608 +0.277305029500834, 317.2992046316687 +0.2873761381011288, 319.32951881256776 +0.2978130072093433, 321.2486163873796 +0.30862892044245194, 323.24171852037404 +0.3198376438491737, 325.3729403946062 +0.33145344343083155, 327.26509653212355 +0.34349110329853155, 329.4865237681474 +0.3559659444897699, 331.53073582017134 +0.36889384446841844, 334.4268849447033 +0.4118970982150999, 342.274238611865 +0.4268562946484919, 347.8766936049769 +0.4423587761861066, 353.6391973657495 +0.4584242737477019, 359.6361523070299 +0.4750732348366332, 365.5934490109371 +0.49232684956459355, 371.9368728289524 +0.5102070776215141, 384.36104047810585 +0.5287366762249531, 399.43287005892876 +0.5479392290845448, 414.05401146476294 +0.5678391764183731, 429.2933233880519 +0.5884618460594737, 445.1795576768337 +0.6464923352317284, 512.9377179157074 +0.6656400378471785, 537.6271269271311 +0.6853548539386427, 563.5049198222947 +0.7056535801788674, 590.9074178880861 +0.7265535107216625, 619.496099038419 +0.7456503246236443, 647.4982856182813 +0.7627713390984185, 679.1227696999097 +0.7790212344563301, 711.3909582635638 +0.79561731363842, 745.720663452266 +0.8125669516608036, 780.8764637272163 +0.8298776806551467, 818.8494521328103 +0.8489326549689583, 860.4094744726675 +0.868425154058486, 905.4528683051662 +0.8883652240107086, 951.6973910993604 +0.9087631415826625, 1000.9116084137623 +0.9311380725083862, 1047.8857698881695 +0.9556122099605342, 1097.772798737779 +0.9807296283843355, 1148.81291023301 +1.0081406503468062, 1205.745836639583 +1.0363177999996016, 1265.50024779824 +1.063556493196812, 1325.7473178370237 +1.0915111312587078, 1387.018261801692 +1.1220184543019642, 1449.7075275386158 +1.170334099757356, 1458.8898287383624 +1.2128380595250574, 1463.1256538320197 +1.256885669602792, 1465.1065788725257 +1.3025329919737914, 1469.3604540380259 +1.3498381246691766, 1469.6444844643904 +1.398861275712749, 1478.7625052349354 +1.4496648397512706, 1492.8342275774417 +1.5023134774678115, 1507.3311686338693 +1.5568741978791918, 1521.6747468677868 +1.6134164436223084, 1536.451758745519 +1.6665984973394812, 1548.4763831466105 + diff --git a/examples/nIFTyCluster/Baryonic/data/S/G2-anarchy.csv b/examples/nIFTyCluster/Baryonic/data/S/G2-anarchy.csv new file mode 100644 index 0000000000000000000000000000000000000000..556547e4fbd7070bc677b488b88978336fa8c836 --- /dev/null +++ b/examples/nIFTyCluster/Baryonic/data/S/G2-anarchy.csv @@ -0,0 +1,132 @@ +# R [h^-1 Mpc], S [keV h^-2 cm^2] +0.021602650640268874, 347.54066206129767 +0.022387211385683413, 333.0078425270195 +0.023200265651337454, 318.4665915532779 +0.024042848259200337, 304.6780602024425 +0.024916031613698732, 291.3738686075044 +0.025820927066628776, 281.0305042268024 +0.026758686331638883, 281.5197964490719 +0.0277305029500834, 283.21166621618903 +0.028737613810112878, 285.18918226754585 +0.029781300720934344, 287.06951326666643 +0.030862892044245194, 288.9622418070897 +0.03198376438491738, 290.9799110614818 +0.03314534434308316, 292.84181500312786 +0.034349110329853175, 295.0005886407969 +0.03559659444897701, 297.00300915307866 +0.036889384446841866, 298.9612319738122 +0.03822912573329066, 299.1346349691304 +0.03961752347583191, 296.658774295449 +0.04105634476990667, 294.14654654760056 +0.0425474208879748, 291.655593371091 +0.04409264961028314, 289.18573460415513 +0.04569399764028186, 287.2360188471269 +0.04735350310776388, 287.06951326666643 +0.04907327816291211, 286.84765595907857 +0.05085551166455757, 286.4598181644131 +0.052702471966068344, 286.4598181644131 +0.05461650980241659, 285.9066736410082 +0.056600061282097, 285.2443099285707 +0.05865565098770536, 283.92418246858807 +0.060785895189123244, 282.6647937677751 +0.06299350517339852, 281.4109912762306 +0.06528129069555988, 280.1086046406557 +0.067652163554757, 279.243697231575 +0.070109141300279, 279.243697231575 +0.07265535107216625, 279.243697231575 +0.07529403358130603, 279.243697231575 +0.0780285472340751, 279.243697231575 +0.0808623724067817, 279.3516644385573 +0.08379911587534444, 279.8380336925424 +0.0868425154058486, 280.3252497467486 +0.08999644451182047, 281.0305042268024 +0.09326491738427596, 281.4109912762306 +0.0966520940008174, 282.22805622177844 +0.10016228542028172, 281.6830830920368 +0.10379995926967846, 280.9218881615315 +0.10756974543040143, 280.00034488227715 +0.11147644193095074, 279.3516644385573 +0.11552502105366615, 278.59676972331647 +0.11972063566324288, 278.65062305731004 +0.12406862576508564, 280.1627502154776 +0.12857452530184735, 281.57421481020026 +0.13324406919680348, 282.93809786528726 +0.13808320065302598, 284.3085872674406 +0.14309807871764735, 286.1278031622636 +0.14829508612084202, 288.79473556606786 +0.1536808373995024, 291.7119710028077 +0.1592621873159487, 294.6017275194088 +0.1650462395823884, 297.5201105359659 +0.17104035590222783, 300.4674036322541 +0.1772521653397455, 303.03361614635133 +0.18368957403005057, 305.4445825443507 +0.19036077524168585, 307.815229514304 +0.19727425980468238, 310.3841999528984 +0.20443882691733817, 312.7931847743365 +0.2118635953454751, 315.0990360795067 +0.21955801502842848, 317.2992046316687 +0.22753187910654032, 319.70006019199053 +0.23579533638546504, 321.93235524217675 +0.244358904253151, 324.117584616376 +0.2532334820659387, 326.6331583531207 +0.262430365020812, 329.23188511906943 +0.27196125853146014, 331.9795951061551 +0.2818382931264455, 334.620858668927 +0.29207403988844066, 337.4135440581907 +0.30268152645418456, 340.16378233113164 +0.31367425359552153, 342.9364376370908 +0.3250662124026278, 345.66487495802886 +0.33687190209129425, 348.54973171715926 +0.34910634845693106, 351.390740411305 +0.3617851229987809, 354.2549060029196 +0.37492436273868185, 357.4877325707256 +0.3885407907596031, 361.1686656291895 +0.40265173749009725, 364.8169801593987 +0.4172751627617544, 368.787159375885 +0.4289378456458218, 373.6662221042858 +0.44959026763494253, 375.98453541775336 +0.4659183970566755, 384.8814266853222 +0.4828395282171145, 392.6204990176873 +0.5003751976348053, 400.36039018631766 +0.518547723987267, 408.48965519198816 +0.537380236517285, 416.9451298453705 +0.5568967044708579, 430.2901822543164 +0.5771219676042677, 445.1795576768337 +0.5980817677990957, 460.5841516881443 +0.6198027818254311, 476.70603555923617 +0.6423126552949634, 493.2968804088424 +0.6634848122245312, 513.5439457556074 +0.6831357952014436, 538.0082814289949 +0.7033687977285311, 563.5049198222947 +0.724201057964169, 589.9310731968759 +0.7456503246236443, 617.7424240172813 +0.7677348721007459, 646.7121019541034 +0.7891927712315969, 676.9603775992875 +0.8086237240678166, 713.3743737236715 +0.827190682368812, 750.7203163463294 +0.8461839600199457, 790.0213606403505 +0.8642108575959873, 828.7746181014514 +0.8826217958198916, 869.0768303282124 +0.9028878374790444, 914.5739698886133 +0.9221227406891038, 959.3883928040095 +0.9417674196056702, 1006.0931089347177 +0.9649549587977603, 1058.5220462361754 +0.9903179430790581, 1112.1619988490186 +1.0163475708816814, 1167.5888402277278 +1.0430613643386564, 1226.4297004385676 +1.070477306136718, 1288.578269992149 +1.0986138516215547, 1353.5164153760545 +1.125663154040737, 1416.7698328364834 +1.159002858386986, 1479.3342562146825 +1.2010952923968496, 1492.5457153919215 +1.2447164310065815, 1496.879258933145 +1.289921793404095, 1501.8058207968631 +1.336768915112072, 1507.039854701129 +1.3853174212167954, 1511.9998573405976 +1.4356291022565106, 1523.1460300009153 +1.4877679928658685, 1536.7487580603745 +1.5418004532765797, 1550.4729677158282 +1.5977952537779734, 1564.3197438804 +1.6558236622449927, 1578.5952679249924 +1.6883589669589307, 1582.8726801377911 + diff --git a/examples/nIFTyCluster/Baryonic/data/S/G3-music.csv b/examples/nIFTyCluster/Baryonic/data/S/G3-music.csv new file mode 100644 index 0000000000000000000000000000000000000000..de958bcf61116f4ad7fc32c7379c031cd0458155 --- /dev/null +++ b/examples/nIFTyCluster/Baryonic/data/S/G3-music.csv @@ -0,0 +1,124 @@ +# R [h^-1 Mpc], S [keV h^-2 cm^2] +0.02532334820659387, 18.658664281116415 +0.0262430365020812, 19.379080441170494 +0.027196125853146014, 20.170150618524662 +0.02818382931264455, 20.993512938294945 +0.029207403988844083, 21.842040552870667 +0.030268152645418454, 22.742440583199127 +0.03136742535955217, 23.657084375555222 +0.03250662124026278, 24.622786230680124 +0.03368719020912944, 25.622955867948182 +0.03491063484569312, 26.6585989108688 +0.036178512299878104, 27.74146260277447 +0.03749243627386818, 28.879473556606786 +0.038854079075960314, 30.03512753592241 +0.040265173749009724, 31.237026683706542 +0.04172751627617544, 32.34917241797587 +0.0432429678667737, 33.526825067636985 +0.04481345732514833, 34.72720705460065 +0.04644098350557375, 35.970567072192644 +0.04812761785631392, 37.26564602440962 +0.04987550705607678, 38.62228001228843 +0.05168687574621804, 40.23774124901132 +0.053564029362173436, 41.96941641753095 +0.05550935706772161, 43.77561611939136 +0.05752533479581356, 45.65072321975329 +0.059614528399838, 47.615351982968264 +0.06177959691933385, 49.66453069205537 +0.06402329596430621, 51.79188656713497 +0.06634848122245313, 54.031249340532085 +0.06875811209376749, 56.35654320402382 +0.07125525545713905, 58.7591898877582 +0.07384308957375194, 61.2524283082932 +0.07652490813224404, 63.826780400584205 +0.07930412444077876, 66.52218522644235 +0.08218427577136243, 69.22429494078924 +0.08516902786193882, 71.980491427036 +0.08826217958198916, 74.84642711795493 +0.09146766776757671, 77.81143021840522 +0.09478957223198951, 80.87825647208776 +0.09823212095835863, 84.08220742115354 +0.10179969548086092, 87.39618739122974 +0.10549683646135512, 90.73549611521734 +0.10932824946854927, 94.16598753972622 +0.11329881096705453, 97.76396261255954 +0.11741357452394861, 101.49941221269262 +0.12167777724074763, 105.37758908514832 +0.1260968464189731, 109.40394667635054 +0.13067640646779777, 113.54024742907998 +0.13542228606256182, 117.8784908934817 +0.14034052556327067, 122.42981184995563 +0.14543738470251644, 127.1077154403787 +0.15071935055260746, 132.21966824345617 +0.1561931457820468, 138.4440317342558 +0.1618657372118677, 144.8493816848817 +0.16774434468271637, 151.6976184449593 +0.1738364502439674, 158.96177569439814 +0.18014980767656838, 166.57378270631526 +0.1866924523617326, 174.5502965343922 +0.19347271150804102, 182.90877186815007 +0.20049921474997057, 191.29739556707423 +0.20778090513133704, 199.26030961825003 +0.215327050487633, 207.67507214858904 +0.22314725524174683, 216.15254127594775 +0.23125147262807652, 225.23712391628064 +0.2396500173605962, 234.6581586827919 +0.24835357876099937, 244.2843113774384 +0.25737323436362647, 252.59079922912176 +0.2667204640144951, 260.3732759394005 +0.2764071644823743, 268.55120983870427 +0.286445664600502, 277.09309465818933 +0.29684874095821584, 285.79617297485805 +0.30762963416246963, 292.89842193394907 +0.31880206568993263, 299.3081385413651 +0.33038025535111926, 305.9763812506314 +0.34237893938877834, 312.7931847743365 +0.35481338923357547, 319.6382734501186 +0.36769943094094104, 326.696297220767 +0.38105346533382145, 333.9747167542396 +0.3948924888769701, 341.3493076134749 +0.4092341153093485, 351.32282897906805 +0.4240965980621671, 363.1987792063031 +0.43949885349110007, 375.47617842052716 +0.4554604849522437, 388.0935777185204 +0.47200180775246064, 401.29006410136617 +0.4891438750058646, 414.8550830379401 +0.5060871986919684, 430.68957364370954 +0.5236174176295533, 450.54649159508483 +0.5417548611260561, 471.2187143235674 +0.5596123933458592, 492.83943138173225 +0.5789966571661932, 516.2198715026071 +0.6000245419615925, 540.9394574810825 +0.620808631374834, 566.3608951034978 +0.6412719643924004, 592.3469781974583 +0.6634848122245312, 619.7888618396709 +0.6864670849437778, 648.0885505033483 +0.7067987530571936, 678.9423068431375 +0.7253763306947708, 711.832241099146 +0.744442203464997, 747.3078397587705 +0.7640092057718629, 784.5514365893058 +0.784090509360272, 823.432275064956 +0.804699632182747, 864.46968700977 +0.8258504474991899, 907.0700188496438 +0.8475571932158205, 952.2756868244468 +0.8698344814695815, 999.7342706432105 +0.892697308464461, 1049.000326262132 +0.9161610645663522, 1101.2793780100944 +0.9402415446632512, 1155.8566353013707 +0.9649549587977603, 1213.4610872136634 +0.9903179430790581, 1273.2594187999182 +1.0213037571352885, 1332.4586472492138 +1.0583952627257696, 1395.1853736668513 +1.0968338501979686, 1460.3004061318138 +1.1366684426022513, 1527.8637024122213 +1.1779497397665373, 1599.4801201741793 +1.220730282824961, 1661.2364875592195 +1.2650645210900537, 1710.4354545219762 +1.3110088813535938, 1760.7511349365304 +1.3586218397042937, 1813.2477517600967 +1.4079639959537649, 1853.286591902295 +1.459098150765452, 1848.635713609354 +1.5120893855847402, 1841.1473988916746 +1.5670051454719254, 1833.689417276887 +1.5977952537779734, 1829.087718681499 + diff --git a/examples/nIFTyCluster/Baryonic/data/kT/AREPO.csv b/examples/nIFTyCluster/Baryonic/data/kT/AREPO.csv new file mode 100644 index 0000000000000000000000000000000000000000..a5c18c1af29a88cfe29ffecb1a27df116aa52d73 --- /dev/null +++ b/examples/nIFTyCluster/Baryonic/data/kT/AREPO.csv @@ -0,0 +1,156 @@ +# R [h^-1 Mpc], kT [keV] +0.023571760518999674, 11.7465160158983 +0.02427417836094951, 11.670187891689121 +0.024997527640086278, 11.593859767479943 +0.02574243209492653, 11.517531643270765 +0.026509534050848896, 11.438772687080402 +0.027299494973966353, 11.360013730890039 +0.028112996041503385, 11.28222710749215 +0.028950738729169836, 11.228262637509863 +0.029813445416038028, 11.200551152924366 +0.03070186000744467, 11.173812001131342 +0.031616748576454703, 11.14512818375337 +0.03255890002444023, 11.117902865564108 +0.03352912676134405, 11.091163713771083 +0.03452826540621455, 11.06296606278935 +0.03555717750861585, 11.021641919109221 +0.03661675029153537, 10.965246617145752 +0.037707897416429347, 10.909337481578518 +0.03883155977106613, 10.854400678803758 +0.03998870628084644, 10.797519210444051 +0.041180334744300266, 10.743554740461766 +0.04240747269348094, 10.686673272102059 +0.043671178279997926, 10.649724625988064 +0.044972541187453106, 10.62590247257246 +0.04631268357106623, 10.602080319156855 +0.047692761025301046, 10.57874433213749 +0.049113963580325215, 10.555408345118122 +0.05057751672816446, 10.532072358098755 +0.05208468247943459, 10.50825020468315 +0.05363676045156391, 10.476163222531522 +0.0552350889894429, 10.43678374443634 +0.056881046319469185, 10.397890432737396 +0.05857605173798106, 10.358510954642215 +0.06032156683510627, 10.319131476547033 +0.062119096755079574, 10.28023816484809 +0.0639701914941172, 10.240858686752908 +0.06587644723696665, 10.197103711091597 +0.06783950773328443, 10.149945570656625 +0.06986106571502887, 10.102787430221653 +0.07194286435608972, 10.055629289786683 +0.07408669877541368, 10.00895731574795 +0.07629441758492166, 9.96179917531298 +0.07856792448355247, 9.91464103487801 +0.08090917989880797, 9.880609387141433 +0.08332020267721445, 9.852411736159699 +0.08580307182515849, 9.823727918781728 +0.08835992830159839, 9.795044101403755 +0.09099297686419607, 9.76684645042202 +0.09370448797046334, 9.738162633044048 +0.0964967997355592, 9.708020316477366 +0.0993723199484293, 9.658431344061214 +0.10233352814802307, 9.604466874078927 +0.10538297776138171, 9.547099239322984 +0.10852329830543826, 9.492162436548224 +0.11175719765443, 9.435767134584754 +0.11508746437487757, 9.379857999017522 +0.11851697013014431, 9.32686586182771 +0.12204867215664957, 9.30401604120458 +0.12568561581387086, 9.290889548506186 +0.12943093721033397, 9.278249222204028 +0.13328786590785513, 9.265608895901874 +0.13725972770636735, 9.25248240320348 +0.14134994751173208, 9.23838357771261 +0.14556205228900923, 9.225743251410455 +0.14989967410373198, 9.205810429164746 +0.15436655325380888, 9.1853914405228 +0.15896654149475398, 9.165944784673327 +0.16370360536102607, 9.146011962427618 +0.16858182958634063, 9.125106807389434 +0.17360542062590442, 9.105660151539963 +0.1787787102836094, 9.08329649731307 +0.18410615944731382, 9.04343085282165 +0.18959236193543158, 9.00064820995281 +0.1952420484581465, 8.957379400687737 +0.20106009069666717, 8.914110591422661 +0.20705150550404033, 8.871327948553823 +0.21322145923114444, 8.828545305684983 +0.2195752721815947, 8.781387165250012 +0.2261184231993994, 8.709434538606965 +0.23285655439332514, 8.633106414397785 +0.23979547600204393, 8.557264456584845 +0.24694117140425711, 8.481422498771902 +0.2542998022781169, 8.40558054095896 +0.26187771391439385, 8.32973858314602 +0.2696814406879725, 8.250493460559419 +0.27771771169239234, 8.161525010048084 +0.2859934565422934, 8.069639561159327 +0.29451581134876986, 7.976781779478097 +0.30329212487278334, 7.885868663381814 +0.3123299648619433, 7.793497048096819 +0.3216371245761173, 7.702583932000536 +0.33122162950749906, 7.609239983923071 +0.3410917443009288, 7.510548205486998 +0.3512559798804326, 7.412342593447162 +0.3617231007881269, 7.313164648614854 +0.3725021327418156, 7.214472870178782 +0.38360237041779705, 7.114808758950237 +0.3950333854655921, 7.016603146910402 +0.4068050347615034, 6.922773032436698 +0.4189274689081246, 6.847903407416229 +0.43141114098712613, 6.78227094392426 +0.4426391366046959, 6.7266656623546766 +0.45921856937733685, 6.594173165220239 +0.47239819753814777, 6.532381416258541 +0.48647525055199764, 6.466262786370336 +0.5009717874304928, 6.408408985218156 +0.5145249837853954, 6.374971540854757 +0.5427412930601848, 6.3510413504622125 +0.5589145087816455, 6.313120371555742 +0.5755696721826314, 6.2873535525551905 +0.5927211448823655, 6.261100567158403 +0.6103837164637591, 6.245543242478826 +0.6285726172263562, 6.272282394271851 +0.6473035313193026, 6.3019385444422955 +0.6665926102656677, 6.33159469461274 +0.6864564868897791, 6.3636816767643705 +0.7069122896595774, 6.393337826934815 +0.7279776574563634, 6.422993977105261 +0.7496707547846697, 6.475499947898836 +0.7709805600530688, 6.589894900933356 +0.7918385228733045, 6.705408036679222 +0.8132607730900733, 6.819851606353366 +0.8352625768282906, 6.935899525135092 +0.8578596132197389, 7.0530170099885385 +0.8810679855764783, 7.167460579662683 +0.9061128297044159, 7.286425496821829 +0.9331141993259596, 7.294204159161619 +0.9609201861403502, 7.235378025216965 +0.9895547670360233, 7.176551891272312 +1.0190426333917137, 7.1177257573276576 +1.0494092123676415, 7.058899623383004 +1.0777997314921062, 7.0083923366628476 +1.117562184309672, 6.887005076142133 +1.138424224089001, 6.752290682822991 +1.152694677254384, 6.622160144096938 +1.1676633986322162, 6.490692647781236 +1.1842557462550283, 6.341526379564435 +1.199253144232993, 6.203246766006224 +1.2182543524937854, 6.041029245128543 +1.235932118693666, 5.892308629441626 +1.2515839455194286, 5.755365973473065 +1.2684010212049035, 5.614985426559686 +1.2884978223498615, 5.4527679056820055 +1.3071948729336986, 5.304047289995088 +1.3237491702686597, 5.165767676436877 +1.3446730633428137, 5.0093436384476835 +1.3636506832733684, 4.85626199443262 +1.392620482339304, 4.727839790404454 +1.4283884082969245, 4.611197668249551 +1.4670317591890156, 4.490871485180941 +1.5047108569802587, 4.3760713934828885 +1.5412991303654127, 4.263172752579008 +1.5787770774995773, 4.150274111675127 +1.610703903524253, 4.051636351727526 +1.6765075331554564, 3.8782775176027524 + diff --git a/examples/nIFTyCluster/Baryonic/data/kT/G2-anarchy.csv b/examples/nIFTyCluster/Baryonic/data/kT/G2-anarchy.csv new file mode 100644 index 0000000000000000000000000000000000000000..c65e0a1356865586472d6a7142f317c7344d864a --- /dev/null +++ b/examples/nIFTyCluster/Baryonic/data/kT/G2-anarchy.csv @@ -0,0 +1,162 @@ +# R [h^-1 Mpc], kT [keV] +0.02164182018928114, 13.29349748872382 +0.022286727497794135, 13.240505351534008 +0.02295085247991018, 13.182165383985591 +0.023634767805490255, 13.123825416437175 +0.02433906320945621, 13.069860946454888 +0.02506434600031464, 13.011034812510236 +0.02581124158383433, 12.958042675320424 +0.02658039400232886, 12.932762022716108 +0.027372466490009312, 12.91137070128169 +0.028188142044886032, 12.88997937984727 +0.029028124017712563, 12.869074224809088 +0.029893136718479593, 12.847682903374668 +0.03078392604098186, 12.826291581940248 +0.031701260105996665, 12.803441761317119 +0.03264592992362848, 12.780105774297752 +0.033618750075390884, 12.756769787278385 +0.03462055941661393, 12.732947633862782 +0.035652221799782655, 12.709125480447177 +0.03671462681943038, 12.685789493427812 +0.03780869057922936, 12.65564717686113 +0.03893535648193969, 12.59925187489766 +0.04009559604289855, 12.540425740953006 +0.041290409727750096, 12.481599607008352 +0.042520827815139585, 12.4227734730637 +0.04378791128511442, 12.363947339119045 +0.04509275273399938, 12.304635038778155 +0.04643647731653373, 12.241919573663607 +0.047820243716083746, 12.181634940530241 +0.04924524514376632, 12.118433309019458 +0.05071271036734574, 12.057662509489857 +0.05222390477079071, 11.995433210771544 +0.053780131445405194, 11.934176244845707 +0.05538273231347402, 11.875350110901053 +0.057033089285392136, 11.83013663605103 +0.05873262545127529, 11.786381660389718 +0.06048280630807974, 11.742626684728405 +0.062285141023288935, 11.698385542670856 +0.06414118373625706, 11.65511673340578 +0.06605253489833143, 11.610875591348229 +0.06802084265290938, 11.562745118120786 +0.0700478042566196, 11.511697646515922 +0.0721351675428535, 11.460650174911057 +0.07428473242890858, 11.409602703306192 +0.0764983524680429, 11.358069065305092 +0.0787779364477804, 11.307507760096463 +0.08112545003584301, 11.255487955699124 +0.08354291747513143, 11.195689488961996 +0.08603242332921363, 11.13443252303616 +0.08859611427982851, 11.075120222695269 +0.09123620097795254, 11.016294088750616 +0.09395495995002759, 10.957467954805962 +0.0967547355609916, 10.898155654465072 +0.09963794203580698, 10.830092358991918 +0.10260706554122782, 10.761542897122528 +0.10566466632960254, 10.69104876966819 +0.10881338094655969, 10.622499307798801 +0.11205592450448101, 10.552005180344464 +0.11539509302372193, 10.4824833856826 +0.11883376584359842, 10.417823254983105 +0.12237490810521909, 10.36531728418953 +0.12602157330830355, 10.312811313395954 +0.12977690594419172, 10.26030534260238 +0.13364414420731457, 10.20877170460128 +0.1376266227874642, 10.15675190020394 +0.14172777574527118, 10.10521826220284 +0.1459511394733686, 10.059518620956577 +0.15030035574579625, 10.017708310880213 +0.1547791748582744, 9.97541183440761 +0.15939145886205475, 9.933115357935009 +0.16414118489413773, 9.891305047858644 +0.16903244860672698, 9.848522404989804 +0.1740694676988787, 9.798447266177412 +0.1792565855533914, 9.731842469892971 +0.184598274982071, 9.66475150721229 +0.19009914208260223, 9.597174378135374 +0.19576393021035132, 9.528624916265985 +0.20159752406852474, 9.461533953585306 +0.2076049539202111, 9.39395682450839 +0.21379139992593846, 9.317142533902974 +0.22016219661048675, 9.23546657933519 +0.2267228374628075, 9.156707623144827 +0.2334789796730171, 9.075031668577044 +0.24043644901054825, 8.99627271238668 +0.2476012448476661, 8.914596757818899 +0.2549795453326809, 8.830976137666166 +0.26257771271731756, 8.741035354362356 +0.27040229884283645, 8.649636071869839 +0.2784600507896357, 8.55969528856603 +0.28675791669520684, 8.468782172469746 +0.29530305174545984, 8.378355222769699 +0.3041028243445854, 8.285983607484706 +0.3131648224687728, 8.184374830671214 +0.3224968602092636, 8.079362889084063 +0.3321069845103821, 7.973864781100675 +0.34200348210835385, 7.868366673117288 +0.35219488667689436, 7.763840897926374 +0.3626899861857299, 7.658342789942987 +0.3734978304783972, 7.550413849978416 +0.38462773907585274, 7.433247748485345 +0.3960893092126244, 7.315595480596039 +0.40789242411243315, 7.202318710272862 +0.42004726151042043, 7.09001427274216 +0.43256430242933114, 6.973334337645326 +0.4454543402172187, 6.859085234529678 +0.458728489854466, 6.766227452848446 +0.47239819753814777, 6.678717501525821 +0.48647525055199764, 6.591207550203196 +0.5009717874304928, 6.511962427616597 +0.5117853240522606, 6.458873057147537 +0.5284448457610844, 6.326733030650372 +0.544192039860134, 6.262559066347114 +0.560408486567062, 6.211511594742248 +0.577108169199062, 6.161436455929858 +0.5943054877639471, 6.115736814683599 +0.6120152713771655, 6.0783020021733645 +0.6302527910488327, 6.034060860115813 +0.6490337728518059, 5.990305884454502 +0.6683744114821556, 5.996139881209343 +0.686227468931639, 6.008719436711971 +0.7088018653288362, 6.050104351191628 +0.72992354082749, 6.065175509474971 +0.7516746237779194, 6.087052997305626 +0.7740738699715566, 6.111361317117467 +0.7971405941060102, 6.164839620703516 +0.8208946864399801, 6.277630224630455 +0.8453566299444747, 6.387989996576209 +0.8705475179651194, 6.502725266088097 +0.8964890724107856, 6.615029703618799 +0.923203662484226, 6.727334141149502 +0.9507143239708659, 6.835749247510309 +0.9790447791023836, 6.873184060020543 +1.0082194570122083, 6.893116882266252 +1.0382635148005739, 6.912563538115725 +1.066352500322889, 6.934116915015558 +1.0995955410507865, 6.938573440314395 +1.1369057642766107, 6.971875838456615 +1.1610031825856024, 6.900756639921402 +1.1723482700279304, 6.779475487145898 +1.1892339231617177, 6.659340298018668 +1.2040647592568248, 6.474649156705421 +1.216990323399776, 6.358333846405765 +1.2327939784612199, 6.210377206484363 +1.2465824370294991, 6.079578188963486 +1.2599644259345197, 5.957915048305225 +1.2734900697008127, 5.83692038644179 +1.287160910454834, 5.7139202881938775 +1.3009785068776827, 5.592257147535616 +1.3149444343828007, 5.471930964467006 +1.329060285295607, 5.348930866219094 +1.3433276690350335, 5.227267725560832 +1.3577482122970341, 5.106273063697397 +1.3723235592400478, 4.98260448665466 +1.3884960391215562, 4.8573761257573285 +1.418887678883871, 4.734376027509416 +1.4533890916018033, 4.61612955624693 +1.4887294343472832, 4.498477288357623 +1.5249291063890833, 4.380230817095137 +1.5620090030208615, 4.263172752579008 +1.5957251562683945, 4.147387981005405 +1.6520730623808917, 3.9976487309644675 +1.6809888357022051, 3.909027542164729 diff --git a/examples/nIFTyCluster/Baryonic/data/kT/G3-music.csv b/examples/nIFTyCluster/Baryonic/data/kT/G3-music.csv new file mode 100644 index 0000000000000000000000000000000000000000..c3cdead7c08418c3c21f9f74ce7e8cb759742aec --- /dev/null +++ b/examples/nIFTyCluster/Baryonic/data/kT/G3-music.csv @@ -0,0 +1,166 @@ +# R [h^-1 Mpc], kT [keV] +0.020903674110940202, 4.081130446432558 +0.02152658531207827, 4.109328097414295 +0.02216805872206269, 4.138984247584739 +0.022828647478478115, 4.167668064962712 +0.023508921201925326, 4.196351882340684 +0.024209466487200678, 4.225521866114892 +0.02493088740911227, 4.255664182681572 +0.02567380604336903, 4.2872649984369655 +0.026438863002991773, 4.326158310135911 +0.027226717990708957, 4.365537788231091 +0.02803805036781311, 4.402486434345089 +0.028873559739969072, 4.4423520788365085 +0.029733966560478328, 4.481245390535452 +0.030620012751520577, 4.518680203045687 +0.0315324623439073, 4.5580596811408665 +0.03247210213589987, 4.596952992839812 +0.03343974237165944, 4.636332470934994 +0.034436217439914374, 4.673767283445228 +0.035462386593447165, 4.712660595144172 +0.03651913469002152, 4.752040073239355 +0.03760737295538841, 4.789474885749588 +0.038728039769028985, 4.831285195825954 +0.03988210147331202, 4.882332667430818 +0.04107055320676348, 4.934838638224393 +0.0422944197621668, 4.987830775414205 +0.04355475647023386, 5.04033674620778 +0.0448526501096085, 5.092842717001355 +0.04618921984398736, 5.145834854191168 +0.0475656181871662, 5.20660565372077 +0.04885244946031935, 5.317883739970526 +0.05004033666675292, 5.4289997707548725 +0.05125710832075868, 5.5424926150319305 +0.05250346677126926, 5.654202849189456 +0.053780131445405194, 5.768289896839693 +0.05508783926374505, 5.880000130997217 +0.05650270984832897, 5.999494429343377 +0.05795391982828354, 6.117681480268546 +0.059521794256896896, 6.230472084195485 +0.06129549165371255, 6.338401024160056 +0.063122043681252, 6.446329964124628 +0.06500302536127163, 6.553772737692961 +0.06694005864979798, 6.661215511261297 +0.06893481383572848, 6.769144451225866 +0.07098901098110824, 6.876587224794202 +0.07310442140432678, 6.959235512154459 +0.07528286920751173, 6.9859746639474825 +0.07752623284943862, 7.012713815740508 +0.0798364467653109, 7.037508301948584 +0.08221550303480891, 7.0623027881566625 +0.08466545309984463, 7.088555773553449 +0.08718840953350437, 7.113350259761527 +0.08978654786170424, 7.131824582818526 +0.09246210843912943, 7.120156589308842 +0.09521739838107475, 7.108488595799159 +0.09805479355285251, 7.095848269497002 +0.10097674061848276, 7.0836941095910815 +0.10398575915043295, 7.07153994968516 +0.10708444380222581, 7.057927290590531 +0.11027546654578914, 7.04723162987332 +0.11356157897547672, 7.037508301948584 +0.11694561468074673, 7.0302158060050335 +0.12043049168954437, 7.0238956428539545 +0.12401921498449475, 7.016116980514164 +0.12771487909407636, 7.0068798189856665 +0.13152067076100907, 7.0005596558345875 +0.13543987169015806, 6.994725659079746 +0.1394758613783224, 6.994725659079746 +0.14363212002834927, 6.9981288238534045 +0.14791223155008607, 7.005421319796955 +0.15231988665075832, 7.005421319796955 +0.15685888601743814, 7.011741482948034 +0.16153314359434728, 7.016116980514164 +0.16634668995782134, 7.018061646099111 +0.17130367579184458, 7.031674305193743 +0.17640837546715274, 7.046259297080848 +0.1816651907269902, 7.062788954552898 +0.18707865448269914, 7.076887780043766 +0.19265343472241417, 7.093903603912054 +0.19839433853623256, 7.108488595799159 +0.2043063162613311, 7.1240459204787365 +0.21039446575060364, 7.136686246780893 +0.2166640367685005, 7.148354240290577 +0.22312043551785982, 7.160022233800261 +0.2297692293016349, 7.171204060913706 +0.23661615132353644, 7.182385888027153 +0.24366710563173016, 7.194053881536837 +0.250928172209852, 7.2052357086502825 +0.25840561221973113, 7.206694207838994 +0.2661058734003419, 7.19502621432931 +0.2740355956276391, 7.1843305536121 +0.28220161664007254, 7.173634892894891 +0.2906109779347156, 7.162939232177681 +0.2992709308390943, 7.151757405064234 +0.30818894276395126, 7.140575577950788 +0.3173727036423364, 7.1240459204787365 +0.3268301325605771, 7.0963344358932385 +0.3365693845868452, 7.06862295130774 +0.34659885780321, 7.040425300326005 +0.3569272005472392, 7.012713815740508 +0.36756331886939425, 6.985002331155011 +0.378516384212649, 6.956804680173276 +0.3897958413209542, 6.923259198832936 +0.4014114163833679, 6.870753228039359 +0.4133731254208731, 6.817761090849547 +0.4256912829231158, 6.764768953659736 +0.4383765107425098, 6.710804483677451 +0.4514397472533784, 6.658298512883874 +0.46489225678403046, 6.604820209297825 +0.47874563932990405, 6.550855739315541 +0.493011840556153, 6.496405102937018 +0.5077031620983022, 6.440495967369785 +0.5228322721698535, 6.385072998198789 +0.5384122164859879, 6.330622361820266 +0.5544564295127864, 6.274227059856797 +0.5709787460516657, 6.219290257082038 +0.5879934131690222, 6.167270452684699 +0.6055151024813665, 6.1381004689104905 +0.6235589228065459, 6.114278315494888 +0.6421404331919619, 6.089483829286811 +0.6612756563310167, 6.066147842267442 +0.680981092379359, 6.042325688851841 +0.7012737331828403, 6.018503535436237 +0.7221710769294537, 5.996626047605579 +0.7436911432378863, 6.017045036247527 +0.7658524886956978, 6.051562850380341 +0.788674222860523, 6.086080664513153 +0.8121760247380967, 6.120112312249729 +0.8363781597513082, 6.15511629277878 +0.8613014972149204, 6.189147940515355 +0.8869675283310184, 6.22512425383688 +0.9133983847207084, 6.307286374800901 +0.9406168575080436, 6.415215314765472 +0.9686464169726356, 6.524602753918753 +0.9975112327878959, 6.633504026675798 +1.0272361948623585, 6.741432966640369 +1.0578469348020576, 6.850334239397414 +1.0893698480124634, 6.959235512154459 +1.1173491148395036, 6.946595185852301 +1.1414672306212095, 6.8195842148354355 +1.1645505564461764, 6.703650892418537 +1.188100684923771, 6.584948157851647 +1.21212705597258, 6.468346356639923 +1.2366393004099834, 6.350312100867857 +1.2616472438126052, 6.233041820861308 +1.287160910454834, 6.1156760438840685 +1.313190527326989, 5.997737285082694 +1.3379595395016624, 5.889252726379565 +1.3613774715763878, 5.7763116423776015 +1.381512499983937, 5.647072408711315 +1.4000753781319284, 5.515515781889636 +1.418887678883871, 5.385028721139676 +1.437952753640063, 5.25668079253316 +1.4572739988323442, 5.12512416571148 +1.4768548565291624, 4.994637104961521 +1.4966988150487839, 4.865219610283281 +1.5168094095807325, 4.734732549533325 +1.5371902228155758, 4.604245488783365 +1.557844885583188, 4.4748279941051265 +1.5787770774995773, 4.343271367283446 +1.5999905276224007, 4.212784306533488 +1.6214890151153045, 4.084436377926972 +1.6432763699211743, 3.9539493171770115 +1.6653564734444324, 3.8245318224987717 +1.683233976919969, 3.7557230718847237 + diff --git a/examples/nIFTyCluster/Baryonic/data/rho_gas/AREPO.csv b/examples/nIFTyCluster/Baryonic/data/rho_gas/AREPO.csv new file mode 100644 index 0000000000000000000000000000000000000000..22d672ecd52c751a9c0d067468a7badd1d5f8a3f --- /dev/null +++ b/examples/nIFTyCluster/Baryonic/data/rho_gas/AREPO.csv @@ -0,0 +1,23 @@ +# R [h^-1 Mpc], rho_gas [h^-1 M_sun / (h^-3 Mpc)] +0.023312761045735087, 414774859727881.75 +0.028487568396294648, 352196519257984.7 +0.03490810225182011, 362003337896150.25 +0.04289496203552197, 356625573505578.2 +0.0525626371473216, 349464183288065.1 +0.06440921480692889, 324751663967946.1 +0.07914583279120943, 306632450201933.8 +0.09698373639500778, 271662379125504.47 +0.11884195027613696, 245842790067854.7 +0.1460326003558813, 209867603150716.38 +0.1789454569939827, 175392559947453.8 +0.21927621983549578, 145805123054012.47 +0.2694459027673423, 119931061606351 +0.3301736741546455, 101299135078543.39 +0.4045882827875415, 83321879761281.28 +0.497156760484846, 64308470986871.266 +0.6092060504695779, 44400170658160.59 +0.7465090318128236, 28309935701134.95 +0.9173078601577587, 17485329232128.578 +1.1240508889116114, 9358175624139.916 +1.3773897027827604, 5281411942909.416 +1.692531968159478, 3551005408166.5728 diff --git a/examples/nIFTyCluster/Baryonic/data/rho_gas/G2-anarchy.csv b/examples/nIFTyCluster/Baryonic/data/rho_gas/G2-anarchy.csv new file mode 100644 index 0000000000000000000000000000000000000000..0ad47d801a362d5ed24561140b99694e50cf5438 --- /dev/null +++ b/examples/nIFTyCluster/Baryonic/data/rho_gas/G2-anarchy.csv @@ -0,0 +1,25 @@ +# R [h^-1 Mpc], rho_gas [h^-1 M_sun / (h^-3 Mpc)] +0.021265069263568432, 205248241157412.56 +0.025689253667398475, 279951177802765.8 +0.031096170782104932, 262213161039334.62 +0.03759904152539372, 242507132183911.8 +0.045565623088149126, 248730378356210.84 +0.05509543653517412, 237942094300786.47 +0.06662006300083274, 237942094300786.47 +0.08055330322008279, 227621734885809.84 +0.0976156810924936, 211853106934796.5 +0.11816310190645761, 203952186463605.72 +0.14271386896315075, 186249981347129.06 +0.17255396600592612, 164781600577166.25 +0.20840096804172273, 144867217091572.5 +0.2528138864464032, 125756186881544.06 +0.306006737917123, 106434956941906.14 +0.3695637764571211, 87643129424068.7 +0.446806108699688, 69038907938108.26 +0.5401777052056586, 51805795482555.76 +0.6544909940291803, 36565289809315.08 +0.7912059173500027, 24173073924405.37 +0.9575115804830386, 15126973937525.086 +1.156169751748322, 9017385448022.969 +1.4022111788977407, 5056097601455.426 +1.6951278026832943, 3385169867783.922 diff --git a/examples/nIFTyCluster/Baryonic/data/rho_gas/G3-music.csv b/examples/nIFTyCluster/Baryonic/data/rho_gas/G3-music.csv new file mode 100644 index 0000000000000000000000000000000000000000..0c20e3fe79174d39ec03068e98b2cf5484b015de --- /dev/null +++ b/examples/nIFTyCluster/Baryonic/data/rho_gas/G3-music.csv @@ -0,0 +1,19 @@ +# R [h^-1 Mpc], rho_gas [h^-1 M_sun / (h^-3 Mpc)] +0.025062976570965047, 3182364577568090 +0.03003516263444017, 2687691467446492.5 +0.04012229174855199, 1988943867821441.8 +0.050132679673772766, 1576470405785951.5 +0.0702154833774691, 1043846330375803.4 +0.08025535172618023, 881396497690922.2 +0.10027881421653238, 655518339776614.6 +0.15015566339373532, 376233399587329.8 +0.2005845417821262, 234945830379718.12 +0.24993291720468944, 163955475951628.3 +0.3003516263444014, 124531159006782.27 +0.40010736128087626, 82438195147480.19 +0.5013267967377272, 56622020355333.16 +0.7002025694664931, 29372421531383.96 +1.0027881421653229, 11626065702107.764 +1.2017289667307804, 6701370603962.383 +1.400593062935807, 4116124914936.153 +1.6008590055114547, 3348838975325.094 diff --git a/examples/nIFTyCluster/Baryonic/plotSolution.py b/examples/nIFTyCluster/Baryonic/plotSolution.py new file mode 100644 index 0000000000000000000000000000000000000000..e4200b4d313ea3a9f039ea7fbc8efbeb934b796b --- /dev/null +++ b/examples/nIFTyCluster/Baryonic/plotSolution.py @@ -0,0 +1,409 @@ +""" +NIFTY Cluster Solution + +Josh Borrow (joshua.borrow@durham.ac.uk) +""" + +from swiftsimio import load, SWIFTDataset +from swiftsimio.visualisation.projection import scatter_parallel + +import numpy as np +import matplotlib.pyplot as plt +import scipy.stats as stat + +from matplotlib.colors import LogNorm + +import unyt +import h5py + +try: + plt.style.use("../../../tools/stylesheets/mnras.mplstyle") +except: + pass + +# Global constants +radial_bin_units = unyt.Mpc + +image_bounds = [-2.5, 2.5] * unyt.Mpc +image_cmap = "twilight" +image_res = 1024 +image_textcolor = "black" + +extra_data_directory = "data" +extra_data_schemes = ["G2-anarchy", "AREPO", "G3-music"] +h = 0.7 + +gas_density_units = unyt.Solar_Mass / unyt.Mpc ** 3 + +dm_density_units = gas_density_units + +temperature_units = unyt.keV + +entropy_units = unyt.keV * unyt.cm ** 2 + +info_fontsize = 5 + + +def image( + data: SWIFTDataset, ax: plt.Axes, radial_bins: np.array, center: np.array +) -> None: + """ + Creates the image of the gas density. + """ + + delta = image_bounds[1] - image_bounds[0] + + # Need to re-scale our x, y to 0:1 + x = data.gas.coordinates[:, 0] + y = data.gas.coordinates[:, 1] + + left = center[0] + image_bounds[0] + bottom = center[1] + image_bounds[0] + + x = x - left + x = x / delta + y = y - bottom + y = y / delta + + h = data.gas.smoothing_lengths + h = h / delta + + m = data.gas.masses + + image = scatter_parallel(y, x, m, h, image_res) + + ax.imshow(image, cmap=image_cmap, norm=LogNorm(), origin="lower") + + ax.text( + 0.025, + 0.975, + "Gas Density", + color=image_textcolor, + transform=ax.transAxes, + ha="left", + va="top", + ) + + ax.set_xticks([]) + ax.set_yticks([]) + + return + + +def bin_volumes(radial_bins: np.array) -> np.array: + """ + Returns the volumes of the bins. + """ + + single_vol = lambda x: (4.0 / 3.0) * np.pi * x ** 3 + outer = single_vol(radial_bins[1:]) + inner = single_vol(radial_bins[:-1]) + + return outer - inner + + +def bin_centers(radial_bins: np.array) -> np.array: + """ + Returns the centers of the bins. + """ + + outer = radial_bins[1:] + inner = radial_bins[:-1] + + return 0.5 * (outer + inner) + + +def gas_density( + data: SWIFTDataset, ax: plt.Axes, radial_bins: np.array, center: np.array +) -> None: + + r_gas = np.sqrt(np.sum((data.gas.coordinates - center) ** 2, axis=1)) + + mass, _, _ = stat.binned_statistic( + x=r_gas, + values=data.gas.masses, + statistic="sum", + bins=radial_bins.to(r_gas.units), + ) + + # binned_statistic strips unit info :/ + mass *= data.gas.masses.units + + density = (mass / bin_volumes(radial_bins)).to(gas_density_units) + + centers = bin_centers(radial_bins).to(radial_bin_units) + + ax.plot(centers, density, label="SWIFT") + + ax.loglog() + + ax.set_ylabel(f"Gas Density $\\left[{density.units.latex_repr}\\right]$") + ax.set_xlabel(f"Radius [${centers.units.latex_repr}$]") + + ax.set_xlim(centers[0], centers[-1]) + + for scheme_name in extra_data_schemes: + path = f"{extra_data_directory}/rho_gas/{scheme_name}.csv" + R, rho = np.loadtxt(path, delimiter=",").T + + # Correct h-factors + R /= h + rho *= (h * h) + ax.plot(R, rho, linestyle="dashed", lw=1, label=scheme_name) + + ax.legend() + + return + + +def dm_density( + data: SWIFTDataset, ax: plt.Axes, radial_bins: np.array, center: np.array +) -> None: + + r_dm = np.sqrt(np.sum((data.dark_matter.coordinates - center) ** 2, axis=1)) + + mass, _, _ = stat.binned_statistic( + x=r_dm, + values=data.dark_matter.masses, + statistic="sum", + bins=radial_bins.to(r_dm.units), + ) + + # binned_statistic strips unit info :/ + mass *= data.dark_matter.masses.units + + density = (mass / bin_volumes(radial_bins)).to(dm_density_units) + + centers = bin_centers(radial_bins).to(radial_bin_units) + + ax.plot(centers, density) + + ax.loglog() + + ax.set_ylabel(f"Dark Matter Density $\\left[{density.units.latex_repr}\\right]$") + ax.set_xlabel(f"Radius [${centers.units.latex_repr}$]") + + ax.set_xlim(centers[0], centers[-1]) + + return + + +def get_gas_temperatures(data: SWIFTDataset) -> np.array: + """ + We store the internal energy, not temperature. We can assume it's all ionized. + """ + + H_frac = data.metadata.hydro_scheme["Hydrogen mass fraction"][0] + gas_gamma = data.metadata.hydro_scheme["Adiabatic index"][0] + mu = 4.0 / (8.0 - 5.0 * (1.0 - H_frac)) + + T = mu * (gas_gamma - 1.0) * data.gas.internal_energies * unyt.mh / unyt.kb + + return T.to(unyt.K) + + +def temperature( + data: SWIFTDataset, ax: plt.Axes, radial_bins: np.array, center: np.array +) -> None: + + r_gas = np.sqrt(np.sum((data.gas.coordinates - center) ** 2, axis=1)) + temperatures = get_gas_temperatures(data) + + temp, _, _ = stat.binned_statistic( + x=r_gas, values=temperatures, statistic="mean", bins=radial_bins.to(r_gas.units) + ) + + # binned_statistic strips unit info :/ + temp *= temperatures.units + + kT = (temp * unyt.kb).to(temperature_units) + + centers = bin_centers(radial_bins).to(radial_bin_units) + + ax.plot(centers, kT) + + ax.semilogx() + + ax.set_ylabel(f"Gas Temperature (kT) [${kT.units.latex_repr}$]") + ax.set_xlabel(f"Radius [${centers.units.latex_repr}$]") + + for scheme_name in extra_data_schemes: + path = f"{extra_data_directory}/kT/{scheme_name}.csv" + R, kT = np.loadtxt(path, delimiter=",").T + + # Correct h-factors + R /= h + ax.plot(R, kT, linestyle="dashed", lw=1, label=scheme_name) + + ax.set_xlim(centers[0], centers[-1]) + + return + + +def entropy( + data: SWIFTDataset, ax: plt.Axes, radial_bins: np.array, center: np.array +) -> None: + + r_gas = np.sqrt(np.sum((data.gas.coordinates - center) ** 2, axis=1)) + + # Need temperatures _and_ densities here. + temperatures = get_gas_temperatures(data) + + temp, _, _ = stat.binned_statistic( + x=r_gas, values=temperatures, statistic="mean", bins=radial_bins.to(r_gas.units) + ) + + # binned_statistic strips unit info :/ + temp *= temperatures.units + + mass, _, _ = stat.binned_statistic( + x=r_gas, + values=data.gas.masses, + statistic="sum", + bins=radial_bins.to(r_gas.units), + ) + + # binned_statistic strips unit info :/ + mass *= data.gas.masses.units + + density = mass / bin_volumes(radial_bins) + + # Really need the number density + density = density / unyt.mh + + entropy = unyt.kb * temp / (density ** (2.0 / 3.0)) + entropy.convert_to_units(entropy_units) + + centers = bin_centers(radial_bins).to(radial_bin_units) + + ax.plot(centers, entropy) + + ax.loglog() + + ax.set_ylabel(f"Gas Entropy (T $n_e^{{2/3}}$) [${entropy.units.latex_repr}$]") + ax.set_xlabel(f"Radius [${centers.units.latex_repr}$]") + + for scheme_name in extra_data_schemes: + path = f"{extra_data_directory}/S/{scheme_name}.csv" + R, S = np.loadtxt(path, delimiter=",").T + + # Correct h-factors + R /= h + S /= (h * h) + ax.plot(R, S, linestyle="dashed", lw=1, label=scheme_name) + + ax.set_xlim(centers[0], centers[-1]) + + return + + +def info( + data: SWIFTDataset, ax: plt.Axes, radial_bins: np.array, center: np.array +) -> None: + + metadata = data.metadata + + try: + viscosity = metadata.viscosity_info + except: + viscosity = "No info" + + try: + diffusion = metadata.diffusion_info + except: + diffusion = "No info" + + output = ( + "$\\bf{SWIFT}$\n" + + metadata.code_info + + "\n\n" + + "$\\bf{Compiler}$\n" + + metadata.compiler_info + + "\n\n" + + "$\\bf{Hydrodynamics}$\n" + + metadata.hydro_info + + "\n\n" + + "$\\bf{Viscosity}$\n" + + viscosity + + "\n\n" + + "$\\bf{Diffusion}$\n" + + diffusion + ) + + ax.text( + 0.5, + 0.45, + output, + ha="center", + va="center", + fontsize=info_fontsize, + transform=ax.transAxes, + ) + + ax.axis("off") + +def get_center(snapshot): + catalogue_filename = f"halo_0303.properties" + + with h5py.File(catalogue_filename, "r") as handle: + highest_mass = handle["Mass_200crit"][...].argsort()[-1] + x = handle["Xcmbp"][highest_mass] + y = handle["Ycmbp"][highest_mass] + z = handle["Zcmbp"][highest_mass] + + return [x, y, z] * unyt.Mpc + + + +if __name__ == "__main__": + import matplotlib.gridspec as gridspec + + snapshot = "nifty_0303" + center = get_center(snapshot) + radial_bins = np.logspace(-1.5, 0.5, 25) * unyt.Mpc + + # Perform plotting to create the following figure structure: + # +---------------------+ +---------+ + # | | | | + # | | | Gas | + # | | | Density | + # | | | | + # | Image | +---------+ + # | | +---------+ + # | | | | + # | | | DM | + # | | | Density | + # | | | | + # +---------------------+ +---------+ + # +---------+ +---------+ +---------+ + # | | | | | | + # | Entropy | | Temp | | SWIFT | + # | | | | | Info | + # | | | | | | + # +---------+ +---------+ +---------+ + + fig = plt.figure(figsize=(8, 8)) + gs = gridspec.GridSpec(3, 3, figure=fig) + + axes = { + k: plt.subplot(x) + for k, x in { + "image": gs[0:2, 0:2], + "gas_density": gs[0, 2], + "dm_density": gs[1, 2], + "entropy": gs[2, 0], + "temperature": gs[2, 1], + "info": gs[2, 2], + }.items() + } + + data = load(f"{snapshot}.hdf5") + + for name, ax in axes.items(): + try: + locals()[name](data, ax, radial_bins, center) + except KeyError: + pass + + fig.tight_layout() + fig.savefig("nifty_cluster.pdf") diff --git a/examples/nIFTyCluster/Baryonic/run.sh b/examples/nIFTyCluster/Baryonic/run.sh index 1977ac4b76e41030562634acc6cc56ef37ede364..7c9451fa36f55102ffae74dde5f462f6a6d1a15d 100755 --- a/examples/nIFTyCluster/Baryonic/run.sh +++ b/examples/nIFTyCluster/Baryonic/run.sh @@ -2,13 +2,12 @@ #SBATCH -J nIFTyClusterSWIFT #SBATCH -N 1 -#SBATCH --tasks-per-node=2 #SBATCH -o nifty_%j.out #SBATCH -e nifty_%j.err -#SBATCH -p <CHANGEME> -#SBATCH -A <CHANGEME> +#SBATCH -p cosma7 +#SBATCH -A dp004 #SBATCH --exclusive #SBATCH -t 72:00:00 -mpirun -np 2 ../../swift_mpi --cosmology --hydro --self-gravity -v 1 --pin --threads=14 nifty.yml +../../swift --cosmology --hydro --self-gravity -v 1 --pin --threads=56 nifty.yml diff --git a/examples/nIFTyCluster/Baryonic/run_vr_swift.sh b/examples/nIFTyCluster/Baryonic/run_vr_swift.sh new file mode 100644 index 0000000000000000000000000000000000000000..92483282cba81bbd0a58bea6d1ce606c6eeecdb5 --- /dev/null +++ b/examples/nIFTyCluster/Baryonic/run_vr_swift.sh @@ -0,0 +1,10 @@ +#!/bin/bash + +snapshot="nifty_0303" +out_name="halo_0303" +vr_loc="./stf" +config_file="vrconfig_swift.cfg" + +export OMP_NUM_THREADS=16 + +$vr_loc -i $snapshot -I 2 -o $out_name -C $config_file diff --git a/examples/nIFTyCluster/Baryonic/vrconfig_swift.cfg b/examples/nIFTyCluster/Baryonic/vrconfig_swift.cfg new file mode 100644 index 0000000000000000000000000000000000000000..92b8d2f8f2c82a79215ac2ee6cbd00db121a08e3 --- /dev/null +++ b/examples/nIFTyCluster/Baryonic/vrconfig_swift.cfg @@ -0,0 +1,191 @@ +#Configuration file for analysing Hydro +#runs 3DFOF + substructure algorithm, demands subhalos and FOF halos be self-bound, calculates many properties +#Units currently set to take in as input, Mpc, 1e10 solar masses, km/s, output in same units +#To set temporally unique halo ids, alter Snapshot_value=SNAP to appropriate value. Ie: for snapshot 12, change SNAP to 12 +# This is the same as the configuration file used in the EAGLE examples. + +################################ +#input options +#set up to use SWIFT HDF input, load gas, star, bh and dark matter +################################ +HDF_name_convention=6 #HDF SWIFT naming convention +Input_includes_dm_particle=1 #include dark matter particles in hydro input +Input_includes_gas_particle=1 #include gas particles in hydro input +Input_includes_star_particle=0 #include star particles in hydro input +Input_includes_bh_particle=0 #include bh particles in hydro input +Input_includes_wind_particle=0 #include wind particles in hydro input (used by Illustris and moves particle type 0 to particle type 3 when decoupled from hydro forces). Here shown as example +Input_includes_tracer_particle=0 #include tracer particles in hydro input (used by Illustris). Here shown as example +Input_includes_extradm_particle=1 #include extra dm particles stored in particle type 2 and type 3, useful for zooms + +Halo_core_phase_merge_dist=0.25 #merge substructures if difference in dispersion normalised distance is < this value +Apply_phase_merge_to_host=1 #merge substructures with background if centrally located and phase-distance is small + +#units conversion from input input to desired internal unit +Length_input_unit_conversion_to_output_unit=1.0 #default code unit, +Velocity_input_unit_conversion_to_output_unit=1.0 #default velocity unit, +Mass_input_unit_conversion_to_output_unit=1.0 #default mass unit, +#assumes input is in 1e10 msun, Mpc and km/s and output units are the same +Gravity=43.0211349 #for 1e10 Msun, km/s and Mpc +Hubble_unit=100.0 # assuming units are km/s and Mpc, then value of Hubble in km/s/Mpc +#converting hydro quantities +Stellar_age_input_is_cosmological_scalefactor=1 +Metallicity_input_unit_conversion_to_output_unit=1.0 +Stellar_age_input_unit_conversion_to_output_unit=1.0 +Star_formation_rate_input_unit_conversion_to_output_unit=1.0 + +#set the units of the output by providing conversion to a defined unit +#conversion of output length units to kpc +Length_unit_to_kpc=1000.0 +#conversion of output velocity units to km/s +Velocity_to_kms=1.0 +#conversion of output mass units to solar masses +Mass_to_solarmass=1.0e10 +Metallicity_to_solarmetallicity=1.0 +Star_formation_rate_to_solarmassperyear=1.0 +Stellar_age_to_yr=1.0 +#ensures that output is physical and not comoving distances per little h +Comoving_units=0 + +#sets the total buffer size in bytes used to store temporary particle information +#of mpi read threads before they are broadcast to the appropriate waiting non-read threads +#if not set, default value is equivalent to 1e6 particles per mpi process, quite large +#but significantly minimises the number of send/receives +#in this example the buffer size is roughly that for a send/receive of 10000 particles +#for 100 mpi processes +MPI_particle_total_buf_size=100000000 + +################################ +#search related options +################################ + +#how to search a simulation +Particle_search_type=1 #search dark matter particles only +#for baryon search +Baryon_searchflag=2 #if 1 search for baryons separately using phase-space search when identifying substructures, 2 allows special treatment in field FOF linking and phase-space substructure search, 0 treat the same as dark matter particles +#for search for substruture +Search_for_substructure=1 #if 0, end search once field objects are found +#also useful for zoom simulations or simulations of individual objects, setting this flag means no field structure search is run +Singlehalo_search=0 #if file is single halo in which one wishes to search for substructure. Here disabled. +#additional option for field haloes +Keep_FOF=0 #if field 6DFOF search is done, allows to keep structures found in 3DFOF (can be interpreted as the inter halo stellar mass when only stellar search is used).\n + +#minimum size for structures +Minimum_size=20 #min 20 particles +Minimum_halo_size=32 #if field halos have different minimum sizes, otherwise set to -1. + +#for field fof halo search +FoF_Field_search_type=5 #5 3DFOF search for field halos, 4 for 6DFOF clean up of field halos, 3 for 6DFOF with velocity scale distinct for each initial 3D FOF candidate +Halo_3D_linking_length=0.20 + +#for mean field estimates and local velocity density distribution funciton estimator related quantiites, rarely need to change this +Local_velocity_density_approximate_calculation=1 #calculates velocity density using approximative (and quicker) near neighbour search +Cell_fraction = 0.01 #fraction of field fof halo used to determine mean velocity distribution function. Typical values are ~0.005-0.02 +Grid_type=1 #normal entropy based grid, shouldn't have to change +Nsearch_velocity=32 #number of velocity neighbours used to calculate local velocity distribution function. Typial values are ~32 +Nsearch_physical=256 #numerof physical neighbours from which the nearest velocity neighbour set is based. Typical values are 128-512 + +#for substructure search, rarely ever need to change this +FoF_search_type=1 #default phase-space FOF search. Don't really need to change +Iterative_searchflag=1 #iterative substructure search, for substructure find initial candidate substructures with smaller linking lengths then expand search region +Outlier_threshold=2.5 #outlier threshold for a particle to be considered residing in substructure, that is how dynamically distinct a particle is. Typical values are >2 +Substructure_physical_linking_length=0.10 +Velocity_ratio=2.0 #ratio of speeds used in phase-space FOF +Velocity_opening_angle=0.10 #angle between velocities. 18 degrees here, typical values are ~10-30 +Velocity_linking_length=0.20 #where scaled by structure dispersion +Significance_level=1.0 #how significant a substructure is relative to Poisson noise. Values >= 1 are fine. + +#for iterative substructure search, rarely ever need to change this +Iterative_threshold_factor=1.0 #change in threshold value when using iterative search. Here no increase in threshold if iterative or not +Iterative_linking_length_factor=2.0 #increase in final linking final iterative substructure search +Iterative_Vratio_factor=1.0 #change in Vratio when using iterative search. no change in vratio +Iterative_ThetaOp_factor=1.0 #change in velocity opening angle. no change in velocity opening angle + +#for checking for halo merger remnants, which are defined as large, well separated phase-space density maxima +Halo_core_search=2 # searches for separate 6dfof cores in field haloes, and then more than just flags halo as merging, assigns particles to each merging "halo". 2 is full separation, 1 is flagging, 0 is off +#if searching for cores, linking lengths. likely does not need to change much +Use_adaptive_core_search=0 #calculate dispersions in configuration & vel space to determine linking lengths +Use_phase_tensor_core_growth=2 #use full stepped phase-space tensor assignment +Halo_core_ellx_fac=0.7 #how linking lengths are changed when searching for local 6DFOF cores, +Halo_core_ellv_fac=2.0 #how velocity lengths based on dispersions are changed when searching for local 6DFOF cores +Halo_core_ncellfac=0.005 #fraction of total halo particle number setting min size of a local 6DFOF core +Halo_core_num_loops=8 #number of loops to iteratively search for cores +Halo_core_loop_ellx_fac=0.75 #how much to change the configuration space linking per iteration +Halo_core_loop_ellv_fac=1.0 #how much to change the velocity space linking per iteration +Halo_core_loop_elln_fac=1.2 #how much to change the min number of particles per iteration +Halo_core_phase_significance=2.0 #how significant a core must be in terms of dispersions (sigma) significance + +################################ +#Unbinding options (VELOCIraptor is able to accurately identify tidal debris so particles need not be bound to a structure) +################################ + +#unbinding related items +Unbind_flag=1 #run unbinding +#objects must have particles that meet the allowed kinetic to potential ratio AND also have some total fraction that are completely bound. +Unbinding_type=0 +#alpha factor used to determine whether particle is "bound" alaph*T+W<0. For standard subhalo catalogues use >0.9 but if interested in tidal debris 0.2-0.5 +Allowed_kinetic_potential_ratio=0.95 +Min_bound_mass_frac=0.65 #minimum bound mass fraction +#run unbinding of field structures, aka halos. This is useful for sams and 6DFOF halos but may not be useful if interested in 3DFOF mass functions. +Bound_halos=0 +#don't keep background potential when unbinding +Keep_background_potential=1 +#use all particles to determine velocity frame for unbinding +Frac_pot_ref=1.0 +Min_npot_ref=20 +#reference frame only meaningful if calculating velocity frame using subset of particles in object. Can use radially sorted fraction of particles about minimum potential or centre of mass +Kinetic_reference_frame_type=0 +Unbinding_max_unbound_removal_fraction_per_iteration=0.5 +Unbinding_max_unbound_fraction=0.95 +Unbinding_max_unbound_fraction_allowed=0.005 + +################################ +#Calculation of properties related options +################################ +Virial_density=500 #user defined virial overdensity. Note that 200 rho_c, 200 rho_m and BN98 are already calculated. +#when calculating properties, for field objects calculate inclusive masses +Inclusive_halo_masses=3 #calculate inclusive masses for halos using full Spherical overdensity apertures +#ensures that output is physical and not comoving distances per little h +Comoving_units=0 +#calculate more (sub)halo properties (like angular momentum in spherical overdensity apertures, both inclusive and exclusive) +Extensive_halo_properties_output=1 +Extensive_gas_properties_output=1 +Extensive_star_properties_output=1 +#calculate aperture masses +Calculate_aperture_quantities=1 +Number_of_apertures=5 +Aperture_values_in_kpc=5,10,30,50,100, +Number_of_projected_apertures=5 +Projected_aperture_values_in_kpc=5,10,30,50,100, +#calculate radial profiles +Calculate_radial_profiles=1 +Number_of_radial_profile_bin_edges=20 +#default radial normalisation log rad bins, normed by R200crit, Integer flag of 0 is log bins and R200crit norm. +Radial_profile_norm=0 +Radial_profile_bin_edges=-2.,-1.87379263,-1.74758526,-1.62137789,-1.49517052,-1.36896316,-1.24275579,-1.11654842,-0.99034105,-0.86413368,-0.73792631,-0.61171894,-0.48551157,-0.3593042,-0.23309684,-0.10688947,0.0193179,0.14552527,0.27173264,0.39794001, +Iterate_cm_flag=0 #do not interate to determine centre-of-mass +Sort_by_binding_energy=1 #sort particles by binding energy +Reference_frame_for_properties=2 #use the minimum potential as reference frame about which to calculate properties + +################################ +#output related +################################ + +Write_group_array_file=0 #do not write a group array file +Separate_output_files=0 #do not separate output into field and substructure files similar to subfind +Binary_output=2 #Use HDF5 output (binary output 1, ascii 0, and HDF 2) +#output particles residing in the spherical overdensity apertures of halos, only the particles exclusively belonging to halos +Spherical_overdensity_halo_particle_list_output=1 + +#halo ids are adjusted by this value * 1000000000000 (or 1000000 if code compiled with the LONGINTS option turned off) +#to ensure that halo ids are temporally unique. So if you had 100 snapshots, for snap 100 set this to 100 and 100*1000000000000 will +#be added to the halo id as set for this snapshot, so halo 1 becomes halo 100*1000000000000+1 and halo 1 of snap 0 would just have ID=1 + +#ALTER THIS as part of a script to get temporally unique ids +Snapshot_value=SNAP + +################################ +#other options +################################ +Verbose=0 #how talkative do you want the code to be, 0 not much, 1 a lot, 2 chatterbox + + diff --git a/examples/parameter_example.yml b/examples/parameter_example.yml index 5ae4235a0d2c6f26c8628f1f6ebdfaff86d13115..4d43ae30f5bcd0df4970168591f03f97c092b21e 100644 --- a/examples/parameter_example.yml +++ b/examples/parameter_example.yml @@ -28,26 +28,28 @@ Cosmology: # 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. - use_mass_weighted_num_ngb: 0 # (Optional) Are we using the mass-weighted definition of the number of neighbours? - h_tolerance: 1e-4 # (Optional) Relative accuracy of the Netwon-Raphson scheme for the smoothing lengths. - h_max: 10. # (Optional) Maximal allowed smoothing length in internal units. Defaults to FLT_MAX if unspecified. - h_min_ratio: 0. # (Optional) Minimal allowed smoothing length in units of the softening. Defaults to 0 if unspecified. - max_volume_change: 1.4 # (Optional) Maximal allowed change of kernel volume over one time-step. - max_ghost_iterations: 30 # (Optional) Maximal number of iterations allowed to converge towards the smoothing length. - initial_temperature: 0 # (Optional) Initial temperature (in internal units) to set the gas particles at start-up. Value is ignored if set to 0. - 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. - diffusion_alpha: 0.0 # (Optional) Override the initial value for the thermal diffusion coefficient in schemes with thermal diffusion. - diffusion_beta: 0.01 # (Optional) Override the decay/rise rate tuning parameter for the thermal diffusion. - diffusion_alpha_max: 1.0 # (Optional) Override the maximal thermal diffusion coefficient that is allowed for a given particle. - diffusion_alpha_min: 0.0 # (Optional) Override the minimal thermal diffusion coefficient that is allowed for a given particle. + 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. + use_mass_weighted_num_ngb: 0 # (Optional) Are we using the mass-weighted definition of the number of neighbours? + h_tolerance: 1e-4 # (Optional) Relative accuracy of the Netwon-Raphson scheme for the smoothing lengths. + h_max: 10. # (Optional) Maximal allowed smoothing length in internal units. Defaults to FLT_MAX if unspecified. + h_min_ratio: 0. # (Optional) Minimal allowed smoothing length in units of the softening. Defaults to 0 if unspecified. + max_volume_change: 1.4 # (Optional) Maximal allowed change of kernel volume over one time-step. + max_ghost_iterations: 30 # (Optional) Maximal number of iterations allowed to converge towards the smoothing length. + particle_splitting: 1 # (Optional) Are we splitting particles that are too massive (default: 0) + particle_splitting_mass_threshold: 7e-4 # (Optional) Mass threshold for particle splitting (in internal units) + initial_temperature: 0 # (Optional) Initial temperature (in internal units) to set the gas particles at start-up. Value is ignored if set to 0. + 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. + diffusion_alpha: 0.0 # (Optional) Override the initial value for the thermal diffusion coefficient in schemes with thermal diffusion. + diffusion_beta: 0.01 # (Optional) Override the decay/rise rate tuning parameter for the thermal diffusion. + diffusion_alpha_max: 1.0 # (Optional) Override the maximal thermal diffusion coefficient that is allowed for a given particle. + diffusion_alpha_min: 0.0 # (Optional) Override the minimal thermal diffusion coefficient that is allowed for a given particle. # Parameters of the stars neighbour search Stars: @@ -60,18 +62,20 @@ Stars: # Parameters for the self-gravity scheme Gravity: - mesh_side_length: 32 # Number of cells along each axis for the periodic gravity mesh. - eta: 0.025 # Constant dimensionless multiplier for time integration. - theta: 0.7 # Opening angle (Multipole acceptance criterion). - comoving_DM_softening: 0.0026994 # Comoving Plummer-equivalent softening length for DM particles (in internal units). - max_physical_DM_softening: 0.0007 # Maximal Plummer-equivalent softening length in physical coordinates for DM particles (in internal units). + mesh_side_length: 128 # Number of cells along each axis for the periodic gravity mesh. + eta: 0.025 # Constant dimensionless multiplier for time integration. + theta: 0.7 # Opening angle (Multipole acceptance criterion). + comoving_DM_softening: 0.0026994 # Comoving Plummer-equivalent softening length for DM particles (in internal units). + max_physical_DM_softening: 0.0007 # Maximal Plummer-equivalent softening length in physical coordinates for DM particles (in internal units). comoving_baryon_softening: 0.0026994 # Comoving Plummer-equivalent softening length for baryon particles (in internal units). max_physical_baryon_softening: 0.0007 # Maximal Plummer-equivalent softening length in physical coordinates for baryon particles (in internal units). softening_ratio_background: 0.04 # Fraction of the mean inter-particle separation to use as Plummer-equivalent softening for the background DM particles. - rebuild_frequency: 0.01 # (Optional) Frequency of the gravity-tree rebuild in units of the number of g-particles (this is the default value). - a_smooth: 1.25 # (Optional) Smoothing scale in top-level cell sizes to smooth the long-range forces over (this is the default value). - r_cut_max: 4.5 # (Optional) Cut-off in number of top-level cells beyond which no FMM forces are computed (this is the default value). - r_cut_min: 0.1 # (Optional) Cut-off in number of top-level cells below which no truncation of FMM forces are performed (this is the default value). + rebuild_frequency: 0.01 # (Optional) Frequency of the gravity-tree rebuild in units of the number of g-particles (this is the default value). + a_smooth: 1.25 # (Optional) Smoothing scale in top-level cell sizes to smooth the long-range forces over (this is the default value). + r_cut_max: 4.5 # (Optional) Cut-off in number of top-level cells beyond which no FMM forces are computed (this is the default value). + r_cut_min: 0.1 # (Optional) Cut-off in number of top-level cells below which no truncation of FMM forces are performed (this is the default value). + dithering: 1 # (Optional) Activate the dithering of the gravity mesh at every rebuild (this is the default value). + dithering_ratio: 1.0 # (Optional) Magnitude of each component of the dithering vector in units of the top-level cell sizes (this is the default value). # Parameters for the Friends-Of-Friends algorithm FOF: @@ -118,7 +122,8 @@ TimeIntegration: # Parameters governing the snapshots Snapshots: - basename: output # Common part of the name of output files + basename: output # Common part of the name of output files. + subdir: dir # (Optional) Sub-directory in which to write the snapshots. Defaults to "" (i.e. the directory where SWIFT is run). scale_factor_first: 0.1 # (Optional) Scale-factor of the first snapshot if cosmological time-integration. time_first: 0. # (Optional) Time of the first output if non-cosmological time-integration (in internal units) delta_time: 0.01 # Time difference between consecutive outputs (in internal units) @@ -200,7 +205,8 @@ DomainDecomposition: # Structure finding options (requires velociraptor) StructureFinding: config_file_name: stf_input.cfg # Name of the STF config file. - basename: ./stf # Common part of the name of output files. + basename: haloes # Common part of the name of output files. + subdir_per_output: stf # (Optional) Sub-directory (within Snapshots:subdir) to use for each invocation of STF. Defaults to "" (i.e. no sub-directory) scale_factor_first: 0.92 # (Optional) Scale-factor of the first snaphot (cosmological run) time_first: 0.01 # (Optional) Time of the first structure finding output (in internal units). delta_time: 1.10 # (Optional) Time difference between consecutive structure finding outputs (in internal units) in simulation time intervals. @@ -301,7 +307,7 @@ EAGLEEntropyFloor: # Parameters related to pressure floors ---------------------------------------------- GEARPressureFloor: - Jeans_factor: 10. # Number of particles required to suppose a resolved clump and avoid the pressure floor. + jeans_factor: 10. # Number of particles required to suppose a resolved clump and avoid the pressure floor. # Parameters related to cooling function ---------------------------------------------- @@ -329,15 +335,17 @@ EAGLECooling: # Cooling with Grackle 3.0 GrackleCooling: - CloudyTable: CloudyData_UVB=HM2012.h5 # Name of the Cloudy Table (available on the grackle bitbucket repository) - WithUVbackground: 1 # Enable or not the UV background - Redshift: 0 # Redshift to use (-1 means time based redshift) - WithMetalCooling: 1 # Enable or not the metal cooling - ProvideVolumetricHeatingRates: 0 # (optional) User provide volumetric heating rates - ProvideSpecificHeatingRates: 0 # (optional) User provide specific heating rates - SelfShieldingMethod: 0 # (optional) Grackle (<= 3) or Gear self shielding method - MaxSteps: 10000 # (optional) Max number of step when computing the initial composition - ConvergenceLimit: 1e-2 # (optional) Convergence threshold (relative) for initial composition + cloudy_table: CloudyData_UVB=HM2012.h5 # Name of the Cloudy Table (available on the grackle bitbucket repository) + with_UV_background: 1 # Enable or not the UV background + redshift: 0 # Redshift to use (-1 means time based redshift) + with_metal_cooling: 1 # Enable or not the metal cooling + provide_volumetric_heating_rates: 0 # (optional) User provide volumetric heating rates + provide_specific_heating_rates: 0 # (optional) User provide specific heating rates + max_steps: 10000 # (optional) Max number of step when computing the initial composition + convergence_limit: 1e-2 # (optional) Convergence threshold (relative) for initial composition + thermal_time_myr: 5 # (optional) Time (in Myr) for adiabatic cooling after a feedback event. + self_shielding_method: -1 # (optional) Grackle (1->3 for Grackle's ones, 0 for none and -1 for GEAR) + self_shielding_threshold_atom_per_cm3: 0.007 # Required only with GEAR's self shielding. Density threshold of the self shielding # Parameters related to chemistry models ----------------------------------------------- @@ -354,6 +362,12 @@ EAGLEChemistry: init_abundance_Silicon: 0.000 # Inital fraction of particle mass in Silicon init_abundance_Iron: 0.000 # Inital fraction of particle mass in Iron +# GEAR chemistry model (Revaz and Jablonka 2018) +GEARChemistry: + initial_metallicity: 1 # Initial metallicity of the gas (mass fraction) + scale_initial_metallicity: 1 # Should we scale the initial metallicity with the solar one? + + # Parameters related to star formation models ----------------------------------------------- # GEAR star formation model (Revaz and Jablonka 2018) @@ -367,13 +381,13 @@ EAGLEStarFormation: EOS_temperature_norm_K: 8000 # Temperature om the polytropic EOS assumed for star-forming gas at the density normalisation in Kelvin. EOS_gamma_effective: 1.3333333 # Slope the of the polytropic EOS assumed for the star-forming gas. gas_fraction: 0.25 # (Optional) The gas fraction used internally by the model (Defaults to 1). - KS_normalisation: 1.515e-4 # The normalization of the Kennicutt-Schmidt law in Msun / kpc^2 / yr. - KS_exponent: 1.4 # The exponent of the Kennicutt-Schmidt law. - min_over_density: 57.7 # The over-density above which star-formation is allowed. + KS_normalisation: 1.515e-4 # Normalization of the Kennicutt-Schmidt law in Msun / kpc^2 / yr. + KS_exponent: 1.4 # Exponent of the Kennicutt-Schmidt law. + min_over_density: 57.7 # Over-density above which star-formation is allowed. KS_high_density_threshold_H_p_cm3: 1e3 # Hydrogen number density above which the Kennicut-Schmidt law changes slope in Hydrogen atoms per cm^3. KS_high_density_exponent: 2.0 # Slope of the Kennicut-Schmidt law above the high-density threshold. KS_max_density_threshold_H_p_cm3: 1e5 # (Optional) Density above which a gas particle gets automatically turned into a star in Hydrogen atoms per cm^3 (Defaults to FLT_MAX). - EOS_temperature_margin_dex: 0.5 # (Optional) Logarithm base 10 of the maximal temperature difference above the EOS allowed to form stars (Defaults to FLT_MAX). + EOS_entropy_margin_dex: 0.5 # (Optional) Logarithm base 10 of the maximal entropy above the EOS at which stars can form. threshold_norm_H_p_cm3: 0.1 # Normalisation of the metal-dependant density threshold for star formation in Hydrogen atoms per cm^3. threshold_Z0: 0.002 # Reference metallicity (metal mass fraction) for the metal-dependant threshold for star formation. threshold_slope: -0.64 # Slope of the metal-dependant star formation threshold @@ -391,22 +405,27 @@ EAGLEFeedback: filename: ./yieldtables/ # Path to the directory containing the EAGLE yield tables. IMF_min_mass_Msun: 0.1 # Minimal stellar mass considered for the Chabrier IMF in solar masses. IMF_max_mass_Msun: 100.0 # Maximal stellar mass considered for the Chabrier IMF in solar masses. - SNII_min_mass_Msun: 6.0 # Minimal mass considered for SNII feedback (not SNII enrichment!) in solar masses. - SNII_max_mass_Msun: 100.0 # Maximal mass considered for SNII feedback (not SNII enrichment!) in solar masses. - SNII_wind_delay_Gyr: 0.03 # Time in Gyr between a star's birth and the SNII thermal feedback event. + SNII_min_mass_Msun: 6.0 # Minimal mass considered for SNII stars in solar masses. + SNII_max_mass_Msun: 100.0 # Maximal mass considered for SNII stars in solar masses. + SNII_sampled_delay: 1 # Sample the SNII lifetimes to do feedback. + SNII_wind_delay_Gyr: 0.03 # Time in Gyr between a star's birth and the SNII thermal feedback event when not sampling. SNII_delta_T_K: 3.16228e7 # Change in temperature to apply to the gas particle in a SNII thermal feedback event in Kelvin. SNII_energy_erg: 1.0e51 # Energy of one SNII explosion in ergs. - SNII_energy_fraction_min: 3.0 # Maximal fraction of energy applied in a SNII feedback event. - SNII_energy_fraction_max: 0.3 # Minimal fraction of energy applied in a SNII feedback event. + SNII_energy_fraction_min: 0.3 # Maximal fraction of energy applied in a SNII feedback event. + SNII_energy_fraction_max: 3.0 # Minimal fraction of energy applied in a SNII feedback event. SNII_energy_fraction_Z_0: 0.0012663729 # Pivot point for the metallicity dependance of the SNII energy fraction (metal mass fraction). SNII_energy_fraction_n_0_H_p_cm3: 0.67 # Pivot point for the birth density dependance of the SNII energy fraction in cm^-3. SNII_energy_fraction_n_Z: 0.8686 # Power-law for the metallicity dependance of the SNII energy fraction. SNII_energy_fraction_n_n: 0.8686 # Power-law for the birth density dependance of the SNII energy fraction. - SNIa_max_mass_Msun: 8.0 # Maximal mass considered for SNIa feedback and enrichment in solar masses. - SNIa_timescale_Gyr: 2.0 # Time-scale of the exponential decay of the SNIa rates in Gyr. - SNIa_efficiency_p_Msun: 0.002 # Normalisation of the SNIa rates in inverse solar masses. + SNIa_DTD: PowerLaw # Functional form of the SNIa delay time distribution Two choices: 'PowerLaw' or 'Exponential'. + SNIa_DTD_delay_Gyr: 0.04 # Stellar age after which SNIa start in Gyr (40 Myr corresponds to stars ~ 8 Msun). + SNIa_DTD_power_law_norm_p_Msun: 0.0012 # Normalization of the SNIa delay time distribution in the power-law DTD case (in Msun^-1). + SNIa_DTD_exp_norm_p_Msun: 0.002 # Normalization of the SNIa delay time distribution in the exponential DTD case (in Msun^-1). + SNIa_DTD_exp_timescale_Gyr: 2.0 # Time-scale of the SNIa delay time distribution in the exponential DTD case (in Gyr). SNIa_energy_erg: 1.0e51 # Energy of one SNIa explosion in ergs. AGB_ejecta_velocity_km_p_s: 10.0 # Velocity of the AGB ejectas in km/s. + stellar_evolution_age_cut_Gyr: 0.1 # Stellar age in Gyr above which the enrichment is down-sampled. + stellar_evolution_sampling_rate: 10 # Number of time-steps in-between two enrichment events for a star above the age threshold. SNII_yield_factor_Hydrogen: 1.0 # (Optional) Correction factor to apply to the Hydrogen yield from the SNII channel. SNII_yield_factor_Helium: 1.0 # (Optional) Correction factor to apply to the Helium yield from the SNII channel. SNII_yield_factor_Carbon: 0.5 # (Optional) Correction factor to apply to the Carbon yield from the SNII channel. @@ -417,15 +436,24 @@ EAGLEFeedback: SNII_yield_factor_Silicon: 1.0 # (Optional) Correction factor to apply to the Silicon yield from the SNII channel. SNII_yield_factor_Iron: 0.5 # (Optional) Correction factor to apply to the Iron yield from the SNII channel. +# GEAR feedback model +GEARFeedback: + supernovae_energy_erg: 0.1e51 # Energy released by a single supernovae. + yields_table: chemistry-AGB+OMgSFeZnSrYBaEu-16072013.h5 # Table containing the yields. + discrete_yields: 0 # Should we use discrete yields or the IMF integrated one? + # Parameters related to AGN models ----------------------------------------------- # EAGLE AGN model EAGLEAGN: subgrid_seed_mass_Msun: 1.5e5 # Black hole subgrid mass at creation time in solar masses. max_eddington_fraction: 1. # Maximal allowed accretion rate in units of the Eddington rate. + eddington_fraction_for_recording: 0.1 # Record the last time BHs reached an Eddington ratio above this threshold. viscous_alpha: 1e6 # Normalisation constant of the Bondi viscuous time-scale accretion reduction term radiative_efficiency: 0.1 # Fraction of the accreted mass that gets radiated. coupling_efficiency: 0.15 # Fraction of the radiated energy that couples to the gas in feedback events. AGN_delta_T_K: 3.16228e8 # Change in temperature to apply to the gas particle in an AGN feedback event in Kelvin. AGN_num_ngb_to_heat: 1. # Target number of gas neighbours to heat in an AGN feedback event. max_reposition_mass: 2e8 # Maximal BH mass considered for BH repositioning in solar masses. + threshold_major_merger: 0.333 # Mass ratio threshold to consider a BH merger as 'major' + threshold_minor_merger: 0.1 # Mass ratio threshold to consider a BH merger as 'minor' diff --git a/logger/Makefile.am b/logger/Makefile.am index 3bfd5af848c504d50fe201e02f49186287fbfb5a..d4dd4b08456cd3fd3de3aea02069b2bcc89f0266 100644 --- a/logger/Makefile.am +++ b/logger/Makefile.am @@ -48,11 +48,11 @@ SUBDIRS = tests # List required headers include_HEADERS = logger_header.h logger_loader_io.h logger_particle.h logger_time.h logger_tools.h logger_reader.h \ - logger_logfile.h + logger_logfile.h logger_index.h quick_sort.h # Common source files AM_SOURCES = logger_header.c logger_loader_io.c logger_particle.c logger_time.c logger_tools.c logger_reader.c \ - logger_logfile.c + logger_logfile.c logger_index.c quick_sort.c if HAVEPYTHON AM_SOURCES += logger_python_wrapper.c endif diff --git a/logger/examples/reader_example.py b/logger/examples/reader_example.py new file mode 100644 index 0000000000000000000000000000000000000000..b15446a6cd3d5b159038b56910eede5f571a6d07 --- /dev/null +++ b/logger/examples/reader_example.py @@ -0,0 +1,60 @@ +#!/usr/bin/env python3 +""" +Read a logger file by using an index file. +Example: ./reader_example.py ../../examples/SedovBlast_3D/index 0.1 +""" +import sys +import numpy as np +import matplotlib.pyplot as plt +sys.path.append("../.libs/") + +import liblogger as logger + + +def plot3D(pos): + from mpl_toolkits.mplot3d import Axes3D + fig = plt.figure() + ax = fig.add_subplot(111, projection="3d") + ax.plot(pos[:, 0], pos[:, 1], pos[:, 2], ".", markersize=0.2) + + +def plot2D(): + center = np.array([0.5]*3) + r2 = np.sum((pos - center)**2, axis=1) + + # plot entropy vs distance + plt.plot(np.sqrt(r2), data["entropies"], '.', + markersize=0.2) + + plt.xlim(0., 0.5) + plt.ylim(-1, 50) + plt.xlabel("Radius") + plt.ylabel("Entropy") + + +basename = "../../examples/HydroTests/SedovBlast_3D/index" +time = 0.05 +if len(sys.argv) >= 2: + basename = sys.argv[1] +else: + print("No basename supplied (first argument), using default.") +if len(sys.argv) >= 3: + time = float(sys.argv[2]) +else: + print("No time supplied (second argument), using default.") +if len(sys.argv) > 3: + print("Ignoring excess arguments '%s'." % sys.argv[3:]) +print("basename: %s" % basename) +print("time: %g" % time) + +# read dump + +t = logger.getTimeLimits(basename) +data = logger.loadSnapshotAtTime(basename, time) +print("The data contains the following elements:") +print(data.dtype.names) + +pos = data["positions"] + +plot3D(pos) +plt.show() diff --git a/logger/logger_header.c b/logger/logger_header.c index 61e5da246c9aa07eeeb42e751832f017fa04ca0a..2e2ffe07647dedfc204a0f2f31be1a08de1b4627 100644 --- a/logger/logger_header.c +++ b/logger/logger_header.c @@ -45,9 +45,9 @@ void header_print(const struct header *h) { #endif message("First Offset: %lu.", h->offset_first_record); message("Offset direction: %s.", logger_offset_name[h->offset_direction]); - message("Number masks: %i.", h->number_mask); + message("Number masks: %i.", h->masks_count); - for (size_t i = 0; i < h->number_mask; i++) { + for (size_t i = 0; i < h->masks_count; i++) { message(" Mask: %s.", h->masks[i].name); message(" Value: %u.", h->masks[i].mask); message(" Size: %i.", h->masks[i].size); @@ -70,7 +70,7 @@ void header_free(struct header *h) { free(h->masks); }; * @return Index of the field (-1 if not found). */ int header_get_field_index(const struct header *h, const char *field) { - for (size_t i = 0; i < h->number_mask; i++) { + for (size_t i = 0; i < h->masks_count; i++) { if (strcmp(h->masks[i].name, field) == 0) { return i; } @@ -93,8 +93,8 @@ void header_change_offset_direction(struct header *h, /* Skip file format and version numbers. */ size_t offset = LOGGER_VERSION_SIZE + 2 * sizeof(int); - logger_loader_io_write_data(h->log->log.map + offset, sizeof(unsigned int), - &new_value); + logger_loader_io_write_data((char *)h->log->log.map + offset, + sizeof(unsigned int), &new_value); } /** @@ -135,10 +135,12 @@ void header_read(struct header *h, struct logger_logfile *log) { error("Wrong offset value in the header (%i).", h->offset_direction); /* Read offset to first record. */ + h->offset_first_record = 0; map = logger_loader_io_read_data(map, LOGGER_OFFSET_SIZE, &h->offset_first_record); /* Read the size of the strings. */ + h->string_length = 0; map = logger_loader_io_read_data(map, sizeof(unsigned int), &h->string_length); @@ -148,13 +150,17 @@ void header_read(struct header *h, struct logger_logfile *log) { } /* Read the number of masks. */ - map = logger_loader_io_read_data(map, sizeof(unsigned int), &h->number_mask); + map = logger_loader_io_read_data(map, sizeof(unsigned int), &h->masks_count); /* Allocate the masks memory. */ - h->masks = malloc(sizeof(struct mask_data) * h->number_mask); + h->masks = malloc(sizeof(struct mask_data) * h->masks_count); + if (h->masks == NULL) { + error("Failed to allocate the memory for the masks."); + } /* Loop over all masks. */ - for (size_t i = 0; i < h->number_mask; i++) { + h->timestamp_mask = 0; + for (size_t i = 0; i < h->masks_count; i++) { /* Read the mask name. */ map = logger_loader_io_read_data(map, h->string_length, h->masks[i].name); @@ -164,12 +170,22 @@ void header_read(struct header *h, struct logger_logfile *log) { /* Read the mask data size. */ map = logger_loader_io_read_data(map, sizeof(unsigned int), &h->masks[i].size); + + /* Keep the timestamp mask in memory */ + if (strcmp(h->masks[i].name, "timestamp") == 0) { + h->timestamp_mask = h->masks[i].mask; + } + } + + /* Check that the timestamp mask exists */ + if (h->timestamp_mask == 0) { + error("Unable to find the timestamp mask."); } /* Check the logfile header's size. */ - if (map != log->log.map + h->offset_first_record) { + if (map != (char *)log->log.map + h->offset_first_record) { header_print(h); - size_t offset = map - log->log.map; + size_t offset = (char *)map - (char *)log->log.map; error("Wrong header size (in header %zi, current %zi).", h->offset_first_record, offset); } @@ -187,7 +203,7 @@ size_t header_get_record_size_from_mask(const struct header *h, const size_t mask) { size_t count = 0; /* Loop over each masks. */ - for (size_t i = 0; i < h->number_mask; i++) { + for (size_t i = 0; i < h->masks_count; i++) { if (mask & h->masks[i].mask) { count += h->masks[i].size; } diff --git a/logger/logger_header.h b/logger/logger_header.h index c388ef65cda21d00f53ddc54e97f43671edf1aeb..a68b98bc9a4807e6fe2b10132911132daad54813 100644 --- a/logger/logger_header.h +++ b/logger/logger_header.h @@ -24,9 +24,13 @@ #include <stdio.h> #include <stdlib.h> +/* Number of character for the version information */ #define LOGGER_VERSION_SIZE 20 -#define LOGGER_OFFSET_SIZE 7 -#define LOGGER_MASK_SIZE 1 +/* Number of bytes for the mask information in the headers + (need to be large enough for the larges mask) */ +#define LOGGER_MASK_SIZE 2 +/* Number of bytes for the offset size in the headers */ +#define LOGGER_OFFSET_SIZE (8 - LOGGER_MASK_SIZE) enum logger_offset_direction { logger_offset_backward = 0, @@ -68,7 +72,7 @@ struct header { unsigned int string_length; /* Number of masks. */ - unsigned int number_mask; + unsigned int masks_count; /* List of masks. */ struct mask_data *masks; @@ -78,6 +82,9 @@ struct header { /* The corresponding log. */ struct logger_logfile *log; + + /* Timestamp mask */ + size_t timestamp_mask; }; void header_print(const struct header *h); diff --git a/logger/logger_index.c b/logger/logger_index.c new file mode 100644 index 0000000000000000000000000000000000000000..98368a89b93c707a9e1004bf400e0b898b53b261 --- /dev/null +++ b/logger/logger_index.c @@ -0,0 +1,227 @@ +/******************************************************************************* + * This file is part of SWIFT. + * Copyright (c) 2019 Loic Hausammann (loic.hausammann@epfl.ch) + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published + * by the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this program. If not, see <http://www.gnu.org/licenses/>. + * + ******************************************************************************/ + +/* Include the corresponding header */ +#include "logger_index.h" + +/* Include the standard headers */ +#include <errno.h> +#include <fcntl.h> + +/* Include local headers */ +#include "logger_loader_io.h" +#include "logger_reader.h" +#include "quick_sort.h" + +/* Define the place and size of each element in the header. */ +/* The time in double precision. */ +#define logger_index_time_offset 0 +#define logger_index_time_size sizeof(double) +/* The time on the integer timeline. */ +#define logger_index_integer_time_offset \ + logger_index_time_offset + logger_index_time_size +#define logger_index_integer_time_size sizeof(integertime_t) +/* The number of particle (for each type). */ +#define logger_index_npart_offset \ + logger_index_integer_time_offset + logger_index_integer_time_size +#define logger_index_npart_size sizeof(uint64_t) * swift_type_count +/* The flag used for checking if the file is sorted or not. */ +#define logger_index_is_sorted_offset \ + logger_index_npart_offset + logger_index_npart_size +#define logger_index_is_sorted_size sizeof(char) +/* The array containing the offset and ids. Rounding to a multiplier of 8 in + * order to align the memory */ +#define logger_index_data_offset \ + ((logger_index_is_sorted_offset + logger_index_is_sorted_size + 7) & ~7) + +/** + * @brief Read the index file header. + * + * @param index The #logger_index. + * @param filename The filename of the index file. + */ +void logger_index_read_header(struct logger_index *index, + const char *filename) { + + /* Open the file */ + message("Reading %s", filename); + logger_index_map_file(index, filename, 0); + + /* Read times */ + memcpy(&index->time, (char *)index->index.map + logger_index_time_offset, + logger_index_time_size); + memcpy(&index->integer_time, + (char *)index->index.map + logger_index_integer_time_offset, + logger_index_integer_time_size); + + /* Read the number of particles */ + memcpy(index->nparts, (char *)index->index.map + logger_index_npart_offset, + logger_index_npart_size); + + /* Read if the file is sorted */ + memcpy(&index->is_sorted, + (char *)index->index.map + logger_index_is_sorted_offset, + logger_index_is_sorted_size); + + /* Close the file */ + logger_index_free(index); +} + +/** + * @brief Write that the file is sorted. + * + * WARNING The file must be mapped. + * + * @param index The #logger_index. + */ +void logger_index_write_sorted(struct logger_index *index) { + /* Set the value */ + const char is_sorted = 1; + + /* Write the value */ + memcpy((char *)index->index.map + logger_index_is_sorted_offset, &is_sorted, + logger_index_is_sorted_size); +} + +/** + * @brief Get the #index_data of a particle type. + * + * @param index The #logger_index. + * @param type The particle type. + */ +struct index_data *logger_index_get_data(struct logger_index *index, int type) { + /* Get the offset of particles of this type by skipping entries of lower + * types. */ + size_t count = 0; + for (int i = 0; i < type; i++) { + count += index->nparts[i]; + } + const size_t type_offset = count * sizeof(struct index_data); + + const char *ret = + (char *)index->index.map + logger_index_data_offset + type_offset; + return (struct index_data *)ret; +} + +/** + * @brief Map the file and if required sort it. + * + * @param index The #logger_index. + * @param filename The index filename. + * @param sorted Does the file needs to be sorted? + */ +void logger_index_map_file(struct logger_index *index, const char *filename, + int sorted) { + /* Un-map previous file */ + if (index->index.map != NULL) { + error("Trying to remap."); + } + + /* Check if need to sort the file */ + if (sorted && !index->is_sorted) { + if (index->reader->verbose > 0) { + message("Sorting the index file."); + } + /* Map the index file */ + logger_loader_io_mmap_file(&index->index, filename, + /* read_only */ 0); + /* Sort the file */ + for (int i = 0; i < swift_type_count; i++) { + if (index->nparts[i] != 0) { + struct index_data *data = logger_index_get_data(index, i); + quick_sort(data, index->nparts[i]); + } + } + + /* Write that the file is sorted */ + logger_index_write_sorted(index); + + /* Free the index file before opening it again in read only */ + logger_index_free(index); + + if (index->reader->verbose > 0) { + message("Sorting done."); + } + } + + /* Map the index file */ + logger_loader_io_mmap_file(&index->index, filename, + /* read_only */ 1); +} + +/** + * @brief Cleanup the memory of a logger_index + * + * @param index The #logger_index. + */ +void logger_index_free(struct logger_index *index) { + if (index->index.map == NULL) { + error("Trying to unmap an unexisting map"); + } + logger_loader_io_munmap_file(&index->index); +} + +/** + * @brief Get the offset of a given particle + * + * @param index The #logger_index. + * @param id The ID of the particle. + * @param type The type of the particle. + * + * @return The offset of the particle or 0 if not found. + */ +size_t logger_index_get_particle_offset(struct logger_index *index, + long long id, int type) { + /* Define a few variables */ + const struct index_data *data = logger_index_get_data(index, type); + size_t left = 0; + size_t right = index->nparts[type] - 1; + + /* Search for the value (binary search) */ + while (left <= right) { + size_t m = (left + right) / 2; + if (data[m].id < id) { + left = m + 1; + } else if (data[m].id > id) { + right = m - 1; + } else { + return data[m].offset; + } + } + + return 0; +} + +/** + * @brief Initialize the #logger_index. + * + * @param index The #logger_index. + * @param reader The #logger_reader. + */ +void logger_index_init(struct logger_index *index, + struct logger_reader *reader) { + /* Set the mapped file to NULL */ + index->index.map = NULL; + + /* Set the pointer to the reader */ + index->reader = reader; + + /* Set the time to its default value */ + index->time = -1; +} diff --git a/logger/logger_index.h b/logger/logger_index.h new file mode 100644 index 0000000000000000000000000000000000000000..8419e0aaa18e00846e2c3ad9f1218780bf44f431 --- /dev/null +++ b/logger/logger_index.h @@ -0,0 +1,85 @@ +/******************************************************************************* + * This file is part of SWIFT. + * Copyright (c) 2019 Loic Hausammann (loic.hausammann@epfl.ch) + * + * 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 LOGGER_LOGGER_INDEX_H +#define LOGGER_LOGGER_INDEX_H + +#include "logger_loader_io.h" +#include "logger_tools.h" + +/* predefine the structure */ +struct logger_reader; + +/** + * @brief Data structure contained in the logger files. + */ +struct index_data { + /* Id of the particle. */ + int64_t id; + + /* Offset of the particle in the file. */ + uint64_t offset; +}; + +/** + * @brief Structure dealing with the index files. + * + * The structure is initialized with #logger_index_init and + * then a file can be read with #logger_index_read_header and + * #logger_index_map_file. + * + * The functions #logger_index_get_particle_offset and + * #logger_index_get_data should be used to access the element + * stored inside the index file. + * The first one access a particle through its ids and the second one + * gives a pointer to the first element that can be looped through. + */ +struct logger_index { + /* Pointer to the reader */ + struct logger_reader *reader; + + /* Time of the index file */ + double time; + + /* Integer time of the index file */ + integertime_t integer_time; + + /* Number of particles in the file */ + uint64_t nparts[swift_type_count]; + + /* Is the file sorted ? */ + char is_sorted; + + /* The mapped file */ + struct mapped_file index; +}; + +void logger_index_write_sorted(struct logger_index *index); +void logger_index_init(struct logger_index *index, + struct logger_reader *reader); +void logger_index_read_header(struct logger_index *index, const char *filename); +void logger_index_map_file(struct logger_index *index, const char *filename, + int sorted); +size_t logger_index_get_particle_offset(struct logger_index *index, + long long id, int type); +void logger_index_free(struct logger_index *index); +void logger_index_sort_file(struct logger_index *index); +struct index_data *logger_index_get_data(struct logger_index *index, int type); + +#endif // LOGGER_LOGGER_INDEX_H diff --git a/logger/logger_loader_io.c b/logger/logger_loader_io.c index f18f9bb7eb2eaf88ba11eaf916c0a68a27cfd2d2..6bebe3aefa619052b1f7688ad627fde6812d8d81 100644 --- a/logger/logger_loader_io.c +++ b/logger/logger_loader_io.c @@ -44,13 +44,13 @@ size_t logger_loader_io_get_file_size(int fd) { * * #logger_loader_io_munmap_file should be called to unmap the file. * + * @param map The #mapped_file. * @param filename file to read. - * @param file_size (out) size of the file. * @param read_only Open the file in read only mode? * */ -void *logger_loader_io_mmap_file(char *filename, size_t *file_size, - int read_only) { +void logger_loader_io_mmap_file(struct mapped_file *map, const char *filename, + int read_only) { /* open the file. */ int fd; @@ -63,33 +63,34 @@ void *logger_loader_io_mmap_file(char *filename, size_t *file_size, error("Unable to open file %s (%s).", filename, strerror(errno)); /* get the file size. */ - *file_size = logger_loader_io_get_file_size(fd); + map->mmap_size = logger_loader_io_get_file_size(fd); /* map the memory. */ int mode = PROT_READ; if (!read_only) mode |= PROT_WRITE; - void *map = mmap(NULL, *file_size, mode, MAP_SHARED, fd, 0); - if (map == MAP_FAILED) - error("Failed to allocate map of size %zi bytes (%s).", *file_size, + map->map = mmap(NULL, map->mmap_size, mode, MAP_SHARED, fd, 0); + if (map->map == MAP_FAILED) + error("Failed to allocate map of size %zi bytes (%s).", map->mmap_size, strerror(errno)); /* Close the file. */ close(fd); - - return map; } /** * @brief Unmap a file. * - * @param map file mapping. - * @param file_size The file size. + * @param map The #mapped_file. * */ -void logger_loader_io_munmap_file(void *map, size_t file_size) { +void logger_loader_io_munmap_file(struct mapped_file *map) { /* unmap the file. */ - if (munmap(map, file_size) != 0) { + if (munmap(map->map, map->mmap_size) != 0) { error("Unable to unmap the file (%s).", strerror(errno)); } + + /* Reset values */ + map->map = NULL; + map->mmap_size = 0; } diff --git a/logger/logger_loader_io.h b/logger/logger_loader_io.h index d44fea673017644306e73261afdbc6dec26948c6..e921b05730b22043a13dc8d991d53ffe8ac59d18 100644 --- a/logger/logger_loader_io.h +++ b/logger/logger_loader_io.h @@ -29,10 +29,19 @@ #include <stdio.h> #include <stdlib.h> +/* Structure for mapping a file. */ +struct mapped_file { + /* Mapped data. */ + void *map; + + /* File size. */ + size_t mmap_size; +}; + size_t logger_loader_io_get_file_size(int fd); -void *logger_loader_io_mmap_file(char *filename, size_t *file_size, - int read_only); -void logger_loader_io_munmap_file(void *map, size_t file_size); +void logger_loader_io_mmap_file(struct mapped_file *map, const char *filename, + int read_only); +void logger_loader_io_munmap_file(struct mapped_file *map); /** * @brief read a mask with its offset. @@ -52,14 +61,14 @@ __attribute__((always_inline)) INLINE static void *logger_loader_io_read_mask( *mask = 0; memcpy(mask, data, LOGGER_MASK_SIZE); } - data += LOGGER_MASK_SIZE; + data = (char *)data + LOGGER_MASK_SIZE; /* read offset */ if (diff_offset) { *diff_offset = 0; memcpy(diff_offset, data, LOGGER_OFFSET_SIZE); } - data += LOGGER_OFFSET_SIZE; + data = (char *)data + LOGGER_OFFSET_SIZE; return data; } @@ -76,7 +85,7 @@ __attribute__((always_inline)) INLINE static void *logger_loader_io_read_mask( __attribute__((always_inline)) INLINE static void *logger_loader_io_read_data( void *data, const size_t size, void *p) { memcpy(p, data, size); - return data + size; + return (char *)data + size; }; /** @@ -92,7 +101,7 @@ __attribute__((always_inline)) INLINE static void *logger_loader_io_write_data( void *data, const size_t size, const void *p) { memcpy(data, p, size); - return data + size; + return (char *)data + size; }; #endif // LOGGER_LOGGER_LOADER_IO_H diff --git a/logger/logger_logfile.c b/logger/logger_logfile.c index c70068cd24c01a5ba231e97e343a0c076dc0ecb4..7c1660ec7530af7fc5440abd20c5ab627dbc9882 100644 --- a/logger/logger_logfile.c +++ b/logger/logger_logfile.c @@ -42,8 +42,8 @@ void logger_logfile_init_from_file(struct logger_logfile *log, char *filename, /* Open file, map it and get its size. */ if (reader->verbose > 1) message("Mapping the log file."); - log->log.map = logger_loader_io_mmap_file(filename, &log->log.file_size, - /* read_only */ 1); + logger_loader_io_mmap_file(&log->log, filename, + /* read_only */ 1); /* Read the header. */ if (reader->verbose > 1) message("Reading the header."); @@ -69,7 +69,7 @@ void logger_logfile_init_from_file(struct logger_logfile *log, char *filename, } /* Initialize the time array. */ - if (reader->verbose > 1) message("Reading the time stamps."); + if (reader->verbose > 1) message("Reading the timestamps."); time_array_populate(&log->times, log); /* Print the time array. */ @@ -84,7 +84,7 @@ void logger_logfile_init_from_file(struct logger_logfile *log, char *filename, * @param log The #logger_logfile. */ void logger_logfile_free(struct logger_logfile *log) { - logger_loader_io_munmap_file(log->log.map, log->log.file_size); + logger_loader_io_munmap_file(&log->log); time_array_free(&log->times); } @@ -98,9 +98,9 @@ void logger_logfile_free(struct logger_logfile *log) { void logger_logfile_reverse_offset(struct logger_logfile *log, char *filename) { /* Close and reopen the file in write mode. */ - logger_loader_io_munmap_file(log->log.map, log->log.file_size); - log->log.map = logger_loader_io_mmap_file(filename, &log->log.file_size, - /* read_only */ 0); + logger_loader_io_munmap_file(&log->log); + logger_loader_io_mmap_file(&log->log, filename, + /* read_only */ 0); /* Get pointers */ struct header *header = &log->header; @@ -119,7 +119,7 @@ void logger_logfile_reverse_offset(struct logger_logfile *log, char *filename) { /* check that the record offset points to another record. */ for (size_t offset_debug = header->offset_first_record; - offset_debug < log->log.file_size; + offset_debug < log->log.mmap_size; offset_debug = tools_check_record_consistency(reader, offset_debug)) { } @@ -138,7 +138,7 @@ void logger_logfile_reverse_offset(struct logger_logfile *log, char *filename) { } /* reverse the record's offset. */ - for (size_t offset = header->offset_first_record; offset < log->log.file_size; + for (size_t offset = header->offset_first_record; offset < log->log.mmap_size; offset = tools_reverse_offset(header, log->log.map, offset)) { } @@ -159,7 +159,7 @@ void logger_logfile_reverse_offset(struct logger_logfile *log, char *filename) { /* check that the record offset points to another record. */ for (size_t offset_debug = header->offset_first_record; - offset_debug < log->log.file_size; + offset_debug < log->log.mmap_size; offset_debug = tools_check_record_consistency(reader, offset_debug)) { } @@ -169,7 +169,7 @@ void logger_logfile_reverse_offset(struct logger_logfile *log, char *filename) { #endif /* Close and reopen the file in read mode. */ - logger_loader_io_munmap_file(log->log.map, log->log.file_size); - log->log.map = logger_loader_io_mmap_file(filename, &log->log.file_size, - /* read_only */ 1); + logger_loader_io_munmap_file(&log->log); + logger_loader_io_mmap_file(&log->log, filename, + /* read_only */ 1); } diff --git a/logger/logger_logfile.h b/logger/logger_logfile.h index 0b6ef728d524bb104b83fc28b9250c51a764dfd4..15cd8bc3fb98be7f7dff2248256f1bdcf32ad799 100644 --- a/logger/logger_logfile.h +++ b/logger/logger_logfile.h @@ -24,6 +24,7 @@ #define LOGGER_LOGGER_LOGFILE_H #include "logger_header.h" +#include "logger_loader_io.h" #include "logger_time.h" struct logger_reader; @@ -49,15 +50,8 @@ struct logger_logfile { /* Information about the time records. */ struct time_array times; - /* The log's variables. */ - struct { - /* Mapped data. */ - void *map; - - /* File size. */ - size_t file_size; - - } log; + /* The file. */ + struct mapped_file log; }; void logger_logfile_init_from_file(struct logger_logfile *log, char *filename, diff --git a/logger/logger_particle.c b/logger/logger_particle.c index 6809e0edf6125e66cbb8807cc98eeb31b5e04ecd..480b0f7f50502a6c9e3f73dfd0ddfd70ee164b07 100644 --- a/logger/logger_particle.c +++ b/logger/logger_particle.c @@ -33,7 +33,7 @@ * @param p The #logger_particle to print */ void logger_particle_print(const struct logger_particle *p) { - message("ID: %lu.", p->id); + message("ID: %lli.", p->id); message("Mass: %g", p->mass); message("Time: %g.", p->time); message("Cutoff Radius: %g.", p->h); @@ -42,6 +42,7 @@ void logger_particle_print(const struct logger_particle *p) { message("Accelerations: (%g, %g, %g).", p->acc[0], p->acc[1], p->acc[2]); message("Entropy: %g.", p->entropy); message("Density: %g.", p->density); + message("Type: %i.", p->type); } /** @@ -61,6 +62,8 @@ void logger_particle_init(struct logger_particle *part) { part->h = -1; part->mass = -1; part->id = SIZE_MAX; + + part->type = 0; } /** @@ -92,6 +95,8 @@ void *logger_particle_read_field(struct logger_particle *part, void *map, p = &part->density; } else if (strcmp("consts", field) == 0) { p = malloc(size); + } else if (strcmp("special flags", field) == 0) { + p = &part->type; } else { error("Type %s not defined.", field); } @@ -104,9 +109,9 @@ void *logger_particle_read_field(struct logger_particle *part, void *map, part->mass = 0; part->id = 0; memcpy(&part->mass, p, sizeof(float)); - p += sizeof(float); + p = (char *)p + sizeof(float); memcpy(&part->id, p, sizeof(size_t)); - p -= sizeof(float); + p = (char *)p - sizeof(float); free(p); } @@ -119,7 +124,7 @@ void *logger_particle_read_field(struct logger_particle *part, void *map, * @param reader The #logger_reader. * @param part The #logger_particle to update. * @param offset offset of the record to read. - * @param time time to interpolate. + * @param time time to interpolate (not used if constant interpolation). * @param reader_type #logger_reader_type. * * @return position after the record. @@ -129,6 +134,9 @@ size_t logger_particle_read(struct logger_particle *part, const double time, const enum logger_reader_type reader_type) { + /* Save the offset */ + part->offset = offset; + /* Get a few pointers. */ const struct header *h = &reader->log.header; void *map = reader->log.log.map; @@ -141,13 +149,20 @@ size_t logger_particle_read(struct logger_particle *part, logger_particle_init(part); /* Read the record's mask. */ - map = logger_loader_io_read_mask(h, map + offset, &mask, &h_offset); + map = logger_loader_io_read_mask(h, (char *)map + offset, &mask, &h_offset); + + /* Check that the mask is meaningful */ + if (mask > (unsigned int)(1 << h->masks_count)) { + error("Found an unexpected mask %zi", mask); + } /* Check if it is not a time record. */ - if (mask == 128) error("Unexpected mask: %lu.", mask); + if (mask == h->timestamp_mask) { + error("Unexpected timestamp while reading a particle: %lu.", mask); + } /* Read all the fields. */ - for (size_t i = 0; i < h->number_mask; i++) { + for (size_t i = 0; i < h->masks_count; i++) { if (mask & h->masks[i].mask) { map = logger_particle_read_field(part, map, h->masks[i].name, h->masks[i].size); @@ -163,7 +178,7 @@ size_t logger_particle_read(struct logger_particle *part, part->time = -1; /* update the offset. */ - offset = (size_t)(map - reader->log.log.map); + offset = (size_t)((char *)map - (char *)reader->log.log.map); /* Check if an interpolation is required. */ if (reader_type == logger_reader_const) return offset; @@ -177,7 +192,7 @@ size_t logger_particle_read(struct logger_particle *part, } /* No next particle. */ - if (h_offset == 0) return (size_t)(map - reader->log.log.map); + if (h_offset == 0) return (size_t)((char *)map - (char *)reader->log.log.map); /* get absolute offset of next particle. */ h_offset += offset - header_get_record_size_from_mask(h, mask) - @@ -215,8 +230,9 @@ void logger_particle_interpolate(struct logger_particle *part_curr, #ifdef SWIFT_DEBUG_CHECKS /* Check the particle order. */ - if (part_next->time <= part_curr->time) - error("Wrong particle order (next before current)."); + if (part_next->time < part_curr->time) + error("Wrong particle order (next before current): %g, %g", part_next->time, + part_curr->time); if ((time < part_curr->time) || (part_next->time < time)) error( "Cannot extrapolate (particle time: %f, " diff --git a/logger/logger_particle.h b/logger/logger_particle.h index addd23564b65a734152ae8f538596d79019dd36f..57cab1f6f1490681f6673caa0c8622ce3bc5abff 100644 --- a/logger/logger_particle.h +++ b/logger/logger_particle.h @@ -53,13 +53,13 @@ struct logger_reader; */ struct logger_particle { /* position. */ - double pos[DIM]; + double pos[3]; /* velocity. */ - float vel[DIM]; + float vel[3]; /* acceleration. */ - float acc[DIM]; + float acc[3]; /* entropy. */ float entropy; @@ -74,10 +74,16 @@ struct logger_particle { float mass; /* unique id. */ - size_t id; + long long id; /* time of the record. */ double time; + + /* offset of the particle */ + size_t offset; + + /* The particle type */ + int type; }; /** diff --git a/logger/logger_python_wrapper.c b/logger/logger_python_wrapper.c index 07c87b4989896977c56ddff4df243a5310d393a7..ee8042df8e6dc9fb4914c51fbf729149e4e3a6cf 100644 --- a/logger/logger_python_wrapper.c +++ b/logger/logger_python_wrapper.c @@ -30,204 +30,125 @@ #include <stdio.h> #include <stdlib.h> +typedef struct { + PyObject_HEAD struct logger_particle part; +} PyLoggerParticle; + +static PyTypeObject PyLoggerParticle_Type; +const char *particle_name = "Particle"; + +PyArray_Descr *logger_particle_descr; + /** - * @brief load data from the offset without any interpolation + * @brief load data from the index files. * - * <b>offset</b> PyArrayObject list of offset for each particle. + * <b>basename</b> Base name of the logger files. * - * <b>filename</b> string filename of the log file. + * <b>time</b> The time requested. * * <b>verbose</b> Verbose level. * * <b>returns</b> dictionnary containing the data read. */ -static PyObject *loadFromIndex(__attribute__((unused)) PyObject *self, - PyObject *args) { +static PyObject *loadSnapshotAtTime(__attribute__((unused)) PyObject *self, + PyObject *args) { - /* input variables. */ - PyArrayObject *offset = NULL; - char *filename = NULL; + /* declare variables. */ + char *basename = NULL; - /* output variables. */ - PyArrayObject *pos = NULL; - PyArrayObject *vel = NULL; - PyArrayObject *acc = NULL; - PyArrayObject *entropy = NULL; - PyArrayObject *h_sph = NULL; - PyArrayObject *rho = NULL; - PyArrayObject *mass = NULL; - PyArrayObject *id = NULL; - - size_t time_offset; + double time = 0; int verbose = 2; /* parse arguments. */ - if (!PyArg_ParseTuple(args, "OsL|i", &offset, &filename, &time_offset, - &verbose)) - return NULL; - - if (!PyArray_Check(offset)) { - error("Offset is not a numpy array."); - } - if (PyArray_NDIM(offset) != 1) { - error("Offset is not a 1 dimensional array."); - } - if (PyArray_TYPE(offset) != NPY_UINT64) { - error("Offset does not contain unsigned int."); - } + if (!PyArg_ParseTuple(args, "sd|i", &basename, &time, &verbose)) return NULL; /* initialize the reader. */ struct logger_reader reader; - logger_reader_init(&reader, filename, verbose); - struct header *h = &reader.log.header; + logger_reader_init(&reader, basename, verbose); - /* init array. */ - npy_intp dim[2]; - dim[0] = PyArray_DIMS(offset)[0]; - dim[1] = DIM; + if (verbose > 1) message("Reading particles."); - /* Get required time. */ - double time = time_array_get_time(&reader.log.times, time_offset); + /* Number of particles in the index files */ + npy_intp n_tot = 0; - /* init output. */ - if (header_get_field_index(h, "positions") != -1) { - pos = (PyArrayObject *)PyArray_SimpleNew(2, dim, NPY_DOUBLE); - } + /* Set the reading time */ + logger_reader_set_time(&reader, time); - if (header_get_field_index(h, "velocities") != -1) { - vel = (PyArrayObject *)PyArray_SimpleNew(2, dim, NPY_FLOAT); + /* Get the number of particles */ + int n_type = 0; + const uint64_t *n_parts = + logger_reader_get_number_particles(&reader, &n_type); + for (int i = 0; i < n_type; i++) { + n_tot += n_parts[i]; } - if (header_get_field_index(h, "accelerations") != -1) { - acc = (PyArrayObject *)PyArray_SimpleNew(2, dim, NPY_FLOAT); - } - - if (header_get_field_index(h, "entropy") != -1) { - entropy = - (PyArrayObject *)PyArray_SimpleNew(1, PyArray_DIMS(offset), NPY_FLOAT); - } +#ifdef SWIFT_DEBUG_CHECKS + message("Found %lu particles", n_tot); +#endif // SWIFT_DEBUG_CHECKS - if (header_get_field_index(h, "smoothing length") != -1) { - h_sph = - (PyArrayObject *)PyArray_SimpleNew(1, PyArray_DIMS(offset), NPY_FLOAT); - } + /* Allocate the output memory */ + PyArrayObject *out = (PyArrayObject *)PyArray_SimpleNewFromDescr( + 1, &n_tot, logger_particle_descr); - if (header_get_field_index(h, "density") != -1) { - rho = - (PyArrayObject *)PyArray_SimpleNew(1, PyArray_DIMS(offset), NPY_FLOAT); - } + /* Reference is stolen, therefore need to take it into account */ + Py_INCREF(logger_particle_descr); - if (header_get_field_index(h, "consts") != -1) { - mass = - (PyArrayObject *)PyArray_SimpleNew(1, PyArray_DIMS(offset), NPY_FLOAT); - id = (PyArrayObject *)PyArray_SimpleNew(1, PyArray_DIMS(offset), NPY_ULONG); - } + void *data = PyArray_DATA(out); + /* Allows to use threads */ + Py_BEGIN_ALLOW_THREADS; - if (verbose > 1) message("Reading particles."); + /* Read the particle. */ + logger_reader_read_all_particles(&reader, time, logger_reader_const, data, + n_tot); - /* loop over all particles. */ - for (npy_intp i = 0; i < PyArray_DIMS(offset)[0]; i++) { - struct logger_particle part; - - /* Get the offset. */ - size_t offset_particle = *(size_t *)PyArray_GETPTR1(offset, i); - - /* Read the particle. */ - logger_particle_read(&part, &reader, offset_particle, time, - logger_reader_lin); - - double *dtmp; - float *ftmp; - size_t *stmp; - - /* copy the data. */ - for (size_t k = 0; k < DIM; k++) { - if (pos) { - dtmp = PyArray_GETPTR2(pos, i, k); - *dtmp = part.pos[k]; - } - - if (vel) { - ftmp = PyArray_GETPTR2(vel, i, k); - *ftmp = part.vel[k]; - } - - if (acc) { - ftmp = PyArray_GETPTR2(acc, i, k); - *ftmp = part.acc[k]; - } - } - - if (entropy) { - ftmp = PyArray_GETPTR1(entropy, i); - *ftmp = part.entropy; - } - - if (rho) { - ftmp = PyArray_GETPTR1(rho, i); - *ftmp = part.density; - } - - if (h_sph) { - ftmp = PyArray_GETPTR1(h_sph, i); - *ftmp = part.h; - } - - if (mass) { - ftmp = PyArray_GETPTR1(mass, i); - *ftmp = part.mass; - } - - if (id) { - stmp = PyArray_GETPTR1(id, i); - *stmp = part.id; - } - } + /* No need of threads anymore */ + Py_END_ALLOW_THREADS; /* Free the memory. */ logger_reader_free(&reader); - /* construct return value. */ - PyObject *dict = PyDict_New(); - PyObject *key = PyUnicode_FromString("positions"); - PyDict_SetItem(dict, key, PyArray_Return(pos)); + return (PyObject *)out; +} - if (vel) { - key = PyUnicode_FromString("velocities"); - PyDict_SetItem(dict, key, PyArray_Return(vel)); - } +/** + * @brief Read the minimal and maximal time. + * + * <b>basename</b> Base name of the logger files. + * + * <b>verbose</b> Verbose level. + * + * <b>returns</b> tuple containing min and max time. + */ +static PyObject *getTimeLimits(__attribute__((unused)) PyObject *self, + PyObject *args) { - if (acc) { - key = PyUnicode_FromString("accelerations"); - PyDict_SetItem(dict, key, PyArray_Return(acc)); - } + /* declare variables. */ + char *basename = NULL; - if (entropy) { - key = PyUnicode_FromString("entropy"); - PyDict_SetItem(dict, key, PyArray_Return(entropy)); - } + int verbose = 2; - if (rho) { - key = PyUnicode_FromString("rho"); - PyDict_SetItem(dict, key, PyArray_Return(rho)); - } + /* parse arguments. */ + if (!PyArg_ParseTuple(args, "s|i", &basename, &verbose)) return NULL; - if (h_sph) { - key = PyUnicode_FromString("h_sph"); - PyDict_SetItem(dict, key, PyArray_Return(h_sph)); - } + /* initialize the reader. */ + struct logger_reader reader; + logger_reader_init(&reader, basename, verbose); - if (mass) { - key = PyUnicode_FromString("mass"); - PyDict_SetItem(dict, key, PyArray_Return(mass)); - } + if (verbose > 1) message("Reading time limits."); - if (id) { - key = PyUnicode_FromString("id"); - PyDict_SetItem(dict, key, PyArray_Return(id)); - } + /* Get the time limits */ + double time_min = logger_reader_get_time_begin(&reader); + double time_max = logger_reader_get_time_end(&reader); + + /* Free the memory. */ + logger_reader_free(&reader); + + /* Create the output */ + PyObject *out = PyTuple_New(2); + PyTuple_SetItem(out, 0, PyFloat_FromDouble(time_min)); + PyTuple_SetItem(out, 1, PyFloat_FromDouble(time_max)); - return dict; + return (PyObject *)out; } /** @@ -259,10 +180,40 @@ static PyObject *pyReverseOffset(__attribute__((unused)) PyObject *self, /* definition of the method table. */ static PyMethodDef libloggerMethods[] = { - {"loadFromIndex", loadFromIndex, METH_VARARGS, - "Load snapshot directly from the offset in an index file."}, + {"loadSnapshotAtTime", loadSnapshotAtTime, METH_VARARGS, + "Load a snapshot directly from the logger using the index files.\n\n" + "Parameters\n" + "----------\n\n" + "basename: str\n" + " The basename of the index files.\n\n" + "time: double\n" + " The (double) time of the snapshot.\n\n" + "verbose: int, optional\n" + " The verbose level of the loader.\n\n" + "Returns\n" + "-------\n\n" + "snapshot: dict\n" + " The full output generated for the whole file.\n"}, {"reverseOffset", pyReverseOffset, METH_VARARGS, - "Reverse the offset (from pointing backward to forward)."}, + "Reverse the offset (from pointing backward to forward).\n\n" + "Parameters\n" + "----------\n\n" + "filename: str\n" + " The filename of the log file.\n\n" + "verbose: int, optional\n" + " The verbose level of the loader.\n"}, + {"getTimeLimits", getTimeLimits, METH_VARARGS, + "Read the time limits of the simulation.\n\n" + "Parameters\n" + "----------\n\n" + "basename: str\n" + " The basename of the index files.\n\n" + "verbose: int, optional\n" + " The verbose level of the loader.\n\n" + "Returns\n" + "-------\n\n" + "times: tuple\n" + " time min, time max\n"}, {NULL, NULL, 0, NULL} /* Sentinel */ }; @@ -279,12 +230,114 @@ static struct PyModuleDef libloggermodule = { NULL /* m_free */ }; +#define CREATE_FIELD(fields, name, field_name, type) \ + ({ \ + PyObject *tuple = PyTuple_New(2); \ + PyTuple_SetItem(tuple, 0, (PyObject *)PyArray_DescrFromType(type)); \ + PyTuple_SetItem( \ + tuple, 1, \ + PyLong_FromSize_t(offsetof(struct logger_particle, field_name))); \ + PyDict_SetItem(fields, PyUnicode_FromString(name), tuple); \ + }) + +#define CREATE_FIELD_3D(fields, name, field_name, type) \ + ({ \ + /* Create the 3D descriptor */ \ + PyArray_Descr *vec = PyArray_DescrNewFromType(type); \ + vec->subarray = malloc(sizeof(PyArray_ArrayDescr)); \ + vec->subarray->base = PyArray_DescrFromType(type); \ + vec->subarray->shape = PyTuple_New(1); \ + PyTuple_SetItem(vec->subarray->shape, 0, PyLong_FromSize_t(3)); \ + \ + /* Create the field */ \ + PyObject *tuple = PyTuple_New(2); \ + PyTuple_SetItem(tuple, 0, (PyObject *)vec); \ + PyTuple_SetItem( \ + tuple, 1, \ + PyLong_FromSize_t(offsetof(struct logger_particle, field_name))); \ + PyDict_SetItem(fields, PyUnicode_FromString(name), tuple); \ + }) + +void pylogger_particle_define_typeobject(void) { + + PyLoggerParticle_Type.tp_name = particle_name; + PyLoggerParticle_Type.tp_print = NULL; + PyType_Ready(&PyLoggerParticle_Type); +} + +void pylogger_particle_define_descr(void) { + /* Generate list of field names */ + PyObject *names = PyTuple_New(9); + PyTuple_SetItem(names, 0, PyUnicode_FromString("positions")); + PyTuple_SetItem(names, 1, PyUnicode_FromString("velocities")); + PyTuple_SetItem(names, 2, PyUnicode_FromString("accelerations")); + PyTuple_SetItem(names, 3, PyUnicode_FromString("entropies")); + PyTuple_SetItem(names, 4, PyUnicode_FromString("smoothing_lengths")); + PyTuple_SetItem(names, 5, PyUnicode_FromString("densities")); + PyTuple_SetItem(names, 6, PyUnicode_FromString("masses")); + PyTuple_SetItem(names, 7, PyUnicode_FromString("ids")); + PyTuple_SetItem(names, 8, PyUnicode_FromString("times")); + + /* Generate list of fields */ + PyObject *fields = PyDict_New(); + CREATE_FIELD_3D(fields, "positions", pos, NPY_DOUBLE); + CREATE_FIELD_3D(fields, "velocities", vel, NPY_FLOAT32); + CREATE_FIELD_3D(fields, "accelerations", acc, NPY_FLOAT32); + CREATE_FIELD(fields, "entropies", entropy, NPY_FLOAT32); + CREATE_FIELD(fields, "smoothing_lengths", h, NPY_FLOAT32); + CREATE_FIELD(fields, "densities", density, NPY_FLOAT32); + CREATE_FIELD(fields, "masses", mass, NPY_FLOAT32); + CREATE_FIELD(fields, "ids", id, NPY_LONGLONG); + CREATE_FIELD(fields, "times", time, NPY_DOUBLE); + + /* Generate descriptor */ + logger_particle_descr = PyObject_New(PyArray_Descr, &PyArrayDescr_Type); + logger_particle_descr->typeobj = &PyLoggerParticle_Type; + // V if for an arbitrary kind of array + logger_particle_descr->kind = 'V'; + // Not well documented (seems any value is fine) + logger_particle_descr->type = 'v'; + // Native byte ordering + logger_particle_descr->byteorder = '='; + // Flags + logger_particle_descr->flags = NPY_USE_GETITEM | NPY_USE_SETITEM; + // id of the data type (assigned automatically) + logger_particle_descr->type_num = 0; + // Size of an element (using more size than required in order to log + // everything) + logger_particle_descr->elsize = sizeof(struct logger_particle); + // alignment (doc magic) + logger_particle_descr->alignment = offsetof( + struct { + char c; + struct logger_particle v; + }, + v); + // no subarray + logger_particle_descr->subarray = NULL; + // functions + logger_particle_descr->f = NULL; + // Meta data + logger_particle_descr->metadata = NULL; + logger_particle_descr->c_metadata = NULL; + logger_particle_descr->names = names; + logger_particle_descr->fields = fields; +} + PyMODINIT_FUNC PyInit_liblogger(void) { PyObject *m; m = PyModule_Create(&libloggermodule); if (m == NULL) return NULL; + /* Deal with SWIFT clock */ + clocks_set_cpufreq(0); + import_array(); + /* Define the type object */ + pylogger_particle_define_typeobject(); + + /* Define the descr of the logger_particle */ + pylogger_particle_define_descr(); return m; } diff --git a/logger/logger_reader.c b/logger/logger_reader.c index 0954b9c5a8e56213de4d5b2a445aeeb9105e327c..854cf084e1d6c9c6fa5b066ce83b7cec5ad820ad 100644 --- a/logger/logger_reader.c +++ b/logger/logger_reader.c @@ -17,29 +17,98 @@ * ******************************************************************************/ +/* Include corresponding header */ #include "logger_reader.h" +/* Include standard library */ +#include <sys/sysinfo.h> +#include <unistd.h> + +/* Include local headers */ +#include "threadpool.h" + +#define nr_threads get_nprocs() + /** * @brief Initialize the reader. * * @param reader The #logger_reader. - * @param filename The log filename. + * @param basename The basename of the logger files. * @param verbose The verbose level. */ -void logger_reader_init(struct logger_reader *reader, char *filename, +void logger_reader_init(struct logger_reader *reader, const char *basename, int verbose) { if (verbose > 1) message("Initializing the reader."); + /* Set the variable to the default values */ + reader->time.time = -1.; + reader->time.int_time = 0; + reader->time.time_offset = 0; + + /* Copy the base name */ + strcpy(reader->basename, basename); + /* Initialize the reader variables. */ reader->verbose = verbose; + /* Generate the logfile filename */ + char logfile_name[STRING_SIZE]; + sprintf(logfile_name, "%s.dump", basename); + /* Initialize the log file. */ - logger_logfile_init_from_file(&reader->log, filename, reader, + logger_logfile_init_from_file(&reader->log, logfile_name, reader, /* only_header */ 0); + /* Initialize the index files */ + logger_reader_init_index(reader); + if (verbose > 1) message("Initialization done."); } +/** + * @brief Initialize the index part of the reader. + * + * @param reader The #logger_reader. + */ +void logger_reader_init_index(struct logger_reader *reader) { + /* Initialize the logger_index */ + logger_index_init(&reader->index.index, reader); + + /* Count the number of files */ + int count = 0; + while (1) { + char filename[STRING_SIZE + 50]; + sprintf(filename, "%s_%04i.index", reader->basename, count); + + /* Check if file exists */ + if (access(filename, F_OK) != -1) { + count++; + } else { + break; + } + } + + reader->index.n_files = count; + + /* Initialize the arrays */ + reader->index.times = (double *)malloc(count * sizeof(double)); + reader->index.int_times = + (integertime_t *)malloc(count * sizeof(integertime_t)); + + /* Get the information contained in the headers */ + for (int i = 0; i < reader->index.n_files; i++) { + char filename[STRING_SIZE + 50]; + sprintf(filename, "%s_%04i.index", reader->basename, i); + + /* Read the header */ + logger_index_read_header(&reader->index.index, filename); + + /* Save the required information */ + reader->index.times[i] = reader->index.index.time; + reader->index.int_times[i] = reader->index.index.integer_time; + } +} + /** * @brief Free the reader. * @@ -48,6 +117,10 @@ void logger_reader_init(struct logger_reader *reader, char *filename, void logger_reader_free(struct logger_reader *reader) { /* Free the log. */ logger_logfile_free(&reader->log); + + if (reader->time.time != -1.) { + logger_index_free(&reader->index.index); + } } /** @@ -69,7 +142,8 @@ size_t reader_read_record(struct logger_reader *reader, /* Read mask to find out if timestamp or particle. */ size_t mask = 0; - logger_loader_io_read_mask(&log->header, log->log.map + offset, &mask, NULL); + logger_loader_io_read_mask(&log->header, (char *)log->log.map + offset, &mask, + NULL); /* Check if timestamp or not. */ int ind = header_get_field_index(&log->header, "timestamp"); @@ -88,3 +162,301 @@ size_t reader_read_record(struct logger_reader *reader, return offset; } + +/** + * @brief Set the reader to a given time and read the correct index file. + * + * @param reader The #logger_reader. + * @param time The requested time. + */ +void logger_reader_set_time(struct logger_reader *reader, double time) { + /* Set the time */ + reader->time.time = time; + + /* Find the correct index */ + unsigned int left = 0; + unsigned int right = reader->index.n_files - 1; + + while (left != right) { + /* Do a ceil - division */ + unsigned int m = (left + right + 1) / 2; + if (reader->index.times[m] > time) { + right = m - 1; + } else { + left = m; + } + } + + /* Generate the filename */ + char filename[STRING_SIZE + 50]; + sprintf(filename, "%s_%04u.index", reader->basename, left); + + /* Check if the file is already mapped */ + if (reader->index.index.index.map != NULL) { + logger_index_free(&reader->index.index); + } + + /* Read the file */ + logger_index_read_header(&reader->index.index, filename); + logger_index_map_file(&reader->index.index, filename, /* sorted */ 1); + + /* Get the offset of the time chunk */ + size_t ind = time_array_get_index_from_time(&reader->log.times, time); + + /* Check if we requested exactly a time step */ + if (reader->log.times.records[ind].time != time) { + /* In order to interpolate, we need to be above and not below the time */ + ind += 1; + } + + /* Save the values */ + reader->time.index = ind; + reader->time.int_time = reader->log.times.records[ind].int_time; + reader->time.time_offset = reader->log.times.records[ind].offset; +} + +/** + * @brief Provides the number of particle (per type) from the index file. + * + * @param reader The #logger_reader. + * @param n_type (output) The number of particle type possible. + * + * @return For each type possible, the number of particle. + */ +const uint64_t *logger_reader_get_number_particles(struct logger_reader *reader, + int *n_type) { + *n_type = swift_type_count; + return reader->index.index.nparts; +} + +struct extra_data_read { + struct logger_reader *reader; + struct logger_particle *parts; + struct index_data *data; + enum logger_reader_type type; +}; + +/** + * @brief Mapper function of logger_reader_read_all_particles(). + * + * @param map_data The array of #logger_particle. + * @param num_elements The number of element to process. + * @param extra_data The #extra_data_read. + */ +void logger_reader_read_all_particles_mapper(void *map_data, int num_elements, + void *extra_data) { + + struct logger_particle *parts = (struct logger_particle *)map_data; + struct extra_data_read *read = (struct extra_data_read *)extra_data; + const struct logger_reader *reader = read->reader; + struct index_data *data = read->data + (parts - read->parts); + + const uint64_t *nparts = reader->index.index.nparts; + const size_t shift = parts - read->parts; + + /* Read the particles */ + for (int i = 0; i < num_elements; i++) { + const size_t part_ind = shift + i; + + /* Get the offset */ + size_t prev_offset = data[i].offset; + size_t next_offset = prev_offset; + +#ifdef SWIFT_DEBUG_CHECKS + /* check with the offset of the next timestamp. + * (the sentinel protects against overflow) + */ + const size_t ind = reader->time.index + 1; + if (prev_offset >= reader->log.times.records[ind].offset) { + error("An offset is out of range (%zi > %zi).", prev_offset, + reader->log.times.records[ind].offset); + } +#endif + + while (next_offset < reader->time.time_offset) { + prev_offset = next_offset; + int test = tools_get_next_record(&reader->log.header, reader->log.log.map, + &next_offset, reader->log.log.mmap_size); + + if (test == -1) { + size_t mask = 0; + logger_loader_io_read_mask(&reader->log.header, + (char *)reader->log.log.map + prev_offset, + &mask, &next_offset); + error( + "Trying to get a particle without next record (mask: %zi, diff " + "offset: %zi)", + mask, next_offset); + } + } + + /* Read the particle */ + logger_particle_read(&parts[i], reader, prev_offset, reader->time.time, + read->type); + + /* Set the type */ + size_t count = 0; + for (int ptype = 0; ptype < swift_type_count; ptype++) { + count += nparts[ptype]; + if (part_ind < count) { + parts[i].type = ptype; + break; + } + } + } +} + +/** + * @brief Read all the particles from the index file. + * + * @param reader The #logger_reader. + * @param time The requested time for the particle. + * @param interp_type The type of interpolation. + * @param parts The array of particles to use. + * @param n_tot The total number of particles + */ +void logger_reader_read_all_particles(struct logger_reader *reader, double time, + enum logger_reader_type interp_type, + struct logger_particle *parts, + size_t n_tot) { + + /* Initialize the thread pool */ + struct threadpool threadpool; + threadpool_init(&threadpool, nr_threads); + + /* Shortcut to some structures */ + struct logger_index *index = &reader->index.index; + + /* Get the correct index file */ + logger_reader_set_time(reader, time); + struct index_data *data = logger_index_get_data(index, 0); + + /* Read the particles */ + struct extra_data_read read; + read.reader = reader; + read.parts = parts; + read.data = data; + read.type = interp_type; + threadpool_map(&threadpool, logger_reader_read_all_particles_mapper, parts, + n_tot, sizeof(struct logger_particle), 0, &read); + + /* Cleanup the threadpool */ + threadpool_clean(&threadpool); +} + +/** + * @brief Get the simulation initial time. + * + * @param reader The #logger_reader. + * + * @return The initial time + */ +double logger_reader_get_time_begin(struct logger_reader *reader) { + return reader->log.times.records[0].time; +} + +/** + * @brief Get the simulation final time. + * + * @param reader The #logger_reader. + * + * @return The final time + */ +double logger_reader_get_time_end(struct logger_reader *reader) { + const size_t ind = reader->log.times.size; + return reader->log.times.records[ind - 1].time; +} + +/** + * @brief Get the offset of the last timestamp before a given time. + * + * @param reader The #logger_reader. + * @param time The requested time. + * + * @return The offset of the timestamp. + */ +size_t logger_reader_get_next_offset_from_time(struct logger_reader *reader, + double time) { + size_t ind = time_array_get_index_from_time(&reader->log.times, time); + return reader->log.times.records[ind + 1].offset; +} + +/** + * @brief Get the two particle records around the requested time. + * + * @param reader The #logger_reader. + * @param prev (in) A record before the requested time. (out) The last record + * before the time. + * @param next (out) The first record after the requested time. + * @param time_offset The offset of the requested time. + */ +void logger_reader_get_next_particle(struct logger_reader *reader, + struct logger_particle *prev, + struct logger_particle *next, + size_t time_offset) { + + void *map = reader->log.log.map; + size_t prev_offset = prev->offset; + size_t next_offset = 0; + + /* Get the mask index of the special flags */ + const int spec_flag_ind = + header_get_field_index(&reader->log.header, "special flags"); + if (spec_flag_ind < -1) { + error("The logfile does not contain the special flags field."); + } + + /* Keep the type in memory */ + const int prev_type = prev->type; + int new_type = -1; + + while (1) { + /* Read the offset to the next particle */ + size_t mask = 0; + logger_loader_io_read_mask(&reader->log.header, (char *)map + prev_offset, + &mask, &next_offset); + + /* Check if something special happened */ + if (mask & reader->log.header.masks[spec_flag_ind].mask) { + struct logger_particle tmp; + logger_particle_read(&tmp, reader, prev_offset, /* Time */ -1, + logger_reader_const); + new_type = tmp.type; + } + + /* Are we at the end of the file? */ + if (next_offset == 0) { + time_array_print(&reader->log.times); + error("End of file for offset %zi", prev_offset); + } + + next_offset += prev_offset; + + /* Have we found the next particle? */ + if (next_offset > time_offset) { + break; + } + + /* Update the previous offset */ + prev_offset = next_offset; + } + + /* Read the previous offset if required */ + if (prev_offset != prev->offset) { + logger_particle_read(prev, reader, prev_offset, /* Time */ 0, + logger_reader_const); + } + + /* Read the next particle */ + logger_particle_read(next, reader, next_offset, /* Time */ 0, + logger_reader_const); + + /* Set the types */ + if (new_type == -1) { + next->type = prev_type; + prev->type = prev_type; + } else { + next->type = new_type; + prev->type = new_type; + } +} diff --git a/logger/logger_reader.h b/logger/logger_reader.h index 124d271f57587a26dbfb59299678f0ce5cfbdf79..95a8ab8ef0b800e77d6de2bb483c1b4cd1092a3b 100644 --- a/logger/logger_reader.h +++ b/logger/logger_reader.h @@ -27,7 +27,7 @@ * files. * * The <b>parameter file</b> contains all the information related to the code - * (e.g. boxsize). + * (e.g. boxsize, scheme, ...). * * The <b>index files</b> are not mandatory files that indicates the position of * the particles in the log file at a given time step. They are useful to @@ -47,6 +47,7 @@ #ifndef LOGGER_LOGGER_READER_H #define LOGGER_LOGGER_READER_H +#include "logger_index.h" #include "logger_loader_io.h" #include "logger_logfile.h" #include "logger_particle.h" @@ -62,20 +63,71 @@ */ struct logger_reader { - /* Time of each index file. #TODO */ - double *times; + /* Base name of the files */ + char basename[STRING_SIZE]; + + struct { + /* Information contained in the index file */ + struct logger_index index; + + /* Number of index files */ + int n_files; + + /* Time of each index file */ + double *times; + + /* Integer time of each index file */ + integertime_t *int_times; + } index; /* Informations contained in the file header. */ struct logger_logfile log; + /* Information about the current time */ + struct { + /* Double time */ + double time; + + /* Integer time */ + integertime_t int_time; + + /* Offset of the chunk */ + size_t time_offset; + + /* Index of the element in the time array */ + size_t index; + } time; + /* Level of verbosity. */ int verbose; }; -void logger_reader_init(struct logger_reader *reader, char *filename, +void logger_reader_init_index(struct logger_reader *reader); +void logger_reader_init(struct logger_reader *reader, const char *basename, int verbose); void logger_reader_free(struct logger_reader *reader); size_t reader_read_record(struct logger_reader *reader, struct logger_particle *lp, double *time, int *is_particle, size_t offset); + +void logger_reader_set_time(struct logger_reader *reader, double time); + +double logger_reader_get_time_begin(struct logger_reader *reader); +double logger_reader_get_time_end(struct logger_reader *reader); +size_t logger_reader_get_next_offset_from_time(struct logger_reader *reader, + double time); +void logger_reader_get_next_particle(struct logger_reader *reader, + struct logger_particle *prev, + struct logger_particle *next, size_t time); + +const uint64_t *logger_reader_get_number_particles(struct logger_reader *reader, + int *n_type); + +void logger_reader_read_all_particles_mapper(void *map_data, int num_elements, + void *extra_data); +void logger_reader_read_all_particles(struct logger_reader *reader, double time, + enum logger_reader_type inter_type, + struct logger_particle *parts, + size_t n_tot); + #endif // LOGGER_LOGGER_READER_H diff --git a/logger/logger_time.c b/logger/logger_time.c index d2c6ebc3f9e3171ba7fdec6c6a63eb23d7001df6..e0eb8080f53f27343ff030ada6aa487e62cc9dd3 100644 --- a/logger/logger_time.c +++ b/logger/logger_time.c @@ -92,7 +92,8 @@ size_t time_read(integertime_t *int_time, double *time, *time = 0; /* read record header. */ - map = logger_loader_io_read_mask(h, map + offset, &mask, &prev_offset); + map = + logger_loader_io_read_mask(h, (char *)map + offset, &mask, &prev_offset); #ifdef SWIFT_DEBUG_CHECKS @@ -109,7 +110,7 @@ size_t time_read(integertime_t *int_time, double *time, logger_loader_io_read_data(map, sizeof(unsigned long long int), int_time); map = logger_loader_io_read_data(map, sizeof(double), time); - return map - h->log->log.map; + return (char *)map - (char *)h->log->log.map; } /** @@ -131,7 +132,7 @@ size_t time_offset_first_record(const struct header *h) { if (i == -1) error("Time mask not present in the log file header."); size_t mask = 0; - logger_loader_io_read_mask(h, map + offset, &mask, NULL); + logger_loader_io_read_mask(h, (char *)map + offset, &mask, NULL); if (mask != h->masks[i].mask) error("Log file should begin by timestep."); @@ -166,9 +167,9 @@ void time_array_populate(struct time_array *t, struct logger_logfile *log) { double time = 0; /* get file size. */ - size_t file_size = log->log.file_size; + size_t file_size = log->log.mmap_size; - /* get first time stamp. */ + /* get first timestamp. */ size_t offset = time_offset_first_record(&log->header); while (offset < file_size) { /* read current time record and store it. */ @@ -178,7 +179,7 @@ void time_array_populate(struct time_array *t, struct logger_logfile *log) { /* get next record. */ int test = tools_get_next_record(&log->header, log->log.map, &offset, - log->log.file_size); + log->log.mmap_size); if (test == -1) break; } } @@ -224,14 +225,16 @@ size_t time_array_get_index(const struct time_array *t, const size_t offset) { if (!t) error("NULL pointer."); if (offset < t->records[0].offset || offset > t->records[t->size - 1].offset) - error("Offset outside of range."); + error("Offset outside of range. %zi > %zi > %zi", + t->records[t->size - 1].offset, offset, t->records[0].offset); #endif - /* left will contain the index at the end of the loop */ + /* right will contain the index at the end of the loop */ size_t left = 0; size_t right = t->size - 1; /* Find the time_array with the correct offset through a bisection method. */ + // TODO use interpolation search (same for the other binary searches) while (left <= right) { size_t center = (left + right) / 2; const size_t offset_center = t->records[center].offset; @@ -245,6 +248,71 @@ size_t time_array_get_index(const struct time_array *t, const size_t offset) { } } + /* Avoid the sentinel */ + if (right == t->size - 1) { + right = right - 1; + } + +#ifdef SWIFT_DEBUG_CHECKS + if (t->records[right].offset > offset || + t->records[right + 1].offset <= offset) { + error("Found the wrong element"); + } + +#endif + + return right; +} + +/** + * @brief Find the index of the last time record written before a given time. + * + * @param t #time_array to access. + * @param time The time requested. + * + * @return The index of the last time record. + */ +size_t time_array_get_index_from_time(const struct time_array *t, + const double time) { + +#ifdef SWIFT_DEBUG_CHECKS + if (!t) error("NULL pointer."); + + if (time < t->records[0].time || time > t->records[t->size - 1].time) + error("Time outside of range (%g > %g).", time, + t->records[t->size - 1].time); +#endif + + /* right will contain the index at the end of the loop */ + size_t left = 0; + size_t right = t->size - 1; + + /* Find the time_array with the correct time through a bisection method. */ + while (left <= right) { + size_t center = (left + right) / 2; + const double time_center = t->records[center].time; + + if (time > time_center) { + left = center + 1; + } else if (time < time_center) { + right = center - 1; + } else { + return center; + } + } + + /* Avoid the sentinel */ + if (right == t->size - 1) { + right = right - 1; + } + +#ifdef SWIFT_DEBUG_CHECKS + if (t->records[right].time > time || t->records[right + 1].time <= time) { + error("Found the wrong element"); + } + +#endif + return right; } @@ -269,7 +337,11 @@ void time_array_free(struct time_array *t) { * @param t #time_array to print */ void time_array_print(const struct time_array *t) { - const size_t threshold = 4; +#ifdef SWIFT_DEBUG_CHECKS + const size_t threshold = 1000; +#else + const size_t threshold = 5; +#endif size_t n = t->size; size_t up_threshold = n - threshold; @@ -281,7 +353,7 @@ void time_array_print(const struct time_array *t) { for (size_t i = 1; i < n; i++) { /* Skip the times at the center of the array. */ if (i < threshold || i > up_threshold) - printf(", %lli (%g)", t->records[i].int_time, t->records[i].time); + printf(", %zi (%g)", t->records[i].offset, t->records[i].time); if (i == threshold) printf(", ..."); } diff --git a/logger/logger_time.h b/logger/logger_time.h index b27abffb9c1b3aa02c82c1739d1206b43f3ac431..9094f700da687a2699ba54a061ea049189a6572a 100644 --- a/logger/logger_time.h +++ b/logger/logger_time.h @@ -84,6 +84,9 @@ double time_array_get_time(const struct time_array *t, const size_t offset); size_t time_array_get_index(const struct time_array *t, const size_t offset); +size_t time_array_get_index_from_time(const struct time_array *t, + const double time); + void time_array_free(struct time_array *t); void time_array_print(const struct time_array *t); diff --git a/logger/logger_tools.c b/logger/logger_tools.c index a9a6ecfcb0acf72b11898d00fdfeff90fd70406d..d145934bc036357bb5d9ca9a60ec9cd4c8cb2904 100644 --- a/logger/logger_tools.c +++ b/logger/logger_tools.c @@ -60,7 +60,8 @@ int _tools_get_next_record_forward(const struct header *h, void *map, size_t diff_offset = 0; /* Read the offset. */ - map = logger_loader_io_read_mask(h, map + *offset, NULL, &diff_offset); + map = + logger_loader_io_read_mask(h, (char *)map + *offset, NULL, &diff_offset); if (diff_offset == 0) return -1; @@ -91,7 +92,8 @@ int _tools_get_next_record_backward(const struct header *h, void *map, while (current_offset < file_size) { size_t mask = 0; size_t prev_offset; - logger_loader_io_read_mask(h, map + current_offset, &mask, &prev_offset); + logger_loader_io_read_mask(h, (char *)map + current_offset, &mask, + &prev_offset); prev_offset = current_offset - prev_offset - record_header; if (*offset == prev_offset) { @@ -123,16 +125,17 @@ size_t tools_reverse_offset(const struct header *h, void *file_map, void *map = file_map; /* read mask + offset. */ - map = logger_loader_io_read_mask(h, map + offset, &mask, &prev_offset); + map = + logger_loader_io_read_mask(h, (char *)map + offset, &mask, &prev_offset); /* write offset of zero (in case it is the last record). */ const size_t zero = 0; - map -= LOGGER_OFFSET_SIZE; + map = (char *)map - LOGGER_OFFSET_SIZE; map = logger_loader_io_write_data(map, LOGGER_OFFSET_SIZE, &zero); /* set offset after current record. */ - map += header_get_record_size_from_mask(h, mask); - size_t after_current_record = (size_t)(map - file_map); + map = (char *)map + header_get_record_size_from_mask(h, mask); + size_t after_current_record = (size_t)((char *)map - (char *)file_map); /* first records do not have a previous partner. */ if (prev_offset == cur_offset) return after_current_record; @@ -142,16 +145,17 @@ size_t tools_reverse_offset(const struct header *h, void *file_map, cur_offset); /* modify previous offset. */ - map = file_map + cur_offset - prev_offset + LOGGER_MASK_SIZE; + map = (char *)file_map + cur_offset - prev_offset + LOGGER_MASK_SIZE; map = logger_loader_io_write_data(map, LOGGER_OFFSET_SIZE, &prev_offset); #ifdef SWIFT_DEBUG_CHECKS size_t prev_mask = 0; - map -= LOGGER_MASK_SIZE + LOGGER_OFFSET_SIZE; + map = (char *)map - LOGGER_MASK_SIZE - LOGGER_OFFSET_SIZE; logger_loader_io_read_mask(h, map, &prev_mask, NULL); - /* Check if we are not mixing time stamp and particles */ - if ((prev_mask != 128 && mask == 128) || (prev_mask == 128 && mask != 128)) + /* Check if we are not mixing timestamp and particles */ + if ((prev_mask != h->timestamp_mask && mask == h->timestamp_mask) || + (prev_mask == h->timestamp_mask && mask != h->timestamp_mask)) error("Unexpected mask: %lu, got %lu.", mask, prev_mask); #endif // SWIFT_DEBUG_CHECKS @@ -178,7 +182,7 @@ size_t tools_check_record_consistency(const struct logger_reader *reader, const struct header *h = &reader->log.header; void *file_init = reader->log.log.map; - void *map = file_init + offset; + void *map = (char *)file_init + offset; size_t mask; size_t pointed_offset; @@ -199,33 +203,35 @@ size_t tools_check_record_consistency(const struct logger_reader *reader, } /* set offset after current record. */ - map += header_get_record_size_from_mask(h, mask); + map = (char *)+header_get_record_size_from_mask(h, mask); if (pointed_offset == offset || pointed_offset == 0) - return (size_t)(map - file_init); + return (size_t)((char *)map - (char *)file_init); /* read mask of the pointed record. */ size_t pointed_mask = 0; - logger_loader_io_read_mask(h, file_init + pointed_offset, &pointed_mask, - NULL); + logger_loader_io_read_mask(h, (char *)file_init + pointed_offset, + &pointed_mask, NULL); - /* check if not mixing time stamp and particles. */ - if ((pointed_mask != 128 && mask == 128) || - (pointed_mask == 128 && mask != 128)) + /* check if not mixing timestamp and particles. */ + if ((pointed_mask != h->timestamp_mask && mask == h->timestamp_mask) || + (pointed_mask == h->timestamp_mask && mask != h->timestamp_mask)) error("Error in the offset (mask %lu at %lu != %lu at %lu).", mask, offset, pointed_mask, pointed_offset); - if (pointed_mask == 128) return (size_t)(map - file_init); + if (pointed_mask == h->timestamp_mask) + return (size_t)((char *)map - (char *)file_init); struct logger_particle part; logger_particle_read(&part, reader, offset, 0, logger_reader_const); - size_t id = part.id; + long long id = part.id; logger_particle_read(&part, reader, pointed_offset, 0, logger_reader_const); - if (id != part.id) - error("Offset wrong, id incorrect (%lu != %lu) at %lu.", id, part.id, + if (id != part.id) { + error("Offset wrong, id incorrect (%lli != %lli) at %lu.", id, part.id, pointed_offset); + } - return (size_t)(map - file_init); + return (size_t)((char *)map - (char *)file_init); } diff --git a/logger/python/reader_example.py b/logger/python/reader_example.py deleted file mode 100644 index 6ace309c5b68b4fc4f1088b6206cd1ae3ccd69a5..0000000000000000000000000000000000000000 --- a/logger/python/reader_example.py +++ /dev/null @@ -1,55 +0,0 @@ -#!/usr/bin/env python3 -""" -Read a logger file by using an index. -Example: ./reader_example.py ../../examples/SedovBlast_3D/index.dump ../../examples/SedovBlast_3D/index_0005.hdf5 -""" -import sys -from h5py import File -import numpy as np -import matplotlib.pyplot as plt -sys.path.append("../.libs/") - -import liblogger as logger - -# Get filenames -if len(sys.argv) != 3: - print("WARNING missing arguments. Will use the default ones") - index = "../../examples/HydroTests/SedovBlast_3D/index_0002.hdf5" - dump = "../../examples/HydroTests/SedovBlast_3D/index.dump" -else: - index = sys.argv[-1] - dump = sys.argv[-2] - -# constant -offset_name = "PartType0/Offset" -header = "Header" -time_name = "Time Offset" - -# Read index file -with File(index, "r") as f: - if offset_name not in f: - raise Exception("Unable to find the offset dataset") - offset = f[offset_name][:] - - if header not in f: - raise Exception("Unable to find the header") - if time_name not in f[header].attrs: - raise Exception("Unable to find the time offset") - time_offset = f[header].attrs[time_name] - -# read dump -data = logger.loadFromIndex(offset, dump, time_offset) - -# Compute distance from center -pos = data["positions"] -center = pos.mean() -r2 = np.sum((pos - center)**2, axis=1) - -# plot entropy vs distance -plt.plot(np.sqrt(r2), data["entropy"], '.') - -plt.xlim(0., 0.5) -plt.ylim(-5, 50) -plt.xlabel("Radius") -plt.ylabel("Entropy") -plt.show() diff --git a/logger/quick_sort.c b/logger/quick_sort.c new file mode 100644 index 0000000000000000000000000000000000000000..a1b76c864bbdb6d66a2bc84cee0de03a05379b4d --- /dev/null +++ b/logger/quick_sort.c @@ -0,0 +1,125 @@ +/******************************************************************************* + * This file is part of SWIFT. + * Copyright (c) 2019 Loic Hausammann (loic.hausammann@epfl.ch) + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published + * by the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this program. If not, see <http://www.gnu.org/licenses/>. + * + ******************************************************************************/ + +/* Include corresponding header */ +#include "quick_sort.h" + +/* Include local headers */ +#include "logger_index.h" + +struct qstack { + int64_t lo; + int64_t hi; +}; + +/** + * @brief Sort the data with the quicksort according to the ids. + */ +void quick_sort(struct index_data *data, size_t N) { + int64_t qpos, i, j, lo, hi, imin, pivot; + struct index_data temp; + + /* Allocate a stack of operations */ + int stack_size = log(N) + 1; + struct qstack *qstack = + (struct qstack *)malloc(sizeof(struct qstack) * stack_size); + + /* Sort parts in decreasing order with quicksort */ + qstack[0].lo = 0; + qstack[0].hi = N - 1; + qpos = 0; + while (qpos >= 0) { + lo = qstack[qpos].lo; + hi = qstack[qpos].hi; + qpos -= 1; + /* Do we have a low number of element to sort? */ + if (hi - lo < 15) { + /* Sort the last elements. */ + for (i = lo; i < hi; i++) { + imin = i; + /* Find the minimal value. */ + for (j = i + 1; j <= hi; j++) + if (data[j].id < data[imin].id) imin = j; + /* Did we find the minimal value? */ + if (imin != i) { + /* Swap the elements. */ + temp = data[imin]; + data[imin] = data[i]; + data[i] = temp; + } + } + } else { + /* Select a pivot */ + pivot = data[(lo + hi) / 2].id; + i = lo; + j = hi; + /* Ensure that the elements before/after the pivot + are smaller/larger than the pivot. */ + while (i <= j) { + /* Find the first elements that do not respect + the order. */ + while (data[i].id < pivot) i++; + while (data[j].id > pivot) j--; + + /* Did we get two elements */ + if (i <= j) { + /* Are they different? */ + if (i < j) { + /* Swap them */ + temp = data[i]; + data[i] = data[j]; + data[j] = temp; + } + /* The two elements are good now */ + i += 1; + j -= 1; + } + } + /* Add the next operations to the stack. + * The order is important in order to decrease the stack size. + */ + if (j > (lo + hi) / 2) { + if (lo < j) { + qpos += 1; + qstack[qpos].lo = lo; + qstack[qpos].hi = j; + } + if (i < hi) { + qpos += 1; + qstack[qpos].lo = i; + qstack[qpos].hi = hi; + } + } else { + if (i < hi) { + qpos += 1; + qstack[qpos].lo = i; + qstack[qpos].hi = hi; + } + if (lo < j) { + qpos += 1; + qstack[qpos].lo = lo; + qstack[qpos].hi = j; + } + } + } + } + + /* Free the allocated memory */ + free(qstack); +} diff --git a/logger/quick_sort.h b/logger/quick_sort.h new file mode 100644 index 0000000000000000000000000000000000000000..57ed5779213d16cd6f67dc7cb4ecd8f86b9af2e6 --- /dev/null +++ b/logger/quick_sort.h @@ -0,0 +1,27 @@ +/******************************************************************************* + * This file is part of SWIFT. + * Copyright (c) 2019 Loic Hausammann (loic.hausammann@epfl.ch) + * + * 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 LOGGER_LOGGER_QUICK_SORT_H +#define LOGGER_LOGGER_QUICK_SORT_H + +#include "logger_index.h" + +void quick_sort(struct index_data *data, size_t N); + +#endif // LOGGER_LOGGER_QUICK_SORT_H diff --git a/logger/tests/Makefile.am b/logger/tests/Makefile.am index dd94462b8b98b0a089d0f959b81c603c29911a76..d5c88e234531e0f0685cd3fb73e6da61c513b9bb 100644 --- a/logger/tests/Makefile.am +++ b/logger/tests/Makefile.am @@ -17,13 +17,13 @@ # Add the source directory and the non-standard paths to the included library headers to CFLAGS AM_CFLAGS = -I$(top_srcdir)/src -I$(top_srcdir)/logger $(HDF5_CPPFLAGS) $(GSL_INCS) $(FFTW_INCS) -AM_LDFLAGS = ../../src/.libs/libswiftsim.a ../.libs/liblogger.a $(HDF5_LDFLAGS) $(HDF5_LIBS) $(FFTW_LIBS) $(TCMALLOC_LIBS) $(JEMALLOC_LIBS) $(TBBMALLOC_LIBS) $(GRACKLE_LIBS) $(GSL_LIBS) $(PROFILER_LIBS) +AM_LDFLAGS = ../../src/.libs/libswiftsim.a ../.libs/liblogger.a $(HDF5_LDFLAGS) $(HDF5_LIBS) $(FFTW_LIBS) $(TCMALLOC_LIBS) $(JEMALLOC_LIBS) $(TBBMALLOC_LIBS) $(GRACKLE_LIBS) $(GSL_LIBS) $(PROFILER_LIBS) -lswiftsim # List of programs and scripts to run in the test suite -TESTS = testLogfileHeader testLogfileReader testTimeArray +TESTS = testLogfileHeader testLogfileReader testTimeArray testQuickSort testVR # List of test programs to compile -check_PROGRAMS = testLogfileHeader testLogfileReader testTimeArray +check_PROGRAMS = testLogfileHeader testLogfileReader testTimeArray testQuickSort testVR # Rebuild tests when SWIFT is updated. $(check_PROGRAMS): ../../src/.libs/libswiftsim.a ../.libs/liblogger.a @@ -32,6 +32,8 @@ $(check_PROGRAMS): ../../src/.libs/libswiftsim.a ../.libs/liblogger.a testLogfileHeader_SOURCES = testLogfileHeader.c testLogfileReader_SOURCES = testLogfileReader.c testTimeArray_SOURCES = testTimeArray.c +testQuickSort_SOURCES = testQuickSort.c +testVR_SOURCES = testVR.c # Files necessary for distribution EXTRA_DIST = testLogfileHeader.yml testLogfileReader.yml diff --git a/logger/tests/generate_log.h b/logger/tests/generate_log.h new file mode 100644 index 0000000000000000000000000000000000000000..4ef753b0abd39ac72a722be66cc2e804b6d54c56 --- /dev/null +++ b/logger/tests/generate_log.h @@ -0,0 +1,209 @@ +/******************************************************************************* + * This file is part of SWIFT. + * Copyright (C) 2019 Loic Hausammann (loic.hausammann@epfl.ch) + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published + * by the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this program. If not, see <http://www.gnu.org/licenses/>. + * + ******************************************************************************/ + +/* Include config */ +#include "../../config.h" + +/* Local headers */ +#include "engine.h" +#include "hydro.h" +#include "logger.h" + +/* Not all the fields are written at every step. + * Here we define how often a few fields are written. + */ +#define period_rho 2 +#define period_h 4 +#define const_time_base 1e-4 + +/** + * @brief Generate the data of a bunch of particles. + * + * @param parts The list of particles. + * @param xparts The list of extra particles. + * @param nparts The number of particles. + */ +void generate_particles(struct part *parts, struct xpart *xparts, + size_t nparts) { + struct hydro_space hs; + + for (size_t i = 0; i < nparts; i++) { + /* Set internal energy. */ + hydro_set_init_internal_energy(&parts[i], 100); + + /* Initialize particle. */ + hydro_first_init_part(&parts[i], &xparts[i]); + hydro_init_part(&parts[i], &hs); + logger_part_data_init(&xparts[i].logger_data); + + for (int j = 0; j < 3; j++) { + parts[i].x[j] = 0; + parts[i].v[j] = (j == 0) ? -1 : 0; + parts[i].a_hydro[j] = (j == 1) ? 1e-2 : 0; + } + parts[i].h = 15; + parts[i].rho = 50; + parts[i].id = i; + hydro_set_mass(&parts[i], 1.5); + + /* Add time bin in order to skip particles. */ + parts[i].time_bin = (i % 10) + 1; + } +} + +/** Provides a integer time given the step number.*/ +integertime_t get_integer_time(int step) { return step; } + +/** Provides a double time given the step number. */ +double get_double_time(int step) { return step * const_time_base; } + +/** + * @brief Write a few particles during multiple time steps. + * + * As only the logger is tested, there is no need to really + * evolve the particles. + * + * @param log The #logger_writer. + * @param e The #engine. + */ +void write_particles(struct logger_writer *log, struct engine *e) { + + size_t nparts = e->total_nr_parts; + struct part *parts = e->s->parts; + struct xpart *xparts = e->s->xparts; + + const int number_steps = 100; + const int number_index = 5; + + /* Loop over all the steps. */ + for (int i = 0; i < number_steps; i++) { + e->time = get_double_time(i); + e->ti_current = get_integer_time(i); + /* Dump an index file if required */ + if (i % (number_steps / number_index) == number_index - 1) { + engine_dump_index(e); + } + integertime_t ti_int = get_integer_time(i); + double ti_double = get_double_time(i); + + /* Mark the current time step in the particle logger file. */ + logger_log_timestamp(log, ti_int, ti_double, &log->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(log, nparts, /* number gpart */ 0, 0); + + /* Loop over all the particles. */ + for (size_t j = 0; j < nparts; j++) { + + /* Skip some particles. */ + if (i % parts[j].time_bin != 0) continue; + + /* Write a time information to check that the correct particle is read. */ + parts[j].x[0] = i; + + /* Write this particle. */ + unsigned int mask = + logger_mask_data[logger_x].mask | logger_mask_data[logger_v].mask | + logger_mask_data[logger_a].mask | logger_mask_data[logger_u].mask | + logger_mask_data[logger_consts].mask; + + int number_particle_step = i / parts[j].time_bin; + + if (number_particle_step % period_h == 0) + mask |= logger_mask_data[logger_h].mask; + if (number_particle_step % period_rho == 0) + mask |= logger_mask_data[logger_rho].mask; + + logger_log_part(log, &parts[j], mask, &xparts[j].logger_data.last_offset, + /* special flags */ 0); + } + } +} + +void generate_log(struct swift_params *params, struct part *parts, + struct xpart *xparts, size_t nparts) { + /* Initialize the particles */ + generate_particles(parts, xparts, nparts); + + /* Initialize the writer */ + struct logger_writer log; + logger_init(&log, params); + + /* initialize the engine */ + struct engine e; + e.total_nr_parts = nparts; + e.total_nr_gparts = 0; + e.total_nr_sparts = 0; + e.total_nr_bparts = 0; + e.verbose = 1; + e.policy = 0; + e.ti_current = 0; + e.time = 0; + e.time_base = const_time_base; + e.time_begin = 0; + e.logger = &log; + threadpool_init(&e.threadpool, 1); + struct space s; + e.s = &s; + s.xparts = xparts; + s.parts = parts; + s.gparts = NULL; + s.nr_parts = nparts; + s.nr_gparts = 0; + s.nr_sparts = 0; + s.nr_bparts = 0; + s.nr_inhibited_parts = 0; + s.nr_inhibited_gparts = 0; + s.nr_inhibited_sparts = 0; + s.nr_inhibited_bparts = 0; + s.nr_extra_gparts = 0; + s.nr_extra_parts = 0; + s.nr_extra_sparts = 0; + s.nr_extra_bparts = 0; + + /* Write file header */ + logger_write_file_header(&log); + + /* Mark the current time step in the particle logger file. */ + logger_log_timestamp(&log, e.ti_current, e.time, &log.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(&log, nparts, /* number gpart */ 0, 0); + + /* Log all the particles before starting */ + logger_log_all(&log, &e); + engine_dump_index(&e); + + /* Write particles */ + write_particles(&log, &e); + + /* Write a sentinel timestamp */ + logger_log_timestamp(e.logger, e.ti_current, e.time, + &e.logger->timestamp_offset); + + /* Write all the particles at the end */ + logger_log_all(e.logger, &e); + + /* Write a sentinel timestamp */ + logger_log_timestamp(e.logger, e.ti_current, e.time, + &e.logger->timestamp_offset); + + /* Cleanup the memory */ + logger_free(&log); +} diff --git a/logger/tests/testLogfileHeader.c b/logger/tests/testLogfileHeader.c index 0f2c8a5df7942d50cbb641b99e3173a05fe1d539..6044ffae36c68066672e8279e0f5e65e2b40bafb 100644 --- a/logger/tests/testLogfileHeader.c +++ b/logger/tests/testLogfileHeader.c @@ -76,10 +76,10 @@ int main(int argc, char *argv[]) { assert(h->minor_version == logger_minor_version); message("Checking offset of first record"); - assert(h->offset_first_record == logfile->log.file_size); + assert(h->offset_first_record == logfile->log.mmap_size); message("Checking number of masks"); - assert(h->number_mask == logger_count_mask); + assert(h->masks_count == logger_count_mask); message("Checking masks"); for (int i = 0; i < logger_count_mask; i++) { diff --git a/logger/tests/testLogfileReader.c b/logger/tests/testLogfileReader.c index 751c6b7d628fcd1191e8deba9135cddd8cd04bf8..0741b7c3e58045480480b6a7da011b9da31b9ea8 100644 --- a/logger/tests/testLogfileReader.c +++ b/logger/tests/testLogfileReader.c @@ -17,116 +17,18 @@ * ******************************************************************************/ +/* Local header */ #include "logger_header.h" #include "logger_loader_io.h" #include "logger_particle.h" #include "logger_reader.h" #include "swift.h" -#define number_parts 100 -/* Not all the fields are written at every step. - * Here we define how often a few fields are written. - */ -#define period_rho 2 -#define period_h 4 - -/** - * @brief Initialize the particles. - * - * @param p The array of #part. - * @param xp The array of #xpart. - */ -void init_particles(struct part *p, struct xpart *xp) { - struct hydro_space hs; - - for (int i = 0; i < number_parts; i++) { - /* Set internal energy. */ - hydro_set_init_internal_energy(&p[i], 100); - - /* Initialize particle. */ - hydro_first_init_part(&p[i], &xp[i]); - hydro_init_part(&p[i], &hs); - - for (int j = 0; j < 3; j++) { - p[i].x[j] = i; - p[i].v[j] = (j == 0) ? -1 : 0; - p[i].a_hydro[j] = (j == 1) ? 1e-2 : 0; - } - p[i].h = 15; - p[i].rho = 50; - p[i].id = i; - hydro_set_mass(&p[i], 1.5); - xp[i].logger_data.last_offset = 0; - - /* Add time bin in order to skip particles. */ - p[i].time_bin = (i % 10) + 1; - } -} - -/** Provides a integer time given the step number.*/ -integertime_t get_integer_time(int step) { return step; } - -/** Provides a double time given the step number. */ -double get_double_time(int step) { - const double time_base = 1e-4; - return step * time_base; -} - -/** - * @brief Write a few particles during multiple time steps. - * - * As only the logger is tested, there is no need to really - * evolve the particles. - */ -void write_particles(struct logger_writer *log, struct part *parts, - struct xpart *xparts) { - - const int number_steps = 100; - - /* Loop over all the steps. */ - for (int i = 0; i < number_steps; i++) { - integertime_t ti_int = get_integer_time(i); - double ti_double = get_double_time(i); +/* Tests header */ +#include "generate_log.h" - /* Mark the current time step in the particle logger file. */ - logger_log_timestamp(log, ti_int, ti_double, &log->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(log, number_parts, /* number gpart */ 0, 0); - - /* Loop over all the particles. */ - for (int j = 0; j < number_parts; j++) { - - /* Skip some particles. */ - if (i % parts[j].time_bin != 0) continue; - - /* Write a time information to check that the correct particle is read. */ - parts[j].x[0] = i; - - /* Write this particle. */ - unsigned int mask = - logger_mask_data[logger_x].mask | logger_mask_data[logger_v].mask | - logger_mask_data[logger_a].mask | logger_mask_data[logger_u].mask | - logger_mask_data[logger_consts].mask; - - int number_particle_step = i / parts[j].time_bin; - - if (number_particle_step % period_h == 0) - mask |= logger_mask_data[logger_h].mask; - if (number_particle_step % period_rho == 0) - mask |= logger_mask_data[logger_rho].mask; - - logger_log_part(log, &parts[j], mask, &xparts[j].logger_data.last_offset); - } - - // TODO write index files. - } - - /* Mark the current time step in the particle logger file. */ - integertime_t ti_int = get_integer_time(number_steps); - double ti_double = get_double_time(number_steps); - logger_log_timestamp(log, ti_int, ti_double, &log->timestamp_offset); -} +#define number_parts 100 +#define max_step 99 /** Count the number of active particles. */ int get_number_active_particles(int step, struct part *p) { @@ -136,6 +38,7 @@ int get_number_active_particles(int step, struct part *p) { } return count; } + /** * @brief Check that the reader contains the correct data * @@ -155,18 +58,19 @@ void check_data(struct logger_reader *reader, struct part *parts, /* Define a few variables */ double time = get_double_time(0); int is_particle = 0; - int step = -1; + int step = 0; + int init_log_all_done = -1; /* Number of particle found during this time step. */ int count = 0; /* Set it to an impossible value in order to flag it. */ const size_t id_flag = 5 * number_parts; - size_t previous_id = id_flag; + long long previous_id = id_flag; /* Loop over each record. */ for (size_t offset = reader_read_record(reader, &lp, &time, &is_particle, logfile->header.offset_first_record); - offset < logfile->log.file_size; + offset < logfile->log.mmap_size; offset = reader_read_record(reader, &lp, &time, &is_particle, offset)) { /* Do the particle case */ @@ -183,16 +87,21 @@ void check_data(struct logger_reader *reader, struct part *parts, } /* Get the corresponding particle */ - if (lp.id >= number_parts) error("Wrong id %zi", lp.id); + if (lp.id >= number_parts) error("Wrong id %lli", lp.id); struct part *p = &parts[lp.id]; /* Check the record's data. */ for (int i = 0; i < 3; i++) { /* in the first index, we are storing the step information. */ - if (i == 0) - assert(step == lp.pos[i]); - else + if (i == 0) { + double tmp = step; + /* At the end, we are not updating the particle */ + if (step >= max_step) { + tmp = max_step - max_step % p->time_bin; + } + assert(tmp == lp.pos[i]); + } else assert(p->x[i] == lp.pos[i]); assert(p->v[i] == lp.vel[i]); assert(p->a_hydro[i] == lp.acc[i]); @@ -203,12 +112,12 @@ void check_data(struct logger_reader *reader, struct part *parts, /* Check optional fields. */ int number_steps = step / p->time_bin; - if (number_steps % period_h == 0) { + if (number_steps % period_h == 0 || step > max_step) { assert(p->h == lp.h); } else { assert(-1 == lp.h); } - if (number_steps % period_rho == 0) { + if (number_steps % period_rho == 0 || step > max_step) { assert(p->rho == lp.density); } else { assert(-1 == lp.density); @@ -216,22 +125,28 @@ void check_data(struct logger_reader *reader, struct part *parts, } /* Time stamp case. */ else { - + message("Step: %i", step); /* Check if we have the current amount of particles in previous step. */ - if (step != -1 && count != get_number_active_particles(step, parts)) + if (step != 0 && count != get_number_active_particles(step, parts)) error( "The reader did not find the correct number of particles during " - "step %i", - step); + "step %i: %i != %i", + step, count, get_number_active_particles(step, parts)); + + /* Avoid the initial log */ + if (init_log_all_done > 0) { + step += 1; + } - step += 1; + init_log_all_done += 1; /* Reset some variables. */ previous_id = id_flag; count = 0; /* Check the record's data. */ - assert(time == get_double_time(step)); + const int tmp_step = step >= max_step ? max_step : step; + assert(time == get_double_time(tmp_step)); } } } @@ -245,7 +160,6 @@ int main(int argc, char *argv[]) { message("Generating the dump."); /* Create required structures. */ - struct logger_writer log; struct swift_params params; char filename[200] = "testLogfileReader.yml"; @@ -263,25 +177,9 @@ int main(int argc, char *argv[]) { NULL) error("Failed to allocate xparticles array."); - init_particles(parts, xparts); - - /* Initialize the logger. */ - logger_init(&log, ¶ms); - - /* get dump filename. */ - char dump_filename[PARSER_MAX_LINE_SIZE]; - message("%s", log.base_name); - strcpy(dump_filename, log.base_name); - strcat(dump_filename, ".dump"); - - /* Write file header. */ - logger_write_file_header(&log); - - /* Write particles. */ - write_particles(&log, parts, xparts); + /* Write a 'simulation' */ + generate_log(¶ms, parts, xparts, number_parts); - /* clean memory */ - logger_free(&log); /* Then read the file. */ @@ -295,7 +193,9 @@ int main(int argc, char *argv[]) { reader.verbose = 1; /* Read the header. */ - logger_reader_init(&reader, dump_filename, /* verbose */ 1); + char basename[200]; + parser_get_param_string(¶ms, "Logger:basename", basename); + logger_reader_init(&reader, basename, /* verbose */ 1); /* Finally check everything. diff --git a/logger/tests/testQuickSort.c b/logger/tests/testQuickSort.c new file mode 100644 index 0000000000000000000000000000000000000000..85e2a13ce0bd7204666fb09ae540297036ad7054 --- /dev/null +++ b/logger/tests/testQuickSort.c @@ -0,0 +1,97 @@ + +/******************************************************************************* + * This file is part of SWIFT. + * Copyright (c) 2019 Loic Hausammann (loic.hausammann@epfl.ch) + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published + * by the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this program. If not, see <http://www.gnu.org/licenses/>. + * + ******************************************************************************/ + +#include "memswap.h" +#include "quick_sort.h" + +#define N 10000 + +int64_t getRandom(void) { + return llabs(((int64_t)lrand48() << 32) + (int64_t)lrand48()); +} +/** + * @brief Initialize the array. + */ +void init_array(struct index_data *data) { + /* Assign the ids */ + for (int i = 0; i < N; i++) { + data[i].id = getRandom(); + } + + /* randomize the array */ + for (int i = 0; i < N; i++) { + /* Select an index randomly */ + int j = rand() % N; + + /* Swap the two elements */ + memswap(&data[i], &data[j], sizeof(struct index_data)); + } +} + +/** + * @brief Ensure that the array is sorted + */ +void check_sort(struct index_data *data) { + for (size_t i = 1; i < N; i++) { + if (data[i].id < data[i - 1].id) { + error("The array is not sorted index=%zi, prev=%li, cur=%li", i, + data[i - 1].id, data[i].id); + } + } +} + +/** + * @brief print the array + */ +void print_array(struct index_data *data) { + for (int i = 0; i < N; i++) { + printf("%li \t %zi\n", data[i].id, data[i].offset); + } +} + +int main(int argc, char *argv[]) { + + /* Create the array */ + struct index_data *data = + (struct index_data *)malloc(N * sizeof(struct index_data)); + + if (data == NULL) { + error("Failed to allocate the memory"); + } + + /* Initialize the array */ + init_array(data); + + /* Print the array */ + message("\nArray before sort\n"); + print_array(data); + + /* Sort the array */ + quick_sort(data, N); + + /* Print the array */ + message("\nArray after sort\n"); + print_array(data); + + /* Check the results */ + check_sort(data); + + return 0; +} diff --git a/logger/tests/testVR.c b/logger/tests/testVR.c new file mode 100644 index 0000000000000000000000000000000000000000..6e7828ee6380730972c260c249f22c876d3189b4 --- /dev/null +++ b/logger/tests/testVR.c @@ -0,0 +1,116 @@ +/******************************************************************************* + * This file is part of SWIFT. + * Copyright (C) 2019 Loic Hausammann (loic.hausammann@epfl.ch) + * Florian Cabot (florian.cabot@epfl.ch) + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published + * by the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this program. If not, see <http://www.gnu.org/licenses/>. + * + ******************************************************************************/ + +/* Include configuration */ +#include "config.h" + +/* Standard include */ +#include <stdlib.h> + +/* Local include */ +#include "generate_log.h" +#include "hydro.h" +#include "logger_reader.h" + +#define number_steps 10. +#define number_parts 100 + +/** + * This function test the logger in the VR mode. + * The idea is to simply read a snapshot at a given time and + * then simply advance in time the particles. + */ +int main(int argc, char *argv[]) { + /* Create required structures. */ + struct swift_params params; + char filename[200] = "testVR.yml"; + + /* Read parameters. */ + parser_read_file(filename, ¶ms); + + /* Initialize the particles. */ + struct part *parts; + if ((parts = (struct part *)malloc(sizeof(struct part) * number_parts)) == + NULL) + error("Failed to allocate particles array."); + + struct xpart *xparts; + if ((xparts = (struct xpart *)malloc(sizeof(struct xpart) * number_parts)) == + NULL) + error("Failed to allocate xparticles array."); + + /* Write a 'simulation' */ + generate_log(¶ms, parts, xparts, number_parts); + + /* Initialize the reader */ + struct logger_reader reader; + char basename[200]; + parser_get_param_string(¶ms, "Logger:basename", basename); + logger_reader_init(&reader, basename, + /* Verbose */ 0); + + /* Read the time limits */ + double begin = logger_reader_get_time_begin(&reader); + double end = logger_reader_get_time_end(&reader); + + /* Set the time */ + message("Time begin: %f end: %f", begin, end); + logger_reader_set_time(&reader, begin); + + /* Get the number of particles */ + int n_type = 0; + uint64_t n_tot = 0; + const uint64_t *n_parts = + logger_reader_get_number_particles(&reader, &n_type); + for (int i = 0; i < n_type; i++) { + n_tot += n_parts[i]; + } + + /* Allocate the particles memory */ + struct logger_particle *particles = + malloc(n_tot * sizeof(struct logger_particle)); + + logger_reader_read_all_particles(&reader, begin, logger_reader_const, + particles, n_tot); + + /* Loop over time for a single particle */ + size_t id = 0; + struct logger_particle p = particles[id]; + for (double t = begin; t < end; t += (end - begin) / number_steps) { + /* Get the offset of the given time */ + size_t o = logger_reader_get_next_offset_from_time(&reader, t); + message("time: %f offset: %ld", t, o); + + /* Read the next particle */ + struct logger_particle n; + logger_reader_get_next_particle(&reader, &p, &n, o); + + message("Particle %zi: %f %f %f %f", id, p.pos[0], p.pos[1], p.pos[2], + p.time); + + /* Now you can interpolate */ + logger_particle_interpolate(&p, &n, t); + } + + /* Cleanup the memory */ + free(particles); + logger_reader_free(&reader); + return 0; +} diff --git a/logger/tests/testVR.yml b/logger/tests/testVR.yml new file mode 100644 index 0000000000000000000000000000000000000000..e9297e337f84062630756550f0ed8cc5f68016cc --- /dev/null +++ b/logger/tests/testVR.yml @@ -0,0 +1,6 @@ +# Parameter file for the tests +Logger: + delta_step: 10 + initial_buffer_size: 0.01 # in GB + buffer_scale: 10 + basename: testvr diff --git a/m4/ax_cc_maxopt.m4 b/m4/ax_cc_maxopt.m4 index 72407f3b6a5f29758fbb7b41afda9357ce4210ec..282668af72e638b0f73e9d84b1822b60a0ddda21 100644 --- a/m4/ax_cc_maxopt.m4 +++ b/m4/ax_cc_maxopt.m4 @@ -133,6 +133,14 @@ if test "$ac_test_CFLAGS" != "set"; then *000?f[[346]]?:*:*:*|?f[[346]]?:*:*:*|f[[346]]?:*:*:*) icc_flags="-xSSE3 -xP -xO -xN -xW -xK" ;; *00??f??:*:*:*|??f??:*:*:*|?f??:*:*:*|f??:*:*:*) icc_flags="-xSSE2 -xN -xW -xK" ;; esac ;; + *:68747541:444d4163:69746e65) # AMDs with AVX2 support. + case $ax_cv_gcc_x86_cpuid_1 in + *061?f??:*:*:*|61?f??:*:*:*) icc_flags="-march=core-avx2" ;; + *06??f??:*:*:*|6??f??:*:*:*) icc_flags="-march=core-avx2" ;; + *070?f??:*:*:*|70?f??:*:*:*) icc_flags="-march=core-avx2" ;; + 83?f??:*:*:*) icc_flags="-march=core-avx2" + CFLAGS="$CFLAGS -fma -ftz -fomit-frame-pointer";; # EPYC + esac ;; esac ;; esac if test "x$icc_flags" != x; then diff --git a/m4/ax_compare_version.m4 b/m4/ax_compare_version.m4 index 74dc0fdd9a40cea41852e138d687b43a05492bd9..6df1c5301aab7da3e937932703b14d71417b917e 100644 --- a/m4/ax_compare_version.m4 +++ b/m4/ax_compare_version.m4 @@ -1,5 +1,5 @@ # =========================================================================== -# http://www.gnu.org/software/autoconf-archive/ax_compare_version.html +# https://www.gnu.org/software/autoconf-archive/ax_compare_version.html # =========================================================================== # # SYNOPSIS @@ -79,7 +79,7 @@ # and this notice are preserved. This file is offered as-is, without any # warranty. -#serial 11 +#serial 13 dnl ######################################################################### AC_DEFUN([AX_COMPARE_VERSION], [ @@ -146,7 +146,7 @@ x$B" | sed 's/^ *//' | sort -r | sed "s/x${A}/true/;s/x${B}/false/;1q"` ], [.+],[ AC_WARNING( - [illegal OP numeric parameter: $2]) + [invalid OP numeric parameter: $2]) ],[]) # Pad zeros at end of numbers to make same length. @@ -162,7 +162,7 @@ x$B" | sed 's/^ *//' | sort -r | sed "s/x${A}/true/;s/x${B}/false/;1q"` [ne],[ test "x$A" != "x$B" && ax_compare_version=true ],[ - AC_WARNING([illegal OP parameter: $2]) + AC_WARNING([invalid OP parameter: $2]) ]) ]) @@ -175,3 +175,4 @@ x$B" | sed 's/^ *//' | sort -r | sed "s/x${A}/true/;s/x${B}/false/;1q"` m4_ifvaln([$5],[else $5])dnl fi ]) dnl AX_COMPARE_VERSION + diff --git a/m4/ax_compiler_vendor.m4 b/m4/ax_compiler_vendor.m4 index 39ca3c0f3378267d13cfb2ad3dd8ffa4854fb772..6b67c4f93116916943d1abd92a485bb33330515f 100644 --- a/m4/ax_compiler_vendor.m4 +++ b/m4/ax_compiler_vendor.m4 @@ -1,5 +1,5 @@ # =========================================================================== -# http://www.gnu.org/software/autoconf-archive/ax_compiler_vendor.html +# https://www.gnu.org/software/autoconf-archive/ax_compiler_vendor.html # =========================================================================== # # SYNOPSIS @@ -8,15 +8,29 @@ # # DESCRIPTION # -# Determine the vendor of the C/C++ compiler, e.g., gnu, intel, ibm, sun, -# hp, borland, comeau, dec, cray, kai, lcc, metrowerks, sgi, microsoft, -# watcom, etc. The vendor is returned in the cache variable -# $ax_cv_c_compiler_vendor for C and $ax_cv_cxx_compiler_vendor for C++. +# Determine the vendor of the C, C++ or Fortran compiler. The vendor is +# returned in the cache variable $ax_cv_c_compiler_vendor for C, +# $ax_cv_cxx_compiler_vendor for C++ or $ax_cv_fc_compiler_vendor for +# (modern) Fortran. The value is one of "intel", "ibm", "pathscale", +# "clang" (LLVM), "cray", "fujitsu", "sdcc", "sx", "portland" (PGI), "gnu" +# (GCC), "sun" (Oracle Developer Studio), "hp", "dec", "borland", +# "comeau", "kai", "lcc", "sgi", "microsoft", "metrowerks", "watcom", +# "tcc" (Tiny CC) or "unknown" (if the compiler cannot be determined). +# +# To check for a Fortran compiler, you must first call AC_FC_PP_SRCEXT +# with an appropriate preprocessor-enabled extension. For example: +# +# AC_LANG_PUSH([Fortran]) +# AC_PROG_FC +# AC_FC_PP_SRCEXT([F]) +# AX_COMPILER_VENDOR +# AC_LANG_POP([Fortran]) # # LICENSE # # Copyright (c) 2008 Steven G. Johnson <stevenj@alum.mit.edu> # Copyright (c) 2008 Matteo Frigo +# Copyright (c) 2018-19 John Zaitseff <J.Zaitseff@zap.org.au> # # This program is free software: you can redistribute it and/or modify it # under the terms of the GNU General Public License as published by the @@ -29,7 +43,7 @@ # Public License for more details. # # You should have received a copy of the GNU General Public License along -# with this program. If not, see <http://www.gnu.org/licenses/>. +# with this program. If not, see <https://www.gnu.org/licenses/>. # # As a special exception, the respective Autoconf Macro's copyright owner # gives unlimited permission to copy, distribute and modify the configure @@ -44,44 +58,61 @@ # modified version of the Autoconf Macro, you may extend this special # exception to the GPL to apply to your modified version as well. -#serial 15 +#serial 30 + +AC_DEFUN([AX_COMPILER_VENDOR], [dnl + AC_CACHE_CHECK([for _AC_LANG compiler vendor], ax_cv_[]_AC_LANG_ABBREV[]_compiler_vendor, [dnl + dnl If you modify this list of vendors, please add similar support + dnl to ax_compiler_version.m4 if at all possible. + dnl + dnl Note: Do NOT check for GCC first since some other compilers + dnl define __GNUC__ to remain compatible with it. Compilers that + dnl are very slow to start (such as Intel) are listed first. + + vendors=" + intel: __ICC,__ECC,__INTEL_COMPILER + ibm: __xlc__,__xlC__,__IBMC__,__IBMCPP__,__ibmxl__ + pathscale: __PATHCC__,__PATHSCALE__ + clang: __clang__ + cray: _CRAYC + fujitsu: __FUJITSU + sdcc: SDCC,__SDCC + sx: _SX + portland: __PGI + gnu: __GNUC__ + sun: __SUNPRO_C,__SUNPRO_CC,__SUNPRO_F90,__SUNPRO_F95 + hp: __HP_cc,__HP_aCC + dec: __DECC,__DECCXX,__DECC_VER,__DECCXX_VER + borland: __BORLANDC__,__CODEGEARC__,__TURBOC__ + comeau: __COMO__ + kai: __KCC + lcc: __LCC__ + sgi: __sgi,sgi + microsoft: _MSC_VER + metrowerks: __MWERKS__ + watcom: __WATCOMC__ + tcc: __TINYC__ + unknown: UNKNOWN + " + for ventest in $vendors; do + case $ventest in + *:) + vendor=$ventest + continue + ;; + *) + vencpp="defined("`echo $ventest | sed 's/,/) || defined(/g'`")" + ;; + esac + + AC_COMPILE_IFELSE([AC_LANG_PROGRAM([], [[ +#if !($vencpp) + thisisanerror; +#endif + ]])], [break]) + done + + ax_cv_[]_AC_LANG_ABBREV[]_compiler_vendor=`echo $vendor | cut -d: -f1` + ]) +])dnl -AC_DEFUN([AX_COMPILER_VENDOR], -[AC_CACHE_CHECK([for _AC_LANG compiler vendor], ax_cv_[]_AC_LANG_ABBREV[]_compiler_vendor, - dnl Please add if possible support to ax_compiler_version.m4 - [# note: don't check for gcc first since some other compilers define __GNUC__ - vendors="intel: __ICC,__ECC,__INTEL_COMPILER - ibm: __xlc__,__xlC__,__IBMC__,__IBMCPP__ - pathscale: __PATHCC__,__PATHSCALE__ - clang: __clang__ - cray: _CRAYC - fujitsu: __FUJITSU - gnu: __GNUC__ - sun: __SUNPRO_C,__SUNPRO_CC - hp: __HP_cc,__HP_aCC - dec: __DECC,__DECCXX,__DECC_VER,__DECCXX_VER - borland: __BORLANDC__,__CODEGEARC__,__TURBOC__ - comeau: __COMO__ - kai: __KCC - lcc: __LCC__ - sgi: __sgi,sgi - microsoft: _MSC_VER - metrowerks: __MWERKS__ - watcom: __WATCOMC__ - portland: __PGI - tcc: __TINYC__ - unknown: UNKNOWN" - for ventest in $vendors; do - case $ventest in - *:) vendor=$ventest; continue ;; - *) vencpp="defined("`echo $ventest | sed 's/,/) || defined(/g'`")" ;; - esac - AC_COMPILE_IFELSE([AC_LANG_PROGRAM(,[ - #if !($vencpp) - thisisanerror; - #endif - ])], [break]) - done - ax_cv_[]_AC_LANG_ABBREV[]_compiler_vendor=`echo $vendor | cut -d: -f1` - ]) -]) diff --git a/m4/ax_compiler_version.m4 b/m4/ax_compiler_version.m4 index 10ac77514e4dc302dfbb42ab91fd9d0c2f514cac..4995beb6032e792c209b1e045c7f58b8712f89a2 100644 --- a/m4/ax_compiler_version.m4 +++ b/m4/ax_compiler_version.m4 @@ -1,5 +1,5 @@ # =========================================================================== -# http://www.gnu.org/software/autoconf-archive/ax_compiler_version.html +# https://www.gnu.org/software/autoconf-archive/ax_compiler_version.html # =========================================================================== # # SYNOPSIS @@ -20,8 +20,8 @@ # Epoch use: * borland compiler use chronologically 0turboc for turboc # era, # -# 1borlanc BORLANC++ before 5, 2cppbuilder for cppbuilder era, -# 3borlancpp for return of BORLANC++ (after version 5.5), +# 1borlanc BORLANDC++ before 5, 2cppbuilder for cppbuilder era, +# 3borlancpp for return of BORLANDC++ (after version 5.5), # 4cppbuilder for cppbuilder with year version, # and 5xe for XE era. # @@ -36,7 +36,7 @@ # and this notice are preserved. This file is offered as-is, without any # warranty. -#serial 4 +#serial 12 # for intel AC_DEFUN([_AX_COMPILER_VERSION_INTEL], @@ -299,7 +299,7 @@ AC_DEFUN([_AX_COMPILER_VERSION_BORLAND],[dnl _AX_COMPILER_VERSION_BORLANDC_NUMBER,, AC_MSG_FAILURE([[[$0]] unknown borlandc version])) AS_CASE([$_ax_[]_AC_LANG_ABBREV[]_compiler_version_borlandc_raw], - dnl BORLANC++ before 5.5 + dnl BORLANDC++ before 5.5 [512] ,[ax_cv_[]_AC_LANG_ABBREV[]_compiler_version="1borlanc:2.00"], [1024],[ax_cv_[]_AC_LANG_ABBREV[]_compiler_version="1borlanc:3.00"], [1024],[ax_cv_[]_AC_LANG_ABBREV[]_compiler_version="1borlanc:3.00"], @@ -310,7 +310,7 @@ AC_DEFUN([_AX_COMPILER_VERSION_BORLAND],[dnl dnl C++ Builder era [1328],[ax_cv_[]_AC_LANG_ABBREV[]_compiler_version="2cppbuilder:3.0"], [1344],[ax_cv_[]_AC_LANG_ABBREV[]_compiler_version="2cppbuilder:4.0"], - dnl BORLANC++ after 5.5 + dnl BORLANDC++ after 5.5 [1360],[ax_cv_[]_AC_LANG_ABBREV[]_compiler_version="3borlancpp:5.5"], [1361],[ax_cv_[]_AC_LANG_ABBREV[]_compiler_version="3borlancpp:5.51"], [1378],[ax_cv_[]_AC_LANG_ABBREV[]_compiler_version="3borlancpp:5.6.4"], @@ -325,7 +325,7 @@ AC_DEFUN([_AX_COMPILER_VERSION_BORLAND],[dnl [1616],[ax_cv_[]_AC_LANG_ABBREV[]_compiler_version="5xe:3"], [1632],[ax_cv_[]_AC_LANG_ABBREV[]_compiler_version="5xe:4"], [ - AC_MSG_WARN([[[$0]] Unknow borlanc compiler version $_ax_[]_AC_LANG_ABBREV[]_compiler_version_borlandc_raw please report bug]) + AC_MSG_WARN([[[$0]] Unknown borlandc compiler version $_ax_[]_AC_LANG_ABBREV[]_compiler_version_borlandc_raw please report bug]) ]) ]) ]) @@ -389,7 +389,7 @@ AC_DEFUN([_AX_COMPILER_VERSION_MICROSOFT],[ AC_COMPUTE_INT(_ax_[]_AC_LANG_ABBREV[]_compiler_version_major, (_MSC_VER/100)%100,, AC_MSG_FAILURE([[[$0]] unknown microsoft compiler major version])) - dnl could be overriden + dnl could be overridden _ax_[]_AC_LANG_ABBREV[]_compiler_version_patch=0 _ax_[]_AC_LANG_ABBREV[]_compiler_version_build=0 # special case for version 6 @@ -460,6 +460,42 @@ AC_DEFUN([_AX_COMPILER_VERSION_PORTLAND],[ AC_DEFUN([_AX_COMPILER_VERSION_TCC],[ ax_cv_[]_AC_LANG_ABBREV[]_compiler_version=[`tcc -v | $SED 's/^[ ]*tcc[ ]\+version[ ]\+\([0-9.]\+\).*/\1/g'`] ]) + +# for GNU +AC_DEFUN([_AX_COMPILER_VERSION_SDCC],[ + AC_COMPUTE_INT(_ax_[]_AC_LANG_ABBREV[]_compiler_version_major, + /* avoid parse error with comments */ + #if(defined(__SDCC_VERSION_MAJOR)) + __SDCC_VERSION_MAJOR + #else + SDCC/100 + #endif + ,, + AC_MSG_FAILURE([[[$0]] unknown sdcc major])) + AC_COMPUTE_INT(_ax_[]_AC_LANG_ABBREV[]_compiler_version_minor, + /* avoid parse error with comments */ + #if(defined(__SDCC_VERSION_MINOR)) + __SDCC_VERSION_MINOR + #else + (SDCC%100)/10 + #endif + ,, + AC_MSG_FAILURE([[[$0]] unknown sdcc minor])) + AC_COMPUTE_INT(_ax_[]_AC_LANG_ABBREV[]_compiler_version_patch, + [ + /* avoid parse error with comments */ + #if(defined(__SDCC_VERSION_PATCH)) + __SDCC_VERSION_PATCH + #elsif(defined(_SDCC_VERSION_PATCHLEVEL)) + __SDCC_VERSION_PATCHLEVEL + #else + SDCC%10 + #endif + ],, + AC_MSG_FAILURE([[[$0]] unknown sdcc patch level])) + ax_cv_[]_AC_LANG_ABBREV[]_compiler_version="$_ax_[]_AC_LANG_ABBREV[]_compiler_version_major.$_ax_[]_AC_LANG_ABBREV[]_compiler_version_minor.$_ax_[]_AC_LANG_ABBREV[]_compiler_version_patch" + ]) + # main entry point AC_DEFUN([AX_COMPILER_VERSION],[dnl AC_REQUIRE([AX_COMPILER_VENDOR]) @@ -487,6 +523,8 @@ AC_DEFUN([AX_COMPILER_VERSION],[dnl [watcom],[_AX_COMPILER_VERSION_WATCOM], [portland],[_AX_COMPILER_VERSION_PORTLAND], [tcc],[_AX_COMPILER_VERSION_TCC], + [sdcc],[_AX_COMPILER_VERSION_SDCC], [ax_cv_[]_AC_LANG_ABBREV[]_compiler_version=""]) ]) ]) + diff --git a/m4/ax_gcc_archflag.m4 b/m4/ax_gcc_archflag.m4 index ec600016ad3bd7a6afea4ab36c434a91172de9af..2754d8a40d912e2674719cea5e1338c6ab0dd693 100644 --- a/m4/ax_gcc_archflag.m4 +++ b/m4/ax_gcc_archflag.m4 @@ -146,6 +146,7 @@ case $host_cpu in *061?f??:*:*:*|61?f??:*:*:*) ax_gcc_arch="bdver2 bdver1 amdfam10 k8" ;; *06??f??:*:*:*|6??f??:*:*:*) ax_gcc_arch="bdver3 bdver2 bdver1 amdfam10 k8" ;; *070?f??:*:*:*|70?f??:*:*:*) ax_gcc_arch="btver2 btver1 amdfam10 k8" ;; + 83?f??:*:*:*) ax_gcc_arch="znver2 znver1 btver2 btver1 amdfam10 k8" ;; *???f??:*:*:*) ax_gcc_arch="amdfam10 k8" ;; esac ;; *:746e6543:736c7561:48727561) # IDT / VIA (Centaur) diff --git a/src/Makefile.am b/src/Makefile.am index c2a3a7755a188de6c907afe99e5ae1c4dfc5f3a8..7144496b68a9e6789d0eaf0fb0dd19ff014e6d4b 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -19,7 +19,7 @@ AM_CFLAGS = $(HDF5_CPPFLAGS) $(GSL_INCS) $(FFTW_INCS) $(NUMA_INCS) $(GRACKLE_INCS) # Assign a "safe" version number -AM_LDFLAGS = $(HDF5_LDFLAGS) $(FFTW_LIBS) -version-info 0:0:0 +AM_LDFLAGS = $(HDF5_LDFLAGS) $(FFTW_LIBS) # The git command, if available. GIT_CMD = @GIT_CMD@ @@ -31,11 +31,13 @@ EXTRA_LIBS = $(HDF5_LIBS) $(FFTW_LIBS) $(NUMA_LIBS) $(PROFILER_LIBS) $(TCMALLOC_ MPI_LIBS = $(PARMETIS_LIBS) $(METIS_LIBS) $(MPI_THREAD_LIBS) MPI_FLAGS = -DWITH_MPI $(PARMETIS_INCS) $(METIS_INCS) -# Build the libswiftsim library +# Build the libswiftsim library and a convenience library just for the gravity tasks lib_LTLIBRARIES = libswiftsim.la +noinst_LTLIBRARIES = libgrav.la # Build a MPI-enabled version too? if HAVEMPI lib_LTLIBRARIES += libswiftsim_mpi.la +noinst_LTLIBRARIES += libgrav_mpi.la endif # List required headers @@ -55,7 +57,7 @@ include_HEADERS = space.h runner.h queue.h task.h lock.h cell.h part.h const.h \ pressure_floor.h pressure_floor_struct.h pressure_floor_iact.h \ velociraptor_struct.h velociraptor_io.h random.h memuse.h mpiuse.h memuse_rnodes.h \ black_holes.h black_holes_io.h black_holes_properties.h black_holes_struct.h \ - feedback.h feedback_struct.h feedback_properties.h + feedback.h feedback_struct.h feedback_properties.h task_order.h # source files for EAGLE cooling EAGLE_COOLING_SOURCES = @@ -69,12 +71,25 @@ if HAVEEAGLEFEEDBACK EAGLE_FEEDBACK_SOURCES += feedback/EAGLE/feedback.c endif +# source files for GRACKLE cooling +GRACKLE_COOLING_SOURCES = +if HAVEGRACKLECOOLING +GRACKLE_COOLING_SOURCES += cooling/grackle/cooling.c +endif + +# source files for GRACKLE cooling +GEAR_FEEDBACK_SOURCES = +if HAVEGEARFEEDBACK +GEAR_FEEDBACK_SOURCES += feedback/GEAR/stellar_evolution.c feedback/GEAR/feedback.c \ + feedback/GEAR/initial_mass_function.c feedback/GEAR/supernovae_ia.c feedback/GEAR/supernovae_ii.c +endif + # Common source files -AM_SOURCES = space.c runner_main.c runner_doiact_hydro.c runner_doiact_grav.c \ +AM_SOURCES = space.c runner_main.c runner_doiact_hydro.c runner_doiact_limiter.c \ runner_doiact_stars.c runner_doiact_black_holes.c runner_ghost.c runner_recv.c \ runner_sort.c runner_drift.c runner_black_holes.c runner_time_integration.c \ runner_doiact_hydro_vec.c runner_others.c\ - queue.c task.c cell.c engine.c engine_maketasks.c \ + queue.c task.c cell.c engine.c engine_maketasks.c engine_split_particles.c \ engine_marktasks.c engine_drift.c engine_unskip.c engine_collect_end_of_step.c \ engine_redistribute.c engine_fof.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 \ @@ -87,17 +102,18 @@ AM_SOURCES = space.c runner_main.c runner_doiact_hydro.c runner_doiact_grav.c \ chemistry.c cosmology.c restart.c mesh_gravity.c velociraptor_interface.c \ outputlist.c velociraptor_dummy.c logger_io.c memuse.c mpiuse.c memuse_rnodes.c fof.c \ hashmap.c pressure_floor.c \ - $(EAGLE_COOLING_SOURCES) $(EAGLE_FEEDBACK_SOURCES) + $(EAGLE_COOLING_SOURCES) $(EAGLE_FEEDBACK_SOURCES) $(GRACKLE_COOLING_SOURCES) \ + $(GEAR_FEEDBACK_SOURCES) # 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_nosort.h runner_doiact_hydro.h runner_doiact_stars.h runner_doiact_black_holes.h runner_doiact_grav.h \ runner_doiact_functions_hydro.h runner_doiact_functions_stars.h runner_doiact_functions_black_holes.h \ - units.h intrinsics.h minmax.h \ + runner_doiact_functions_limiter.h runner_doiact_limiter.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 timestep_limiter.h hashmap.h \ - gravity.h gravity_io.h gravity_cache.h \ + timestep_limiter.h timestep_limiter_iact.h timestep_sync.h timestep_sync_part.h timestep_limiter_struct.h \ + dump.h logger.h sign.h logger_io.h hashmap.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 \ gravity/Potential/gravity.h gravity/Potential/gravity_iact.h gravity/Potential/gravity_io.h \ @@ -128,32 +144,33 @@ nobase_noinst_HEADERS = align.h approx_math.h atomic.h barrier.h cycle.h error.h hydro/AnarchyPU/hydro.h hydro/PressureEnergy/hydro_iact.h hydro/PressureEnergy/hydro_io.h \ hydro/AnarchyPU/hydro_debug.h hydro/PressureEnergy/hydro_part.h \ hydro/AnarchyPU/hydro_parameters.h \ - hydro/AnarchyDU/hydro.h hydro/PressureEnergy/hydro_iact.h hydro/PressureEnergy/hydro_io.h \ - hydro/AnarchyDU/hydro_debug.h hydro/PressureEnergy/hydro_part.h \ - hydro/AnarchyDU/hydro_parameters.h \ - hydro/GizmoMFV/hydro.h hydro/GizmoMFV/hydro_iact.h \ - hydro/GizmoMFV/hydro_io.h hydro/GizmoMFV/hydro_debug.h \ - hydro/GizmoMFV/hydro_part.h \ - hydro/GizmoMFV/hydro_gradients_gizmo.h \ - hydro/GizmoMFV/hydro_gradients.h \ - hydro/GizmoMFV/hydro_gradients_sph.h \ - hydro/GizmoMFV/hydro_slope_limiters_cell.h \ - hydro/GizmoMFV/hydro_slope_limiters_face.h \ - hydro/GizmoMFV/hydro_slope_limiters.h \ - hydro/GizmoMFV/hydro_unphysical.h \ - hydro/GizmoMFV/hydro_velocities.h \ - hydro/GizmoMFV/hydro_parameters.h \ - hydro/GizmoMFM/hydro.h hydro/GizmoMFM/hydro_iact.h \ - hydro/GizmoMFM/hydro_io.h hydro/GizmoMFM/hydro_debug.h \ - hydro/GizmoMFM/hydro_part.h \ - hydro/GizmoMFM/hydro_gradients_gizmo.h \ - hydro/GizmoMFM/hydro_gradients.h \ - hydro/GizmoMFM/hydro_gradients_sph.h \ - hydro/GizmoMFM/hydro_slope_limiters_cell.h \ - hydro/GizmoMFM/hydro_slope_limiters_face.h \ - hydro/GizmoMFM/hydro_slope_limiters.h \ - hydro/GizmoMFM/hydro_unphysical.h \ - hydro/GizmoMFM/hydro_parameters.h \ + hydro/SPHENIX/hydro.h hydro/PressureEnergy/hydro_iact.h hydro/PressureEnergy/hydro_io.h \ + hydro/SPHENIX/hydro_debug.h hydro/PressureEnergy/hydro_part.h \ + hydro/SPHENIX/hydro_parameters.h \ + hydro/Gizmo/hydro_parameters.h \ + hydro/Gizmo/hydro_io.h hydro/Gizmo/hydro_debug.h \ + hydro/Gizmo/hydro.h hydro/Gizmo/hydro_iact.h \ + hydro/Gizmo/hydro_part.h \ + hydro/Gizmo/hydro_gradients.h \ + hydro/Gizmo/hydro_getters.h \ + hydro/Gizmo/hydro_setters.h \ + hydro/Gizmo/hydro_flux.h \ + hydro/Gizmo/hydro_slope_limiters.h \ + hydro/Gizmo/hydro_slope_limiters_face.h \ + hydro/Gizmo/hydro_slope_limiters_cell.h \ + hydro/Gizmo/hydro_unphysical.h \ + hydro/Gizmo/hydro_gradients_sph.h \ + hydro/Gizmo/hydro_gradients_gizmo.h \ + hydro/Gizmo/hydro_velocities.h \ + hydro/Gizmo/hydro_lloyd.h \ + hydro/Gizmo/MFV/hydro_debug.h \ + hydro/Gizmo/MFV/hydro_part.h \ + hydro/Gizmo/MFV/hydro_velocities.h \ + hydro/Gizmo/MFV/hydro_flux.h \ + hydro/Gizmo/MFM/hydro_debug.h \ + hydro/Gizmo/MFM/hydro_part.h \ + hydro/Gizmo/MFM/hydro_flux.h \ + hydro/Gizmo/MFM/hydro_velocities.h \ hydro/Shadowswift/hydro_debug.h \ hydro/Shadowswift/hydro_gradients.h hydro/Shadowswift/hydro.h \ hydro/Shadowswift/hydro_iact.h \ @@ -179,6 +196,8 @@ nobase_noinst_HEADERS = align.h approx_math.h atomic.h barrier.h cycle.h error.h stars/Default/stars_debug.h stars/Default/stars_part.h \ stars/EAGLE/stars.h stars/EAGLE/stars_iact.h stars/EAGLE/stars_io.h \ stars/EAGLE/stars_debug.h stars/EAGLE/stars_part.h \ + stars/GEAR/stars.h stars/GEAR/stars_iact.h stars/GEAR/stars_io.h \ + stars/GEAR/stars_debug.h stars/GEAR/stars_part.h \ potential/none/potential.h potential/point_mass/potential.h \ potential/isothermal/potential.h potential/disc_patch/potential.h \ potential/sine_wave/potential.h \ @@ -226,32 +245,47 @@ nobase_noinst_HEADERS = align.h approx_math.h atomic.h barrier.h cycle.h error.h feedback/EAGLE/feedback.h feedback/EAGLE/feedback_struct.h feedback/EAGLE/feedback_iact.h \ feedback/EAGLE/feedback_properties.h feedback/EAGLE/imf.h feedback/EAGLE/interpolate.h \ feedback/EAGLE/yield_tables.h \ + feedback/GEAR/stellar_evolution_struct.h feedback/GEAR/stellar_evolution.h \ + feedback/GEAR/feedback.h feedback/GEAR/feedback_iact.h \ + feedback/GEAR/feedback_properties.h feedback/GEAR/feedback_struct.h \ + feedback/GEAR/initial_mass_function.h feedback/GEAR/supernovae_ia.h feedback/GEAR/supernovae_ii.h \ + feedback/GEAR/lifetime.h feedback/GEAR/hdf5_functions.h feedback/GEAR/interpolation.h \ black_holes/Default/black_holes.h black_holes/Default/black_holes_io.h \ black_holes/Default/black_holes_part.h black_holes/Default/black_holes_iact.h \ black_holes/Default/black_holes_properties.h \ black_holes/Default/black_holes_struct.h \ black_holes/EAGLE/black_holes.h black_holes/EAGLE/black_holes_io.h \ black_holes/EAGLE/black_holes_part.h black_holes/EAGLE/black_holes_iact.h \ - black_holes/EAGLE/black_holes_properties.h \ + black_holes/EAGLE/black_holes_properties.h black_holes/EAGLE/black_holes_parameters.h \ black_holes/EAGLE/black_holes_struct.h \ pressure_floor/GEAR/pressure_floor.h pressure_floor/none/pressure_floor.h \ pressure_floor/GEAR/pressure_floor_iact.h pressure_floor/none/pressure_floor_iact.h \ - pressure_floor/GEAR/pressure_floor_struct.h pressure_floor/none/pressure_floor_struct.h + pressure_floor/GEAR/pressure_floor_struct.h pressure_floor/none/pressure_floor_struct.h \ + task_order/GEAR/task_order.h task_order/EAGLE/task_order.h task_order/none/task_order.h +# Sources and special flags for the gravity library +libgrav_la_SOURCES = runner_doiact_grav.c +libgrav_la_CFLAGS = $(AM_CFLAGS) $(GRAVITY_CFLAGS) +libgrav_la_LDFLAGS = $(AM_LDFLAGS) $(EXTRA_LIBS) + +# Sources and special flags for the gravity MPI library +libgrav_mpi_la_SOURCES = runner_doiact_grav.c +libgrav_mpi_la_CFLAGS = $(AM_CFLAGS) $(GRAVITY_CFLAGS) -DWITH_MPI +libgrav_mpi_la_LDFLAGS = $(AM_LDFLAGS) $(MPI_LIBS) $(EXTRA_LIBS) + # Sources and flags for regular library libswiftsim_la_SOURCES = $(AM_SOURCES) libswiftsim_la_CFLAGS = $(AM_CFLAGS) -libswiftsim_la_LDFLAGS = $(AM_LDFLAGS) $(EXTRA_LIBS) -libswiftsim_la_LIBADD = $(GRACKLE_LIBS) $(VELOCIRAPTOR_LIBS) +libswiftsim_la_LDFLAGS = $(AM_LDFLAGS) $(EXTRA_LIBS) -version-info 0:0:0 +libswiftsim_la_LIBADD = $(GRACKLE_LIBS) $(VELOCIRAPTOR_LIBS) libgrav.la # Sources and flags for MPI library libswiftsim_mpi_la_SOURCES = $(AM_SOURCES) libswiftsim_mpi_la_CFLAGS = $(AM_CFLAGS) $(MPI_FLAGS) -libswiftsim_mpi_la_LDFLAGS = $(AM_LDFLAGS) $(MPI_LIBS) $(EXTRA_LIBS) +libswiftsim_mpi_la_LDFLAGS = $(AM_LDFLAGS) $(MPI_LIBS) $(EXTRA_LIBS) -version-info 0:0:0 libswiftsim_mpi_la_SHORTNAME = mpi -libswiftsim_mpi_la_LIBADD = $(GRACKLE_LIBS) $(VELOCIRAPTOR_LIBS) - +libswiftsim_mpi_la_LIBADD = $(GRACKLE_LIBS) $(VELOCIRAPTOR_LIBS) $(MPI_LIBS) libgrav_mpi.la # Versioning. If any sources change then update the version_string.h file with # the current git revision and package version. diff --git a/src/active.h b/src/active.h index f15a98fceeddc741b0f66009ff4a0c3b416b32f1..115fd5cbd7dbcec86aa88b4cf338823e00dd3414 100644 --- a/src/active.h +++ b/src/active.h @@ -136,9 +136,9 @@ __attribute__((always_inline)) INLINE static int cell_is_active_hydro( 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)", + "e->ti_current=%lld (t=%e, a=%e) c->nodeID=%d", 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); + e->ti_current * e->time_base, e->cosmology->a, c->nodeID); #endif return (c->hydro.ti_end_min == e->ti_current); diff --git a/src/approx_math.h b/src/approx_math.h index f347bab44790d1e3120675bcbd6e7a457ca09821..4015e6040b102839234c452783838dadddb86cf6 100644 --- a/src/approx_math.h +++ b/src/approx_math.h @@ -50,10 +50,10 @@ __attribute__((always_inline, const)) INLINE static float approx_erfcf( * @brief Approximate version of expf(x) using a 4th order Taylor expansion * * The absolute error is smaller than 3 * 10^-6 for -0.2 < x < 0.2. - * The absolute error is smaller than 2 * 10^-7 for -0.1 < x < 0.1. + * The absolute error is smaller than 3 * 10^-7 for -0.1 < x < 0.1. * The relative error is smaller than 1 * 10^-6 for -0.2 < x < 0.2. - * The relative error is smaller than 4 * 10^-8 for -0.1 < x < 0.1. + * The relative error is smaller than 3 * 10^-7 for -0.1 < x < 0.1. * * @param x The number to take the exponential of. */ diff --git a/src/black_holes/Default/black_holes.h b/src/black_holes/Default/black_holes.h index 082134cc78f5a7f5e0aa9adeb231c92b9d66c233..929524ebffb418136c7a753b831fd1c1d6e12f63 100644 --- a/src/black_holes/Default/black_holes.h +++ b/src/black_holes/Default/black_holes.h @@ -163,9 +163,14 @@ __attribute__((always_inline)) INLINE static void black_holes_swallow_part( * @param bpi The #bpart to update. * @param bpj The #bpart that is swallowed. * @param cosmo The current cosmological model. + * @param time Time since the start of the simulation (non-cosmo mode). + * @param with_cosmology Are we running with cosmology? + * @param props The properties of the black hole scheme. */ __attribute__((always_inline)) INLINE static void black_holes_swallow_bpart( - struct bpart* bpi, const struct bpart* bpj, const struct cosmology* cosmo) { + struct bpart* bpi, const struct bpart* bpj, const struct cosmology* cosmo, + const double time, const int with_cosmology, + const struct black_holes_props* props) { /* Nothing to do here: No merging in the default model */ } @@ -180,12 +185,14 @@ __attribute__((always_inline)) INLINE static void black_holes_swallow_bpart( * @param props The properties of the black hole scheme. * @param constants The physical constants (in internal units). * @param cosmo The cosmological model. + * @param time Time since the start of the simulation (non-cosmo mode). + * @param with_cosmology Are we running with cosmology? * @param dt The time-step size (in physical internal units). */ __attribute__((always_inline)) INLINE static void black_holes_prepare_feedback( struct bpart* restrict bp, const struct black_holes_props* props, const struct phys_const* constants, const struct cosmology* cosmo, - const double dt) {} + const double time, const int with_cosmology, const double dt) {} /** * @brief Finish the calculation of the new BH position. @@ -220,6 +227,32 @@ __attribute__((always_inline)) INLINE static void black_holes_reset_feedback( #endif } +/** + * @brief Store the gravitational potential of a black hole by copying it from + * its #gpart friend. + * + * Nothing to do here. + * + * @param bp The black hole particle. + * @param gp The black hole's #gpart. + */ +__attribute__((always_inline)) INLINE static void +black_holes_store_potential_in_bpart(struct bpart* bp, const struct gpart* gp) { +} + +/** + * @brief Store the gravitational potential of a particle by copying it from + * its #gpart friend. + * + * Nothing to do here. + * + * @param p_data The black hole data of a gas particle. + * @param gp The black hole's #gpart. + */ +__attribute__((always_inline)) INLINE static void +black_holes_store_potential_in_part(struct black_holes_part_data* p_data, + const struct gpart* gp) {} + /** * @brief Initialise a BH particle that has just been seeded. * diff --git a/src/black_holes/Default/black_holes_iact.h b/src/black_holes/Default/black_holes_iact.h index b26b8a50f40599402f4ea9886dbbd7495e8efd59..c57d07dca5e2ec1e9a2bd871d4e9d6d744cbe796 100644 --- a/src/black_holes/Default/black_holes_iact.h +++ b/src/black_holes/Default/black_holes_iact.h @@ -34,11 +34,13 @@ * @param ti_current Current integer time value (for random numbers). */ __attribute__((always_inline)) INLINE static void -runner_iact_nonsym_bh_gas_density( - const float r2, const float *dx, const float hi, const float hj, - struct bpart *restrict bi, const struct part *restrict pj, - const struct xpart *restrict xpj, const struct cosmology *cosmo, - const struct gravity_props *grav_props, const integertime_t ti_current) { +runner_iact_nonsym_bh_gas_density(const float r2, const float *dx, + const float hi, const float hj, + struct bpart *bi, const struct part *pj, + const struct xpart *xpj, + const struct cosmology *cosmo, + const struct gravity_props *grav_props, + const integertime_t ti_current) { float wi, wi_dx; @@ -83,11 +85,13 @@ runner_iact_nonsym_bh_gas_density( * @param ti_current Current integer time value (for random numbers). */ __attribute__((always_inline)) INLINE static void -runner_iact_nonsym_bh_gas_swallow( - const float r2, const float *dx, const float hi, const float hj, - const struct bpart *restrict bi, struct part *restrict pj, - struct xpart *restrict xpj, const struct cosmology *cosmo, - const struct gravity_props *grav_props, const integertime_t ti_current) {} +runner_iact_nonsym_bh_gas_swallow(const float r2, const float *dx, + const float hi, const float hj, + const struct bpart *bi, struct part *pj, + struct xpart *xpj, + const struct cosmology *cosmo, + const struct gravity_props *grav_props, + const integertime_t ti_current) {} /** * @brief Swallowing interaction between two BH particles (non-symmetric). @@ -108,8 +112,7 @@ runner_iact_nonsym_bh_gas_swallow( __attribute__((always_inline)) INLINE static void runner_iact_nonsym_bh_bh_swallow(const float r2, const float *dx, const float hi, const float hj, - const struct bpart *restrict bi, - struct bpart *restrict bj, + const struct bpart *bi, struct bpart *bj, const struct cosmology *cosmo, const struct gravity_props *grav_props, const integertime_t ti_current) {} @@ -129,11 +132,13 @@ runner_iact_nonsym_bh_bh_swallow(const float r2, const float *dx, * @param ti_current Current integer time value (for random numbers). */ __attribute__((always_inline)) INLINE static void -runner_iact_nonsym_bh_gas_feedback( - const float r2, const float *dx, const float hi, const float hj, - struct bpart *restrict bi, struct part *restrict pj, - struct xpart *restrict xpj, const struct cosmology *cosmo, - const struct gravity_props *grav_props, const integertime_t ti_current) { +runner_iact_nonsym_bh_gas_feedback(const float r2, const float *dx, + const float hi, const float hj, + struct bpart *bi, struct part *pj, + struct xpart *xpj, + const struct cosmology *cosmo, + const struct gravity_props *grav_props, + const integertime_t ti_current) { #ifdef DEBUG_INTERACTIONS_BH /* Update ngb counters */ if (si->num_ngb_force < MAX_NUM_OF_NEIGHBOURS_BH) diff --git a/src/black_holes/Default/black_holes_io.h b/src/black_holes/Default/black_holes_io.h index 53322da1dd90a98fb0f1f2529774a20dc718b30c..b2c3374aec6650a5cf29dc80a7485067de38fefb 100644 --- a/src/black_holes/Default/black_holes_io.h +++ b/src/black_holes/Default/black_holes_io.h @@ -52,10 +52,11 @@ INLINE static void black_holes_read_particles(struct bpart* bparts, INLINE static void convert_bpart_pos(const struct engine* e, const struct bpart* bp, double* ret) { - if (e->s->periodic) { - ret[0] = box_wrap(bp->x[0], 0.0, e->s->dim[0]); - ret[1] = box_wrap(bp->x[1], 0.0, e->s->dim[1]); - ret[2] = box_wrap(bp->x[2], 0.0, e->s->dim[2]); + const struct space* s = e->s; + if (s->periodic) { + ret[0] = box_wrap(bp->x[0] - s->pos_dithering[0], 0.0, s->dim[0]); + ret[1] = box_wrap(bp->x[1] - s->pos_dithering[1], 0.0, s->dim[1]); + ret[2] = box_wrap(bp->x[2] - s->pos_dithering[2], 0.0, s->dim[2]); } else { ret[0] = bp->x[0]; ret[1] = bp->x[1]; diff --git a/src/black_holes/Default/black_holes_struct.h b/src/black_holes/Default/black_holes_struct.h index 0b06ded1a7ac3114363f1e49fc527a18dd5a1cf9..0aaefb7ccf54f9c9b8c8da213f3a83436c73bcf7 100644 --- a/src/black_holes/Default/black_holes_struct.h +++ b/src/black_holes/Default/black_holes_struct.h @@ -41,6 +41,16 @@ black_holes_mark_part_as_not_swallowed(struct black_holes_part_data* p_data) { /* Nothing to do here: No swallowing in the default model */ } +/** + * @brief Reset the particle-carried potential at the start of a time-step. + * + * Nothing to do here. + * + * @param p_data The #part's black hole data. + */ +__attribute__((always_inline)) INLINE static void black_holes_init_potential( + struct black_holes_part_data* p_data) {} + /** * @brief Update a given #part's BH data field to mark the particle has * having been been swallowed. diff --git a/src/black_holes/EAGLE/black_holes.h b/src/black_holes/EAGLE/black_holes.h index a1b41f0954e1bec890329779d0edb7fcd31265f1..e493e89f0e20d82e4304f7c19003ad261a185b93 100644 --- a/src/black_holes/EAGLE/black_holes.h +++ b/src/black_holes/EAGLE/black_holes.h @@ -62,6 +62,14 @@ __attribute__((always_inline)) INLINE static void black_holes_first_init_bpart( bp->formation_time = -1.f; bp->cumulative_number_seeds = 1; bp->number_of_mergers = 0; + bp->last_high_Eddington_fraction_scale_factor = -1.f; + bp->last_minor_merger_time = -1.; + bp->last_major_merger_time = -1.; + bp->swallowed_angular_momentum[0] = 0.f; + bp->swallowed_angular_momentum[1] = 0.f; + bp->swallowed_angular_momentum[2] = 0.f; + + black_holes_mark_bpart_as_not_swallowed(&bp->merger_data); } /** @@ -90,10 +98,11 @@ __attribute__((always_inline)) INLINE static void black_holes_init_bpart( bp->circular_velocity_gas[2] = 0.f; bp->ngb_mass = 0.f; bp->num_ngbs = 0; - bp->reposition.x[0] = -FLT_MAX; - bp->reposition.x[1] = -FLT_MAX; - bp->reposition.x[2] = -FLT_MAX; + bp->reposition.delta_x[0] = -FLT_MAX; + bp->reposition.delta_x[1] = -FLT_MAX; + bp->reposition.delta_x[2] = -FLT_MAX; bp->reposition.min_potential = FLT_MAX; + bp->reposition.potential = FLT_MAX; } /** @@ -112,19 +121,40 @@ __attribute__((always_inline)) INLINE static void black_holes_predict_extra( if (bp->reposition.min_potential != FLT_MAX) { #ifdef SWIFT_DEBUG_CHECKS - if (bp->reposition.x[0] == -FLT_MAX || bp->reposition.x[1] == -FLT_MAX || - bp->reposition.x[2] == -FLT_MAX) { + if (bp->reposition.delta_x[0] == -FLT_MAX || + bp->reposition.delta_x[1] == -FLT_MAX || + bp->reposition.delta_x[2] == -FLT_MAX) { error("Something went wrong with the new repositioning position"); } -#endif - bp->x[0] = bp->reposition.x[0]; - bp->x[1] = bp->reposition.x[1]; - bp->x[2] = bp->reposition.x[2]; + const double dx = bp->reposition.delta_x[0]; + const double dy = bp->reposition.delta_x[1]; + const double dz = bp->reposition.delta_x[2]; + const double d = sqrt(dx * dx + dy * dy + dz * dz); + if (d > 1.01 * kernel_gamma * bp->h) + error("Repositioning BH beyond the kernel support!"); +#endif - bp->gpart->x[0] = bp->reposition.x[0]; - bp->gpart->x[1] = bp->reposition.x[1]; - bp->gpart->x[2] = bp->reposition.x[2]; + /* Move the black hole */ + bp->x[0] += bp->reposition.delta_x[0]; + bp->x[1] += bp->reposition.delta_x[1]; + bp->x[2] += bp->reposition.delta_x[2]; + + /* Move its gravity properties as well */ + bp->gpart->x[0] += bp->reposition.delta_x[0]; + bp->gpart->x[1] += bp->reposition.delta_x[1]; + bp->gpart->x[2] += bp->reposition.delta_x[2]; + + /* Store the delta position */ + bp->x_diff[0] -= bp->reposition.delta_x[0]; + bp->x_diff[1] -= bp->reposition.delta_x[1]; + bp->x_diff[2] -= bp->reposition.delta_x[2]; + + /* Reset the reposition variables */ + bp->reposition.delta_x[0] = -FLT_MAX; + bp->reposition.delta_x[1] = -FLT_MAX; + bp->reposition.delta_x[2] = -FLT_MAX; + bp->reposition.min_potential = FLT_MAX; } } @@ -227,6 +257,24 @@ __attribute__((always_inline)) INLINE static void black_holes_swallow_part( bp->mass += gas_mass; bp->gpart->mass += gas_mass; + /* Physical velocity difference between the particles */ + const float dv[3] = {(bp->v[0] - p->v[0]) * cosmo->a_inv, + (bp->v[1] - p->v[1]) * cosmo->a_inv, + (bp->v[2] - p->v[2]) * cosmo->a_inv}; + + /* Physical distance between the particles */ + const float dx[3] = {(bp->x[0] - p->x[0]) * cosmo->a, + (bp->x[0] - p->x[0]) * cosmo->a, + (bp->x[0] - p->x[0]) * cosmo->a}; + + /* Collect the swallowed angular momentum */ + bp->swallowed_angular_momentum[0] += + gas_mass * (dx[1] * dv[2] - dx[2] * dv[1]); + bp->swallowed_angular_momentum[1] += + gas_mass * (dx[2] * dv[0] - dx[0] * dv[2]); + bp->swallowed_angular_momentum[2] += + gas_mass * (dx[0] * dv[1] - dx[1] * dv[0]); + /* Update the BH momentum */ const float BH_mom[3] = {BH_mass * bp->v[0] + gas_mass * p->v[0], BH_mass * bp->v[1] + gas_mass * p->v[1], @@ -242,22 +290,7 @@ __attribute__((always_inline)) INLINE static void black_holes_swallow_part( /* Update the BH metal masses */ struct chemistry_bpart_data* bp_chem = &bp->chemistry_data; const struct chemistry_part_data* p_chem = &p->chemistry_data; - - bp_chem->metal_mass_total += p_chem->metal_mass_fraction_total * gas_mass; - for (int i = 0; i < chemistry_element_count; ++i) { - bp_chem->metal_mass[i] += p_chem->metal_mass_fraction[i] * gas_mass; - } - bp_chem->mass_from_SNIa += p_chem->mass_from_SNIa; - bp_chem->mass_from_SNII += p_chem->mass_from_SNII; - bp_chem->mass_from_AGB += p_chem->mass_from_AGB; - bp_chem->metal_mass_from_SNIa += - p_chem->metal_mass_fraction_from_SNIa * gas_mass; - bp_chem->metal_mass_from_SNII += - p_chem->metal_mass_fraction_from_SNII * gas_mass; - bp_chem->metal_mass_from_AGB += - p_chem->metal_mass_fraction_from_AGB * gas_mass; - bp_chem->iron_mass_from_SNIa += - p_chem->iron_mass_fraction_from_SNIa * gas_mass; + chemistry_add_part_to_bpart(bp_chem, p_chem, gas_mass); /* This BH lost a neighbour */ bp->num_ngbs--; @@ -271,19 +304,45 @@ __attribute__((always_inline)) INLINE static void black_holes_swallow_part( * @param bpi The #bpart to update. * @param bpj The #bpart that is swallowed. * @param cosmo The current cosmological model. + * @param time Time since the start of the simulation (non-cosmo mode). + * @param with_cosmology Are we running with cosmology? + * @param props The properties of the black hole scheme. */ __attribute__((always_inline)) INLINE static void black_holes_swallow_bpart( - struct bpart* bpi, const struct bpart* bpj, const struct cosmology* cosmo) { + struct bpart* bpi, const struct bpart* bpj, const struct cosmology* cosmo, + const double time, const int with_cosmology, + const struct black_holes_props* props) { /* Get the current dynamical masses */ const float bpi_dyn_mass = bpi->mass; const float bpj_dyn_mass = bpj->mass; + /* Is this merger ratio above the threshold for recording? */ + const double merger_ratio = bpj->subgrid_mass / bpi->subgrid_mass; + if (merger_ratio > props->major_merger_threshold) { + if (with_cosmology) { + bpi->last_major_merger_scale_factor = cosmo->a; + } else { + bpi->last_major_merger_time = time; + } + } else if (merger_ratio > props->minor_merger_threshold) { + if (with_cosmology) { + bpi->last_minor_merger_scale_factor = cosmo->a; + } else { + bpi->last_minor_merger_time = time; + } + } + /* Increase the masses of the BH. */ bpi->mass += bpj->mass; bpi->gpart->mass += bpj->mass; bpi->subgrid_mass += bpj->subgrid_mass; + /* Collect the swallowed angular momentum */ + bpi->swallowed_angular_momentum[0] += bpj->swallowed_angular_momentum[0]; + bpi->swallowed_angular_momentum[1] += bpj->swallowed_angular_momentum[1]; + bpi->swallowed_angular_momentum[2] += bpj->swallowed_angular_momentum[2]; + /* Update the BH momentum */ const float BH_mom[3] = {bpi_dyn_mass * bpi->v[0] + bpj_dyn_mass * bpj->v[0], bpi_dyn_mass * bpi->v[1] + bpj_dyn_mass * bpj->v[1], @@ -296,6 +355,11 @@ __attribute__((always_inline)) INLINE static void black_holes_swallow_bpart( bpi->gpart->v_full[1] = bpi->v[1]; bpi->gpart->v_full[2] = bpi->v[2]; + /* Update the BH metal masses */ + struct chemistry_bpart_data* bpi_chem = &bpi->chemistry_data; + const struct chemistry_bpart_data* bpj_chem = &bpj->chemistry_data; + chemistry_add_bpart_to_bpart(bpi_chem, bpj_chem); + /* Update the energy reservoir */ bpi->energy_reservoir += bpj->energy_reservoir; @@ -314,12 +378,14 @@ __attribute__((always_inline)) INLINE static void black_holes_swallow_bpart( * @param props The properties of the black hole scheme. * @param constants The physical constants (in internal units). * @param cosmo The cosmological model. + * @param time Time since the start of the simulation (non-cosmo mode). + * @param with_cosmology Are we running with cosmology? * @param dt The time-step size (in physical internal units). */ __attribute__((always_inline)) INLINE static void black_holes_prepare_feedback( struct bpart* restrict bp, const struct black_holes_props* props, const struct phys_const* constants, const struct cosmology* cosmo, - const double dt) { + const double time, const int with_cosmology, const double dt) { if (dt == 0.) return; @@ -331,6 +397,7 @@ __attribute__((always_inline)) INLINE static void black_holes_prepare_feedback( /* Gather the parameters of the model */ const double f_Edd = props->f_Edd; + const double f_Edd_recording = props->f_Edd_recording; const double epsilon_r = props->epsilon_r; const double epsilon_f = props->epsilon_f; const double num_ngbs_to_heat = props->num_ngbs_to_heat; @@ -398,6 +465,15 @@ __attribute__((always_inline)) INLINE static void black_holes_prepare_feedback( const double Eddington_rate = 4. * M_PI * G * BH_mass * proton_mass / (epsilon_r * c * sigma_Thomson); + /* Shall we record this high rate? */ + if (Bondi_rate > f_Edd_recording * Eddington_rate) { + if (with_cosmology) { + bp->last_high_Eddington_fraction_scale_factor = cosmo->a; + } else { + bp->last_high_Eddington_fraction_time = time; + } + } + /* Limit the accretion rate to the Eddington fraction */ const double accr_rate = min(Bondi_rate, f_Edd * Eddington_rate); bp->accretion_rate = accr_rate; @@ -481,9 +557,9 @@ __attribute__((always_inline)) INLINE static void black_holes_end_reposition( /* No need to reposition */ bp->reposition.min_potential = FLT_MAX; - bp->reposition.x[0] = -FLT_MAX; - bp->reposition.x[1] = -FLT_MAX; - bp->reposition.x[2] = -FLT_MAX; + bp->reposition.delta_x[0] = -FLT_MAX; + bp->reposition.delta_x[1] = -FLT_MAX; + bp->reposition.delta_x[2] = -FLT_MAX; } } @@ -509,6 +585,36 @@ __attribute__((always_inline)) INLINE static void black_holes_reset_feedback( #endif } +/** + * @brief Store the gravitational potential of a black hole by copying it from + * its #gpart friend. + * + * @param bp The black hole particle. + * @param gp The black hole's #gpart. + */ +__attribute__((always_inline)) INLINE static void +black_holes_store_potential_in_bpart(struct bpart* bp, const struct gpart* gp) { + +#ifdef SWIFT_DEBUG_CHECKS + if (bp->gpart != gp) error("Copying potential to the wrong black hole!"); +#endif + + bp->reposition.potential = gp->potential; +} + +/** + * @brief Store the gravitational potential of a particle by copying it from + * its #gpart friend. + * + * @param p_data The black hole data of a gas particle. + * @param gp The black hole's #gpart. + */ +__attribute__((always_inline)) INLINE static void +black_holes_store_potential_in_part(struct black_holes_part_data* p_data, + const struct gpart* gp) { + p_data->potential = gp->potential; +} + /** * @brief Initialise a BH particle that has just been seeded. * @@ -540,25 +646,21 @@ INLINE static void black_holes_create_from_gas( /* Initial metal masses */ const float gas_mass = hydro_get_mass(p); - struct chemistry_bpart_data* bp_chem = &bp->chemistry_data; const struct chemistry_part_data* p_chem = &p->chemistry_data; + chemistry_bpart_from_part(bp_chem, p_chem, gas_mass); - bp_chem->metal_mass_total = p_chem->metal_mass_fraction_total * gas_mass; - for (int i = 0; i < chemistry_element_count; ++i) { - bp_chem->metal_mass[i] = p_chem->metal_mass_fraction[i] * gas_mass; - } - bp_chem->mass_from_SNIa = p_chem->mass_from_SNIa; - bp_chem->mass_from_SNII = p_chem->mass_from_SNII; - bp_chem->mass_from_AGB = p_chem->mass_from_AGB; - bp_chem->metal_mass_from_SNIa = - p_chem->metal_mass_fraction_from_SNIa * gas_mass; - bp_chem->metal_mass_from_SNII = - p_chem->metal_mass_fraction_from_SNII * gas_mass; - bp_chem->metal_mass_from_AGB = - p_chem->metal_mass_fraction_from_AGB * gas_mass; - bp_chem->iron_mass_from_SNIa = - p_chem->iron_mass_fraction_from_SNIa * gas_mass; + /* No swallowed angular momentum */ + bp->swallowed_angular_momentum[0] = 0.f; + bp->swallowed_angular_momentum[1] = 0.f; + bp->swallowed_angular_momentum[2] = 0.f; + + /* Last time this BH had a high Eddington fraction */ + bp->last_high_Eddington_fraction_scale_factor = -1.f; + + /* Last time of mergers */ + bp->last_minor_merger_time = -1.; + bp->last_major_merger_time = -1.; /* First initialisation */ black_holes_init_bpart(bp); diff --git a/src/black_holes/EAGLE/black_holes_iact.h b/src/black_holes/EAGLE/black_holes_iact.h index 3e2238dc2a05f73dc9020b66f754e26a5976572a..5677ef23dff8cf49b503dc0f00dd91f371a0dbd1 100644 --- a/src/black_holes/EAGLE/black_holes_iact.h +++ b/src/black_holes/EAGLE/black_holes_iact.h @@ -20,10 +20,13 @@ #define SWIFT_EAGLE_BH_IACT_H /* Local includes */ +#include "black_holes_parameters.h" #include "gravity.h" #include "hydro.h" #include "random.h" #include "space.h" +#include "timestep_sync_part.h" +#include "tracers.h" /** * @brief Density interaction between two particles (non-symmetric). @@ -40,11 +43,13 @@ * @param ti_current Current integer time value (for random numbers). */ __attribute__((always_inline)) INLINE static void -runner_iact_nonsym_bh_gas_density( - const float r2, const float *dx, const float hi, const float hj, - struct bpart *restrict bi, const struct part *restrict pj, - const struct xpart *restrict xpj, const struct cosmology *cosmo, - const struct gravity_props *grav_props, const integertime_t ti_current) { +runner_iact_nonsym_bh_gas_density(const float r2, const float *dx, + const float hi, const float hj, + struct bpart *bi, const struct part *pj, + const struct xpart *xpj, + const struct cosmology *cosmo, + const struct gravity_props *grav_props, + const integertime_t ti_current) { float wi, wi_dx; @@ -121,11 +126,13 @@ runner_iact_nonsym_bh_gas_density( * @param ti_current Current integer time value (for random numbers). */ __attribute__((always_inline)) INLINE static void -runner_iact_nonsym_bh_gas_swallow( - const float r2, const float *dx, const float hi, const float hj, - struct bpart *restrict bi, struct part *restrict pj, - struct xpart *restrict xpj, const struct cosmology *cosmo, - const struct gravity_props *grav_props, const integertime_t ti_current) { +runner_iact_nonsym_bh_gas_swallow(const float r2, const float *dx, + const float hi, const float hj, + struct bpart *bi, struct part *pj, + struct xpart *xpj, + const struct cosmology *cosmo, + const struct gravity_props *grav_props, + const integertime_t ti_current) { float wi; @@ -141,11 +148,13 @@ runner_iact_nonsym_bh_gas_swallow( /* Start by checking the repositioning criteria */ - /* Note the factor 9 is taken from EAGLE. Will be turned into a parameter */ + /* (Square of) Max repositioning distance allowed based on the softening */ const float max_dist_repos2 = kernel_gravity_softening_plummer_equivalent_inv * - kernel_gravity_softening_plummer_equivalent_inv * 9.f * - grav_props->epsilon_baryon_cur * grav_props->epsilon_baryon_cur; + kernel_gravity_softening_plummer_equivalent_inv * + const_max_repositioning_distance_ratio * + const_max_repositioning_distance_ratio * grav_props->epsilon_baryon_cur * + grav_props->epsilon_baryon_cur; /* This gas neighbour is close enough that we can consider it's potential for repositioning */ @@ -163,16 +172,16 @@ runner_iact_nonsym_bh_gas_swallow( /* Check the velocity criterion */ if (v2_pec < 0.25f * bi->sound_speed_gas * bi->sound_speed_gas) { - const float potential = gravity_get_comoving_potential(pj->gpart); + const float potential = pj->black_holes_data.potential; /* Is the potential lower? */ if (potential < bi->reposition.min_potential) { /* Store this as our new best */ bi->reposition.min_potential = potential; - bi->reposition.x[0] = pj->x[0]; - bi->reposition.x[1] = pj->x[1]; - bi->reposition.x[2] = pj->x[2]; + bi->reposition.delta_x[0] = -dx[0]; + bi->reposition.delta_x[1] = -dx[1]; + bi->reposition.delta_x[2] = -dx[2]; } } } @@ -231,8 +240,7 @@ runner_iact_nonsym_bh_gas_swallow( __attribute__((always_inline)) INLINE static void runner_iact_nonsym_bh_bh_swallow(const float r2, const float *dx, const float hi, const float hj, - struct bpart *restrict bi, - struct bpart *restrict bj, + struct bpart *bi, struct bpart *bj, const struct cosmology *cosmo, const struct gravity_props *grav_props, const integertime_t ti_current) { @@ -246,11 +254,13 @@ runner_iact_nonsym_bh_bh_swallow(const float r2, const float *dx, const float v2_pec = v2 * cosmo->a2_inv; - /* Note the factor 9 is taken from EAGLE. Will be turned into a parameter */ + /* (Square of) Max repositioning distance allowed based on the softening */ const float max_dist_repos2 = kernel_gravity_softening_plummer_equivalent_inv * - kernel_gravity_softening_plummer_equivalent_inv * 9.f * - grav_props->epsilon_baryon_cur * grav_props->epsilon_baryon_cur; + kernel_gravity_softening_plummer_equivalent_inv * + const_max_repositioning_distance_ratio * + const_max_repositioning_distance_ratio * grav_props->epsilon_baryon_cur * + grav_props->epsilon_baryon_cur; /* This gas neighbour is close enough that we can consider it's potential for repositioning */ @@ -259,16 +269,16 @@ runner_iact_nonsym_bh_bh_swallow(const float r2, const float *dx, /* Check the velocity criterion */ if (v2_pec < 0.25f * bi->sound_speed_gas * bi->sound_speed_gas) { - const float potential = gravity_get_comoving_potential(bj->gpart); + const float potential = bj->reposition.potential; /* Is the potential lower? */ if (potential < bi->reposition.min_potential) { /* Store this as our new best */ bi->reposition.min_potential = potential; - bi->reposition.x[0] = bj->x[0]; - bi->reposition.x[1] = bj->x[1]; - bi->reposition.x[2] = bj->x[2]; + bi->reposition.delta_x[0] = -dx[0]; + bi->reposition.delta_x[1] = -dx[1]; + bi->reposition.delta_x[2] = -dx[2]; } } } @@ -281,10 +291,11 @@ runner_iact_nonsym_bh_bh_swallow(const float r2, const float *dx, h = hj; } - /* Note the factor 9 is taken from EAGLE. Will be turned into a parameter */ + /* (Square of) Max swallowing distance allowed based on the softening */ const float max_dist_merge2 = kernel_gravity_softening_plummer_equivalent_inv * - kernel_gravity_softening_plummer_equivalent_inv * 9.f * + kernel_gravity_softening_plummer_equivalent_inv * + const_max_merging_distance_ratio * const_max_merging_distance_ratio * grav_props->epsilon_baryon_cur * grav_props->epsilon_baryon_cur; const float G_Newton = grav_props->G_Newton; @@ -338,11 +349,13 @@ runner_iact_nonsym_bh_bh_swallow(const float r2, const float *dx, * @param ti_current Current integer time value (for random numbers). */ __attribute__((always_inline)) INLINE static void -runner_iact_nonsym_bh_gas_feedback( - const float r2, const float *dx, const float hi, const float hj, - const struct bpart *restrict bi, struct part *restrict pj, - struct xpart *restrict xpj, const struct cosmology *cosmo, - const struct gravity_props *grav_props, const integertime_t ti_current) { +runner_iact_nonsym_bh_gas_feedback(const float r2, const float *dx, + const float hi, const float hj, + const struct bpart *bi, struct part *pj, + struct xpart *xpj, + const struct cosmology *cosmo, + const struct gravity_props *grav_props, + const integertime_t ti_current) { /* Get the heating probability */ const float prob = bi->to_distribute.AGN_heating_probability; @@ -368,10 +381,16 @@ runner_iact_nonsym_bh_gas_feedback( /* Impose maximal viscosity */ hydro_diffusive_feedback_reset(pj); + /* Mark this particle has having been heated by AGN feedback */ + tracers_after_black_holes_feedback(xpj); + /* message( */ /* "We did some AGN heating! id %llu BH id %llu probability " */ /* " %.5e random_num %.5e du %.5e du/ini %.5e", */ /* pj->id, bi->id, prob, rand, delta_u, delta_u / u_init); */ + + /* Synchronize the particle on the timeline */ + timestep_sync_part(pj); } } diff --git a/src/black_holes/EAGLE/black_holes_io.h b/src/black_holes/EAGLE/black_holes_io.h index cd6c4599f93b3a324ed2be16e6e3fb4ee06ec02c..7461d16958436e9b529779797f7b3a0b88c0bfaf 100644 --- a/src/black_holes/EAGLE/black_holes_io.h +++ b/src/black_holes/EAGLE/black_holes_io.h @@ -19,6 +19,7 @@ #ifndef SWIFT_EAGLE_BLACK_HOLES_IO_H #define SWIFT_EAGLE_BLACK_HOLES_IO_H +#include "adiabatic_index.h" #include "black_holes_part.h" #include "io_properties.h" @@ -54,10 +55,11 @@ INLINE static void black_holes_read_particles(struct bpart* bparts, INLINE static void convert_bpart_pos(const struct engine* e, const struct bpart* bp, double* ret) { - if (e->s->periodic) { - ret[0] = box_wrap(bp->x[0], 0.0, e->s->dim[0]); - ret[1] = box_wrap(bp->x[1], 0.0, e->s->dim[1]); - ret[2] = box_wrap(bp->x[2], 0.0, e->s->dim[2]); + const struct space* s = e->s; + if (s->periodic) { + ret[0] = box_wrap(bp->x[0] - s->pos_dithering[0], 0.0, s->dim[0]); + ret[1] = box_wrap(bp->x[1] - s->pos_dithering[1], 0.0, s->dim[1]); + ret[2] = box_wrap(bp->x[2] - s->pos_dithering[2], 0.0, s->dim[2]); } else { ret[0] = bp->x[0]; ret[1] = bp->x[1]; @@ -112,7 +114,7 @@ INLINE static void black_holes_write_particles(const struct bpart* bparts, int with_cosmology) { /* Say how much we want to write */ - *num_fields = 12; + *num_fields = 18; /* List what we want to write */ list[0] = io_make_output_field_convert_bpart( @@ -178,6 +180,57 @@ INLINE static void black_holes_write_particles(const struct bpart* bparts, cumulative_number_seeds, "Total number of BH seeds that have merged into this black hole"); + list[13] = + io_make_output_field("NumberOfMergers", INT, 1, UNIT_CONV_NO_UNITS, 0.f, + bparts, number_of_mergers, + "Number of mergers the black holes went through. " + "This does not include the number of mergers " + "accumulated by any merged black hole."); + + if (with_cosmology) { + list[14] = io_make_output_field( + "LastHighEddingtonFractionScaleFactors", FLOAT, 1, UNIT_CONV_NO_UNITS, + 0.f, bparts, last_high_Eddington_fraction_scale_factor, + "Scale-factors at which the black holes last reached a large Eddington " + "ratio. -1 if never reached."); + } else { + list[14] = io_make_output_field( + "LastHighEddingtonFractionTimes", FLOAT, 1, UNIT_CONV_TIME, 0.f, bparts, + last_high_Eddington_fraction_time, + "Times at which the black holes last reached a large Eddington ratio. " + "-1 if never reached."); + } + + if (with_cosmology) { + list[15] = io_make_output_field( + "LastMinorMergerScaleFactors", FLOAT, 1, UNIT_CONV_NO_UNITS, 0.f, + bparts, last_minor_merger_scale_factor, + "Scale-factors at which the black holes last had a minor merger."); + } else { + list[15] = io_make_output_field( + "LastMinorMergerScaleTimes", FLOAT, 1, UNIT_CONV_TIME, 0.f, bparts, + last_minor_merger_time, + "Times at which the black holes last had a minor merger."); + } + + if (with_cosmology) { + list[16] = io_make_output_field( + "LastMajorMergerScaleFactors", FLOAT, 1, UNIT_CONV_NO_UNITS, 0.f, + bparts, last_major_merger_scale_factor, + "Scale-factors at which the black holes last had a major merger."); + } else { + list[16] = io_make_output_field( + "LastMajorMergerScaleTimes", FLOAT, 1, UNIT_CONV_TIME, 0.f, bparts, + last_major_merger_time, + "Times at which the black holes last had a major merger."); + } + + list[17] = io_make_output_field( + "SwallowedAngularMomenta", FLOAT, 3, UNIT_CONV_ANGULAR_MOMENTUM, 0.f, + bparts, swallowed_angular_momentum, + "Physical angular momenta that the black holes have accumulated by " + "swallowing gas particles."); + #ifdef DEBUG_INTERACTIONS_BLACK_HOLES list += *num_fields; diff --git a/src/black_holes/EAGLE/black_holes_parameters.h b/src/black_holes/EAGLE/black_holes_parameters.h new file mode 100644 index 0000000000000000000000000000000000000000..cb6438bc85b4f113e5f1b1f6122ebf9fcc7088c6 --- /dev/null +++ b/src/black_holes/EAGLE/black_holes_parameters.h @@ -0,0 +1,39 @@ +/******************************************************************************* + * This file is part of SWIFT. + * Coypright (c) 2019 Matthieu Schaller (schaller@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_EAGLE_BLACK_HOLES_PARAMETERS_H +#define SWIFT_EAGLE_BLACK_HOLES_PARAMETERS_H + +/* Configuration file */ +#include "config.h" + +/** + * @file EAGLE/black_holes_parameters.h + * @brief Parameters of the EAGLE black holes + * model that need to be defined at compile time. + */ + +/*! Maximal distance for merging particles in units of the (spline not Plummer) + * softening length. */ +#define const_max_merging_distance_ratio 3.f + +/*! Maximal distance for repositioning particles in units of the (spline not + * Plummer) softening length. */ +#define const_max_repositioning_distance_ratio 3.f + +#endif /* SWIFT_EAGLE_BLACK_HOLES_PARAMETERS_H */ diff --git a/src/black_holes/EAGLE/black_holes_part.h b/src/black_holes/EAGLE/black_holes_part.h index 4d8a9c8e177cc64d7e3191c046ff95c374b2d4a4..46dd43718d506537e7515f917ab637b17b334e8c 100644 --- a/src/black_holes/EAGLE/black_holes_part.h +++ b/src/black_holes/EAGLE/black_holes_part.h @@ -77,8 +77,8 @@ struct bpart { /*! Subgrid mass of the black hole */ float subgrid_mass; - /*! Total accreted mass of the black hole (including accreted mass onto BHs - * that were merged) */ + /*! Total accreted mass of the black hole (not including mass merged in + * from other black holes) */ float total_accreted_mass; /*! Energy reservoir for feedback */ @@ -111,6 +111,39 @@ struct bpart { /*! Total number of BH merger events (i.e. not including all progenies) */ int number_of_mergers; + /*! Total (physical) angular momentum accumulated by swallowing particles */ + float swallowed_angular_momentum[3]; + + /*! Union for the last high Eddington ratio point in time */ + union { + + /*! Last time the BH had a a high Eddington fraction */ + float last_high_Eddington_fraction_time; + + /*! Last scale factor the BH had a a high Eddington fraction */ + float last_high_Eddington_fraction_scale_factor; + }; + + /*! Union for the last minor merger point in time */ + union { + + /*! Last time the BH had a a high Eddington fraction */ + float last_minor_merger_time; + + /*! Last scale factor the BH had a a high Eddington fraction */ + float last_minor_merger_scale_factor; + }; + + /*! Union for the last major merger point in time */ + union { + + /*! Last time the BH had a a high Eddington fraction */ + float last_major_merger_time; + + /*! Last scale factor the BH had a a high Eddington fraction */ + float last_major_merger_scale_factor; + }; + /*! Properties used in the feedback loop to distribute to gas neighbours. */ struct { @@ -124,11 +157,14 @@ struct bpart { struct { + /*! Gravitational potential copied from the #gpart. */ + float potential; + /*! Value of the minimum potential across all neighbours. */ float min_potential; - /*! New position of the BH following the reposition procedure */ - double x[3]; + /*! Delta position to apply after the reposition procedure */ + double delta_x[3]; } reposition; diff --git a/src/black_holes/EAGLE/black_holes_properties.h b/src/black_holes/EAGLE/black_holes_properties.h index db50e5b3e08b1a66497aaf75da9d3acdea3287ee..b238294a5c8ead519767b52130a4ac4ced24956a 100644 --- a/src/black_holes/EAGLE/black_holes_properties.h +++ b/src/black_holes/EAGLE/black_holes_properties.h @@ -66,6 +66,9 @@ struct black_holes_props { /*! Normalisation of the viscuous angular momentum accretion reduction */ float alpha_visc; + /*! Eddington fraction threshold for recording */ + float f_Edd_recording; + /* ---- Properties of the feedback model ------- */ /*! Temperature increase induced by AGN feedback (Kelvin) */ @@ -79,6 +82,14 @@ struct black_holes_props { /*! Maximal mass of BH to reposition */ float max_reposition_mass; + /* ---- Properties of the merger model ---------- */ + + /*! Mass ratio above which a merger is considered 'minor' */ + float minor_merger_threshold; + + /*! Mass ratio above which a merger is considered 'major' */ + float major_merger_threshold; + /* ---- Common conversion factors --------------- */ /*! Conversion factor from temperature to internal energy */ @@ -148,6 +159,8 @@ INLINE static void black_holes_props_init(struct black_holes_props *bp, /* Accretion parameters ---------------------------------- */ bp->f_Edd = parser_get_param_float(params, "EAGLEAGN:max_eddington_fraction"); + bp->f_Edd_recording = parser_get_param_float( + params, "EAGLEAGN:eddington_fraction_for_recording"); bp->epsilon_r = parser_get_param_float(params, "EAGLEAGN:radiative_efficiency"); bp->epsilon_f = @@ -170,6 +183,14 @@ INLINE static void black_holes_props_init(struct black_holes_props *bp, /* Convert to internal units */ bp->max_reposition_mass *= phys_const->const_solar_mass; + /* Merger parameters ------------------------------------- */ + + bp->minor_merger_threshold = + parser_get_param_float(params, "EAGLEAGN:threshold_minor_merger"); + + bp->major_merger_threshold = + parser_get_param_float(params, "EAGLEAGN:threshold_major_merger"); + /* Common conversion factors ----------------------------- */ /* Calculate temperature to internal energy conversion factor (all internal diff --git a/src/black_holes/EAGLE/black_holes_struct.h b/src/black_holes/EAGLE/black_holes_struct.h index 177a54b921bec24f357756e4f777b0ecf1781c30..d744839358a6e56d8f6106a8a42786fd10ef211a 100644 --- a/src/black_holes/EAGLE/black_holes_struct.h +++ b/src/black_holes/EAGLE/black_holes_struct.h @@ -19,6 +19,10 @@ #ifndef SWIFT_BLACK_HOLES_STRUCT_EAGLE_H #define SWIFT_BLACK_HOLES_STRUCT_EAGLE_H +/* Standard headers */ +#include <float.h> + +/* Local includes */ #include "inline.h" /** @@ -28,6 +32,9 @@ struct black_holes_part_data { /*! ID of the black-hole that will swallow this #part. */ long long swallow_id; + + /*! Gravitational potential of the particle (for repositioning) */ + float potential; }; /** @@ -54,6 +61,16 @@ black_holes_mark_part_as_not_swallowed(struct black_holes_part_data* p_data) { p_data->swallow_id = -1; } +/** + * @brief Reset the particle-carried potential at the start of a time-step. + * + * @param p_data The #part's black hole data. + */ +__attribute__((always_inline)) INLINE static void black_holes_init_potential( + struct black_holes_part_data* p_data) { + p_data->potential = FLT_MAX; +} + /** * @brief Update a given #part's BH data field to mark the particle has * having been been swallowed. diff --git a/src/cache.h b/src/cache.h index e2e5185d5ac8e12761037eee1a79a26f827ad843..4b32ac92cf01867997b6bca246ecd01d31ae400f 100644 --- a/src/cache.h +++ b/src/cache.h @@ -340,7 +340,6 @@ __attribute__((always_inline)) INLINE int cache_read_particles_subset_self( * @param sort_i The array of sorted particle indices for cell ci. * @param first_pi The first particle in cell ci that is in range. * @param last_pi The last particle in cell ci that is in range. - * @param last_pi The last particle in cell ci that is in range. * @param loc The cell location to remove from the particle positions. * @param flipped Flag to check whether the cells have been flipped or not. */ diff --git a/src/cell.c b/src/cell.c index 9c88cc0fc625928385cbe274b8a6a2b05f503e83..b6d998ee39bfb053d5c6667e20d83c4be382534a 100644 --- a/src/cell.c +++ b/src/cell.c @@ -67,6 +67,7 @@ #include "space_getsid.h" #include "star_formation.h" #include "stars.h" +#include "task_order.h" #include "timers.h" #include "tools.h" #include "tracers.h" @@ -2462,8 +2463,10 @@ void cell_activate_star_resort_tasks(struct cell *c, struct scheduler *s) { * * @param c The (top-level) #cell. * @param s The #scheduler. + * @param with_feedback Are we running with feedback? */ -void cell_activate_star_formation_tasks(struct cell *c, struct scheduler *s) { +void cell_activate_star_formation_tasks(struct cell *c, struct scheduler *s, + const int with_feedback) { #ifdef SWIFT_DEBUG_CHECKS if (c->depth != 0) error("Function should be called at the top-level only"); @@ -2476,7 +2479,9 @@ void cell_activate_star_formation_tasks(struct cell *c, struct scheduler *s) { scheduler_activate(s, c->hydro.star_formation); /* Activate the star resort tasks at whatever level they are */ - cell_activate_star_resort_tasks(c, s); + if (task_order_star_formation_before_feedback && with_feedback) { + cell_activate_star_resort_tasks(c, s); + } } /** @@ -2589,6 +2594,42 @@ void cell_activate_drift_part(struct cell *c, struct scheduler *s) { } } +void cell_activate_sync_part(struct cell *c, struct scheduler *s) { + /* If this cell is already marked for drift, quit early. */ + if (cell_get_flag(c, cell_flag_do_hydro_sync)) return; + + /* Mark this cell for synchronization. */ + cell_set_flag(c, cell_flag_do_hydro_sync); + + /* Set the do_sub_sync all the way up and activate the super sync + if this has not yet been done. */ + if (c == c->super) { +#ifdef SWIFT_DEBUG_CHECKS + if (c->timestep_sync == NULL) + error("Trying to activate un-existing c->timestep_sync"); +#endif + scheduler_activate(s, c->timestep_sync); + scheduler_activate(s, c->kick1); + } else { + for (struct cell *parent = c->parent; + parent != NULL && !cell_get_flag(parent, cell_flag_do_hydro_sub_sync); + parent = parent->parent) { + /* Mark this cell for drifting */ + cell_set_flag(parent, cell_flag_do_hydro_sub_sync); + + if (parent == c->super) { +#ifdef SWIFT_DEBUG_CHECKS + if (parent->timestep_sync == NULL) + error("Trying to activate un-existing parent->timestep_sync"); +#endif + scheduler_activate(s, parent->timestep_sync); + scheduler_activate(s, parent->kick1); + break; + } + } + } +} + /** * @brief Activate the #gpart drifts on the given cell. */ @@ -2724,6 +2765,7 @@ void cell_activate_limiter(struct cell *c, struct scheduler *s) { error("Trying to activate un-existing c->timestep_limiter"); #endif scheduler_activate(s, c->timestep_limiter); + scheduler_activate(s, c->kick1); } else { for (struct cell *parent = c->parent; parent != NULL && @@ -2738,6 +2780,7 @@ void cell_activate_limiter(struct cell *c, struct scheduler *s) { error("Trying to activate un-existing parent->timestep_limiter"); #endif scheduler_activate(s, parent->timestep_limiter); + scheduler_activate(s, parent->kick1); break; } } @@ -2867,11 +2910,12 @@ void cell_activate_stars_sorts(struct cell *c, int sid, struct scheduler *s) { * @param ci The first #cell we recurse in. * @param cj The second #cell we recurse in. * @param s The task #scheduler. + * @param with_timestep_limiter Are we running with time-step limiting on? */ void cell_activate_subcell_hydro_tasks(struct cell *ci, struct cell *cj, - struct scheduler *s) { + struct scheduler *s, + const int with_timestep_limiter) { const struct engine *e = s->space->e; - const int with_limiter = (e->policy & engine_policy_limiter); /* Store the current dx_max and h_max values. */ ci->hydro.dx_max_part_old = ci->hydro.dx_max_part; @@ -2892,17 +2936,18 @@ void cell_activate_subcell_hydro_tasks(struct cell *ci, struct cell *cj, /* Loop over all progenies and pairs of progenies */ for (int j = 0; j < 8; j++) { if (ci->progeny[j] != NULL) { - cell_activate_subcell_hydro_tasks(ci->progeny[j], NULL, s); + cell_activate_subcell_hydro_tasks(ci->progeny[j], NULL, s, + with_timestep_limiter); for (int k = j + 1; k < 8; k++) if (ci->progeny[k] != NULL) cell_activate_subcell_hydro_tasks(ci->progeny[j], ci->progeny[k], - s); + s, with_timestep_limiter); } } } else { /* We have reached the bottom of the tree: activate drift */ cell_activate_drift_part(ci, s); - if (with_limiter) cell_activate_limiter(ci, s); + if (with_timestep_limiter) cell_activate_limiter(ci, s); } } @@ -2925,7 +2970,7 @@ void cell_activate_subcell_hydro_tasks(struct cell *ci, struct cell *cj, const int pjd = csp->pairs[k].pjd; if (ci->progeny[pid] != NULL && cj->progeny[pjd] != NULL) cell_activate_subcell_hydro_tasks(ci->progeny[pid], cj->progeny[pjd], - s); + s, with_timestep_limiter); } } @@ -2942,9 +2987,9 @@ void cell_activate_subcell_hydro_tasks(struct cell *ci, struct cell *cj, if (cj->nodeID == engine_rank) cell_activate_drift_part(cj, s); /* Also activate the time-step limiter */ - if (ci->nodeID == engine_rank && with_limiter) + if (ci->nodeID == engine_rank && with_timestep_limiter) cell_activate_limiter(ci, s); - if (cj->nodeID == engine_rank && with_limiter) + if (cj->nodeID == engine_rank && with_timestep_limiter) cell_activate_limiter(cj, s); /* Do we need to sort the cells? */ @@ -2962,10 +3007,12 @@ void cell_activate_subcell_hydro_tasks(struct cell *ci, struct cell *cj, * @param cj The second #cell we recurse in. * @param s The task #scheduler. * @param with_star_formation Are we running with star formation switched on? + * @param with_timestep_sync Are we running with time-step synchronization on? */ void cell_activate_subcell_stars_tasks(struct cell *ci, struct cell *cj, struct scheduler *s, - const int with_star_formation) { + const int with_star_formation, + const int with_timestep_sync) { const struct engine *e = s->space->e; /* Store the current dx_max and h_max values. */ @@ -2997,18 +3044,20 @@ void cell_activate_subcell_stars_tasks(struct cell *ci, struct cell *cj, /* 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, - with_star_formation); + cell_activate_subcell_stars_tasks( + ci->progeny[j], NULL, s, with_star_formation, with_timestep_sync); 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, with_star_formation); + s, with_star_formation, + with_timestep_sync); } } } else { /* We have reached the bottom of the tree: activate drift */ cell_activate_drift_spart(ci, s); cell_activate_drift_part(ci, s); + if (with_timestep_sync) cell_activate_sync_part(ci, s); } } @@ -3037,7 +3086,8 @@ void cell_activate_subcell_stars_tasks(struct cell *ci, struct cell *cj, const int pjd = csp->pairs[k].pjd; if (ci->progeny[pid] != NULL && cj->progeny[pjd] != NULL) cell_activate_subcell_stars_tasks(ci->progeny[pid], cj->progeny[pjd], - s, with_star_formation); + s, with_star_formation, + with_timestep_sync); } } @@ -3056,6 +3106,8 @@ void cell_activate_subcell_stars_tasks(struct cell *ci, struct cell *cj, /* Activate the drifts if the cells are local. */ 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 && with_timestep_sync) + cell_activate_sync_part(cj, s); /* Do we need to sort the cells? */ cell_activate_hydro_sorts(cj, sid, s); @@ -3074,6 +3126,8 @@ void cell_activate_subcell_stars_tasks(struct cell *ci, struct cell *cj, /* Activate the drifts if the cells are local. */ if (ci->nodeID == engine_rank) cell_activate_drift_part(ci, s); if (cj->nodeID == engine_rank) cell_activate_drift_spart(cj, s); + if (ci->nodeID == engine_rank && with_timestep_sync) + cell_activate_sync_part(ci, s); /* Do we need to sort the cells? */ cell_activate_hydro_sorts(ci, sid, s); @@ -3331,11 +3385,12 @@ void cell_activate_subcell_external_grav_tasks(struct cell *ci, int cell_unskip_hydro_tasks(struct cell *c, struct scheduler *s) { struct engine *e = s->space->e; const int nodeID = e->nodeID; - const int with_limiter = (e->policy & engine_policy_limiter); + const int with_feedback = e->policy & engine_policy_feedback; + const int with_timestep_limiter = + (e->policy & engine_policy_timestep_limiter); #ifdef WITH_MPI const int with_star_formation = e->policy & engine_policy_star_formation; - const int with_feedback = e->policy & engine_policy_feedback; #endif int rebuild = 0; @@ -3362,7 +3417,8 @@ int cell_unskip_hydro_tasks(struct cell *c, struct scheduler *s) { /* Activate hydro drift */ if (t->type == task_type_self) { if (ci_nodeID == nodeID) cell_activate_drift_part(ci, s); - if (ci_nodeID == nodeID && with_limiter) cell_activate_limiter(ci, s); + if (ci_nodeID == nodeID && with_timestep_limiter) + cell_activate_limiter(ci, s); } /* Set the correct sorting flags and activate hydro drifts */ @@ -3378,8 +3434,10 @@ int cell_unskip_hydro_tasks(struct cell *c, struct scheduler *s) { if (cj_nodeID == nodeID) cell_activate_drift_part(cj, s); /* Activate the limiter tasks. */ - if (ci_nodeID == nodeID && with_limiter) cell_activate_limiter(ci, s); - if (cj_nodeID == nodeID && with_limiter) cell_activate_limiter(cj, s); + if (ci_nodeID == nodeID && with_timestep_limiter) + cell_activate_limiter(ci, s); + if (cj_nodeID == nodeID && with_timestep_limiter) + cell_activate_limiter(cj, s); /* Check the sorts and activate them if needed. */ cell_activate_hydro_sorts(ci, t->flags, s); @@ -3388,12 +3446,12 @@ int cell_unskip_hydro_tasks(struct cell *c, struct scheduler *s) { /* Store current values of dx_max and h_max. */ else if (t->type == task_type_sub_self) { - cell_activate_subcell_hydro_tasks(ci, NULL, s); + cell_activate_subcell_hydro_tasks(ci, NULL, s, with_timestep_limiter); } /* Store current values of dx_max and h_max. */ else if (t->type == task_type_sub_pair) { - cell_activate_subcell_hydro_tasks(ci, cj, s); + cell_activate_subcell_hydro_tasks(ci, cj, s, with_timestep_limiter); } } @@ -3418,16 +3476,15 @@ int cell_unskip_hydro_tasks(struct cell *c, struct scheduler *s) { } } + /* If the foreign cell is active, we want its particles for the limiter + */ + if (ci_active && with_timestep_limiter) + scheduler_activate_recv(s, ci->mpi.recv, task_subtype_limiter); + /* If the foreign cell is active, we want its ti_end values. */ - if (ci_active || with_limiter) + if (ci_active) scheduler_activate_recv(s, ci->mpi.recv, task_subtype_tend_part); - if (with_limiter) - scheduler_activate_recv(s, ci->mpi.recv, task_subtype_limiter); - if (with_limiter) - scheduler_activate_send(s, cj->mpi.send, task_subtype_limiter, - ci->nodeID); - /* Is the foreign cell active and will need stuff from us? */ if (ci_active) { @@ -3436,7 +3493,7 @@ int cell_unskip_hydro_tasks(struct cell *c, struct scheduler *s) { /* Drift the cell which will be sent; note that not all sent particles will be drifted, only those that are needed. */ cell_activate_drift_part(cj, s); - if (with_limiter) cell_activate_limiter(cj, s); + if (with_timestep_limiter) cell_activate_limiter(cj, s); /* If the local cell is also active, more stuff will be needed. */ if (cj_active) { @@ -3450,20 +3507,29 @@ int cell_unskip_hydro_tasks(struct cell *c, struct scheduler *s) { } } + /* If the local cell is active, send its particles for the limiting. */ + if (cj_active && with_timestep_limiter) + scheduler_activate_send(s, cj->mpi.send, task_subtype_limiter, + ci_nodeID); + /* If the local cell is active, send its ti_end values. */ - if (cj_active || with_limiter) + if (cj_active) scheduler_activate_send(s, cj->mpi.send, task_subtype_tend_part, ci_nodeID); /* Propagating new star counts? */ if (with_star_formation && with_feedback) { if (ci_active && ci->hydro.count > 0) { - scheduler_activate_recv(s, ci->mpi.recv, task_subtype_sf_counts); + if (task_order_star_formation_before_feedback) { + scheduler_activate_recv(s, ci->mpi.recv, task_subtype_sf_counts); + } scheduler_activate_recv(s, ci->mpi.recv, task_subtype_tend_spart); } if (cj_active && cj->hydro.count > 0) { - scheduler_activate_send(s, cj->mpi.send, task_subtype_sf_counts, - ci_nodeID); + if (task_order_star_formation_before_feedback) { + scheduler_activate_send(s, cj->mpi.send, task_subtype_sf_counts, + ci_nodeID); + } scheduler_activate_send(s, cj->mpi.send, task_subtype_tend_spart, ci_nodeID); } @@ -3482,16 +3548,15 @@ int cell_unskip_hydro_tasks(struct cell *c, struct scheduler *s) { } } + /* If the foreign cell is active, we want its particles for the limiter + */ + if (cj_active && with_timestep_limiter) + scheduler_activate_recv(s, cj->mpi.recv, task_subtype_limiter); + /* If the foreign cell is active, we want its ti_end values. */ - if (cj_active || with_limiter) + if (cj_active) scheduler_activate_recv(s, cj->mpi.recv, task_subtype_tend_part); - if (with_limiter) - scheduler_activate_recv(s, cj->mpi.recv, task_subtype_limiter); - if (with_limiter) - scheduler_activate_send(s, ci->mpi.send, task_subtype_limiter, - cj->nodeID); - /* Is the foreign cell active and will need stuff from us? */ if (cj_active) { @@ -3500,7 +3565,7 @@ int cell_unskip_hydro_tasks(struct cell *c, struct scheduler *s) { /* Drift the cell which will be sent; note that not all sent particles will be drifted, only those that are needed. */ cell_activate_drift_part(ci, s); - if (with_limiter) cell_activate_limiter(ci, s); + if (with_timestep_limiter) cell_activate_limiter(ci, s); /* If the local cell is also active, more stuff will be needed. */ if (ci_active) { @@ -3515,20 +3580,29 @@ int cell_unskip_hydro_tasks(struct cell *c, struct scheduler *s) { } } + /* If the local cell is active, send its particles for the limiting. */ + if (ci_active && with_timestep_limiter) + scheduler_activate_send(s, ci->mpi.send, task_subtype_limiter, + cj_nodeID); + /* If the local cell is active, send its ti_end values. */ - if (ci_active || with_limiter) + if (ci_active) scheduler_activate_send(s, ci->mpi.send, task_subtype_tend_part, cj_nodeID); /* Propagating new star counts? */ if (with_star_formation && with_feedback) { if (cj_active && cj->hydro.count > 0) { - scheduler_activate_recv(s, cj->mpi.recv, task_subtype_sf_counts); + if (task_order_star_formation_before_feedback) { + scheduler_activate_recv(s, cj->mpi.recv, task_subtype_sf_counts); + } scheduler_activate_recv(s, cj->mpi.recv, task_subtype_tend_spart); } if (ci_active && ci->hydro.count > 0) { - scheduler_activate_send(s, ci->mpi.send, task_subtype_sf_counts, - cj_nodeID); + if (task_order_star_formation_before_feedback) { + scheduler_activate_send(s, ci->mpi.send, task_subtype_sf_counts, + cj_nodeID); + } scheduler_activate_send(s, ci->mpi.send, task_subtype_tend_spart, cj_nodeID); } @@ -3560,7 +3634,7 @@ int cell_unskip_hydro_tasks(struct cell *c, struct scheduler *s) { #endif if (c->top->hydro.star_formation != NULL) { - cell_activate_star_formation_tasks(c->top, s); + cell_activate_star_formation_tasks(c->top, s, with_feedback); } } @@ -3734,6 +3808,7 @@ int cell_unskip_stars_tasks(struct cell *c, struct scheduler *s, const int with_star_formation) { struct engine *e = s->space->e; + const int with_timestep_sync = (e->policy & engine_policy_timestep_sync); const int nodeID = e->nodeID; int rebuild = 0; @@ -3767,8 +3842,9 @@ int cell_unskip_stars_tasks(struct cell *c, struct scheduler *s, /* Activate the drifts */ if (t->type == task_type_self && ci_active) { - cell_activate_drift_part(ci, s); cell_activate_drift_spart(ci, s); + cell_activate_drift_part(ci, s); + if (with_timestep_sync) cell_activate_sync_part(ci, s); } /* Only activate tasks that involve a local active cell. */ @@ -3790,6 +3866,8 @@ int cell_unskip_stars_tasks(struct cell *c, struct scheduler *s, /* Activate the drift tasks. */ if (ci_nodeID == nodeID) cell_activate_drift_spart(ci, s); if (cj_nodeID == nodeID) cell_activate_drift_part(cj, s); + if (cj_nodeID == nodeID && with_timestep_sync) + cell_activate_sync_part(cj, s); /* Check the sorts and activate them if needed. */ cell_activate_stars_sorts(ci, t->flags, s); @@ -3809,6 +3887,8 @@ int cell_unskip_stars_tasks(struct cell *c, struct scheduler *s, /* Activate the drift tasks. */ if (cj_nodeID == nodeID) cell_activate_drift_spart(cj, s); if (ci_nodeID == nodeID) cell_activate_drift_part(ci, s); + if (ci_nodeID == nodeID && with_timestep_sync) + cell_activate_sync_part(ci, s); /* Check the sorts and activate them if needed. */ cell_activate_hydro_sorts(ci, t->flags, s); @@ -3817,11 +3897,13 @@ int cell_unskip_stars_tasks(struct cell *c, struct scheduler *s, } else if (t->type == task_type_sub_self) { - cell_activate_subcell_stars_tasks(ci, NULL, s, with_star_formation); + cell_activate_subcell_stars_tasks(ci, NULL, s, with_star_formation, + with_timestep_sync); } else if (t->type == task_type_sub_pair) { - cell_activate_subcell_stars_tasks(ci, cj, s, with_star_formation); + cell_activate_subcell_stars_tasks(ci, cj, s, with_star_formation, + with_timestep_sync); } } @@ -4546,6 +4628,7 @@ void cell_drift_part(struct cell *c, const struct engine *e, int force) { /* Get ready for a density calculation */ if (part_is_active(p, e)) { hydro_init_part(p, &e->s->hs); + black_holes_init_potential(&p->black_holes_data); chemistry_init_part(p, e->chemistry); pressure_floor_init_part(p, xp); star_formation_init_part(p, e->star_formation); @@ -5179,7 +5262,8 @@ void cell_clear_hydro_sort_flags(struct cell *c, const int clear_unused_flags) { /** * @brief Recursively checks that all particles in a cell have a time-step */ -void cell_check_timesteps(struct cell *c) { +void cell_check_timesteps(const struct cell *c, const integertime_t ti_current, + const timebin_t max_bin) { #ifdef SWIFT_DEBUG_CHECKS if (c->hydro.ti_end_min == 0 && c->grav.ti_end_min == 0 && @@ -5189,13 +5273,68 @@ void cell_check_timesteps(struct cell *c) { if (c->split) { for (int k = 0; k < 8; ++k) - if (c->progeny[k] != NULL) cell_check_timesteps(c->progeny[k]); + if (c->progeny[k] != NULL) + cell_check_timesteps(c->progeny[k], ti_current, max_bin); } else { if (c->nodeID == engine_rank) for (int i = 0; i < c->hydro.count; ++i) if (c->hydro.parts[i].time_bin == 0) error("Particle without assigned time-bin"); } + + /* Other checks not relevent when starting-up */ + if (ti_current == 0) return; + + integertime_t ti_end_min = max_nr_timesteps; + integertime_t ti_end_max = 0; + integertime_t ti_beg_max = 0; + + int count = 0; + + for (int i = 0; i < c->hydro.count; ++i) { + + const struct part *p = &c->hydro.parts[i]; + if (p->time_bin == time_bin_inhibited) continue; + if (p->time_bin == time_bin_not_created) continue; + + ++count; + + integertime_t ti_end, ti_beg; + + if (p->time_bin <= max_bin) { + integertime_t time_step = get_integer_timestep(p->time_bin); + ti_end = get_integer_time_end(ti_current, p->time_bin) + time_step; + ti_beg = get_integer_time_begin(ti_current + 1, p->time_bin); + } else { + ti_end = get_integer_time_end(ti_current, p->time_bin); + ti_beg = get_integer_time_begin(ti_current + 1, p->time_bin); + } + + ti_end_min = min(ti_end, ti_end_min); + ti_end_max = max(ti_end, ti_end_max); + ti_beg_max = max(ti_beg, ti_beg_max); + } + + /* Only check cells that have at least one non-inhibited particle */ + if (count > 0) { + + if (ti_end_min != c->hydro.ti_end_min) + error( + "Non-matching ti_end_min. Cell=%lld true=%lld ti_current=%lld " + "depth=%d", + c->hydro.ti_end_min, ti_end_min, ti_current, c->depth); + if (ti_end_max > c->hydro.ti_end_max) + error( + "Non-matching ti_end_max. Cell=%lld true=%lld ti_current=%lld " + "depth=%d", + c->hydro.ti_end_max, ti_end_max, ti_current, c->depth); + if (ti_beg_max != c->hydro.ti_beg_max) + error( + "Non-matching ti_beg_max. Cell=%lld true=%lld ti_current=%lld " + "depth=%d", + c->hydro.ti_beg_max, ti_beg_max, ti_current, c->depth); + } + #else error("Calling debugging code without debugging flag activated."); #endif diff --git a/src/cell.h b/src/cell.h index 10a3e2bddfebd907b8efaffa472f94c421e4966c..df6949643b35455e55125474acfc9dfc5c13b3fc 100644 --- a/src/cell.h +++ b/src/cell.h @@ -293,6 +293,8 @@ enum cell_flags { cell_flag_do_bh_sub_drift = (1UL << 12), cell_flag_do_stars_resort = (1UL << 13), cell_flag_has_tasks = (1UL << 14), + cell_flag_do_hydro_sync = (1UL << 15), + cell_flag_do_hydro_sub_sync = (1UL << 16) }; /** @@ -758,6 +760,10 @@ struct cell { /*! The task to limit the time-step of inactive particles */ struct task *timestep_limiter; + /*! The task to synchronize the time-step of inactive particles hit by + * feedback */ + struct task *timestep_sync; + #ifdef WITH_LOGGER /*! The logger task */ struct task *logger; @@ -879,17 +885,21 @@ void cell_drift_spart(struct cell *c, const struct engine *e, int force); void cell_drift_bpart(struct cell *c, const struct engine *e, int force); void cell_drift_multipole(struct cell *c, const struct engine *e); void cell_drift_all_multipoles(struct cell *c, const struct engine *e); -void cell_check_timesteps(struct cell *c); +void cell_check_timesteps(const struct cell *c, const integertime_t ti_current, + const timebin_t max_bin); void cell_store_pre_drift_values(struct cell *c); void cell_set_star_resort_flag(struct cell *c); -void cell_activate_star_formation_tasks(struct cell *c, struct scheduler *s); +void cell_activate_star_formation_tasks(struct cell *c, struct scheduler *s, + const int with_feedback); void cell_activate_subcell_hydro_tasks(struct cell *ci, struct cell *cj, - struct scheduler *s); + struct scheduler *s, + const int with_timestep_limiter); void cell_activate_subcell_grav_tasks(struct cell *ci, struct cell *cj, struct scheduler *s); void cell_activate_subcell_stars_tasks(struct cell *ci, struct cell *cj, struct scheduler *s, - const int with_star_formation); + const int with_star_formation, + const int with_timestep_sync); void cell_activate_subcell_black_holes_tasks(struct cell *ci, struct cell *cj, struct scheduler *s); void cell_activate_subcell_external_grav_tasks(struct cell *ci, @@ -899,6 +909,7 @@ void cell_activate_drift_part(struct cell *c, struct scheduler *s); void cell_activate_drift_gpart(struct cell *c, struct scheduler *s); void cell_activate_drift_spart(struct cell *c, struct scheduler *s); void cell_activate_drift_bpart(struct cell *c, struct scheduler *s); +void cell_activate_sync_part(struct cell *c, struct scheduler *s); void cell_activate_hydro_sorts(struct cell *c, int sid, struct scheduler *s); void cell_activate_stars_sorts(struct cell *c, int sid, struct scheduler *s); void cell_activate_limiter(struct cell *c, struct scheduler *s); diff --git a/src/chemistry/EAGLE/chemistry.h b/src/chemistry/EAGLE/chemistry.h index e53050884a443de6dbcd79981fcd60cdcaff8c40..d2f475af9053d148345350cc02004cf501b99165 100644 --- a/src/chemistry/EAGLE/chemistry.h +++ b/src/chemistry/EAGLE/chemistry.h @@ -319,6 +319,105 @@ __attribute__((always_inline)) INLINE static float chemistry_timestep( return FLT_MAX; } +/** + * @brief Initialise the chemistry properties of a black hole with + * the chemistry properties of the gas it is born from. + * + * Black holes don't store fractions so we need to use element masses. + * + * @param bp_data The black hole data to initialise. + * @param p_data The gas data to use. + * @param gas_mass The mass of the gas particle. + */ +__attribute__((always_inline)) INLINE static void chemistry_bpart_from_part( + struct chemistry_bpart_data* bp_data, + const struct chemistry_part_data* p_data, const double gas_mass) { + + bp_data->metal_mass_total = p_data->metal_mass_fraction_total * gas_mass; + for (int i = 0; i < chemistry_element_count; ++i) { + bp_data->metal_mass[i] = p_data->metal_mass_fraction[i] * gas_mass; + } + bp_data->mass_from_SNIa = p_data->mass_from_SNIa; + bp_data->mass_from_SNII = p_data->mass_from_SNII; + bp_data->mass_from_AGB = p_data->mass_from_AGB; + bp_data->metal_mass_from_SNIa = + p_data->metal_mass_fraction_from_SNIa * gas_mass; + bp_data->metal_mass_from_SNII = + p_data->metal_mass_fraction_from_SNII * gas_mass; + bp_data->metal_mass_from_AGB = + p_data->metal_mass_fraction_from_AGB * gas_mass; + bp_data->iron_mass_from_SNIa = + p_data->iron_mass_fraction_from_SNIa * gas_mass; +} + +/** + * @brief Add the chemistry data of a gas particle to a black hole. + * + * Black holes don't store fractions so we need to add element masses. + * + * @param bp_data The black hole data to add to. + * @param p_data The gas data to use. + * @param gas_mass The mass of the gas particle. + */ +__attribute__((always_inline)) INLINE static void chemistry_add_part_to_bpart( + struct chemistry_bpart_data* bp_data, + const struct chemistry_part_data* p_data, const double gas_mass) { + + bp_data->metal_mass_total += p_data->metal_mass_fraction_total * gas_mass; + for (int i = 0; i < chemistry_element_count; ++i) { + bp_data->metal_mass[i] += p_data->metal_mass_fraction[i] * gas_mass; + } + bp_data->mass_from_SNIa += p_data->mass_from_SNIa; + bp_data->mass_from_SNII += p_data->mass_from_SNII; + bp_data->mass_from_AGB += p_data->mass_from_AGB; + bp_data->metal_mass_from_SNIa += + p_data->metal_mass_fraction_from_SNIa * gas_mass; + bp_data->metal_mass_from_SNII += + p_data->metal_mass_fraction_from_SNII * gas_mass; + bp_data->metal_mass_from_AGB += + p_data->metal_mass_fraction_from_AGB * gas_mass; + bp_data->iron_mass_from_SNIa += + p_data->iron_mass_fraction_from_SNIa * gas_mass; +} + +/** + * @brief Add the chemistry data of a black hole to another one. + * + * @param bp_data The black hole data to add to. + * @param swallowed_data The black hole data to use. + */ +__attribute__((always_inline)) INLINE static void chemistry_add_bpart_to_bpart( + struct chemistry_bpart_data* bp_data, + const struct chemistry_bpart_data* swallowed_data) { + + bp_data->metal_mass_total += swallowed_data->metal_mass_total; + for (int i = 0; i < chemistry_element_count; ++i) { + bp_data->metal_mass[i] += swallowed_data->metal_mass[i]; + } + bp_data->mass_from_SNIa += swallowed_data->mass_from_SNIa; + bp_data->mass_from_SNII += swallowed_data->mass_from_SNII; + bp_data->mass_from_AGB += swallowed_data->mass_from_AGB; + bp_data->metal_mass_from_SNIa += swallowed_data->metal_mass_from_SNIa; + bp_data->metal_mass_from_SNII += swallowed_data->metal_mass_from_SNII; + bp_data->metal_mass_from_AGB += swallowed_data->metal_mass_from_AGB; + bp_data->iron_mass_from_SNIa += swallowed_data->iron_mass_from_SNIa; +} + +/** + * @brief Split the metal content of a particle into n pieces + * + * We only need to split the fields that are not fractions. + * + * @param p The #part. + * @param n The number of pieces to split into. + */ +__attribute__((always_inline)) INLINE static void chemistry_split_part( + struct part* p, const double n) { + p->chemistry_data.mass_from_SNIa /= n; + p->chemistry_data.mass_from_SNII /= n; + p->chemistry_data.mass_from_AGB /= n; +} + /** * @brief Returns the total metallicity (metal mass fraction) of the * star particle to be used in feedback/enrichment related routines. diff --git a/src/chemistry/EAGLE/chemistry_io.h b/src/chemistry/EAGLE/chemistry_io.h index 5e671e4c74dafc515812bdbf7516b03c6bcff08e..393952e0b23c92a0783a09f67b66a9600feb5790 100644 --- a/src/chemistry/EAGLE/chemistry_io.h +++ b/src/chemistry/EAGLE/chemistry_io.h @@ -225,12 +225,12 @@ INLINE static int chemistry_write_bparticles(const struct bpart* bparts, list[0] = io_make_output_field( "ElementMasses", FLOAT, chemistry_element_count, UNIT_CONV_MASS, 0.f, bparts, chemistry_data.metal_mass, - "Mass contents of the BH particles in a given element"); + "Masses of the BH particles in a given element"); - list[1] = io_make_output_field( - "MetalMasses", FLOAT, chemistry_element_count, UNIT_CONV_MASS, 0.f, - bparts, chemistry_data.metal_mass_total, - "Mass contents of the BH particles in a metals"); + list[1] = io_make_output_field("MetalMasses", FLOAT, chemistry_element_count, + UNIT_CONV_MASS, 0.f, bparts, + chemistry_data.metal_mass_total, + "Masses of the BH particles in a metals"); list[2] = io_make_output_field( "MassesFromSNIa", FLOAT, 1, UNIT_CONV_MASS, 0.f, bparts, diff --git a/src/chemistry/GEAR/chemistry.h b/src/chemistry/GEAR/chemistry.h index 34c4d10e5fb2f491b029c4c8d76cf04ca7a5429a..ebeb41b3ba991ced597791e3e0e1c3625aa34b53 100644 --- a/src/chemistry/GEAR/chemistry.h +++ b/src/chemistry/GEAR/chemistry.h @@ -27,6 +27,7 @@ /* Some standard headers. */ #include <float.h> #include <math.h> +#include <string.h> /* Local includes. */ #include "chemistry_struct.h" @@ -38,16 +39,21 @@ #include "units.h" /** - * @brief Compute the metal mass fraction + * @brief Copies the chemistry properties of the gas particle over to the + * star particle. * - * @param p Pointer to the particle data. - * @param xp Pointer to the extended particle data. - * @param data The global chemistry information. + * @param p the gas particles. + * @param xp the additional properties of the gas particles. + * @param sp the new created star particle with its properties. */ -__attribute__((always_inline)) INLINE static float -chemistry_metal_mass_fraction(const struct part* restrict p, - const struct xpart* restrict xp) { - return p->chemistry_data.Z; +INLINE static void chemistry_copy_star_formation_properties( + const struct part* p, const struct xpart* xp, struct spart* sp) { + + /* Store the chemistry struct in the star particle */ + for (int i = 0; i < GEAR_CHEMISTRY_ELEMENT_COUNT; i++) { + sp->chemistry_data.metal_mass_fraction[i] = + p->chemistry_data.smoothed_metal_mass_fraction[i]; + } } /** @@ -62,6 +68,60 @@ static INLINE void chemistry_print_backend( message("Chemistry function is 'Gear'."); } +/** + * @brief Read the solar abundances and scale with them the initial + * metallicities. + * + * @param parameter_file The parsed parameter file. + * @param data The properties to initialise. + */ +static INLINE void chemistry_scale_initial_metallicities( + struct swift_params* parameter_file, struct chemistry_global_data* data) { +#ifdef HAVE_HDF5 + + /* Get the yields table */ + char filename[DESCRIPTION_BUFFER_SIZE]; + parser_get_param_string(parameter_file, "GEARFeedback:yields_table", + filename); + + /* Open file. */ + hid_t file_id = H5Fopen(filename, H5F_ACC_RDONLY, H5P_DEFAULT); + if (file_id < 0) error("unable to open file %s.\n", filename); + + /* Open group. */ + hid_t group_id = H5Gopen(file_id, "Data", H5P_DEFAULT); + if (group_id < 0) error("unable to open group Data.\n"); + + /* Read the data */ + float* sol_ab = (float*)malloc(sizeof(float) * GEAR_CHEMISTRY_ELEMENT_COUNT); + io_read_array_attribute(group_id, "SolarMassAbundances", FLOAT, sol_ab, + GEAR_CHEMISTRY_ELEMENT_COUNT); + + /* Close group */ + hid_t status = H5Gclose(group_id); + if (status < 0) error("error closing group."); + + /* Close file */ + status = H5Fclose(file_id); + if (status < 0) error("error closing file."); + + /* Scale the initial metallicities */ + char txt[DESCRIPTION_BUFFER_SIZE] = "Scaling initial metallicities by:"; + for (int i = 0; i < GEAR_CHEMISTRY_ELEMENT_COUNT; i++) { + data->initial_metallicities[i] *= sol_ab[i]; + char tmp[10]; + sprintf(tmp, " %.2g", sol_ab[i]); + strcat(txt, tmp); + } + + if (engine_rank == 0) { + message("%s", txt); + } +#else + error("Cannot scale the solar abundances without HDF5"); +#endif +} + /** * @brief Initialises the chemistry properties. * @@ -78,8 +138,22 @@ static INLINE void chemistry_init_backend(struct swift_params* parameter_file, struct chemistry_global_data* data) { /* read parameters */ - data->initial_metallicity = parser_get_opt_param_float( - parameter_file, "GearChemistry:InitialMetallicity", -1); + const float initial_metallicity = parser_get_param_float( + parameter_file, "GEARChemistry:initial_metallicity"); + + /* Set the initial metallicities */ + for (int i = 0; i < GEAR_CHEMISTRY_ELEMENT_COUNT; i++) { + data->initial_metallicities[i] = initial_metallicity; + } + + /* Check if need to scale the initial metallicity */ + const int scale_metallicity = parser_get_opt_param_int( + parameter_file, "GEARChemistry:scale_initial_metallicity", 0); + + /* Scale the metallicities if required */ + if (scale_metallicity) { + chemistry_scale_initial_metallicities(parameter_file, data); + } } /** @@ -96,8 +170,12 @@ __attribute__((always_inline)) INLINE static void chemistry_init_part( struct chemistry_part_data* cpd = &p->chemistry_data; - for (int i = 0; i < chemistry_element_count; i++) { + for (int i = 0; i < GEAR_CHEMISTRY_ELEMENT_COUNT; i++) { + /* Reset the smoothed metallicity */ cpd->smoothed_metal_mass_fraction[i] = 0.f; + + /* Convert the total mass into mass fraction */ + cpd->metal_mass_fraction[i] = cpd->metal_mass[i] / p->mass; } } @@ -125,13 +203,16 @@ __attribute__((always_inline)) INLINE static void chemistry_end_density( struct chemistry_part_data* cpd = &p->chemistry_data; - for (int i = 0; i < chemistry_element_count; i++) { + for (int i = 0; i < GEAR_CHEMISTRY_ELEMENT_COUNT; i++) { /* Final operation on the density (add self-contribution). */ cpd->smoothed_metal_mass_fraction[i] += m * cpd->metal_mass_fraction[i] * kernel_root; /* Finish the calculation by inserting the missing h-factors */ cpd->smoothed_metal_mass_fraction[i] *= factor; + + /* Convert the mass fraction into a total mass */ + cpd->metal_mass[i] = m * cpd->metal_mass_fraction[i]; } } @@ -157,7 +238,14 @@ chemistry_part_has_no_neighbours(struct part* restrict p, struct xpart* restrict xp, const struct chemistry_global_data* cd, const struct cosmology* cosmo) { - error("Needs implementing!"); + + /* Set the smoothed fractions with the non smoothed fractions */ + for (int i = 0; i < GEAR_CHEMISTRY_ELEMENT_COUNT; i++) { + p->chemistry_data.smoothed_metal_mass_fraction[i] = + p->chemistry_data.metal_mass_fraction[i]; + p->chemistry_data.metal_mass[i] = + p->chemistry_data.metal_mass_fraction[i] * p->mass; + } } /** @@ -198,7 +286,10 @@ __attribute__((always_inline)) INLINE static void chemistry_first_init_part( const struct chemistry_global_data* data, struct part* restrict p, struct xpart* restrict xp) { - p->chemistry_data.Z = data->initial_metallicity; + for (int i = 0; i < GEAR_CHEMISTRY_ELEMENT_COUNT; i++) { + p->chemistry_data.metal_mass[i] = data->initial_metallicities[i] * p->mass; + } + chemistry_init_part(p, data); } @@ -212,9 +303,145 @@ __attribute__((always_inline)) INLINE static void chemistry_first_init_part( __attribute__((always_inline)) INLINE static void chemistry_first_init_spart( const struct chemistry_global_data* data, struct spart* restrict sp) { - error( - "MATTHIEU: Loic this is a new function. I don't know whether you" - " want something here."); + for (int i = 0; i < GEAR_CHEMISTRY_ELEMENT_COUNT; i++) { + sp->chemistry_data.metal_mass_fraction[i] = data->initial_metallicities[i]; + } +} + +/** + * @brief Initialise the chemistry properties of a black hole with + * the chemistry properties of the gas it is born from. + * + * Nothing to do here. + * + * @param bp_data The black hole data to initialise. + * @param p_data The gas data to use. + * @param gas_mass The mass of the gas particle. + */ +__attribute__((always_inline)) INLINE static void chemistry_bpart_from_part( + struct chemistry_bpart_data* bp_data, + const struct chemistry_part_data* p_data, const double gas_mass) { + error("Loic: to be implemented"); +} + +/** + * @brief Add the chemistry data of a gas particle to a black hole. + * + * Nothing to do here. + * + * @param bp_data The black hole data to add to. + * @param p_data The gas data to use. + * @param gas_mass The mass of the gas particle. + */ +__attribute__((always_inline)) INLINE static void chemistry_add_part_to_bpart( + struct chemistry_bpart_data* bp_data, + const struct chemistry_part_data* p_data, const double gas_mass) { + error("Loic: to be implemented"); +} + +/** + * @brief Add the chemistry data of a black hole to another one. + * + * Nothing to do here. + * + * @param bp_data The black hole data to add to. + * @param swallowed_data The black hole data to use. + */ +__attribute__((always_inline)) INLINE static void chemistry_add_bpart_to_bpart( + struct chemistry_bpart_data* bp_data, + const struct chemistry_bpart_data* swallowed_data) { + error("Loic: to be implemented"); +} + +/** + * @brief Split the metal content of a particle into n pieces + * + * @param p The #part. + * @param n The number of pieces to split into. + */ +__attribute__((always_inline)) INLINE static void chemistry_split_part( + struct part* p, const double n) { + error("Loic: to be implemented"); +} + +/** + * @brief Returns the total metallicity (metal mass fraction) of the + * star particle to be used in feedback/enrichment related routines. + * + * @param sp Pointer to the particle data. + */ +__attribute__((always_inline)) INLINE static float +chemistry_get_total_metal_mass_fraction_for_feedback( + const struct spart* restrict sp) { + + return sp->chemistry_data + .metal_mass_fraction[GEAR_CHEMISTRY_ELEMENT_COUNT - 1]; +} + +/** + * @brief Returns the abundances (metal mass fraction) of the + * star particle to be used in feedback/enrichment related routines. + * + * @param sp Pointer to the particle data. + */ +__attribute__((always_inline)) INLINE static float const* +chemistry_get_metal_mass_fraction_for_feedback( + const struct spart* restrict sp) { + + return sp->chemistry_data.metal_mass_fraction; +} + +/** + * @brief Returns the total metallicity (metal mass fraction) of the + * gas particle to be used in cooling related routines. + * + * @param p Pointer to the particle data. + */ +__attribute__((always_inline)) INLINE static float +chemistry_get_total_metal_mass_fraction_for_cooling( + const struct part* restrict p) { + + return p->chemistry_data + .smoothed_metal_mass_fraction[GEAR_CHEMISTRY_ELEMENT_COUNT - 1]; +} + +/** + * @brief Returns the abundance array (metal mass fractions) of the + * gas particle to be used in cooling related routines. + * + * @param p Pointer to the particle data. + */ +__attribute__((always_inline)) INLINE static float const* +chemistry_get_metal_mass_fraction_for_cooling(const struct part* restrict p) { + + return p->chemistry_data.smoothed_metal_mass_fraction; +} + +/** + * @brief Returns the total metallicity (metal mass fraction) of the + * gas particle to be used in star formation related routines. + * + * @param p Pointer to the particle data. + */ +__attribute__((always_inline)) INLINE static float +chemistry_get_total_metal_mass_fraction_for_star_formation( + const struct part* restrict p) { + + return p->chemistry_data + .smoothed_metal_mass_fraction[GEAR_CHEMISTRY_ELEMENT_COUNT - 1]; +} + +/** + * @brief Returns the abundance array (metal mass fractions) of the + * gas particle to be used in star formation related routines. + * + * @param p Pointer to the particle data. + */ +__attribute__((always_inline)) INLINE static float const* +chemistry_get_metal_mass_fraction_for_star_formation( + const struct part* restrict p) { + + return p->chemistry_data.smoothed_metal_mass_fraction; } #endif /* SWIFT_CHEMISTRY_GEAR_H */ diff --git a/src/chemistry/GEAR/chemistry_iact.h b/src/chemistry/GEAR/chemistry_iact.h index f1d724b680574cf1d78848ef242a0e0e5b0cc8e3..ff49af4abb141ee69dea48bbaf99f6b38db4ce45 100644 --- a/src/chemistry/GEAR/chemistry_iact.h +++ b/src/chemistry/GEAR/chemistry_iact.h @@ -68,7 +68,7 @@ __attribute__((always_inline)) INLINE static void runner_iact_chemistry( kernel_deval(uj, &wj, &wj_dx); /* Compute contribution to the smooth metallicity */ - for (int i = 0; i < chemistry_element_count; i++) { + for (int i = 0; i < GEAR_CHEMISTRY_ELEMENT_COUNT; i++) { chi->smoothed_metal_mass_fraction[i] += mj * chj->metal_mass_fraction[i] * wi; chj->smoothed_metal_mass_fraction[i] += @@ -109,7 +109,7 @@ __attribute__((always_inline)) INLINE static void runner_iact_nonsym_chemistry( kernel_deval(ui, &wi, &wi_dx); /* Compute contribution to the smooth metallicity */ - for (int i = 0; i < chemistry_element_count; i++) { + for (int i = 0; i < GEAR_CHEMISTRY_ELEMENT_COUNT; i++) { chi->smoothed_metal_mass_fraction[i] += mj * chj->metal_mass_fraction[i] * wi; } diff --git a/src/chemistry/GEAR/chemistry_io.h b/src/chemistry/GEAR/chemistry_io.h index 008268657fc89ae20208585cb983f4d436122201..0943f369b116e4d2c200c95ff9712551e657d706 100644 --- a/src/chemistry/GEAR/chemistry_io.h +++ b/src/chemistry/GEAR/chemistry_io.h @@ -27,19 +27,6 @@ #include "physical_constants.h" #include "units.h" -/** - * @brief Return a string containing the name of a given #chemistry_element. - */ -__attribute__((always_inline)) INLINE static const char* -chemistry_get_element_name(enum chemistry_element elem) { - - static const char* chemistry_element_names[chemistry_element_count] = { - "Oxygen", "Magnesium", "Sulfur", "Iron", "Zinc", - "Strontium", "Yttrium", "Barium", "Europium"}; - - return chemistry_element_names[elem]; -} - /** * @brief Specifies which particle fields to read from a dataset * @@ -53,12 +40,10 @@ INLINE static int chemistry_read_particles(struct part* parts, /* List what we want to read */ list[0] = io_make_input_field( - "ElementAbundance", FLOAT, chemistry_element_count, OPTIONAL, + "ElementAbundance", FLOAT, GEAR_CHEMISTRY_ELEMENT_COUNT, OPTIONAL, UNIT_CONV_NO_UNITS, parts, chemistry_data.metal_mass_fraction); - list[1] = io_make_input_field("Z", FLOAT, 1, OPTIONAL, UNIT_CONV_NO_UNITS, - parts, chemistry_data.Z); - return 2; + return 1; } /** @@ -73,21 +58,18 @@ INLINE static int chemistry_write_particles(const struct part* parts, struct io_props* list) { /* List what we want to write */ - list[0] = - io_make_output_field("SmoothedElementAbundances", FLOAT, - chemistry_element_count, UNIT_CONV_NO_UNITS, 0.f, - parts, chemistry_data.smoothed_metal_mass_fraction, - "Element abundances smoothed over the neighbors"); - - list[1] = io_make_output_field("Z", FLOAT, 1, UNIT_CONV_NO_UNITS, 0.f, parts, - chemistry_data.Z, "Temporary field"); - - list[2] = io_make_output_field("ElementAbundances", FLOAT, - chemistry_element_count, UNIT_CONV_NO_UNITS, - 0.f, parts, chemistry_data.metal_mass_fraction, - "Mass fraction of each element"); + list[0] = io_make_output_field( + "SmoothedElementAbundances", FLOAT, GEAR_CHEMISTRY_ELEMENT_COUNT, + UNIT_CONV_NO_UNITS, 0.f, parts, + chemistry_data.smoothed_metal_mass_fraction, + "Element abundances smoothed over the neighbors"); + + list[1] = io_make_output_field( + "ElementAbundances", FLOAT, GEAR_CHEMISTRY_ELEMENT_COUNT, + UNIT_CONV_NO_UNITS, 0.f, parts, chemistry_data.metal_mass_fraction, + "Mass fraction of each element"); - return 3; + return 2; } /** @@ -102,21 +84,12 @@ INLINE static int chemistry_write_sparticles(const struct spart* sparts, struct io_props* list) { /* List what we want to write */ - list[0] = - io_make_output_field("SmoothedElementAbundances", FLOAT, - chemistry_element_count, UNIT_CONV_NO_UNITS, 0.f, - sparts, chemistry_data.smoothed_metal_mass_fraction, - "Element abundances smoothed over the neighbors"); - - list[1] = io_make_output_field("Z", FLOAT, 1, UNIT_CONV_NO_UNITS, 0.f, sparts, - chemistry_data.Z, "Temporary field"); - - list[2] = io_make_output_field( - "ElementAbundance", FLOAT, chemistry_element_count, UNIT_CONV_NO_UNITS, - 0.f, sparts, chemistry_data.metal_mass_fraction, + list[0] = io_make_output_field( + "ElementAbundances", FLOAT, GEAR_CHEMISTRY_ELEMENT_COUNT, + UNIT_CONV_NO_UNITS, 0.f, sparts, chemistry_data.metal_mass_fraction, "Mass fraction of each element"); - return 3; + return 1; } /** @@ -143,12 +116,6 @@ INLINE static int chemistry_write_bparticles(const struct bpart* bparts, INLINE static void chemistry_write_flavour(hid_t h_grp) { io_write_attribute_s(h_grp, "Chemistry Model", "GEAR"); - for (enum chemistry_element i = chemistry_element_O; - i < chemistry_element_count; i++) { - char buffer[20]; - sprintf(buffer, "Element %d", (int)i); - io_write_attribute_s(h_grp, buffer, chemistry_get_element_name(i)); - } } #endif diff --git a/src/chemistry/GEAR/chemistry_struct.h b/src/chemistry/GEAR/chemistry_struct.h index 105b72d7fd731356a6f1135ce41b03bb2f898acf..ae108bf271cb470894cada86785777130f9deb3e 100644 --- a/src/chemistry/GEAR/chemistry_struct.h +++ b/src/chemistry/GEAR/chemistry_struct.h @@ -19,43 +19,37 @@ #ifndef SWIFT_CHEMISTRY_STRUCT_GEAR_H #define SWIFT_CHEMISTRY_STRUCT_GEAR_H -/** - * @brief The individual elements traced in the model. - */ -enum chemistry_element { - chemistry_element_O = 0, - chemistry_element_Mg, - chemistry_element_S, - chemistry_element_Fe, - chemistry_element_Zn, - chemistry_element_Sr, - chemistry_element_Y, - chemistry_element_Ba, - chemistry_element_Eu, - chemistry_element_count -}; - /** * @brief Global chemical abundance information. */ struct chemistry_global_data { /* Initial metallicity Z */ - float initial_metallicity; + float initial_metallicities[GEAR_CHEMISTRY_ELEMENT_COUNT]; }; /** - * @brief Properties of the chemistry function. + * @brief Properties of the chemistry function for #part. */ struct chemistry_part_data { /*! Fraction of the particle mass in a given element */ - float metal_mass_fraction[chemistry_element_count]; + float metal_mass_fraction[GEAR_CHEMISTRY_ELEMENT_COUNT]; + + /*! Total mass of element in a particle */ + float metal_mass[GEAR_CHEMISTRY_ELEMENT_COUNT]; /*! Smoothed fraction of the particle mass in a given element */ - float smoothed_metal_mass_fraction[chemistry_element_count]; + float smoothed_metal_mass_fraction[GEAR_CHEMISTRY_ELEMENT_COUNT]; +}; - float Z; +/** + * @brief Properties of the chemistry function for #spart. + */ +struct chemistry_spart_data { + + /*! Fraction of the particle mass in a given element */ + float metal_mass_fraction[GEAR_CHEMISTRY_ELEMENT_COUNT]; }; /** diff --git a/src/chemistry/none/chemistry.h b/src/chemistry/none/chemistry.h index 7c89e682570484737fe93a82690ebcb1e09b03e8..4070c4fe7e942778ece03c3d77a9110e33add6eb 100644 --- a/src/chemistry/none/chemistry.h +++ b/src/chemistry/none/chemistry.h @@ -175,6 +175,56 @@ __attribute__((always_inline)) INLINE static void chemistry_init_part( __attribute__((always_inline)) INLINE static void chemistry_first_init_spart( const struct chemistry_global_data* data, struct spart* restrict sp) {} +/** + * @brief Initialise the chemistry properties of a black hole with + * the chemistry properties of the gas it is born from. + * + * Nothing to do here. + * + * @param bp_data The black hole data to initialise. + * @param p_data The gas data to use. + * @param gas_mass The mass of the gas particle. + */ +__attribute__((always_inline)) INLINE static void chemistry_bpart_from_part( + struct chemistry_bpart_data* bp_data, + const struct chemistry_part_data* p_data, const double gas_mass) {} + +/** + * @brief Add the chemistry data of a gas particle to a black hole. + * + * Nothing to do here. + * + * @param bp_data The black hole data to add to. + * @param p_data The gas data to use. + * @param gas_mass The mass of the gas particle. + */ +__attribute__((always_inline)) INLINE static void chemistry_add_part_to_bpart( + struct chemistry_bpart_data* bp_data, + const struct chemistry_part_data* p_data, const double gas_mass) {} + +/** + * @brief Add the chemistry data of a black hole to another one. + * + * Nothing to do here. + * + * @param bp_data The black hole data to add to. + * @param swallowed_data The black hole data to use. + */ +__attribute__((always_inline)) INLINE static void chemistry_add_bpart_to_bpart( + struct chemistry_bpart_data* bp_data, + const struct chemistry_bpart_data* swallowed_data) {} + +/** + * @brief Split the metal content of a particle into n pieces + * + * Nothing to do here. + * + * @param p The #part. + * @param n The number of pieces to split into. + */ +__attribute__((always_inline)) INLINE static void chemistry_split_part( + struct part* p, const double n) {} + /** * @brief Returns the total metallicity (metal mass fraction) of the * star particle to be used in feedback/enrichment related routines. diff --git a/src/collectgroup.c b/src/collectgroup.c index af140c9150a640829ce783149f0c68bc7e732975..6b096416a3f334617a4567e51b4be04c92432eef 100644 --- a/src/collectgroup.c +++ b/src/collectgroup.c @@ -31,6 +31,7 @@ /* Local headers. */ #include "engine.h" #include "error.h" +#include "star_formation_logger.h" #ifdef WITH_MPI diff --git a/src/common_io.c b/src/common_io.c index 25abb187a7ac1ae86feab50bfd5cdbd0633d17ac..460fda26699a3f4f45944f18c1fe65b2e9274dfa 100644 --- a/src/common_io.c +++ b/src/common_io.c @@ -79,6 +79,8 @@ hid_t io_hdf5_type(enum IO_DATA_TYPE type) { return H5T_NATIVE_INT; case UINT: return H5T_NATIVE_UINT; + case UINT64: + return H5T_NATIVE_UINT64; case LONG: return H5T_NATIVE_LONG; case ULONG: @@ -118,7 +120,7 @@ int io_is_double_precision(enum IO_DATA_TYPE type) { } /** - * @brief Reads an attribute from a given HDF5 group. + * @brief Reads an attribute (scalar) from a given HDF5 group. * * @param grp The group from which to read. * @param name The name of the attribute to read. @@ -218,6 +220,150 @@ void io_assert_valid_header_cosmology(hid_t h_grp, double a) { } } +/** + * @brief Reads the number of elements in a HDF5 attribute. + * + * @param attr The attribute from which to read. + * + * @return The number of elements. + * + * Calls #error() if an error occurs. + */ +hsize_t io_get_number_element_in_attribute(hid_t attr) { + /* Get the dataspace */ + hid_t space = H5Aget_space(attr); + if (space < 0) error("Failed to get data space"); + + /* Read the number of dimensions */ + const int ndims = H5Sget_simple_extent_ndims(space); + + /* Read the dimensions */ + hsize_t* dims = (hsize_t*)malloc(sizeof(hsize_t) * ndims); + H5Sget_simple_extent_dims(space, dims, NULL); + + /* Compute number of elements */ + hsize_t count = 1; + for (int i = 0; i < ndims; i++) { + count *= dims[i]; + } + + /* Cleanup */ + free(dims); + H5Sclose(space); + return count; +}; + +/** + * @brief Reads an attribute (array) from a given HDF5 group. + * + * @param grp The group from which to read. + * @param name The name of the dataset to read. + * @param type The #IO_DATA_TYPE of the attribute. + * @param data (output) The attribute read from the HDF5 group (need to be + * already allocated). + * @param number_element Number of elements in the attribute. + * + * Calls #error() if an error occurs. + */ +void io_read_array_attribute(hid_t grp, const char* name, + enum IO_DATA_TYPE type, void* data, + hsize_t number_element) { + + /* Open attribute */ + const hid_t h_attr = H5Aopen(grp, name, H5P_DEFAULT); + if (h_attr < 0) error("Error while opening attribute '%s'", name); + + /* Get the number of elements */ + hsize_t count = io_get_number_element_in_attribute(h_attr); + + /* Check if correct number of element */ + if (count != number_element) { + error( + "Error found a different number of elements than expected (%lli != " + "%lli) in attribute %s", + count, number_element, name); + } + + /* Read attribute */ + const hid_t h_err = H5Aread(h_attr, io_hdf5_type(type), data); + if (h_err < 0) error("Error while reading attribute '%s'", name); + + /* Cleanup */ + H5Aclose(h_attr); +} + +/** + * @brief Reads the number of elements in a HDF5 dataset. + * + * @param dataset The dataset from which to read. + * + * @return The number of elements. + * + * Calls #error() if an error occurs. + */ +hsize_t io_get_number_element_in_dataset(hid_t dataset) { + /* Get the dataspace */ + hid_t space = H5Dget_space(dataset); + if (space < 0) error("Failed to get data space"); + + /* Read the number of dimensions */ + const int ndims = H5Sget_simple_extent_ndims(space); + + /* Read the dimensions */ + hsize_t* dims = (hsize_t*)malloc(sizeof(hsize_t) * ndims); + H5Sget_simple_extent_dims(space, dims, NULL); + + /* Compute number of elements */ + hsize_t count = 1; + for (int i = 0; i < ndims; i++) { + count *= dims[i]; + } + + /* Cleanup */ + free(dims); + H5Sclose(space); + return count; +}; + +/** + * @brief Reads a dataset (array) from a given HDF5 group. + * + * @param grp The group from which to read. + * @param name The name of the dataset to read. + * @param type The #IO_DATA_TYPE of the attribute. + * @param data (output) The attribute read from the HDF5 group (need to be + * already allocated). + * @param number_element Number of elements in the attribute. + * + * Calls #error() if an error occurs. + */ +void io_read_array_dataset(hid_t grp, const char* name, enum IO_DATA_TYPE type, + void* data, hsize_t number_element) { + + /* Open dataset */ + const hid_t h_dataset = H5Dopen(grp, name, H5P_DEFAULT); + if (h_dataset < 0) error("Error while opening attribute '%s'", name); + + /* Get the number of elements */ + hsize_t count = io_get_number_element_in_dataset(h_dataset); + + /* Check if correct number of element */ + if (count != number_element) { + error( + "Error found a different number of elements than expected (%lli != " + "%lli) in dataset %s", + count, number_element, name); + } + + /* Read dataset */ + const hid_t h_err = H5Dread(h_dataset, io_hdf5_type(type), H5S_ALL, H5S_ALL, + H5P_DEFAULT, data); + if (h_err < 0) error("Error while reading dataset '%s'", name); + + /* Cleanup */ + H5Dclose(h_dataset); +} + /** * @brief Write an attribute to a given HDF5 group. * @@ -453,6 +599,7 @@ void io_write_code_description(hid_t h_file) { #else io_write_attribute_s(h_grpcode, "MPI library", "Non-MPI version of SWIFT"); #endif + io_write_attribute_i(h_grpcode, "RandomSeed", SWIFT_RANDOM_SEED_XOR); H5Gclose(h_grpcode); } @@ -543,7 +690,8 @@ static long long cell_count_non_inhibited_black_holes(const struct cell* c) { return count; } -void io_write_cell_offsets(hid_t h_grp, const int cdim[3], +void io_write_cell_offsets(hid_t h_grp, const int cdim[3], const double dim[3], + const double pos_dithering[3], const struct cell* cells_top, const int nr_cells, const double width[3], const int nodeID, const long long global_counts[swift_type_count], @@ -599,6 +747,17 @@ void io_write_cell_offsets(hid_t h_grp, const int cdim[3], centres[i * 3 + 1] = cells_top[i].loc[1] + cell_width[1] * 0.5; centres[i * 3 + 2] = cells_top[i].loc[2] + cell_width[2] * 0.5; + /* Undo the dithering since the particles will have this vector applied to + * them */ + centres[i * 3 + 0] = centres[i * 3 + 0] - pos_dithering[0]; + centres[i * 3 + 1] = centres[i * 3 + 1] - pos_dithering[1]; + centres[i * 3 + 2] = centres[i * 3 + 2] - pos_dithering[2]; + + /* Finish by box wrapping to match what is done to the particles */ + centres[i * 3 + 0] = box_wrap(centres[i * 3 + 0], 0.0, dim[0]); + centres[i * 3 + 1] = box_wrap(centres[i * 3 + 1], 0.0, dim[1]); + centres[i * 3 + 2] = box_wrap(centres[i * 3 + 2], 0.0, dim[2]); + /* Count real particles that will be written */ count_part[i] = cell_count_non_inhibited_gas(&cells_top[i]); count_gpart[i] = cell_count_non_inhibited_dark_matter(&cells_top[i]); @@ -1021,6 +1180,8 @@ size_t io_sizeof_type(enum IO_DATA_TYPE type) { return sizeof(int); case UINT: return sizeof(unsigned int); + case UINT64: + return sizeof(uint64_t); case LONG: return sizeof(long); case ULONG: @@ -1035,6 +1196,8 @@ size_t io_sizeof_type(enum IO_DATA_TYPE type) { return sizeof(double); case CHAR: return sizeof(char); + case SIZE_T: + return sizeof(size_t); default: error("Unknown type"); return 0; diff --git a/src/common_io.h b/src/common_io.h index b4a846dc4f683cb4e18e3bba03c4cc95235a8854..3d160d6778a07172107c205246a5720997a1e0e3 100644 --- a/src/common_io.h +++ b/src/common_io.h @@ -55,23 +55,32 @@ enum IO_DATA_TYPE { LONG, LONGLONG, UINT, + UINT64, ULONG, ULONGLONG, FLOAT, DOUBLE, - CHAR + CHAR, + SIZE_T, }; #if defined(HAVE_HDF5) hid_t io_hdf5_type(enum IO_DATA_TYPE type); +hsize_t io_get_number_element_in_attribute(hid_t attr); +hsize_t io_get_number_element_in_dataset(hid_t dataset); void io_read_attribute(hid_t grp, const char* name, enum IO_DATA_TYPE type, void* data); void io_read_attribute_graceful(hid_t grp, const char* name, enum IO_DATA_TYPE type, void* data); void io_assert_valid_header_cosmology(hid_t h_grp, double a); +void io_read_array_attribute(hid_t grp, const char* name, + enum IO_DATA_TYPE type, void* data, + hsize_t number_element); +void io_read_array_dataset(hid_t grp, const char* name, enum IO_DATA_TYPE type, + void* data, hsize_t number_element); void io_write_attribute(hid_t grp, const char* name, enum IO_DATA_TYPE type, const void* data, int num); @@ -84,7 +93,8 @@ void io_write_attribute_s(hid_t grp, const char* name, const char* str); void io_write_code_description(hid_t h_file); void io_write_engine_policy(hid_t h_file, const struct engine* e); -void io_write_cell_offsets(hid_t h_grp, const int cdim[3], +void io_write_cell_offsets(hid_t h_grp, const int cdim[3], const double dim[3], + const double pos_dithering[3], const struct cell* cells_top, const int nr_cells, const double width[3], const int nodeID, const long long global_counts[swift_type_count], diff --git a/src/const.h b/src/const.h index 521d094f51e61fde1e1f983caa7194bc0242214b..b1e7e777e52d13785da8eeb7e4ca13019234ebef 100644 --- a/src/const.h +++ b/src/const.h @@ -20,12 +20,6 @@ #ifndef SWIFT_CONST_H #define SWIFT_CONST_H -/* Time integration constants. */ -#define const_max_u_change 0.1f - -/* Time-step limiter maximal difference in signal velocity */ -#define const_limiter_max_v_sig_ratio 4.1f - /* I/O Constant; this determines the relative tolerance between the value of * redshift read from the snapshot, and the value from the parameter file. This * current value asserts that they must match within 0.1%. */ diff --git a/src/cooling/Compton/cooling.h b/src/cooling/Compton/cooling.h index e04fc6f9adaef6bd238fe32d21526db1dc282aaa..a594cdca6916c361b737763e0360ed32d459ba99 100644 --- a/src/cooling/Compton/cooling.h +++ b/src/cooling/Compton/cooling.h @@ -136,6 +136,7 @@ __attribute__((always_inline)) INLINE static double Compton_cooling_rate_cgs( * @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 time The current time. * @param dt The time-step of this particle. * @param dt_therm The time-step operator used for thermal quantities. */ @@ -146,8 +147,8 @@ __attribute__((always_inline)) INLINE static void cooling_cool_part( const struct hydro_props* hydro_props, const struct entropy_floor_properties* floor_props, const struct cooling_function_data* restrict cooling, - struct part* restrict p, struct xpart* restrict xp, const float dt, - const float dt_therm) { + struct part* restrict p, struct xpart* restrict xp, const double time, + const float dt, const float dt_therm) { /* Nothing to do here? */ if (dt == 0.) return; @@ -240,6 +241,7 @@ __attribute__((always_inline)) INLINE static float cooling_timestep( * @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 hydro_props The properties of the hydro scheme. * @param cosmo The current cosmological model. * @param p Pointer to the particle data. * @param xp Pointer to the extended particle data. @@ -247,6 +249,7 @@ __attribute__((always_inline)) INLINE static float cooling_timestep( __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 hydro_props* hydro_props, const struct cosmology* restrict cosmo, const struct cooling_function_data* restrict cooling, const struct part* restrict p, struct xpart* restrict xp) { @@ -308,6 +311,19 @@ __attribute__((always_inline)) INLINE static float cooling_get_radiated_energy( return xp->cooling_data.radiated_energy; } +/** + * @brief Split the coolong content of a particle into n pieces + * + * @param p The #part. + * @param xp The #xpart. + * @param n The number of pieces to split into. + */ +static INLINE void cooling_split_part(struct part* p, struct xpart* xp, + double n) { + + xp->cooling_data.radiated_energy /= n; +} + /** * @brief Initialises the cooling properties. * diff --git a/src/cooling/EAGLE/cooling.c b/src/cooling/EAGLE/cooling.c index a228eb6ee74e301d2ec6ac461ab9b7420fe66250..3a6fb523b83ba34d7fea2ff981a5c899e9f04a1c 100644 --- a/src/cooling/EAGLE/cooling.c +++ b/src/cooling/EAGLE/cooling.c @@ -372,6 +372,8 @@ INLINE static double bisection_iter( * @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 time The current time (since the Big Bang or start of the run) in + * internal units. * @param dt The cooling time-step of this particle. * @param dt_therm The hydro time-step of this particle. */ @@ -382,7 +384,8 @@ void cooling_cool_part(const struct phys_const *phys_const, const struct entropy_floor_properties *floor_props, const struct cooling_function_data *cooling, struct part *restrict p, struct xpart *restrict xp, - const float dt, const float dt_therm) { + const double time, const float dt, + const float dt_therm) { /* No cooling happens over zero time */ if (dt == 0.) return; @@ -548,6 +551,7 @@ __attribute__((always_inline)) INLINE float cooling_timestep( * * @param phys_const #phys_const data structure. * @param us The internal system of units. + * @param hydro_props The properties of the hydro scheme. * @param cosmo #cosmology data structure. * @param cooling #cooling_function_data struct. * @param p #part data. @@ -556,6 +560,7 @@ __attribute__((always_inline)) INLINE float cooling_timestep( __attribute__((always_inline)) INLINE void cooling_first_init_part( const struct phys_const *restrict phys_const, const struct unit_system *restrict us, + const struct hydro_props *hydro_props, const struct cosmology *restrict cosmo, const struct cooling_function_data *restrict cooling, const struct part *restrict p, struct xpart *restrict xp) { @@ -642,6 +647,18 @@ __attribute__((always_inline)) INLINE float cooling_get_radiated_energy( return xp->cooling_data.radiated_energy; } +/** + * @brief Split the coolong content of a particle into n pieces + * + * @param p The #part. + * @param xp The #xpart. + * @param n The number of pieces to split into. + */ +void cooling_split_part(struct part *p, struct xpart *xp, double n) { + + xp->cooling_data.radiated_energy /= n; +} + /** * @brief Inject a fixed amount of energy to each particle in the simulation * to mimic Hydrogen reionization. diff --git a/src/cooling/EAGLE/cooling.h b/src/cooling/EAGLE/cooling.h index f154df3136558931a917aab2bcc27167d2a40508..90c1c01e82c7eec6d6615546866083afdfc1e328 100644 --- a/src/cooling/EAGLE/cooling.h +++ b/src/cooling/EAGLE/cooling.h @@ -44,7 +44,7 @@ void cooling_cool_part(const struct phys_const *phys_const, const struct entropy_floor_properties *floor_props, const struct cooling_function_data *cooling, struct part *restrict p, struct xpart *restrict xp, - const float dt, const float dt_therm); + const double time, const float dt, const float dt_therm); float cooling_timestep(const struct cooling_function_data *restrict cooling, const struct phys_const *restrict phys_const, @@ -57,6 +57,7 @@ float cooling_timestep(const struct cooling_function_data *restrict cooling, void cooling_first_init_part( const struct phys_const *restrict phys_const, const struct unit_system *restrict us, + const struct hydro_props *hydro_props, const struct cosmology *restrict cosmo, const struct cooling_function_data *restrict cooling, const struct part *restrict p, struct xpart *restrict xp); @@ -71,6 +72,8 @@ float cooling_get_temperature( float cooling_get_radiated_energy(const struct xpart *restrict xp); +void cooling_split_part(struct part *p, struct xpart *xp, double n); + void cooling_Hydrogen_reionization(const struct cooling_function_data *cooling, const struct cosmology *cosmo, struct space *s); diff --git a/src/cooling/const_du/cooling.h b/src/cooling/const_du/cooling.h index 386ad3e0013a5884b12e589b3d1b1a09bfbb89dc..de5164e59498a1a17c62fecfed0b0f61bcf2a2c2 100644 --- a/src/cooling/const_du/cooling.h +++ b/src/cooling/const_du/cooling.h @@ -76,6 +76,7 @@ INLINE static void cooling_update(const struct cosmology* cosmo, * @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 time The current time. * @param dt The time-step of this particle. * @param dt_therm The time-step operator used for thermal quantities. */ @@ -86,8 +87,8 @@ __attribute__((always_inline)) INLINE static void cooling_cool_part( const struct hydro_props* hydro_props, const struct entropy_floor_properties* floor_props, const struct cooling_function_data* restrict cooling, - struct part* restrict p, struct xpart* restrict xp, const float dt, - const float dt_therm) { + struct part* restrict p, struct xpart* restrict xp, const double time, + const float dt, const float dt_therm) { /* Internal energy floor */ const float u_floor = cooling->min_energy; @@ -155,6 +156,7 @@ __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 hydro_props The properties of the hydro scheme. * @param cooling The properties of the cooling function. * @param us The internal system of units. * @param cosmo The current cosmological model. @@ -162,6 +164,7 @@ __attribute__((always_inline)) INLINE static float cooling_timestep( __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 hydro_props* hydro_props, const struct cosmology* restrict cosmo, const struct cooling_function_data* restrict cooling, const struct part* restrict p, struct xpart* restrict xp) { @@ -226,6 +229,19 @@ __attribute__((always_inline)) INLINE static float cooling_get_radiated_energy( return xp->cooling_data.radiated_energy; } +/** + * @brief Split the coolong content of a particle into n pieces + * + * @param p The #part. + * @param xp The #xpart. + * @param n The number of pieces to split into. + */ +static INLINE void cooling_split_part(struct part* p, struct xpart* xp, + double n) { + + xp->cooling_data.radiated_energy /= n; +} + /** * @brief Initialises the cooling function properties from the parameter file * diff --git a/src/cooling/const_lambda/cooling.h b/src/cooling/const_lambda/cooling.h index 3e3a44249d152e407bf9d3fdf294dd504cee2257..ef56b6e3575d11f767af8061e303f6ffe9248d7a 100644 --- a/src/cooling/const_lambda/cooling.h +++ b/src/cooling/const_lambda/cooling.h @@ -106,6 +106,7 @@ __attribute__((always_inline)) INLINE static double cooling_rate_cgs( * @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 time The current time. * @param dt The time-step of this particle. * @param dt_therm The time-step operator used for thermal quantities. */ @@ -116,8 +117,8 @@ __attribute__((always_inline)) INLINE static void cooling_cool_part( const struct hydro_props* hydro_props, const struct entropy_floor_properties* floor_props, const struct cooling_function_data* restrict cooling, - struct part* restrict p, struct xpart* restrict xp, const float dt, - const float dt_therm) { + struct part* restrict p, struct xpart* restrict xp, const double time, + const float dt, const float dt_therm) { /* Nothing to do here? */ if (dt == 0.) return; @@ -234,6 +235,7 @@ __attribute__((always_inline)) INLINE static float cooling_timestep( * @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 hydro_props The properties of the hydro scheme. * @param cosmo The current cosmological model. * @param p Pointer to the particle data. * @param xp Pointer to the extended particle data. @@ -241,6 +243,7 @@ __attribute__((always_inline)) INLINE static float cooling_timestep( __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 hydro_props* hydro_props, const struct cosmology* restrict cosmo, const struct cooling_function_data* restrict cooling, const struct part* restrict p, struct xpart* restrict xp) { @@ -302,6 +305,19 @@ __attribute__((always_inline)) INLINE static float cooling_get_radiated_energy( return xp->cooling_data.radiated_energy; } +/** + * @brief Split the coolong content of a particle into n pieces + * + * @param p The #part. + * @param xp The #xpart. + * @param n The number of pieces to split into. + */ +static INLINE void cooling_split_part(struct part* p, struct xpart* xp, + double n) { + + xp->cooling_data.radiated_energy /= n; +} + /** * @brief Initialises the cooling properties. * diff --git a/src/cooling/grackle/cooling.c b/src/cooling/grackle/cooling.c new file mode 100644 index 0000000000000000000000000000000000000000..6b74b72aefa0bb64717f83d9b5a54d497e6ae260 --- /dev/null +++ b/src/cooling/grackle/cooling.c @@ -0,0 +1,1038 @@ +/******************************************************************************* + * This file is part of SWIFT. + * Copyright (c) 2016 Matthieu Schaller (matthieu.schaller@durham.ac.uk) + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published + * by the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this program. If not, see <http://www.gnu.org/licenses/>. + * + ******************************************************************************/ +/** + * @file src/cooling/grackle/cooling.c + * @brief Cooling using the GRACKLE 3.0 library. + */ + +#include "../config.h" + +/* Include header */ +#include "cooling.h" + +/* Some standard headers. */ +#include <fenv.h> +#include <float.h> +#include <math.h> + +/* The grackle library itself */ +#include <grackle.h> + +/* Local includes. */ +#include "chemistry.h" +#include "cooling_io.h" +#include "entropy_floor.h" +#include "error.h" +#include "hydro.h" +#include "parser.h" +#include "part.h" +#include "physical_constants.h" +#include "units.h" + +/* need to rework (and check) code if changed */ +#define GRACKLE_NPART 1 +#define GRACKLE_RANK 3 + +/** + * @brief Common operations performed on the cooling function at a + * given time-step or redshift. + * + * @param cosmo The current cosmological model. + * @param cooling The #cooling_function_data used in the run. + * @param s The #space containing all the particles. + */ +void cooling_update(const struct cosmology* cosmo, + struct cooling_function_data* cooling, struct space* s) { + /* set current time */ + if (cooling->redshift == -1) + cooling->units.a_value = cosmo->a; + else + cooling->units.a_value = 1. / (1. + cooling->redshift); +} + +/** + * @brief Print the chemical network + * + * @param xp The #xpart to print + */ +void cooling_print_fractions(const struct xpart* restrict xp) { + + const struct cooling_xpart_data tmp = xp->cooling_data; +#if COOLING_GRACKLE_MODE > 0 + message("HI %g, HII %g, HeI %g, HeII %g, HeIII %g, e %g", tmp.HI_frac, + tmp.HII_frac, tmp.HeI_frac, tmp.HeII_frac, tmp.HeIII_frac, + tmp.e_frac); +#endif + +#if COOLING_GRACKLE_MODE > 1 + message("HM %g, H2I %g, H2II %g", tmp.HM_frac, tmp.H2I_frac, tmp.H2II_frac); +#endif + +#if COOLING_GRACKLE_MODE > 2 + message("DI %g, DII %g, HDI %g", tmp.DI_frac, tmp.DII_frac, tmp.HDI_frac); +#endif + message("Metal: %g", tmp.metal_frac); +} + +/** + * @brief Check if the difference of a given field is lower than limit + * + * @param xp First #xpart + * @param old Second #xpart + * @param field The field to check + * @param limit Difference limit + * + * @return 0 if diff > limit + */ +#define cooling_check_field(xp, old, field, limit) \ + ({ \ + float tmp = xp->cooling_data.field - old->cooling_data.field; \ + tmp = fabs(tmp) / xp->cooling_data.field; \ + if (tmp > limit) return 0; \ + }) + +/** + * @brief Check if difference between two particles is lower than a given value + * + * @param xp One of the #xpart + * @param old The other #xpart + * @param limit The difference limit + */ +int cooling_converged(const struct xpart* restrict xp, + const struct xpart* restrict old, const float limit) { + +#if COOLING_GRACKLE_MODE > 0 + cooling_check_field(xp, old, HI_frac, limit); + cooling_check_field(xp, old, HII_frac, limit); + cooling_check_field(xp, old, HeI_frac, limit); + cooling_check_field(xp, old, HeII_frac, limit); + cooling_check_field(xp, old, HeIII_frac, limit); + cooling_check_field(xp, old, e_frac, limit); +#endif +#if COOLING_GRACKLE_MODE > 1 + cooling_check_field(xp, old, HM_frac, limit); + cooling_check_field(xp, old, H2I_frac, limit); + cooling_check_field(xp, old, H2II_frac, limit); +#endif + +#if COOLING_GRACKLE_MODE > 2 + cooling_check_field(xp, old, DI_frac, limit); + cooling_check_field(xp, old, DII_frac, limit); + cooling_check_field(xp, old, HDI_frac, limit); +#endif + + return 1; +} + +/** + * @brief Compute equilibrium fraction + * + * @param p Pointer to the particle data. + * @param xp Pointer to the extended particle data. + * @param cooling The properties of the cooling function. + */ +void cooling_compute_equilibrium( + const struct phys_const* restrict phys_const, + const struct unit_system* restrict us, + const struct hydro_props* hydro_properties, + const struct cosmology* restrict cosmo, + const struct cooling_function_data* restrict cooling, + const struct part* restrict p, struct xpart* restrict xp) { + + /* get temporary data */ + struct part p_tmp = *p; + struct cooling_function_data cooling_tmp = *cooling; + cooling_tmp.chemistry.with_radiative_cooling = 0; + /* need density for computation, therefore quick estimate */ + p_tmp.rho = 0.2387 * p_tmp.mass / pow(p_tmp.h, 3); + + /* compute time step */ + const double alpha = 0.01; + double dt = fabs(cooling_time(phys_const, us, hydro_properties, cosmo, + &cooling_tmp, &p_tmp, xp)); + cooling_new_energy(phys_const, us, cosmo, hydro_properties, &cooling_tmp, + &p_tmp, xp, dt); + dt = alpha * fabs(cooling_time(phys_const, us, hydro_properties, cosmo, + &cooling_tmp, &p_tmp, xp)); + + /* init simple variables */ + int step = 0; + const int max_step = cooling_tmp.max_step; + const float conv_limit = cooling_tmp.convergence_limit; + struct xpart old; + + do { + /* update variables */ + step += 1; + old = *xp; + + /* update chemistry */ + cooling_new_energy(phys_const, us, cosmo, hydro_properties, &cooling_tmp, + &p_tmp, xp, dt); + } while (step < max_step && !cooling_converged(xp, &old, conv_limit)); + + if (step == max_step) + error( + "A particle element fraction failed to converge." + "You can change 'GrackleCooling:MaxSteps' or " + "'GrackleCooling:ConvergenceLimit' to avoid this problem"); +} + +/** + * @brief Sets the cooling properties of the (x-)particles to a valid start + * state. + * + * @param p Pointer to the particle data. + * @param xp Pointer to the extended particle data. + * @param cooling The properties of the cooling function. + */ +void cooling_first_init_part(const struct phys_const* restrict phys_const, + const struct unit_system* restrict us, + const struct hydro_props* hydro_props, + const struct cosmology* restrict cosmo, + const struct cooling_function_data* cooling, + const struct part* restrict p, + struct xpart* restrict xp) { + + xp->cooling_data.radiated_energy = 0.f; + xp->cooling_data.time_last_event = -cooling->thermal_time; + +#if COOLING_GRACKLE_MODE >= 1 + gr_float zero = 1.e-20; + + /* primordial chemistry >= 1 */ + xp->cooling_data.HI_frac = zero; + xp->cooling_data.HII_frac = grackle_data->HydrogenFractionByMass; + xp->cooling_data.HeI_frac = 1. - grackle_data->HydrogenFractionByMass; + xp->cooling_data.HeII_frac = zero; + xp->cooling_data.HeIII_frac = zero; + xp->cooling_data.e_frac = xp->cooling_data.HII_frac + + 0.25 * xp->cooling_data.HeII_frac + + 0.5 * xp->cooling_data.HeIII_frac; +#endif // MODE >= 1 + +#if COOLING_GRACKLE_MODE >= 2 + /* primordial chemistry >= 2 */ + xp->cooling_data.HM_frac = zero; + xp->cooling_data.H2I_frac = zero; + xp->cooling_data.H2II_frac = zero; +#endif // MODE >= 2 + +#if COOLING_GRACKLE_MODE >= 3 + /* primordial chemistry >= 3 */ + xp->cooling_data.DI_frac = grackle_data->DeuteriumToHydrogenRatio * + grackle_data->HydrogenFractionByMass; + xp->cooling_data.DII_frac = zero; + xp->cooling_data.HDI_frac = zero; +#endif // MODE >= 3 + +#if COOLING_GRACKLE_MODE > 0 + cooling_compute_equilibrium(phys_const, us, hydro_props, cosmo, cooling, p, + xp); +#endif +} + +/** + * @brief Returns the total radiated energy by this particle. + * + * @param xp The extended particle data + */ +float cooling_get_radiated_energy(const struct xpart* restrict xp) { + + return xp->cooling_data.radiated_energy; +} + +/** + * @brief Prints the properties of the cooling model to stdout. + * + * @param cooling The properties of the cooling function. + */ +void cooling_print_backend(const struct cooling_function_data* cooling) { + + message("Cooling function is 'Grackle'."); + message("Using Grackle = %i", cooling->chemistry.use_grackle); + message("Chemical network = %i", cooling->chemistry.primordial_chemistry); + message("CloudyTable = %s", cooling->cloudy_table); + message("Redshift = %g", cooling->redshift); + message("UV background = %d", cooling->with_uv_background); + message("Metal cooling = %i", cooling->chemistry.metal_cooling); + message("Self Shielding = %i", cooling->self_shielding_method); + if (cooling->self_shielding_method == -1) { + message("Self Shelding density = %g", cooling->self_shielding_threshold); + } + message("Specific Heating Rates = %i", + cooling->provide_specific_heating_rates); + message("Volumetric Heating Rates = %i", + cooling->provide_volumetric_heating_rates); + message("Units:"); + message("\tComoving = %i", cooling->units.comoving_coordinates); + message("\tLength = %g", cooling->units.length_units); + message("\tDensity = %g", cooling->units.density_units); + message("\tTime = %g", cooling->units.time_units); + message("\tScale Factor = %g (units: %g)", cooling->units.a_value, + cooling->units.a_units); +} + +/** + * @brief copy a #xpart to the grackle data + * + * @param data The #grackle_field_data + * @param p The #part + * @param xp The #xpart + * @param rho Particle density + */ +#if COOLING_GRACKLE_MODE > 0 +void cooling_copy_to_grackle1(grackle_field_data* data, const struct part* p, + struct xpart* xp, gr_float rho) { + /* HI */ + xp->cooling_data.HI_frac *= rho; + data->HI_density = &xp->cooling_data.HI_frac; + /* HII */ + xp->cooling_data.HII_frac *= rho; + data->HII_density = &xp->cooling_data.HII_frac; + + /* HeI */ + xp->cooling_data.HeI_frac *= rho; + data->HeI_density = &xp->cooling_data.HeI_frac; + + /* HeII */ + xp->cooling_data.HeII_frac *= rho; + data->HeII_density = &xp->cooling_data.HeII_frac; + + /* HeIII */ + xp->cooling_data.HeIII_frac *= rho; + data->HeIII_density = &xp->cooling_data.HeIII_frac; + + /* HeII */ + xp->cooling_data.e_frac *= rho; + data->e_density = &xp->cooling_data.e_frac; +} +#else +void cooling_copy_to_grackle1(grackle_field_data* data, const struct part* p, + struct xpart* xp, gr_float rho) { + data->HI_density = NULL; + data->HII_density = NULL; + data->HeI_density = NULL; + data->HeII_density = NULL; + data->HeIII_density = NULL; + data->e_density = NULL; +} +#endif + +/** + * @brief copy a #xpart to the grackle data + * + * @param data The #grackle_field_data + * @param p The #part + * @param xp The #xpart + * @param rho Particle density + */ +#if COOLING_GRACKLE_MODE > 1 +void cooling_copy_to_grackle2(grackle_field_data* data, const struct part* p, + struct xpart* xp, gr_float rho) { + /* HM */ + xp->cooling_data.HM_frac *= rho; + data->HM_density = &xp->cooling_data.HM_frac; + + /* H2I */ + xp->cooling_data.H2I_frac *= rho; + data->H2I_density = &xp->cooling_data.H2I_frac; + + /* H2II */ + xp->cooling_data.H2II_frac *= rho; + data->H2II_density = &xp->cooling_data.H2II_frac; +} +#else +void cooling_copy_to_grackle2(grackle_field_data* data, const struct part* p, + struct xpart* xp, gr_float rho) { + data->HM_density = NULL; + data->H2I_density = NULL; + data->H2II_density = NULL; +} +#endif + +/** + * @brief copy a #xpart to the grackle data + * + * @param data The #grackle_field_data + * @param p The #part + * @param xp The #xpart + * @param rho Particle density + */ +#if COOLING_GRACKLE_MODE > 2 +void cooling_copy_to_grackle3(grackle_field_data* data, const struct part* p, + struct xpart* xp, gr_float rho) { + /* DI */ + xp->cooling_data.DI_frac *= rho; + data->DI_density = &xp->cooling_data.DI_frac; + + /* DII */ + xp->cooling_data.DII_frac *= rho; + data->DII_density = &xp->cooling_data.DII_frac; + + /* HDI */ + xp->cooling_data.HDI_frac *= rho; + data->HDI_density = &xp->cooling_data.HDI_frac; +} +#else +void cooling_copy_to_grackle3(grackle_field_data* data, const struct part* p, + struct xpart* xp, gr_float rho) { + data->DI_density = NULL; + data->DII_density = NULL; + data->HDI_density = NULL; +} +#endif + +/** + * @brief copy the grackle data to a #xpart + * + * @param data The #grackle_field_data + * @param p The #part + * @param xp The #xpart + * @param rho Particle density + */ +#if COOLING_GRACKLE_MODE > 0 +void cooling_copy_from_grackle1(grackle_field_data* data, const struct part* p, + struct xpart* xp, gr_float rho) { + + /* HI */ + xp->cooling_data.HI_frac = *data->HI_density / rho; + + /* HII */ + xp->cooling_data.HII_frac = *data->HII_density / rho; + + /* HeI */ + xp->cooling_data.HeI_frac = *data->HeI_density / rho; + + /* HeII */ + xp->cooling_data.HeII_frac = *data->HeII_density / rho; + + /* HeIII */ + xp->cooling_data.HeIII_frac = *data->HeIII_density / rho; + + /* e */ + xp->cooling_data.e_frac = *data->e_density / rho; +} +#else +void cooling_copy_from_grackle1(grackle_field_data* data, const struct part* p, + struct xpart* xp, gr_float rho) {} +#endif + +/** + * @brief copy the grackle data to a #xpart + * + * @param data The #grackle_field_data + * @param p The #part + * @param xp The #xpart + * @param rho Particle density + */ +#if COOLING_GRACKLE_MODE > 1 +void cooling_copy_from_grackle2(grackle_field_data* data, const struct part* p, + struct xpart* xp, gr_float rho) { + /* HM */ + xp->cooling_data.HM_frac = *data->HM_density / rho; + /* H2I */ + xp->cooling_data.H2I_frac = *data->H2I_density / rho; + /* H2II */ + xp->cooling_data.H2II_frac = *data->H2II_density / rho; +} +#else +void cooling_copy_from_grackle2(grackle_field_data* data, const struct part* p, + struct xpart* xp, gr_float rho) {} +#endif + +/** + * @brief copy the grackle data to a #xpart + * + * @param data The #grackle_field_data + * @param p The #part + * @param xp The #xpart + * @param rho Particle density + */ +#if COOLING_GRACKLE_MODE > 2 +void cooling_copy_from_grackle3(grackle_field_data* data, const struct part* p, + struct xpart* xp, gr_float rho) { + + /* DI */ + xp->cooling_data.DI_frac = *data->DI_density / rho; + + /* DII */ + xp->cooling_data.DII_frac = *data->DII_density / rho; + + /* HDI */ + xp->cooling_data.HDI_frac = *data->HDI_density / rho; +} +#else +void cooling_copy_from_grackle3(grackle_field_data* data, const struct part* p, + struct xpart* xp, gr_float rho) {} +#endif + +/** + * @brief copy a #xpart to the grackle data + * + * Warning this function creates some variable, therefore the grackle call + * should be in a block that still has the variables. + * + * @param data The #grackle_field_data + * @param p The #part + * @param xp The #xpart + * @param rho Particle density + */ +void cooling_copy_to_grackle(grackle_field_data* data, const struct part* p, + struct xpart* xp, gr_float rho) { + + cooling_copy_to_grackle1(data, p, xp, rho); + cooling_copy_to_grackle2(data, p, xp, rho); + cooling_copy_to_grackle3(data, p, xp, rho); + + data->volumetric_heating_rate = NULL; + data->specific_heating_rate = NULL; + data->RT_heating_rate = NULL; + data->RT_HI_ionization_rate = NULL; + data->RT_HeI_ionization_rate = NULL; + data->RT_HeII_ionization_rate = NULL; + data->RT_H2_dissociation_rate = NULL; + + gr_float* metal_density = (gr_float*)malloc(sizeof(gr_float)); + *metal_density = chemistry_get_total_metal_mass_fraction_for_cooling(p) * rho; + data->metal_density = metal_density; +} + +/** + * @brief copy a #xpart to the grackle data + * + * Warning this function creates some variable, therefore the grackle call + * should be in a block that still has the variables. + * + * @param data The #grackle_field_data + * @param p The #part + * @param xp The #xpart + * @param rho Particle density + */ +void cooling_copy_from_grackle(grackle_field_data* data, const struct part* p, + struct xpart* xp, gr_float rho) { + cooling_copy_from_grackle1(data, p, xp, rho); + cooling_copy_from_grackle2(data, p, xp, rho); + cooling_copy_from_grackle3(data, p, xp, rho); + + free(data->metal_density); +} + +/** + * @brief Apply the self shielding (if needed) by turning on/off the UV + * background. + * + * @param cooling The #cooling_function_data used in the run. + * @param chemistry The #chemistry_data from grackle. + * @param p Pointer to the particle data. + * + */ +void cooling_apply_self_shielding( + const struct cooling_function_data* restrict cooling, + chemistry_data* restrict chemistry, const struct part* restrict p, + const struct cosmology* cosmo) { + + /* Are we using self shielding or UV background? */ + if (!cooling->with_uv_background || cooling->self_shielding_method >= 0) { + return; + } + + /* Are we in a self shielding regime? */ + const float rho = hydro_get_physical_density(p, cosmo); + if (rho > cooling->self_shielding_threshold) { + chemistry->UVbackground = 0; + } else { + chemistry->UVbackground = 1; + } +} + +/** + * @brief Compute the energy of a particle after dt and update the particle + * chemistry data + * + * @param phys_const The physical constants in internal units. + * @param us The internal system of units. + * @param cooling The #cooling_function_data used in the run. + * @param p Pointer to the particle data. + * @param xp Pointer to the particle extra data + * @param dt The time-step of this particle. + * + * @return du / dt + */ +gr_float cooling_new_energy( + 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, + const struct part* restrict p, struct xpart* restrict xp, double dt) { + + /* set current time */ + code_units units = cooling->units; + chemistry_data chemistry_grackle = cooling->chemistry; + + /* initialize data */ + grackle_field_data data; + + /* set values */ + /* grid */ + int grid_dimension[GRACKLE_RANK] = {GRACKLE_NPART, 1, 1}; + int grid_start[GRACKLE_RANK] = {0, 0, 0}; + int grid_end[GRACKLE_RANK] = {GRACKLE_NPART - 1, 0, 0}; + + data.grid_dx = 0.; + data.grid_rank = GRACKLE_RANK; + data.grid_dimension = grid_dimension; + data.grid_start = grid_start; + data.grid_end = grid_end; + + /* general particle data */ + gr_float density = hydro_get_physical_density(p, cosmo); + gr_float energy = hydro_get_physical_internal_energy(p, xp, cosmo) + + dt * hydro_get_physical_internal_energy_dt(p, cosmo); + + /* We now need to check that we are not going to go below any of the limits */ + const double u_minimal = hydro_props->minimal_internal_energy; + energy = max(energy, u_minimal); + + /* initialize density */ + data.density = &density; + + /* initialize energy */ + data.internal_energy = &energy; + + /* grackle 3.0 doc: "Currently not used" */ + data.x_velocity = NULL; + data.y_velocity = NULL; + data.z_velocity = NULL; + + /* copy to grackle structure */ + cooling_copy_to_grackle(&data, p, xp, density); + + /* Apply the self shielding if requested */ + cooling_apply_self_shielding(cooling, &chemistry_grackle, p, cosmo); + + /* solve chemistry */ + if (local_solve_chemistry(&chemistry_grackle, &grackle_rates, &units, &data, + dt) == 0) { + error("Error in solve_chemistry."); + } + + /* copy from grackle data to particle */ + cooling_copy_from_grackle(&data, p, xp, density); + + return energy; +} + +/** + * @brief Compute the cooling time + * + * @param cooling The #cooling_function_data used in the run. + * @param p Pointer to the particle data. + * @param xp Pointer to the particle extra data + * + * @return cooling time + */ +gr_float cooling_time(const struct phys_const* restrict phys_const, + const struct unit_system* restrict us, + const struct hydro_props* hydro_props, + const struct cosmology* restrict cosmo, + const struct cooling_function_data* restrict cooling, + const struct part* restrict p, + struct xpart* restrict xp) { + + error("TODO: use energy after adiabatic cooling"); + + /* set current time */ + code_units units = cooling->units; + + /* initialize data */ + grackle_field_data data; + chemistry_data chemistry_grackle = cooling->chemistry; + + /* set values */ + /* grid */ + int grid_dimension[GRACKLE_RANK] = {GRACKLE_NPART, 1, 1}; + int grid_start[GRACKLE_RANK] = {0, 0, 0}; + int grid_end[GRACKLE_RANK] = {GRACKLE_NPART - 1, 0, 0}; + + data.grid_rank = GRACKLE_RANK; + data.grid_dimension = grid_dimension; + data.grid_start = grid_start; + data.grid_end = grid_end; + + /* general particle data */ + gr_float density = hydro_get_physical_density(p, cosmo); + gr_float energy = hydro_get_physical_internal_energy(p, xp, cosmo); + + /* initialize density */ + data.density = &density; + + /* initialize energy */ + data.internal_energy = &energy; + + /* grackle 3.0 doc: "Currently not used" */ + data.x_velocity = NULL; + data.y_velocity = NULL; + data.z_velocity = NULL; + + /* copy data from particle to grackle data */ + cooling_copy_to_grackle(&data, p, xp, density); + + /* Apply the self shielding if requested */ + cooling_apply_self_shielding(cooling, &chemistry_grackle, p, cosmo); + + /* Compute cooling time */ + gr_float cooling_time; + 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."); + } + + /* copy from grackle data to particle */ + cooling_copy_from_grackle(&data, p, xp, density); + + /* compute rate */ + return cooling_time; +} + +/** + * @brief Apply the cooling to a particle. + * + * Depending on the task order, you may wish to either + * cool down the particle immediately or do it during the drift. + * + * @param p Pointer to the particle data. + * @param xp Pointer to the xparticle data. + * @param cosmo The current cosmological model. + * @param cooling_du_dt Time derivative of the cooling. + * @param u_new Internal energy after the cooling. + */ +void cooling_apply(struct part* restrict p, struct xpart* restrict xp, + const struct cosmology* restrict cosmo, float cooling_du_dt, + gr_float u_new) { + +#ifdef TASK_ORDER_GEAR + /* Cannot use du / dt as it will be erased before being used */ + hydro_set_physical_internal_energy(p, xp, cosmo, u_new); + hydro_set_drifted_physical_internal_energy(p, cosmo, u_new); +#else + hydro_set_physical_internal_energy_dt(p, cosmo, cooling_du_dt); +#endif +} + +/** + * @brief Apply the cooling function to a particle. + * + * @param phys_const The physical constants in internal units. + * @param us The internal system of units. + * @param cosmo The current cosmological model. + * @param floor_props Properties of the entropy floor. + * @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 time The current time. + * @param dt The time-step of this particle. + * @param dt_therm The time-step operator used for thermal quantities. + */ +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 entropy_floor_properties* floor_props, + const struct cooling_function_data* restrict cooling, + struct part* restrict p, struct xpart* restrict xp, + const double time, const double dt, + const double dt_therm) { + + /* Nothing to do here? */ + if (dt == 0.) return; + + /* Is the cooling turn off */ + if (time - xp->cooling_data.time_last_event < cooling->thermal_time) { + return; + } + + /* Get the change in internal energy due to hydro forces */ + const float hydro_du_dt = hydro_get_physical_internal_energy_dt(p, cosmo); + + /* Current energy */ + const float u_old = hydro_get_physical_internal_energy(p, xp, cosmo); + + /* Calculate energy after dt */ + gr_float u_new = cooling_new_energy(phys_const, us, cosmo, hydro_props, + cooling, p, xp, dt); + + /* We now need to check that we are not going to go below any of the limits */ + const double u_minimal = hydro_props->minimal_internal_energy; + u_new = max(u_new, u_minimal); + + /* Expected change in energy over the next kick step + (assuming no change in dt) */ + const double delta_u = u_new - u_old; + + /* Turn this into a rate of change (including cosmology term) */ + const float cooling_du_dt = delta_u / dt_therm; + + /* Update the internal energy time derivative */ + cooling_apply(p, xp, cosmo, cooling_du_dt, u_new); + + /* Store the radiated energy */ + xp->cooling_data.radiated_energy -= + hydro_get_mass(p) * (cooling_du_dt - hydro_du_dt) * dt; +} + +/** + * @brief Compute the temperature of a #part based on the cooling function. + * + * @param phys_const #phys_const data structure. + * @param hydro_props The properties of the hydro scheme. + * @param us The internal system of units. + * @param cosmo #cosmology data structure. + * @param cooling #cooling_function_data struct. + * @param p #part data. + * @param xp Pointer to the #xpart data. + */ +float cooling_get_temperature( + const struct phys_const* restrict phys_const, + const struct hydro_props* restrict hydro_props, + const struct unit_system* restrict us, + const struct cosmology* restrict cosmo, + const struct cooling_function_data* restrict cooling, + const struct part* restrict p, const struct xpart* restrict xp) { + // TODO use the grackle library + + /* Physical constants */ + const double m_H = phys_const->const_proton_mass; + const double k_B = phys_const->const_boltzmann_k; + + /* Gas properties */ + const double T_transition = hydro_props->hydrogen_ionization_temperature; + const double mu_neutral = hydro_props->mu_neutral; + const double mu_ionised = hydro_props->mu_ionised; + + /* Particle temperature */ + const double u = hydro_get_drifted_physical_internal_energy(p, cosmo); + + /* Temperature over mean molecular weight */ + const double T_over_mu = hydro_gamma_minus_one * u * m_H / k_B; + + /* Are we above or below the HII -> HI transition? */ + if (T_over_mu > (T_transition + 1.) / mu_ionised) + return T_over_mu * mu_ionised; + else if (T_over_mu < (T_transition - 1.) / mu_neutral) + return T_over_mu * mu_neutral; + else + return T_transition; +} + +/** + * @brief Computes the cooling time-step. + * + * We return FLT_MAX so as to impose no limit on the time-step. + * + * @param cooling The #cooling_function_data used in the run. + * @param phys_const The physical constants in internal units. + * @param cosmo The current cosmological model. + * @param us The internal system of units. + * @param p Pointer to the particle data. + */ +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 Split the coolong content of a particle into n pieces + * + * @param p The #part. + * @param xp The #xpart. + * @param n The number of pieces to split into. + */ +void cooling_split_part(struct part* p, struct xpart* xp, double n) { + + error("Loic: to be implemented"); +} + +/** + * @brief Initialises the cooling unit system. + * + * @param us The current internal system of units. + * @param cooling The cooling properties to initialize + */ +void cooling_init_units(const struct unit_system* us, + const struct phys_const* phys_const, + struct cooling_function_data* cooling) { + + /* These are conversions from code units to cgs. */ + + /* first cosmo */ + cooling->units.a_units = 1.0; // units for the expansion factor + cooling->units.a_value = 1.0; + + /* We assume here all physical quantities to + be in proper coordinate (not comobile) */ + cooling->units.comoving_coordinates = 0; + + /* then units */ + cooling->units.density_units = + units_cgs_conversion_factor(us, UNIT_CONV_DENSITY); + cooling->units.length_units = + units_cgs_conversion_factor(us, UNIT_CONV_LENGTH); + cooling->units.time_units = units_cgs_conversion_factor(us, UNIT_CONV_TIME); + cooling->units.velocity_units = + units_cgs_conversion_factor(us, UNIT_CONV_VELOCITY); + + /* Self shielding */ + if (cooling->self_shielding_method == -1) { + cooling->self_shielding_threshold *= + phys_const->const_proton_mass * + pow(units_cgs_conversion_factor(us, UNIT_CONV_LENGTH), 3.); + } +} + +/** + * @brief Initialises Grackle. + * + * @param cooling The cooling properties to initialize + */ +void cooling_init_grackle(struct cooling_function_data* cooling) { + +#ifdef SWIFT_DEBUG_CHECKS + /* enable verbose for grackle */ + grackle_verbose = 1; +#endif + + chemistry_data* chemistry = &cooling->chemistry; + + /* Create a chemistry object for parameters and rate data. */ + if (set_default_chemistry_parameters(chemistry) == 0) { + error("Error in set_default_chemistry_parameters."); + } + + // Set parameter values for chemistry. + chemistry->use_grackle = 1; + chemistry->with_radiative_cooling = 1; + + /* molecular network with H, He, D + From Cloudy table */ + chemistry->primordial_chemistry = cooling->primordial_chemistry; + chemistry->metal_cooling = cooling->with_metal_cooling; + chemistry->UVbackground = cooling->with_uv_background; + chemistry->grackle_data_file = cooling->cloudy_table; + + /* radiative transfer */ + chemistry->use_radiative_transfer = cooling->provide_specific_heating_rates || + cooling->provide_volumetric_heating_rates; + chemistry->use_volumetric_heating_rate = + cooling->provide_volumetric_heating_rates; + chemistry->use_specific_heating_rate = + cooling->provide_specific_heating_rates; + + if (cooling->provide_specific_heating_rates && + cooling->provide_volumetric_heating_rates) + message( + "WARNING: You should specified either the specific or the volumetric " + "heating rates, not both"); + + /* self shielding */ + chemistry->self_shielding_method = cooling->self_shielding_method; + + /* Initialize the chemistry object. */ + if (initialize_chemistry_data(&cooling->units) == 0) { + error("Error in initialize_chemistry_data."); + } +} + +/** + * @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 hydro_props The properties of the hydro scheme. + * @param cooling The cooling properties to initialize + */ +void cooling_init_backend(struct swift_params* parameter_file, + const struct unit_system* us, + const struct phys_const* phys_const, + const struct hydro_props* hydro_props, + struct cooling_function_data* cooling) { + + if (GRACKLE_NPART != 1) + error("Grackle with multiple particles not implemented"); + + /* read parameters */ + cooling_read_parameters(parameter_file, cooling, phys_const); + + /* Set up the units system. */ + cooling_init_units(us, phys_const, cooling); + + /* Set up grackle */ + cooling_init_grackle(cooling); +} + +/** + * @brief Clean-up the memory allocated for the cooling routines + * + * @param cooling the cooling data structure. + */ +void cooling_clean(struct cooling_function_data* cooling) { + _free_chemistry_data(&cooling->chemistry, &grackle_rates); +} + +/** + * @brief Write a cooling struct to the given FILE as a stream of bytes. + * + * Nothing to do beyond writing the structure from the stream. + * + * @param cooling the struct + * @param stream the file stream + */ +void cooling_struct_dump(const struct cooling_function_data* cooling, + FILE* stream) { + restart_write_blocks((void*)cooling, sizeof(struct cooling_function_data), 1, + stream, "cooling", "cooling function"); +} + +/** + * @brief Restore a hydro_props struct from the given FILE as a stream of + * bytes. + * + * Nothing to do beyond reading the structure from the stream. + * + * @param cooling the struct + * @param stream the file stream + * @param cosmo #cosmology structure + */ +void cooling_struct_restore(struct cooling_function_data* cooling, FILE* stream, + const struct cosmology* cosmo) { + restart_read_blocks((void*)cooling, sizeof(struct cooling_function_data), 1, + stream, NULL, "cooling function"); + + /* Set up grackle */ + cooling_init_grackle(cooling); +} diff --git a/src/cooling/grackle/cooling.h b/src/cooling/grackle/cooling.h index dec0e80ffa834e7749c8c1815a8a7441befc251b..209b986c6f39595a7f60b64539c97e3292e79571 100644 --- a/src/cooling/grackle/cooling.h +++ b/src/cooling/grackle/cooling.h @@ -25,6 +25,7 @@ */ /* Some standard headers. */ +#include <fenv.h> #include <float.h> #include <math.h> @@ -46,875 +47,108 @@ #define GRACKLE_NPART 1 #define GRACKLE_RANK 3 -/* prototype */ -static gr_float cooling_time( +void cooling_update(const struct cosmology* cosmo, + struct cooling_function_data* cooling, struct space* s); +void cooling_print_fractions(const struct xpart* restrict xp); +int cooling_converged(const struct xpart* restrict xp, + const struct xpart* restrict old, const float limit); +void cooling_compute_equilibrium( const struct phys_const* restrict phys_const, const struct unit_system* restrict us, + const struct hydro_props* hydro_properties, const struct cosmology* restrict cosmo, const struct cooling_function_data* restrict cooling, const struct part* restrict p, struct xpart* restrict xp); -static gr_float cooling_new_energy( - 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, double dt); - -/** - * @brief Common operations performed on the cooling function at a - * given time-step or redshift. - * - * @param cosmo The current cosmological model. - * @param cooling The #cooling_function_data used in the run. - * @param s The #space containing all the particles. - */ -INLINE static void cooling_update(const struct cosmology* cosmo, - struct cooling_function_data* cooling, - struct space* s) { - /* set current time */ - if (cooling->redshift == -1) - cooling->units.a_value = cosmo->a; - else - cooling->units.a_value = 1. / (1. + cooling->redshift); -} - -/** - * @brief Print the chemical network - * - * @param xp The #xpart to print - */ -__attribute__((always_inline)) INLINE static void cooling_print_fractions( - const struct xpart* restrict xp) { - - const struct cooling_xpart_data tmp = xp->cooling_data; -#if COOLING_GRACKLE_MODE > 0 - message("HI %g, HII %g, HeI %g, HeII %g, HeIII %g, e %g", tmp.HI_frac, - tmp.HII_frac, tmp.HeI_frac, tmp.HeII_frac, tmp.HeIII_frac, - tmp.e_frac); -#endif - -#if COOLING_GRACKLE_MODE > 1 - message("HM %g, H2I %g, H2II %g", tmp.HM_frac, tmp.H2I_frac, tmp.H2II_frac); -#endif - -#if COOLING_GRACKLE_MODE > 2 - message("DI %g, DII %g, HDI %g", tmp.DI_frac, tmp.DII_frac, tmp.HDI_frac); -#endif - message("Metal: %g", tmp.metal_frac); -} - -/** - * @brief Check if the difference of a given field is lower than limit - * - * @param xp First #xpart - * @param old Second #xpart - * @param field The field to check - * @param limit Difference limit - * - * @return 0 if diff > limit - */ -#define cooling_check_field(xp, old, field, limit) \ - ({ \ - float tmp = xp->cooling_data.field - old->cooling_data.field; \ - tmp = fabs(tmp) / xp->cooling_data.field; \ - if (tmp > limit) return 0; \ - }) - -/** - * @brief Check if difference between two particles is lower than a given value - * - * @param xp One of the #xpart - * @param old The other #xpart - * @param limit The difference limit - */ -__attribute__((always_inline)) INLINE static int cooling_converged( - const struct xpart* restrict xp, const struct xpart* restrict old, - const float limit) { - -#if COOLING_GRACKLE_MODE > 0 - cooling_check_field(xp, old, HI_frac, limit); - cooling_check_field(xp, old, HII_frac, limit); - cooling_check_field(xp, old, HeI_frac, limit); - cooling_check_field(xp, old, HeII_frac, limit); - cooling_check_field(xp, old, HeIII_frac, limit); - cooling_check_field(xp, old, e_frac, limit); -#endif -#if COOLING_GRACKLE_MODE > 1 - cooling_check_field(xp, old, HM_frac, limit); - cooling_check_field(xp, old, H2I_frac, limit); - cooling_check_field(xp, old, H2II_frac, limit); -#endif - -#if COOLING_GRACKLE_MODE > 2 - cooling_check_field(xp, old, DI_frac, limit); - cooling_check_field(xp, old, DII_frac, limit); - cooling_check_field(xp, old, HDI_frac, limit); -#endif - - return 1; -} - -/** - * @brief Compute equilibrium fraction - * - * @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_compute_equilibrium( - 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) { - - /* get temporary data */ - struct part p_tmp = *p; - struct cooling_function_data cooling_tmp = *cooling; - cooling_tmp.chemistry.with_radiative_cooling = 0; - /* need density for computation, therefore quick estimate */ - p_tmp.rho = 0.2387 * p_tmp.mass / pow(p_tmp.h, 3); - - /* compute time step */ - const double alpha = 0.01; - double dt = - fabs(cooling_time(phys_const, us, cosmo, &cooling_tmp, &p_tmp, xp)); - cooling_new_energy(phys_const, us, cosmo, &cooling_tmp, &p_tmp, xp, dt); - dt = alpha * - fabs(cooling_time(phys_const, us, cosmo, &cooling_tmp, &p_tmp, xp)); - - /* init simple variables */ - int step = 0; - const int max_step = cooling_tmp.max_step; - const float conv_limit = cooling_tmp.convergence_limit; - struct xpart old; - - do { - /* update variables */ - step += 1; - old = *xp; - - /* update chemistry */ - cooling_new_energy(phys_const, us, cosmo, &cooling_tmp, &p_tmp, xp, dt); - } while (step < max_step && !cooling_converged(xp, &old, conv_limit)); - - if (step == max_step) - error( - "A particle element fraction failed to converge." - "You can change 'GrackleCooling:MaxSteps' or " - "'GrackleCooling:ConvergenceLimit' to avoid this problem"); -} - -/** - * @brief Sets the cooling properties of the (x-)particles to a valid start - * state. - * - * @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, - const struct unit_system* restrict us, - const struct cosmology* restrict cosmo, - const struct cooling_function_data* cooling, const struct part* restrict p, - struct xpart* restrict xp) { - - xp->cooling_data.radiated_energy = 0.f; - -#if COOLING_GRACKLE_MODE >= 1 - gr_float zero = 1.e-20; - - /* primordial chemistry >= 1 */ - xp->cooling_data.HI_frac = zero; - xp->cooling_data.HII_frac = grackle_data->HydrogenFractionByMass; - xp->cooling_data.HeI_frac = 1. - grackle_data->HydrogenFractionByMass; - xp->cooling_data.HeII_frac = zero; - xp->cooling_data.HeIII_frac = zero; - xp->cooling_data.e_frac = xp->cooling_data.HII_frac + - 0.25 * xp->cooling_data.HeII_frac + - 0.5 * xp->cooling_data.HeIII_frac; -#endif // MODE >= 1 - -#if COOLING_GRACKLE_MODE >= 2 - /* primordial chemistry >= 2 */ - xp->cooling_data.HM_frac = zero; - xp->cooling_data.H2I_frac = zero; - xp->cooling_data.H2II_frac = zero; -#endif // MODE >= 2 - -#if COOLING_GRACKLE_MODE >= 3 - /* primordial chemistry >= 3 */ - xp->cooling_data.DI_frac = grackle_data->DeuteriumToHydrogenRatio * - grackle_data->HydrogenFractionByMass; - xp->cooling_data.DII_frac = zero; - xp->cooling_data.HDI_frac = zero; -#endif // MODE >= 3 - -#if COOLING_GRACKLE_MODE > 0 - cooling_compute_equilibrium(phys_const, us, cosmo, cooling, p, xp); -#endif -} - -/** - * @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 Prints the properties of the cooling model to stdout. - * - * @param cooling The properties of the cooling function. - */ -__attribute__((always_inline)) INLINE static void cooling_print_backend( - const struct cooling_function_data* cooling) { - - message("Cooling function is 'Grackle'."); - message("Using Grackle = %i", cooling->chemistry.use_grackle); - message("Chemical network = %i", cooling->chemistry.primordial_chemistry); - message("CloudyTable = %s", cooling->cloudy_table); - message("Redshift = %g", cooling->redshift); - message("UV background = %d", cooling->with_uv_background); - message("Metal cooling = %i", cooling->chemistry.metal_cooling); - message("Self Shielding = %i", cooling->self_shielding_method); - message("Specific Heating Rates = %i", - cooling->provide_specific_heating_rates); - message("Volumetric Heating Rates = %i", - cooling->provide_volumetric_heating_rates); - message("Units:"); - message("\tComoving = %i", cooling->units.comoving_coordinates); - message("\tLength = %g", cooling->units.length_units); - message("\tDensity = %g", cooling->units.density_units); - message("\tTime = %g", cooling->units.time_units); - message("\tScale Factor = %g (units: %g)", cooling->units.a_value, - cooling->units.a_units); -} - -/** - * @brief copy a single field from the grackle data to a #xpart - * - * @param data The #grackle_field_data - * @param xp The #xpart - * @param rho Particle density - * @param field The field to copy - */ -#define cooling_copy_field_from_grackle(data, xp, rho, field) \ - xp->cooling_data.field##_frac = *data.field##_density / rho; - -/** - * @brief copy a single field from a #xpart to the grackle data - * - * @param data The #grackle_field_data - * @param xp The #xpart - * @param rho Particle density - * @param field The field to copy - */ -#define cooling_copy_field_to_grackle(data, xp, rho, field) \ - gr_float grackle_##field = xp->cooling_data.field##_frac * rho; \ - data.field##_density = &grackle_##field; - -/** - * @brief copy a #xpart to the grackle data - * - * Warning this function creates some variable, therefore the grackle call - * should be in a block that still has the variables. - * - * @param data The #grackle_field_data - * @param p The #part - * @param xp The #xpart - * @param rho Particle density - */ -#if COOLING_GRACKLE_MODE > 0 -#define cooling_copy_to_grackle1(data, p, xp, rho) \ - cooling_copy_field_to_grackle(data, xp, rho, HI); \ - cooling_copy_field_to_grackle(data, xp, rho, HII); \ - cooling_copy_field_to_grackle(data, xp, rho, HeI); \ - cooling_copy_field_to_grackle(data, xp, rho, HeII); \ - cooling_copy_field_to_grackle(data, xp, rho, HeIII); \ - cooling_copy_field_to_grackle(data, xp, rho, e); -#else -#define cooling_copy_to_grackle1(data, p, xp, rho) \ - data.HI_density = NULL; \ - data.HII_density = NULL; \ - data.HeI_density = NULL; \ - data.HeII_density = NULL; \ - data.HeIII_density = NULL; \ - data.e_density = NULL; -#endif - -/** - * @brief copy a #xpart to the grackle data - * - * Warning this function creates some variable, therefore the grackle call - * should be in a block that still has the variables. - * - * @param data The #grackle_field_data - * @param p The #part - * @param xp The #xpart - * @param rho Particle density - */ -#if COOLING_GRACKLE_MODE > 1 -#define cooling_copy_to_grackle2(data, p, xp, rho) \ - cooling_copy_field_to_grackle(data, xp, rho, HM); \ - cooling_copy_field_to_grackle(data, xp, rho, H2I); \ - cooling_copy_field_to_grackle(data, xp, rho, H2II); -#else -#define cooling_copy_to_grackle2(data, p, xp, rho) \ - data.HM_density = NULL; \ - data.H2I_density = NULL; \ - data.H2II_density = NULL; -#endif - -/** - * @brief copy a #xpart to the grackle data - * - * Warning this function creates some variable, therefore the grackle call - * should be in a block that still has the variables. - * - * @param data The #grackle_field_data - * @param p The #part - * @param xp The #xpart - * @param rho Particle density - */ -#if COOLING_GRACKLE_MODE > 2 -#define cooling_copy_to_grackle3(data, p, xp, rho) \ - cooling_copy_field_to_grackle(data, xp, rho, DI); \ - cooling_copy_field_to_grackle(data, xp, rho, DII); \ - cooling_copy_field_to_grackle(data, xp, rho, HDI); -#else -#define cooling_copy_to_grackle3(data, p, xp, rho) \ - data.DI_density = NULL; \ - data.DII_density = NULL; \ - data.HDI_density = NULL; -#endif - -/** - * @brief copy the grackle data to a #xpart - * - * @param data The #grackle_field_data - * @param p The #part - * @param xp The #xpart - * @param rho Particle density - */ -#if COOLING_GRACKLE_MODE > 0 -#define cooling_copy_from_grackle1(data, p, xp, rho) \ - cooling_copy_field_from_grackle(data, xp, rho, HI); \ - cooling_copy_field_from_grackle(data, xp, rho, HII); \ - cooling_copy_field_from_grackle(data, xp, rho, HeI); \ - cooling_copy_field_from_grackle(data, xp, rho, HeII); \ - cooling_copy_field_from_grackle(data, xp, rho, HeIII); \ - cooling_copy_field_from_grackle(data, xp, rho, e); -#else -#define cooling_copy_from_grackle1(data, p, xp, rho) -#endif - -/** - * @brief copy the grackle data to a #xpart - * - * @param data The #grackle_field_data - * @param p The #part - * @param xp The #xpart - * @param rho Particle density - */ -#if COOLING_GRACKLE_MODE > 1 -#define cooling_copy_from_grackle2(data, p, xp, rho) \ - cooling_copy_field_from_grackle(data, xp, rho, HM); \ - cooling_copy_field_from_grackle(data, xp, rho, H2I); \ - cooling_copy_field_from_grackle(data, xp, rho, H2II); -#else -#define cooling_copy_from_grackle2(data, p, xp, rho) -#endif - -/** - * @brief copy the grackle data to a #xpart - * - * @param data The #grackle_field_data - * @param p The #part - * @param xp The #xpart - * @param rho Particle density - */ -#if COOLING_GRACKLE_MODE > 2 -#define cooling_copy_from_grackle3(data, p, xp, rho) \ - cooling_copy_field_from_grackle(data, xp, rho, DI); \ - cooling_copy_field_from_grackle(data, xp, rho, DII); \ - cooling_copy_field_from_grackle(data, xp, rho, HDI); -#else -#define cooling_copy_from_grackle3(data, p, xp, rho) -#endif - -/** - * @brief copy a #xpart to the grackle data - * - * Warning this function creates some variable, therefore the grackle call - * should be in a block that still has the variables. - * - * @param data The #grackle_field_data - * @param p The #part - * @param xp The #xpart - * @param rho Particle density - */ -#define cooling_copy_to_grackle(data, p, xp, rho) \ - cooling_copy_to_grackle1(data, p, xp, rho); \ - cooling_copy_to_grackle2(data, p, xp, rho); \ - cooling_copy_to_grackle3(data, p, xp, rho); \ - data.volumetric_heating_rate = NULL; \ - data.specific_heating_rate = NULL; \ - data.RT_heating_rate = NULL; \ - data.RT_HI_ionization_rate = NULL; \ - data.RT_HeI_ionization_rate = NULL; \ - data.RT_HeII_ionization_rate = NULL; \ - data.RT_H2_dissociation_rate = NULL; \ - gr_float metal_density = chemistry_metal_mass_fraction(p, xp) * rho; \ - data.metal_density = &metal_density; - -/** - * @brief copy a #xpart to the grackle data - * - * Warning this function creates some variable, therefore the grackle call - * should be in a block that still has the variables. - * - * @param data The #grackle_field_data - * @param p The #part - * @param xp The #xpart - * @param rho Particle density - */ -#define cooling_copy_from_grackle(data, p, xp, rho) \ - cooling_copy_from_grackle1(data, p, xp, rho); \ - cooling_copy_from_grackle2(data, p, xp, rho); \ - cooling_copy_from_grackle3(data, p, xp, rho); - -/** - * @brief Compute the energy of a particle after dt and update the particle - * chemistry data - * - * @param phys_const The physical constants in internal units. - * @param us The internal system of units. - * @param cooling The #cooling_function_data used in the run. - * @param p Pointer to the particle data. - * @param xp Pointer to the particle extra data - * @param dt The time-step of this particle. - * - * @return du / dt - */ -__attribute__((always_inline)) INLINE static gr_float cooling_new_energy( - const struct phys_const* restrict phys_const, - const struct unit_system* restrict us, - const struct cosmology* restrict cosmo, +void cooling_first_init_part(const struct phys_const* restrict phys_const, + const struct unit_system* restrict us, + const struct hydro_props* hydro_properties, + const struct cosmology* restrict cosmo, + const struct cooling_function_data* cooling, + const struct part* restrict p, + struct xpart* restrict xp); + +float cooling_get_radiated_energy(const struct xpart* restrict xp); +void cooling_print_backend(const struct cooling_function_data* cooling); + +void cooling_copy_to_grackle1(grackle_field_data* data, const struct part* p, + struct xpart* xp, gr_float rho); +void cooling_copy_to_grackle2(grackle_field_data* data, const struct part* p, + struct xpart* xp, gr_float rho); +void cooling_copy_to_grackle3(grackle_field_data* data, const struct part* p, + struct xpart* xp, gr_float rho); +void cooling_copy_from_grackle1(grackle_field_data* data, const struct part* p, + struct xpart* xp, gr_float rho); +void cooling_copy_from_grackle2(grackle_field_data* data, const struct part* p, + struct xpart* xp, gr_float rho); +void cooling_copy_from_grackle3(grackle_field_data* data, const struct part* p, + struct xpart* xp, gr_float rho); +void cooling_copy_to_grackle(grackle_field_data* data, const struct part* p, + struct xpart* xp, gr_float rho); +void cooling_copy_from_grackle(grackle_field_data* data, const struct part* p, + struct xpart* xp, gr_float rho); +void cooling_apply_self_shielding( const struct cooling_function_data* restrict cooling, - const struct part* restrict p, struct xpart* restrict xp, double dt) { - - /* set current time */ - code_units units = cooling->units; - - /* initialize data */ - grackle_field_data data; - - /* set values */ - /* grid */ - int grid_dimension[GRACKLE_RANK] = {GRACKLE_NPART, 1, 1}; - int grid_start[GRACKLE_RANK] = {0, 0, 0}; - int grid_end[GRACKLE_RANK] = {GRACKLE_NPART - 1, 0, 0}; - - data.grid_dx = 0.; - data.grid_rank = GRACKLE_RANK; - data.grid_dimension = grid_dimension; - data.grid_start = grid_start; - data.grid_end = grid_end; - - /* general particle data */ - gr_float density = hydro_get_physical_density(p, cosmo); - const float energy_before = hydro_get_physical_internal_energy(p, xp, cosmo); - gr_float energy = energy_before; - - /* initialize density */ - data.density = &density; - - /* initialize energy */ - data.internal_energy = &energy; - - /* grackle 3.0 doc: "Currently not used" */ - data.x_velocity = NULL; - data.y_velocity = NULL; - data.z_velocity = NULL; - - /* copy to grackle structure */ - cooling_copy_to_grackle(data, p, xp, density); - - /* solve chemistry */ - chemistry_data chemistry_grackle = cooling->chemistry; - if (local_solve_chemistry(&chemistry_grackle, &grackle_rates, &units, &data, - dt) == 0) { - error("Error in solve_chemistry."); - } - - /* copy from grackle data to particle */ - cooling_copy_from_grackle(data, p, xp, density); - - return energy; -} - -/** - * @brief Compute the cooling time - * - * @param cooling The #cooling_function_data used in the run. - * @param p Pointer to the particle data. - * @param xp Pointer to the particle extra data - * - * @return cooling time - */ -__attribute__((always_inline)) INLINE static gr_float cooling_time( - 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) { - - /* set current time */ - code_units units = cooling->units; - - /* initialize data */ - grackle_field_data data; - - /* set values */ - /* grid */ - int grid_dimension[GRACKLE_RANK] = {GRACKLE_NPART, 1, 1}; - int grid_start[GRACKLE_RANK] = {0, 0, 0}; - int grid_end[GRACKLE_RANK] = {GRACKLE_NPART - 1, 0, 0}; - - data.grid_rank = GRACKLE_RANK; - data.grid_dimension = grid_dimension; - data.grid_start = grid_start; - data.grid_end = grid_end; - - /* general particle data */ - const gr_float energy_before = - hydro_get_physical_internal_energy(p, xp, cosmo); - gr_float density = hydro_get_physical_density(p, cosmo); - gr_float energy = energy_before; - - /* initialize density */ - data.density = &density; - - /* initialize energy */ - data.internal_energy = &energy; - - /* grackle 3.0 doc: "Currently not used" */ - data.x_velocity = NULL; - data.y_velocity = NULL; - data.z_velocity = NULL; - - /* copy data from particle to grackle data */ - cooling_copy_to_grackle(data, p, xp, density); - - /* Compute cooling time */ - gr_float cooling_time; - 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."); - } - - /* copy from grackle data to particle */ - cooling_copy_from_grackle(data, p, xp, density); - - /* compute rate */ - return cooling_time; -} - -/** - * @brief Apply the cooling function to a particle. - * - * @param phys_const The physical constants in internal units. - * @param us The internal system of units. - * @param cosmo The current cosmological model. - * @param cooling The #cooling_function_data used in the run. - * @param p Pointer to the particle data. - * @param dt The time-step of this particle. - * @param hydro_properties the hydro_props struct, used for - * getting the minimal internal energy allowed in by SWIFT. - * Read from yml file into engine struct. - */ -__attribute__((always_inline)) INLINE static void cooling_cool_part( + chemistry_data* restrict chemistry, const struct part* restrict p, + const struct cosmology* cosmo); +gr_float cooling_new_energy( 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 entropy_floor_properties* floor_props, + const struct hydro_props* hydro_properties, const struct cooling_function_data* restrict cooling, - struct part* restrict p, struct xpart* restrict xp, double dt, - double dt_therm) { - - /* Nothing to do here? */ - if (dt == 0.) return; - - /* 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 energy after dt */ - gr_float u_new = - cooling_new_energy(phys_const, us, cosmo, cooling, p, xp, dt); - - float delta_u = u_new - u_old + hydro_du_dt * dt_therm; - - /* 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_u. */ - if (u_old + 1.5 * delta_u < hydro_props->minimal_internal_energy) { - delta_u = (hydro_props->minimal_internal_energy - u_old) / 1.5; - } - - /* 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_u but this time against 0 energy not the minimum. - * To avoid numerical rounding bringing us below 0., we add a tiny tolerance. - */ - const float rounding_tolerance = 1.0e-4; - - if (u_old + 2.5 * delta_u < 0.) { - delta_u = -u_old / (2.5 + rounding_tolerance); - } - - /* Turn this into a rate of change (including cosmology term) */ - const float cooling_du_dt = delta_u / dt_therm; - - /* Update the internal energy time derivative */ - hydro_set_physical_internal_energy_dt(p, cosmo, cooling_du_dt); - - /* Store the radiated energy */ - xp->cooling_data.radiated_energy -= hydro_get_mass(p) * cooling_du_dt * dt; -} + const struct part* restrict p, struct xpart* restrict xp, double dt); -/** - * @brief Compute the temperature of a #part based on the cooling function. - * - * @param phys_const #phys_const data structure. - * @param hydro_props The properties of the hydro scheme. - * @param us The internal system of units. - * @param cosmo #cosmology data structure. - * @param cooling #cooling_function_data struct. - * @param p #part data. - * @param xp Pointer to the #xpart data. - */ -static INLINE float cooling_get_temperature( +gr_float cooling_time(const struct phys_const* restrict phys_const, + const struct unit_system* restrict us, + const struct hydro_props* hydro_properties, + const struct cosmology* restrict cosmo, + const struct cooling_function_data* restrict cooling, + const struct part* restrict p, struct xpart* restrict xp); +void cooling_apply(struct part* restrict p, struct xpart* restrict xp, + const struct cosmology* restrict cosmo, float cooling_du_dt, + gr_float u_new); + +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_properties, + const struct entropy_floor_properties* floor_props, + const struct cooling_function_data* restrict cooling, + struct part* restrict p, struct xpart* restrict xp, + const double time, const double dt, + const double dt_therm); + +float cooling_get_temperature( const struct phys_const* restrict phys_const, - const struct hydro_props* restrict hydro_props, + const struct hydro_props* hydro_properties, const struct unit_system* restrict us, const struct cosmology* restrict cosmo, const struct cooling_function_data* restrict cooling, - const struct part* restrict p, const struct xpart* restrict xp) { - // TODO use the grackle library - - /* Physical constants */ - const double m_H = phys_const->const_proton_mass; - const double k_B = phys_const->const_boltzmann_k; - - /* Gas properties */ - const double T_transition = hydro_props->hydrogen_ionization_temperature; - const double mu_neutral = hydro_props->mu_neutral; - const double mu_ionised = hydro_props->mu_ionised; - - /* Particle temperature */ - const double u = hydro_get_physical_internal_energy(p, xp, cosmo); - - /* Temperature over mean molecular weight */ - const double T_over_mu = hydro_gamma_minus_one * u * m_H / k_B; - - /* Are we above or below the HII -> HI transition? */ - if (T_over_mu > (T_transition + 1.) / mu_ionised) - return T_over_mu * mu_ionised; - else if (T_over_mu < (T_transition - 1.) / mu_neutral) - return T_over_mu * mu_neutral; - else - return T_transition; -} - -/** - * @brief Computes the cooling time-step. - * - * We return FLT_MAX so as to impose no limit on the time-step. - * - * @param cooling The #cooling_function_data used in the run. - * @param phys_const The physical constants in internal units. - * @param cosmo The current cosmological model. - * @param us The internal system of units. - * @param p Pointer to the particle data. - */ -__attribute__((always_inline)) INLINE static float cooling_timestep( - const struct cooling_function_data* restrict cooling, - const struct phys_const* restrict phys_const, - const struct cosmology* restrict cosmo, - const struct unit_system* restrict us, - const struct hydro_props* hydro_props, const struct part* restrict p, - const struct xpart* restrict xp) { - - return FLT_MAX; -} - -/** - * @brief Initialises the cooling unit system. - * - * @param us The current internal system of units. - * @param cooling The cooling properties to initialize - */ -__attribute__((always_inline)) INLINE static void cooling_init_units( - const struct unit_system* us, struct cooling_function_data* cooling) { - - /* These are conversions from code units to cgs. */ - - /* first cosmo */ - cooling->units.a_units = 1.0; // units for the expansion factor - cooling->units.a_value = 1.0; - - /* We assume here all physical quantities to - be in proper coordinate (not comobile) */ - cooling->units.comoving_coordinates = 0; - - /* then units */ - cooling->units.density_units = - units_cgs_conversion_factor(us, UNIT_CONV_DENSITY); - cooling->units.length_units = - units_cgs_conversion_factor(us, UNIT_CONV_LENGTH); - cooling->units.time_units = units_cgs_conversion_factor(us, UNIT_CONV_TIME); - cooling->units.velocity_units = - units_cgs_conversion_factor(us, UNIT_CONV_VELOCITY); -} - -/** - * @brief Initialises Grackle. - * - * @param cooling The cooling properties to initialize - */ -__attribute__((always_inline)) INLINE static void cooling_init_grackle( - struct cooling_function_data* cooling) { - -#ifdef SWIFT_DEBUG_CHECKS - /* enable verbose for grackle */ - grackle_verbose = 1; -#endif - - chemistry_data* chemistry = &cooling->chemistry; - - /* Create a chemistry object for parameters and rate data. */ - if (set_default_chemistry_parameters(chemistry) == 0) { - error("Error in set_default_chemistry_parameters."); - } - - // Set parameter values for chemistry. - chemistry->use_grackle = 1; - chemistry->with_radiative_cooling = 1; - - /* molecular network with H, He, D - From Cloudy table */ - chemistry->primordial_chemistry = COOLING_GRACKLE_MODE; - chemistry->metal_cooling = cooling->with_metal_cooling; - chemistry->UVbackground = cooling->with_uv_background; - chemistry->grackle_data_file = cooling->cloudy_table; - - /* radiative transfer */ - chemistry->use_radiative_transfer = cooling->provide_specific_heating_rates || - cooling->provide_volumetric_heating_rates; - chemistry->use_volumetric_heating_rate = - cooling->provide_volumetric_heating_rates; - chemistry->use_specific_heating_rate = - cooling->provide_specific_heating_rates; - - if (cooling->provide_specific_heating_rates && - cooling->provide_volumetric_heating_rates) - message( - "WARNING: You should specified either the specific or the volumetric " - "heating rates, not both"); - - /* self shielding */ - chemistry->self_shielding_method = cooling->self_shielding_method; - - /* Initialize the chemistry object. */ - if (initialize_chemistry_data(&cooling->units) == 0) { - error("Error in initialize_chemistry_data."); - } -} - -/** - * @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 hydro_props The properties of the hydro scheme. - * @param cooling The cooling properties to initialize - */ -__attribute__((always_inline)) INLINE static void cooling_init_backend( - struct swift_params* parameter_file, const struct unit_system* us, - const struct phys_const* phys_const, const struct hydro_props* hydro_props, - struct cooling_function_data* cooling) { - - if (GRACKLE_NPART != 1) - error("Grackle with multiple particles not implemented"); - - /* read parameters */ - cooling_read_parameters(parameter_file, cooling); - - /* Set up the units system. */ - cooling_init_units(us, cooling); - - /* Set up grackle */ - cooling_init_grackle(cooling); -} - -/** - * @brief Clean-up the memory allocated for the cooling routines - * - * @param cooling the cooling data structure. - */ -static INLINE void cooling_clean(struct cooling_function_data* cooling) { - - // MATTHIEU: To do: free stuff here -} - -/** - * @brief Write a cooling struct to the given FILE as a stream of bytes. - * - * Nothing to do beyond writing the structure from the stream. - * - * @param cooling the struct - * @param stream the file stream - */ -static INLINE void cooling_struct_dump( - const struct cooling_function_data* cooling, FILE* stream) { - restart_write_blocks((void*)cooling, sizeof(struct cooling_function_data), 1, - stream, "cooling", "cooling function"); -} - -/** - * @brief Restore a hydro_props struct from the given FILE as a stream of - * bytes. - * - * Nothing to do beyond reading the structure from the stream. - * - * @param cooling the struct - * @param stream the file stream - * @param cosmo #cosmology structure - */ -static INLINE void cooling_struct_restore(struct cooling_function_data* cooling, - FILE* stream, - const struct cosmology* cosmo) { - restart_read_blocks((void*)cooling, sizeof(struct cooling_function_data), 1, - stream, NULL, "cooling function"); - - /* Set up grackle */ - cooling_init_grackle(cooling); -} - + const struct part* restrict p, const struct xpart* restrict xp); +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_properties, + const struct part* restrict p, + const struct xpart* restrict xp); + +void cooling_split_part(struct part* p, struct xpart* xp, double n); + +void cooling_init_units(const struct unit_system* us, + const struct phys_const* phys_const, + struct cooling_function_data* cooling); +void cooling_init_grackle(struct cooling_function_data* cooling); + +void cooling_init_backend(struct swift_params* parameter_file, + const struct unit_system* us, + const struct phys_const* phys_const, + const struct hydro_props* hydro_props, + struct cooling_function_data* cooling); + +void cooling_clean(struct cooling_function_data* cooling); +void cooling_struct_dump(const struct cooling_function_data* cooling, + FILE* stream); +void cooling_struct_restore(struct cooling_function_data* cooling, FILE* stream, + const struct cosmology* cosmo); #endif /* SWIFT_COOLING_GRACKLE_H */ diff --git a/src/cooling/grackle/cooling_io.h b/src/cooling/grackle/cooling_io.h index 18712f4cf6c74253bfed3bd36f1a4484b9e50943..613f50786891a237c04011114fff41696530f242 100644 --- a/src/cooling/grackle/cooling_io.h +++ b/src/cooling/grackle/cooling_io.h @@ -136,34 +136,58 @@ __attribute__((always_inline)) INLINE static int cooling_write_particles( * @param cooling The cooling properties to initialize */ __attribute__((always_inline)) INLINE static void cooling_read_parameters( - struct swift_params* parameter_file, - struct cooling_function_data* cooling) { + struct swift_params* parameter_file, struct cooling_function_data* cooling, + const struct phys_const* phys_const) { - parser_get_param_string(parameter_file, "GrackleCooling:CloudyTable", + parser_get_param_string(parameter_file, "GrackleCooling:cloudy_table", cooling->cloudy_table); + + cooling->primordial_chemistry = parser_get_opt_param_int( + parameter_file, "GrackleCooling:primordial_chemistry", + COOLING_GRACKLE_MODE); + + if (cooling->primordial_chemistry < 0) + error("Primordial chemistry cannot be below 0"); + + if (cooling->primordial_chemistry > COOLING_GRACKLE_MODE) + error("Cannot run primordial chemistry %i when compiled with %i", + cooling->primordial_chemistry, COOLING_GRACKLE_MODE); + cooling->with_uv_background = - parser_get_param_int(parameter_file, "GrackleCooling:WithUVbackground"); + parser_get_param_int(parameter_file, "GrackleCooling:with_UV_background"); cooling->redshift = - parser_get_param_double(parameter_file, "GrackleCooling:Redshift"); + parser_get_param_double(parameter_file, "GrackleCooling:redshift"); cooling->with_metal_cooling = - parser_get_param_int(parameter_file, "GrackleCooling:WithMetalCooling"); + parser_get_param_int(parameter_file, "GrackleCooling:with_metal_cooling"); cooling->provide_volumetric_heating_rates = parser_get_opt_param_int( - parameter_file, "GrackleCooling:ProvideVolumetricHeatingRates", 0); + parameter_file, "GrackleCooling:provide_volumetric_heating_rates", 0); cooling->provide_specific_heating_rates = parser_get_opt_param_int( - parameter_file, "GrackleCooling:ProvideSpecificHeatingRates", 0); + parameter_file, "GrackleCooling:provide_specific_heating_rates", 0); + /* Self shielding */ cooling->self_shielding_method = parser_get_opt_param_int( - parameter_file, "GrackleCooling:SelfShieldingMethod", 0); + parameter_file, "GrackleCooling:self_shielding_method", 0); + + if (cooling->self_shielding_method == -1) { + cooling->self_shielding_threshold = parser_get_param_float( + parameter_file, "GrackleCooling:self_shielding_threshold_atom_per_cm3"); + } + /* Initial step convergence */ cooling->max_step = parser_get_opt_param_int( - parameter_file, "GrackleCooling:MaxSteps", 10000); + parameter_file, "GrackleCooling:max_steps", 10000); cooling->convergence_limit = parser_get_opt_param_double( - parameter_file, "GrackleCooling:ConvergenceLimit", 1e-2); + parameter_file, "GrackleCooling:convergence_limit", 1e-2); + + /* Thermal time */ + cooling->thermal_time = + parser_get_param_float(parameter_file, "GrackleCooling:thermal_time_myr"); + cooling->thermal_time *= phys_const->const_year * 1e6; } #endif /* SWIFT_COOLING_GRACKLE_IO_H */ diff --git a/src/cooling/grackle/cooling_struct.h b/src/cooling/grackle/cooling_struct.h index 66c385234cccf6532100e86f2c16a508b1112baa..fb1e7452420b5a1affd8d420bcffba7adf907a83 100644 --- a/src/cooling/grackle/cooling_struct.h +++ b/src/cooling/grackle/cooling_struct.h @@ -32,41 +32,51 @@ */ struct cooling_function_data { - /* Filename of the Cloudy Table */ + /*! Filename of the Cloudy Table */ char cloudy_table[200]; - /* Enable/Disable UV backgroud */ + /*! Enable/Disable UV backgroud */ int with_uv_background; - /* Redshift to use for the UV backgroud (-1 to use cosmological one) */ + /*! Chemistry network */ + int primordial_chemistry; + + /*! Redshift to use for the UV backgroud (-1 to use cosmological one) */ double redshift; - /* unit system */ + /*! unit system */ code_units units; - /* grackle chemistry data */ + /*! grackle chemistry data */ chemistry_data chemistry; - /* Enable/Disable metal cooling */ + /*! Enable/Disable metal cooling */ int with_metal_cooling; - /* User provide volumetric heating rates */ + /*! User provide volumetric heating rates */ int provide_volumetric_heating_rates; - /* User provide specific heating rates */ + /*! User provide specific heating rates */ int provide_specific_heating_rates; - /* Self shielding method (<= 3) means grackle modes */ + /*! Self shielding method (1 -> 3 for grackle's ones, 0 for none and -1 for + * GEAR) */ int self_shielding_method; - /* convergence limit for first init */ + /*! Self shielding threshold */ + float self_shielding_threshold; + + /*! convergence limit for first init */ float convergence_limit; - /* number of step max for first init */ + /*! number of step max for first init */ int max_step; - /* over relaxation parameter */ + /*! over relaxation parameter */ float omega; + + /*! Duration for switching off cooling after an event (e.g. supernovae) */ + float thermal_time; }; /** @@ -77,6 +87,9 @@ struct cooling_xpart_data { /*! Energy radiated away by this particle since the start of the run */ float radiated_energy; + /*! Last time the cooling was switch off */ + float time_last_event; + /* here all fractions are mass fraction */ #if COOLING_GRACKLE_MODE >= 1 /* primordial chemistry >= 1 */ diff --git a/src/cooling/none/cooling.h b/src/cooling/none/cooling.h index 5630914dea5a3ce205c14ba1fb7a353d784df37f..107ea4b88a24d2505b8cceb346672f855df7b9da 100644 --- a/src/cooling/none/cooling.h +++ b/src/cooling/none/cooling.h @@ -63,6 +63,7 @@ INLINE static void cooling_update(const struct cosmology* cosmo, * @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 time The current time. * @param dt The time-step of this particle. * @param dt_therm The time-step operator used for thermal quantities. */ @@ -73,8 +74,8 @@ __attribute__((always_inline)) INLINE static void cooling_cool_part( const struct hydro_props* hydro_props, const struct entropy_floor_properties* floor_props, const struct cooling_function_data* restrict cooling, - struct part* restrict p, struct xpart* restrict xp, const float dt, - const float dt_therm) {} + struct part* restrict p, struct xpart* restrict xp, const double time, + const float dt, const float dt_therm) {} /** * @brief Computes the cooling time-step. @@ -108,6 +109,7 @@ __attribute__((always_inline)) INLINE static float cooling_timestep( * * @param phys_const The physical constant in internal units. * @param us The unit system. + * @param hydro_props The properties of the hydro scheme. * @param cosmo The current cosmological model. * @param data The properties of the cooling function. * @param p Pointer to the particle data. @@ -116,6 +118,7 @@ __attribute__((always_inline)) INLINE static float cooling_timestep( __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 hydro_props* hydro_props, const struct cosmology* restrict cosmo, const struct cooling_function_data* data, const struct part* restrict p, struct xpart* restrict xp) {} @@ -176,6 +179,18 @@ __attribute__((always_inline)) INLINE static float cooling_get_radiated_energy( return 0.f; } +/** + * @brief Split the coolong content of a particle into n pieces + * + * Nothing to do here. + * + * @param p The #part. + * @param xp The #xpart. + * @param n The number of pieces to split into. + */ +static INLINE void cooling_split_part(struct part* p, struct xpart* xp, + double n) {} + /** * @brief Initialises the cooling properties. * diff --git a/src/cosmology.c b/src/cosmology.c index 3c8954d352df03ba1e7796e84e3bd328af022899..4c72bb4ed13bdf412d531f16f1be8c4967810a03 100644 --- a/src/cosmology.c +++ b/src/cosmology.c @@ -30,13 +30,16 @@ /* Local headers */ #include "adiabatic_index.h" +#include "align.h" #include "common_io.h" #include "inline.h" #include "memuse.h" +#include "minmax.h" #include "restart.h" #ifdef HAVE_LIBGSL #include <gsl/gsl_integration.h> +#include <gsl/gsl_interp.h> #endif /*! Number of values stored in the cosmological interpolation tables */ @@ -58,12 +61,17 @@ const size_t GSL_workspace_size = 100000; * @brief x_min The mininum of the range of x. * @brief x_max The maximum of the range of x. */ -static INLINE double interp_table(double *table, double x, double x_min, - double x_max) { +static INLINE double interp_table(const double *table, const double x, + const double x_min, const double x_max) { + + const double xx = + ((x - x_min) / (x_max - x_min)) * ((double)cosmology_table_length); - const double xx = ((x - x_min) / (x_max - x_min)) * cosmology_table_length; const int i = (int)xx; - const int ii = (i >= cosmology_table_length) ? cosmology_table_length - 1 : i; + const int ii = min(cosmology_table_length - 1, i); + + /* Indicate that the whole array is aligned on boundaries */ + swift_align_information(double, table, SWIFT_STRUCT_ALIGNMENT); if (ii <= 1) return table[0] * xx; @@ -80,8 +88,8 @@ static INLINE double interp_table(double *table, double x, double x_min, * @param w_0 The equation of state parameter at z=0 * @param w_a The equation of state evolution parameter */ -static INLINE double cosmology_dark_energy_EoS(double a, double w_0, - double w_a) { +__attribute__((const)) static INLINE double cosmology_dark_energy_EoS( + const double a, const double w_0, const double w_a) { return w_0 + w_a * (1. - a); } @@ -94,21 +102,37 @@ static INLINE double cosmology_dark_energy_EoS(double a, double w_0, * and compute \f$ \tilde{w}(a) = \int_0^a\frac{1 + w(z)}{1+z}dz \f$. * * @param a The current scale-factor. - * @param w0 The equation of state parameter at z=0 - * @param wa The equation of state evolution parameter + * @param w0 The equation of state parameter at z=0. + * @param wa The equation of state evolution parameter. */ -static INLINE double w_tilde(double a, double w0, double wa) { +__attribute__((const)) static INLINE double w_tilde(const double a, + const double w0, + const double wa) { return (a - 1.) * wa - (1. + w0 + wa) * log(a); } /** * @brief Compute \f$ E(z) \f$. + * + * @param Omega_r The radiation density parameter \f$ \Omega_r \f$. + * @param Omega_m The matter density parameter \f$ \Omega_m \f$. + * @param Omega_k The curvature density parameter \f$ \Omega_k \f$. + * @param Omega_l The cosmological constant density parameter \f$ \Omega_\Lambda + * \f$. + * @param w0 The equation of state parameter at z=0. + * @param wa The equation of state evolution parameter. + * @param a The current scale-factor. */ -static INLINE double E(double Or, double Om, double Ok, double Ol, double w0, - double wa, double a) { +__attribute__((const)) static INLINE double E( + const double Omega_r, const double Omega_m, const double Omega_k, + const double Omega_l, const double w0, const double wa, const double a) { + const double a_inv = 1. / a; - return sqrt(Or * a_inv * a_inv * a_inv * a_inv + Om * a_inv * a_inv * a_inv + - Ok * a_inv * a_inv + Ol * exp(3. * w_tilde(a, w0, wa))); + + return sqrt(Omega_r * a_inv * a_inv * a_inv * a_inv + /* Radiation */ + Omega_m * a_inv * a_inv * a_inv + /* Matter */ + Omega_k * a_inv * a_inv + /* Curvature */ + Omega_l * exp(3. * w_tilde(a, w0, wa))); /* Lambda */ } /** @@ -336,18 +360,30 @@ void cosmology_init_tables(struct cosmology *c) { const double a_begin = c->a_begin; /* Allocate memory for the interpolation tables */ - c->drift_fac_interp_table = (double *)swift_malloc( - "cosmo.table", cosmology_table_length * sizeof(double)); - c->grav_kick_fac_interp_table = (double *)swift_malloc( - "cosmo.table", cosmology_table_length * sizeof(double)); - c->hydro_kick_fac_interp_table = (double *)swift_malloc( - "cosmo.table", cosmology_table_length * sizeof(double)); - c->hydro_kick_corr_interp_table = (double *)swift_malloc( - "cosmo.table", cosmology_table_length * sizeof(double)); - c->time_interp_table = (double *)swift_malloc( - "cosmo.table", cosmology_table_length * sizeof(double)); - c->scale_factor_interp_table = (double *)swift_malloc( - "cosmo.table", cosmology_table_length * sizeof(double)); + if (swift_memalign("cosmo.table", (void **)&c->drift_fac_interp_table, + SWIFT_STRUCT_ALIGNMENT, + cosmology_table_length * sizeof(double)) != 0) + error("Failed to allocate cosmology interpolation table"); + if (swift_memalign("cosmo.table", (void **)&c->grav_kick_fac_interp_table, + SWIFT_STRUCT_ALIGNMENT, + cosmology_table_length * sizeof(double)) != 0) + error("Failed to allocate cosmology interpolation table"); + if (swift_memalign("cosmo.table", (void **)&c->hydro_kick_fac_interp_table, + SWIFT_STRUCT_ALIGNMENT, + cosmology_table_length * sizeof(double)) != 0) + error("Failed to allocate cosmology interpolation table"); + if (swift_memalign("cosmo.table", (void **)&c->hydro_kick_corr_interp_table, + SWIFT_STRUCT_ALIGNMENT, + cosmology_table_length * sizeof(double)) != 0) + error("Failed to allocate cosmology interpolation table"); + if (swift_memalign("cosmo.table", (void **)&c->time_interp_table, + SWIFT_STRUCT_ALIGNMENT, + cosmology_table_length * sizeof(double)) != 0) + error("Failed to allocate cosmology interpolation table"); + if (swift_memalign("cosmo.table", (void **)&c->scale_factor_interp_table, + SWIFT_STRUCT_ALIGNMENT, + cosmology_table_length * sizeof(double)) != 0) + error("Failed to allocate cosmology interpolation table"); /* Prepare a table of scale factors for the integral bounds */ const double delta_a = @@ -498,6 +534,7 @@ void cosmology_init(struct swift_params *params, const struct unit_system *us, c->a_end = parser_get_param_double(params, "Cosmology:a_end"); c->log_a_begin = log(c->a_begin); c->log_a_end = log(c->a_end); + c->time_base = (c->log_a_end - c->log_a_begin) / max_nr_timesteps; c->time_base_inv = 1. / c->time_base; @@ -623,8 +660,8 @@ void cosmology_init_no_cosmo(struct cosmology *c) { * @param ti_end the (integer) time of the end of the drift. */ double cosmology_get_drift_factor(const struct cosmology *c, - integertime_t ti_start, - integertime_t ti_end) { + const integertime_t ti_start, + const integertime_t ti_end) { #ifdef SWIFT_DEBUG_CHECKS if (ti_end < ti_start) error("ti_end must be >= ti_start"); @@ -651,8 +688,8 @@ double cosmology_get_drift_factor(const struct cosmology *c, * @param ti_end the (integer) time of the end of the drift. */ double cosmology_get_grav_kick_factor(const struct cosmology *c, - integertime_t ti_start, - integertime_t ti_end) { + const integertime_t ti_start, + const integertime_t ti_end) { #ifdef SWIFT_DEBUG_CHECKS if (ti_end < ti_start) error("ti_end must be >= ti_start"); @@ -680,8 +717,8 @@ double cosmology_get_grav_kick_factor(const struct cosmology *c, * @param ti_end the (integer) time of the end of the drift. */ double cosmology_get_hydro_kick_factor(const struct cosmology *c, - integertime_t ti_start, - integertime_t ti_end) { + const integertime_t ti_start, + const integertime_t ti_end) { #ifdef SWIFT_DEBUG_CHECKS if (ti_end < ti_start) error("ti_end must be >= ti_start"); @@ -709,8 +746,8 @@ double cosmology_get_hydro_kick_factor(const struct cosmology *c, * @param ti_end the (integer) time of the end of the drift. */ double cosmology_get_corr_kick_factor(const struct cosmology *c, - integertime_t ti_start, - integertime_t ti_end) { + const integertime_t ti_start, + const integertime_t ti_end) { #ifdef SWIFT_DEBUG_CHECKS if (ti_end < ti_start) error("ti_end must be >= ti_start"); @@ -738,8 +775,8 @@ double cosmology_get_corr_kick_factor(const struct cosmology *c, * @param ti_end the (integer) time of the end of the drift. */ double cosmology_get_therm_kick_factor(const struct cosmology *c, - integertime_t ti_start, - integertime_t ti_end) { + const integertime_t ti_start, + const integertime_t ti_end) { #ifdef SWIFT_DEBUG_CHECKS if (ti_end < ti_start) error("ti_end must be >= ti_start"); @@ -765,7 +802,8 @@ double cosmology_get_therm_kick_factor(const struct cosmology *c, * @param ti_end the (integer) time of the end. */ double cosmology_get_delta_time(const struct cosmology *c, - integertime_t ti_start, integertime_t ti_end) { + const integertime_t ti_start, + const integertime_t ti_end) { #ifdef SWIFT_DEBUG_CHECKS if (ti_end < ti_start) error("ti_end must be >= ti_start"); @@ -798,6 +836,7 @@ double cosmology_get_delta_time_from_scale_factors(const struct cosmology *c, #ifdef SWIFT_DEBUG_CHECKS if (a_end < a_start) error("a_end must be >= a_start"); + if (a_end < c->a_begin) error("Error a_end can't be smaller than a_begin"); #endif const double log_a_start = log(a_start); diff --git a/src/cosmology.h b/src/cosmology.h index a4fec80004bcac9ebc69f2e2c2202afa73838674..bb75335b8f72ea8dd35ebd66ea9d9340e58b1e4a 100644 --- a/src/cosmology.h +++ b/src/cosmology.h @@ -192,21 +192,23 @@ void cosmology_update(struct cosmology *c, const struct phys_const *phys_const, integertime_t ti_current); double cosmology_get_drift_factor(const struct cosmology *cosmo, - integertime_t ti_start, integertime_t ti_end); + const integertime_t ti_start, + const integertime_t ti_end); double cosmology_get_grav_kick_factor(const struct cosmology *cosmo, - integertime_t ti_start, - integertime_t ti_end); + const integertime_t ti_start, + const integertime_t ti_end); double cosmology_get_hydro_kick_factor(const struct cosmology *cosmo, - integertime_t ti_start, - integertime_t ti_end); + const integertime_t ti_start, + const integertime_t ti_end); double cosmology_get_therm_kick_factor(const struct cosmology *cosmo, - integertime_t ti_start, - integertime_t ti_end); + const integertime_t ti_start, + const integertime_t ti_end); double cosmology_get_corr_kick_factor(const struct cosmology *cosmo, - integertime_t ti_start, - integertime_t ti_end); + const integertime_t ti_start, + const integertime_t ti_end); double cosmology_get_delta_time(const struct cosmology *c, - integertime_t ti_start, integertime_t ti_end); + const integertime_t ti_start, + const integertime_t ti_end); double cosmology_get_delta_time_from_scale_factors(const struct cosmology *c, const double a_start, diff --git a/src/debug.c b/src/debug.c index 8e3c581163bb404b8013790ef32549503c93fa38..fba8db46661e9624f9332c74d0d76c435cb9a6d2 100644 --- a/src/debug.c +++ b/src/debug.c @@ -52,16 +52,14 @@ #include "./hydro/PressureEnergyMorrisMonaghanAV/hydro_debug.h" #elif defined(DEFAULT_SPH) #include "./hydro/Default/hydro_debug.h" -#elif defined(GIZMO_MFV_SPH) -#include "./hydro/GizmoMFV/hydro_debug.h" -#elif defined(GIZMO_MFM_SPH) -#include "./hydro/GizmoMFM/hydro_debug.h" +#elif defined(GIZMO_MFV_SPH) || defined(GIZMO_MFM_SPH) +#include "./hydro/Gizmo/hydro_debug.h" #elif defined(SHADOWFAX_SPH) #include "./hydro/Shadowswift/hydro_debug.h" #elif defined(PLANETARY_SPH) #include "./hydro/Planetary/hydro_debug.h" -#elif defined(ANARCHY_DU_SPH) -#include "./hydro/AnarchyDU/hydro_debug.h" +#elif defined(SPHENIX_SPH) +#include "./hydro/SPHENIX/hydro_debug.h" #elif defined(ANARCHY_PU_SPH) #include "./hydro/AnarchyPU/hydro_debug.h" #else diff --git a/src/dump.c b/src/dump.c index 9c519c2130b2612309e623b8234e3369214b52e2..37b570e68bfcc9685491d45d50254d75d8ab8744 100644 --- a/src/dump.c +++ b/src/dump.c @@ -158,4 +158,27 @@ void dump_init(struct dump *d, const char *filename, size_t size) { d->page_mask = page_mask; } +/** + * @brief Restart a file dump. + * + * @param d The #dump to restart. + * @param filename The fully qualified name of the file in which to dump, + * note that it will be overwritten. + */ +void dump_restart(struct dump *d, const char *filename) { + /* Create the output file. + The option O_RDWR seems to be required by mmap. + */ + if ((d->fd = open(filename, O_RDWR, 0660)) == -1) { + error("Failed to open dump file '%s' (%s).", filename, strerror(errno)); + } + + /* Map memory to the created file. */ + if ((d->data = mmap(NULL, d->size, PROT_WRITE, MAP_SHARED, d->fd, + d->file_offset)) == MAP_FAILED) { + error("Failed to allocate map of size %zi bytes (%s).", d->size, + strerror(errno)); + } +} + #endif diff --git a/src/dump.h b/src/dump.h index 021bc1e1dc22c178a893e42384c91fafdcf63112..e92684c6f7c60e414365b06278c9afedc8e74c50 100644 --- a/src/dump.h +++ b/src/dump.h @@ -51,6 +51,7 @@ struct dump { /* Function prototypes. */ void dump_init(struct dump *d, const char *filename, size_t size); +void dump_restart(struct dump *d, const char *filename); 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); diff --git a/src/engine.c b/src/engine.c index 9c0b90cc37ad041873ffc858f9fd4ffeb1f91740..fc83a3f21c1958e5fc78885e856990576be12bf7 100644 --- a/src/engine.c +++ b/src/engine.c @@ -33,8 +33,8 @@ #include <stdio.h> #include <stdlib.h> #include <string.h> -#include <sys/types.h> #include <sys/stat.h> +#include <sys/types.h> #include <unistd.h> @@ -54,6 +54,7 @@ /* Local headers. */ #include "active.h" #include "atomic.h" +#include "black_holes_properties.h" #include "cell.h" #include "chemistry.h" #include "clocks.h" @@ -86,7 +87,6 @@ #include "sort_part.h" #include "star_formation.h" #include "star_formation_logger.h" -#include "star_formation_logger_struct.h" #include "stars_io.h" #include "statistics.h" #include "timers.h" @@ -120,7 +120,8 @@ const char *engine_policy_names[] = {"none", "feedback", "black holes", "fof search", - "time-step limiter"}; + "time-step limiter", + "time-step sync"}; /** The rank of the engine as a global variable (for messages). */ int engine_rank; @@ -597,7 +598,6 @@ void engine_exchange_strays(struct engine *e, const size_t offset_parts, /* Reallocate the particle arrays if necessary */ if (offset_parts + count_parts_in > s->size_parts) { - message("re-allocating parts array."); s->size_parts = (offset_parts + count_parts_in) * engine_parts_size_grow; struct part *parts_new = NULL; struct xpart *xparts_new = NULL; @@ -622,7 +622,6 @@ void engine_exchange_strays(struct engine *e, const size_t offset_parts, } if (offset_sparts + count_sparts_in > s->size_sparts) { - message("re-allocating sparts array."); s->size_sparts = (offset_sparts + count_sparts_in) * engine_parts_size_grow; struct spart *sparts_new = NULL; if (swift_memalign("sparts", (void **)&sparts_new, spart_align, @@ -641,7 +640,6 @@ void engine_exchange_strays(struct engine *e, const size_t offset_parts, } if (offset_bparts + count_bparts_in > s->size_bparts) { - message("re-allocating bparts array."); s->size_bparts = (offset_bparts + count_bparts_in) * engine_parts_size_grow; struct bpart *bparts_new = NULL; if (swift_memalign("bparts", (void **)&bparts_new, bpart_align, @@ -660,7 +658,6 @@ void engine_exchange_strays(struct engine *e, const size_t offset_parts, } if (offset_gparts + count_gparts_in > s->size_gparts) { - message("re-allocating gparts array."); s->size_gparts = (offset_gparts + count_gparts_in) * engine_parts_size_grow; struct gpart *gparts_new = NULL; if (swift_memalign("gparts", (void **)&gparts_new, gpart_align, @@ -1356,7 +1353,7 @@ int engine_estimate_nr_tasks(const struct engine *e) { #endif #endif } - if (e->policy & engine_policy_limiter) { + if (e->policy & engine_policy_timestep_limiter) { n1 += 18; n2 += 1; } @@ -1633,6 +1630,17 @@ void engine_prepare(struct engine *e) { engine_fof(e, /*dump_results=*/0, /*seed_black_holes=*/1); } + /* Perform particle splitting. Only if there is a rebuild coming and no + repartitioning. */ + if (e->forcerebuild && !e->forcerepart && e->step > 1) { + + /* Let's start by drifting everybody to the current time */ + if (!drifted_all) engine_drift_all(e, /*drift_mpole=*/0); + drifted_all = 1; + + engine_split_gas_particles(e); + } + /* Do we need repartitioning ? */ if (e->forcerepart) { @@ -1781,6 +1789,7 @@ void engine_skip_force_and_kick(struct engine *e) { t->type == task_type_kick1 || t->type == task_type_kick2 || t->type == task_type_timestep || t->type == task_type_timestep_limiter || + t->type == task_type_timestep_sync || t->subtype == task_subtype_force || t->subtype == task_subtype_limiter || t->subtype == task_subtype_grav || t->type == task_type_end_hydro_force || @@ -1835,7 +1844,7 @@ void engine_skip_drift(struct engine *e) { /* Skip everything that moves the particles */ if (t->type == task_type_drift_part || t->type == task_type_drift_gpart || - t->type == task_type_drift_spart) + t->type == task_type_drift_spart || t->type == task_type_drift_bpart) t->skip = 1; } @@ -1847,8 +1856,9 @@ void engine_skip_drift(struct engine *e) { * @brief Launch the runners. * * @param e The #engine. + * @param call What kind of tasks are we running? (For time analysis) */ -void engine_launch(struct engine *e) { +void engine_launch(struct engine *e, const char *call) { const ticks tic = getticks(); #ifdef SWIFT_DEBUG_CHECKS @@ -1875,7 +1885,7 @@ void engine_launch(struct engine *e) { swift_barrier_wait(&e->wait_barrier); if (e->verbose) - message("took %.3f %s.", clocks_from_ticks(getticks() - tic), + message("(%s) took %.3f %s.", call, clocks_from_ticks(getticks() - tic), clocks_getunit()); } @@ -1957,12 +1967,13 @@ void engine_init_particles(struct engine *e, int flag_entropy_ICs, &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); + logger_ensure_size(e->logger, s->nr_parts, s->nr_gparts, s->nr_sparts); + logger_write_description(e->logger, e); #endif /* Now, launch the calculation */ TIMER_TIC; - engine_launch(e); + engine_launch(e, "tasks"); TIMER_TOC(timer_runners); /* Apply some conversions (e.g. internal energy -> entropy) */ @@ -1976,7 +1987,7 @@ void engine_init_particles(struct engine *e, int flag_entropy_ICs, if (hydro_need_extra_init_loop) { engine_marktasks(e); engine_skip_force_and_kick(e); - engine_launch(e); + engine_launch(e, "tasks"); } } @@ -2024,9 +2035,19 @@ void engine_init_particles(struct engine *e, int flag_entropy_ICs, /* Run the 0th time-step */ TIMER_TIC2; - engine_launch(e); + engine_launch(e, "tasks"); TIMER_TOC2(timer_runners); + /* Since the time-steps may have changed because of the limiter's + * action, we need to communicate the new time-step sizes */ + if ((e->policy & engine_policy_timestep_sync) || + (e->policy & engine_policy_timestep_limiter)) { +#ifdef WITH_MPI + engine_unskip_timestep_communications(e); + engine_launch(e, "timesteps"); +#endif + } + #ifdef SWIFT_GRAVITY_FORCE_CHECKS /* Check the accuracy of the gravity calculation */ if (e->policy & engine_policy_self_gravity) @@ -2170,8 +2191,8 @@ void engine_step(struct engine *e) { /* Print some information to the screen */ printf( - " %6d %14e %12.7f %12.7f %14e %4d %4d %12lld %12lld %12lld %12lld " - "%21.3f %6d\n", + " %6d %14e %12.7f %12.7f %14e %4d %4d %12lld %12lld %12lld " + "%12lld %21.3f %6d\n", e->step, e->time, e->cosmology->a, e->cosmology->z, e->time_step, e->min_active_bin, e->max_active_bin, e->updates, e->g_updates, e->s_updates, e->b_updates, e->wallclock_time, e->step_props); @@ -2185,7 +2206,11 @@ void engine_step(struct engine *e) { e->cosmology->a, e->cosmology->z, e->sfh, e->step); +#ifdef SWIFT_DEBUG_CHECKS fflush(e->sfh_logger); +#else + if (e->step % 32 == 0) fflush(e->sfh_logger); +#endif } if (!e->restarting) @@ -2265,7 +2290,8 @@ void engine_step(struct engine *e) { &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); + logger_ensure_size(e->logger, e->s->nr_parts, e->s->nr_gparts, + e->s->nr_sparts); #endif /* Are we drifting everything (a la Gadget/GIZMO) ? */ @@ -2317,9 +2343,19 @@ void engine_step(struct engine *e) { /* Start all the tasks. */ TIMER_TIC; - engine_launch(e); + engine_launch(e, "tasks"); TIMER_TOC(timer_runners); + /* Since the time-steps may have changed because of the limiter's + * action, we need to communicate the new time-step sizes */ + if ((e->policy & engine_policy_timestep_sync) || + (e->policy & engine_policy_timestep_limiter)) { +#ifdef WITH_MPI + engine_unskip_timestep_communications(e); + engine_launch(e, "timesteps"); +#endif + } + #ifdef SWIFT_GRAVITY_FORCE_CHECKS /* Check the accuracy of the gravity calculation */ if (e->policy & engine_policy_self_gravity) @@ -2342,6 +2378,9 @@ void engine_step(struct engine *e) { e->b_updates_since_rebuild += e->collect_group1.b_updated; #ifdef SWIFT_DEBUG_CHECKS + /* Verify that all cells have correct time-step information */ + space_check_timesteps(e->s); + if (e->ti_end_min == e->ti_current && e->ti_end_min < max_nr_timesteps) error("Obtained a time-step of size 0"); #endif @@ -2354,6 +2393,9 @@ void engine_step(struct engine *e) { engine_dump_restarts(e, 0, e->restart_onexit && engine_is_done(e)); engine_check_for_dumps(e); +#ifdef WITH_LOGGER + engine_check_for_index_dump(e); +#endif TIMER_TOC2(timer_step); @@ -2383,7 +2425,7 @@ void engine_check_for_dumps(struct engine *e) { output_none, output_snapshot, output_statistics, - output_stf + output_stf, }; /* What kind of output do we want? And at which time ? @@ -2391,6 +2433,7 @@ void engine_check_for_dumps(struct engine *e) { * before the next time-step */ enum output_type type = output_none; integertime_t ti_output = max_nr_timesteps; + e->stf_this_timestep = 0; /* Save some statistics ? */ if (e->ti_end_min > e->ti_next_stats && e->ti_next_stats > 0) { @@ -2440,10 +2483,11 @@ void engine_check_for_dumps(struct engine *e) { /* Write some form of output */ switch (type) { + case output_snapshot: /* Do we want a corresponding VELOCIraptor output? */ - if (with_stf && e->snapshot_invoke_stf) { + if (with_stf && e->snapshot_invoke_stf && !e->stf_this_timestep) { #ifdef HAVE_VELOCIRAPTOR velociraptor_invoke(e, /*linked_with_snap=*/1); @@ -2455,16 +2499,11 @@ void engine_check_for_dumps(struct engine *e) { #endif } - /* Dump... */ -#ifdef WITH_LOGGER - /* Write a file containing the offsets in the particle logger. */ - engine_dump_index(e); -#else + /* Dump... */ engine_dump_snapshot(e); -#endif /* Free the memory allocated for VELOCIraptor i/o. */ - if (with_stf && e->snapshot_invoke_stf) { + if (with_stf && e->snapshot_invoke_stf && e->s->gpart_group_data) { #ifdef HAVE_VELOCIRAPTOR swift_free("gpart_group_data", e->s->gpart_group_data); e->s->gpart_group_data = NULL; @@ -2489,8 +2528,10 @@ void engine_check_for_dumps(struct engine *e) { #ifdef HAVE_VELOCIRAPTOR /* Unleash the raptor! */ - velociraptor_invoke(e, /*linked_with_snap=*/0); - e->step_props |= engine_step_prop_stf; + if (!e->stf_this_timestep) { + velociraptor_invoke(e, /*linked_with_snap=*/0); + e->step_props |= engine_step_prop_stf; + } /* ... and find the next output time */ engine_compute_next_stf_time(e); @@ -2547,6 +2588,38 @@ void engine_check_for_dumps(struct engine *e) { e->time = time; } +/** + * @brief Check whether an index file has to be written during this + * step. + * + * @param e The #engine. + */ +void engine_check_for_index_dump(struct engine *e) { +#ifdef WITH_LOGGER + /* Get a few variables */ + struct logger_writer *log = e->logger; + const size_t dump_size = log->dump.count; + const size_t old_dump_size = log->index.dump_size_last_output; + const float mem_frac = log->index.mem_frac; + const size_t total_nr_parts = + (e->total_nr_parts + e->total_nr_gparts + e->total_nr_sparts + + e->total_nr_bparts + e->total_nr_DM_background_gparts); + const size_t index_file_size = + total_nr_parts * sizeof(struct logger_part_data); + + /* Check if we should write a file */ + if (mem_frac * (dump_size - old_dump_size) > index_file_size) { + /* Write an index file */ + engine_dump_index(e); + + /* Update the dump size for last output */ + log->index.dump_size_last_output = dump_size; + } +#else + error("This function should not be called without the logger."); +#endif +} + /** * @brief dump restart files if it is time to do so and dumps are enabled. * @@ -2579,6 +2652,13 @@ void engine_dump_restarts(struct engine *e, int drifted_all, int force) { if (!drifted_all) engine_drift_all(e, /*drift_mpole=*/1); restart_write(e, e->restart_file); +#ifdef WITH_MPI + /* Make sure all ranks finished writing to avoid having incomplete + * sets of restart files should the code crash before all the ranks + * are done */ + MPI_Barrier(MPI_COMM_WORLD); +#endif + if (e->verbose) message("Dumping restart files took %.3f %s", clocks_from_ticks(getticks() - tic), clocks_getunit()); @@ -3094,7 +3174,7 @@ void engine_collect_stars_counter(struct engine *e) { /* Reset counters */ for (size_t i = 0; i < e->s->nr_sparts_foreign; i++) { - e->s->sparts_foreign[i].num_ngb_force = 0; + e->s->sparts_foreign[i].num_ngb_feedback = 0; } /* Update counters */ @@ -3114,7 +3194,7 @@ void engine_collect_stars_counter(struct engine *e) { id_j, j, displs[engine_rank], n_sparts_int[engine_rank]); } - local_sparts[i].num_ngb_force += sparts[j].num_ngb_force; + local_sparts[i].num_ngb_feedback += sparts[j].num_ngb_feedback; } } } @@ -3167,21 +3247,41 @@ void engine_dump_snapshot(struct engine *e) { engine_collect_stars_counter(e); #endif + /* Determine snapshot location */ + char snapshotBase[FILENAME_BUFFER_SIZE]; + if (strnlen(e->snapshot_subdir, PARSER_MAX_LINE_SIZE) > 0) { + if (snprintf(snapshotBase, FILENAME_BUFFER_SIZE, "%s/%s", + e->snapshot_subdir, + e->snapshot_base_name) >= FILENAME_BUFFER_SIZE) { + error( + "FILENAME_BUFFER_SIZE is too small for snapshot path and file name"); + } + /* Try to ensure the directory exists */ +#ifdef WITH_MPI + if (engine_rank == 0) mkdir(e->snapshot_subdir, 0777); + MPI_Barrier(MPI_COMM_WORLD); +#else + mkdir(e->snapshot_subdir, 0777); +#endif + } else { + if (snprintf(snapshotBase, FILENAME_BUFFER_SIZE, "%s", + e->snapshot_base_name) >= FILENAME_BUFFER_SIZE) { + error("FILENAME_BUFFER_SIZE is too small for snapshot file name"); + } + } + /* Dump... */ #if defined(HAVE_HDF5) #if defined(WITH_MPI) #if defined(HAVE_PARALLEL_HDF5) - write_output_parallel(e, e->snapshot_base_name, e->internal_units, - e->snapshot_units, e->nodeID, e->nr_nodes, - MPI_COMM_WORLD, MPI_INFO_NULL); + write_output_parallel(e, snapshotBase, e->internal_units, e->snapshot_units, + e->nodeID, e->nr_nodes, MPI_COMM_WORLD, MPI_INFO_NULL); #else - write_output_serial(e, e->snapshot_base_name, e->internal_units, - e->snapshot_units, e->nodeID, e->nr_nodes, MPI_COMM_WORLD, - MPI_INFO_NULL); + write_output_serial(e, snapshotBase, e->internal_units, e->snapshot_units, + e->nodeID, e->nr_nodes, MPI_COMM_WORLD, MPI_INFO_NULL); #endif #else - write_output_single(e, e->snapshot_base_name, e->internal_units, - e->snapshot_units); + write_output_single(e, snapshotBase, e->internal_units, e->snapshot_units); #endif #endif @@ -3215,8 +3315,7 @@ void engine_dump_index(struct engine *e) { } /* Dump... */ - write_index_single(e, e->logger->base_name, e->internal_units, - e->snapshot_units); + logger_write_index_file(e->logger, e); /* Flag that we dumped a snapshot */ e->step_props |= engine_step_prop_logger_index; @@ -3390,7 +3489,7 @@ void engine_init(struct engine *e, struct space *s, struct swift_params *params, const struct entropy_floor_properties *entropy_floor, struct gravity_props *gravity, const struct stars_props *stars, const struct black_holes_props *black_holes, - const struct feedback_props *feedback, struct pm_mesh *mesh, + struct feedback_props *feedback, struct pm_mesh *mesh, const struct external_potential *potential, struct cooling_function_data *cooling_func, const struct star_formation *starform, @@ -3430,6 +3529,8 @@ void engine_init(struct engine *e, struct space *s, struct swift_params *params, parser_get_opt_param_double(params, "Snapshots:delta_time", -1.); e->ti_next_snapshot = 0; parser_get_param_string(params, "Snapshots:basename", e->snapshot_base_name); + parser_get_opt_param_string(params, "Snapshots:subdir", e->snapshot_subdir, + engine_default_snapshot_subdir); e->snapshot_compression = parser_get_opt_param_int(params, "Snapshots:compression", 0); e->snapshot_int_time_label_on = @@ -3471,6 +3572,7 @@ void engine_init(struct engine *e, struct space *s, struct swift_params *params, e->chemistry = chemistry; e->fof_properties = fof_properties; e->parameter_file = params; + e->stf_this_timestep = 0; #ifdef WITH_MPI e->cputime_last_step = 0; e->last_repartition = 0; @@ -3522,6 +3624,9 @@ void engine_init(struct engine *e, struct space *s, struct swift_params *params, if (e->policy & engine_policy_structure_finding) { parser_get_param_string(params, "StructureFinding:basename", e->stf_base_name); + parser_get_opt_param_string(params, "StructureFinding:subdir_per_output", + e->stf_subdir_per_output, + engine_default_stf_subdir_per_output); parser_get_param_string(params, "StructureFinding:config_file_name", e->stf_config_file_name); @@ -3631,16 +3736,18 @@ void engine_config(int restart, int fof, struct engine *e, if (nr_cores > CPU_SETSIZE) /* Unlikely, except on e.g. SGI UV. */ error("must allocate dynamic cpu_set_t (too many cores per node)"); - char *buf = (char *)malloc((nr_cores + 1) * sizeof(char)); - buf[nr_cores] = '\0'; - for (int j = 0; j < nr_cores; ++j) { - /* Reversed bit order from convention, but same as e.g. Intel MPI's - * I_MPI_PIN_DOMAIN explicit mask: left-to-right, LSB-to-MSB. */ - buf[j] = CPU_ISSET(j, entry_affinity) ? '1' : '0'; + if (verbose && with_aff) { + char *buf = (char *)malloc((nr_cores + 1) * sizeof(char)); + buf[nr_cores] = '\0'; + for (int j = 0; j < nr_cores; ++j) { + /* Reversed bit order from convention, but same as e.g. Intel MPI's + * I_MPI_PIN_DOMAIN explicit mask: left-to-right, LSB-to-MSB. */ + buf[j] = CPU_ISSET(j, entry_affinity) ? '1' : '0'; + } + message("Affinity at entry: %s", buf); + free(buf); } - if (verbose && with_aff) message("Affinity at entry: %s", buf); - int *cpuid = NULL; cpu_set_t cpuset; @@ -4119,38 +4226,32 @@ void engine_config(int restart, int fof, struct engine *e, /* Overwrite the constants for the scheduler */ space_maxsize = parser_get_opt_param_int(params, "Scheduler:cell_max_size", - space_maxsize_default); - space_subsize_pair_hydro = - parser_get_opt_param_int(params, "Scheduler:cell_sub_size_pair_hydro", - space_subsize_pair_hydro_default); - space_subsize_self_hydro = - parser_get_opt_param_int(params, "Scheduler:cell_sub_size_self_hydro", - space_subsize_self_hydro_default); - space_subsize_pair_stars = - parser_get_opt_param_int(params, "Scheduler:cell_sub_size_pair_stars", - space_subsize_pair_stars_default); - space_subsize_self_stars = - parser_get_opt_param_int(params, "Scheduler:cell_sub_size_self_stars", - space_subsize_self_stars_default); - space_subsize_pair_grav = - parser_get_opt_param_int(params, "Scheduler:cell_sub_size_pair_grav", - space_subsize_pair_grav_default); - space_subsize_self_grav = - parser_get_opt_param_int(params, "Scheduler:cell_sub_size_self_grav", - space_subsize_self_grav_default); + space_maxsize); + space_subsize_pair_hydro = parser_get_opt_param_int( + params, "Scheduler:cell_sub_size_pair_hydro", space_subsize_pair_hydro); + space_subsize_self_hydro = parser_get_opt_param_int( + params, "Scheduler:cell_sub_size_self_hydro", space_subsize_self_hydro); + space_subsize_pair_stars = parser_get_opt_param_int( + params, "Scheduler:cell_sub_size_pair_stars", space_subsize_pair_stars); + space_subsize_self_stars = parser_get_opt_param_int( + params, "Scheduler:cell_sub_size_self_stars", space_subsize_self_stars); + space_subsize_pair_grav = parser_get_opt_param_int( + params, "Scheduler:cell_sub_size_pair_grav", space_subsize_pair_grav); + space_subsize_self_grav = parser_get_opt_param_int( + params, "Scheduler:cell_sub_size_self_grav", space_subsize_self_grav); space_splitsize = parser_get_opt_param_int( - params, "Scheduler:cell_split_size", space_splitsize_default); + params, "Scheduler:cell_split_size", space_splitsize); space_subdepth_diff_grav = parser_get_opt_param_int(params, "Scheduler:cell_subdepth_diff_grav", space_subdepth_diff_grav_default); space_extra_parts = parser_get_opt_param_int( - params, "Scheduler:cell_extra_parts", space_extra_parts_default); + params, "Scheduler:cell_extra_parts", space_extra_parts); space_extra_sparts = parser_get_opt_param_int( - params, "Scheduler:cell_extra_sparts", space_extra_sparts_default); + params, "Scheduler:cell_extra_sparts", space_extra_sparts); space_extra_gparts = parser_get_opt_param_int( - params, "Scheduler:cell_extra_gparts", space_extra_gparts_default); + params, "Scheduler:cell_extra_gparts", space_extra_gparts); space_extra_bparts = parser_get_opt_param_int( - params, "Scheduler:cell_extra_bparts", space_extra_bparts_default); + params, "Scheduler:cell_extra_bparts", space_extra_bparts); engine_max_parts_per_ghost = parser_get_opt_param_int(params, "Scheduler:engine_max_parts_per_ghost", @@ -4226,11 +4327,13 @@ void engine_config(int restart, int fof, struct engine *e, } #ifdef WITH_LOGGER - /* Write the particle logger header */ - logger_write_file_header(e->logger); + if (!restart) { + /* Write the particle logger header */ + logger_write_file_header(e->logger); + } #endif - /* Initialise the structure finder */ + /* Initialise the structure finder */ #ifdef HAVE_VELOCIRAPTOR if (e->policy & engine_policy_structure_finding) velociraptor_init(e); #endif @@ -4240,7 +4343,6 @@ void engine_config(int restart, int fof, struct engine *e, if (with_aff) { free(cpuid); } - free(buf); #endif #ifdef SWIFT_DUMPER_THREAD @@ -4831,6 +4933,10 @@ void engine_struct_dump(struct engine *e, FILE *stream) { if (e->output_list_stats) output_list_struct_dump(e->output_list_stats, stream); if (e->output_list_stf) output_list_struct_dump(e->output_list_stf, stream); + +#ifdef WITH_LOGGER + logger_struct_dump(e->logger, stream); +#endif } /** @@ -4975,6 +5081,13 @@ void engine_struct_restore(struct engine *e, FILE *stream) { e->output_list_stf = output_list_stf; } +#ifdef WITH_LOGGER + struct logger_writer *log = + (struct logger_writer *)malloc(sizeof(struct logger_writer)); + logger_struct_restore(log, stream); + e->logger = log; +#endif + #ifdef EOS_PLANETARY eos_init(&eos, e->physical_constants, e->snapshot_units, e->parameter_file); #endif diff --git a/src/engine.h b/src/engine.h index 68a4df10c08325d5d810b361dab863bf9ee68ea6..a30d8943b8476f91915687988b42b0c074572397 100644 --- a/src/engine.h +++ b/src/engine.h @@ -34,13 +34,9 @@ /* Includes. */ #include "barrier.h" -#include "black_holes_properties.h" -#include "chemistry_struct.h" #include "clocks.h" #include "collectgroup.h" -#include "cooling_struct.h" #include "dump.h" -#include "gravity_properties.h" #include "mesh_gravity.h" #include "parser.h" #include "partition.h" @@ -48,11 +44,12 @@ #include "runner.h" #include "scheduler.h" #include "space.h" -#include "star_formation_logger.h" #include "task.h" #include "units.h" #include "velociraptor_interface.h" +struct black_holes_properties; + /** * @brief The different policies the #engine can follow. */ @@ -79,9 +76,10 @@ enum engine_policy { engine_policy_feedback = (1 << 18), engine_policy_black_holes = (1 << 19), engine_policy_fof = (1 << 20), - engine_policy_limiter = (1 << 21) + engine_policy_timestep_limiter = (1 << 21), + engine_policy_timestep_sync = (1 << 22) }; -#define engine_maxpolicy 22 +#define engine_maxpolicy 23 extern const char *engine_policy_names[engine_maxpolicy + 1]; /** @@ -115,6 +113,8 @@ enum engine_step_properties { #define engine_max_sparts_per_ghost_default 1000 #define engine_star_resort_task_depth_default 2 #define engine_tasks_per_cell_margin 1.2 +#define engine_default_stf_subdir_per_output "" +#define engine_default_snapshot_subdir "" /** * @brief The rank of the engine as a global variable (for messages). @@ -288,6 +288,7 @@ struct engine { integertime_t ti_next_snapshot; char snapshot_base_name[PARSER_MAX_LINE_SIZE]; + char snapshot_subdir[PARSER_MAX_LINE_SIZE]; int snapshot_compression; int snapshot_int_time_label_on; int snapshot_invoke_stf; @@ -307,6 +308,7 @@ struct engine { char stf_config_file_name[PARSER_MAX_LINE_SIZE]; char stf_base_name[PARSER_MAX_LINE_SIZE]; + char stf_subdir_per_output[PARSER_MAX_LINE_SIZE]; int stf_output_count; /* FoF black holes seeding information */ @@ -382,9 +384,8 @@ struct engine { int forcerepart; struct repartition *reparttype; -#ifdef WITH_LOGGER + /* The particle logger */ struct logger_writer *logger; -#endif /* How many steps have we done with the same set of tasks? */ int tasks_age; @@ -439,7 +440,7 @@ struct engine { const struct star_formation *star_formation; /* Properties of the sellar feedback model */ - const struct feedback_props *feedback_props; + struct feedback_props *feedback_props; /* Properties of the chemistry model */ const struct chemistry_global_data *chemistry; @@ -477,6 +478,9 @@ struct engine { /* Label of the run */ char run_name[PARSER_MAX_LINE_SIZE]; + + /* Has there been an stf this timestep? */ + char stf_this_timestep; }; /* Function prototypes, engine.c. */ @@ -488,12 +492,14 @@ void engine_compute_next_fof_time(struct engine *e); void engine_compute_next_statistics_time(struct engine *e); void engine_recompute_displacement_constraint(struct engine *e); void engine_unskip(struct engine *e); +void engine_unskip_timestep_communications(struct engine *e); void engine_drift_all(struct engine *e, const int drift_mpoles); void engine_drift_top_multipoles(struct engine *e); void engine_reconstruct_multipoles(struct engine *e); void engine_allocate_foreign_particles(struct engine *e); void engine_print_stats(struct engine *e); void engine_check_for_dumps(struct engine *e); +void engine_check_for_index_dump(struct engine *e); void engine_collect_end_of_step(struct engine *e, int apply); void engine_dump_snapshot(struct engine *e); void engine_init_output_lists(struct engine *e, struct swift_params *params); @@ -507,7 +513,7 @@ void engine_init(struct engine *e, struct space *s, struct swift_params *params, const struct entropy_floor_properties *entropy_floor, struct gravity_props *gravity, const struct stars_props *stars, const struct black_holes_props *black_holes, - const struct feedback_props *feedback, struct pm_mesh *mesh, + struct feedback_props *feedback, struct pm_mesh *mesh, const struct external_potential *potential, struct cooling_function_data *cooling_func, const struct star_formation *starform, @@ -518,7 +524,7 @@ void engine_config(int restart, int fof, struct engine *e, 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_launch(struct engine *e, const char *call); void engine_prepare(struct engine *e); void engine_init_particles(struct engine *e, int flag_entropy_ICs, int clean_h_values); @@ -556,6 +562,9 @@ void engine_make_fof_tasks(struct engine *e); /* Function prototypes, engine_marktasks.c. */ int engine_marktasks(struct engine *e); +/* Function prototypes, engine_split_particles.c. */ +void engine_split_gas_particles(struct engine *e); + #ifdef HAVE_SETAFFINITY cpu_set_t *engine_entry_affinity(void); #endif diff --git a/src/engine_collect_end_of_step.c b/src/engine_collect_end_of_step.c index ec02acfefdf65aca13d44a7cf90d48f31b99778f..458a0a7a40e9e433f0241b04ff67fa1fbc37bbf0 100644 --- a/src/engine_collect_end_of_step.c +++ b/src/engine_collect_end_of_step.c @@ -27,6 +27,7 @@ /* Local headers. */ #include "active.h" +#include "star_formation_logger.h" #include "timeline.h" /** @@ -75,12 +76,6 @@ void engine_collect_end_of_step_recurse_hydro(struct cell *c, integertime_t ti_hydro_end_min = max_nr_timesteps, ti_hydro_end_max = 0, ti_hydro_beg_max = 0; - /* Local Star formation history properties */ - struct star_formation_history sfh_updated; - - /* Initialize the star formation structs */ - star_formation_logger_init(&sfh_updated); - /* Collect the values from the progeny. */ for (int k = 0; k < 8; k++) { struct cell *cp = c->progeny[k]; @@ -96,14 +91,6 @@ void engine_collect_end_of_step_recurse_hydro(struct cell *c, updated += cp->hydro.updated; - /* Check if the cell is inactive and in that case reorder the SFH */ - if (!cell_is_starting_hydro(cp, e)) { - star_formation_logger_log_inactive_cell(&cp->stars.sfh); - } - - /* Add the star formation history in this cell to sfh_updated */ - star_formation_logger_add(&sfh_updated, &cp->stars.sfh); - /* Collected, so clear for next time. */ cp->hydro.updated = 0; } @@ -114,10 +101,6 @@ void engine_collect_end_of_step_recurse_hydro(struct cell *c, c->hydro.ti_end_max = ti_hydro_end_max; c->hydro.ti_beg_max = ti_hydro_beg_max; c->hydro.updated = updated; - // c->hydro.inhibited = inhibited; - - /* Store the star formation history in the parent cell */ - star_formation_logger_add(&c->stars.sfh, &sfh_updated); } /** @@ -381,7 +364,7 @@ void engine_collect_end_of_step_mapper(void *map_data, int num_elements, s_updated += c->stars.updated; b_updated += c->black_holes.updated; - /* Check if the cell is inactive and in that case reorder the SFH */ + /* Check if the cell was inactive and in that case reorder the SFH */ if (!cell_is_starting_hydro(c, e)) { star_formation_logger_log_inactive_cell(&c->stars.sfh); } diff --git a/src/engine_fof.c b/src/engine_fof.c index f1bb5b452104642f68b4a9987a1ab8d8e3b0162b..961b7e966ecc33250c3d005d3a31d59200f98fb0 100644 --- a/src/engine_fof.c +++ b/src/engine_fof.c @@ -123,8 +123,11 @@ void engine_fof(struct engine *e, const int dump_results, /* and activate them. */ engine_activate_fof_tasks(e); + /* Print the number of active tasks ? */ + if (e->verbose) engine_print_task_counts(e); + /* Perform local FOF tasks. */ - engine_launch(e); + engine_launch(e, "fof"); /* Perform FOF search over foreign particles and * find groups which require black hole seeding. */ diff --git a/src/engine_maketasks.c b/src/engine_maketasks.c index 42590cb5f41539d11ca39639c369ea68472e9826..5d8d3a5fed14330776ccd835664804427d1cb370 100644 --- a/src/engine_maketasks.c +++ b/src/engine_maketasks.c @@ -50,6 +50,7 @@ #include "debug.h" #include "error.h" #include "proxy.h" +#include "task_order.h" #include "timers.h" extern int engine_max_parts_per_ghost; @@ -132,12 +133,16 @@ void engine_addtasks_send_gravity(struct engine *e, struct cell *ci, * @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. - * @param t_ti The recv_ti_end #task, if it has already been created. + * @param t_ti The send_ti_end #task, if it has already been created. + * @param t_limiter The send_limiter #task, if it has already been created. + * @param with_limiter Are we running with the time-step limiter? + * @param with_sync Are we running with time-step synchronization? */ 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, - struct task *t_ti) { + struct task *t_ti, struct task *t_limiter, + const int with_limiter, const int with_sync) { #ifdef WITH_MPI struct link *l = NULL; @@ -175,6 +180,11 @@ void engine_addtasks_send_hydro(struct engine *e, struct cell *ci, t_ti = scheduler_addtask(s, task_type_send, task_subtype_tend_part, ci->mpi.tag, 0, ci, cj); + if (with_limiter) { + t_limiter = scheduler_addtask(s, task_type_send, task_subtype_limiter, + ci->mpi.tag, 0, ci, cj); + } + #ifdef EXTRA_HYDRO_LOOP scheduler_addunlock(s, t_gradient, ci->hydro.super->hydro.end_force); @@ -209,6 +219,7 @@ void engine_addtasks_send_hydro(struct engine *e, struct cell *ci, scheduler_addunlock(s, ci->hydro.super->hydro.drift, t_xv); scheduler_addunlock(s, ci->super->timestep, t_ti); + if (with_limiter) scheduler_addunlock(s, ci->super->timestep, t_limiter); } /* Add them to the local cell. */ @@ -218,6 +229,7 @@ void engine_addtasks_send_hydro(struct engine *e, struct cell *ci, engine_addlink(e, &ci->mpi.send, t_gradient); #endif engine_addlink(e, &ci->mpi.send, t_ti); + if (with_limiter) engine_addlink(e, &ci->mpi.send, t_limiter); } /* Recurse? */ @@ -225,7 +237,8 @@ void engine_addtasks_send_hydro(struct engine *e, struct cell *ci, 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, t_ti); + t_gradient, t_ti, t_limiter, with_limiter, + with_sync); #else error("SWIFT was not compiled with MPI support."); @@ -257,7 +270,8 @@ void engine_addtasks_send_stars(struct engine *e, struct cell *ci, /* Early abort (are we below the level where tasks are)? */ if (!cell_get_flag(ci, cell_flag_has_tasks)) return; - if (t_sf_counts == NULL && with_star_formation && ci->hydro.count > 0) { + if (task_order_star_formation_before_feedback && t_sf_counts == NULL && + with_star_formation && ci->hydro.count > 0) { #ifdef SWIFT_DEBUG_CHECKS if (ci->depth != 0) error( @@ -305,7 +319,8 @@ void engine_addtasks_send_stars(struct engine *e, struct cell *ci, engine_addlink(e, &ci->mpi.send, t_feedback); engine_addlink(e, &ci->mpi.send, t_ti); - if (with_star_formation && ci->hydro.count > 0) { + if (task_order_star_formation_before_feedback && with_star_formation && + ci->hydro.count > 0) { engine_addlink(e, &ci->mpi.send, t_sf_counts); } } @@ -438,10 +453,15 @@ void engine_addtasks_send_black_holes(struct engine *e, struct cell *ci, * @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. * @param t_ti The recv_ti_end #task, if it has already been created. + * @param t_limiter The recv_limiter #task, if it has already been created. + * @param with_limiter Are we running with the time-step limiter? + * @param with_sync Are we running with time-step synchronization? */ void engine_addtasks_recv_hydro(struct engine *e, struct cell *c, struct task *t_xv, struct task *t_rho, - struct task *t_gradient, struct task *t_ti) { + struct task *t_gradient, struct task *t_ti, + struct task *t_limiter, const int with_limiter, + const int with_sync) { #ifdef WITH_MPI struct scheduler *s = &e->sched; @@ -455,7 +475,7 @@ void engine_addtasks_recv_hydro(struct engine *e, struct cell *c, #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 +#endif /* SWIFT_DEBUG_CHECKS */ /* Create the tasks. */ t_xv = scheduler_addtask(s, task_type_recv, task_subtype_xv, c->mpi.tag, 0, @@ -469,6 +489,11 @@ void engine_addtasks_recv_hydro(struct engine *e, struct cell *c, t_ti = scheduler_addtask(s, task_type_recv, task_subtype_tend_part, c->mpi.tag, 0, c, NULL); + + if (with_limiter) { + t_limiter = scheduler_addtask(s, task_type_recv, task_subtype_limiter, + c->mpi.tag, 0, c, NULL); + } } if (t_xv != NULL) { @@ -478,6 +503,7 @@ void engine_addtasks_recv_hydro(struct engine *e, struct cell *c, engine_addlink(e, &c->mpi.recv, t_gradient); #endif engine_addlink(e, &c->mpi.recv, t_ti); + if (with_limiter) engine_addlink(e, &c->mpi.recv, t_limiter); /* Add dependencies. */ if (c->hydro.sorts != NULL) { @@ -505,8 +531,15 @@ void engine_addtasks_recv_hydro(struct engine *e, struct cell *c, } #endif - /* Make sure the density has been computed before the stars compute theirs. - */ + if (with_limiter) { + for (struct link *l = c->hydro.limiter; l != NULL; l = l->next) { + scheduler_addunlock(s, t_ti, l->t); + scheduler_addunlock(s, t_limiter, l->t); + } + } + + /* Make sure the gas density has been computed before the + * stars compute theirs. */ for (struct link *l = c->stars.density; l != NULL; l = l->next) { scheduler_addunlock(s, t_rho, l->t); } @@ -523,7 +556,7 @@ void engine_addtasks_recv_hydro(struct engine *e, struct cell *c, 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, - t_ti); + t_ti, t_limiter, with_limiter, with_sync); #else error("SWIFT was not compiled with MPI support."); @@ -551,7 +584,8 @@ void engine_addtasks_recv_stars(struct engine *e, struct cell *c, /* Early abort (are we below the level where tasks are)? */ if (!cell_get_flag(c, cell_flag_has_tasks)) return; - if (t_sf_counts == NULL && with_star_formation && c->hydro.count > 0) { + if (task_order_star_formation_before_feedback && t_sf_counts == NULL && + with_star_formation && c->hydro.count > 0) { #ifdef SWIFT_DEBUG_CHECKS if (c->depth != 0) error( @@ -578,7 +612,8 @@ void engine_addtasks_recv_stars(struct engine *e, struct cell *c, t_ti = scheduler_addtask(s, task_type_recv, task_subtype_tend_spart, c->mpi.tag, 0, c, NULL); - if (with_star_formation && c->hydro.count > 0) { + if (task_order_star_formation_before_feedback && with_star_formation && + c->hydro.count > 0) { /* Receive the stars only once the counts have been received */ scheduler_addunlock(s, t_sf_counts, t_feedback); @@ -588,7 +623,8 @@ void engine_addtasks_recv_stars(struct engine *e, struct cell *c, if (t_feedback != NULL) { engine_addlink(e, &c->mpi.recv, t_feedback); engine_addlink(e, &c->mpi.recv, t_ti); - if (with_star_formation && c->hydro.count > 0) { + if (task_order_star_formation_before_feedback && with_star_formation && + c->hydro.count > 0) { engine_addlink(e, &c->mpi.recv, t_sf_counts); } @@ -791,8 +827,10 @@ void engine_addtasks_recv_gravity(struct engine *e, struct cell *c, void engine_make_hierarchical_tasks_common(struct engine *e, struct cell *c) { struct scheduler *s = &e->sched; - const int with_limiter = (e->policy & engine_policy_limiter); const int with_star_formation = (e->policy & engine_policy_star_formation); + const int with_timestep_limiter = + (e->policy & engine_policy_timestep_limiter); + const int with_timestep_sync = (e->policy & engine_policy_timestep_sync); /* Are we at the top-level? */ if (c->top == c && c->nodeID == e->nodeID) { @@ -843,15 +881,29 @@ void engine_make_hierarchical_tasks_common(struct engine *e, struct cell *c) { scheduler_addunlock(s, c->top->hydro.star_formation, c->timestep); } - /* Time-step limiting */ - if (with_limiter) { + /* Time-step limiter */ + if (with_timestep_limiter) { + c->timestep_limiter = scheduler_addtask( s, task_type_timestep_limiter, task_subtype_none, 0, 0, c, NULL); - /* Make sure it is not run before kick2 */ scheduler_addunlock(s, c->timestep, c->timestep_limiter); scheduler_addunlock(s, c->timestep_limiter, c->kick1); } + + /* Time-step synchronization */ + if (with_timestep_sync) { + + c->timestep_sync = scheduler_addtask(s, task_type_timestep_sync, + task_subtype_none, 0, 0, c, NULL); + + scheduler_addunlock(s, c->timestep, c->timestep_sync); + scheduler_addunlock(s, c->timestep_sync, c->kick1); + } + + if (with_timestep_limiter && with_timestep_sync) { + scheduler_addunlock(s, c->timestep_limiter, c->timestep_sync); + } } } else { /* We are above the super-cell so need to go deeper */ @@ -1022,10 +1074,11 @@ void engine_make_hierarchical_tasks_hydro(struct engine *e, struct cell *c, /* Are we are the level where we create the stars' resort tasks? * If the tree is shallow, we need to do this at the super-level if the * super-level is above the level we want */ - if ((c->nodeID == e->nodeID) && (star_resort_cell == NULL) && + if (task_order_star_formation_before_feedback && (c->nodeID == e->nodeID) && + (star_resort_cell == NULL) && (c->depth == engine_star_resort_task_depth || c->hydro.super == c)) { - if (with_star_formation && c->hydro.count > 0) { + if (with_feedback && with_star_formation && c->hydro.count > 0) { /* Record this is the level where we re-sort */ star_resort_cell = c; @@ -1102,8 +1155,7 @@ void engine_make_hierarchical_tasks_hydro(struct engine *e, struct cell *c, c->hydro.cooling = scheduler_addtask(s, task_type_cooling, task_subtype_none, 0, 0, c, NULL); - scheduler_addunlock(s, c->hydro.end_force, c->hydro.cooling); - scheduler_addunlock(s, c->hydro.cooling, c->super->kick2); + task_order_addunlock_cooling(s, c); } else { scheduler_addunlock(s, c->hydro.end_force, c->super->kick2); @@ -1130,9 +1182,8 @@ void engine_make_hierarchical_tasks_hydro(struct engine *e, struct cell *c, #endif scheduler_addunlock(s, c->stars.stars_out, c->super->timestep); - if (with_star_formation && c->hydro.count > 0) { - scheduler_addunlock(s, star_resort_cell->hydro.stars_resort, - c->stars.stars_in); + if (with_feedback && with_star_formation && c->hydro.count > 0) { + task_order_addunlock_star_formation_feedback(s, c, star_resort_cell); } } @@ -1773,7 +1824,9 @@ void engine_make_extra_hydroloop_tasks_mapper(void *map_data, int num_elements, struct scheduler *sched = &e->sched; const int nodeID = e->nodeID; const int with_cooling = (e->policy & engine_policy_cooling); - const int with_limiter = (e->policy & engine_policy_limiter); + const int with_timestep_limiter = + (e->policy & engine_policy_timestep_limiter); + const int with_timestep_sync = (e->policy & engine_policy_timestep_sync); const int with_feedback = (e->policy & engine_policy_feedback); const int with_black_holes = (e->policy & engine_policy_black_holes); #ifdef EXTRA_HYDRO_LOOP @@ -1800,16 +1853,8 @@ void engine_make_extra_hydroloop_tasks_mapper(void *map_data, int num_elements, /* Escape early */ if (t->type == task_type_none) continue; - -#ifdef WITH_LOGGER - struct task *const ci_super_kick2_or_logger = ci->super->logger; - struct task *const cj_super_kick2_or_logger = - (cj == NULL) ? NULL : cj->super->logger; -#else - struct task *const ci_super_kick2_or_logger = ci->super->kick2; - struct task *const cj_super_kick2_or_logger = - (cj == NULL) ? NULL : cj->super->kick2; -#endif + if (t->type == task_type_stars_resort) continue; + if (t->type == task_type_star_formation) continue; /* Sort tasks depend on the drift of the cell (gas version). */ if (t_type == task_type_sort && ci->nodeID == nodeID) { @@ -1834,7 +1879,7 @@ void engine_make_extra_hydroloop_tasks_mapper(void *map_data, int num_elements, flags, 0, ci, NULL); /* the task for the time-step limiter */ - if (with_limiter) { + if (with_timestep_limiter) { t_limiter = scheduler_addtask(sched, task_type_self, task_subtype_limiter, flags, 0, ci, NULL); } @@ -1868,7 +1913,7 @@ void engine_make_extra_hydroloop_tasks_mapper(void *map_data, int num_elements, /* Link the tasks to the cells */ engine_addlink(e, &ci->hydro.force, t_force); - if (with_limiter) { + if (with_timestep_limiter) { engine_addlink(e, &ci->hydro.limiter, t_limiter); } if (with_feedback) { @@ -1895,12 +1940,12 @@ void engine_make_extra_hydroloop_tasks_mapper(void *map_data, int num_elements, /* Now, build all the dependencies for the hydro */ engine_make_hydro_loops_dependencies(sched, t, t_gradient, t_force, t_limiter, ci, with_cooling, - with_limiter); + with_timestep_limiter); #else /* Now, build all the dependencies for the hydro */ engine_make_hydro_loops_dependencies(sched, t, t_force, t_limiter, ci, - with_cooling, with_limiter); + with_cooling, with_timestep_limiter); #endif /* Create the task dependencies */ @@ -1956,11 +2001,19 @@ void engine_make_extra_hydroloop_tasks_mapper(void *map_data, int num_elements, ci->hydro.super->black_holes.black_holes_out); } - if (with_limiter) { - scheduler_addunlock(sched, ci_super_kick2_or_logger, t_limiter); - scheduler_addunlock(sched, t_limiter, ci->super->timestep); + if (with_timestep_limiter) { + scheduler_addunlock(sched, ci->super->timestep, t_limiter); + scheduler_addunlock(sched, ci->hydro.super->hydro.drift, t_limiter); + scheduler_addunlock(sched, t_limiter, ci->super->kick1); scheduler_addunlock(sched, t_limiter, ci->super->timestep_limiter); } + + if (with_timestep_sync && with_feedback) { + scheduler_addunlock(sched, t_star_feedback, ci->super->timestep_sync); + } + if (with_timestep_sync && with_black_holes && bcount_i > 0) { + scheduler_addunlock(sched, t_bh_feedback, ci->super->timestep_sync); + } } /* Otherwise, pair interaction? */ @@ -1988,7 +2041,7 @@ void engine_make_extra_hydroloop_tasks_mapper(void *map_data, int num_elements, flags, 0, ci, cj); /* and the task for the time-step limiter */ - if (with_limiter) { + if (with_timestep_limiter) { t_limiter = scheduler_addtask(sched, task_type_pair, task_subtype_limiter, flags, 0, ci, cj); } @@ -2021,7 +2074,7 @@ void engine_make_extra_hydroloop_tasks_mapper(void *map_data, int num_elements, engine_addlink(e, &ci->hydro.force, t_force); engine_addlink(e, &cj->hydro.force, t_force); - if (with_limiter) { + if (with_timestep_limiter) { engine_addlink(e, &ci->hydro.limiter, t_limiter); engine_addlink(e, &cj->hydro.limiter, t_limiter); } @@ -2059,12 +2112,12 @@ void engine_make_extra_hydroloop_tasks_mapper(void *map_data, int num_elements, if (ci->nodeID == nodeID) { engine_make_hydro_loops_dependencies(sched, t, t_gradient, t_force, t_limiter, ci, with_cooling, - with_limiter); + with_timestep_limiter); } if ((cj->nodeID == nodeID) && (ci->hydro.super != cj->hydro.super)) { engine_make_hydro_loops_dependencies(sched, t, t_gradient, t_force, t_limiter, cj, with_cooling, - with_limiter); + with_timestep_limiter); } #else @@ -2072,11 +2125,13 @@ void engine_make_extra_hydroloop_tasks_mapper(void *map_data, int num_elements, /* that are local and are not descendant of the same super_hydro-cells */ if (ci->nodeID == nodeID) { engine_make_hydro_loops_dependencies(sched, t, t_force, t_limiter, ci, - with_cooling, with_limiter); + with_cooling, + with_timestep_limiter); } if ((cj->nodeID == nodeID) && (ci->hydro.super != cj->hydro.super)) { engine_make_hydro_loops_dependencies(sched, t, t_force, t_limiter, cj, - with_cooling, with_limiter); + with_cooling, + with_timestep_limiter); } #endif @@ -2146,11 +2201,20 @@ void engine_make_extra_hydroloop_tasks_mapper(void *map_data, int num_elements, ci->hydro.super->black_holes.black_holes_out); } - if (with_limiter) { - scheduler_addunlock(sched, ci_super_kick2_or_logger, t_limiter); - scheduler_addunlock(sched, t_limiter, ci->super->timestep); + if (with_timestep_limiter) { + scheduler_addunlock(sched, ci->hydro.super->hydro.drift, t_limiter); + scheduler_addunlock(sched, ci->super->timestep, t_limiter); + scheduler_addunlock(sched, t_limiter, ci->super->kick1); scheduler_addunlock(sched, t_limiter, ci->super->timestep_limiter); } + + if (with_timestep_sync && with_feedback) { + scheduler_addunlock(sched, t_star_feedback, ci->super->timestep_sync); + } + if (with_timestep_sync && with_black_holes && + (bcount_i > 0 || bcount_j > 0)) { + scheduler_addunlock(sched, t_bh_feedback, ci->super->timestep_sync); + } } else /*(ci->nodeID != nodeID) */ { if (with_feedback) { scheduler_addunlock(sched, ci->hydro.super->stars.sorts, @@ -2224,12 +2288,29 @@ void engine_make_extra_hydroloop_tasks_mapper(void *map_data, int num_elements, cj->hydro.super->black_holes.black_holes_out); } - if (with_limiter) { - scheduler_addunlock(sched, cj_super_kick2_or_logger, t_limiter); - scheduler_addunlock(sched, t_limiter, cj->super->timestep); + if (with_timestep_limiter) { + scheduler_addunlock(sched, cj->hydro.super->hydro.drift, t_limiter); + } + } + + if (ci->super != cj->super) { + + if (with_timestep_limiter) { + scheduler_addunlock(sched, cj->super->timestep, t_limiter); + scheduler_addunlock(sched, t_limiter, cj->super->kick1); scheduler_addunlock(sched, t_limiter, cj->super->timestep_limiter); } + + if (with_timestep_sync && with_feedback) { + scheduler_addunlock(sched, t_star_feedback, + cj->super->timestep_sync); + } + if (with_timestep_sync && with_black_holes && + (bcount_i > 0 || bcount_j > 0)) { + scheduler_addunlock(sched, t_bh_feedback, cj->super->timestep_sync); + } } + } else /*(cj->nodeID != nodeID) */ { if (with_feedback) { scheduler_addunlock(sched, cj->hydro.super->stars.sorts, @@ -2259,7 +2340,7 @@ void engine_make_extra_hydroloop_tasks_mapper(void *map_data, int num_elements, flags, 0, ci, NULL); /* and the task for the time-step limiter */ - if (with_limiter) { + if (with_timestep_limiter) { t_limiter = scheduler_addtask(sched, task_type_sub_self, task_subtype_limiter, flags, 0, ci, NULL); } @@ -2298,7 +2379,7 @@ void engine_make_extra_hydroloop_tasks_mapper(void *map_data, int num_elements, /* Add the link between the new loop and the cell */ engine_addlink(e, &ci->hydro.force, t_force); - if (with_limiter) { + if (with_timestep_limiter) { engine_addlink(e, &ci->hydro.limiter, t_limiter); } if (with_feedback) { @@ -2326,13 +2407,13 @@ void engine_make_extra_hydroloop_tasks_mapper(void *map_data, int num_elements, /* that are local and are not descendant of the same super_hydro-cells */ engine_make_hydro_loops_dependencies(sched, t, t_gradient, t_force, t_limiter, ci, with_cooling, - with_limiter); + with_timestep_limiter); #else /* Now, build all the dependencies for the hydro for the cells */ /* that are local and are not descendant of the same super_hydro-cells */ engine_make_hydro_loops_dependencies(sched, t, t_force, t_limiter, ci, - with_cooling, with_limiter); + with_cooling, with_timestep_limiter); #endif /* Create the task dependencies */ @@ -2392,12 +2473,19 @@ void engine_make_extra_hydroloop_tasks_mapper(void *map_data, int num_elements, ci->hydro.super->black_holes.black_holes_out); } - if (with_limiter) { - scheduler_addunlock(sched, ci_super_kick2_or_logger, t_limiter); - scheduler_addunlock(sched, t_limiter, ci->super->timestep); + if (with_timestep_limiter) { + scheduler_addunlock(sched, ci->hydro.super->hydro.drift, t_limiter); + scheduler_addunlock(sched, ci->super->timestep, t_limiter); + scheduler_addunlock(sched, t_limiter, ci->super->kick1); scheduler_addunlock(sched, t_limiter, ci->super->timestep_limiter); } + if (with_timestep_sync && with_feedback) { + scheduler_addunlock(sched, t_star_feedback, ci->super->timestep_sync); + } + if (with_timestep_sync && with_black_holes && bcount_i > 0) { + scheduler_addunlock(sched, t_bh_feedback, ci->super->timestep_sync); + } } /* Otherwise, sub-pair interaction? */ @@ -2426,7 +2514,7 @@ void engine_make_extra_hydroloop_tasks_mapper(void *map_data, int num_elements, flags, 0, ci, cj); /* and the task for the time-step limiter */ - if (with_limiter) { + if (with_timestep_limiter) { t_limiter = scheduler_addtask(sched, task_type_sub_pair, task_subtype_limiter, flags, 0, ci, cj); } @@ -2462,7 +2550,7 @@ void engine_make_extra_hydroloop_tasks_mapper(void *map_data, int num_elements, engine_addlink(e, &ci->hydro.force, t_force); engine_addlink(e, &cj->hydro.force, t_force); - if (with_limiter) { + if (with_timestep_limiter) { engine_addlink(e, &ci->hydro.limiter, t_limiter); engine_addlink(e, &cj->hydro.limiter, t_limiter); } @@ -2500,12 +2588,12 @@ void engine_make_extra_hydroloop_tasks_mapper(void *map_data, int num_elements, if (ci->nodeID == nodeID) { engine_make_hydro_loops_dependencies(sched, t, t_gradient, t_force, t_limiter, ci, with_cooling, - with_limiter); + with_timestep_limiter); } if ((cj->nodeID == nodeID) && (ci->hydro.super != cj->hydro.super)) { engine_make_hydro_loops_dependencies(sched, t, t_gradient, t_force, t_limiter, cj, with_cooling, - with_limiter); + with_timestep_limiter); } #else @@ -2513,11 +2601,13 @@ void engine_make_extra_hydroloop_tasks_mapper(void *map_data, int num_elements, /* that are local and are not descendant of the same super_hydro-cells */ if (ci->nodeID == nodeID) { engine_make_hydro_loops_dependencies(sched, t, t_force, t_limiter, ci, - with_cooling, with_limiter); + with_cooling, + with_timestep_limiter); } if ((cj->nodeID == nodeID) && (ci->hydro.super != cj->hydro.super)) { engine_make_hydro_loops_dependencies(sched, t, t_force, t_limiter, cj, - with_cooling, with_limiter); + with_cooling, + with_timestep_limiter); } #endif @@ -2586,15 +2676,23 @@ void engine_make_extra_hydroloop_tasks_mapper(void *map_data, int num_elements, ci->hydro.super->black_holes.black_holes_out); } - if (with_limiter) { - scheduler_addunlock(sched, ci_super_kick2_or_logger, t_limiter); - scheduler_addunlock(sched, t_limiter, ci->super->timestep); + if (with_timestep_limiter) { + scheduler_addunlock(sched, ci->hydro.super->hydro.drift, t_limiter); + scheduler_addunlock(sched, ci->super->timestep, t_limiter); + scheduler_addunlock(sched, t_limiter, ci->super->kick1); scheduler_addunlock(sched, t_limiter, ci->super->timestep_limiter); } + + if (with_timestep_sync && with_feedback) { + scheduler_addunlock(sched, t_star_feedback, ci->super->timestep_sync); + } + if (with_timestep_sync && with_black_holes && + (bcount_i > 0 || bcount_j > 0)) { + scheduler_addunlock(sched, t_bh_feedback, ci->super->timestep_sync); + } } else /* ci->nodeID != nodeID */ { if (with_feedback) { - /* message("%p/%p",ci->hydro.super->stars.sorts, t_star_feedback); */ scheduler_addunlock(sched, ci->hydro.super->stars.sorts, t_star_feedback); } @@ -2666,11 +2764,27 @@ void engine_make_extra_hydroloop_tasks_mapper(void *map_data, int num_elements, cj->hydro.super->black_holes.black_holes_out); } - if (with_limiter) { - scheduler_addunlock(sched, cj_super_kick2_or_logger, t_limiter); - scheduler_addunlock(sched, t_limiter, cj->super->timestep); + if (with_timestep_limiter) { + scheduler_addunlock(sched, cj->hydro.super->hydro.drift, t_limiter); + } + } + + if (ci->super != cj->super) { + + if (with_timestep_limiter) { + scheduler_addunlock(sched, cj->super->timestep, t_limiter); + scheduler_addunlock(sched, t_limiter, cj->super->kick1); scheduler_addunlock(sched, t_limiter, cj->super->timestep_limiter); } + + if (with_timestep_sync && with_feedback) { + scheduler_addunlock(sched, t_star_feedback, + cj->super->timestep_sync); + } + if (with_timestep_sync && with_black_holes && + (bcount_i > 0 || bcount_j > 0)) { + scheduler_addunlock(sched, t_bh_feedback, cj->super->timestep_sync); + } } } else /* cj->nodeID != nodeID */ { if (with_feedback) { @@ -2830,6 +2944,8 @@ void engine_addtasks_send_mapper(void *map_data, int num_elements, struct engine *e = (struct engine *)extra_data; const int with_star_formation = (e->policy & engine_policy_star_formation); + const int with_limiter = (e->policy & engine_policy_timestep_limiter); + const int with_sync = (e->policy & engine_policy_timestep_sync); struct cell_type_pair *cell_type_pairs = (struct cell_type_pair *)map_data; for (int k = 0; k < num_elements; k++) { @@ -2842,7 +2958,8 @@ void engine_addtasks_send_mapper(void *map_data, int num_elements, if ((e->policy & engine_policy_hydro) && (type & proxy_cell_type_hydro)) engine_addtasks_send_hydro(e, ci, cj, /*t_xv=*/NULL, /*t_rho=*/NULL, /*t_gradient=*/NULL, - /*t_ti=*/NULL); + /*t_ti=*/NULL, /*t_limiter=*/NULL, + with_limiter, with_sync); /* Add the send tasks for the cells in the proxy that have a stars * connection. */ @@ -2874,6 +2991,8 @@ void engine_addtasks_recv_mapper(void *map_data, int num_elements, struct engine *e = (struct engine *)extra_data; const int with_star_formation = (e->policy & engine_policy_star_formation); + const int with_limiter = (e->policy & engine_policy_timestep_limiter); + const int with_sync = (e->policy & engine_policy_timestep_sync); struct cell_type_pair *cell_type_pairs = (struct cell_type_pair *)map_data; for (int k = 0; k < num_elements; k++) { @@ -2884,7 +3003,8 @@ void engine_addtasks_recv_mapper(void *map_data, int num_elements, * connection. */ if ((e->policy & engine_policy_hydro) && (type & proxy_cell_type_hydro)) engine_addtasks_recv_hydro(e, ci, /*t_xv=*/NULL, /*t_rho=*/NULL, - /*t_gradient=*/NULL, /*t_ti=*/NULL); + /*t_gradient=*/NULL, /*t_ti=*/NULL, + /*t_limiter=*/NULL, with_limiter, with_sync); /* Add the recv tasks for the cells in the proxy that have a stars * connection. */ @@ -3035,8 +3155,8 @@ void engine_make_fof_tasks(struct engine *e) { e->sched.size * sizeof(struct task) / (1024 * 1024)); if (e->verbose) - message("took %.3f %s (including reweight).", - clocks_from_ticks(getticks() - tic), clocks_getunit()); + message("took %.3f %s.", clocks_from_ticks(getticks() - tic), + clocks_getunit()); } /** diff --git a/src/engine_marktasks.c b/src/engine_marktasks.c index 7f4e2d4c4b4ae4865eb2c2320d021be534cc57c3..e7da143404849799911d7ae4f20fd8532d04b5b8 100644 --- a/src/engine_marktasks.c +++ b/src/engine_marktasks.c @@ -51,6 +51,7 @@ #include "debug.h" #include "error.h" #include "proxy.h" +#include "task_order.h" #include "timers.h" /** @@ -69,11 +70,10 @@ void engine_marktasks_mapper(void *map_data, int num_elements, 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; - const int with_limiter = e->policy & engine_policy_limiter; + const int with_timestep_limiter = e->policy & engine_policy_timestep_limiter; + const int with_timestep_sync = e->policy & engine_policy_timestep_sync; const int with_star_formation = e->policy & engine_policy_star_formation; -#ifdef WITH_MPI const int with_feedback = e->policy & engine_policy_feedback; -#endif for (int ind = 0; ind < num_elements; ind++) { @@ -102,7 +102,7 @@ void engine_marktasks_mapper(void *map_data, int num_elements, if (ci_active_hydro) { scheduler_activate(s, t); cell_activate_drift_part(ci, s); - if (with_limiter) cell_activate_limiter(ci, s); + if (with_timestep_limiter) cell_activate_limiter(ci, s); } } @@ -111,8 +111,8 @@ void engine_marktasks_mapper(void *map_data, int num_elements, t_subtype == task_subtype_density) { if (ci_active_hydro) { scheduler_activate(s, t); - cell_activate_subcell_hydro_tasks(ci, NULL, s); - if (with_limiter) cell_activate_limiter(ci, s); + cell_activate_subcell_hydro_tasks(ci, NULL, s, with_timestep_limiter); + if (with_timestep_limiter) cell_activate_limiter(ci, s); } } @@ -151,6 +151,7 @@ void engine_marktasks_mapper(void *map_data, int num_elements, scheduler_activate(s, t); cell_activate_drift_part(ci, s); cell_activate_drift_spart(ci, s); + if (with_timestep_sync) cell_activate_sync_part(ci, s); } } @@ -159,7 +160,8 @@ void engine_marktasks_mapper(void *map_data, int num_elements, t_subtype == task_subtype_stars_density) { if (ci_active_stars) { scheduler_activate(s, t); - cell_activate_subcell_stars_tasks(ci, NULL, s, with_star_formation); + cell_activate_subcell_stars_tasks(ci, NULL, s, with_star_formation, + with_timestep_sync); } } @@ -317,8 +319,10 @@ void engine_marktasks_mapper(void *map_data, int num_elements, if (cj_nodeID == nodeID) cell_activate_drift_part(cj, s); /* And the limiter */ - if (ci_nodeID == nodeID && with_limiter) cell_activate_limiter(ci, s); - if (cj_nodeID == nodeID && with_limiter) cell_activate_limiter(cj, s); + if (ci_nodeID == nodeID && with_timestep_limiter) + cell_activate_limiter(ci, s); + if (cj_nodeID == nodeID && with_timestep_limiter) + cell_activate_limiter(cj, s); /* Check the sorts and activate them if needed. */ cell_activate_hydro_sorts(ci, t->flags, s); @@ -329,7 +333,8 @@ void engine_marktasks_mapper(void *map_data, int num_elements, /* Store current values of dx_max and h_max. */ else if (t_type == task_type_sub_pair && t_subtype == task_subtype_density) { - cell_activate_subcell_hydro_tasks(t->ci, t->cj, s); + cell_activate_subcell_hydro_tasks(t->ci, t->cj, s, + with_timestep_limiter); } } @@ -357,6 +362,8 @@ void engine_marktasks_mapper(void *map_data, int num_elements, /* Activate the drift tasks. */ if (ci_nodeID == nodeID) cell_activate_drift_spart(ci, s); if (cj_nodeID == nodeID) cell_activate_drift_part(cj, s); + if (cj_nodeID == nodeID && with_timestep_sync) + cell_activate_sync_part(cj, s); /* Check the sorts and activate them if needed. */ cell_activate_hydro_sorts(cj, t->flags, s); @@ -377,6 +384,8 @@ void engine_marktasks_mapper(void *map_data, int num_elements, /* Activate the drift tasks. */ if (ci_nodeID == nodeID) cell_activate_drift_part(ci, s); if (cj_nodeID == nodeID) cell_activate_drift_spart(cj, s); + if (ci_nodeID == nodeID && with_timestep_sync) + cell_activate_sync_part(ci, s); /* Check the sorts and activate them if needed. */ cell_activate_hydro_sorts(ci, t->flags, s); @@ -387,7 +396,8 @@ void engine_marktasks_mapper(void *map_data, int num_elements, /* Store current values of dx_max and h_max. */ else if (t_type == task_type_sub_pair && t_subtype == task_subtype_stars_density) { - cell_activate_subcell_stars_tasks(ci, cj, s, with_star_formation); + cell_activate_subcell_stars_tasks(ci, cj, s, with_star_formation, + with_timestep_sync); } } @@ -481,6 +491,11 @@ void engine_marktasks_mapper(void *map_data, int num_elements, } } + /* If the foreign cell is active, we want its particles for the + * limiter */ + if (ci_active_hydro && with_timestep_limiter) + scheduler_activate_recv(s, ci->mpi.recv, task_subtype_limiter); + /* If the foreign cell is active, we want its ti_end values. */ if (ci_active_hydro) scheduler_activate_recv(s, ci->mpi.recv, task_subtype_tend_part); @@ -507,6 +522,12 @@ void engine_marktasks_mapper(void *map_data, int num_elements, } } + /* If the local cell is active, send its particles for the limiting. + */ + if (cj_active_hydro && with_timestep_limiter) + scheduler_activate_send(s, cj->mpi.send, task_subtype_limiter, + ci_nodeID); + /* If the local cell is active, send its ti_end values. */ if (cj_active_hydro) scheduler_activate_send(s, cj->mpi.send, task_subtype_tend_part, @@ -515,12 +536,17 @@ void engine_marktasks_mapper(void *map_data, int num_elements, /* Propagating new star counts? */ if (with_star_formation && with_feedback) { if (ci_active_hydro && ci->hydro.count > 0) { - scheduler_activate_recv(s, ci->mpi.recv, task_subtype_sf_counts); + if (task_order_star_formation_before_feedback) { + scheduler_activate_recv(s, ci->mpi.recv, + task_subtype_sf_counts); + } scheduler_activate_recv(s, ci->mpi.recv, task_subtype_tend_spart); } if (cj_active_hydro && cj->hydro.count > 0) { - scheduler_activate_send(s, cj->mpi.send, task_subtype_sf_counts, - ci_nodeID); + if (task_order_star_formation_before_feedback) { + scheduler_activate_send(s, cj->mpi.send, task_subtype_sf_counts, + ci_nodeID); + } scheduler_activate_send(s, cj->mpi.send, task_subtype_tend_spart, ci_nodeID); } @@ -540,6 +566,11 @@ void engine_marktasks_mapper(void *map_data, int num_elements, } } + /* If the foreign cell is active, we want its particles for the + * limiter */ + if (cj_active_hydro && with_timestep_limiter) + scheduler_activate_recv(s, cj->mpi.recv, task_subtype_limiter); + /* If the foreign cell is active, we want its ti_end values. */ if (cj_active_hydro) scheduler_activate_recv(s, cj->mpi.recv, task_subtype_tend_part); @@ -568,6 +599,12 @@ void engine_marktasks_mapper(void *map_data, int num_elements, } } + /* If the local cell is active, send its particles for the limiting. + */ + if (ci_active_hydro && with_timestep_limiter) + scheduler_activate_send(s, ci->mpi.send, task_subtype_limiter, + cj_nodeID); + /* If the local cell is active, send its ti_end values. */ if (ci_active_hydro) scheduler_activate_send(s, ci->mpi.send, task_subtype_tend_part, @@ -576,12 +613,17 @@ void engine_marktasks_mapper(void *map_data, int num_elements, /* Propagating new star counts? */ if (with_star_formation && with_feedback) { if (cj_active_hydro && cj->hydro.count > 0) { - scheduler_activate_recv(s, cj->mpi.recv, task_subtype_sf_counts); + if (task_order_star_formation_before_feedback) { + scheduler_activate_recv(s, cj->mpi.recv, + task_subtype_sf_counts); + } scheduler_activate_recv(s, cj->mpi.recv, task_subtype_tend_spart); } if (ci_active_hydro && ci->hydro.count > 0) { - scheduler_activate_send(s, ci->mpi.send, task_subtype_sf_counts, - cj_nodeID); + if (task_order_star_formation_before_feedback) { + scheduler_activate_send(s, ci->mpi.send, task_subtype_sf_counts, + cj_nodeID); + } scheduler_activate_send(s, ci->mpi.send, task_subtype_tend_spart, cj_nodeID); } @@ -941,7 +983,7 @@ void engine_marktasks_mapper(void *map_data, int num_elements, /* Subgrid tasks: star formation */ else if (t_type == task_type_star_formation) { if (cell_is_active_hydro(t->ci, e)) { - cell_activate_star_formation_tasks(t->ci, s); + cell_activate_star_formation_tasks(t->ci, s, with_feedback); cell_activate_super_spart_drifts(t->ci, s); } } diff --git a/src/engine_split_particles.c b/src/engine_split_particles.c new file mode 100644 index 0000000000000000000000000000000000000000..58d7f905588c79c6339d9c2e1ac264ec63095c3c --- /dev/null +++ b/src/engine_split_particles.c @@ -0,0 +1,283 @@ +/******************************************************************************* + * This file is part of SWIFT. + * Copyright (c) 2019 Matthieu Schaller (schaller@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/>. + * + ******************************************************************************/ + +/* Config parameters. */ +#include "../config.h" + +/* This object's header. */ +#include "engine.h" + +/* Local headers */ +#include "active.h" +#include "black_holes_struct.h" +#include "chemistry.h" +#include "cooling.h" +#include "hydro.h" +#include "random.h" +#include "star_formation.h" +#include "tracers.h" + +const int particle_split_factor = 2; +const double displacement_factor = 0.2; + +/** + * @brief Identify all the gas particles above a given mass threshold + * and split them into 2. + * + * This may reallocate the space arrays as new particles are created. + * This is an expensive function as it has to loop multiple times over + * the local array of particles. In case of reallocations, it may + * also have to loop over the gravity and other arrays. + * + * @param e The #engine. + */ +void engine_split_gas_particles(struct engine *e) { + + /* Abort if we are not doing any splitting */ + if (!e->hydro_properties->particle_splitting) return; + + /* Time this */ + const ticks tic = getticks(); + + /* Get useful constants */ + struct space *s = e->s; + const int with_gravity = (e->policy & engine_policy_self_gravity) || + (e->policy & engine_policy_external_gravity); + const double mass_threshold = + e->hydro_properties->particle_splitting_mass_threshold; + + /* Quick check to avoid problems */ + if (particle_split_factor != 2) { + error( + "Invalid splitting factor. Can currently only split particles into 2!"); + } + + /* Start by counting how many particles are above the threshold for splitting + */ + + size_t counter = 0; + const size_t nr_parts_old = s->nr_parts; + const struct part *parts_old = s->parts; + for (size_t i = 0; i < nr_parts_old; ++i) { + + const struct part *p = &parts_old[i]; + + /* Ignore inhibited particles */ + if (part_is_inhibited(p, e)) continue; + + /* Is the mass of this particle larger than the threshold? */ + const float gas_mass = hydro_get_mass(p); + if (gas_mass > mass_threshold) ++counter; + } + + /* Early abort? */ + if (counter == 0) { + + if (e->verbose) + message("took %.3f %s.", clocks_from_ticks(getticks() - tic), + clocks_getunit()); + return; + } + + /* Be verbose about this. This is an important event */ + message("Splitting %zd particles above the mass threshold", counter); + + /* Number of particles to create */ + const size_t count_new_gas = counter * particle_split_factor; + + /* Do we need to reallocate the gas array for the new particles? */ + if (s->nr_parts + count_new_gas > s->size_parts) { + + const size_t nr_parts_new = s->nr_parts + count_new_gas; + s->size_parts = engine_parts_size_grow * nr_parts_new; + + if (e->verbose) message("Reallocating the part array!"); + + struct part *parts_new = NULL; + if (swift_memalign("parts", (void **)&parts_new, part_align, + sizeof(struct part) * s->size_parts) != 0) + error("Failed to allocate new part data."); + memcpy(parts_new, s->parts, sizeof(struct part) * s->nr_parts); + swift_free("parts", s->parts); + + struct xpart *xparts_new = NULL; + if (swift_memalign("xparts", (void **)&xparts_new, xpart_align, + sizeof(struct xpart) * s->size_parts) != 0) + error("Failed to allocate new part data."); + memcpy(xparts_new, s->xparts, sizeof(struct xpart) * s->nr_parts); + swift_free("xparts", s->xparts); + + s->xparts = xparts_new; + s->parts = parts_new; + } + + /* Do we need to reallocate the gpart array for the new particles? */ + if (with_gravity && s->nr_gparts + count_new_gas > s->size_gparts) { + + const size_t nr_gparts_new = s->nr_gparts + count_new_gas; + s->size_gparts = engine_parts_size_grow * nr_gparts_new; + + if (e->verbose) message("Reallocating the gpart array!"); + + struct gpart *gparts_new = NULL; + if (swift_memalign("gparts", (void **)&gparts_new, gpart_align, + sizeof(struct gpart) * s->size_gparts) != 0) + error("Failed to allocate new gpart data."); + + /* Copy the particles */ + memcpy(gparts_new, s->gparts, sizeof(struct gpart) * s->nr_gparts); + swift_free("gparts", s->gparts); + + /* We now need to correct all the pointers of the other particle arrays */ + part_relink_all_parts_to_gparts(gparts_new, s->nr_gparts, s->parts, + s->sparts, s->bparts); + s->gparts = gparts_new; + } + +#ifdef SWIFT_DEBUG_CHECKS + /* Verify that whatever reallocation happened we are still having correct + * links */ + part_verify_links(s->parts, s->gparts, s->sparts, s->bparts, s->nr_parts, + s->nr_gparts, s->nr_sparts, s->nr_bparts, e->verbose); +#endif + + size_t k_parts = s->nr_parts; + size_t k_gparts = s->nr_gparts; + + /* Loop over the particles again to split them */ + struct part *parts = s->parts; + struct xpart *xparts = s->xparts; + struct gpart *gparts = s->gparts; + for (size_t i = 0; i < nr_parts_old; ++i) { + + /* Is the mass of this particle larger than the threshold? */ + struct part *p = &parts[i]; + + /* Ignore inhibited particles */ + if (part_is_inhibited(p, e)) continue; + + const float gas_mass = hydro_get_mass(p); + const float h = p->h; + + /* Found a particle to split */ + if (gas_mass > mass_threshold) { + + struct xpart *xp = &xparts[i]; + struct gpart *gp = p->gpart; + + /* Start by copying over the particles */ + memcpy(&parts[k_parts], p, sizeof(struct part)); + memcpy(&xparts[k_parts], xp, sizeof(struct xpart)); + + if (with_gravity) { + memcpy(&gparts[k_gparts], gp, sizeof(struct gpart)); + } + + /* Update the IDs */ + parts[k_parts].id += 2; + + /* Re-link everything */ + if (with_gravity) { + parts[k_parts].gpart = &gparts[k_gparts]; + gparts[k_gparts].id_or_neg_offset = -k_parts; + } + + /* Displacement unit vector */ + const double delta_x = random_unit_interval(p->id, e->ti_current, + (enum random_number_type)0); + const double delta_y = random_unit_interval(p->id, e->ti_current, + (enum random_number_type)1); + const double delta_z = random_unit_interval(p->id, e->ti_current, + (enum random_number_type)2); + + /* Displace the old particle */ + p->x[0] += delta_x * displacement_factor * h; + p->x[1] += delta_y * displacement_factor * h; + p->x[2] += delta_z * displacement_factor * h; + + if (with_gravity) { + gp->x[0] += delta_x * displacement_factor * h; + gp->x[1] += delta_y * displacement_factor * h; + gp->x[2] += delta_z * displacement_factor * h; + } + + /* Displace the new particle */ + parts[k_parts].x[0] -= delta_x * displacement_factor * h; + parts[k_parts].x[1] -= delta_y * displacement_factor * h; + parts[k_parts].x[2] -= delta_z * displacement_factor * h; + + if (with_gravity) { + gparts[k_gparts].x[0] -= delta_x * displacement_factor * h; + gparts[k_gparts].x[1] -= delta_y * displacement_factor * h; + gparts[k_gparts].x[2] -= delta_z * displacement_factor * h; + } + + /* Divide the mass */ + const double new_mass = gas_mass * 0.5; + hydro_set_mass(p, new_mass); + hydro_set_mass(&parts[k_parts], new_mass); + + if (with_gravity) { + gp->mass = new_mass; + gparts[k_gparts].mass = new_mass; + } + + /* Split the chemistry fields */ + chemistry_split_part(p, particle_split_factor); + chemistry_split_part(&parts[k_parts], particle_split_factor); + + /* Split the cooling fields */ + cooling_split_part(p, xp, particle_split_factor); + cooling_split_part(&parts[k_parts], &xparts[k_parts], + particle_split_factor); + + /* Split the star formation fields */ + star_formation_split_part(p, xp, particle_split_factor); + star_formation_split_part(&parts[k_parts], &xparts[k_parts], + particle_split_factor); + + /* Split the tracer fields */ + tracers_split_part(p, xp, particle_split_factor); + tracers_split_part(&parts[k_parts], &xparts[k_parts], + particle_split_factor); + + /* Mark the particles as not having been swallowed */ + black_holes_mark_part_as_not_swallowed(&p->black_holes_data); + black_holes_mark_part_as_not_swallowed(&parts[k_parts].black_holes_data); + + /* Move to the next free slot */ + k_parts++; + if (with_gravity) k_gparts++; + } + } + + /* Update the local counters */ + s->nr_parts = k_parts; + s->nr_gparts = k_gparts; + +#ifdef SWIFT_DEBUG_CHECKS + if (s->nr_parts != nr_parts_old + (particle_split_factor - 1) * counter) { + error("Incorrect number of particles created"); + } +#endif + + if (e->verbose) + message("took %.3f %s.", clocks_from_ticks(getticks() - tic), + clocks_getunit()); +} diff --git a/src/engine_unskip.c b/src/engine_unskip.c index dfadfa5ca1a6aebd0d7a277164eca9707ac97a62..22bc55f34e0bc51711f770d4d7a0d2b2a629f778 100644 --- a/src/engine_unskip.c +++ b/src/engine_unskip.c @@ -398,3 +398,59 @@ void engine_unskip(struct engine *e) { message("took %.3f %s.", clocks_from_ticks(getticks() - tic), clocks_getunit()); } + +void engine_unskip_timestep_communications_mapper(void *map_data, + int num_elements, + void *extra_data) { + /* Unpack the data */ + struct scheduler *s = (struct scheduler *)extra_data; + struct task *const tasks = (struct task *)map_data; + const int nr_tasks = num_elements; + + /* Unskip the tasks in this part of the array */ + for (int i = 0; i < nr_tasks; ++i) { + + struct task *const t = &tasks[i]; + + if (t->type == task_type_send || t->type == task_type_recv) { + + if (t->subtype == task_subtype_tend_part || + t->subtype == task_subtype_tend_gpart) { + + scheduler_activate(s, t); + } + } + } +} + +/** + * @brief Blindly unskips all the tend communications for #part and #gpart. + * + * This function is only necessary when running with the time-step limiter + * or the time-step synchronization policy as the time-steps of inactive + * sections of the tree might have been changed by these tasks. + * + * @param e The #engine. + */ +void engine_unskip_timestep_communications(struct engine *e) { + +#ifdef WITH_MPI + + const ticks tic = getticks(); + + struct scheduler *s = &e->sched; + struct task *tasks = e->sched.tasks; + const int nr_tasks = e->sched.nr_tasks; + + /* Activate all the part and gpart ti_end tasks */ + threadpool_map(&e->threadpool, engine_unskip_timestep_communications_mapper, + tasks, nr_tasks, sizeof(struct task), 0, s); + + if (e->verbose) + message("took %.3f %s.", clocks_from_ticks(getticks() - tic), + clocks_getunit()); + +#else + error("SWIFT was not compiled with MPI support."); +#endif +} diff --git a/src/equation_of_state.c b/src/equation_of_state.c index 0953ee7114314f3baf6e86a14a6ddb0e98442dd9..d59bd05a2c8eae69f3afad1157f05ce48d7e14ec 100644 --- a/src/equation_of_state.c +++ b/src/equation_of_state.c @@ -22,4 +22,23 @@ /* Equation of state for the physics model * (temporary ugly solution as a global variable) */ + +#ifdef __APPLE__ +/* + * The clang compiler and linker on OSX incorrectly optimize + * out the eos global object before the final linking stage, which + * leads to a compilation error. + * The fake initialisation below forces the compiler to keep the + * instance and pass it to the linker stage. + */ +#if defined(EOS_PLANETARY) +struct eos_parameters eos = {.Til_iron.rho_0 = -1.f}; +#elif defined(EOS_ISOTHERMAL_GAS) +struct eos_parameters eos = {.isothermal_internal_energy = -1.}; +#else +struct eos_parameters eos; +#endif + +#else /* i.e. not __APPLE__ */ struct eos_parameters eos; +#endif /* __APPLE__ */ diff --git a/src/equation_of_state/planetary/sesame.h b/src/equation_of_state/planetary/sesame.h index 11c16964602b28c0d1a080b6c262ff20c1f5b9cb..037de315aa7e88303f1700746c83daddb16e2949 100644 --- a/src/equation_of_state/planetary/sesame.h +++ b/src/equation_of_state/planetary/sesame.h @@ -338,15 +338,35 @@ INLINE static float SESAME_pressure_from_internal_energy( idx_u_2 = mat->num_T - 2; } - intp_rho = (log_rho - mat->table_log_rho[idx_rho]) / - (mat->table_log_rho[idx_rho + 1] - mat->table_log_rho[idx_rho]); - intp_u_1 = (log_u - mat->table_log_u_rho_T[idx_rho * mat->num_T + idx_u_1]) / - (mat->table_log_u_rho_T[idx_rho * mat->num_T + (idx_u_1 + 1)] - - mat->table_log_u_rho_T[idx_rho * mat->num_T + idx_u_1]); - intp_u_2 = - (log_u - mat->table_log_u_rho_T[(idx_rho + 1) * mat->num_T + idx_u_2]) / - (mat->table_log_u_rho_T[(idx_rho + 1) * mat->num_T + (idx_u_2 + 1)] - - mat->table_log_u_rho_T[(idx_rho + 1) * mat->num_T + idx_u_2]); + // Check for duplicates in SESAME tables before interpolation + if (mat->table_log_rho[idx_rho + 1] != mat->table_log_rho[idx_rho]) { + intp_rho = (log_rho - mat->table_log_rho[idx_rho]) / + (mat->table_log_rho[idx_rho + 1] - mat->table_log_rho[idx_rho]); + } else { + intp_rho = 1.; + } + + // Check for duplicates in SESAME tables before interpolation + if (mat->table_log_u_rho_T[idx_rho * mat->num_T + (idx_u_1 + 1)] != + mat->table_log_u_rho_T[idx_rho * mat->num_T + idx_u_1]) { + intp_u_1 = + (log_u - mat->table_log_u_rho_T[idx_rho * mat->num_T + idx_u_1]) / + (mat->table_log_u_rho_T[idx_rho * mat->num_T + (idx_u_1 + 1)] - + mat->table_log_u_rho_T[idx_rho * mat->num_T + idx_u_1]); + } else { + intp_u_1 = 1.; + } + + // Check for duplicates in SESAME tables before interpolation + if (mat->table_log_u_rho_T[(idx_rho + 1) * mat->num_T + (idx_u_2 + 1)] != + mat->table_log_u_rho_T[(idx_rho + 1) * mat->num_T + idx_u_2]) { + intp_u_2 = + (log_u - mat->table_log_u_rho_T[(idx_rho + 1) * mat->num_T + idx_u_2]) / + (mat->table_log_u_rho_T[(idx_rho + 1) * mat->num_T + (idx_u_2 + 1)] - + mat->table_log_u_rho_T[(idx_rho + 1) * mat->num_T + idx_u_2]); + } else { + intp_u_2 = 1.; + } // Table values P_1 = mat->table_P_rho_T[idx_rho * mat->num_T + idx_u_1]; @@ -442,15 +462,35 @@ INLINE static float SESAME_soundspeed_from_internal_energy( idx_u_2 = mat->num_T - 2; } - intp_rho = (log_rho - mat->table_log_rho[idx_rho]) / - (mat->table_log_rho[idx_rho + 1] - mat->table_log_rho[idx_rho]); - intp_u_1 = (log_u - mat->table_log_u_rho_T[idx_rho * mat->num_T + idx_u_1]) / - (mat->table_log_u_rho_T[idx_rho * mat->num_T + (idx_u_1 + 1)] - - mat->table_log_u_rho_T[idx_rho * mat->num_T + idx_u_1]); - intp_u_2 = - (log_u - mat->table_log_u_rho_T[(idx_rho + 1) * mat->num_T + idx_u_2]) / - (mat->table_log_u_rho_T[(idx_rho + 1) * mat->num_T + (idx_u_2 + 1)] - - mat->table_log_u_rho_T[(idx_rho + 1) * mat->num_T + idx_u_2]); + // Check for duplicates in SESAME tables before interpolation + if (mat->table_log_rho[idx_rho + 1] != mat->table_log_rho[idx_rho]) { + intp_rho = (log_rho - mat->table_log_rho[idx_rho]) / + (mat->table_log_rho[idx_rho + 1] - mat->table_log_rho[idx_rho]); + } else { + intp_rho = 1.; + } + + // Check for duplicates in SESAME tables before interpolation + if (mat->table_log_u_rho_T[idx_rho * mat->num_T + (idx_u_1 + 1)] != + mat->table_log_u_rho_T[idx_rho * mat->num_T + idx_u_1]) { + intp_u_1 = + (log_u - mat->table_log_u_rho_T[idx_rho * mat->num_T + idx_u_1]) / + (mat->table_log_u_rho_T[idx_rho * mat->num_T + (idx_u_1 + 1)] - + mat->table_log_u_rho_T[idx_rho * mat->num_T + idx_u_1]); + } else { + intp_u_1 = 1.; + } + + // Check for duplicates in SESAME tables before interpolation + if (mat->table_log_u_rho_T[(idx_rho + 1) * mat->num_T + (idx_u_2 + 1)] != + mat->table_log_u_rho_T[(idx_rho + 1) * mat->num_T + idx_u_2]) { + intp_u_2 = + (log_u - mat->table_log_u_rho_T[(idx_rho + 1) * mat->num_T + idx_u_2]) / + (mat->table_log_u_rho_T[(idx_rho + 1) * mat->num_T + (idx_u_2 + 1)] - + mat->table_log_u_rho_T[(idx_rho + 1) * mat->num_T + idx_u_2]); + } else { + intp_u_2 = 1.; + } // Table values c_1 = mat->table_c_rho_T[idx_rho * mat->num_T + idx_u_1]; diff --git a/src/feedback.h b/src/feedback.h index ee2934c76456dd58b6909c63acfaa34104ac0300..0b44e41bcdb843aa25602bb8abde32be68475c23 100644 --- a/src/feedback.h +++ b/src/feedback.h @@ -29,6 +29,9 @@ #elif defined(FEEDBACK_EAGLE) #include "./feedback/EAGLE/feedback.h" #include "./feedback/EAGLE/feedback_iact.h" +#elif defined(FEEDBACK_GEAR) +#include "./feedback/GEAR/feedback.h" +#include "./feedback/GEAR/feedback_iact.h" #else #error "Invalid choice of feedback model" #endif diff --git a/src/feedback/EAGLE/feedback.c b/src/feedback/EAGLE/feedback.c index d041969e808ac95a4f7f4de06a4d2cb8ccaf41d7..01c96b83fb4cd78592569d6b38000cac21038ec7 100644 --- a/src/feedback/EAGLE/feedback.c +++ b/src/feedback/EAGLE/feedback.c @@ -44,7 +44,7 @@ double eagle_feedback_temperature_change(const struct spart* sp, /** * @brief Computes the number of supernovae of type II exploding for a given - * star particle. + * star particle assuming that all the SNII stars go off at once. * * @param sp The #spart. * @param props The properties of the stellar model. @@ -52,16 +52,116 @@ double eagle_feedback_temperature_change(const struct spart* sp, double eagle_feedback_number_of_SNII(const struct spart* sp, const struct feedback_props* props) { - /* Note: For a Chabrier 2003 IMF and SNII going off between 6 and 100 - * M_sun, the first term is 0.017362 M_sun^-1 */ + /* Note: For a Chabrier 2003 IMF and SNII going off + * - between 6 and 100 M_sun, the first term is 0.017362 M_sun^-1 (EAGLE) + * - between 8 and 100 M_sun, the first term is 0.011801 M_sun^-1 (EAGLE-XL) + */ return props->num_SNII_per_msun * sp->mass_init * props->mass_to_solar_mass; } /** - * @brief Computes the number of supernovae of type Ia exploding for a given - * star particle between time t and t+dt + * @brief Computes the number of supernovae of type II exploding for a given + * star particle between two mass limits * - * We follow Foerster et al. 2006, MNRAS, 368 + * @param sp The #spart. + * @param props The properties of the stellar model. + * @param min_dying_mass_Msun Minimal star mass dying this step (in solar + * masses). + * @param max_dying_mass_Msun Maximal star mass dying this step (in solar + * masses). + */ +double eagle_feedback_number_of_sampled_SNII(const struct spart* sp, + const struct feedback_props* props, + const double min_dying_mass_Msun, + const double max_dying_mass_Msun) { + + /* The max dying star mass is below the SNII mass window + * --> No SNII */ + if (max_dying_mass_Msun < props->SNII_min_mass_msun) return 0.; + + /* The min dying star mass is above the SNII mass window + * --> No SNII */ + if (min_dying_mass_Msun > props->SNII_max_mass_msun) return 0.; + + /* Ok, we have some overlap with the SNII mass window. */ + + double log10_min_mass_Msun = -10.; + double log10_max_mass_Msun = -10.; + + /* The min dying star mass dies inside the SNII mass window */ + if (min_dying_mass_Msun <= props->SNII_max_mass_msun && + min_dying_mass_Msun > props->SNII_min_mass_msun) { + + /* Now, check the max dying star mass */ + + /* The max dying star mass is also inside the SNII mass window */ + if (max_dying_mass_Msun <= props->SNII_max_mass_msun) { + log10_min_mass_Msun = log10(min_dying_mass_Msun); + log10_max_mass_Msun = log10(max_dying_mass_Msun); + } + + /* The max dying star is above the SNII mass window */ + else { + log10_min_mass_Msun = log10(min_dying_mass_Msun); + log10_max_mass_Msun = props->log10_SNII_max_mass_msun; + } + + } + + /* The min dying star mass dies below the SNII mass window */ + else if (min_dying_mass_Msun <= props->SNII_min_mass_msun) { + + /* Now, check the max dying star mass */ + + /* The max dying star mass is inside the SNII mass window */ + if (max_dying_mass_Msun > props->SNII_min_mass_msun && + max_dying_mass_Msun <= props->SNII_max_mass_msun) { + log10_min_mass_Msun = props->log10_SNII_min_mass_msun; + log10_max_mass_Msun = log10(max_dying_mass_Msun); + } + + /* The max dying star is above the SNII mass window */ + else if (max_dying_mass_Msun > props->SNII_max_mass_msun) { + log10_min_mass_Msun = props->log10_SNII_min_mass_msun; + log10_max_mass_Msun = props->log10_SNII_max_mass_msun; + } + + /* The max dying star mass is also below the SNII mass window */ + else { + + /* We already excluded this at the star of the function */ +#ifdef SWIFT_DEBUG_CHECKS + error("Error in the logic"); +#endif + } + } + + /* The min dying star mass dies above the SNII mass window */ + else { + + /* We already excluded this at the star of the function */ +#ifdef SWIFT_DEBUG_CHECKS + error("Error in the logic"); +#endif + } + +#ifdef SWIFT_DEBUG_CHECKS + if (log10_min_mass_Msun == -10. || log10_max_mass_Msun == -10.) + error("Something went wrong in the calculation of the number of SNII."); +#endif + + /* Calculate how many supernovae have exploded in this timestep + * by integrating the IMF between the bounds we chose */ + const double num_SNII_per_msun = + integrate_imf(log10_min_mass_Msun, log10_max_mass_Msun, + eagle_imf_integration_no_weight, NULL, props); + + return num_SNII_per_msun * sp->mass_init * props->mass_to_solar_mass; +} + +/** + * @brief Computes the number of supernovae of type Ia exploding for a given + * star particle between time t0 and t1 * * @param M_init The inital mass of the star particle in internal units. * @param t0 The initial time (in Gyr). @@ -72,11 +172,42 @@ double eagle_feedback_number_of_SNIa(const double M_init, const double t0, const double t1, const struct feedback_props* props) { - /* The calculation is written as the integral between t0 and t1 of - * eq. 3 of Schaye 2015 paper. */ - const double tau = props->SNIa_timescale_Gyr_inv; - const double nu = props->SNIa_efficiency; - const double num_SNIa_per_Msun = nu * (exp(-t0 * tau) - exp(-t1 * tau)); + double num_SNIa_per_Msun = 0.; + +#ifdef SWIFT_DEBUG_CHECKS + if (t1 < t0) error("Negative time range!"); + if (t0 < props->SNIa_DTD_delay_Gyr) + error("Initial time smaller than the delay time!"); +#endif + + switch (props->SNIa_DTD) { + + case eagle_feedback_SNIa_DTD_exponential: { + + /* We follow Foerster et al. 2006, MNRAS, 368 */ + + /* The calculation is written as the integral between t0 and t1 of + * eq. 3 of Schaye 2015 paper. */ + const double tau = props->SNIa_DTD_exp_timescale_Gyr_inv; + const double nu = props->SNIa_DTD_exp_norm; + num_SNIa_per_Msun = nu * (exp(-t0 * tau) - exp(-t1 * tau)); + break; + } + + case eagle_feedback_SNIa_DTD_power_law: { + + /* We follow Graur et al. 2011, MNRAS, 417 */ + + const double norm = props->SNIa_DTD_power_law_norm; + num_SNIa_per_Msun = norm * log(t1 / t0); + break; + } + + default: { + num_SNIa_per_Msun = 0.; + error("Invalid choice of SNIa delay time distribution!"); + } + } return num_SNIa_per_Msun * M_init * props->mass_to_solar_mass; } @@ -132,22 +263,32 @@ double eagle_feedback_energy_fraction(const struct spart* sp, * @param dt Length of time-step in internal units. * @param ngb_gas_mass Total un-weighted mass in the star's kernel. * @param feedback_props The properties of the feedback model. + * @param min_dying_mass_Msun Minimal star mass dying this step (in solar + * masses). + * @param max_dying_mass_Msun Maximal star mass dying this step (in solar + * masses). */ INLINE static void compute_SNII_feedback( struct spart* sp, const double star_age, const double dt, - const float ngb_gas_mass, const struct feedback_props* feedback_props) { + const float ngb_gas_mass, const struct feedback_props* feedback_props, + const double min_dying_mass_Msun, const double max_dying_mass_Msun) { - /* Time after birth considered for SNII feedback (internal units) */ + /* Are we sampling the delay function or using a fixed delay? */ + const int SNII_sampled_delay = feedback_props->SNII_sampled_delay; + + /* Time after birth considered for SNII feedback (internal units) + * when using a fixed delay */ const double SNII_wind_delay = feedback_props->SNII_wind_delay; /* Are we doing feedback this step? * Note that since the ages are calculated using an interpolation table we * must allow some tolerance here*/ - if (star_age <= SNII_wind_delay && - (star_age + 1.0001 * dt) > SNII_wind_delay) { + if ((SNII_sampled_delay) || (star_age <= SNII_wind_delay && + (star_age + 1.001 * dt) > SNII_wind_delay)) { - /* Make sure a star does not do feedback twice! */ - if (sp->f_E != -1.f) { + /* Make sure a star does not do feedback twice + * when using a fixed delay! */ + if (!SNII_sampled_delay && sp->f_E != -1.f) { #ifdef SWIFT_DEBUG_CHECKS message("Star has already done feedback! sp->id=%lld age=%e d=%e", sp->id, star_age, dt); @@ -158,10 +299,21 @@ INLINE static void compute_SNII_feedback( /* Properties of the model (all in internal units) */ const double delta_T = eagle_feedback_temperature_change(sp, feedback_props); - const double N_SNe = eagle_feedback_number_of_SNII(sp, feedback_props); const double E_SNe = feedback_props->E_SNII; const double f_E = eagle_feedback_energy_fraction(sp, feedback_props); + /* Number of SNe at this time-step */ + double N_SNe; + if (SNII_sampled_delay) { + N_SNe = eagle_feedback_number_of_sampled_SNII( + sp, feedback_props, min_dying_mass_Msun, max_dying_mass_Msun); + } else { + N_SNe = eagle_feedback_number_of_SNII(sp, feedback_props); + } + + /* Abort if there are no SNe exploding this step */ + if (N_SNe == 0.) return; + /* Conversion factor from T to internal energy */ const double conv_factor = feedback_props->temp_to_u_factor; @@ -272,31 +424,25 @@ INLINE static void determine_bin_yields(int* index_Z_low, int* index_Z_high, INLINE static void evolve_SNIa( const double log10_min_mass, const double log10_max_mass, const double M_init, const double Z, const struct feedback_props* props, - double star_age_Gyr, double dt_Gyr, + double star_age_Gyr, const double dt_Gyr, struct feedback_spart_data* const feedback_data) { + const double star_age_end_step_Gyr = star_age_Gyr + dt_Gyr; + /* Check if we're outside the mass range for SNIa */ - if (log10_min_mass >= props->log10_SNIa_max_mass_msun) return; + if (star_age_end_step_Gyr < props->SNIa_DTD_delay_Gyr) return; #ifdef SWIFT_DEBUG_CHECKS if (dt_Gyr < 0.) error("Negative time-step length!"); if (star_age_Gyr < 0.) error("Negative age!"); #endif - /* If the max mass is outside the mass range update it to be the maximum - * and use updated values for the star's age and timestep in this function */ - if (log10_max_mass > props->log10_SNIa_max_mass_msun) { - - const double max_mass = props->SNIa_max_mass_msun; - const double lifetime_Gyr = lifetime_in_Gyr(max_mass, Z, props); - - dt_Gyr = max(star_age_Gyr + dt_Gyr - lifetime_Gyr, 0.); - star_age_Gyr = lifetime_Gyr; - } + /* Only consider stars beyond the minimal age for SNIa */ + star_age_Gyr = max(star_age_Gyr, props->SNIa_DTD_delay_Gyr); /* Compute the number of SNIa */ const float num_SNIa = eagle_feedback_number_of_SNIa( - M_init, star_age_Gyr, star_age_Gyr + dt_Gyr, props); + M_init, star_age_Gyr, star_age_end_step_Gyr, props); /* Compute mass of each metal */ for (int i = 0; i < chemistry_element_count; i++) { @@ -694,10 +840,13 @@ void compute_stellar_evolution(const struct feedback_props* feedback_props, #ifdef SWIFT_DEBUG_CHECKS if (age < 0.f) error("Negative age for a star."); + + if (sp->count_since_last_enrichment != 0) + error("Computing feedback on a star that should not"); #endif /* Convert dt and stellar age from internal units to Gyr. */ - const double Gyr_in_cgs = 1e9 * 365. * 24. * 3600.; + const double Gyr_in_cgs = 1e9 * 365.25 * 24. * 3600.; const double time_to_cgs = units_cgs_conversion_factor(us, UNIT_CONV_TIME); const double conversion_factor = time_to_cgs / Gyr_in_cgs; const double dt_Gyr = dt * conversion_factor; @@ -719,7 +868,7 @@ void compute_stellar_evolution(const struct feedback_props* feedback_props, const float ngb_gas_mass = sp->feedback_data.to_collect.ngb_mass; /* Check if there are neighbours, otherwise exit */ - if (ngb_gas_mass == 0.f) { + if (ngb_gas_mass == 0.f || sp->density.wcount * pow_dimension(sp->h) < 1e-4) { feedback_reset_feedback(sp, feedback_props); return; } @@ -728,6 +877,11 @@ void compute_stellar_evolution(const struct feedback_props* feedback_props, const float enrichment_weight_inv = sp->feedback_data.to_collect.enrichment_weight_inv; +#ifdef SWIFT_DEBUG_CHECKS + if (sp->feedback_data.to_collect.enrichment_weight_inv < 0.) + error("Negative inverse weight!"); +#endif + /* Now we start filling the data structure for information to apply to the * particles. Do _NOT_ read from the to_collect substructure any more. */ @@ -739,10 +893,10 @@ void compute_stellar_evolution(const struct feedback_props* feedback_props, (enrichment_weight_inv != 0.f) ? 1.f / enrichment_weight_inv : 0.f; sp->feedback_data.to_distribute.enrichment_weight = enrichment_weight; - /* Compute properties of the stochastic SNII feedback model. */ - if (feedback_props->with_SNII_feedback) { - compute_SNII_feedback(sp, age, dt, ngb_gas_mass, feedback_props); - } +#ifdef SWIFT_DEBUG_CHECKS + if (sp->feedback_data.to_distribute.enrichment_weight < 0.) + error("Negative weight!"); +#endif /* Calculate mass of stars that has died from the star's birth up to the * beginning and end of timestep */ @@ -751,13 +905,19 @@ void compute_stellar_evolution(const struct feedback_props* feedback_props, const double min_dying_mass_Msun = dying_mass_msun(star_age_Gyr + dt_Gyr, Z, feedback_props); -#ifdef SWIFT_DEBUG_CHECK +#ifdef SWIFT_DEBUG_CHECKS /* Sanity check. Worth investigating if necessary as functions for evaluating * mass of stars dying might be strictly decreasing. */ if (min_dying_mass_Msun > max_dying_mass_Msun) error("min dying mass is greater than max dying mass"); #endif + /* Compute properties of the stochastic SNII feedback model. */ + if (feedback_props->with_SNII_feedback) { + compute_SNII_feedback(sp, age, dt, ngb_gas_mass, feedback_props, + min_dying_mass_Msun, max_dying_mass_Msun); + } + /* Integration interval is zero - this can happen if minimum and maximum * dying masses are above imf_max_mass_Msun. Return without doing any * enrichment. */ @@ -824,6 +984,8 @@ void feedback_props_init(struct feedback_props* fp, const struct hydro_props* hydro_props, const struct cosmology* cosmo) { + const double Gyr_in_cgs = 1.0e9 * 365.25 * 24. * 3600.; + /* Main operation modes ------------------------------------------------- */ fp->with_SNII_feedback = @@ -863,11 +1025,17 @@ void feedback_props_init(struct feedback_props* fp, /* Properties of the SNII energy feedback model ------------------------- */ - /* Set the delay time before SNII occur */ - const double Gyr_in_cgs = 1.0e9 * 365. * 24. * 3600.; - fp->SNII_wind_delay = - parser_get_param_double(params, "EAGLEFeedback:SNII_wind_delay_Gyr") * - Gyr_in_cgs / units_cgs_conversion_factor(us, UNIT_CONV_TIME); + /* Are we sampling the SNII lifetimes for feedback or using a fixed delay? */ + fp->SNII_sampled_delay = + parser_get_param_int(params, "EAGLEFeedback:SNII_sampled_delay"); + + if (!fp->SNII_sampled_delay) { + + /* Set the delay time before SNII occur */ + fp->SNII_wind_delay = + parser_get_param_double(params, "EAGLEFeedback:SNII_wind_delay_Gyr") * + Gyr_in_cgs / units_cgs_conversion_factor(us, UNIT_CONV_TIME); + } /* Read the temperature change to use in stochastic heating */ fp->SNe_deltaT_desired = @@ -892,6 +1060,8 @@ void feedback_props_init(struct feedback_props* fp, error("Can't have the max SNII mass smaller than the min SNII mass!"); } + fp->SNII_min_mass_msun = SNII_min_mass_msun; + fp->SNII_max_mass_msun = SNII_max_mass_msun; fp->log10_SNII_min_mass_msun = log10(SNII_min_mass_msun); fp->log10_SNII_max_mass_msun = log10(SNII_max_mass_msun); @@ -928,16 +1098,38 @@ void feedback_props_init(struct feedback_props* fp, /* Properties of the SNIa enrichment model -------------------------------- */ - fp->SNIa_max_mass_msun = - parser_get_param_double(params, "EAGLEFeedback:SNIa_max_mass_Msun"); - fp->log10_SNIa_max_mass_msun = log10(fp->SNIa_max_mass_msun); + fp->SNIa_DTD_delay_Gyr = + parser_get_param_double(params, "EAGLEFeedback:SNIa_DTD_delay_Gyr"); + + char temp[32] = {0}; + parser_get_param_string(params, "EAGLEFeedback:SNIa_DTD", temp); + + if (strcmp(temp, "Exponential") == 0) { + + fp->SNIa_DTD = eagle_feedback_SNIa_DTD_exponential; + + /* Read SNIa exponential DTD model parameters */ + fp->SNIa_DTD_exp_norm = parser_get_param_float( + params, "EAGLEFeedback:SNIa_DTD_exp_norm_p_Msun"); + fp->SNIa_DTD_exp_timescale_Gyr = parser_get_param_float( + params, "EAGLEFeedback:SNIa_DTD_exp_timescale_Gyr"); + fp->SNIa_DTD_exp_timescale_Gyr_inv = 1.f / fp->SNIa_DTD_exp_timescale_Gyr; + + } else if (strcmp(temp, "PowerLaw") == 0) { - /* Read SNIa timescale model parameters */ - fp->SNIa_efficiency = - parser_get_param_float(params, "EAGLEFeedback:SNIa_efficiency_p_Msun"); - fp->SNIa_timescale_Gyr = - parser_get_param_float(params, "EAGLEFeedback:SNIa_timescale_Gyr"); - fp->SNIa_timescale_Gyr_inv = 1.f / fp->SNIa_timescale_Gyr; + fp->SNIa_DTD = eagle_feedback_SNIa_DTD_power_law; + + /* Read SNIa power-law DTD model parameters */ + fp->SNIa_DTD_power_law_norm = parser_get_param_float( + params, "EAGLEFeedback:SNIa_DTD_power_law_norm_p_Msun"); + + /* Renormalize everything such that the integral converges to + 'SNIa_DTD_power_law_norm' over 13.6 Gyr. */ + fp->SNIa_DTD_power_law_norm /= log(13.6 / fp->SNIa_DTD_delay_Gyr); + + } else { + error("Invalid SNIa DTD model: '%s'", temp); + } /* Energy released by supernova type Ia */ fp->E_SNIa_cgs = @@ -960,6 +1152,28 @@ void feedback_props_init(struct feedback_props* fp, fp->AGB_ejecta_specific_kinetic_energy = 0.5f * ejecta_velocity * ejecta_velocity; + /* Properties of the enrichment down-sampling ----------------------------- */ + + fp->stellar_evolution_age_cut = + parser_get_param_double(params, + "EAGLEFeedback:stellar_evolution_age_cut_Gyr") * + Gyr_in_cgs / units_cgs_conversion_factor(us, UNIT_CONV_TIME); + + fp->stellar_evolution_sampling_rate = parser_get_param_double( + params, "EAGLEFeedback:stellar_evolution_sampling_rate"); + + if (fp->stellar_evolution_sampling_rate < 1 || + fp->stellar_evolution_sampling_rate >= (1 << (8 * sizeof(char) - 1))) + error("Stellar evolution sampling rate too large. Must be >0 and <%d", + (1 << (8 * sizeof(char) - 1))); + + /* Check that we are not downsampling before reaching the SNII delay */ + if (!fp->SNII_sampled_delay && + fp->stellar_evolution_age_cut < fp->SNII_wind_delay) + error( + "Time at which the enrichment downsampling stars is lower than the " + "SNII wind delay!"); + /* Gather common conversion factors --------------------------------------- */ /* Calculate internal mass to solar mass conversion factor */ @@ -1076,6 +1290,60 @@ void feedback_restore_tables(struct feedback_props* fp) { compute_ejecta(fp); } +/** + * @brief Clean-up the memory allocated for the feedback routines + * + * We simply free all the arrays. + * + * @param feedback_props the feedback data structure. + */ +void feedback_clean(struct feedback_props* feedback_props) { + + swift_free("imf-tables", feedback_props->imf); + swift_free("imf-tables", feedback_props->imf_mass_bin); + swift_free("imf-tables", feedback_props->imf_mass_bin_log10); + swift_free("feedback-tables", feedback_props->yields_SNIa); + swift_free("feedback-tables", feedback_props->yield_SNIa_IMF_resampled); + swift_free("feedback-tables", feedback_props->yield_AGB.mass); + swift_free("feedback-tables", feedback_props->yield_AGB.metallicity); + swift_free("feedback-tables", feedback_props->yield_AGB.yield); + swift_free("feedback-tables", feedback_props->yield_AGB.yield_IMF_resampled); + swift_free("feedback-tables", feedback_props->yield_AGB.ejecta); + swift_free("feedback-tables", feedback_props->yield_AGB.ejecta_IMF_resampled); + swift_free("feedback-tables", feedback_props->yield_AGB.total_metals); + swift_free("feedback-tables", + feedback_props->yield_AGB.total_metals_IMF_resampled); + swift_free("feedback-tables", feedback_props->yield_SNII.mass); + swift_free("feedback-tables", feedback_props->yield_SNII.metallicity); + swift_free("feedback-tables", feedback_props->yield_SNII.yield); + swift_free("feedback-tables", feedback_props->yield_SNII.yield_IMF_resampled); + swift_free("feedback-tables", feedback_props->yield_SNII.ejecta); + swift_free("feedback-tables", + feedback_props->yield_SNII.ejecta_IMF_resampled); + swift_free("feedback-tables", feedback_props->yield_SNII.total_metals); + swift_free("feedback-tables", + feedback_props->yield_SNII.total_metals_IMF_resampled); + swift_free("feedback-tables", feedback_props->lifetimes.mass); + swift_free("feedback-tables", feedback_props->lifetimes.metallicity); + swift_free("feedback-tables", feedback_props->yield_mass_bins); + for (int i = 0; i < eagle_feedback_lifetime_N_metals; i++) { + free(feedback_props->lifetimes.dyingtime[i]); + } + free(feedback_props->lifetimes.dyingtime); + for (int i = 0; i < eagle_feedback_SNIa_N_elements; i++) { + free(feedback_props->SNIa_element_names[i]); + } + free(feedback_props->SNIa_element_names); + for (int i = 0; i < eagle_feedback_SNII_N_elements; i++) { + free(feedback_props->SNII_element_names[i]); + } + free(feedback_props->SNII_element_names); + for (int i = 0; i < eagle_feedback_AGB_N_elements; i++) { + free(feedback_props->AGB_element_names[i]); + } + free(feedback_props->AGB_element_names); +} + /** * @brief Write a feedback struct to the given FILE as a stream of bytes. * diff --git a/src/feedback/EAGLE/feedback.h b/src/feedback/EAGLE/feedback.h index d6237adae9f87ce75b1a4f56f3d358fdc75d103d..9a3b33aa5cfd102b3d429d9c928df70559edbb05 100644 --- a/src/feedback/EAGLE/feedback.h +++ b/src/feedback/EAGLE/feedback.h @@ -34,15 +34,18 @@ void compute_stellar_evolution(const struct feedback_props* feedback_props, const double dt); /** - * @brief Should we do feedback for this star? + * @brief Update the properties of a particle fue to feedback effects after + * the cooling was applied. * - * @param sp The star to consider. + * Nothing to do here in the EAGLE model. + * + * @param p The #part to consider. + * @param xp The #xpart to consider. + * @param e The #engine. */ -__attribute__((always_inline)) INLINE static int feedback_do_feedback( - const struct spart* sp) { - - return (sp->birth_time != -1.); -} +__attribute__((always_inline)) INLINE static void feedback_update_part( + struct part* restrict p, struct xpart* restrict xp, + const struct engine* restrict e) {} /** * @brief Should this particle be doing any feedback-related operation? @@ -56,13 +59,7 @@ __attribute__((always_inline)) INLINE static int feedback_is_active( const struct spart* sp, const float time, const struct cosmology* cosmo, const int with_cosmology) { - if (sp->birth_time == -1.) return 0; - - if (with_cosmology) { - return ((float)cosmo->a) > sp->birth_scale_factor; - } else { - return time > sp->birth_time; - } + return (sp->birth_time != -1.) && (sp->count_since_last_enrichment == 0); } /** @@ -77,6 +74,30 @@ __attribute__((always_inline)) INLINE static void feedback_init_spart( sp->feedback_data.to_collect.ngb_mass = 0.f; } +/** + * @brief Returns the length of time since the particle last did + * enrichment/feedback. + * + * @param sp The #spart. + * @param with_cosmology Are we running with cosmological time integration on? + * @param cosmo The cosmological model. + * @param time The current time (since the Big Bang / start of the run) in + * internal units. + * @param dt_star the length of this particle's time-step in internal units. + * @return The length of the enrichment step in internal units. + */ +INLINE static double feedback_get_enrichment_timestep( + const struct spart* sp, const int with_cosmology, + const struct cosmology* cosmo, const double time, const double dt_star) { + + if (with_cosmology) { + return cosmology_get_delta_time_from_scale_factors( + cosmo, (double)sp->last_enrichment_time, cosmo->a); + } else { + return time - sp->last_enrichment_time; + } +} + /** * @brief Prepares a star's feedback field before computing what * needs to be distributed. @@ -150,14 +171,20 @@ __attribute__((always_inline)) INLINE static void feedback_prepare_spart( * @param feedback_props The #feedback_props structure. * @param cosmo The current cosmological model. * @param us The unit system. + * @param phys_const The physical constants in internal units. * @param star_age_beg_step The age of the star at the star of the time-step in * internal units. * @param dt The time-step size of this star in internal units. + * @param time The physical time in internal units. + * @param ti_begin The integer time at the beginning of the step. + * @param with_cosmology Are we running with cosmology on? */ __attribute__((always_inline)) INLINE static void feedback_evolve_spart( struct spart* restrict sp, const struct feedback_props* feedback_props, const struct cosmology* cosmo, const struct unit_system* us, - const double star_age_beg_step, const double dt) { + const struct phys_const* phys_const, const double star_age_beg_step, + const double dt, const double time, const integertime_t ti_begin, + const int with_cosmology) { #ifdef SWIFT_DEBUG_CHECKS if (sp->birth_time == -1.) error("Evolving a star particle that should not!"); @@ -170,10 +197,107 @@ __attribute__((always_inline)) INLINE static void feedback_evolve_spart( /* Decrease star mass by amount of mass distributed to gas neighbours */ sp->mass -= sp->feedback_data.to_distribute.mass; + + /* Mark this is the last time we did enrichment */ + if (with_cosmology) + sp->last_enrichment_time = cosmo->a; + else + sp->last_enrichment_time = time; } +/** + * @brief Will this star particle want to do feedback during the next time-step? + * + * @param sp The star of interest. + * @param feedback_props The properties of the feedback model. + * @param with_cosmology Are we running a cosmological problem? + * @param cosmo The cosmological model. + * @param time The current time (since the start of the run / Big Bang). + */ +__attribute__((always_inline)) INLINE static int feedback_will_do_feedback( + struct spart* restrict sp, const struct feedback_props* feedback_props, + const int with_cosmology, const struct cosmology* cosmo, + const double time) { + + /* Special case for new-born stars */ + if (with_cosmology) { + if (sp->birth_scale_factor == (float)cosmo->a) { + + /* Set the counter to "let's do enrichment" */ + sp->count_since_last_enrichment = 0; + + /* Say we want to do feedback */ + return 1; + } + } else { + if (sp->birth_time == (float)time) { + + /* Set the counter to "let's do enrichment" */ + sp->count_since_last_enrichment = 0; + + /* Say we want to do feedback */ + return 1; + } + } + + /* Calculate age of the star at current time */ + double age_of_star; + if (with_cosmology) { + age_of_star = cosmology_get_delta_time_from_scale_factors( + cosmo, (double)sp->birth_scale_factor, cosmo->a); + } else { + age_of_star = time - (double)sp->birth_time; + } + + /* Is the star still young? */ + if (age_of_star < feedback_props->stellar_evolution_age_cut) { + + /* Set the counter to "let's do enrichment" */ + sp->count_since_last_enrichment = 0; + + /* Say we want to do feedback */ + return 1; + + } else { + + /* Increment counter */ + sp->count_since_last_enrichment++; + + if ((sp->count_since_last_enrichment % + feedback_props->stellar_evolution_sampling_rate) == 0) { + + /* Reset counter */ + sp->count_since_last_enrichment = 0; + + /* Say we want to do feedback */ + return 1; + + } else { + + /* Say we don't want to do feedback */ + return 0; + } + } +} + +void feedback_clean(struct feedback_props* feedback_props); + void feedback_struct_dump(const struct feedback_props* feedback, FILE* stream); void feedback_struct_restore(struct feedback_props* feedback, FILE* stream); +#ifdef HAVE_HDF5 +/** + * @brief Writes the current model of feedback to the file + * + * @param feedback The properties of the feedback scheme. + * @param h_grp The HDF5 group in which to write. + */ +INLINE static void feedback_write_flavour(struct feedback_props* feedback, + hid_t h_grp) { + + io_write_attribute_s(h_grp, "Feedback Model", "EAGLE"); +}; +#endif // HAVE_HDF5 + #endif /* SWIFT_FEEDBACK_EAGLE_H */ diff --git a/src/feedback/EAGLE/feedback_iact.h b/src/feedback/EAGLE/feedback_iact.h index c9e84a0b8be52f48c264baf146447f9036fec799..7715e3a8b3af096df16c5de7926795e32c587004 100644 --- a/src/feedback/EAGLE/feedback_iact.h +++ b/src/feedback/EAGLE/feedback_iact.h @@ -21,6 +21,8 @@ /* Local includes */ #include "random.h" +#include "timestep_sync_part.h" +#include "tracers.h" /** * @brief Density interaction between two particles (non-symmetric). @@ -38,18 +40,16 @@ __attribute__((always_inline)) INLINE static void runner_iact_nonsym_feedback_density(const float r2, const float *dx, const float hi, const float hj, - struct spart *restrict si, - const struct part *restrict pj, - const struct xpart *restrict xpj, - const struct cosmology *restrict cosmo, + struct spart *si, const struct part *pj, + const struct xpart *xpj, + const struct cosmology *cosmo, const integertime_t ti_current) { /* Get the gas mass. */ const float mj = hydro_get_mass(pj); - /* Get r and 1/r. */ - const float r_inv = 1.0f / sqrtf(r2); - const float r = r2 * r_inv; + /* Get r. */ + const float r = sqrtf(r2); /* Compute the kernel function */ const float hi_inv = 1.0f / hi; @@ -87,15 +87,18 @@ runner_iact_nonsym_feedback_density(const float r2, const float *dx, __attribute__((always_inline)) INLINE static void runner_iact_nonsym_feedback_apply(const float r2, const float *dx, const float hi, const float hj, - const struct spart *restrict si, - struct part *restrict pj, - struct xpart *restrict xpj, - const struct cosmology *restrict cosmo, + const struct spart *si, struct part *pj, + struct xpart *xpj, + const struct cosmology *cosmo, const integertime_t ti_current) { - /* Get r and 1/r. */ - const float r_inv = 1.0f / sqrtf(r2); - const float r = r2 * r_inv; +#ifdef SWIFT_DEBUG_CHECKS + if (si->count_since_last_enrichment != 0) + error("Computing feedback from a star that should not"); +#endif + + /* Get r. */ + const float r = sqrtf(r2); /* Compute the kernel function */ const float hi_inv = 1.0f / hi; @@ -115,9 +118,11 @@ runner_iact_nonsym_feedback_apply(const float r2, const float *dx, } #ifdef SWIFT_DEBUG_CHECKS - if (Omega_frac < 0. || Omega_frac > 1.00001) - error("Invalid fraction of material to distribute. Omega_frac=%e", - Omega_frac); + if (Omega_frac < 0. || Omega_frac > 1.01) + error( + "Invalid fraction of material to distribute for star ID=%lld " + "Omega_frac=%e count since last enrich=%d", + si->id, Omega_frac, si->count_since_last_enrichment); #endif /* Update particle mass */ @@ -275,7 +280,7 @@ runner_iact_nonsym_feedback_apply(const float r2, const float *dx, /* Draw a random number (Note mixing both IDs) */ const float rand = random_unit_interval(si->id + pj->id, ti_current, - random_number_stellar_feedback); + random_number_stellar_feedback_1); /* Are we lucky? */ if (rand < prob) { @@ -291,10 +296,16 @@ runner_iact_nonsym_feedback_apply(const float r2, const float *dx, /* Impose maximal viscosity */ hydro_diffusive_feedback_reset(pj); + /* Mark this particle has having been heated by supernova feedback */ + tracers_after_feedback(xpj); + /* message( */ /* "We did some heating! id %llu star id %llu probability %.5e " */ /* "random_num %.5e du %.5e du/ini %.5e", */ /* pj->id, si->id, prob, rand, delta_u, delta_u / u_init); */ + + /* Synchronize the particle on the timeline */ + timestep_sync_part(pj); } } } diff --git a/src/feedback/EAGLE/feedback_properties.h b/src/feedback/EAGLE/feedback_properties.h index 63928b59c153951747af0dcc5151bb7b118814d7..55822742587e9e7f40e25f4d8c2d3bd9c91f0d33 100644 --- a/src/feedback/EAGLE/feedback_properties.h +++ b/src/feedback/EAGLE/feedback_properties.h @@ -71,6 +71,18 @@ struct lifetime_table { double **dyingtime; }; +/** + * @brief Functional form of the SNIa delay time distribution. + */ +enum eagle_feedback_SNIa_DTD { + + /*! Power-law with slope -1 */ + eagle_feedback_SNIa_DTD_power_law = 1, + + /*! Exponential model (EAGLE default) */ + eagle_feedback_SNIa_DTD_exponential = 2 +}; + /** * @brief Properties of the EAGLE feedback model. */ @@ -127,20 +139,25 @@ struct feedback_props { /* ------------- SNIa parameters --------------- */ - /*! Efficiency of the SNIa model */ - float SNIa_efficiency; + /* What delay time distribution are we using? */ + enum eagle_feedback_SNIa_DTD SNIa_DTD; + + /*! Normalisation of the SNIa DTD in the exponential model */ + float SNIa_DTD_exp_norm; - /*! Time-scale of the SNIa decay function in Giga-years */ - float SNIa_timescale_Gyr; + /*! Time-scale of the SNIa decay function in the exponential model in + * Giga-years */ + float SNIa_DTD_exp_timescale_Gyr; - /*! Inverse of time-scale of the SNIa decay function in Giga-years */ - float SNIa_timescale_Gyr_inv; + /*! Inverse of time-scale of the SNIa decay function in the exponential model + * in Giga-years */ + float SNIa_DTD_exp_timescale_Gyr_inv; - /*! Maximal mass used for SNIa feedback (in solar masses) */ - double SNIa_max_mass_msun; + /*! Normalisation of the SNIa DTD in the power-law model */ + float SNIa_DTD_power_law_norm; - /*! Log 10 of the maximal mass used for SNIa feedback (in solar masses) */ - double log10_SNIa_max_mass_msun; + /*! Stellar age below which no SNIa explode in Giga-years */ + float SNIa_DTD_delay_Gyr; /*! Energy released by one supernova type II in cgs units */ double E_SNIa_cgs; @@ -195,6 +212,12 @@ struct feedback_props { /* ------------ SNe feedback properties ------------ */ + /*! Minimal stellar mass considered for SNII feedback (in solar masses) */ + double SNII_min_mass_msun; + + /*! Maximal stellar mass considered for SNII feedback (in solar masses) */ + double SNII_max_mass_msun; + /*! Log 10 of the minimal stellar mass considered for SNII feedback (in solar * masses) */ double log10_SNII_min_mass_msun; @@ -206,7 +229,10 @@ struct feedback_props { /*! Number of type II supernovae per solar mass */ float num_SNII_per_msun; - /*! Wind delay time for SNII */ + /*! Are we sampling the SNII life-times or using a fixed delay? */ + int SNII_sampled_delay; + + /*! Wind delay time for SNII when using a fixed delay */ double SNII_wind_delay; /*! Temperature increase induced by SNe feedback */ @@ -238,6 +264,15 @@ struct feedback_props { /*! Slope of the metallicity dependance of the feedback energy fraction model */ double n_Z; + + /* ------------ Enrichment sampling properties ------------ */ + + /*! Star age above which the enrichment will be downsampled (in internal + * units) */ + double stellar_evolution_age_cut; + + /*! Number of time-steps in-between two enrichment events */ + int stellar_evolution_sampling_rate; }; void feedback_props_init(struct feedback_props *fp, diff --git a/src/feedback/EAGLE/feedback_struct.h b/src/feedback/EAGLE/feedback_struct.h index 3c69e8b11a36fc5bbb763270f865b82ea51dc58d..000a14471987f4bed9b6605768d5fa68f281b7f2 100644 --- a/src/feedback/EAGLE/feedback_struct.h +++ b/src/feedback/EAGLE/feedback_struct.h @@ -21,6 +21,11 @@ #include "chemistry_struct.h" +/** + * @brief Feedback fields carried by each hydro particles + */ +struct feedback_part_data {}; + /** * @brief Feedback fields carried by each star particles */ @@ -43,6 +48,8 @@ struct feedback_spart_data { /** * @brief Values to be distributed to the gas neighbours. + * + * WARNING: The first two elements must be the enrichment_weight and mass!! */ struct { diff --git a/src/feedback/EAGLE/yield_tables.h b/src/feedback/EAGLE/yield_tables.h index 435826f7f94559f094e5e27be31a3ef32d064de1..036ea45bc2644e4c74af70f32533212ebd6fdd01 100644 --- a/src/feedback/EAGLE/yield_tables.h +++ b/src/feedback/EAGLE/yield_tables.h @@ -90,8 +90,9 @@ INLINE static void read_yield_tables(struct feedback_props *feedback_props) { /* filenames to read HDF5 files */ char fname[256], setname[100]; + char **temp; - hid_t file_id, dataset, datatype; + hid_t file_id, dataset, dataset2, datatype, dataspace; herr_t status; /* Open SNIa tables for reading */ @@ -99,17 +100,33 @@ INLINE static void read_yield_tables(struct feedback_props *feedback_props) { file_id = H5Fopen(fname, H5F_ACC_RDONLY, H5P_DEFAULT); if (file_id < 0) error("unable to open file %s\n", fname); - /* read element name array */ + /* read element name array into temporary array */ datatype = H5Tcopy(H5T_C_S1); H5Tset_size(datatype, H5T_VARIABLE); dataset = H5Dopen(file_id, "Species_names", H5P_DEFAULT); - status = H5Dread(dataset, datatype, H5S_ALL, H5S_ALL, H5P_DEFAULT, - feedback_props->SNIa_element_names); + dataspace = H5Dget_space(dataset); + + temp = (char **)malloc(eagle_feedback_SNIa_N_elements * sizeof(char *)); + status = H5Dread(dataset, datatype, H5S_ALL, H5S_ALL, H5P_DEFAULT, temp); if (status < 0) error("error reading SNIa element names"); + + /* Copy the element names into their final destination */ + for (int i = 0; i < eagle_feedback_SNIa_N_elements; i++) { + memcpy(feedback_props->SNIa_element_names[i], temp[i], strlen(temp[i])); + } + + /* Release the memory allocated by HDF5 for the strings */ + status = H5Dvlen_reclaim(datatype, dataspace, H5P_DEFAULT, temp); + if (status < 0) error("error freeing string memory"); status = H5Dclose(dataset); if (status < 0) error("error closing dataset"); status = H5Tclose(datatype); if (status < 0) error("error closing datatype"); + status = H5Sclose(dataspace); + if (status < 0) error("error closing dataspace"); + + /* Free the temporary memory */ + free(temp); /* read SNIa yields */ dataset = H5Dopen(file_id, "Yield", H5P_DEFAULT); @@ -130,22 +147,40 @@ INLINE static void read_yield_tables(struct feedback_props *feedback_props) { status = H5Fclose(file_id); if (status < 0) error("error closing SNIa file"); + /**************************************************************************/ + /* Open SNII tables for reading */ sprintf(fname, "%s/SNII.hdf5", feedback_props->yield_table_path); file_id = H5Fopen(fname, H5F_ACC_RDONLY, H5P_DEFAULT); if (file_id < 0) error("unable to open file %s\n", fname); - /* read element name array */ + /* read element name array into temporary array */ datatype = H5Tcopy(H5T_C_S1); H5Tset_size(datatype, H5T_VARIABLE); dataset = H5Dopen(file_id, "Species_names", H5P_DEFAULT); - status = H5Dread(dataset, datatype, H5S_ALL, H5S_ALL, H5P_DEFAULT, - feedback_props->SNII_element_names); + dataspace = H5Dget_space(dataset); + + temp = (char **)malloc(eagle_feedback_SNII_N_elements * sizeof(char *)); + status = H5Dread(dataset, datatype, H5S_ALL, H5S_ALL, H5P_DEFAULT, temp); if (status < 0) error("error reading SNII element names"); + + /* Copy the element names into their final destination */ + for (int i = 0; i < eagle_feedback_SNII_N_elements; i++) { + memcpy(feedback_props->SNII_element_names[i], temp[i], strlen(temp[i])); + } + + /* Release the memory allocated by HDF5 for the strings */ + status = H5Dvlen_reclaim(datatype, dataspace, H5P_DEFAULT, temp); + if (status < 0) error("error freeing string memory"); status = H5Dclose(dataset); if (status < 0) error("error closing dataset"); status = H5Tclose(datatype); if (status < 0) error("error closing datatype"); + status = H5Sclose(dataspace); + if (status < 0) error("error closing dataspace"); + + /* Free the temporary memory */ + free(temp); /* read array of masses */ dataset = H5Dopen(file_id, "Masses", H5P_DEFAULT); @@ -173,14 +208,12 @@ INLINE static void read_yield_tables(struct feedback_props *feedback_props) { /* read metallicity names */ datatype = H5Tcopy(H5T_C_S1); H5Tset_size(datatype, H5T_VARIABLE); - dataset = H5Dopen(file_id, "Yield_names", H5P_DEFAULT); - status = H5Dread(dataset, datatype, H5S_ALL, H5S_ALL, H5P_DEFAULT, + dataset2 = H5Dopen(file_id, "Yield_names", H5P_DEFAULT); + dataspace = H5Dget_space(dataset2); + + status = H5Dread(dataset2, datatype, H5S_ALL, H5S_ALL, H5P_DEFAULT, metallicity_yield_table_name_SNII); if (status < 0) error("error reading yield table names"); - status = H5Dclose(dataset); - if (status < 0) error("error closing dataset"); - status = H5Tclose(datatype); - if (status < 0) error("error closing datatype"); /* read SNII yield tables */ for (int i = 0; i < eagle_feedback_SNII_N_metals; i++) { @@ -233,9 +266,22 @@ INLINE static void read_yield_tables(struct feedback_props *feedback_props) { } } + /* Release the memory allocated by HDF5 for the strings */ + status = H5Dvlen_reclaim(datatype, dataspace, H5P_DEFAULT, + metallicity_yield_table_name_SNII); + if (status < 0) error("error freeing string memory"); + status = H5Dclose(dataset2); + if (status < 0) error("error closing dataset"); + status = H5Tclose(datatype); + if (status < 0) error("error closing datatype"); + status = H5Sclose(dataspace); + if (status < 0) error("error closing dataspace"); + status = H5Fclose(file_id); if (status < 0) error("error closing file"); + /**************************************************************************/ + /* Read AGB tables */ sprintf(fname, "%s/AGB.hdf5", feedback_props->yield_table_path); file_id = H5Fopen(fname, H5F_ACC_RDONLY, H5P_DEFAULT); @@ -245,13 +291,29 @@ INLINE static void read_yield_tables(struct feedback_props *feedback_props) { datatype = H5Tcopy(H5T_C_S1); H5Tset_size(datatype, H5T_VARIABLE); dataset = H5Dopen(file_id, "Species_names", H5P_DEFAULT); - status = H5Dread(dataset, datatype, H5S_ALL, H5S_ALL, H5P_DEFAULT, - feedback_props->AGB_element_names); + dataspace = H5Dget_space(dataset); + + temp = (char **)malloc(eagle_feedback_AGB_N_elements * sizeof(char *)); + status = H5Dread(dataset, datatype, H5S_ALL, H5S_ALL, H5P_DEFAULT, temp); if (status < 0) error("error reading AGB element names"); + + /* Copy the element names into their final destination */ + for (int i = 0; i < eagle_feedback_AGB_N_elements; i++) { + memcpy(feedback_props->AGB_element_names[i], temp[i], strlen(temp[i])); + } + + /* Release the memory allocated by HDF5 for the strings */ + status = H5Dvlen_reclaim(datatype, dataspace, H5P_DEFAULT, temp); + if (status < 0) error("error freeing string memory"); status = H5Dclose(dataset); if (status < 0) error("error closing dataset"); status = H5Tclose(datatype); if (status < 0) error("error closing datatype"); + status = H5Sclose(dataspace); + if (status < 0) error("error closing dataspace"); + + /* Free the temporary memory */ + free(temp); /* read array of masses */ dataset = H5Dopen(file_id, "Masses", H5P_DEFAULT); @@ -279,14 +341,12 @@ INLINE static void read_yield_tables(struct feedback_props *feedback_props) { /* read metallicity names */ datatype = H5Tcopy(H5T_C_S1); H5Tset_size(datatype, H5T_VARIABLE); - dataset = H5Dopen(file_id, "Yield_names", H5P_DEFAULT); - status = H5Dread(dataset, datatype, H5S_ALL, H5S_ALL, H5P_DEFAULT, + dataset2 = H5Dopen(file_id, "Yield_names", H5P_DEFAULT); + dataspace = H5Dget_space(dataset2); + + status = H5Dread(dataset2, datatype, H5S_ALL, H5S_ALL, H5P_DEFAULT, metallicity_yield_table_name_AGB); if (status < 0) error("error reading yield table names"); - status = H5Dclose(dataset); - if (status < 0) error("error closing dataset"); - status = H5Tclose(datatype); - if (status < 0) error("error closing datatype"); /* read AGB yield tables */ for (int i = 0; i < eagle_feedback_AGB_N_metals; i++) { @@ -338,6 +398,17 @@ INLINE static void read_yield_tables(struct feedback_props *feedback_props) { } } + /* Release the memory allocated by HDF5 for the strings */ + status = H5Dvlen_reclaim(datatype, dataspace, H5P_DEFAULT, + metallicity_yield_table_name_AGB); + if (status < 0) error("error freeing string memory"); + status = H5Dclose(dataset2); + if (status < 0) error("error closing dataset"); + status = H5Tclose(datatype); + if (status < 0) error("error closing datatype"); + status = H5Sclose(dataspace); + if (status < 0) error("error closing dataspace"); + status = H5Fclose(file_id); if (status < 0) error("error closing file"); @@ -579,18 +650,24 @@ INLINE static void allocate_yield_tables( for (int i = 0; i < eagle_feedback_SNIa_N_elements; i++) { feedback_props->SNIa_element_names[i] = (char *)malloc(eagle_feedback_element_name_length * sizeof(char)); + memset(feedback_props->SNIa_element_names[i], 0, + eagle_feedback_element_name_length); } feedback_props->SNII_element_names = (char **)malloc(eagle_feedback_SNII_N_elements * sizeof(char *)); for (int i = 0; i < eagle_feedback_SNII_N_elements; i++) { feedback_props->SNII_element_names[i] = (char *)malloc(eagle_feedback_element_name_length * sizeof(char)); + memset(feedback_props->SNII_element_names[i], 0, + eagle_feedback_element_name_length); } feedback_props->AGB_element_names = (char **)malloc(eagle_feedback_AGB_N_elements * sizeof(char *)); for (int i = 0; i < eagle_feedback_AGB_N_elements; i++) { feedback_props->AGB_element_names[i] = (char *)malloc(eagle_feedback_element_name_length * sizeof(char)); + memset(feedback_props->AGB_element_names[i], 0, + eagle_feedback_element_name_length); } /* Allocate array of IMF mass bins */ diff --git a/src/feedback/GEAR/feedback.c b/src/feedback/GEAR/feedback.c new file mode 100644 index 0000000000000000000000000000000000000000..7b498fd2ca840e6c8d31376f25909103ae997825 --- /dev/null +++ b/src/feedback/GEAR/feedback.c @@ -0,0 +1,279 @@ +/******************************************************************************* + * This file is part of SWIFT. + * Copyright (c) 2018 Loic Hausammann (loic.hausammann@epfl.ch) + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published + * by the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this program. If not, see <http://www.gnu.org/licenses/>. + * + ******************************************************************************/ + +/* Include header */ +#include "feedback.h" + +/* Local includes */ +#include "cosmology.h" +#include "engine.h" +#include "error.h" +#include "feedback_properties.h" +#include "hydro_properties.h" +#include "part.h" +#include "stellar_evolution.h" +#include "units.h" + +#include <strings.h> + +/** + * @brief Update the properties of the particle due to a supernovae. + * + * @param p The #part to consider. + * @param xp The #xpart to consider. + * @param cosmo The #cosmology. + */ +void feedback_update_part(struct part* restrict p, struct xpart* restrict xp, + const struct engine* restrict e) { + + /* Did the particle receive a supernovae */ + if (xp->feedback_data.delta_mass == 0) return; + + const struct cosmology* cosmo = e->cosmology; + + /* Turn off the cooling */ + xp->cooling_data.time_last_event = e->time; + + /* Update mass */ + const float old_mass = hydro_get_mass(p); + const float new_mass = old_mass + xp->feedback_data.delta_mass; + + if (xp->feedback_data.delta_mass < 0.) { + error("Delta mass smaller than 0"); + } + + hydro_set_mass(p, new_mass); + + xp->feedback_data.delta_mass = 0; + + /* Update the density */ + p->rho *= new_mass / old_mass; + + /* Update internal energy */ + const float u = hydro_get_physical_internal_energy(p, xp, cosmo); + const float u_new = u + xp->feedback_data.delta_u; + + hydro_set_physical_internal_energy(p, xp, cosmo, u_new); + hydro_set_drifted_physical_internal_energy(p, cosmo, u_new); + + xp->feedback_data.delta_u = 0.; + + /* Update the velocities */ + for (int i = 0; i < 3; i++) { + const float dv = xp->feedback_data.delta_p[i] / new_mass; + + xp->v_full[i] += dv; + p->v[i] += dv; + + xp->feedback_data.delta_p[i] = 0; + } +} + +/** + * @Brief Should we do feedback for this star? + * + * @param sp The star to consider. + */ +int feedback_will_do_feedback(const struct spart* sp, + const struct feedback_props* feedback_props, + const int with_cosmology, + const struct cosmology* cosmo, + const double time) { + + return (sp->birth_time != -1.); +} + +/** + * @brief Should this particle be doing any feedback-related operation? + * + * @param sp The #spart. + * @param time The current simulation time (Non-cosmological runs). + * @param cosmo The cosmological model (cosmological runs). + * @param with_cosmology Are we doing a cosmological run? + */ +int feedback_is_active(const struct spart* sp, const double time, + const struct cosmology* cosmo, + const int with_cosmology) { + + if (sp->birth_time == -1.) return 0; + + if (with_cosmology) { + return ((double)cosmo->a) > sp->birth_scale_factor; + } else { + return time > sp->birth_time; + } +} + +/** + * @brief Returns the length of time since the particle last did + * enrichment/feedback. + * + * @param sp The #spart. + * @param with_cosmology Are we running with cosmological time integration on? + * @param cosmo The cosmological model. + * @param time The current time (since the Big Bang / start of the run) in + * internal units. + * @param dt_star the length of this particle's time-step in internal units. + * @return The length of the enrichment step in internal units. + */ +double feedback_get_enrichment_timestep(const struct spart* sp, + const int with_cosmology, + const struct cosmology* cosmo, + const double time, + const double dt_star) { + return dt_star; +} + +/** + * @brief Prepares a s-particle for its feedback interactions + * + * @param sp The particle to act upon + */ +void feedback_init_spart(struct spart* sp) { + + sp->feedback_data.enrichment_weight = 0.f; +} + +/** + * @brief Prepares a star's feedback field before computing what + * needs to be distributed. + */ +void feedback_reset_feedback(struct spart* sp, + const struct feedback_props* feedback_props) { + + /* Zero the energy of supernovae */ + sp->feedback_data.energy_ejected = 0; +} + +/** + * @brief Initialises the s-particles feedback props for the first time + * + * This function is called only once just after the ICs have been + * read in to do some conversions. + * + * @param sp The particle to act upon. + * @param feedback_props The properties of the feedback model. + */ +void feedback_first_init_spart(struct spart* sp, + const struct feedback_props* feedback_props) { + + feedback_init_spart(sp); + + feedback_reset_feedback(sp, feedback_props); +} + +/** + * @brief Initialises the s-particles feedback props for the first time + * + * This function is called only once just after the ICs have been + * read in to do some conversions. + * + * @param sp The particle to act upon. + * @param feedback_props The properties of the feedback model. + */ +void feedback_prepare_spart(struct spart* sp, + const struct feedback_props* feedback_props) {} + +/** + * @brief Evolve the stellar properties of a #spart. + * + * This function compute the SN rate and yields before sending + * this information to a different MPI rank. + * + * @param sp The particle to act upon + * @param feedback_props The #feedback_props structure. + * @param cosmo The current cosmological model. + * @param us The unit system. + * @param phys_const The #phys_const. + * @param star_age_beg_step The age of the star at the star of the time-step in + * internal units. + * @param dt The time-step size of this star in internal units. + * @param time The physical time in internal units. + * @param ti_begin The integer time at the beginning of the step. + * @param with_cosmology Are we running with cosmology on? + */ +void feedback_evolve_spart(struct spart* restrict sp, + const struct feedback_props* feedback_props, + const struct cosmology* cosmo, + const struct unit_system* us, + const struct phys_const* phys_const, + const double star_age_beg_step, const double dt, + const double time, const integertime_t ti_begin, + const int with_cosmology) { + +#ifdef SWIFT_DEBUG_CHECKS + if (sp->birth_time == -1.) error("Evolving a star particle that should not!"); +#endif + + /* Reset the feedback */ + feedback_reset_feedback(sp, feedback_props); + + /* Add missing h factor */ + const float hi_inv = 1.f / sp->h; + const float hi_inv_dim = pow_dimension(hi_inv); /* 1/h^d */ + + sp->feedback_data.enrichment_weight *= hi_inv_dim; + + /* Compute the stellar evolution */ + stellar_evolution_evolve_spart(sp, &feedback_props->stellar_model, cosmo, us, + phys_const, ti_begin, star_age_beg_step, dt); + + /* Transform the number of SN to the energy */ + sp->feedback_data.energy_ejected = + sp->feedback_data.number_sn * feedback_props->energy_per_supernovae; +} + +/** + * @brief Write a feedback struct to the given FILE as a stream of bytes. + * + * @param feedback the struct + * @param stream the file stream + */ +void feedback_struct_dump(const struct feedback_props* feedback, FILE* stream) { + + restart_write_blocks((void*)feedback, sizeof(struct feedback_props), 1, + stream, "feedback", "feedback function"); + + stellar_evolution_dump(&feedback->stellar_model, stream); +} + +/** + * @brief Restore a feedback struct from the given FILE as a stream of + * bytes. + * + * @param feedback the struct + * @param stream the file stream + */ +void feedback_struct_restore(struct feedback_props* feedback, FILE* stream) { + + restart_read_blocks((void*)feedback, sizeof(struct feedback_props), 1, stream, + NULL, "feedback function"); + + stellar_evolution_restore(&feedback->stellar_model, stream); +} + +/** + * @brief Clean the allocated memory. + * + * @param feedback the #feedback_props. + */ +void feedback_clean(struct feedback_props* feedback) { + + stellar_evolution_clean(&feedback->stellar_model); +} diff --git a/src/feedback/GEAR/feedback.h b/src/feedback/GEAR/feedback.h new file mode 100644 index 0000000000000000000000000000000000000000..1f333b39f73da45157d04812d13c374d2a9dc5e8 --- /dev/null +++ b/src/feedback/GEAR/feedback.h @@ -0,0 +1,85 @@ +/******************************************************************************* + * This file is part of SWIFT. + * Copyright (c) 2018 Loic Hausammann (loic.hausammann@epfl.ch) + * + * 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_FEEDBACK_GEAR_H +#define SWIFT_FEEDBACK_GEAR_H + +#include "cosmology.h" +#include "error.h" +#include "feedback_properties.h" +#include "hydro_properties.h" +#include "part.h" +#include "stellar_evolution.h" +#include "units.h" + +#include <strings.h> + +void feedback_update_part(struct part* restrict p, struct xpart* restrict xp, + const struct engine* restrict e); + +int feedback_will_do_feedback(const struct spart* sp, + const struct feedback_props* feedback_props, + const int with_cosmology, + const struct cosmology* cosmo, const double time); + +int feedback_is_active(const struct spart* sp, const double time, + const struct cosmology* cosmo, const int with_cosmology); +double feedback_get_enrichment_timestep(const struct spart* sp, + const int with_cosmology, + const struct cosmology* cosmo, + const double time, + const double dt_star); +void feedback_init_spart(struct spart* sp); + +void feedback_reset_feedback(struct spart* sp, + const struct feedback_props* feedback_props); +void feedback_first_init_spart(struct spart* sp, + const struct feedback_props* feedback_props); +void feedback_prepare_spart(struct spart* sp, + const struct feedback_props* feedback_props); +void feedback_evolve_spart(struct spart* restrict sp, + const struct feedback_props* feedback_props, + const struct cosmology* cosmo, + const struct unit_system* us, + const struct phys_const* phys_const, + const double star_age_beg_step, const double dt, + const double time, const integertime_t ti_begin, + const int with_cosmology); +void feedback_struct_dump(const struct feedback_props* feedback, FILE* stream); +void feedback_struct_restore(struct feedback_props* feedback, FILE* stream); +void feedback_clean(struct feedback_props* feedback); + +/** + * @brief Writes the current model of feedback to the file + * @param h_grpsph The HDF5 group in which to write + */ +INLINE static void feedback_write_flavour(struct feedback_props* feedback, + hid_t h_grp) { + + io_write_attribute_s(h_grp, "Feedback Model", "GEAR"); + + for (int i = 0; i < GEAR_CHEMISTRY_ELEMENT_COUNT; i++) { + char buffer[20]; + sprintf(buffer, "Element %d", (int)i); + io_write_attribute_s( + h_grp, buffer, + stellar_evolution_get_element_name(&feedback->stellar_model, i)); + } +}; + +#endif /* SWIFT_FEEDBACK_GEAR_H */ diff --git a/src/feedback/GEAR/feedback_iact.h b/src/feedback/GEAR/feedback_iact.h new file mode 100644 index 0000000000000000000000000000000000000000..93c37cadc2d1c5e132258bfd6506802e1b3a3848 --- /dev/null +++ b/src/feedback/GEAR/feedback_iact.h @@ -0,0 +1,148 @@ +/******************************************************************************* + * This file is part of SWIFT. + * Coypright (c) 2018 Loic Hausammann (loic.hausammann@epfl.ch) + * + * 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_GEAR_FEEDBACK_IACT_H +#define SWIFT_GEAR_FEEDBACK_IACT_H + +/* Local includes */ +#include "hydro.h" +#include "random.h" +#include "timestep_sync_part.h" + +/** + * @brief Density interaction between two particles (non-symmetric). + * + * @param r2 Comoving square distance between the two particles. + * @param dx Comoving vector separating both particles (pi - pj). + * @param hi Comoving smoothing-length of particle i. + * @param hj Comoving smoothing-length of particle j. + * @param si First sparticle. + * @param pj Second particle (not updated). + * @param xpj Extra particle data (not updated). + * @param cosmo The cosmological model. + * @param ti_current Current integer time value + */ +__attribute__((always_inline)) INLINE static void +runner_iact_nonsym_feedback_density(const float r2, const float *dx, + const float hi, const float hj, + struct spart *restrict si, + const struct part *restrict pj, + const struct xpart *restrict xpj, + const struct cosmology *restrict cosmo, + const integertime_t ti_current) { + + /* Get the gas mass. */ + const float mj = hydro_get_mass(pj); + + /* Get r and 1/r. */ + const float r_inv = 1.0f / sqrtf(r2); + const float r = r2 * r_inv; + + /* Compute the kernel function */ + const float hi_inv = 1.0f / hi; + const float ui = r * hi_inv; + float wi; + kernel_eval(ui, &wi); + + /* Add contribution of pj to normalisation of density weighted fraction + * which determines how much mass to distribute to neighbouring + * gas particles */ + + /* The normalization by 1 / h^d is done in feedback.h */ + si->feedback_data.enrichment_weight += mj * wi; +} + +/** + * @brief Feedback interaction between two particles (non-symmetric). + * Used for updating properties of gas particles neighbouring a star particle + * + * @param r2 Comoving square distance between the two particles. + * @param dx Comoving vector separating both particles (si - pj). + * @param hi Comoving smoothing-length of particle i. + * @param hj Comoving smoothing-length of particle j. + * @param si First (star) particle (not updated). + * @param pj Second (gas) particle. + * @param xpj Extra particle data + * @param cosmo The cosmological model. + * @param ti_current Current integer time used value for seeding random number + * generator + */ +__attribute__((always_inline)) INLINE static void +runner_iact_nonsym_feedback_apply(const float r2, const float *dx, + const float hi, const float hj, + struct spart *si, struct part *pj, + struct xpart *xpj, + const struct cosmology *cosmo, + const integertime_t ti_current) { + + const double e_sn = si->feedback_data.energy_ejected; + + /* Do we have supernovae? */ + if (e_sn == 0) { + return; + } + + const float mj = hydro_get_mass(pj); + const float r = sqrtf(r2); + + /* Get the kernel for hi. */ + float hi_inv = 1.0f / hi; + float hi_inv_dim = pow_dimension(hi_inv); /* 1/h^d */ + float xi = r * hi_inv; + float wi, wi_dx; + kernel_deval(xi, &wi, &wi_dx); + wi *= hi_inv_dim; + + /* Compute inverse enrichment weight */ + const double si_inv_weight = si->feedback_data.enrichment_weight == 0 + ? 0. + : 1. / si->feedback_data.enrichment_weight; + + /* Mass received */ + const double m_ej = si->feedback_data.mass_ejected; + // TODO compute inverse before feedback loop + const double weight = mj * wi * si_inv_weight; + const double dm = m_ej * weight; + const double new_mass = mj + dm; + + /* Energy received */ + // TODO compute inverse before feedback loop + const double du = e_sn * weight / new_mass; + + xpj->feedback_data.delta_mass += dm; + xpj->feedback_data.delta_u += du; + + /* Compute momentum received. */ + for (int i = 0; i < 3; i++) { + xpj->feedback_data.delta_p[i] += dm * (si->v[i] - xpj->v_full[i]); + } + + /* Add the metals */ + for (int i = 0; i < GEAR_CHEMISTRY_ELEMENT_COUNT; i++) { + pj->chemistry_data.metal_mass[i] += + weight * si->feedback_data.metal_mass_ejected[i]; + } + + /* Impose maximal viscosity */ + hydro_diffusive_feedback_reset(pj); + + /* Synchronize the particle on the timeline */ + timestep_sync_part(pj); +} + +#endif /* SWIFT_GEAR_FEEDBACK_IACT_H */ diff --git a/src/feedback/GEAR/feedback_properties.h b/src/feedback/GEAR/feedback_properties.h new file mode 100644 index 0000000000000000000000000000000000000000..4b2d4f207b779779b099c9b61fc7ee0b41e27d1b --- /dev/null +++ b/src/feedback/GEAR/feedback_properties.h @@ -0,0 +1,102 @@ +/******************************************************************************* + * This file is part of SWIFT. + * Coypright (c) 2018 Loic Hausammann (loic.hausammann@epfl.ch) + * + * 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_GEAR_FEEDBACK_PROPERTIES_H +#define SWIFT_GEAR_FEEDBACK_PROPERTIES_H + +#include "chemistry.h" +#include "hydro_properties.h" +#include "stellar_evolution.h" +#include "stellar_evolution_struct.h" + +/** + * @brief Properties of the GEAR feedback model. + */ +struct feedback_props { + /*! Energy per supernovae */ + float energy_per_supernovae; + + /*! filename of the chemistry table */ + char filename[PARSER_MAX_LINE_SIZE]; + + /*! The stellar model */ + struct stellar_model stellar_model; +}; + +/** + * @brief Print the feedback model. + * + * @param feedback_props The #feedback_props + */ +__attribute__((always_inline)) INLINE static void feedback_props_print( + const struct feedback_props* feedback_props) { + + /* Only the master print */ + if (engine_rank != 0) { + return; + } + + /* Print the feedback properties */ + message("Energy per supernovae = %.2g", + feedback_props->energy_per_supernovae); + message("Yields table = %s", feedback_props->filename); + + /* Print the stellar model */ + stellar_model_print(&feedback_props->stellar_model); +} + +/** + * @brief Initialize the global properties of the feedback scheme. + * + * By default, takes the values provided by the hydro. + * + * @param fp The #feedback_props. + * @param phys_const The physical constants in the internal unit system. + * @param us The internal unit system. + * @param params The parsed parameters. + * @param hydro_props The already read-in properties of the hydro scheme. + * @param cosmo The cosmological model. + */ +__attribute__((always_inline)) INLINE static void feedback_props_init( + struct feedback_props* fp, const struct phys_const* phys_const, + const struct unit_system* us, struct swift_params* params, + const struct hydro_props* hydro_props, const struct cosmology* cosmo) { + + /* Supernovae energy */ + double e_feedback = + parser_get_param_double(params, "GEARFeedback:supernovae_energy_erg"); + e_feedback /= units_cgs_conversion_factor(us, UNIT_CONV_ENERGY); + fp->energy_per_supernovae = e_feedback; + + /* filename of the chemistry table */ + parser_get_param_string(params, "GEARFeedback:yields_table", fp->filename); + + /* Initialize the stellar model */ + stellar_evolution_props_init(&fp->stellar_model, phys_const, us, params, + cosmo); + + /* Print the stellar properties */ + feedback_props_print(fp); + + /* Print a final message. */ + if (engine_rank == 0) { + message("Stellar feedback initialized"); + } +} + +#endif /* SWIFT_GEAR_FEEDBACK_PROPERTIES_H */ diff --git a/src/feedback/GEAR/feedback_struct.h b/src/feedback/GEAR/feedback_struct.h new file mode 100644 index 0000000000000000000000000000000000000000..cd6e336ed7efa7d7a6aa8dea91748ef7dad48e27 --- /dev/null +++ b/src/feedback/GEAR/feedback_struct.h @@ -0,0 +1,63 @@ +/******************************************************************************* + * This file is part of SWIFT. + * Copyright (c) 2018 Matthieu Schaller (schaller@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_FEEDBACK_STRUCT_GEAR_H +#define SWIFT_FEEDBACK_STRUCT_GEAR_H + +#include "chemistry_struct.h" + +/** + * @brief Feedback fields carried by each hydro particles + */ + +struct feedback_part_data { + /*! mass received from supernovae */ + float delta_mass; + + /*! specific energy received from supernovae */ + float delta_u; + + /*! Momemtum received from a supernovae */ + float delta_p[3]; +}; + +/** + * @brief Feedback fields carried by each star particles + */ +struct feedback_spart_data { + + /*! Inverse of normalisation factor used for the enrichment. */ + float enrichment_weight; + + /* Assign two different names for clarification */ + union { + /*! Number of supernovae */ + float number_sn; + + /*! Energy injected in the surrounding particles */ + float energy_ejected; + }; + + /*! Total mass ejected by the supernovae */ + float mass_ejected; + + /*! Chemical composition of the mass ejected */ + float metal_mass_ejected[GEAR_CHEMISTRY_ELEMENT_COUNT]; +}; + +#endif /* SWIFT_FEEDBACK_STRUCT_GEAR_H */ diff --git a/src/feedback/GEAR/hdf5_functions.h b/src/feedback/GEAR/hdf5_functions.h new file mode 100644 index 0000000000000000000000000000000000000000..3d7e9befa030af97a6f4d6f3ee788e5c553fe0c9 --- /dev/null +++ b/src/feedback/GEAR/hdf5_functions.h @@ -0,0 +1,135 @@ +/******************************************************************************* + * This file is part of SWIFT. + * Copyright (c) 2019 Loic Hausammann (loic.hausammann@epfl.ch) + * + * 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_HDF5_FUNCTIONS_GEAR_H +#define SWIFT_HDF5_FUNCTIONS_GEAR_H + +/* Local includes. */ +#include "chemistry.h" +#include "inline.h" + +/** + * @brief Reads a string attribute (array) from a given HDF5 group. + * + * @param grp The group from which to read. + * @param name The name of the attribute to read. + * @param data (output) The attribute read from the HDF5 group (need to be + * allocated). + * @param number_element Number of elements in the attribute. + * @param size_per_element Maximal size per element in data. + * + * Calls #error() if an error occurs. + */ +__attribute__((always_inline)) INLINE static void +io_read_string_array_attribute(hid_t grp, const char *name, void *data, + hsize_t number_element, + hsize_t size_per_element) { + + /* Open attribute */ + const hid_t h_attr = H5Aopen(grp, name, H5P_DEFAULT); + if (h_attr < 0) error("Error while opening attribute '%s'", name); + + /* Get the number of elements */ + hsize_t count = io_get_number_element_in_attribute(h_attr); + + /* Check if correct number of element */ + if (count != number_element) { + error( + "Error found a different number of elements than expected (%lli != " + "%lli) in attribute %s", + count, number_element, name); + } + + /* Get the string length */ + const hid_t type = H5Aget_type(h_attr); + if (type < 0) error("Failed to get attribute type"); + + size_t sdim = H5Tget_size(type); + + /* Check if the size is correct */ + if (sdim > size_per_element) { + error("Cannot read string longer than %lli in %s", size_per_element, name); + } + + /* Allocate the temporary array */ + char *tmp = malloc(sizeof(char) * sdim * number_element); + if (tmp == NULL) { + error("Failed to allocate the temporary array."); + } + + /* Read attribute */ + const hid_t h_err = H5Aread(h_attr, type, tmp); + if (h_err < 0) error("Error while reading attribute '%s'", name); + + /* Copy the attribute correctly */ + for (hsize_t i = 0; i < number_element; i++) { + char *src = tmp + i * sdim; + char *dest = data + i * size_per_element; + memcpy(dest, src, sdim); + } + + /* Cleanup */ + free(tmp); + H5Aclose(h_attr); +} + +/** + * @brief Open a group in the yields table (#h5_close_group needs to be called). + * + * @param params The @swift_params. + * @param group_name The name of the group to open. + * @param file_id (output) The id of the file opened. + * @param group_id (output) The id of the group opened. + * + */ +__attribute__((always_inline)) INLINE static void h5_open_group( + struct swift_params *params, char *group_name, hid_t *file_id, + hid_t *group_id) { + + /* Get filename. */ + char filename[256]; + parser_get_param_string(params, "GEARFeedback:yields_table", filename); + + /* Open file. */ + *file_id = H5Fopen(filename, H5F_ACC_RDONLY, H5P_DEFAULT); + if (*file_id < 0) error("unable to open file %s.\n", filename); + + /* Open group. */ + *group_id = H5Gopen(*file_id, group_name, H5P_DEFAULT); + if (*group_id < 0) error("unable to open group %s.\n", group_name); +} + +/** + * @brief Close a group in the yields table. + * + * @param file_id The id of the file opened. + * @param group_id The id of the group opened. + * + */ +__attribute__((always_inline)) INLINE static void h5_close_group( + hid_t file_id, hid_t group_id) { + + /* Close group */ + hid_t status = H5Gclose(group_id); + if (status < 0) error("error closing group."); + + /* Close file */ + status = H5Fclose(file_id); + if (status < 0) error("error closing file."); +} +#endif // SWIFT_HDF5_FUNCTIONS_GEAR_H diff --git a/src/feedback/GEAR/initial_mass_function.c b/src/feedback/GEAR/initial_mass_function.c new file mode 100644 index 0000000000000000000000000000000000000000..cb165648d2b60faf8549c808e23052e12c30783d --- /dev/null +++ b/src/feedback/GEAR/initial_mass_function.c @@ -0,0 +1,543 @@ +/******************************************************************************* + * This file is part of SWIFT. + * Copyright (c) 2019 Loic Hausammann (loic.hausammann@epfl.ch) + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published + * by the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this program. If not, see <http://www.gnu.org/licenses/>. + * + ******************************************************************************/ + +/* Include header */ +#include "initial_mass_function.h" + +/* local headers */ +#include "hdf5_functions.h" +#include "stellar_evolution_struct.h" + +/** + * @brief Get the IMF exponent in between mass_min and mass_max. + */ +float initial_mass_function_get_exponent( + const struct initial_mass_function *imf, float mass_min, float mass_max) { + +#ifdef SWIFT_DEBUG_CHECKS + if (mass_max > imf->mass_max) + error("Cannot have mass larger than the largest one in the IMF"); + if (mass_min < imf->mass_min) + error("Cannot have mass smaller than the smallest one in the IMF"); + if (mass_max < mass_min) error("Cannot have mass_min larger than mass_max"); +#endif + + for (int i = 0; i < imf->n_parts; i++) { + + /* Check if in the correct part of the IMF */ + if (mass_min < imf->mass_limits[i + 1]) { + + /* Check if in only one segment */ + if (mass_max > imf->mass_limits[i + 1]) { + error("Cannot get a single exponent for the interval [%g, %g]", + mass_min, mass_max); + } + + return imf->exp[i]; + } + } + + error("Masses outside IMF ranges"); + + return -1; +} + +/** @brief Print the initial mass function */ +void initial_mass_function_print(const struct initial_mass_function *imf) { + + message("Number of parts: %i", imf->n_parts); + message("Mass interval: [%g, %g]", imf->mass_min, imf->mass_max); + for (int i = 0; i < imf->n_parts; i++) { + message("[%g, %g]: %.2g * m^{%g}", imf->mass_limits[i], + imf->mass_limits[i + 1], imf->coef[i], imf->exp[i]); + } +} + +/** + * @brief Integrate the #interpolation_1d data with the initial mass function. + * + * The x are supposed to be linear in log. + * + * @param imf The #initial_mass_function. + * @param interp The #interpolation_1d. + */ +void initial_mass_function_integrate(const struct initial_mass_function *imf, + struct interpolation_1d *interp) { + + /* Index in the data */ + int j = 1; + const float mass_min = pow(10, interp->xmin); + const float mass_max = pow(10, interp->xmin + (interp->N - 1) * interp->dx); + + float m = mass_min; + + float *tmp = (float *)malloc(sizeof(float) * interp->N); + + /* Set lower limit */ + tmp[0] = 0; + for (int i = 0; i < imf->n_parts; i++) { + + /* Check if already in the correct part */ + if (mass_min > imf->mass_limits[i + 1]) { + continue; + } + + /* Check if already above the maximal mass */ + if (mass_max < imf->mass_limits[i]) { + break; + } + + /* Integrate the data */ + while (m < imf->mass_limits[i + 1] && j < interp->N) { + + /* Compute the masses */ + const float log_m1 = interp->xmin + (j - 1) * interp->dx; + const float m1 = pow(10, log_m1); + const float log_m2 = interp->xmin + j * interp->dx; + const float m2 = pow(10, log_m2); + const float dm = m2 - m1; + const float imf_1 = imf->coef[i] * pow(m1, imf->exp[i]); + + /* Get the imf of the upper limit */ + float imf_2; + if (m2 > imf->mass_limits[i + 1]) { + imf_2 = imf->coef[i + 1] * pow(m2, imf->exp[i + 1]); + } else { + imf_2 = imf->coef[i] * pow(m2, imf->exp[i]); + } + + /* Compute the integral */ + tmp[j] = + tmp[j - 1] + + 0.5 * (imf_1 * interp->data[j - 1] + imf_2 * interp->data[j]) * dm; + + /* Update j and m */ + j += 1; + m = m2; + } + } + + /* The rest is extrapolated with 0 */ + for (int k = j; k < interp->N; k++) { + tmp[k] = tmp[k - 1]; + } + + /* Copy temporary array */ + memcpy(interp->data, tmp, interp->N * sizeof(float)); + + /* Update the boundary conditions */ + interp->boundary_condition = boundary_condition_zero_const; + + /* clean everything */ + free(tmp); +} + +/** + * @brief Get the IMF coefficient in between mass_min and mass_max. + * + * @param imf The #initial_mass_function. + * @param mass_min The minimal mass of the requested interval. + * @param mass_max The maximal mass of the requested interval. + * + * @return The imf's coefficient of the interval. + */ +float initial_mass_function_get_coefficient( + const struct initial_mass_function *imf, float mass_min, float mass_max) { + + for (int i = 0; i < imf->n_parts; i++) { + + /* Check if in the correct part of the IMF */ + if (mass_min < imf->mass_limits[i + 1]) { + + /* Check if in only one segment */ + if (mass_max > imf->mass_limits[i + 1]) { + error("Cannot get a single coefficient for the interval [%g, %g]", + mass_min, mass_max); + } + + return imf->coef[i]; + } + } + + error("Masses outside IMF ranges"); + + return -1; +} + +/** + * @brief Compute the integral of the fraction number of the initial mass + * function. + * + * @param imf The #initial_mass_function. + * @param m1 The lower mass to evaluate. + * @param m2 The upper mass to evaluate. + * + * @return The number fraction. + */ +float initial_mass_function_get_integral_xi( + const struct initial_mass_function *imf, float m1, float m2) { + + int k = -1; + /* Find the correct part */ + for (int i = 0; i < imf->n_parts; i++) { + if (m1 <= imf->mass_limits[i + 1]) { + k = i; + break; + } + } + + /* Check if found a part */ + if (k == -1) { + error("Failed to find the correct function part: %g %g", m1, m2); + } + + /* Check if m2 is inside the part */ + if (m2 < imf->mass_limits[k] || m2 > imf->mass_limits[k + 1]) { + error("This function is not able to integrate in two different parts %g %g", + m1, m2); + } + + /* Compute the integral */ + const float int_xi1 = pow(m1, imf->exp[k]); + const float int_xi2 = pow(m2, imf->exp[k]); + + return imf->coef[k] * (int_xi2 - int_xi1) / imf->exp[k]; +}; + +/** + * @brief Compute the mass fraction of the initial mass function. + * + * @param imf The #initial_mass_function. + * @param m The mass to evaluate. + * + * @return The mass fraction. + */ +float initial_mass_function_get_imf(const struct initial_mass_function *imf, + float m) { + +#ifdef SWIFT_DEBUG_CHECKS + if (m > imf->mass_max || m < imf->mass_min) + error("Mass below or above limits expecting %g < %g < %g.", imf->mass_min, + m, imf->mass_max); +#endif + + for (int i = 0; i < imf->n_parts; i++) { + if (m <= imf->mass_limits[i + 1]) { + return imf->coef[i] * pow(m, imf->exp[i]); + } + } + + error("Failed to find correct function part: %g larger than mass max %g.", m, + imf->mass_max); + return 0.; +}; + +/** + * @brief Compute the integral of the mass fraction of the initial mass + * function. + * + * @param imf The #initial_mass_function. + * @param m1 The lower mass to evaluate. + * @param m2 The upper mass to evaluate. + * + * @return The integral of the mass fraction. + */ +float initial_mass_function_get_integral_imf( + const struct initial_mass_function *imf, const float m1, const float m2) { + +#ifdef SWIFT_DEBUG_CHECKS + if (m1 > imf->mass_max || m1 < imf->mass_min) + error("Mass 1 below or above limits expecting %g < %g < %g.", imf->mass_min, + m1, imf->mass_max); + if (m2 > imf->mass_max || m2 < imf->mass_min) + error("Mass 2 below or above limits expecting %g < %g < %g.", imf->mass_min, + m2, imf->mass_max); +#endif + + for (int i = 0; i < imf->n_parts; i++) { + if (m1 <= imf->mass_limits[i + 1]) { + if (m2 < imf->mass_limits[i] || m2 > imf->mass_limits[i + 1]) { + error( + "The code does not support the integration over multiple parts of " + "the IMF"); + } + const float exp = imf->exp[i] + 1.; + return imf->coef[i] * (pow(m2, exp) - pow(m1, exp)) / exp; + } + } + + error("Failed to find correct function part: %g, %g larger than mass max %g.", + m1, m2, imf->mass_max); + return 0.; +}; + +/** + * @brief Compute the coefficients of the initial mass function. + * + * @param imf The #initial_mass_function. + */ +void initial_mass_function_compute_coefficients( + struct initial_mass_function *imf) { + + /* Allocate memory */ + if ((imf->coef = (float *)malloc(sizeof(float) * imf->n_parts)) == NULL) + error("Failed to allocate the IMF coefficients."); + + /* Suppose that the first coefficients is 1 (will be corrected later) */ + imf->coef[0] = 1.; + + /* Use the criterion of continuity for the IMF */ + for (int i = 1; i < imf->n_parts; i++) { + float exp = imf->exp[i - 1] - imf->exp[i]; + imf->coef[i] = imf->coef[i - 1] * pow(imf->mass_limits[i], exp); + } + + /* Use the criterion on the integral = 1 */ + float integral = 0; + for (int i = 0; i < imf->n_parts; i++) { + const float exp = imf->exp[i] + 1.; + const float m_i = pow(imf->mass_limits[i], exp); + const float m_i1 = pow(imf->mass_limits[i + 1], exp); + integral += imf->coef[i] * (m_i1 - m_i) / exp; + } + + /* Normalize the coefficients (fix initial supposition) */ + for (int i = 0; i < imf->n_parts; i++) { + imf->coef[i] /= integral; + } +} + +/** + * @brief Reads the initial mass function parameters from the tables. + * + * @param imf The #initial_mass_function. + * @param params The #swift_params. + */ +void initial_mass_function_read_from_table(struct initial_mass_function *imf, + struct swift_params *params) { + + hid_t file_id, group_id; + + /* Open IMF group */ + h5_open_group(params, "Data/IMF", &file_id, &group_id); + + /* Read number of parts */ + io_read_attribute(group_id, "n", INT, &imf->n_parts); + + /* The tables have a different definition of n */ + imf->n_parts += 1; + + /* Allocate the memory for the exponents */ + if ((imf->exp = (float *)malloc(sizeof(float) * imf->n_parts)) == NULL) + error("Failed to allocate the IMF exponents."); + + /* Read the exponents */ + io_read_array_attribute(group_id, "as", FLOAT, imf->exp, imf->n_parts); + + /* Allocate the memory for the temporary mass limits */ + if ((imf->mass_limits = + (float *)malloc(sizeof(float) * (imf->n_parts + 1))) == NULL) + error("Failed to allocate the IMF masses."); + + /* Read the mass limits */ + io_read_array_attribute(group_id, "ms", FLOAT, imf->mass_limits, + imf->n_parts - 1); + + /* Copy the data (need to shift for mass_min) */ + for (int i = imf->n_parts - 1; i > 0; i--) { + imf->mass_limits[i] = imf->mass_limits[i - 1]; + } + + /* Read the minimal mass limit */ + io_read_attribute(group_id, "Mmin", FLOAT, &imf->mass_limits[0]); + + /* Read the maximal mass limit */ + io_read_attribute(group_id, "Mmax", FLOAT, &imf->mass_limits[imf->n_parts]); + + /* Close everything */ + h5_close_group(file_id, group_id); +} + +/** + * @brief Reads the parameters file and if required overwrites the parameters + * found in the yields table. + * + * @param imf The #initial_mass_function. + * @param params The #swift_params. + */ +void initial_mass_function_read_from_params(struct initial_mass_function *imf, + struct swift_params *params) { + + /* Read the number of elements */ + const int n_parts = parser_get_opt_param_int( + params, "GEARInitialMassFunction:number_function_part", imf->n_parts); + + const int n_parts_changed = n_parts != imf->n_parts; + imf->n_parts = n_parts; + + /* Reallocate the exponent memory */ + if (n_parts_changed) { + free(imf->exp); + if ((imf->exp = (float *)malloc(sizeof(float) * imf->n_parts)) == NULL) + error("Failed to allocate the IMF exponents."); + } + + /* Read the exponents */ + const char *exponent_name = "GEARInitialMassFunction:exponents"; + if (n_parts_changed) { + parser_get_param_float_array(params, exponent_name, imf->n_parts, imf->exp); + } else { + parser_get_opt_param_float_array(params, exponent_name, imf->n_parts, + imf->exp); + } + + /* Reallocate the mass limits memory */ + if (n_parts_changed) { + free(imf->mass_limits); + if ((imf->mass_limits = + (float *)malloc(sizeof(float) * (imf->n_parts + 1))) == NULL) + error("Failed to allocate the IMF masses."); + } + + /* Read the mass limits */ + const char *mass_limits_name = "GEARInitialMassFunction:mass_limits_msun"; + if (n_parts_changed) { + parser_get_param_float_array(params, mass_limits_name, imf->n_parts + 1, + imf->mass_limits); + } else { + parser_get_opt_param_float_array(params, mass_limits_name, imf->n_parts + 1, + imf->mass_limits); + } +} + +/** + * @brief Initialize the initial mass function. + * + * @param imf The #initial_mass_function. + * @param phys_const The #phys_const. + * @param us The #unit_system. + * @param params The #swift_params. + */ +void initial_mass_function_init(struct initial_mass_function *imf, + const struct phys_const *phys_const, + const struct unit_system *us, + struct swift_params *params) { + + /* Read the parameters from the yields table */ + initial_mass_function_read_from_table(imf, params); + + /* Overwrites the parameters if found in the params file */ + initial_mass_function_read_from_params(imf, params); + + /* Write the masses in the correct attributes */ + imf->mass_min = imf->mass_limits[0]; + imf->mass_max = imf->mass_limits[imf->n_parts]; + + /* Compute the coefficients */ + initial_mass_function_compute_coefficients(imf); +} + +/** + * @brief Write a initial_mass_function struct to the given FILE as a stream of + * bytes. + * + * Here we are only writing the arrays, everything else has been copied in the + * feedback. + * + * @param imf the struct + * @param stream the file stream + * @param sm The #stellar_model. + */ +void initial_mass_function_dump(const struct initial_mass_function *imf, + FILE *stream, const struct stellar_model *sm) { + + /* Dump the mass limits. */ + if (imf->mass_limits != NULL) { + restart_write_blocks((void *)imf->mass_limits, sizeof(float), + imf->n_parts + 1, stream, "imf_mass_limits", + "imf_mass_limits"); + } + + /*! Dump the exponents. */ + if (imf->exp != NULL) { + restart_write_blocks((void *)imf->exp, sizeof(float), imf->n_parts, stream, + "imf_exponents", "imf_exponents"); + } + + /*! Dump the coefficients. */ + if (imf->coef != NULL) { + restart_write_blocks((void *)imf->coef, sizeof(float), imf->n_parts, stream, + "imf_coef", "imf_coef"); + } +} + +/** + * @brief Restore a initial_mass_function struct from the given FILE as a stream + * of bytes. + * + * Here we are only writing the arrays, everything else has been copied in the + * feedback. + * + * @param imf the struct + * @param stream the file stream + * @param sm The #stellar_model. + */ +void initial_mass_function_restore(struct initial_mass_function *imf, + FILE *stream, + const struct stellar_model *sm) { + + /* Restore the mass limits */ + if (imf->mass_limits != NULL) { + imf->mass_limits = (float *)malloc(sizeof(float) * imf->n_parts + 1); + restart_read_blocks((void *)imf->mass_limits, sizeof(float), + imf->n_parts + 1, stream, NULL, "imf_mass_limits"); + } + + /* Restore the exponents */ + if (imf->exp != NULL) { + imf->exp = (float *)malloc(sizeof(float) * imf->n_parts); + restart_read_blocks((void *)imf->exp, sizeof(float), imf->n_parts, stream, + NULL, "imf_exponents"); + } + + /* Restore the coefficients */ + if (imf->coef != NULL) { + imf->coef = (float *)malloc(sizeof(float) * imf->n_parts); + restart_read_blocks((void *)imf->coef, sizeof(float), imf->n_parts, stream, + NULL, "imf_coef"); + } +} + +/** + * @brief Clean the allocated memory. + * + * @param imf the #initial_mass_function. + */ +void initial_mass_function_clean(struct initial_mass_function *imf) { + + /* Free the pointers */ + free(imf->mass_limits); + imf->mass_limits = NULL; + + free(imf->exp); + imf->exp = NULL; + + free(imf->coef); + imf->coef = NULL; +} diff --git a/src/feedback/GEAR/initial_mass_function.h b/src/feedback/GEAR/initial_mass_function.h new file mode 100644 index 0000000000000000000000000000000000000000..bf29e7bada847af14f679c3f29016a374dd3774d --- /dev/null +++ b/src/feedback/GEAR/initial_mass_function.h @@ -0,0 +1,60 @@ +/******************************************************************************* + * This file is part of SWIFT. + * Copyright (c) 2019 Loic Hausammann (loic.hausammann@epfl.ch) + * + * 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_INITIAL_MASS_FUNCTION_GEAR_H +#define SWIFT_INITIAL_MASS_FUNCTION_GEAR_H + +#include "hdf5_functions.h" +#include "stellar_evolution_struct.h" + +float initial_mass_function_get_exponent( + const struct initial_mass_function *imf, float mass_min, float mass_max); +void initial_mass_function_print(const struct initial_mass_function *imf); + +void initial_mass_function_integrate(const struct initial_mass_function *imf, + struct interpolation_1d *interp); +float initial_mass_function_get_coefficient( + const struct initial_mass_function *imf, float mass_min, float mass_max); +float initial_mass_function_get_integral_xi( + const struct initial_mass_function *imf, float m1, float m2); +float initial_mass_function_get_imf(const struct initial_mass_function *imf, + float m); +float initial_mass_function_get_integral_imf( + const struct initial_mass_function *imf, const float m1, const float m2); +void initial_mass_function_compute_coefficients( + struct initial_mass_function *imf); + +void initial_mass_function_read_from_table(struct initial_mass_function *imf, + struct swift_params *params); +void initial_mass_function_read_from_params(struct initial_mass_function *imf, + struct swift_params *params); + +void initial_mass_function_init(struct initial_mass_function *imf, + const struct phys_const *phys_const, + const struct unit_system *us, + struct swift_params *params); + +void initial_mass_function_dump(const struct initial_mass_function *imf, + FILE *stream, const struct stellar_model *sm); + +void initial_mass_function_restore(struct initial_mass_function *imf, + FILE *stream, + const struct stellar_model *sm); + +void initial_mass_function_clean(struct initial_mass_function *imf); +#endif // SWIFT_INITIAL_MASS_FUNCTION_GEAR_H diff --git a/src/feedback/GEAR/interpolation.h b/src/feedback/GEAR/interpolation.h new file mode 100644 index 0000000000000000000000000000000000000000..37706cda73735955e5b0802fdd26fea8802468ab --- /dev/null +++ b/src/feedback/GEAR/interpolation.h @@ -0,0 +1,207 @@ +/******************************************************************************* + * This file is part of SWIFT. + * Copyright (c) 2019 Loic Hausammann (loic.hausammann@epfl.ch) + * + * 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_GEAR_INTERPOLATION_H +#define SWIFT_GEAR_INTERPOLATION_H + +enum interpolate_boundary_condition { + /* No extrapolation => raise errors */ + boundary_condition_error, + + /* Zero as boundary conditions */ + boundary_condition_zero, + + /* Zero (left boundary) and constant (right boundary) boundary conditions */ + boundary_condition_zero_const, +}; + +struct interpolation_1d { + /* Data to interpolate */ + float *data; + + /* Minimal x */ + float xmin; + + /* Step size between x points */ + float dx; + + /* Number of element in the data */ + int N; + + /* Type of boundary conditions. */ + enum interpolate_boundary_condition boundary_condition; +}; + +/** + * @brief Initialize the #interpolation_1d. + * + * Assumes x are linear in log. + * + * @params interp The #interpolation_1d. + * @params xmin Minimal value of x (in log). + * @params xmax Maximal value of x (in log). + * @params N Requested number of values. + * @params log_data_xmin The minimal value of the data (in log). + * @params step_size The size of the x steps (in log). + * @params N_data The number of element in the data. + * @params data The data to interpolate (y). + * @params N The number of element in data. + * @params boundary_condition The type of #interpolate_boundary_condition. + */ +__attribute__((always_inline)) static INLINE void interpolate_1d_init( + struct interpolation_1d *interp, float xmin, float xmax, int N, + float log_data_xmin, float step_size, int N_data, const float *data, + enum interpolate_boundary_condition boundary_condition) { + + /* Save the variables */ + interp->N = N; + interp->xmin = xmin; + interp->dx = (xmax - xmin) / (N - 1.f); + interp->boundary_condition = boundary_condition; + + /* Allocate the memory */ + interp->data = malloc(sizeof(float) * N); + if (interp->data == NULL) + error("Failed to allocate memory for the interpolation"); + + /* Interpolate the data */ + for (int i = 0; i < N; i++) { + const float log_x = xmin + i * interp->dx; + const float x_j = (log_x - log_data_xmin) / step_size; + + /* Check boundaries */ + if (x_j < 0) { + switch (boundary_condition) { + case boundary_condition_error: + error("Cannot extrapolate"); + break; + case boundary_condition_zero: + interp->data[i] = 0; + break; + case boundary_condition_zero_const: + interp->data[i] = 0; + break; + default: + error("Interpolation type not implemented"); + } + continue; + } else if (x_j >= N_data) { + switch (boundary_condition) { + case boundary_condition_error: + error("Cannot extrapolate"); + break; + case boundary_condition_zero: + interp->data[i] = 0; + break; + case boundary_condition_zero_const: + interp->data[i] = interp->data[i - 1]; + break; + default: + error("Interpolation type not implemented"); + } + continue; + } + + /* Interpolate i */ + const int j = x_j; + const float f = x_j - j; + interp->data[i] = (1. - f) * data[j] + f * data[j + 1]; + } +} + +/** + * @brief Interpolate the data. + * + * @params interp The #interpolation_1d. + * @params x The x value where to interpolate. + * + * @return The interpolated value y. + */ +__attribute__((always_inline)) static INLINE float interpolate_1d( + const struct interpolation_1d *interp, float x) { + + /* Find indice */ + const float i = (x - interp->xmin) / interp->dx; + const int idx = i; + const float dx = i - idx; + + /* Should we extrapolate? */ + if (i < 0) { + switch (interp->boundary_condition) { + case boundary_condition_error: + error("Cannot extrapolate"); + break; + case boundary_condition_zero: + case boundary_condition_zero_const: + return 0; + default: + error("Interpolation type not implemented"); + } + } else if (i >= interp->N - 1) { + switch (interp->boundary_condition) { + case boundary_condition_error: + error("Cannot extrapolate"); + break; + case boundary_condition_zero: + return 0; + case boundary_condition_zero_const: + return interp->data[interp->N - 1]; + default: + error("Interpolation type not implemented"); + } + } + + /* interpolate */ + return interp->data[idx] * (1. - dx) + interp->data[idx + 1] * dx; +} + +/** + * @brief Print the data. + * + * @params interp The #interpolation_1d. + */ +__attribute__((always_inline)) static INLINE void interpolate_1d_print( + const struct interpolation_1d *interp) { + + message("Interpolation between %g and %g", interp->xmin, + interp->xmin + interp->dx * interp->N); + + message("Contains %i values and use the boundary condition %i", interp->N, + interp->boundary_condition); + + /* Print values */ + for (int i = 0; i < interp->N; i++) { + float x = interp->xmin + i * interp->dx; + message("%.2g: %g", x, interp->data[i]); + } +} + +/** + * @brief Cleanup the #interpolation_1d structure. + * + * @params interp The #interpolation_1d. + */ +__attribute__((always_inline)) static INLINE void interpolate_1d_free( + struct interpolation_1d *interp) { + + /* Free the allocated memory */ + free(interp->data); + interp->data = NULL; +} + +#endif // SWIFT_GEAR_INTERPOLATION_H diff --git a/src/feedback/GEAR/lifetime.h b/src/feedback/GEAR/lifetime.h new file mode 100644 index 0000000000000000000000000000000000000000..78a7ac16b226901c01cd24ad01245f118f3391af --- /dev/null +++ b/src/feedback/GEAR/lifetime.h @@ -0,0 +1,242 @@ +/******************************************************************************* + * This file is part of SWIFT. + * Copyright (c) 2019 Loic Hausammann (loic.hausammann@epfl.ch) + * + * 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_LIFETIME_GEAR_H +#define SWIFT_LIFETIME_GEAR_H + +#include "hdf5_functions.h" +#include "stellar_evolution_struct.h" + +/** + * @brief Print the lifetime model. + * + * @param lf The #lifetime. + */ +__attribute__((always_inline)) INLINE static void lifetime_print( + const struct lifetime* lf) { + + /* Only the master print */ + if (engine_rank != 0) { + return; + } + + message("Quadratic terms: %.2g %.2g %.2g", lf->quadratic[0], lf->quadratic[1], + lf->quadratic[2]); + + message("Linear terms: %.2g %.2g %.2g", lf->linear[0], lf->linear[1], + lf->linear[2]); + + message("Constant terms: %.2g %.2g %.2g", lf->constant[0], lf->constant[1], + lf->constant[2]); +} + +/** + * @brief Compute the lifetime of a star. + * + * @param life The #lifetime model. + * @param log_mass The star's mass (in log10(solMass)). + * @param metallicity The star's metallicity. + * + * @return The star's lifetime (in log10(Myr)). + */ +__attribute__((always_inline)) INLINE static float +lifetime_get_log_lifetime_from_mass(const struct lifetime* life, float log_mass, + float metallicity) { + + /* Compute quadratic term */ + const float quadratic = + (life->quadratic[0] * metallicity + life->quadratic[1]) * metallicity + + life->quadratic[2]; + /* Compute linear term */ + const float linear = + (life->linear[0] * metallicity + life->linear[1]) * metallicity + + life->linear[2]; + /* Compute constant term */ + const float constant = + (life->constant[0] * metallicity + life->constant[1]) * metallicity + + life->constant[2]; + + /* Compute lifetime */ + return (quadratic * log_mass + linear) * log_mass + constant; +} + +/** + * @brief Compute the mass of a star with a given lifetime + * + * @param life The #lifetime model. + * @param log_time The star's lifetime (in log10(Myr)). + * @param metallicity The star's metallicity. + * + * @return The star's mass (in log10(solMass)) + */ +__attribute__((always_inline)) INLINE static float +lifetime_get_log_mass_from_lifetime(const struct lifetime* life, float log_time, + float metallicity) { + + /* Compute quadratic term */ + const float quadratic = + (life->quadratic[0] * metallicity + life->quadratic[1]) * metallicity + + life->quadratic[2]; + /* Compute linear term */ + const float linear = + (life->linear[0] * metallicity + life->linear[1]) * metallicity + + life->linear[2]; + /* Compute constant term */ + const float constant = + (life->constant[0] * metallicity + life->constant[1]) * metallicity + + life->constant[2]; + + /* Compute the "c" with the time */ + const float c_t = constant - log_time; + + /* Use the quadratic formula to find the mass */ + if (quadratic != 0) { + const float delta = linear * linear - 4 * quadratic * c_t; + + /* Avoid complex number should not happen in real simulation */ + if (delta < 0) { + return -linear / (2. * quadratic); + } else { + return (-linear - sqrt(delta)) / (2. * quadratic); + } + } else { + return -c_t / linear; + } +} + +/** + * @brief Read lifetime parameters from tables. + * + * @param lt The #lifetime. + * @param params The #swift_params. + */ +__attribute__((always_inline)) INLINE static void lifetime_read_from_tables( + struct lifetime* lt, struct swift_params* params) { + + hid_t file_id, group_id; + + /* Open IMF group */ + h5_open_group(params, "Data/LiveTimes", &file_id, &group_id); + + /* Allocate the temporary array */ + float* tmp; + if ((tmp = (float*)malloc(sizeof(float) * 9)) == NULL) + error("Failed to allocate the temporary array."); + + /* Read the coefficients */ + io_read_array_dataset(group_id, "coeff_z", FLOAT, tmp, 9); + + /* Copy the coefficents */ + const int dim = 3; + for (int i = 0; i < dim; i++) { + lt->quadratic[i] = tmp[i]; + lt->linear[i] = tmp[i + dim]; + lt->constant[i] = tmp[i + 2 * dim]; + } + + /* Change units from yr into Myr */ + lt->constant[dim - 1] -= 6; + + /* Cleanup everything */ + free(tmp); + h5_close_group(file_id, group_id); +} + +/** + * @brief Read lifetime parameters from params. + * + * @param lt The #lifetime. + * @param params The #swift_params. + */ +__attribute__((always_inline)) INLINE static void lifetime_read_from_params( + struct lifetime* lt, struct swift_params* params) { + + /* Read quadratic terms */ + parser_get_opt_param_float_array(params, "GEARLifetime:quadratic", 3, + lt->quadratic); + + /* Read linear terms */ + parser_get_opt_param_float_array(params, "GEARLifetime:linear", 3, + lt->linear); + + /* Read constant terms */ + parser_get_opt_param_float_array(params, "GEARLifetime:constant", 3, + lt->constant); +} + +/** + * @brief Inititialize the Lifetime. + * + * @param lt The #lifetime. + * @param phys_const The #phys_const. + * @param us The #unit_system. + * @param params The #swift_params. + */ +__attribute__((always_inline)) INLINE static void lifetime_init( + struct lifetime* lt, const struct phys_const* phys_const, + const struct unit_system* us, struct swift_params* params) { + + /* Read params from yields table */ + lifetime_read_from_tables(lt, params); + + /* overwrite the parameters if found in the params */ + lifetime_read_from_params(lt, params); +} + +/** + * @brief Write a lifetime struct to the given FILE as a stream of bytes. + * + * Here we are only writing the arrays, everything else has been copied in the + * feedback. + * + * @param lt the struct + * @param stream the file stream + * @param sm The #stellar_model. + */ +__attribute__((always_inline)) INLINE static void lifetime_dump( + const struct lifetime* lt, FILE* stream, const struct stellar_model* sm) { + + /* Nothing to do here */ +} + +/** + * @brief Restore a lifetime struct from the given FILE as a stream of + * bytes. + * + * Here we are only writing the arrays, everything else has been copied in the + * feedback. + * + * @param lt the struct + * @param stream the file stream + * @param sm The #stellar_model. + */ +__attribute__((always_inline)) INLINE static void lifetime_restore( + struct lifetime* lt, FILE* stream, const struct stellar_model* sm) { + + /* Nothing to do here */ +} + +/** + * @brief Clean the allocated memory. + * + * @param lifetime the #lifetime. + */ +__attribute__((always_inline)) INLINE static void lifetime_clean( + struct lifetime* lifetime) {} + +#endif // SWIFT_LIFETIME_GEAR_H diff --git a/src/feedback/GEAR/stellar_evolution.c b/src/feedback/GEAR/stellar_evolution.c new file mode 100644 index 0000000000000000000000000000000000000000..15853d0ff9c74d03642f493d987ba57724f152a4 --- /dev/null +++ b/src/feedback/GEAR/stellar_evolution.c @@ -0,0 +1,502 @@ +/******************************************************************************* + * This file is part of SWIFT. + * Copyright (c) 2019 Loic Hausammann (loic.hausammann@epfl.ch) + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published + * by the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this program. If not, see <http://www.gnu.org/licenses/>. + * + ******************************************************************************/ + +/* Include header */ +#include "stellar_evolution.h" + +/* Include local headers */ +#include "hdf5_functions.h" +#include "initial_mass_function.h" +#include "lifetime.h" +#include "random.h" +#include "stellar_evolution_struct.h" +#include "supernovae_ia.h" +#include "supernovae_ii.h" + +#include <math.h> +#include <stddef.h> + +/** + * @brief Print the stellar model. + * + * @param sm The #stellar_model. + */ +void stellar_model_print(const struct stellar_model* sm) { + + /* Only the master print */ + if (engine_rank != 0) { + return; + } + + /* Print the type of yields */ + message("Discrete yields? %i", sm->discrete_yields); + + /* Print the sub properties */ + initial_mass_function_print(&sm->imf); + lifetime_print(&sm->lifetime); + supernovae_ia_print(&sm->snia); + supernovae_ii_print(&sm->snii); +} + +/** + * @brief Compute the integer number of supernovae from the floating number. + * + * @param sp The particle to act upon + * @param number_supernovae_f Floating number of supernovae during this step. + * @param ti_begin The #integertime_t at the begining of the step. + * @param random_type The categorie of random. + * + * @return The integer number of supernovae. + */ +int stellar_evolution_compute_integer_number_supernovae( + struct spart* restrict sp, float number_supernovae_f, + const integertime_t ti_begin, enum random_number_type random_type) { + + const int number_supernovae_i = floor(number_supernovae_f); + + /* Get the random number for the decimal part */ + const float rand_sn = random_unit_interval(sp->id, ti_begin, random_type); + + /* Get the fraction part */ + const float frac_sn = number_supernovae_f - number_supernovae_i; + + /* Get the integer number of SN */ + return number_supernovae_i + ((rand_sn < frac_sn) ? 1 : 0); +} + +/** + * @brief Compute the feedback properties. + * + * @param sp The particle to act upon + * @param sm The #stellar_model structure. + * @param phys_const The physical constants in the internal unit system. + * @param log_m_beg_step Mass of a star ending its life at the begining of the + * step (log10(solMass)) + * @param log_m_end_step Mass of a star ending its life at the end of the step + * (log10(solMass)) + * @param m_beg_step Mass of a star ending its life at the begining of the step + * (solMass) + * @param m_end_step Mass of a star ending its life at the end of the step + * (solMass) + * @param number_snia Number of SNIa produced by the stellar particle. + * @param number_snii Number of SNII produced by the stellar particle. + * + */ +void stellar_evolution_compute_continuous_feedback_properties( + struct spart* restrict sp, const struct stellar_model* sm, + const struct phys_const* phys_const, const float log_m_beg_step, + const float log_m_end_step, const float m_beg_step, const float m_end_step, + const float m_init, const int number_snia, const int number_snii) { + + /* Compute the mass ejected */ + /* SNIa */ + const float mass_frac_snia = + supernovae_ia_get_ejected_mass_processed(&sm->snia) * + supernovae_ia_get_number(&sm->snia, m_end_step, m_beg_step); + + /* SNII */ + const float mass_frac_snii = + supernovae_ii_get_ejected_mass_fraction_processed( + &sm->snii, log_m_end_step, log_m_beg_step); + + sp->feedback_data.mass_ejected = (mass_frac_snia + mass_frac_snii) * m_init; + + /* Transform into internal units */ + sp->feedback_data.mass_ejected *= phys_const->const_solar_mass; + + if (sp->mass <= sp->feedback_data.mass_ejected) { + error("Stars cannot have negative mass. (%g <= %g). Initial mass = %g", + sp->mass, sp->feedback_data.mass_ejected, sp->birth.mass); + } + + /* Update the mass */ + sp->mass -= sp->feedback_data.mass_ejected; + + /* Now deal with the metals */ + + /* Get the SNIa yields */ + const float* snia_yields = supernovae_ia_get_yields(&sm->snia); + + /* Compute the SNII yields */ + float snii_yields[GEAR_CHEMISTRY_ELEMENT_COUNT]; + supernovae_ii_get_yields(&sm->snii, log_m_end_step, log_m_beg_step, + snii_yields); + + /* Compute the mass fraction of non processed elements */ + const float non_processed = supernovae_ii_get_ejected_mass_fraction( + &sm->snii, log_m_end_step, log_m_beg_step); + + /* Set the yields */ + for (int i = 0; i < GEAR_CHEMISTRY_ELEMENT_COUNT; i++) { + /* Compute the mass fraction of metals */ + sp->feedback_data.metal_mass_ejected[i] = + /* Supernovae Ia yields */ + snia_yields[i] * number_snia + + /* Supernovae II yields */ + snii_yields[i] + + /* Gas contained in stars initial metallicity */ + chemistry_get_metal_mass_fraction_for_feedback(sp)[i] * non_processed; + + /* Convert it to total mass */ + sp->feedback_data.metal_mass_ejected[i] *= sp->birth.mass; + } +} + +/** + * @brief Compute the feedback properties. + * + * @param sp The particle to act upon + * @param sm The #stellar_model structure. + * @param phys_const The physical constants in the internal unit system. + * @param log_m_beg_step Mass of a star ending its life at the begining of the + * step (log10(solMass)) + * @param log_m_end_step Mass of a star ending its life at the end of the step + * (log10(solMass)) + * @param m_beg_step Mass of a star ending its life at the begining of the step + * (solMass) + * @param m_end_step Mass of a star ending its life at the end of the step + * (solMass) + * @param number_snia Number of SNIa produced by the stellar particle. + * @param number_snii Number of SNII produced by the stellar particle. + * + */ +void stellar_evolution_compute_discrete_feedback_properties( + struct spart* restrict sp, const struct stellar_model* sm, + const struct phys_const* phys_const, const float log_m_beg_step, + const float log_m_end_step, const float m_beg_step, const float m_end_step, + const float m_init, const int number_snia, const int number_snii) { + + /* Get the normalization to the average */ + const float normalization = + number_snii == 0 + ? 0. + : number_snii / + (supernovae_ii_get_number(&sm->snii, m_end_step, m_beg_step) * + m_init); + + /* Compute the mass ejected */ + /* SNIa */ + const float mass_snia = + (number_snia == 0) + ? 0 + : (supernovae_ia_get_ejected_mass_processed(&sm->snia) * number_snia); + + /* SNII */ + const float mass_snii = + normalization * supernovae_ii_get_ejected_mass_fraction_processed( + &sm->snii, log_m_end_step, log_m_beg_step); + + sp->feedback_data.mass_ejected = mass_snia + mass_snii; + + /* Transform into internal units */ + sp->feedback_data.mass_ejected *= phys_const->const_solar_mass; + + if (sp->mass <= sp->feedback_data.mass_ejected) { + error("Stars cannot have negative mass. (%g <= %g). Initial mass = %g", + sp->mass, sp->feedback_data.mass_ejected, sp->birth.mass); + } + + /* Update the mass */ + sp->mass -= sp->feedback_data.mass_ejected; + + /* Get the SNIa yields */ + const float* snia_yields = supernovae_ia_get_yields(&sm->snia); + + /* Compute the SNII yields (without the normalization) */ + float snii_yields[GEAR_CHEMISTRY_ELEMENT_COUNT]; + supernovae_ii_get_yields(&sm->snii, log_m_end_step, log_m_beg_step, + snii_yields); + + /* Compute the mass fraction of non processed elements */ + const float non_processed = + normalization * supernovae_ii_get_ejected_mass_fraction( + &sm->snii, log_m_end_step, log_m_beg_step); + + /* Set the yields */ + for (int i = 0; i < GEAR_CHEMISTRY_ELEMENT_COUNT; i++) { + /* Compute the mass fraction of metals */ + sp->feedback_data.metal_mass_ejected[i] = + /* Supernovae Ia yields */ + snia_yields[i] * number_snia + + /* Supernovae II yields */ + normalization * snii_yields[i] + + /* Gas contained in stars initial metallicity */ + chemistry_get_metal_mass_fraction_for_feedback(sp)[i] * non_processed; + + /* Convert it to total mass */ + sp->feedback_data.metal_mass_ejected[i] *= sp->birth.mass; + } +} + +/** + * @brief Evolve the stellar properties of a #spart. + * + * This function compute the SN rate and yields before sending + * this information to a different MPI rank. + * + * Here I am using Myr-solar mass units internally in order to + * avoid numerical errors. + * + * @param sp The particle to act upon + * @param sm The #stellar_model structure. + * @param cosmo The current cosmological model. + * @param us The unit system. + * @param phys_const The physical constants in the internal unit system. + * @param ti_begin The #integertime_t at the begining of the step. + * @param star_age_beg_step The age of the star at the star of the time-step in + * internal units. + * @param dt The time-step size of this star in internal units. + */ +void stellar_evolution_evolve_spart( + struct spart* restrict sp, const struct stellar_model* sm, + const struct cosmology* cosmo, const struct unit_system* us, + const struct phys_const* phys_const, const integertime_t ti_begin, + const double star_age_beg_step, const double dt) { + + /* Convert the inputs */ + const double conversion_to_myr = phys_const->const_year * 1e6; + const double star_age_beg_step_myr = star_age_beg_step / conversion_to_myr; + const double dt_myr = dt / conversion_to_myr; + + /* Get the metallicity */ + const float metallicity = + chemistry_get_total_metal_mass_fraction_for_feedback(sp); + + /* Compute masses range */ + const float log_m_beg_step = + star_age_beg_step == 0. + ? FLT_MAX + : lifetime_get_log_mass_from_lifetime( + &sm->lifetime, log10(star_age_beg_step_myr), metallicity); + const float log_m_end_step = lifetime_get_log_mass_from_lifetime( + &sm->lifetime, log10(star_age_beg_step_myr + dt_myr), metallicity); + + const float m_beg_step = + star_age_beg_step == 0. ? FLT_MAX : pow(10, log_m_beg_step); + const float m_end_step = pow(10, log_m_end_step); + + /* Check if the star can produce a supernovae */ + const int can_produce_snia = + supernovae_ia_can_explode(&sm->snia, m_end_step, m_beg_step); + const int can_produce_snii = + supernovae_ii_can_explode(&sm->snii, m_end_step, m_beg_step); + + /* Is it possible to generate a supernovae? */ + if (!can_produce_snia && !can_produce_snii) return; + + /* Compute the initial mass */ + const float m_init = sp->birth.mass / phys_const->const_solar_mass; + + /* Compute number of SNIa */ + int number_snia = 0; + if (can_produce_snia) { + /* Compute rates */ + const float number_snia_f = + supernovae_ia_get_number(&sm->snia, m_end_step, m_beg_step) * m_init; + + /* Get the integer number of supernovae */ + number_snia = stellar_evolution_compute_integer_number_supernovae( + sp, number_snia_f, ti_begin, random_number_stellar_feedback_1); + } + + /* Compute number of SNII */ + int number_snii = 0; + if (can_produce_snii) { + /* Compute rates */ + const float number_snii_f = + supernovae_ii_get_number(&sm->snii, m_end_step, m_beg_step) * m_init; + + /* Get the integer number of supernovae */ + number_snii = stellar_evolution_compute_integer_number_supernovae( + sp, number_snii_f, ti_begin, random_number_stellar_feedback_2); + } + + /* Does this star produce a supernovae? */ + if (number_snia == 0 && number_snii == 0) return; + + sp->feedback_data.number_sn = number_snia + number_snii; + + /* Compute the properties of the feedback (e.g. yields) */ + if (sm->discrete_yields) { + stellar_evolution_compute_discrete_feedback_properties( + sp, sm, phys_const, log_m_beg_step, log_m_end_step, m_beg_step, + m_end_step, m_init, number_snia, number_snii); + } else { + stellar_evolution_compute_continuous_feedback_properties( + sp, sm, phys_const, log_m_beg_step, log_m_end_step, m_beg_step, + m_end_step, m_init, number_snia, number_snii); + } +} + +/** + * @brief Get the name of the element i. + * + * @param sm The #stellar_model. + * @param i The element indice. + */ +const char* stellar_evolution_get_element_name(const struct stellar_model* sm, + int i) { + + return sm->elements_name + i * GEAR_LABELS_SIZE; +} + +/** + * @brief Read the name of all the elements present in the tables. + * + * @param sm The #stellar_model. + */ +void stellar_evolution_read_elements(struct stellar_model* sm, + struct swift_params* params) { + + hid_t file_id, group_id; + + /* Open IMF group */ + h5_open_group(params, "Data", &file_id, &group_id); + + /* Read the elements */ + io_read_string_array_attribute(group_id, "elts", sm->elements_name, + GEAR_CHEMISTRY_ELEMENT_COUNT, + GEAR_LABELS_SIZE); + + /* Check that we received correctly the metals */ + if (strcmp(stellar_evolution_get_element_name( + sm, GEAR_CHEMISTRY_ELEMENT_COUNT - 1), + "Metals") != 0) { + error( + "The chemistry table should contain the metals in the last column " + "(found %s)", + stellar_evolution_get_element_name(sm, + GEAR_CHEMISTRY_ELEMENT_COUNT - 1)); + } + + /* Print the name of the elements */ + char txt[GEAR_CHEMISTRY_ELEMENT_COUNT * (GEAR_LABELS_SIZE + 2)] = ""; + for (int i = 0; i < GEAR_CHEMISTRY_ELEMENT_COUNT; i++) { + if (i != 0) { + strcat(txt, ", "); + } + strcat(txt, stellar_evolution_get_element_name(sm, i)); + } + + if (engine_rank == 0) { + message("Chemistry elements: %s", txt); + } + + /* Cleanup everything */ + h5_close_group(file_id, group_id); +} + +/** + * @brief Initialize the global properties of the stellar evolution scheme. + * + * @param sm The #stellar_model. + * @param phys_const The physical constants in the internal unit system. + * @param us The internal unit system. + * @param params The parsed parameters. + * @param hydro_props The already read-in properties of the hydro scheme. + * @param cosmo The cosmological model. + */ +void stellar_evolution_props_init(struct stellar_model* sm, + const struct phys_const* phys_const, + const struct unit_system* us, + struct swift_params* params, + const struct cosmology* cosmo) { + + /* Read the list of elements */ + stellar_evolution_read_elements(sm, params); + + /* Use the discrete yields approach? */ + sm->discrete_yields = + parser_get_param_int(params, "GEARFeedback:discrete_yields"); + + /* Initialize the initial mass function */ + initial_mass_function_init(&sm->imf, phys_const, us, params); + + /* Initialize the lifetime model */ + lifetime_init(&sm->lifetime, phys_const, us, params); + + /* Initialize the supernovae Ia model */ + supernovae_ia_init(&sm->snia, phys_const, us, params, sm); + + /* Initialize the supernovae II model */ + supernovae_ii_init(&sm->snii, phys_const, us, params, sm); +} + +/** + * @brief Write a stellar_evolution struct to the given FILE as a stream of + * bytes. + * + * Here we are only writing the arrays, everything has been copied in the + * feedback. + * + * @param sm the struct + * @param stream the file stream + */ +void stellar_evolution_dump(const struct stellar_model* sm, FILE* stream) { + + /* Dump the initial mass function */ + initial_mass_function_dump(&sm->imf, stream, sm); + + /* Dump the lifetime model */ + lifetime_dump(&sm->lifetime, stream, sm); + + /* Dump the supernovae Ia model */ + supernovae_ia_dump(&sm->snia, stream, sm); + + /* Dump the supernovae II model */ + supernovae_ii_dump(&sm->snii, stream, sm); +} + +/** + * @brief Restore a stellar_evolution struct from the given FILE as a stream of + * bytes. + * + * Here we are only writing the arrays, everything has been copied in the + * feedback. + * + * @param sm the struct + * @param stream the file stream + */ +void stellar_evolution_restore(struct stellar_model* sm, FILE* stream) { + + /* Restore the initial mass function */ + initial_mass_function_restore(&sm->imf, stream, sm); + + /* Restore the lifetime model */ + lifetime_restore(&sm->lifetime, stream, sm); + + /* Restore the supernovae Ia model */ + supernovae_ia_restore(&sm->snia, stream, sm); + + /* Restore the supernovae II model */ + supernovae_ii_restore(&sm->snii, stream, sm); +} + +/** + * @brief Clean the allocated memory. + * + * @param sm the #stellar_model. + */ +void stellar_evolution_clean(struct stellar_model* sm) { + + initial_mass_function_clean(&sm->imf); + lifetime_clean(&sm->lifetime); + supernovae_ia_clean(&sm->snia); + supernovae_ii_clean(&sm->snii); +} diff --git a/src/feedback/GEAR/stellar_evolution.h b/src/feedback/GEAR/stellar_evolution.h new file mode 100644 index 0000000000000000000000000000000000000000..9ffda5ff6716c1dc14ce6eeea81b634538f9ab22 --- /dev/null +++ b/src/feedback/GEAR/stellar_evolution.h @@ -0,0 +1,70 @@ +/******************************************************************************* + * This file is part of SWIFT. + * Copyright (c) 2019 Loic Hausammann (loic.hausammann@epfl.ch) + * + * 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_STELLAR_EVOLUTION_GEAR_H +#define SWIFT_STELLAR_EVOLUTION_GEAR_H + +#include "hdf5_functions.h" +#include "initial_mass_function.h" +#include "lifetime.h" +#include "random.h" +#include "stellar_evolution_struct.h" +#include "supernovae_ia.h" +#include "supernovae_ii.h" + +#include <math.h> +#include <stddef.h> + +void stellar_model_print(const struct stellar_model* sm); +int stellar_evolution_compute_integer_number_supernovae( + struct spart* restrict sp, float number_supernovae_f, + const integertime_t ti_begin, enum random_number_type random_type); + +void stellar_evolution_compute_continuous_feedback_properties( + struct spart* restrict sp, const struct stellar_model* sm, + const struct phys_const* phys_const, const float log_m_beg_step, + const float log_m_end_step, const float m_beg_step, const float m_end_step, + const float m_init, const int number_snia, const int number_snii); +void stellar_evolution_compute_discrete_feedback_properties( + struct spart* restrict sp, const struct stellar_model* sm, + const struct phys_const* phys_const, const float log_m_beg_step, + const float log_m_end_step, const float m_beg_step, const float m_end_step, + const float m_init, const int number_snia, const int number_snii); + +void stellar_evolution_evolve_spart( + struct spart* restrict sp, const struct stellar_model* sm, + const struct cosmology* cosmo, const struct unit_system* us, + const struct phys_const* phys_const, const integertime_t ti_begin, + const double star_age_beg_step, const double dt); + +const char* stellar_evolution_get_element_name(const struct stellar_model* sm, + int i); +void stellar_evolution_read_elements(struct stellar_model* sm, + struct swift_params* params); +void stellar_evolution_props_init(struct stellar_model* sm, + const struct phys_const* phys_const, + const struct unit_system* us, + struct swift_params* params, + const struct cosmology* cosmo); + +void stellar_evolution_dump(const struct stellar_model* sm, FILE* stream); +void stellar_evolution_restore(struct stellar_model* sm, FILE* stream); + +void stellar_evolution_clean(struct stellar_model* sm); + +#endif // SWIFT_STELLAR_EVOLUTION_GEAR_H diff --git a/src/feedback/GEAR/stellar_evolution_struct.h b/src/feedback/GEAR/stellar_evolution_struct.h new file mode 100644 index 0000000000000000000000000000000000000000..cb6280c65c3ea8a6dd254da7b9f0b413ce559d44 --- /dev/null +++ b/src/feedback/GEAR/stellar_evolution_struct.h @@ -0,0 +1,163 @@ +/******************************************************************************* + * This file is part of SWIFT. + * Copyright (c) 2018 Loic Hausammann (loic.hausammann@epfl.ch) + * + * 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_STELLAR_EVOLUTION_STRUCT_GEAR_H +#define SWIFT_STELLAR_EVOLUTION_STRUCT_GEAR_H + +#include "interpolation.h" + +/* Number of different type of companion. + If changed, the IO needs to be updated. + */ +#define GEAR_NUMBER_TYPE_OF_COMPANION 2 +#define GEAR_LABELS_SIZE 10 + +/** + * @brief Model for the initial mass function. + * + * Describe a model such as Kroupa 2001: + * + * f(m) = coef[i] * pow(m, exp[i]) + */ +struct initial_mass_function { + + /*! Mass limits between IMF parts (n_parts + 1 elements). */ + float *mass_limits; + + /*! Exponent of each IMF parts (n_parts elements). */ + float *exp; + + /*! Coefficient of each IMF parts (n_parts elements). */ + float *coef; + + /*! Number of parts in the function. */ + int n_parts; + + /*! Minimal mass contained in mass_limits, copied for more clarity. */ + float mass_min; + + /*! Maximal mass contained in mass_limits, copied for more clarity. */ + float mass_max; +}; + +/** + * @brief Model for the stellar lifetime. + */ +struct lifetime { + + /*! Coefficients for the log10(m)^2 term */ + float quadratic[3]; + + /*! Coefficients for the log10(m) term */ + float linear[3]; + + /*! Coefficients for the constant term */ + float constant[3]; +}; + +/** + * @brief Model for SNIa. + */ +struct supernovae_ia { + /*! Mass of each element ejected by a single supernovae */ + float yields[GEAR_CHEMISTRY_ELEMENT_COUNT]; + + /*! White dwarf's mass */ + float mass_white_dwarf; + + /*! Minimal mass of the progenitor */ + float mass_min_progenitor; + + /*! Maximal mass of the progenitor */ + float mass_max_progenitor; + + /*! coefficient of the initial mass function for progenitor divided by + * progenitor_exponent */ + float progenitor_coef_exp; + + /*! exponent of the initial mass function for progenitor */ + float progenitor_exponent; + + /*! exponent of the initial mass function for binaries */ + float companion_exponent; + + struct { + /*! Initial mass function's coeffcients */ + float coef; + + /*! Maximal mass of the companion */ + float mass_max; + + /*! Minimal mass of the companion */ + float mass_min; + } companion[GEAR_NUMBER_TYPE_OF_COMPANION]; +}; + +/** + * @brief Model for SNII. + */ +struct supernovae_ii { + + /*! Integrated (over the IMF) mass fraction of metals ejected by a supernovae + */ + struct interpolation_1d integrated_yields[GEAR_CHEMISTRY_ELEMENT_COUNT]; + + /*! Total mass fraction ejected (integrated over the IMF) */ + struct interpolation_1d integrated_ejected_mass_processed; + + /*! Mass fraction ejected and not processed (=> with the star metallicity) */ + struct interpolation_1d integrated_ejected_mass; + + /*! Minimal mass for a SNII */ + float mass_min; + + /*! Maximal mass for a SNII */ + float mass_max; + + /*! exponent of the IMF */ + float exponent; + + /*! coefficient of the IMF over the exponent */ + float coef_exp; +}; + +/** + * @brief The complete stellar model. + */ +struct stellar_model { + + /*! Name of the different elements */ + char elements_name[GEAR_CHEMISTRY_ELEMENT_COUNT * GEAR_LABELS_SIZE]; + + /*! The initial mass function */ + struct initial_mass_function imf; + + /*! The stellar lifetime */ + struct lifetime lifetime; + + /*! The supernovae type Ia */ + struct supernovae_ia snia; + + /*! The supernovae type II */ + struct supernovae_ii snii; + + /*! Use a discrete yields approach */ + char discrete_yields; +}; + +#endif // SWIFT_STELLAR_EVOLUTION_STRUCT_GEAR_H diff --git a/src/feedback/GEAR/supernovae_ia.c b/src/feedback/GEAR/supernovae_ia.c new file mode 100644 index 0000000000000000000000000000000000000000..7d426947474eef2015545c58722338b283ee2c16 --- /dev/null +++ b/src/feedback/GEAR/supernovae_ia.c @@ -0,0 +1,418 @@ +/******************************************************************************* + * This file is part of SWIFT. + * Copyright (c) 2019 Loic Hausammann (loic.hausammann@epfl.ch) + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published + * by the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this program. If not, see <http://www.gnu.org/licenses/>. + * + ******************************************************************************/ + +/* Include header */ +#include "supernovae_ia.h" + +/* Local headers */ +#include "hdf5_functions.h" +#include "stellar_evolution.h" +#include "stellar_evolution_struct.h" + +/** + * @brief Print the supernovae Ia model. + * + * @param snia The #supernovae_ia. + */ +void supernovae_ia_print(const struct supernovae_ia *snia) { + + /* Only the master print */ + if (engine_rank != 0) { + return; + } + + message("Mass of the white dwarf = %g", snia->mass_white_dwarf); + message("Mass range of the progenitor = [%g, %g]", snia->mass_min_progenitor, + snia->mass_max_progenitor); + + for (int i = 0; i < GEAR_NUMBER_TYPE_OF_COMPANION; i++) { + message("Mass range of the companion %i = [%g, %g]", i, + snia->companion[i].mass_min, snia->companion[i].mass_max); + } +} + +/** + * @brief Check if the given mass is able to produce a SNIa. + * + * @param snia The #supernovae_ia model. + * @param m_low The lower mass. + * @param m_high The higher mass. + * + * @return If the mass is in the range of SNIa. + */ +int supernovae_ia_can_explode(const struct supernovae_ia *snia, float m_low, + float m_high) { + + if (m_low > snia->mass_max_progenitor) return 0; + + for (int i = 0; i < GEAR_NUMBER_TYPE_OF_COMPANION; i++) { + if (m_low < snia->companion[i].mass_max && + m_high > snia->companion[i].mass_min) { + return 1; + } + } + + return 0; +} + +/** + * @brief Get the yields of a supernovae Ia. + * + * @param snia The #supernovae_ia model. + */ +const float *supernovae_ia_get_yields(const struct supernovae_ia *snia) { + return snia->yields; +} + +/** + * @brief Get the processed mass ejected of a supernovae Ia. + * + * @param snia The #supernovae_ia model. + */ +float supernovae_ia_get_ejected_mass_processed( + const struct supernovae_ia *snia) { + return snia->mass_white_dwarf; +} + +/** + * @brief Compute the companion integral (second integral in equation 3.46 in + * Poirier 2004) + * + * @param snia The #supernovae_ia model. + * @param m1 The lower mass limit. + * @param m2 The upper mass limit. + * @param companion_type The type of companion (e.g. index of snia->companion). + * + * @return The fraction of companion. + */ +float supernovae_ia_get_companion_fraction(const struct supernovae_ia *snia, + float m1, float m2, + int companion_type) { +#ifdef SWIFT_DEBUG_CHECKS + if (m1 > m2) error("Mass 1 larger than mass 2 %g > %g.", m1, m2); +#endif + + const float tmp = + pow(m2, snia->companion_exponent) - pow(m1, snia->companion_exponent); + return snia->companion[companion_type].coef * tmp / snia->companion_exponent; +} + +/** + * @brief Compute the number of supernovae Ia per unit of mass (equation 3.46 in + * Poirier 2004). + * + * @param snia The #supernovae_ia model. + * @param m1 The lower mass limit. + * @param m2 The upper mass limit. + * + * @return The number of supernovae Ia per unit of mass. + */ +float supernovae_ia_get_number(const struct supernovae_ia *snia, float m1, + float m2) { + +#ifdef SWIFT_DEBUG_CHECKS + if (m1 > m2) error("Mass 1 larger than mass 2 %g > %g.", m1, m2); +#endif + + /* Do we have white dwarf? */ + if (m1 > snia->mass_max_progenitor) { + return 0.; + } + + float number_companion = 0.; + for (int i = 0; i < GEAR_NUMBER_TYPE_OF_COMPANION; i++) { + /* Check if we are in the possible interval */ + if (m1 > snia->companion[i].mass_max || m2 < snia->companion[i].mass_min) + continue; + + /* Get mass limits */ + const float mass_min = max(m1, snia->companion[i].mass_min); + const float mass_max = min(m2, snia->companion[i].mass_max); + + /* Compute number of companions */ + number_companion += + supernovae_ia_get_companion_fraction(snia, mass_min, mass_max, i); + } + + /* Use only the white dwarf already created */ + const float mass_min = max(m1, snia->mass_min_progenitor); + + /* Compute number of white dwarf */ + float number_white_dwarf = + pow(snia->mass_max_progenitor, snia->progenitor_exponent); + number_white_dwarf -= pow(mass_min, snia->progenitor_exponent); + number_white_dwarf *= snia->progenitor_coef_exp; + + return number_companion * number_white_dwarf; +}; + +/** + * @brief Read the SNIa yields from the table. + * + * @param snia The #supernovae_ia model. + * @param params The #swift_params. + * @param sm The #stellar_model. + */ +void supernovae_ia_read_yields(struct supernovae_ia *snia, + struct swift_params *params, + const struct stellar_model *sm) { + + hid_t file_id, group_id; + const int number_labels = GEAR_CHEMISTRY_ELEMENT_COUNT + 2; + + /* Open IMF group */ + h5_open_group(params, "Data/SNIa/Metals", &file_id, &group_id); + + /* Read the yields */ + float *yields = (float *)malloc(sizeof(float) * number_labels); + io_read_array_attribute(group_id, "data", FLOAT, yields, number_labels); + + /* Read the labels */ + char labels[(GEAR_CHEMISTRY_ELEMENT_COUNT + 2) * GEAR_LABELS_SIZE] = ""; + io_read_string_array_attribute(group_id, "elts", labels, number_labels, + GEAR_LABELS_SIZE); + + /* Save the yields */ + /* Loop over the elements in sm */ + for (int i = 0; i < GEAR_CHEMISTRY_ELEMENT_COUNT; i++) { + int found = 0; + /* Loop over SNIa yields labels */ + for (int j = 0; j < number_labels; j++) { + const char *s1 = labels + j * GEAR_LABELS_SIZE; + const char *s2 = stellar_evolution_get_element_name(sm, i); + if (strcmp(s1, s2) == 0) { + found = 1; + snia->yields[i] = yields[j]; + break; + } + } + + /* Check if found an element */ + if (!found) { + error("Cannot find element %s in SNIa yields", + stellar_evolution_get_element_name(sm, i)); + } + } + + /* Cleanup everything */ + free(yields); + h5_close_group(file_id, group_id); +}; + +/** + * @brief Initialize the companion structure in the #supernovae_ia. + */ +void supernovae_ia_init_companion(struct supernovae_ia *snia) { + + for (int i = 0; i < GEAR_NUMBER_TYPE_OF_COMPANION; i++) { + /* Compute the integral */ + float integral = supernovae_ia_get_companion_fraction( + snia, snia->companion[i].mass_min, snia->companion[i].mass_max, i); + + /* Update the coefficient for a normalization to 1 of the IMF */ + snia->companion[i].coef *= snia->companion[i].coef / integral; + } +} + +/** + * @brief Reads the supernovae Ia parameters from the tables. + * + * @param snia The #supernovae_ia model. + * @param params The simulation parameters. + */ +void supernovae_ia_read_from_tables(struct supernovae_ia *snia, + struct swift_params *params) { + + hid_t file_id, group_id; + + /* Open IMF group */ + h5_open_group(params, "Data/SNIa", &file_id, &group_id); + + /* Read the exponent of the IMF for companion */ + io_read_attribute(group_id, "a", FLOAT, &snia->companion_exponent); + + /* Read the minimal mass for a white dwarf progenitor */ + io_read_attribute(group_id, "Mpl", FLOAT, &snia->mass_min_progenitor); + + /* Read the maximal mass for a white dwarf */ + io_read_attribute(group_id, "Mpu", FLOAT, &snia->mass_max_progenitor); + + /* Read the maximal mass of a red giant companion */ + io_read_attribute(group_id, "Mdu1", FLOAT, &snia->companion[0].mass_max); + + /* Read the minimal mass of a red giant companion */ + io_read_attribute(group_id, "Mdl1", FLOAT, &snia->companion[0].mass_min); + + /* Read the coefficient of the main sequence companion */ + io_read_attribute(group_id, "bb1", FLOAT, &snia->companion[0].coef); + + /* Read the maximal mass of a main sequence companion */ + io_read_attribute(group_id, "Mdu2", FLOAT, &snia->companion[1].mass_max); + + /* Read the minimal mass of a main sequence companion */ + io_read_attribute(group_id, "Mdl2", FLOAT, &snia->companion[1].mass_min); + + /* Read the coefficient of the main sequence companion */ + io_read_attribute(group_id, "bb2", FLOAT, &snia->companion[1].coef); + + /* Cleanup everything */ + h5_close_group(file_id, group_id); + + /* Read the white dwarf mass */ + + /* Open IMF group */ + h5_open_group(params, "Data", &file_id, &group_id); + + /* Read the white dwarf mass */ + io_read_attribute(group_id, "MeanWDMass", FLOAT, &snia->mass_white_dwarf); + + /* Cleanup everything */ + h5_close_group(file_id, group_id); +} + +/** + * @brief Reads the supernovae Ia parameters from the parameters file. + * + * @param snia The #supernovae_ia model. + * @param params The simulation parameters. + */ +void supernovae_ia_read_from_params(struct supernovae_ia *snia, + struct swift_params *params) { + + /* Read the exponent of the IMF for companion */ + snia->companion_exponent = parser_get_opt_param_float( + params, "GEARSupernovaeIa:exponent", snia->companion_exponent); + + /* Read the minimal mass for a white dwarf */ + snia->mass_min_progenitor = parser_get_opt_param_float( + params, "GEARSupernovaeIa:min_mass_white_dwarf_progenitor", + snia->mass_min_progenitor); + + /* Read the maximal mass for a white dwarf */ + snia->mass_max_progenitor = parser_get_opt_param_float( + params, "GEARSupernovaeIa:max_mass_white_dwarf_progenitor", + snia->mass_max_progenitor); + + /* Read the maximal mass of a red giant companion */ + snia->companion[0].mass_max = + parser_get_opt_param_float(params, "GEARSupernovaeIa:max_mass_red_giant", + snia->companion[0].mass_max); + + /* Read the minimal mass of a red giant companion */ + snia->companion[0].mass_min = + parser_get_opt_param_float(params, "GEARSupernovaeIa:min_mass_red_giant", + snia->companion[0].mass_min); + + /* Read the coefficient of the main sequence companion */ + snia->companion[0].coef = parser_get_opt_param_float( + params, "GEARSupernovaeIa:coef_red_giant", snia->companion[0].coef); + + /* Read the maximal mass of a main sequence companion */ + snia->companion[1].mass_max = parser_get_opt_param_float( + params, "GEARSupernovaeIa:max_mass_main_sequence", + snia->companion[1].mass_max); + + /* Read the minimal mass of a main sequence companion */ + snia->companion[1].mass_min = parser_get_opt_param_float( + params, "GEARSupernovaeIa:min_mass_main_sequence", + snia->companion[1].mass_min); + + /* Read the coefficient of the main sequence companion */ + snia->companion[1].coef = parser_get_opt_param_float( + params, "GEARSupernovaeIa:coef_main_sequence", snia->companion[1].coef); + + /* Read the mass of a white dwarf */ + snia->mass_white_dwarf = parser_get_opt_param_float( + params, "GEARSupernovaeIa:white_dwarf_mass", snia->mass_white_dwarf); +} + +/** + * @brief Initialize the #supernovae_ia structure. + * + * @param snia The #supernovae_ia model. + * @param phys_const The #phys_const. + * @param us The #unit_system. + * @param params The simulation parameters. + * @param sm The #stellar_model. + */ +void supernovae_ia_init(struct supernovae_ia *snia, + const struct phys_const *phys_const, + const struct unit_system *us, + struct swift_params *params, + const struct stellar_model *sm) { + + /* Read the parameters from the tables */ + supernovae_ia_read_from_tables(snia, params); + + /* Read the parameters from the params file */ + supernovae_ia_read_from_params(snia, params); + + /* Read the yields */ + supernovae_ia_read_yields(snia, params, sm); + + /* Get the IMF parameters */ + snia->progenitor_exponent = initial_mass_function_get_exponent( + &sm->imf, snia->mass_min_progenitor, snia->mass_max_progenitor); + snia->progenitor_coef_exp = initial_mass_function_get_coefficient( + &sm->imf, snia->mass_min_progenitor, snia->mass_max_progenitor); + snia->progenitor_coef_exp /= snia->progenitor_exponent; + + /* Compute the normalization coefficients of the companion IMF */ + supernovae_ia_init_companion(snia); +} + +/** + * @brief Write a supernovae_ia struct to the given FILE as a stream of bytes. + * + * Here we are only writing the arrays, everything else has been copied in the + * feedback. + * + * @param snia the struct + * @param stream the file stream + * @param sm The #stellar_model. + */ +void supernovae_ia_dump(const struct supernovae_ia *snia, FILE *stream, + const struct stellar_model *sm) { + + /* Nothing to do here */ +} + +/** + * @brief Restore a supernovae_ia struct from the given FILE as a stream of + * bytes. + * + * Here we are only writing the arrays, everything else has been copied in the + * feedback. + * + * @param snia the struct + * @param stream the file stream + * @param sm The #stellar_model. + */ +void supernovae_ia_restore(struct supernovae_ia *snia, FILE *stream, + const struct stellar_model *sm) { + + /* Nothing to do here */ +} + +/** + * @brief Clean the allocated memory. + * + * @param snia the #supernovae_ia. + */ +void supernovae_ia_clean(struct supernovae_ia *snia) {} diff --git a/src/feedback/GEAR/supernovae_ia.h b/src/feedback/GEAR/supernovae_ia.h new file mode 100644 index 0000000000000000000000000000000000000000..19a6923c2ded6f2d80fdff441d9efb4ee9fb9296 --- /dev/null +++ b/src/feedback/GEAR/supernovae_ia.h @@ -0,0 +1,63 @@ +/******************************************************************************* + * This file is part of SWIFT. + * Copyright (c) 2019 Loic Hausammann (loic.hausammann@epfl.ch) + * + * 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_SUPERNOVAE_IA_GEAR_H +#define SWIFT_SUPERNOVAE_IA_GEAR_H + +#include "hdf5_functions.h" +#include "stellar_evolution.h" +#include "stellar_evolution_struct.h" + +void supernovae_ia_print(const struct supernovae_ia *snia); +int supernovae_ia_can_explode(const struct supernovae_ia *snia, float m_low, + float m_high); +const float *supernovae_ia_get_yields(const struct supernovae_ia *snia); +float supernovae_ia_get_ejected_mass_processed( + const struct supernovae_ia *snia); +float supernovae_ia_get_companion_fraction(const struct supernovae_ia *snia, + float m1, float m2, + int companion_type); +float supernovae_ia_get_number(const struct supernovae_ia *snia, float m1, + float m2); + +void supernovae_ia_read_yields(struct supernovae_ia *snia, + struct swift_params *params, + const struct stellar_model *sm); + +void supernovae_ia_init_companion(struct supernovae_ia *snia); + +void supernovae_ia_read_from_tables(struct supernovae_ia *snia, + struct swift_params *params); + +void supernovae_ia_read_from_params(struct supernovae_ia *snia, + struct swift_params *params); + +void supernovae_ia_init(struct supernovae_ia *snia, + const struct phys_const *phys_const, + const struct unit_system *us, + struct swift_params *params, + const struct stellar_model *sm); + +void supernovae_ia_dump(const struct supernovae_ia *snia, FILE *stream, + const struct stellar_model *sm); + +void supernovae_ia_restore(struct supernovae_ia *snia, FILE *stream, + const struct stellar_model *sm); +void supernovae_ia_clean(struct supernovae_ia *snia); + +#endif // SWIFT_SUPERNOVAE_IA_GEAR_H diff --git a/src/feedback/GEAR/supernovae_ii.c b/src/feedback/GEAR/supernovae_ii.c new file mode 100644 index 0000000000000000000000000000000000000000..8b44afe834531f6049db75e0e9071e3918a4c905 --- /dev/null +++ b/src/feedback/GEAR/supernovae_ii.c @@ -0,0 +1,432 @@ +/******************************************************************************* + * This file is part of SWIFT. + * Copyright (c) 2019 Loic Hausammann (loic.hausammann@epfl.ch) + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published + * by the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this program. If not, see <http://www.gnu.org/licenses/>. + * + ******************************************************************************/ + +/* Include header */ +#include "supernovae_ii.h" + +/* Local headers */ +#include "hdf5_functions.h" +#include "interpolation.h" +#include "stellar_evolution.h" +#include "stellar_evolution_struct.h" + +/** + * @brief Print the supernovae II model. + * + * @param snii The #supernovae_ii. + */ +void supernovae_ii_print(const struct supernovae_ii *snii) { + + /* Only the master print */ + if (engine_rank != 0) { + return; + } + + message("Mass range for SNII = [%g, %g]", snii->mass_min, snii->mass_max); +} + +/** + * @brief Check if the given mass is able to produce a SNII. + * + * @param snii The #supernovae_ii model. + * @param m_low The lower mass. + * @param m_high The higher mass + * + * @return If the mass is in the range of SNII. + */ +int supernovae_ii_can_explode(const struct supernovae_ii *snii, float m_low, + float m_high) { + + if (m_high < snii->mass_min || m_low > snii->mass_max) return 0; + + return 1; +} + +/** + * @brief Compute the number of supernovae II per unit of mass (equation 3.47 in + * Poirier 2004). + * + * @param snii The #supernovae_ii model. + * @param m1 The lower mass limit. + * @param m2 The upper mass limit. + * + * @return The number of supernovae II per unit of mass. + */ +float supernovae_ii_get_number(const struct supernovae_ii *snii, float m1, + float m2) { +#ifdef SWIFT_DEBUG_CHECKS + if (m1 > m2) error("Mass 1 larger than mass 2 %g > %g.", m1, m2); +#endif + + /* Can we explode SNII? */ + if (!supernovae_ii_can_explode(snii, m1, m2)) { + return 0.; + } + + const float mass_min = max(m1, snii->mass_min); + const float mass_max = min(m2, snii->mass_max); + + const float pow_mass = + pow(mass_max, snii->exponent) - pow(mass_min, snii->exponent); + + return snii->coef_exp * pow_mass; +}; + +/** + * @brief Get the SNII yields per mass (Poirier version). + * + * @param snii The #supernovae_ii model. + * @param m1 The lower mass in log. + * @param m2 The upper mass in log. + * @param yields The elements ejected (needs to be allocated). + */ +void supernovae_ii_get_yields(const struct supernovae_ii *snii, float log_m1, + float log_m2, float *yields) { + + for (int i = 0; i < GEAR_CHEMISTRY_ELEMENT_COUNT; i++) { + float yields_1 = interpolate_1d(&snii->integrated_yields[i], log_m1); + float yields_2 = interpolate_1d(&snii->integrated_yields[i], log_m2); + + yields[i] = yields_2 - yields_1; + } +}; + +/** + * @brief Get the ejected mass per mass unit. + * + * @param snii The #supernovae_ii model. + * @param m1 The lower mass in log. + * @param m2 The upper mass in log. + * + * @return mass_ejected_processed The mass of processsed elements. + */ +float supernovae_ii_get_ejected_mass_fraction(const struct supernovae_ii *snii, + float log_m1, float log_m2) { + + float mass_ejected_1 = interpolate_1d(&snii->integrated_ejected_mass, log_m1); + float mass_ejected_2 = interpolate_1d(&snii->integrated_ejected_mass, log_m2); + + return mass_ejected_2 - mass_ejected_1; +}; + +/** + * @brief Get the ejected mass (processed) per mass. + * + * @param snii The #supernovae_ii model. + * @param log_m1 The lower mass in log. + * @param log_m2 The upper mass in log. + * + * @return mass_ejected The mass of non processsed elements. + */ +float supernovae_ii_get_ejected_mass_fraction_processed( + const struct supernovae_ii *snii, float log_m1, float log_m2) { + + float mass_ejected_1 = + interpolate_1d(&snii->integrated_ejected_mass_processed, log_m1); + float mass_ejected_2 = + interpolate_1d(&snii->integrated_ejected_mass_processed, log_m2); + + return mass_ejected_2 - mass_ejected_1; +}; + +/** + * @brief Read an array of SNII yields from the table. + * + * @param snii The #supernovae_ii model. + * @param sm The #stellar_model. + */ +void supernovae_ii_read_yields_array( + struct supernovae_ii *snii, struct interpolation_1d *interp, + const struct phys_const *phys_const, const struct stellar_model *sm, + hid_t group_id, const char *hdf5_dataset_name, hsize_t *previous_count, + int interpolation_size) { + + /* Now let's get the number of elements */ + /* Open attribute */ + const hid_t h_dataset = H5Dopen(group_id, hdf5_dataset_name, H5P_DEFAULT); + if (h_dataset < 0) + error("Error while opening attribute '%s'", hdf5_dataset_name); + + /* Get the number of elements */ + hsize_t count = io_get_number_element_in_dataset(h_dataset); + + /* Check that all the arrays have the same size */ + if (*previous_count != 0 && count != *previous_count) { + error("The code is not able to deal with yields arrays of different size"); + } + *previous_count = count; + + /* Read the minimal mass (in log) */ + float log_mass_min = 0; + io_read_attribute(h_dataset, "min", FLOAT, &log_mass_min); + + /* Read the step size (log step) */ + float step_size = 0; + io_read_attribute(h_dataset, "step", FLOAT, &step_size); + + /* Close the attribute */ + H5Dclose(h_dataset); + + /* Allocate the memory */ + float *data = (float *)malloc(sizeof(float) * count); + if (data == NULL) + error("Failed to allocate the SNII yields for %s.", hdf5_dataset_name); + + /* Read the dataset */ + io_read_array_dataset(group_id, hdf5_dataset_name, FLOAT, data, count); + + /* Initialize the interpolation */ + interpolate_1d_init(interp, log10(snii->mass_min), log10(snii->mass_max), + interpolation_size, log_mass_min, step_size, count, data, + boundary_condition_zero); + + /* Integrate the yields */ + initial_mass_function_integrate(&sm->imf, interp); + + /* Cleanup the memory */ + free(data); +} + +/** + * @brief Read the SNII yields from the table. + * + * The tables are in internal units at the end of this function. + * + * @param snii The #supernovae_ii model. + * @param params The simulation parameters. + * @param sm The #stellar_model. + */ +void supernovae_ii_read_yields(struct supernovae_ii *snii, + struct swift_params *params, + const struct phys_const *phys_const, + const struct stellar_model *sm) { + + hid_t file_id, group_id; + + hsize_t previous_count = 0; + + const int interpolation_size = parser_get_opt_param_int( + params, "GEARSupernovaeII:interpolation_size", 200); + + /* Open IMF group */ + h5_open_group(params, "Data/SNII", &file_id, &group_id); + + /* Do all the elements */ + for (int i = 0; i < GEAR_CHEMISTRY_ELEMENT_COUNT; i++) { + + /* Get the element name */ + const char *name = stellar_evolution_get_element_name(sm, i); + + /* Read the array */ + supernovae_ii_read_yields_array(snii, &snii->integrated_yields[i], + phys_const, sm, group_id, name, + &previous_count, interpolation_size); + } + + /* Read the mass ejected */ + supernovae_ii_read_yields_array( + snii, &snii->integrated_ejected_mass_processed, phys_const, sm, group_id, + "Ej", &previous_count, interpolation_size); + + /* Read the mass ejected of non processed gas */ + supernovae_ii_read_yields_array(snii, &snii->integrated_ejected_mass, + phys_const, sm, group_id, "Ejnp", + &previous_count, interpolation_size); + + /* Cleanup everything */ + h5_close_group(file_id, group_id); +}; + +/** + * @brief Reads the supernovae II parameters from parameters file. + * + * @param snii The #supernovae_ii model. + * @param params The simulation parameters. + */ +void supernovae_ii_read_from_params(struct supernovae_ii *snii, + struct swift_params *params) { + + /* Read the minimal mass of a supernovae */ + snii->mass_min = parser_get_opt_param_float( + params, "GEARSupernovaeII:min_mass", snii->mass_min); + + /* Read the maximal mass of a supernovae */ + snii->mass_max = parser_get_opt_param_float( + params, "GEARSupernovaeII:max_mass", snii->mass_max); +} + +/** + * @brief Reads the supernovae II parameters from tables. + * + * @param snii The #supernovae_ii model. + * @param params The simulation parameters. + */ +void supernovae_ii_read_from_tables(struct supernovae_ii *snii, + struct swift_params *params) { + + hid_t file_id, group_id; + + /* Open IMF group */ + h5_open_group(params, "Data/SNII", &file_id, &group_id); + + /* Read the minimal mass of a supernovae */ + io_read_attribute(group_id, "Mmin", FLOAT, &snii->mass_min); + + /* Read the maximal mass of a supernovae */ + io_read_attribute(group_id, "Mmax", FLOAT, &snii->mass_max); + + /* Cleanup everything */ + h5_close_group(file_id, group_id); +} + +/** + * @brief Initialize the #supernovae_ii structure. + * + * @param snii The #supernovae_ii model. + * @param phys_const The #phys_const. + * @param us The #unit_system. + * @param params The simulation parameters. + * @param sm The #stellar_model. + */ +void supernovae_ii_init(struct supernovae_ii *snii, + const struct phys_const *phys_const, + const struct unit_system *us, + struct swift_params *params, + const struct stellar_model *sm) { + + /* Read the parameters from the tables */ + supernovae_ii_read_from_tables(snii, params); + + /* Read the parameters from the params file */ + supernovae_ii_read_from_tables(snii, params); + + /* Read the supernovae yields (and apply the units) */ + supernovae_ii_read_yields(snii, params, phys_const, sm); + + /* Get the IMF parameters */ + snii->exponent = initial_mass_function_get_exponent(&sm->imf, snii->mass_min, + snii->mass_max); + snii->coef_exp = initial_mass_function_get_coefficient( + &sm->imf, snii->mass_min, snii->mass_max); + snii->coef_exp /= snii->exponent; +} + +/** + * @brief Write a supernovae_ii struct to the given FILE as a stream of bytes. + * + * Here we are only writing the arrays, everything else has been copied in the + * feedback. + * + * @param snii the struct + * @param stream the file stream + */ +void supernovae_ii_dump(const struct supernovae_ii *snii, FILE *stream, + const struct stellar_model *sm) { + + /* Dump the yields. */ + for (int i = 0; i < GEAR_CHEMISTRY_ELEMENT_COUNT; i++) { + if (snii->integrated_yields[i].data == NULL) { + continue; + } + + const char *name = stellar_evolution_get_element_name(sm, i); + restart_write_blocks((void *)snii->integrated_yields[i].data, sizeof(float), + snii->integrated_yields[i].N, stream, name, name); + } + + /*! Dump the processed mass. */ + if (snii->integrated_ejected_mass_processed.data != NULL) { + restart_write_blocks((void *)snii->integrated_ejected_mass_processed.data, + sizeof(float), + snii->integrated_ejected_mass_processed.N, stream, + "processed_mass", "processed_mass"); + } + + /*! Dump the non processed mass. */ + if (snii->integrated_ejected_mass.data != NULL) { + restart_write_blocks((void *)snii->integrated_ejected_mass.data, + sizeof(float), snii->integrated_ejected_mass.N, stream, + "non_processed_mass", "non_processed_mass"); + } +} + +/** + * @brief Restore a supernovae_ii struct from the given FILE as a stream of + * bytes. + * + * Here we are only writing the arrays, everything else has been copied in the + * feedback. + * + * @param snii the struct + * @param stream the file stream + */ +void supernovae_ii_restore(struct supernovae_ii *snii, FILE *stream, + const struct stellar_model *sm) { + + /* Restore the yields */ + for (int i = 0; i < GEAR_CHEMISTRY_ELEMENT_COUNT; i++) { + if (snii->integrated_yields[i].data == NULL) { + continue; + } + + const char *name = stellar_evolution_get_element_name(sm, i); + snii->integrated_yields[i].data = + (float *)malloc(sizeof(float) * snii->integrated_yields[i].N); + + restart_read_blocks((void *)snii->integrated_yields[i].data, sizeof(float), + snii->integrated_yields[i].N, stream, NULL, name); + } + + /* Restore the processed mass */ + + if (snii->integrated_ejected_mass_processed.data != NULL) { + snii->integrated_ejected_mass_processed.data = (float *)malloc( + sizeof(float) * snii->integrated_ejected_mass_processed.N); + + restart_read_blocks((void *)snii->integrated_ejected_mass_processed.data, + sizeof(float), + snii->integrated_ejected_mass_processed.N, stream, NULL, + "processed_mass"); + } + + /* Restore the non processed mass */ + if (snii->integrated_ejected_mass.data != NULL) { + snii->integrated_ejected_mass.data = + (float *)malloc(sizeof(float) * snii->integrated_ejected_mass.N); + + restart_read_blocks((void *)snii->integrated_ejected_mass.data, + sizeof(float), snii->integrated_ejected_mass.N, stream, + NULL, "non_processed_mass"); + } +} + +/** + * @brief Clean the allocated memory. + * + * @param snii the #supernovae_ii. + */ +void supernovae_ii_clean(struct supernovae_ii *snii) { + + for (int i = 0; i < GEAR_CHEMISTRY_ELEMENT_COUNT; i++) { + interpolate_1d_free(&snii->integrated_yields[i]); + } + + interpolate_1d_free(&snii->integrated_ejected_mass_processed); + interpolate_1d_free(&snii->integrated_ejected_mass); +} diff --git a/src/feedback/GEAR/supernovae_ii.h b/src/feedback/GEAR/supernovae_ii.h new file mode 100644 index 0000000000000000000000000000000000000000..515e320b58411f426a109c4b1e1664b92caf2efa --- /dev/null +++ b/src/feedback/GEAR/supernovae_ii.h @@ -0,0 +1,67 @@ +/******************************************************************************* + * This file is part of SWIFT. + * Copyright (c) 2019 Loic Hausammann (loic.hausammann@epfl.ch) + * + * 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_SUPERNOVAE_II_GEAR_H +#define SWIFT_SUPERNOVAE_II_GEAR_H + +#include "hdf5_functions.h" +#include "interpolation.h" +#include "stellar_evolution_struct.h" + +/** + * @brief Print the supernovae II model. + * + * @param snii The #supernovae_ii. + */ +void supernovae_ii_print(const struct supernovae_ii *snii); +int supernovae_ii_can_explode(const struct supernovae_ii *snii, float m_low, + float m_high); +float supernovae_ii_get_number(const struct supernovae_ii *snii, float m1, + float m2); +void supernovae_ii_get_yields(const struct supernovae_ii *snii, float log_m1, + float log_m2, float *yields); +float supernovae_ii_get_ejected_mass_fraction(const struct supernovae_ii *snii, + float log_m1, float log_m2); + +float supernovae_ii_get_ejected_mass_fraction_processed( + const struct supernovae_ii *snii, float log_m1, float log_m2); +void supernovae_ii_read_yields_array( + struct supernovae_ii *snii, struct interpolation_1d *interp, + const struct phys_const *phys_const, const struct stellar_model *sm, + hid_t group_id, const char *hdf5_dataset_name, hsize_t *previous_count, + int interpolation_size); +void supernovae_ii_read_yields(struct supernovae_ii *snii, + struct swift_params *params, + const struct phys_const *phys_const, + const struct stellar_model *sm); +void supernovae_ii_read_from_params(struct supernovae_ii *snii, + struct swift_params *params); + +void supernovae_ii_read_from_tables(struct supernovae_ii *snii, + struct swift_params *params); +void supernovae_ii_init(struct supernovae_ii *snii, + const struct phys_const *phys_const, + const struct unit_system *us, + struct swift_params *params, + const struct stellar_model *sm); +void supernovae_ii_dump(const struct supernovae_ii *snii, FILE *stream, + const struct stellar_model *sm); +void supernovae_ii_restore(struct supernovae_ii *snii, FILE *stream, + const struct stellar_model *sm); +void supernovae_ii_clean(struct supernovae_ii *snii); +#endif // SWIFT_SUPERNOVAE_II_GEAR_H diff --git a/src/feedback/none/feedback.h b/src/feedback/none/feedback.h index dd2ffd3d89cecffd024a7987d73e9d178165d7c1..7c83e9ed5d6f58a9f389d8c4024f5bc10ff62c90 100644 --- a/src/feedback/none/feedback.h +++ b/src/feedback/none/feedback.h @@ -26,6 +26,20 @@ #include "part.h" #include "units.h" +/** + * @brief Update the properties of a particle fue to feedback effects after + * the cooling was applied. + * + * Nothing to do here. + * + * @param p The #part to consider. + * @param xp The #xpart to consider. + * @param cosmo The #cosmology. + */ +__attribute__((always_inline)) INLINE static void feedback_update_part( + struct part* restrict p, struct xpart* restrict xp, + const struct engine* restrict e) {} + /** * @brief Prepares a s-particle for its feedback interactions * @@ -64,6 +78,29 @@ __attribute__((always_inline)) INLINE static int feedback_is_active( return 1; } +/** + * @brief Returns the length of time since the particle last did + * enrichment/feedback. + * + * We just return the normal time-step here since particles do something every + * regular time-step. + * + * @param sp The #spart. + * @param with_cosmology Are we running with cosmological time integration on? + * @param cosmo The cosmological model. + * @param time The current time (since the Big Bang / start of the run) in + * internal units. + * @param dt_star the length of this particle's time-step in internal units. + * @return The length of the enrichment step in internal units. + */ +INLINE static double feedback_get_enrichment_timestep( + const struct spart* sp, const int with_cosmology, + const struct cosmology* cosmo, const double time, const double dt_star) { + + /* Just return the regular step length */ + return dt_star; +} + /** * @brief Prepares a star's feedback field before computing what * needs to be distributed. @@ -105,14 +142,45 @@ __attribute__((always_inline)) INLINE static void feedback_prepare_spart( * @param feedback_props The #feedback_props structure. * @param cosmo The current cosmological model. * @param us The unit system. + * @param phys_const The #phys_const. * @param star_age_beg_step The age of the star at the star of the time-step in * internal units. * @param dt The time-step size of this star in internal units. + * @param time The physical time in internal units. + * @param ti_begin The integer time at the beginning of the step. + * @param with_cosmology Are we running with cosmology on? */ __attribute__((always_inline)) INLINE static void feedback_evolve_spart( struct spart* restrict sp, const struct feedback_props* feedback_props, const struct cosmology* cosmo, const struct unit_system* us, - const double star_age_beg_step, const double dt) {} + const struct phys_const* phys_const, const double star_age_beg_step, + const double dt, const double time, const integertime_t ti_begin, + const int with_cosmology) {} + +/** + * @brief Will this star particle want to do feedback during the next time-step? + * + * @param sp The star of interest. + * @param feedback_props The properties of the feedback model. + * @param with_cosmology Are we running with cosmological time integration? + * @param cosmo The #cosmology object. + * @param time The current time (since the Big Bang). + */ +__attribute__((always_inline)) INLINE static int feedback_will_do_feedback( + struct spart* restrict sp, const struct feedback_props* feedback_props, + const int with_cosmology, const struct cosmology* cosmo, + const double time) { + return 1; +} + +/** + * @brief Clean-up the memory allocated for the feedback routines + * + * We simply free all the arrays. + * + * @param feedback_props the feedback data structure. + */ +static INLINE void feedback_clean(struct feedback_props* feedback_props) {} /** * @brief Write a feedback struct to the given FILE as a stream of bytes. @@ -134,4 +202,16 @@ static INLINE void feedback_struct_dump(const struct feedback_props* feedback, static INLINE void feedback_struct_restore(struct feedback_props* feedback, FILE* stream) {} +#ifdef HAVE_HDF5 +/** + * @brief Writes the current model of feedback to the file + * @param h_grpsph The HDF5 group in which to write + */ +INLINE static void feedback_write_flavour(struct feedback_props* feedback, + hid_t h_grp) { + + io_write_attribute_s(h_grp, "Feedback Model", "None"); +}; +#endif + #endif /* SWIFT_FEEDBACK_NONE_H */ diff --git a/src/feedback/none/feedback_iact.h b/src/feedback/none/feedback_iact.h index 1c2613337a17d55ec1e3c9defd742b1ed0c41fd8..fe8e19eca7af1543a5716ad9e0ac03779913d488 100644 --- a/src/feedback/none/feedback_iact.h +++ b/src/feedback/none/feedback_iact.h @@ -37,10 +37,9 @@ __attribute__((always_inline)) INLINE static void runner_iact_nonsym_feedback_density(const float r2, const float *dx, const float hi, const float hj, - struct spart *restrict si, - const struct part *restrict pj, - const struct xpart *restrict xp, - const struct cosmology *restrict cosmo, + struct spart *si, const struct part *pj, + const struct xpart *xp, + const struct cosmology *cosmo, const integertime_t ti_current) {} /** @@ -63,10 +62,9 @@ runner_iact_nonsym_feedback_density(const float r2, const float *dx, __attribute__((always_inline)) INLINE static void runner_iact_nonsym_feedback_apply(const float r2, const float *dx, const float hi, const float hj, - const struct spart *restrict si, - struct part *restrict pj, - struct xpart *restrict xp, - const struct cosmology *restrict cosmo, + const struct spart *si, struct part *pj, + struct xpart *xp, + const struct cosmology *cosmo, const integertime_t ti_current) {} #endif /* SWIFT_NONE_FEEDBACK_IACT_H */ diff --git a/src/feedback/none/feedback_struct.h b/src/feedback/none/feedback_struct.h index 0dde77bbd7e58a1768abfd285af2804be7c28865..23506c34ac836a65a7b5cf1f90f8912b3c259d80 100644 --- a/src/feedback/none/feedback_struct.h +++ b/src/feedback/none/feedback_struct.h @@ -21,6 +21,11 @@ #include "chemistry_struct.h" +/** + * @brief Feedback fields carried by each hydro particles + */ +struct feedback_part_data {}; + /** * @brief Feedback fields carried by each star particles * diff --git a/src/feedback_properties.h b/src/feedback_properties.h index 83afbb1eeac2aeab080d9c564542b180ea1429af..32729203a48bc9f04d1c9aa1f6a5d44914efe6e9 100644 --- a/src/feedback_properties.h +++ b/src/feedback_properties.h @@ -27,6 +27,8 @@ #include "./feedback/none/feedback_properties.h" #elif defined(FEEDBACK_EAGLE) #include "./feedback/EAGLE/feedback_properties.h" +#elif defined(FEEDBACK_GEAR) +#include "./feedback/GEAR/feedback_properties.h" #else #error "Invalid choice of feedback model" #endif diff --git a/src/feedback_struct.h b/src/feedback_struct.h index be6d480e7a7a6165fd6f73e4ca0ed15078f06488..09009b2ba6081236483a58b3c4d976ee362946a0 100644 --- a/src/feedback_struct.h +++ b/src/feedback_struct.h @@ -32,6 +32,8 @@ #include "./feedback/none/feedback_struct.h" #elif defined(FEEDBACK_EAGLE) #include "./feedback/EAGLE/feedback_struct.h" +#elif defined(FEEDBACK_GEAR) +#include "./feedback/GEAR/feedback_struct.h" #else #error "Invalid choice of feedback function." #endif diff --git a/src/fof.c b/src/fof.c index 7d8af4ca33d8dde18c70d46ecbce14611171abfb..51f35227d4441971e25f46dbc6e57ccfaddb43b7 100644 --- a/src/fof.c +++ b/src/fof.c @@ -245,12 +245,42 @@ void fof_set_initial_group_id_mapper(void *map_data, int num_elements, void fof_allocate(const struct space *s, const long long total_nr_DM_particles, struct fof_props *props) { + const int verbose = s->e->verbose; + const ticks total_tic = getticks(); + + /* Start by computing the mean inter DM particle separation */ + + /* Collect the mass of the first non-background gpart */ + double high_res_DM_mass = 0.; + for (size_t i = 0; i < s->nr_gparts; ++i) { + const struct gpart *gp = &s->gparts[i]; + if (gp->type == swift_type_dark_matter && + gp->time_bin != time_bin_inhibited && + gp->time_bin != time_bin_not_created) { + high_res_DM_mass = gp->mass; + break; + } + } + + /* Calculate the mean inter-particle separation as if we were in + a scenario where the entire box was filled with high-resolution + particles */ + const double Omega_m = s->e->cosmology->Omega_m; + const double Omega_b = s->e->cosmology->Omega_b; + const double critical_density_0 = s->e->cosmology->critical_density_0; + double mean_matter_density; + if (s->with_hydro) + mean_matter_density = (Omega_m - Omega_b) * critical_density_0; + else + mean_matter_density = Omega_m * critical_density_0; + + /* Mean inter-particle separation of the DM particles */ + const double mean_inter_particle_sep = + cbrt(high_res_DM_mass / mean_matter_density); + /* Calculate the particle linking length based upon the mean inter-particle * spacing of the DM particles. */ - const double mean_inter_particle_sep = - s->dim[0] / cbrt((double)total_nr_DM_particles); const double l_x = props->l_x_ratio * mean_inter_particle_sep; - int verbose = s->e->verbose; /* Are we using the aboslute value or the one derived from the mean inter-particle sepration? */ @@ -314,6 +344,10 @@ void fof_allocate(const struct space *s, const long long total_nr_DM_particles, #ifdef SWIFT_DEBUG_CHECKS ti_current = s->e->ti_current; #endif + + if (verbose) + message("took %.3f %s.", clocks_from_ticks(getticks() - total_tic), + clocks_getunit()); } /** @@ -1968,6 +2002,9 @@ void fof_seed_black_holes(const struct fof_props *props, /* Set a smoothing length */ bp->h = p->h; + /* Save the ID */ + bp->id = p->id; + #ifdef SWIFT_DEBUG_CHECKS bp->ti_kick = p->ti_kick; bp->ti_drift = p->ti_drift; @@ -2271,7 +2308,7 @@ void fof_search_foreign_cells(struct fof_props *props, const struct space *s) { tic = getticks(); /* Perform send and receive tasks. */ - engine_launch(e); + engine_launch(e, "fof comms"); if (verbose) message("MPI send/recv comms took: %.3f %s.", @@ -2942,8 +2979,8 @@ void fof_search_tree(struct fof_props *props, message("Largest group by size: %d", max_group_size); } if (verbose) - message("FOF search took: %.3f %s.", - clocks_from_ticks(getticks() - tic_total), clocks_getunit()); + message("took %.3f %s.", clocks_from_ticks(getticks() - tic_total), + clocks_getunit()); #ifdef WITH_MPI MPI_Barrier(MPI_COMM_WORLD); diff --git a/src/gravity/Default/gravity_io.h b/src/gravity/Default/gravity_io.h index fea193e92cfe738880ef146b199253c7300501b4..fb828b2239bcdf998f6d3e20123ad44400e0fa8c 100644 --- a/src/gravity/Default/gravity_io.h +++ b/src/gravity/Default/gravity_io.h @@ -24,10 +24,11 @@ INLINE static void convert_gpart_pos(const struct engine* e, const struct gpart* gp, double* ret) { - if (e->s->periodic) { - ret[0] = box_wrap(gp->x[0], 0.0, e->s->dim[0]); - ret[1] = box_wrap(gp->x[1], 0.0, e->s->dim[1]); - ret[2] = box_wrap(gp->x[2], 0.0, e->s->dim[2]); + const struct space* s = e->s; + if (s->periodic) { + ret[0] = box_wrap(gp->x[0] - s->pos_dithering[0], 0.0, s->dim[0]); + ret[1] = box_wrap(gp->x[1] - s->pos_dithering[1], 0.0, s->dim[1]); + ret[2] = box_wrap(gp->x[2] - s->pos_dithering[2], 0.0, s->dim[2]); } else { ret[0] = gp->x[0]; ret[1] = gp->x[1]; diff --git a/src/gravity/Default/gravity_part.h b/src/gravity/Default/gravity_part.h index 29f6bb6a64202c3fc3407407932e8f2e31f994af..bf0d612b077579829bffd69b5e821d86c75345c1 100644 --- a/src/gravity/Default/gravity_part.h +++ b/src/gravity/Default/gravity_part.h @@ -51,6 +51,11 @@ struct gpart { /*! Type of the #gpart (DM, gas, star, ...) */ enum part_type type; +#ifdef WITH_LOGGER + /* Additional data for the particle logger */ + struct logger_part_data logger_data; +#endif + #ifdef SWIFT_DEBUG_CHECKS /* Numer of gparts this gpart interacted with */ diff --git a/src/gravity/MultiSoftening/gravity_io.h b/src/gravity/MultiSoftening/gravity_io.h index 412a270afef5d3e7ab75530184782479aaa46b82..1c6f254427de9bf55fc77ca28a7e19090e86de19 100644 --- a/src/gravity/MultiSoftening/gravity_io.h +++ b/src/gravity/MultiSoftening/gravity_io.h @@ -24,10 +24,11 @@ INLINE static void convert_gpart_pos(const struct engine* e, const struct gpart* gp, double* ret) { - if (e->s->periodic) { - ret[0] = box_wrap(gp->x[0], 0.0, e->s->dim[0]); - ret[1] = box_wrap(gp->x[1], 0.0, e->s->dim[1]); - ret[2] = box_wrap(gp->x[2], 0.0, e->s->dim[2]); + const struct space* s = e->s; + if (s->periodic) { + ret[0] = box_wrap(gp->x[0] - s->pos_dithering[0], 0.0, s->dim[0]); + ret[1] = box_wrap(gp->x[1] - s->pos_dithering[1], 0.0, s->dim[1]); + ret[2] = box_wrap(gp->x[2] - s->pos_dithering[2], 0.0, s->dim[2]); } else { ret[0] = gp->x[0]; ret[1] = gp->x[1]; diff --git a/src/gravity/MultiSoftening/gravity_part.h b/src/gravity/MultiSoftening/gravity_part.h index de410fbbb988136af46c6f9085bdafee863b9f99..e865d99484735820ebb81e7a10fc3b5bb3edfdb2 100644 --- a/src/gravity/MultiSoftening/gravity_part.h +++ b/src/gravity/MultiSoftening/gravity_part.h @@ -52,6 +52,11 @@ struct gpart { /*! Type of the #gpart (DM, gas, star, ...) */ enum part_type type; +#ifdef WITH_LOGGER + /* Additional data for the particle logger */ + struct logger_part_data logger_data; +#endif + #ifdef SWIFT_DEBUG_CHECKS /* Numer of gparts this gpart interacted with */ diff --git a/src/gravity/Potential/gravity_io.h b/src/gravity/Potential/gravity_io.h index d0d31139fb89fe4015f968ab43bdaef72ba796c5..38dbeb546673bdaf8a796032aa5f6887e364838d 100644 --- a/src/gravity/Potential/gravity_io.h +++ b/src/gravity/Potential/gravity_io.h @@ -23,11 +23,11 @@ INLINE static void convert_gpart_pos(const struct engine* e, const struct gpart* gp, double* ret) { - - if (e->s->periodic) { - ret[0] = box_wrap(gp->x[0], 0.0, e->s->dim[0]); - ret[1] = box_wrap(gp->x[1], 0.0, e->s->dim[1]); - ret[2] = box_wrap(gp->x[2], 0.0, e->s->dim[2]); + const struct space* s = e->s; + if (s->periodic) { + ret[0] = box_wrap(gp->x[0] - s->pos_dithering[0], 0.0, s->dim[0]); + ret[1] = box_wrap(gp->x[1] - s->pos_dithering[1], 0.0, s->dim[1]); + ret[2] = box_wrap(gp->x[2] - s->pos_dithering[2], 0.0, s->dim[2]); } else { ret[0] = gp->x[0]; ret[1] = gp->x[1]; diff --git a/src/gravity_properties.c b/src/gravity_properties.c index d1654a1e7830d31c20731f130389a04d69b148b3..6b21b20b8ee8ab3986f7c04f0b4442f9e276e0d7 100644 --- a/src/gravity_properties.c +++ b/src/gravity_properties.c @@ -41,6 +41,7 @@ void gravity_props_init(struct gravity_props *p, struct swift_params *params, const struct phys_const *phys_const, const struct cosmology *cosmo, const int with_cosmology, + const int with_external_potential, const int has_baryons, const int has_DM, const int is_zoom_simulation, const int periodic) { @@ -88,6 +89,16 @@ void gravity_props_init(struct gravity_props *p, struct swift_params *params, p->theta_crit2 = p->theta_crit * p->theta_crit; p->theta_crit_inv = 1. / p->theta_crit; + /* Mesh dithering */ + if (periodic && !with_external_potential) { + p->with_dithering = + parser_get_opt_param_int(params, "Gravity:dithering", 1); + if (p->with_dithering) { + p->dithering_ratio = + parser_get_opt_param_double(params, "Gravity:dithering_ratio", 1.0); + } + } + /* Softening parameters */ if (with_cosmology) { @@ -224,6 +235,8 @@ void gravity_props_print(const struct gravity_props *p) { message("Self-gravity truncation cut-off ratio: r_cut_min=%f", p->r_cut_min_ratio); + message("Self-gravity mesh dithering ratio: %f", p->dithering_ratio); + message("Self-gravity mesh truncation function: %s", kernel_long_gravity_truncation_name); @@ -277,6 +290,7 @@ void gravity_props_print_snapshot(hid_t h_grpgrav, io_write_attribute_f(h_grpgrav, "Mesh a_smooth", p->a_smooth); io_write_attribute_f(h_grpgrav, "Mesh r_cut_max ratio", p->r_cut_max_ratio); io_write_attribute_f(h_grpgrav, "Mesh r_cut_min ratio", p->r_cut_min_ratio); + io_write_attribute_f(h_grpgrav, "Mesh dithering ratio", p->dithering_ratio); io_write_attribute_f(h_grpgrav, "Tree update frequency", p->rebuild_frequency); io_write_attribute_s(h_grpgrav, "Mesh truncation function", diff --git a/src/gravity_properties.h b/src/gravity_properties.h index d0a68ceb14d13f618dc628fb7e0a0dbf37d67cfb..8a4abe4bd372c52cccdb880839353d0dcc3d1e25 100644 --- a/src/gravity_properties.h +++ b/src/gravity_properties.h @@ -111,6 +111,12 @@ struct gravity_props { * a_smooth */ float r_cut_max_ratio; + /*! Are we dithering the particles at every rebuild? */ + int with_dithering; + + /*! Fraction of the top-level cell size used to normalize the dithering */ + double dithering_ratio; + /*! Gravitational constant (in internal units, copied from the physical * constants) */ float G_Newton; @@ -120,6 +126,7 @@ void gravity_props_print(const struct gravity_props *p); void gravity_props_init(struct gravity_props *p, struct swift_params *params, const struct phys_const *phys_const, const struct cosmology *cosmo, const int with_cosmology, + const int with_external_potential, const int has_baryons, const int has_DM, const int is_zoom_simulation, const int periodic); void gravity_props_update(struct gravity_props *p, diff --git a/src/hydro.h b/src/hydro.h index e5aedeb0c00b92e8bdbf3b707516a90132274f65..b38276c3d482bcbbbb39595ecf29cbb8dba23459 100644 --- a/src/hydro.h +++ b/src/hydro.h @@ -55,14 +55,9 @@ #include "./hydro/Default/hydro.h" #include "./hydro/Default/hydro_iact.h" #define SPH_IMPLEMENTATION "Default version of SPH" -#elif defined(GIZMO_MFV_SPH) -#include "./hydro/GizmoMFV/hydro.h" -#include "./hydro/GizmoMFV/hydro_iact.h" -#define SPH_IMPLEMENTATION "GIZMO MFV (Hopkins 2015)" -#elif defined(GIZMO_MFM_SPH) -#include "./hydro/GizmoMFM/hydro.h" -#include "./hydro/GizmoMFM/hydro_iact.h" -#define SPH_IMPLEMENTATION "GIZMO MFM (Hopkins 2015)" +#elif defined(GIZMO_MFV_SPH) || defined(GIZMO_MFM_SPH) +#include "./hydro/Gizmo/hydro.h" +#include "./hydro/Gizmo/hydro_iact.h" #elif defined(SHADOWFAX_SPH) #include "./hydro/Shadowswift/hydro.h" #include "./hydro/Shadowswift/hydro_iact.h" @@ -72,10 +67,10 @@ #include "./hydro/Planetary/hydro.h" #include "./hydro/Planetary/hydro_iact.h" #define SPH_IMPLEMENTATION "Minimal version of SPH with multiple materials" -#elif defined(ANARCHY_DU_SPH) -#include "./hydro/AnarchyDU/hydro.h" -#include "./hydro/AnarchyDU/hydro_iact.h" -#define SPH_IMPLEMENTATION "ANARCHY (Density-Energy) SPH (Borrow+ in prep)" +#elif defined(SPHENIX_SPH) +#include "./hydro/SPHENIX/hydro.h" +#include "./hydro/SPHENIX/hydro_iact.h" +#define SPH_IMPLEMENTATION "SPHENIX (Borrow+ 2020)" #elif defined(ANARCHY_PU_SPH) #include "./hydro/AnarchyPU/hydro.h" #include "./hydro/AnarchyPU/hydro_iact.h" diff --git a/src/hydro/AnarchyPU/hydro.h b/src/hydro/AnarchyPU/hydro.h index 5a048e566ec433c0d32a03d1062da4d9923ca4bc..329563d4e6c4b71e01e5271137da37a5a8b99db5 100644 --- a/src/hydro/AnarchyPU/hydro.h +++ b/src/hydro/AnarchyPU/hydro.h @@ -1059,7 +1059,6 @@ __attribute__((always_inline)) INLINE static void hydro_first_init_part( struct part *restrict p, struct xpart *restrict xp) { p->time_bin = 0; - p->wakeup = time_bin_not_awake; xp->v_full[0] = p->v[0]; xp->v_full[1] = p->v[1]; xp->v_full[2] = p->v[2]; diff --git a/src/hydro/AnarchyPU/hydro_iact.h b/src/hydro/AnarchyPU/hydro_iact.h index bb53221908d71535d090e8d2581e466fcf1009f9..9abd09a5f68c9762fec3b57b6d61e3cdd045d6c3 100644 --- a/src/hydro/AnarchyPU/hydro_iact.h +++ b/src/hydro/AnarchyPU/hydro_iact.h @@ -554,49 +554,4 @@ __attribute__((always_inline)) INLINE static void runner_iact_nonsym_force( pi->force.h_dt -= mj * dvdr * r_inv / rhoj * wi_dr; } -/** - * @brief Timestep limiter loop - * - * @param r2 Comoving square distance between the two particles. - * @param dx Comoving vector separating both particles (pi - pj). - * @param hi Comoving smoothing-length of part*icle i. - * @param hj Comoving smoothing-length of part*icle j. - * @param pi First part*icle. - * @param pj Second part*icle (not updated). - * @param a Current scale factor. - * @param H Current Hubble parameter. - * - */ -__attribute__((always_inline)) INLINE static void runner_iact_limiter( - float r2, const float* dx, float hi, float hj, struct part* restrict pi, - struct part* restrict pj, float a, float H) { - - /* Nothing to do here if both particles are active */ -} - -/** - * @brief Timestep limiter loop (non-symmetric version) - * - * @param r2 Comoving square distance between the two particles. - * @param dx Comoving vector separating both particles (pi - pj). - * @param hi Comoving smoothing-length of part*icle i. - * @param hj Comoving smoothing-length of part*icle j. - * @param pi First part*icle. - * @param pj Second part*icle (not updated). - * @param a Current scale factor. - * @param H Current Hubble parameter. - * - */ -__attribute__((always_inline)) INLINE static void runner_iact_nonsym_limiter( - float r2, const float* dx, float hi, float hj, struct part* restrict pi, - struct part* restrict pj, float a, float H) { - - /* Wake up the neighbour? */ - if (pi->viscosity.v_sig > - const_limiter_max_v_sig_ratio * pj->viscosity.v_sig) { - - pj->wakeup = time_bin_awake; - } -} - #endif /* SWIFT_ANARCHY_PU_HYDRO_IACT_H */ diff --git a/src/hydro/AnarchyPU/hydro_io.h b/src/hydro/AnarchyPU/hydro_io.h index 7dfe61f198163c458ea8ecc22c1cbaa7eb4b99dd..2d02b350caada74a9054ab7d698fe90c3d0b2736 100644 --- a/src/hydro/AnarchyPU/hydro_io.h +++ b/src/hydro/AnarchyPU/hydro_io.h @@ -83,10 +83,11 @@ INLINE static void convert_part_pos(const struct engine* e, const struct part* p, const struct xpart* xp, double* ret) { - if (e->s->periodic) { - ret[0] = box_wrap(p->x[0], 0.0, e->s->dim[0]); - ret[1] = box_wrap(p->x[1], 0.0, e->s->dim[1]); - ret[2] = box_wrap(p->x[2], 0.0, e->s->dim[2]); + const struct space* s = e->s; + if (s->periodic) { + ret[0] = box_wrap(p->x[0] - s->pos_dithering[0], 0.0, s->dim[0]); + ret[1] = box_wrap(p->x[1] - s->pos_dithering[1], 0.0, s->dim[1]); + ret[2] = box_wrap(p->x[2] - s->pos_dithering[2], 0.0, s->dim[2]); } else { ret[0] = p->x[0]; ret[1] = p->x[1]; @@ -228,10 +229,6 @@ INLINE static void hydro_write_flavour(hid_t h_grpsph) { "Simple treatment as in Price (2008)"); io_write_attribute_s(h_grpsph, "Viscosity Model", "Simplified version of Cullen & Denhen (2011)"); - - /* Time integration properties */ - io_write_attribute_f(h_grpsph, "Maximal Delta u change over dt", - const_max_u_change); } /** diff --git a/src/hydro/AnarchyPU/hydro_part.h b/src/hydro/AnarchyPU/hydro_part.h index 2ba76967ac074df68e6beddd51713ae0505430f6..c0b300e3f5816d099654a2e028e5d1c06fff2f8b 100644 --- a/src/hydro/AnarchyPU/hydro_part.h +++ b/src/hydro/AnarchyPU/hydro_part.h @@ -32,7 +32,9 @@ #include "black_holes_struct.h" #include "chemistry_struct.h" #include "cooling_struct.h" +#include "feedback_struct.h" #include "star_formation_struct.h" +#include "timestep_limiter_struct.h" #include "tracers_struct.h" /** @@ -68,6 +70,9 @@ struct xpart { /* Additional data used by the tracers */ struct star_formation_xpart_data sf_data; + /* Additional data used by the feedback */ + struct feedback_part_data feedback_data; + } SWIFT_STRUCT_ALIGN; /** @@ -202,8 +207,8 @@ struct part { /*! Time-step length */ timebin_t time_bin; - /* Need waking up ? */ - timebin_t wakeup; + /*! Time-step limiter information */ + struct timestep_limiter_data limiter_data; #ifdef SWIFT_DEBUG_CHECKS diff --git a/src/hydro/Default/hydro.h b/src/hydro/Default/hydro.h index 50eefa481de7e7e069f058372e529455da779dcb..c64ffada10891f98a0c6bcb9ab3b412e276c3b3b 100644 --- a/src/hydro/Default/hydro.h +++ b/src/hydro/Default/hydro.h @@ -992,7 +992,6 @@ __attribute__((always_inline)) INLINE static void hydro_first_init_part( struct part *restrict p, struct xpart *restrict xp) { p->time_bin = 0; - p->wakeup = time_bin_not_awake; xp->v_full[0] = p->v[0]; xp->v_full[1] = p->v[1]; xp->v_full[2] = p->v[2]; diff --git a/src/hydro/Default/hydro_iact.h b/src/hydro/Default/hydro_iact.h index 07c8f0edc3885376be828480492de10b35d857e3..eb6612fe48e8a4990404a47cd4ec6398fbf6f252 100644 --- a/src/hydro/Default/hydro_iact.h +++ b/src/hydro/Default/hydro_iact.h @@ -517,49 +517,4 @@ __attribute__((always_inline)) INLINE static void runner_iact_nonsym_force( pi->force.h_dt -= mj * dvdr * pi->force.f * r_inv / rhoj * wi_dr; } -/** - * @brief Timestep limiter loop - * - * @param r2 Comoving square distance between the two particles. - * @param dx Comoving vector separating both particles (pi - pj). - * @param hi Comoving smoothing-length of part*icle i. - * @param hj Comoving smoothing-length of part*icle j. - * @param pi First part*icle. - * @param pj Second part*icle (not updated). - * @param a Current scale factor. - * @param H Current Hubble parameter. - * - */ -__attribute__((always_inline)) INLINE static void runner_iact_limiter( - float r2, const float* dx, float hi, float hj, struct part* restrict pi, - struct part* restrict pj, float a, float H) { - - /* Nothing to do here if both particles are active */ -} - -/** - * @brief Timestep limiter loop (non-symmetric version) - * - * @param r2 Comoving square distance between the two particles. - * @param dx Comoving vector separating both particles (pi - pj). - * @param hi Comoving smoothing-length of part*icle i. - * @param hj Comoving smoothing-length of part*icle j. - * @param pi First part*icle. - * @param pj Second part*icle (not updated). - * @param a Current scale factor. - * @param H Current Hubble parameter. - * - */ -__attribute__((always_inline)) INLINE static void runner_iact_nonsym_limiter( - float r2, const float* dx, float hi, float hj, struct part* restrict pi, - struct part* restrict pj, float a, float H) { - - /* Wake up the neighbour? */ - if (pi->viscosity.v_sig > - const_limiter_max_v_sig_ratio * pj->viscosity.v_sig) { - - pj->wakeup = time_bin_awake; - } -} - #endif /* SWIFT_DEFAULT_HYDRO_IACT_H */ diff --git a/src/hydro/Default/hydro_io.h b/src/hydro/Default/hydro_io.h index 1944f677ff16c5f002aa4ee2f830c84e808ffa63..849903d46b2dc0d79dae3ba623c494a1ac507a49 100644 --- a/src/hydro/Default/hydro_io.h +++ b/src/hydro/Default/hydro_io.h @@ -82,10 +82,11 @@ INLINE static void convert_part_pos(const struct engine* e, const struct part* p, const struct xpart* xp, double* ret) { - if (e->s->periodic) { - ret[0] = box_wrap(p->x[0], 0.0, e->s->dim[0]); - ret[1] = box_wrap(p->x[1], 0.0, e->s->dim[1]); - ret[2] = box_wrap(p->x[2], 0.0, e->s->dim[2]); + const struct space* s = e->s; + if (s->periodic) { + ret[0] = box_wrap(p->x[0] - s->pos_dithering[0], 0.0, s->dim[0]); + ret[1] = box_wrap(p->x[1] - s->pos_dithering[1], 0.0, s->dim[1]); + ret[2] = box_wrap(p->x[2] - s->pos_dithering[2], 0.0, s->dim[2]); } else { ret[0] = p->x[0]; ret[1] = p->x[1]; @@ -228,10 +229,6 @@ INLINE static void hydro_write_flavour(hid_t h_grpsph) { "Simple treatment as in Price (2017)"); io_write_attribute_s(h_grpsph, "Viscosity Model", "Simplified version of Cullen & Denhen (2011)"); - - /* Time integration properties */ - io_write_attribute_f(h_grpsph, "Maximal Delta u change over dt", - const_max_u_change); } /** diff --git a/src/hydro/Default/hydro_part.h b/src/hydro/Default/hydro_part.h index a3fa2545aa58d54e02c54af02103d047a5c8cf17..6437e5c5c42b1a25c8ba2cde08d2fee72e22fea1 100644 --- a/src/hydro/Default/hydro_part.h +++ b/src/hydro/Default/hydro_part.h @@ -30,7 +30,9 @@ #include "black_holes_struct.h" #include "chemistry_struct.h" #include "cooling_struct.h" +#include "feedback_struct.h" #include "star_formation_struct.h" +#include "timestep_limiter_struct.h" #include "tracers_struct.h" /** @@ -66,6 +68,9 @@ struct xpart { /* Additional data used by the tracers */ struct star_formation_xpart_data sf_data; + /* Additional data used by the feedback */ + struct feedback_part_data feedback_data; + } SWIFT_STRUCT_ALIGN; /** @@ -197,8 +202,8 @@ struct part { /*! Time-step length */ timebin_t time_bin; - /* Need waking up ? */ - timebin_t wakeup; + /*! Time-step limiter information */ + struct timestep_limiter_data limiter_data; #ifdef SWIFT_DEBUG_CHECKS diff --git a/src/hydro/Gadget2/hydro.h b/src/hydro/Gadget2/hydro.h index 50e31b14ec13a1828ecce8f4c4d5699a38f0482c..2172dae966036c3bd62e9481068011caa5e57689 100644 --- a/src/hydro/Gadget2/hydro.h +++ b/src/hydro/Gadget2/hydro.h @@ -893,7 +893,6 @@ __attribute__((always_inline)) INLINE static void hydro_first_init_part( struct part *restrict p, struct xpart *restrict xp) { p->time_bin = 0; - p->wakeup = time_bin_not_awake; xp->v_full[0] = p->v[0]; xp->v_full[1] = p->v[1]; xp->v_full[2] = p->v[2]; diff --git a/src/hydro/Gadget2/hydro_debug.h b/src/hydro/Gadget2/hydro_debug.h index aeb43ee5d68930debfa867dc856465ac9d22902a..ffa21b861825fe0107f8e19aa4769f04edea7a9a 100644 --- a/src/hydro/Gadget2/hydro_debug.h +++ b/src/hydro/Gadget2/hydro_debug.h @@ -34,7 +34,7 @@ __attribute__((always_inline)) INLINE static void hydro_debug_particle( p->rho, hydro_get_comoving_pressure(p), p->force.P_over_rho2, p->entropy, p->entropy_dt, p->force.soundspeed, p->density.div_v, p->density.rot_v[0], p->density.rot_v[1], p->density.rot_v[2], p->force.balsara, - p->force.v_sig, p->force.h_dt, p->time_bin, p->wakeup); + p->force.v_sig, p->force.h_dt, p->time_bin, p->limiter_data.wakeup); } #endif /* SWIFT_GADGET2_HYDRO_DEBUG_H */ diff --git a/src/hydro/Gadget2/hydro_iact.h b/src/hydro/Gadget2/hydro_iact.h index 118a29d771facbafbb15ecef90d3d3c726e1b92c..27e8e8d8a2717a818c823bfa306e184d42c4a0ca 100644 --- a/src/hydro/Gadget2/hydro_iact.h +++ b/src/hydro/Gadget2/hydro_iact.h @@ -1052,37 +1052,4 @@ runner_iact_nonsym_2_vec_force( #endif -/** - * @brief Timestep limiter loop - */ -__attribute__((always_inline)) INLINE static void runner_iact_limiter( - float r2, const float *dx, float hi, float hj, struct part *restrict pi, - struct part *restrict pj, float a, float H) { - - /* Nothing to do here if both particles are active */ -} - -/** - * @brief Timestep limiter loop (non-symmetric version) - */ -__attribute__((always_inline)) INLINE static void runner_iact_nonsym_limiter( - float r2, const float *dx, float hi, float hj, struct part *restrict pi, - struct part *restrict pj, float a, float H) { - - /* Wake up the neighbour? */ - if (pi->force.v_sig > const_limiter_max_v_sig_ratio * pj->force.v_sig) { - - // ALEXEI seems to crash with this option when running with debug checks - // on comparing ti_kick to ti_start in kick_part. Use code below instead - // (commented MATTHIEU) - // pj->wakeup = time_bin_awake; - - // MATTHIEU - if (pj->wakeup == time_bin_not_awake) - pj->wakeup = time_bin_awake; - else if (pj->wakeup > 0) - pj->wakeup = -pj->wakeup; - } -} - #endif /* SWIFT_GADGET2_HYDRO_IACT_H */ diff --git a/src/hydro/Gadget2/hydro_io.h b/src/hydro/Gadget2/hydro_io.h index 20ad8e2d0c15094101e44999ff643f9d21619622..8142e4e5f0b109a985b330e731ea65a43a409577 100644 --- a/src/hydro/Gadget2/hydro_io.h +++ b/src/hydro/Gadget2/hydro_io.h @@ -74,10 +74,11 @@ INLINE static void convert_part_pos(const struct engine* e, const struct part* p, const struct xpart* xp, double* ret) { - if (e->s->periodic) { - ret[0] = box_wrap(p->x[0], 0.0, e->s->dim[0]); - ret[1] = box_wrap(p->x[1], 0.0, e->s->dim[1]); - ret[2] = box_wrap(p->x[2], 0.0, e->s->dim[2]); + const struct space* s = e->s; + if (s->periodic) { + ret[0] = box_wrap(p->x[0] - s->pos_dithering[0], 0.0, s->dim[0]); + ret[1] = box_wrap(p->x[1] - s->pos_dithering[1], 0.0, s->dim[1]); + ret[2] = box_wrap(p->x[2] - s->pos_dithering[2], 0.0, s->dim[2]); } else { ret[0] = p->x[0]; ret[1] = p->x[1]; diff --git a/src/hydro/Gadget2/hydro_part.h b/src/hydro/Gadget2/hydro_part.h index 5f4cca366b101c2341863f47d7a9adce51b860a2..191641088556b127b5686d274f33acac7cc80f6f 100644 --- a/src/hydro/Gadget2/hydro_part.h +++ b/src/hydro/Gadget2/hydro_part.h @@ -34,9 +34,11 @@ #include "black_holes_struct.h" #include "chemistry_struct.h" #include "cooling_struct.h" +#include "feedback_struct.h" #include "logger.h" #include "pressure_floor_struct.h" #include "star_formation_struct.h" +#include "timestep_limiter_struct.h" #include "tracers_struct.h" /* Extra particle data not needed during the SPH loops over neighbours. */ @@ -66,6 +68,9 @@ struct xpart { /* Additional data used by the star formation */ struct star_formation_xpart_data sf_data; + /* Additional data used by the feedback */ + struct feedback_part_data feedback_data; + #ifdef WITH_LOGGER /* Additional data for the particle logger */ struct logger_part_data logger_data; @@ -162,8 +167,8 @@ struct part { /* Time-step length */ timebin_t time_bin; - /* Need waking-up ? */ - timebin_t wakeup; + /*! Time-step limiter information */ + struct timestep_limiter_data limiter_data; #ifdef SWIFT_DEBUG_CHECKS diff --git a/src/hydro/GizmoMFV/hydro_debug.h b/src/hydro/Gizmo/MFM/hydro_debug.h similarity index 61% rename from src/hydro/GizmoMFV/hydro_debug.h rename to src/hydro/Gizmo/MFM/hydro_debug.h index 181bd6f82d547803c7303bd19be11cf66dc3a8a8..08e91eb3b0bacce9e7c7591bdf6395f0d17f0d88 100644 --- a/src/hydro/GizmoMFV/hydro_debug.h +++ b/src/hydro/Gizmo/MFM/hydro_debug.h @@ -16,8 +16,8 @@ * along with this program. If not, see <http://www.gnu.org/licenses/>. * ******************************************************************************/ -#ifndef SWIFT_GIZMO_MFV_HYDRO_DEBUG_H -#define SWIFT_GIZMO_MFV_HYDRO_DEBUG_H +#ifndef SWIFT_GIZMO_MFM_HYDRO_DEBUG_H +#define SWIFT_GIZMO_MFM_HYDRO_DEBUG_H __attribute__((always_inline)) INLINE static void hydro_debug_particle( const struct part* p, const struct xpart* xp) { @@ -28,8 +28,6 @@ __attribute__((always_inline)) INLINE static void hydro_debug_particle( "h=%.3e, " "time_bin=%d, " "wakeup=%d, " - "primitives={" - "v=[%.3e,%.3e,%.3e], " "rho=%.3e, " "P=%.3e, " "gradients={" @@ -40,7 +38,7 @@ __attribute__((always_inline)) INLINE static void hydro_debug_particle( "rho=[%.3e,%.3e], " "v=[[%.3e,%.3e],[%.3e,%.3e],[%.3e,%.3e]], " "P=[%.3e,%.3e], " - "maxr=%.3e}}, " + "maxr=%.3e}, " "conserved={" "momentum=[%.3e,%.3e,%.3e], " "mass=%.3e, " @@ -54,24 +52,19 @@ __attribute__((always_inline)) INLINE static void hydro_debug_particle( "wcount_dh=%.3e, " "wcount=%.3e}\n", p->x[0], p->x[1], p->x[2], p->v[0], p->v[1], p->v[2], p->a_hydro[0], - p->a_hydro[1], p->a_hydro[2], p->h, p->time_bin, p->wakeup, - p->primitives.v[0], p->primitives.v[1], p->primitives.v[2], - p->primitives.rho, p->primitives.P, p->primitives.gradients.rho[0], - p->primitives.gradients.rho[1], p->primitives.gradients.rho[2], - p->primitives.gradients.v[0][0], p->primitives.gradients.v[0][1], - p->primitives.gradients.v[0][2], p->primitives.gradients.v[1][0], - p->primitives.gradients.v[1][1], p->primitives.gradients.v[1][2], - p->primitives.gradients.v[2][0], p->primitives.gradients.v[2][1], - p->primitives.gradients.v[2][2], p->primitives.gradients.P[0], - p->primitives.gradients.P[1], p->primitives.gradients.P[2], - p->primitives.limiter.rho[0], p->primitives.limiter.rho[1], - p->primitives.limiter.v[0][0], p->primitives.limiter.v[0][1], - p->primitives.limiter.v[1][0], p->primitives.limiter.v[1][1], - p->primitives.limiter.v[2][0], p->primitives.limiter.v[2][1], - p->primitives.limiter.P[0], p->primitives.limiter.P[1], - p->primitives.limiter.maxr, p->conserved.momentum[0], - p->conserved.momentum[1], p->conserved.momentum[2], p->conserved.mass, - p->conserved.energy, p->geometry.volume, p->geometry.matrix_E[0][0], + p->a_hydro[1], p->a_hydro[2], p->h, p->time_bin, p->limiter_data.wakeup, + p->rho, p->P, p->gradients.rho[0], p->gradients.rho[1], + p->gradients.rho[2], p->gradients.v[0][0], p->gradients.v[0][1], + p->gradients.v[0][2], p->gradients.v[1][0], p->gradients.v[1][1], + p->gradients.v[1][2], p->gradients.v[2][0], p->gradients.v[2][1], + p->gradients.v[2][2], p->gradients.P[0], p->gradients.P[1], + p->gradients.P[2], p->limiter.rho[0], p->limiter.rho[1], + p->limiter.v[0][0], p->limiter.v[0][1], p->limiter.v[1][0], + p->limiter.v[1][1], p->limiter.v[2][0], p->limiter.v[2][1], + p->limiter.P[0], p->limiter.P[1], p->limiter.maxr, + p->conserved.momentum[0], p->conserved.momentum[1], + p->conserved.momentum[2], p->conserved.mass, p->conserved.energy, + p->geometry.volume, p->geometry.matrix_E[0][0], p->geometry.matrix_E[0][1], p->geometry.matrix_E[0][2], p->geometry.matrix_E[1][0], p->geometry.matrix_E[1][1], p->geometry.matrix_E[1][2], p->geometry.matrix_E[2][0], @@ -79,4 +72,4 @@ __attribute__((always_inline)) INLINE static void hydro_debug_particle( p->timestepvars.vmax, p->density.wcount_dh, p->density.wcount); } -#endif /* SWIFT_GIZMO_MFV_HYDRO_DEBUG_H */ +#endif /* SWIFT_GIZMO_MFM_HYDRO_DEBUG_H */ diff --git a/src/hydro/Gizmo/MFM/hydro_flux.h b/src/hydro/Gizmo/MFM/hydro_flux.h new file mode 100644 index 0000000000000000000000000000000000000000..22b8109611ac147c5c523ae78daa9df2fdf61403 --- /dev/null +++ b/src/hydro/Gizmo/MFM/hydro_flux.h @@ -0,0 +1,196 @@ +/******************************************************************************* + * This file is part of SWIFT. + * Coypright (c) 2019 Bert Vandenbroucke (bert.vandenbroucke@gmail.com) + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published + * by the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this program. If not, see <http://www.gnu.org/licenses/>. + * + ******************************************************************************/ +#ifndef SWIFT_GIZMO_MFM_HYDRO_FLUX_H +#define SWIFT_GIZMO_MFM_HYDRO_FLUX_H + +#include "riemann.h" + +/** + * @brief Reset the fluxes for the given particle. + * + * @param p Particle. + */ +__attribute__((always_inline)) INLINE static void hydro_part_reset_fluxes( + struct part* restrict p) { + + p->flux.momentum[0] = 0.0f; + p->flux.momentum[1] = 0.0f; + p->flux.momentum[2] = 0.0f; + p->flux.energy = 0.0f; +} + +/** + * @brief Get the fluxes for the given particle. + * + * @param p Particle. + * @param flux Fluxes for the particle (array of size 5 or more). + */ +__attribute__((always_inline)) INLINE static void hydro_part_get_fluxes( + const struct part* restrict p, float* flux) { + + flux[1] = p->flux.momentum[0]; + flux[2] = p->flux.momentum[1]; + flux[3] = p->flux.momentum[2]; + flux[4] = p->flux.energy; +} + +/** + * @brief Compute the flux for the Riemann problem with the given left and right + * state, and interface normal, surface area and velocity. + * + * @param WL Left state variables. + * @param WR Right state variables. + * @param n_unit Unit vector of the interface. + * @param vLR Velocity of the interface. + * @param Anorm Surface area of the interface. + * @param fluxes Array to store the result in (of size 5 or more). + */ +__attribute__((always_inline)) INLINE static void hydro_compute_flux( + const float* WL, const float* WR, const float* n_unit, const float* vLR, + const float Anorm, float* fluxes) { + + riemann_solve_for_middle_state_flux(WL, WR, n_unit, vLR, fluxes); + + fluxes[1] *= Anorm; + fluxes[2] *= Anorm; + fluxes[3] *= Anorm; + fluxes[4] *= Anorm; +} + +/** + * @brief Update the fluxes for the particle with the given contributions, + * assuming the particle is to the left of the interparticle interface. + * + * @param p Particle. + * @param fluxes Fluxes accross the interface. + * @param dx Distance between the particles that share the interface. + */ +__attribute__((always_inline)) INLINE static void hydro_part_update_fluxes_left( + struct part* restrict p, const float* fluxes, const float* dx) { + + p->flux.momentum[0] -= fluxes[1]; + p->flux.momentum[1] -= fluxes[2]; + p->flux.momentum[2] -= fluxes[3]; + p->flux.energy -= fluxes[4]; + +#ifndef GIZMO_TOTAL_ENERGY + p->flux.energy += fluxes[1] * p->v[0]; + p->flux.energy += fluxes[2] * p->v[1]; + p->flux.energy += fluxes[3] * p->v[2]; +#endif +} + +/** + * @brief Update the fluxes for the particle with the given contributions, + * assuming the particle is to the right of the interparticle interface. + * + * @param p Particle. + * @param fluxes Fluxes accross the interface. + * @param dx Distance between the particles that share the interface. + */ +__attribute__((always_inline)) INLINE static void +hydro_part_update_fluxes_right(struct part* restrict p, const float* fluxes, + const float* dx) { + + p->flux.momentum[0] += fluxes[1]; + p->flux.momentum[1] += fluxes[2]; + p->flux.momentum[2] += fluxes[3]; + p->flux.energy += fluxes[4]; + +#ifndef GIZMO_TOTAL_ENERGY + p->flux.energy -= fluxes[1] * p->v[0]; + p->flux.energy -= fluxes[2] * p->v[1]; + p->flux.energy -= fluxes[3] * p->v[2]; +#endif +} + +/** + * @brief Get the drift term for the density based on the mass flux. + * + * @param mass_flux Current mass flux for the particle. + * @param dt Drift time step (in co-moving units). + * @param volume Volume of the particle. + * @return 0, since this is Gizmo MFM. + */ +__attribute__((always_inline)) INLINE static float +hydro_gizmo_mfv_density_drift_term(const float mass_flux, const float dt, + const float volume) { + return 0.0f; +} + +/** + * @brief Add the gravitational contribution to the fluid velocity drift. + * + * This method does nothing, since this is Gizmo MFM. + * + * @param fluid_v Fluid velocity. + * @param v (Undrifted) particle velocity. + * @param v_full (Drifted) particle velocity. + */ +__attribute__((always_inline)) INLINE static void +hydro_gizmo_mfv_extra_velocity_drift(float* fluid_v, const float* v, + const float* v_full) {} + +/** + * @brief Get the term required to update the MFV energy due to the change in + * gravitational energy. + * + * @param dt_kick_corr Time step for the potential energy correction. + * @param dt_grav Time step for the (optional) kinetic energy correction. + * @param p Particle. + * @param momentum Momentum of the particle, explicitly requested so that it is + * clear from the code that the momentum needs to be updated after the call to + * this function. + * @param a_grav Gravitational acceleration. + * @return 0, since this is Gizmo MFM. + */ +__attribute__((always_inline)) INLINE static float +hydro_gizmo_mfv_gravity_energy_update_term(const float dt_kick_corr, + const float dt_grav, + const struct part* restrict p, + const float* momentum, + const float* a_grav) { + + return 0.0f; +} + +/** + * @brief Get the term required to update the MFV mass due to the mass flux. + * + * @param mass_flux Mass flux rate. + * @param dt Time step (in comoving units). + * @return 0, since this is Gizmo MFM. + */ +__attribute__((always_inline)) INLINE static float +hydro_gizmo_mfv_mass_update_term(const float mass_flux, const float dt) { + return 0.0f; +} + +/** + * @brief Update the mass of the gpart associated with the given particle after + * the mass has been updated with the hydrodynamical mass flux. + * + * This function does nothing, since this is Gizmo MFM. + * + * @param p Particle. + */ +__attribute__((always_inline)) INLINE static void +hydro_gizmo_mfv_update_gpart_mass(struct part* restrict p) {} + +#endif /* SWIFT_GIZMO_MFM_HYDRO_FLUX_H */ diff --git a/src/hydro/GizmoMFM/hydro_part.h b/src/hydro/Gizmo/MFM/hydro_part.h similarity index 79% rename from src/hydro/GizmoMFM/hydro_part.h rename to src/hydro/Gizmo/MFM/hydro_part.h index 2ca752dac714d5fca02e2552601c18174f98a8ab..7264349a90584deb16e5b2f8e059c25c58e6139c 100644 --- a/src/hydro/GizmoMFM/hydro_part.h +++ b/src/hydro/Gizmo/MFM/hydro_part.h @@ -19,38 +19,6 @@ #ifndef SWIFT_GIZMO_MFM_HYDRO_PART_H #define SWIFT_GIZMO_MFM_HYDRO_PART_H -#include "black_holes_struct.h" -#include "chemistry_struct.h" -#include "cooling_struct.h" -#include "star_formation_struct.h" -#include "tracers_struct.h" - -/* Extra particle data not needed during the computation. */ -struct xpart { - - /* Offset between current position and position at last tree rebuild. */ - float x_diff[3]; - - /* Offset between the current position and position at the last sort. */ - float x_diff_sort[3]; - - /* Velocity at the last full step. */ - float v_full[3]; - - /* Gravitational acceleration at the last full step. */ - float a_grav[3]; - - /* Additional data used to record cooling information */ - struct cooling_xpart_data cooling_data; - - /* Additional data used by the tracers */ - struct tracers_xpart_data tracers_data; - - /* Additional data used by the star formation */ - struct star_formation_xpart_data sf_data; - -} SWIFT_STRUCT_ALIGN; - /* Data of a single particle. */ struct part { @@ -63,8 +31,16 @@ struct part { /* Particle position. */ double x[3]; - /* Particle predicted velocity. */ - float v[3]; + /* In MFM, the particle and fluid velocities are the same. + We use an anonymous union to make sure we can reference the + same array with both names. */ + union { + /* Particle predicted velocity. */ + float v[3]; + + /* Fluid velocity. */ + float fluid_v[3]; + }; /* Particle acceleration. */ float a_hydro[3]; @@ -182,9 +158,6 @@ struct part { gradients */ float matrix_E[3][3]; - /* Centroid of the "cell". */ - float centroid[3]; - /* Correction factor for wcount. */ float wcorr; @@ -199,8 +172,8 @@ struct part { /* Time-step length */ timebin_t time_bin; - /* Need waking-up ? */ - timebin_t wakeup; + /*! Time-step limiter information */ + struct timestep_limiter_data limiter_data; #ifdef SWIFT_DEBUG_CHECKS diff --git a/src/hydro/Gizmo/MFM/hydro_velocities.h b/src/hydro/Gizmo/MFM/hydro_velocities.h new file mode 100644 index 0000000000000000000000000000000000000000..e9f04dd45657f91767393f93fbe3461d4e06f02a --- /dev/null +++ b/src/hydro/Gizmo/MFM/hydro_velocities.h @@ -0,0 +1,151 @@ +/******************************************************************************* + * This file is part of SWIFT. + * Coypright (c) 2017 Bert Vandenbroucke (bert.vandenbroucke@gmail.com) + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published + * by the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this program. If not, see <http://www.gnu.org/licenses/>. + * + ******************************************************************************/ +#ifndef SWIFT_GIZMO_MFM_HYDRO_VELOCITIES_H +#define SWIFT_GIZMO_MFM_HYDRO_VELOCITIES_H + +#ifdef GIZMO_FIX_PARTICLES +#error "Fixed particles are not allowed for GIZMO MFM!" +#endif + +#ifdef GIZMO_STEER_MOTION +#error "Steering particle movement is not allowed for GIZMO MFM!" +#endif + +/** + * @brief Initialize the GIZMO particle velocities before the start of the + * actual run based on the initial value of the primitive velocity. + * + * @param p The particle to act upon. + * @param xp The extended particle data to act upon. + */ +__attribute__((always_inline)) INLINE static void hydro_velocities_init( + struct part* restrict p, struct xpart* restrict xp) { + + xp->v_full[0] = p->v[0]; + xp->v_full[1] = p->v[1]; + xp->v_full[2] = p->v[2]; +} + +/** + * @brief Set the particle velocity field that will be used to deboost fluid + * velocities during the force loop. + * + * @param p The particle to act upon. + * @param xp The extended particle data to act upon. + */ +__attribute__((always_inline)) INLINE static void +hydro_velocities_prepare_force(struct part* restrict p, + const struct xpart* restrict xp) {} + +/** + * @brief Set the variables that will be used to update the smoothing length + * during the drift (these will depend on the movement of the particles). + * + * @param p The particle to act upon. + */ +__attribute__((always_inline)) INLINE static void hydro_velocities_end_force( + struct part* restrict p) { + + /* Add normalization to h_dt. */ + p->force.h_dt *= p->h * hydro_dimension_inv; +} + +/** + * @brief Set the velocity of a GIZMO particle, based on the values of its + * primitive variables and the geometry of its mesh-free "cell". + * + * @param p The particle to act upon. + * @param xp The extended particle data to act upon. + */ +__attribute__((always_inline)) INLINE static void hydro_velocities_set( + struct part* restrict p, struct xpart* restrict xp) { + + /* Set the velocities: */ + /* We first set the particle velocity */ + if (p->conserved.mass > 0.0f && p->rho > 0.0f) { + + const float inverse_mass = 1.0f / p->conserved.mass; + + /* Normal case: set particle velocity to fluid velocity. */ + xp->v_full[0] = p->conserved.momentum[0] * inverse_mass; + xp->v_full[1] = p->conserved.momentum[1] * inverse_mass; + xp->v_full[2] = p->conserved.momentum[2] * inverse_mass; + + } else { + /* Vacuum particles have no fluid velocity. */ + xp->v_full[0] = 0.0f; + xp->v_full[1] = 0.0f; + xp->v_full[2] = 0.0f; + } + + if (p->gpart) { + p->gpart->v_full[0] = xp->v_full[0]; + p->gpart->v_full[1] = xp->v_full[1]; + p->gpart->v_full[2] = xp->v_full[2]; + } +} + +/** + * @brief Reset the variables used to store the centroid; used for the velocity + * correction. + * + * @param p Particle. + */ +__attribute__((always_inline)) INLINE static void +hydro_velocities_reset_centroids(struct part* restrict p) {} + +/** + * @brief Normalise the centroids after the density loop. + * + * @param p Particle. + * @param wcount Wcount for the particle. This is an explicit argument, so that + * it is clear from the code that wcount needs to be normalised by the time it + * is used here. + */ +__attribute__((always_inline)) INLINE static void +hydro_velocities_normalise_centroid(struct part* restrict p, + const float wcount) {} + +/** + * @brief Update the centroid with the given contribution, assuming the particle + * acts as the left particle in the neighbour interaction. + * + * @param p Particle (pi). + * @param dx Distance vector between the particle and its neighbour (dx = pi->x + * - pj->x). + * @param w Kernel value at position pj->x. + */ +__attribute__((always_inline)) INLINE static void +hydro_velocities_update_centroid_left(struct part* restrict p, const float* dx, + const float w) {} + +/** + * @brief Update the centroid with the given contribution, assuming the particle + * acts as the right particle in the neighbour interaction. + * + * @param p Particle (pj). + * @param dx Distance vector between the particle and its neighbour (dx = pi->x + * - pj->x). + * @param w Kernel value at position pi->x. + */ +__attribute__((always_inline)) INLINE static void +hydro_velocities_update_centroid_right(struct part* restrict p, const float* dx, + const float w) {} + +#endif /* SWIFT_GIZMO_MFM_HYDRO_VELOCITIES_H */ diff --git a/src/hydro/GizmoMFM/hydro_debug.h b/src/hydro/Gizmo/MFV/hydro_debug.h similarity index 89% rename from src/hydro/GizmoMFM/hydro_debug.h rename to src/hydro/Gizmo/MFV/hydro_debug.h index e3c9f793aec92c7bfa2527143e6ad771c3897a09..95a773712a487e50831a9f57f99620e46f266057 100644 --- a/src/hydro/GizmoMFM/hydro_debug.h +++ b/src/hydro/Gizmo/MFV/hydro_debug.h @@ -16,8 +16,8 @@ * along with this program. If not, see <http://www.gnu.org/licenses/>. * ******************************************************************************/ -#ifndef SWIFT_GIZMO_MFM_HYDRO_DEBUG_H -#define SWIFT_GIZMO_MFM_HYDRO_DEBUG_H +#ifndef SWIFT_GIZMO_MFV_HYDRO_DEBUG_H +#define SWIFT_GIZMO_MFV_HYDRO_DEBUG_H __attribute__((always_inline)) INLINE static void hydro_debug_particle( const struct part* p, const struct xpart* xp) { @@ -28,6 +28,8 @@ __attribute__((always_inline)) INLINE static void hydro_debug_particle( "h=%.3e, " "time_bin=%d, " "wakeup=%d, " + "primitives={" + "v=[%.3e,%.3e,%.3e], " "rho=%.3e, " "P=%.3e, " "gradients={" @@ -38,7 +40,7 @@ __attribute__((always_inline)) INLINE static void hydro_debug_particle( "rho=[%.3e,%.3e], " "v=[[%.3e,%.3e],[%.3e,%.3e],[%.3e,%.3e]], " "P=[%.3e,%.3e], " - "maxr=%.3e}, " + "maxr=%.3e}}, " "conserved={" "momentum=[%.3e,%.3e,%.3e], " "mass=%.3e, " @@ -52,7 +54,8 @@ __attribute__((always_inline)) INLINE static void hydro_debug_particle( "wcount_dh=%.3e, " "wcount=%.3e}\n", p->x[0], p->x[1], p->x[2], p->v[0], p->v[1], p->v[2], p->a_hydro[0], - p->a_hydro[1], p->a_hydro[2], p->h, p->time_bin, p->wakeup, p->rho, p->P, + p->a_hydro[1], p->a_hydro[2], p->h, p->time_bin, p->limiter_data.wakeup, + p->fluid_v[0], p->fluid_v[1], p->fluid_v[2], p->rho, p->P, p->gradients.rho[0], p->gradients.rho[1], p->gradients.rho[2], p->gradients.v[0][0], p->gradients.v[0][1], p->gradients.v[0][2], p->gradients.v[1][0], p->gradients.v[1][1], p->gradients.v[1][2], @@ -71,4 +74,4 @@ __attribute__((always_inline)) INLINE static void hydro_debug_particle( p->timestepvars.vmax, p->density.wcount_dh, p->density.wcount); } -#endif /* SWIFT_GIZMO_MFM_HYDRO_DEBUG_H */ +#endif /* SWIFT_GIZMO_MFV_HYDRO_DEBUG_H */ diff --git a/src/hydro/Gizmo/MFV/hydro_flux.h b/src/hydro/Gizmo/MFV/hydro_flux.h new file mode 100644 index 0000000000000000000000000000000000000000..5ce8563c80cd7e447a0c4e201394c8a8daa091cf --- /dev/null +++ b/src/hydro/Gizmo/MFV/hydro_flux.h @@ -0,0 +1,241 @@ +/******************************************************************************* + * This file is part of SWIFT. + * Coypright (c) 2019 Bert Vandenbroucke (bert.vandenbroucke@gmail.com) + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published + * by the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this program. If not, see <http://www.gnu.org/licenses/>. + * + ******************************************************************************/ +#ifndef SWIFT_GIZMO_MFV_HYDRO_FLUX_H +#define SWIFT_GIZMO_MFV_HYDRO_FLUX_H + +#include "riemann.h" + +/** + * @brief Reset the fluxes for the given particle. + * + * @param p Particle. + */ +__attribute__((always_inline)) INLINE static void hydro_part_reset_fluxes( + struct part* restrict p) { + + p->flux.mass = 0.0f; + p->flux.momentum[0] = 0.0f; + p->flux.momentum[1] = 0.0f; + p->flux.momentum[2] = 0.0f; + p->flux.energy = 0.0f; + + p->gravity.mflux[0] = 0.0f; + p->gravity.mflux[1] = 0.0f; + p->gravity.mflux[2] = 0.0f; +} + +/** + * @brief Get the fluxes for the given particle. + * + * @param p Particle. + * @param flux Fluxes for the particle (array of size 5 or more). + */ +__attribute__((always_inline)) INLINE static void hydro_part_get_fluxes( + const struct part* restrict p, float* flux) { + + flux[0] = p->flux.mass; + flux[1] = p->flux.momentum[0]; + flux[2] = p->flux.momentum[1]; + flux[3] = p->flux.momentum[2]; + flux[4] = p->flux.energy; +} + +/** + * @brief Compute the flux for the Riemann problem with the given left and right + * state, and interface normal, surface area and velocity. + * + * @param WL Left state variables. + * @param WR Right state variables. + * @param n_unit Unit vector of the interface. + * @param vLR Velocity of the interface. + * @param Anorm Surface area of the interface. + * @param fluxes Array to store the result in (of size 5 or more). + */ +__attribute__((always_inline)) INLINE static void hydro_compute_flux( + const float* WL, const float* WR, const float* n_unit, const float* vLR, + const float Anorm, float* fluxes) { + + riemann_solve_for_flux(WL, WR, n_unit, vLR, fluxes); + + fluxes[0] *= Anorm; + fluxes[1] *= Anorm; + fluxes[2] *= Anorm; + fluxes[3] *= Anorm; + fluxes[4] *= Anorm; +} + +/** + * @brief Update the fluxes for the particle with the given contributions, + * assuming the particle is to the left of the interparticle interface. + * + * @param p Particle. + * @param fluxes Fluxes accross the interface. + * @param dx Distance between the particles that share the interface. + */ +__attribute__((always_inline)) INLINE static void hydro_part_update_fluxes_left( + struct part* restrict p, const float* fluxes, const float* dx) { + + p->gravity.mflux[0] += fluxes[0] * dx[0]; + p->gravity.mflux[1] += fluxes[0] * dx[1]; + p->gravity.mflux[2] += fluxes[0] * dx[2]; + + p->flux.mass -= fluxes[0]; + p->flux.momentum[0] -= fluxes[1]; + p->flux.momentum[1] -= fluxes[2]; + p->flux.momentum[2] -= fluxes[3]; + p->flux.energy -= fluxes[4]; + +#ifndef GIZMO_TOTAL_ENERGY + const float ekin = + 0.5f * (p->fluid_v[0] * p->fluid_v[0] + p->fluid_v[1] * p->fluid_v[1] + + p->fluid_v[2] * p->fluid_v[2]); + p->flux.energy += fluxes[1] * p->fluid_v[0]; + p->flux.energy += fluxes[2] * p->fluid_v[1]; + p->flux.energy += fluxes[3] * p->fluid_v[2]; + p->flux.energy -= fluxes[0] * ekin; +#endif +} + +/** + * @brief Update the fluxes for the particle with the given contributions, + * assuming the particle is to the right of the interparticle interface. + * + * @param p Particle. + * @param fluxes Fluxes accross the interface. + * @param dx Distance between the particles that share the interface. + */ +__attribute__((always_inline)) INLINE static void +hydro_part_update_fluxes_right(struct part* restrict p, const float* fluxes, + const float* dx) { + + p->gravity.mflux[0] += fluxes[0] * dx[0]; + p->gravity.mflux[1] += fluxes[0] * dx[1]; + p->gravity.mflux[2] += fluxes[0] * dx[2]; + + p->flux.mass += fluxes[0]; + p->flux.momentum[0] += fluxes[1]; + p->flux.momentum[1] += fluxes[2]; + p->flux.momentum[2] += fluxes[3]; + p->flux.energy += fluxes[4]; + +#ifndef GIZMO_TOTAL_ENERGY + const float ekin = + 0.5f * (p->fluid_v[0] * p->fluid_v[0] + p->fluid_v[1] * p->fluid_v[1] + + p->fluid_v[2] * p->fluid_v[2]); + p->flux.energy -= fluxes[1] * p->fluid_v[0]; + p->flux.energy -= fluxes[2] * p->fluid_v[1]; + p->flux.energy -= fluxes[3] * p->fluid_v[2]; + p->flux.energy += fluxes[0] * ekin; +#endif +} + +/** + * @brief Get the drift term for the density based on the mass flux. + * + * @param mass_flux Current mass flux for the particle. + * @param dt Drift time step (in co-moving units). + * @param volume Volume of the particle. + * @return Term that will drift the density. + */ +__attribute__((always_inline)) INLINE static float +hydro_gizmo_mfv_density_drift_term(const float mass_flux, const float dt, + const float volume) { + + if (volume > 0.0f) { + return mass_flux * dt / volume; + } else { + return 0.0f; + } +} + +/** + * @brief Add the gravitational contribution to the fluid velocity drift. + * + * @param fluid_v Fluid velocity. + * @param v (Undrifted) particle velocity. + * @param v_full (Drifted) particle velocity. + */ +__attribute__((always_inline)) INLINE static void +hydro_gizmo_mfv_extra_velocity_drift(float* fluid_v, const float* v, + const float* v_full) { + + fluid_v[0] += v[0] - v_full[0]; + fluid_v[1] += v[1] - v_full[1]; + fluid_v[2] += v[2] - v_full[2]; +} + +/** + * @brief Get the term required to update the MFV energy due to the change in + * gravitational energy. + * + * @param dt_kick_corr Time step for the potential energy correction. + * @param dt_grav Time step for the (optional) kinetic energy correction. + * @param p Particle. + * @param momentum Momentum of the particle, explicitly requested so that it is + * clear from the code that the momentum needs to be updated after the call to + * this function. + * @param a_grav Gravitational acceleration. + * @return Term used to update the energy variable. + */ +__attribute__((always_inline)) INLINE static float +hydro_gizmo_mfv_gravity_energy_update_term(const float dt_kick_corr, + const float dt_grav, + const struct part* restrict p, + const float* momentum, + const float* a_grav) { + + float dE = + -0.5f * dt_kick_corr * + (p->gravity.mflux[0] * a_grav[0] + p->gravity.mflux[1] * a_grav[1] + + p->gravity.mflux[2] * a_grav[2]); +#if defined(GIZMO_TOTAL_ENERGY) + dE += dt_grav * (momentum[0] * a_grav[0] + momentum[1] * a_grav[1] + + momentum[2] * a_grav[2]); +#endif + return dE; +} + +/** + * @brief Get the term required to update the MFV mass due to the mass flux. + * + * @param mass_flux Mass flux rate. + * @param dt Time step (in comoving units). + * @return Mass flux update term. + */ +__attribute__((always_inline)) INLINE static float +hydro_gizmo_mfv_mass_update_term(const float mass_flux, const float dt) { + return mass_flux * dt; +} + +/** + * @brief Update the mass of the gpart associated with the given particle after + * the mass has been updated with the hydrodynamical mass flux. + * + * @param p Particle. + */ +__attribute__((always_inline)) INLINE static void +hydro_gizmo_mfv_update_gpart_mass(struct part* restrict p) { + + if (p->gpart) { + /* Make sure the gpart knows the mass has changed. */ + p->gpart->mass = p->conserved.mass; + } +} + +#endif /* SWIFT_GIZMO_MFV_HYDRO_FLUX_H */ diff --git a/src/hydro/GizmoMFV/hydro_part.h b/src/hydro/Gizmo/MFV/hydro_part.h similarity index 63% rename from src/hydro/GizmoMFV/hydro_part.h rename to src/hydro/Gizmo/MFV/hydro_part.h index db43c03cba3c23a4d4d8ab81cc62ebc5951299f3..82a7296c17f21ef4c0cf5416b498201d78a965d3 100644 --- a/src/hydro/GizmoMFV/hydro_part.h +++ b/src/hydro/Gizmo/MFV/hydro_part.h @@ -19,38 +19,6 @@ #ifndef SWIFT_GIZMO_MFV_HYDRO_PART_H #define SWIFT_GIZMO_MFV_HYDRO_PART_H -#include "black_holes_struct.h" -#include "chemistry_struct.h" -#include "cooling_struct.h" -#include "star_formation_struct.h" -#include "tracers_struct.h" - -/* Extra particle data not needed during the computation. */ -struct xpart { - - /* Offset between current position and position at last tree rebuild. */ - float x_diff[3]; - - /* Offset between the current position and position at the last sort. */ - float x_diff_sort[3]; - - /* Velocity at the last full step. */ - float v_full[3]; - - /* Gravitational acceleration at the last full step. */ - float a_grav[3]; - - /* Additional data used to record cooling information */ - struct cooling_xpart_data cooling_data; - - /* Additional data used by the tracers */ - struct tracers_xpart_data tracers_data; - - /* Additional data used by the star formation */ - struct star_formation_xpart_data sf_data; - -} SWIFT_STRUCT_ALIGN; - /* Data of a single particle. */ struct part { @@ -72,50 +40,45 @@ struct part { /* Particle smoothing length. */ float h; - /* The primitive hydrodynamical variables. */ - struct { - - /* Density. */ - float rho; - - /* Fluid velocity. */ - float v[3]; + /* Density. */ + float rho; - /* Pressure. */ - float P; + /* Fluid velocity. */ + float fluid_v[3]; - /* Gradients of the primitive variables. */ - struct { + /* Pressure. */ + float P; - /* Density gradients. */ - float rho[3]; + /* Gradients of the primitive variables. */ + struct { - /* Fluid velocity gradients. */ - float v[3][3]; + /* Density gradients. */ + float rho[3]; - /* Pressure gradients. */ - float P[3]; + /* Fluid velocity gradients. */ + float v[3][3]; - } gradients; + /* Pressure gradients. */ + float P[3]; - /* Quantities needed by the slope limiter. */ - struct { + } gradients; - /* Extreme values of the density among the neighbours. */ - float rho[2]; + /* Quantities needed by the slope limiter. */ + struct { - /* Extreme values of the fluid velocity among the neighbours. */ - float v[3][2]; + /* Extreme values of the density among the neighbours. */ + float rho[2]; - /* Extreme values of the pressure among the neighbours. */ - float P[2]; + /* Extreme values of the fluid velocity among the neighbours. */ + float v[3][2]; - /* Maximal distance to all neighbouring faces. */ - float maxr; + /* Extreme values of the pressure among the neighbours. */ + float P[2]; - } limiter; + /* Maximal distance to all neighbouring faces. */ + float maxr; - } primitives; + } limiter; /* The conserved hydrodynamical variables. */ struct { @@ -129,21 +92,21 @@ struct part { /* Fluid thermal energy (not per unit mass!). */ float energy; - /* Fluxes. */ - struct { + } conserved; - /* Mass flux. */ - float mass; + /* Fluxes. */ + struct { - /* Momentum flux. */ - float momentum[3]; + /* Mass flux. */ + float mass; - /* Energy flux. */ - float energy; + /* Momentum flux. */ + float momentum[3]; - } flux; + /* Energy flux. */ + float energy; - } conserved; + } flux; /* Geometrical quantities used for hydro. */ struct { @@ -158,6 +121,9 @@ struct part { /* Centroid of the "cell". */ float centroid[3]; + /* Correction factor for wcount. */ + float wcorr; + } geometry; /* Variables used for timestep calculation. */ @@ -180,9 +146,6 @@ struct part { /* Particle number density. */ float wcount; - /* Correction factor for wcount. */ - float wcorr; - } density; /* Quantities used during the force loop. */ @@ -210,8 +173,8 @@ struct part { /* Time-step length */ timebin_t time_bin; - /* Need waking-up ? */ - timebin_t wakeup; + /*! Time-step limiter information */ + struct timestep_limiter_data limiter_data; #ifdef SWIFT_DEBUG_CHECKS diff --git a/src/hydro/GizmoMFV/hydro_velocities.h b/src/hydro/Gizmo/MFV/hydro_velocities.h similarity index 61% rename from src/hydro/GizmoMFV/hydro_velocities.h rename to src/hydro/Gizmo/MFV/hydro_velocities.h index a61a482683291cfc0662116ada99b94a4ccfe68d..5fb11029e29105e6ee08d5df06d79cf04a0d3ddb 100644 --- a/src/hydro/GizmoMFV/hydro_velocities.h +++ b/src/hydro/Gizmo/MFV/hydro_velocities.h @@ -16,8 +16,8 @@ * along with this program. If not, see <http://www.gnu.org/licenses/>. * ******************************************************************************/ -#ifndef SWIFT_HYDRO_VELOCITIES_H -#define SWIFT_HYDRO_VELOCITIES_H +#ifndef SWIFT_GIZMO_MFV_HYDRO_VELOCITIES_H +#define SWIFT_GIZMO_MFV_HYDRO_VELOCITIES_H /** * @brief Initialize the GIZMO particle velocities before the start of the @@ -30,13 +30,13 @@ __attribute__((always_inline)) INLINE static void hydro_velocities_init( struct part* restrict p, struct xpart* restrict xp) { #ifdef GIZMO_FIX_PARTICLES - p->v[0] = 0.f; - p->v[1] = 0.f; - p->v[2] = 0.f; + p->v[0] = 0.0f; + p->v[1] = 0.0f; + p->v[2] = 0.0f; #else - p->v[0] = p->primitives.v[0]; - p->v[1] = p->primitives.v[1]; - p->v[2] = p->primitives.v[2]; + p->v[0] = p->fluid_v[0]; + p->v[1] = p->fluid_v[1]; + p->v[2] = p->fluid_v[2]; #endif xp->v_full[0] = p->v[0]; @@ -87,15 +87,15 @@ __attribute__((always_inline)) INLINE static void hydro_velocities_set( /* We first set the particle velocity. */ #ifdef GIZMO_FIX_PARTICLES - p->v[0] = 0.f; - p->v[1] = 0.f; - p->v[2] = 0.f; + p->v[0] = 0.0f; + p->v[1] = 0.0f; + p->v[2] = 0.0f; #else // GIZMO_FIX_PARTICLES - if (p->conserved.mass > 0.f && p->primitives.rho > 0.f) { + if (p->conserved.mass > 0.0f && p->rho > 0.0f) { - const float inverse_mass = 1.f / p->conserved.mass; + const float inverse_mass = 1.0f / p->conserved.mass; /* Normal case: set particle velocity to fluid velocity. */ p->v[0] = p->conserved.momentum[0] * inverse_mass; @@ -116,15 +116,14 @@ __attribute__((always_inline)) INLINE static void hydro_velocities_set( const float R = get_radius_dimension_sphere(p->geometry.volume); const float eta = 0.25f; const float etaR = eta * R; - const float xi = 1.f; - const float soundspeed = - sqrtf(hydro_gamma * p->primitives.P / p->primitives.rho); + const float xi = 1.0f; + const float soundspeed = sqrtf(hydro_gamma * p->P / p->rho); /* We only apply the correction if the offset between centroid and position is too large. */ if (d > 0.9f * etaR) { float fac = xi * soundspeed / d; if (d < 1.1f * etaR) { - fac *= 5.f * (d - 0.9f * etaR) / etaR; + fac *= 5.0f * (d - 0.9f * etaR) / etaR; } p->v[0] -= ds[0] * fac; p->v[1] -= ds[1] * fac; @@ -134,9 +133,9 @@ __attribute__((always_inline)) INLINE static void hydro_velocities_set( #endif // GIZMO_STEER_MOTION } else { /* Vacuum particles have no fluid velocity. */ - p->v[0] = 0.f; - p->v[1] = 0.f; - p->v[2] = 0.f; + p->v[0] = 0.0f; + p->v[1] = 0.0f; + p->v[2] = 0.0f; } #endif // GIZMO_FIX_PARTICLES @@ -153,4 +152,70 @@ __attribute__((always_inline)) INLINE static void hydro_velocities_set( } } -#endif /* SWIFT_HYDRO_VELOCITIES_H */ +/** + * @brief Reset the variables used to store the centroid; used for the velocity + * correction. + */ +__attribute__((always_inline)) INLINE static void +hydro_velocities_reset_centroids(struct part* restrict p) { + + p->geometry.centroid[0] = 0.0f; + p->geometry.centroid[1] = 0.0f; + p->geometry.centroid[2] = 0.0f; +} + +/** + * @brief Normalise the centroids after the density loop. + * + * @param p Particle. + * @param wcount Wcount for the particle. This is an explicit argument, so that + * it is clear from the code that wcount needs to be normalised by the time it + * is used here. + */ +__attribute__((always_inline)) INLINE static void +hydro_velocities_normalise_centroid(struct part* restrict p, + const float wcount) { + + const float norm = kernel_norm / wcount; + p->geometry.centroid[0] *= norm; + p->geometry.centroid[1] *= norm; + p->geometry.centroid[2] *= norm; +} + +/** + * @brief Update the centroid with the given contribution, assuming the particle + * acts as the left particle in the neighbour interaction. + * + * @param p Particle (pi). + * @param dx Distance vector between the particle and its neighbour (dx = pi->x + * - pj->x). + * @param w Kernel value at position pj->x. + */ +__attribute__((always_inline)) INLINE static void +hydro_velocities_update_centroid_left(struct part* restrict p, const float* dx, + const float w) { + + p->geometry.centroid[0] -= dx[0] * w; + p->geometry.centroid[1] -= dx[1] * w; + p->geometry.centroid[2] -= dx[2] * w; +} + +/** + * @brief Update the centroid with the given contribution, assuming the particle + * acts as the right particle in the neighbour interaction. + * + * @param p Particle (pj). + * @param dx Distance vector between the particle and its neighbour (dx = pi->x + * - pj->x). + * @param w Kernel value at position pi->x. + */ +__attribute__((always_inline)) INLINE static void +hydro_velocities_update_centroid_right(struct part* restrict p, const float* dx, + const float w) { + + p->geometry.centroid[0] += dx[0] * w; + p->geometry.centroid[1] += dx[1] * w; + p->geometry.centroid[2] += dx[2] * w; +} + +#endif /* SWIFT_GIZMO_MFV_HYDRO_VELOCITIES_H */ diff --git a/src/hydro/GizmoMFM/hydro.h b/src/hydro/Gizmo/hydro.h similarity index 51% rename from src/hydro/GizmoMFM/hydro.h rename to src/hydro/Gizmo/hydro.h index b1472ca6181256e8e6ebc12b734b98e7b84f2a64..4972cf7161c7f97506196640e79d438357b9d55a 100644 --- a/src/hydro/GizmoMFM/hydro.h +++ b/src/hydro/Gizmo/hydro.h @@ -1,7 +1,6 @@ /******************************************************************************* * This file is part of SWIFT. - * Coypright (c) 2015 Matthieu Schaller (matthieu.schaller@durham.ac.uk) - * 2016, 2017 Bert Vandenbroucke (bert.vandenbroucke@gmail.com) + * Coypright (c) 2019 Bert Vandenbroucke (bert.vandenbroucke@gmail.com) * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU Lesser General Public License as published @@ -17,23 +16,35 @@ * along with this program. If not, see <http://www.gnu.org/licenses/>. * ******************************************************************************/ -#ifndef SWIFT_GIZMO_MFM_HYDRO_H -#define SWIFT_GIZMO_MFM_HYDRO_H +#ifndef SWIFT_GIZMO_HYDRO_H +#define SWIFT_GIZMO_HYDRO_H + +/** + * @brief Enable Lloyd's iteration. + * + * If you enable the flag below, the code will ignore all hydrodynamical + * variables and instead run in a mode where + */ +/*#define GIZMO_LLOYD_ITERATION*/ -#include "adiabatic_index.h" #include "approx_math.h" -#include "cosmology.h" #include "entropy_floor.h" -#include "equation_of_state.h" +#include "hydro_flux.h" +#include "hydro_getters.h" #include "hydro_gradients.h" -#include "hydro_properties.h" +#include "hydro_lloyd.h" +#include "hydro_setters.h" #include "hydro_space.h" -#include "hydro_unphysical.h" -#include "minmax.h" -#include "riemann.h" +#include "hydro_velocities.h" #include <float.h> +#if defined(GIZMO_MFV_SPH) +#define SPH_IMPLEMENTATION "GIZMO MFV (Hopkins 2015)" +#elif defined(GIZMO_MFM_SPH) +#define SPH_IMPLEMENTATION "GIZMO MFM (Hopkins 2015)" +#endif + /** * @brief Computes the hydro time-step of a given particle * @@ -49,16 +60,22 @@ __attribute__((always_inline)) INLINE static float hydro_compute_timestep( const float CFL_condition = hydro_properties->CFL_condition; + /* skip the time step calculation if we are using Lloyd's algorithm */ + hydro_gizmo_lloyd_skip_timestep(CFL_condition); + + float W[5]; + hydro_part_get_primitive_variables(p, W); + /* v_full is the actual velocity of the particle, v is its hydrodynamical velocity. The time step depends on the relative difference of the two. */ float vrel[3]; - vrel[0] = p->v[0] - xp->v_full[0]; - vrel[1] = p->v[1] - xp->v_full[1]; - vrel[2] = p->v[2] - xp->v_full[2]; + vrel[0] = W[1] - xp->v_full[0]; + vrel[1] = W[2] - xp->v_full[1]; + vrel[2] = W[3] - xp->v_full[2]; float vmax = sqrtf(vrel[0] * vrel[0] + vrel[1] * vrel[1] + vrel[2] * vrel[2]) + - sqrtf(hydro_gamma * p->P / p->rho); + sqrtf(hydro_gamma * W[4] / W[0]); vmax = max(vmax, p->timestepvars.vmax); const float psize = cosmo->a * cosmo->a * @@ -113,38 +130,38 @@ __attribute__((always_inline)) INLINE static void hydro_timestep_extra( __attribute__((always_inline)) INLINE static void hydro_first_init_part( struct part* p, struct xpart* xp) { - const float mass = p->conserved.mass; + float W[5], Q[5]; - /* we can already initialize the momentum */ - p->conserved.momentum[0] = mass * p->v[0]; - p->conserved.momentum[1] = mass * p->v[1]; - p->conserved.momentum[2] = mass * p->v[2]; + W[0] = 0.0f; + W[1] = p->v[0]; + W[2] = p->v[1]; + W[3] = p->v[2]; + W[4] = 0.0f; -/* and the thermal energy */ -/* remember that we store the total thermal energy, not the specific thermal - energy (as in Gadget) */ + Q[0] = p->conserved.mass; + Q[1] = Q[0] * W[1]; + Q[2] = Q[0] * W[2]; + Q[3] = Q[0] * W[3]; #if defined(EOS_ISOTHERMAL_GAS) - /* this overwrites the internal energy from the initial condition file - * Note that we call the EoS function just to get the constant u here. */ - p->conserved.energy = mass * gas_internal_energy_from_entropy(0.0f, 0.0f); + Q[4] = Q[0] * gas_internal_energy_from_entropy(0.0f, 0.0f); #else - p->conserved.energy *= mass; + Q[4] = p->conserved.energy * Q[0]; #endif #ifdef GIZMO_TOTAL_ENERGY - /* add the total kinetic energy */ - p->conserved.energy += 0.5f * (p->conserved.momentum[0] * p->v[0] + - p->conserved.momentum[1] * p->v[1] + - p->conserved.momentum[2] * p->v[2]); + Q[4] += 0.5f * (Q[1] * W[1] + Q[2] * W[2] + Q[3] * W[3]); #endif + /* overwrite all hydro variables if we are using Lloyd's algorithm */ + hydro_gizmo_lloyd_initialize_particle(W, Q, p->v); + p->time_bin = 0; - p->wakeup = time_bin_not_awake; + + hydro_part_set_primitive_variables(p, W); + hydro_part_set_conserved_variables(p, Q); /* initialize the particle velocity based on the primitive fluid velocity */ - xp->v_full[0] = p->v[0]; - xp->v_full[1] = p->v[1]; - xp->v_full[2] = p->v[2]; + hydro_velocities_init(p, xp); /* ignore accelerations present in the initial condition */ p->a_hydro[0] = 0.0f; @@ -171,6 +188,7 @@ __attribute__((always_inline)) INLINE static void hydro_init_part( p->density.wcount = 0.0f; p->density.wcount_dh = 0.0f; + p->geometry.volume = 0.0f; p->geometry.matrix_E[0][0] = 0.0f; p->geometry.matrix_E[0][1] = 0.0f; @@ -181,9 +199,9 @@ __attribute__((always_inline)) INLINE static void hydro_init_part( p->geometry.matrix_E[2][0] = 0.0f; p->geometry.matrix_E[2][1] = 0.0f; p->geometry.matrix_E[2][2] = 0.0f; - p->geometry.centroid[0] = 0.0f; - p->geometry.centroid[1] = 0.0f; - p->geometry.centroid[2] = 0.0f; + + /* reset the centroid variables used for the velocity correction in MFV */ + hydro_velocities_reset_centroids(p); } /** @@ -240,14 +258,8 @@ __attribute__((always_inline)) INLINE static void hydro_end_density( p->geometry.matrix_E[2][1] = ihdim * p->geometry.matrix_E[2][1]; p->geometry.matrix_E[2][2] = ihdim * p->geometry.matrix_E[2][2]; - p->geometry.centroid[0] *= kernel_norm; - p->geometry.centroid[1] *= kernel_norm; - p->geometry.centroid[2] *= kernel_norm; - - const float wcount_inv = 1.0f / p->density.wcount; - p->geometry.centroid[0] *= wcount_inv; - p->geometry.centroid[1] *= wcount_inv; - p->geometry.centroid[2] *= wcount_inv; + /* normalise the centroids for MFV */ + hydro_velocities_normalise_centroid(p, p->density.wcount); /* Check the condition number to see if we have a stable geometry. */ float condition_number_E = 0.0f; @@ -269,7 +281,7 @@ __attribute__((always_inline)) INLINE static void hydro_end_density( } } - float condition_number = + const float condition_number = hydro_dimension_inv * sqrtf(condition_number_E * condition_number_Einv); if (condition_number > const_gizmo_max_condition_number && @@ -283,62 +295,63 @@ __attribute__((always_inline)) INLINE static void hydro_end_density( condition_number, const_gizmo_max_condition_number, p->id); #endif /* add a correction to the number of neighbours for this particle */ - p->geometry.wcorr *= const_gizmo_w_correction_factor; + p->geometry.wcorr = const_gizmo_w_correction_factor * p->geometry.wcorr; } /* compute primitive variables */ /* eqns (3)-(5) */ - const float m = p->conserved.mass; + const float Q[5] = {p->conserved.mass, p->conserved.momentum[0], + p->conserved.momentum[1], p->conserved.momentum[2], + p->conserved.energy}; #ifdef SWIFT_DEBUG_CHECKS - if (m < 0.0f) { + if (Q[0] < 0.) { error("Mass is negative!"); } - if (volume == 0.0f) { + if (volume == 0.) { error("Volume is 0!"); } #endif - // MATTHIEU: Bert is this correct? Do we need cosmology terms here? - float momentum[3]; - momentum[0] = p->conserved.momentum[0]; - momentum[1] = p->conserved.momentum[1]; - momentum[2] = p->conserved.momentum[2]; - p->rho = m * volume_inv; - if (m == 0.0f) { - p->v[0] = 0.0f; - p->v[1] = 0.0f; - p->v[2] = 0.0f; + float W[5]; + + W[0] = Q[0] * volume_inv; + if (Q[0] == 0.0f) { + W[1] = 0.; + W[2] = 0.; + W[3] = 0.; } else { - const float m_inv = 1.0f / m; - p->v[0] = momentum[0] * m_inv; - p->v[1] = momentum[1] * m_inv; - p->v[2] = momentum[2] * m_inv; + const float m_inv = 1.0f / Q[0]; + W[1] = Q[1] * m_inv; + W[2] = Q[2] * m_inv; + W[3] = Q[3] * m_inv; } #ifdef EOS_ISOTHERMAL_GAS /* although the pressure is not formally used anywhere if an isothermal eos has been selected, we still make sure it is set to the correct value */ - p->P = gas_pressure_from_internal_energy(p->rho, 0.0f); + W[4] = gas_pressure_from_internal_energy(W[0], 0.0f); #else - float energy = p->conserved.energy; - #ifdef GIZMO_TOTAL_ENERGY /* subtract the kinetic energy; we want the thermal energy */ - energy -= 0.5f * (momentum[0] * p->v[0] + momentum[1] * p->v[1] + - momentum[2] * p->v[2]); + Q[4] -= 0.5f * (Q[1] * W[1] + Q[2] * W[2] + Q[3] * W[3]); #endif /* energy contains the total thermal energy, we want the specific energy. this is why we divide by the volume, and not by the density */ - p->P = hydro_gamma_minus_one * energy * volume_inv; + W[4] = hydro_gamma_minus_one * Q[4] * volume_inv; #endif /* sanity checks */ - gizmo_check_physical_quantities("density", "pressure", p->rho, p->v[0], - p->v[1], p->v[2], p->P); + gizmo_check_physical_quantities("density", "pressure", W[0], W[1], W[2], W[3], + W[4]); + + /* reset the primitive variables if we are using Lloyd's algorithm */ + hydro_gizmo_lloyd_reset_primitive_variables(W); + + hydro_part_set_primitive_variables(p, W); /* Add a correction factor to wcount (to force a neighbour number increase if the geometry matrix is close to singular) */ @@ -364,7 +377,7 @@ __attribute__((always_inline)) INLINE static void hydro_part_has_no_neighbours( /* Re-set problematic values */ p->density.wcount = kernel_root * h_inv_dim; - p->density.wcount_dh = 0.0f; + p->density.wcount_dh = 0.f; p->geometry.volume = 1.0f; p->geometry.matrix_E[0][0] = 1.0f; p->geometry.matrix_E[0][1] = 0.0f; @@ -375,12 +388,9 @@ __attribute__((always_inline)) INLINE static void hydro_part_has_no_neighbours( p->geometry.matrix_E[2][0] = 0.0f; p->geometry.matrix_E[2][1] = 0.0f; p->geometry.matrix_E[2][2] = 1.0f; - /* centroid is relative w.r.t. particle position */ - /* by setting the centroid to 0.0f, we make sure no velocity correction is - applied */ - p->geometry.centroid[0] = 0.0f; - p->geometry.centroid[1] = 0.0f; - p->geometry.centroid[2] = 0.0f; + + /* reset the centroid to disable MFV velocity corrections for this particle */ + hydro_velocities_reset_centroids(p); } /** @@ -403,11 +413,11 @@ __attribute__((always_inline)) INLINE static void hydro_prepare_gradient( const struct cosmology* cosmo, const struct hydro_props* hydro_props) { /* Initialize time step criterion variables */ - p->timestepvars.vmax = 0.0f; + p->timestepvars.vmax = 0.; hydro_gradients_init(p); - // MATTHIEU: Bert is this correct? Do we need cosmology terms here? + hydro_velocities_prepare_force(p, xp); } /** @@ -437,10 +447,8 @@ __attribute__((always_inline)) INLINE static void hydro_end_gradient( hydro_gradients_finalize(p); -#ifdef GIZMO_LLOYD_ITERATION - /* reset the gradients to zero, as we don't want them */ - hydro_gradients_init(p); -#endif + /* reset the gradients if we are using Lloyd's algorith; we don't use them */ + hydro_gizmo_lloyd_reset_gradients(p); } /** @@ -465,11 +473,7 @@ __attribute__((always_inline)) INLINE static void hydro_prepare_force( 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; - p->flux.momentum[1] = 0.0f; - p->flux.momentum[2] = 0.0f; - p->flux.energy = 0.0f; + hydro_part_reset_fluxes(p); } /** @@ -503,7 +507,7 @@ __attribute__((always_inline)) INLINE static void hydro_reset_acceleration( __attribute__((always_inline)) INLINE static void hydro_reset_predicted_values( struct part* restrict p, const struct xpart* restrict xp, const struct cosmology* cosmo) { - // MATTHIEU: Do we need something here? + // MATTHIEU: Apply the entropy floor here. } /** @@ -530,24 +534,25 @@ __attribute__((always_inline)) INLINE static void hydro_convert_quantities( * @param xp The extended particle data to act upon. * @param dt_drift The drift time-step for positions. * @param dt_therm The drift time-step for thermal quantities. - * @param cosmo The cosmological model. - * @param hydro_props The properties of the hydro scheme. - * @param floor_props The properties of the entropy floor. */ __attribute__((always_inline)) INLINE static void hydro_predict_extra( struct part* p, struct xpart* xp, float dt_drift, float dt_therm, const struct cosmology* cosmo, const struct hydro_props* hydro_props, const struct entropy_floor_properties* floor_props) { + /* skip the drift if we are using Lloyd's algorithm */ + hydro_gizmo_lloyd_skip_drift(); + const float h_inv = 1.0f / p->h; /* Predict smoothing length */ const float w1 = p->force.h_dt * h_inv * dt_drift; float h_corr; - if (fabsf(w1) < 0.2f) + if (fabsf(w1) < 0.2f) { h_corr = approx_expf(w1); /* 4th order expansion of exp(w) */ - else + } else { h_corr = expf(w1); + } /* Limit the smoothing length correction (and make sure it is always positive). */ @@ -555,37 +560,49 @@ __attribute__((always_inline)) INLINE static void hydro_predict_extra( p->h *= h_corr; } - /* drift the primitive variables based on the old fluxes */ +#ifdef SWIFT_DEBUG_CHECKS + if (p->h <= 0.) { + error("Zero or negative smoothing length (%g)!", p->h); + } +#endif + + float W[5]; + hydro_part_get_primitive_variables(p, W); + float flux[5]; + hydro_part_get_fluxes(p, flux); + + W[0] += + hydro_gizmo_mfv_density_drift_term(flux[0], dt_therm, p->geometry.volume); + if (p->conserved.mass > 0.0f) { const float m_inv = 1.0f / p->conserved.mass; - p->v[0] += p->flux.momentum[0] * dt_drift * m_inv; - p->v[1] += p->flux.momentum[1] * dt_drift * m_inv; - p->v[2] += p->flux.momentum[2] * dt_drift * m_inv; + W[1] += flux[1] * dt_therm * m_inv; + W[2] += flux[2] * dt_therm * m_inv; + W[3] += flux[3] * dt_therm * m_inv; #if !defined(EOS_ISOTHERMAL_GAS) #ifdef GIZMO_TOTAL_ENERGY - const float Etot = p->conserved.energy + p->flux.energy * dt_drift; - const float v2 = - (p->v[0] * p->v[0] + p->v[1] * p->v[1] + p->v[2] * p->v[2]); + const float Etot = p->conserved.energy + flux[4] * dt_therm; + const float v2 = (W[1] * W[1] + W[2] * W[2] + W[3] * W[3]); const float u = (Etot * m_inv - 0.5f * v2); #else - const float u = (p->conserved.energy + p->flux.energy * dt_drift) * m_inv; + const float u = (p->conserved.energy + flux[4] * dt_therm) * m_inv; #endif - p->P = hydro_gamma_minus_one * u * p->rho; + W[4] = hydro_gamma_minus_one * u * W[0]; #endif } - // MATTHIEU: Apply the entropy floor here. + // MATTHIEU: Apply the entropy floor here. + + /* add the gravitational contribution to the fluid velocity drift */ + /* (MFV only) */ + hydro_gizmo_mfv_extra_velocity_drift(&W[1], p->v, xp->v_full); -#ifdef SWIFT_DEBUG_CHECKS - if (p->h <= 0.0f) { - error("Zero or negative smoothing length (%g)!", p->h); - } -#endif + gizmo_check_physical_quantities("density", "pressure", W[0], W[1], W[2], W[3], + W[4]); - gizmo_check_physical_quantities("density", "pressure", p->rho, p->v[0], - p->v[1], p->v[2], p->P); + hydro_part_set_primitive_variables(p, W); } /** @@ -604,12 +621,10 @@ __attribute__((always_inline)) INLINE static void hydro_predict_extra( __attribute__((always_inline)) INLINE static void hydro_end_force( struct part* p, const struct cosmology* cosmo) { - /* set the variables that are used to drift the primitive variables */ + hydro_velocities_end_force(p); - // MATTHIEU: Bert is this correct? Do we need cosmology terms here? - - /* Add normalization to h_dt. */ - p->force.h_dt *= p->h * hydro_dimension_inv; + /* Reset force variables if we are using Lloyd's algorithm. */ + hydro_gizmo_lloyd_end_force(p); } /** @@ -632,25 +647,55 @@ __attribute__((always_inline)) INLINE static void hydro_kick_extra( const struct hydro_props* hydro_props, const struct entropy_floor_properties* floor_props) { - float a_grav[3]; + /* Add gravity. We only do this if we have gravity activated. */ + if (p->gpart) { + /* Retrieve the current value of the gravitational acceleration from the + gpart. We are only allowed to do this because this is the kick. We still + need to check whether gpart exists though.*/ + float a_grav[3]; + + a_grav[0] = p->gpart->a_grav[0]; + a_grav[1] = p->gpart->a_grav[1]; + a_grav[2] = p->gpart->a_grav[2]; + + p->conserved.energy += hydro_gizmo_mfv_gravity_energy_update_term( + dt_kick_corr, dt_grav, p, p->conserved.momentum, a_grav); - /* Update conserved variables (note: the mass does not change). */ - p->conserved.momentum[0] += p->flux.momentum[0] * dt_therm; - p->conserved.momentum[1] += p->flux.momentum[1] * dt_therm; - p->conserved.momentum[2] += p->flux.momentum[2] * dt_therm; + /* Kick the momentum for half a time step */ + /* Note that this also affects the particle movement, as the velocity for + the particles is set after this. */ + p->conserved.momentum[0] += p->conserved.mass * a_grav[0] * dt_grav; + p->conserved.momentum[1] += p->conserved.mass * a_grav[1] * dt_grav; + p->conserved.momentum[2] += p->conserved.mass * a_grav[2] * dt_grav; + } + + float flux[5]; + hydro_part_get_fluxes(p, flux); + + /* Update conserved variables. */ + p->conserved.mass += hydro_gizmo_mfv_mass_update_term(flux[0], dt_therm); + p->conserved.momentum[0] += flux[1] * dt_therm; + p->conserved.momentum[1] += flux[2] * dt_therm; + p->conserved.momentum[2] += flux[3] * dt_therm; #if defined(EOS_ISOTHERMAL_GAS) /* We use the EoS equation in a sneaky way here just to get the constant u */ p->conserved.energy = p->conserved.mass * gas_internal_energy_from_entropy(0.0f, 0.0f); #else - p->conserved.energy += p->flux.energy * dt_therm; + p->conserved.energy += flux[4] * dt_therm; #endif #ifndef HYDRO_GAMMA_5_3 + const float Pcorr = (dt_hydro - dt_therm) * p->geometry.volume; p->conserved.momentum[0] -= Pcorr * p->gradients.P[0]; p->conserved.momentum[1] -= Pcorr * p->gradients.P[1]; p->conserved.momentum[2] -= Pcorr * p->gradients.P[2]; +#ifdef GIZMO_TOTAL_ENERGY + p->conserved.energy -= Pcorr * (p->fluid_v[0] * p->gradients.P[0] + + p->fluid_v[1] * p->gradients.P[1] + + p->fluid_v[2] * p->gradients.P[2]); +#endif #endif /* Apply the minimal energy limit */ @@ -670,7 +715,15 @@ __attribute__((always_inline)) INLINE static void hydro_kick_extra( #ifdef SWIFT_DEBUG_CHECKS /* Note that this check will only have effect if no GIZMO_UNPHYSICAL option was selected. */ - if (p->conserved.energy < 0.0f) { +#ifdef GIZMO_MFV_SPH + if (p->conserved.mass < 0.) { + error( + "Negative mass after conserved variables update (mass: %g, dmass: %g)!", + p->conserved.mass, p->flux.mass); + } +#endif + + if (p->conserved.energy < 0.) { error( "Negative energy after conserved variables update (energy: %g, " "denergy: %g)!", @@ -678,476 +731,16 @@ __attribute__((always_inline)) INLINE static void hydro_kick_extra( } #endif - /* Add gravity. We only do this if we have gravity activated. */ - if (p->gpart) { - /* Retrieve the current value of the gravitational acceleration from the - gpart. We are only allowed to do this because this is the kick. We still - need to check whether gpart exists though.*/ - a_grav[0] = p->gpart->a_grav[0]; - a_grav[1] = p->gpart->a_grav[1]; - a_grav[2] = p->gpart->a_grav[2]; - - /* Kick the momentum for half a time step */ - /* Note that this also affects the particle movement, as the velocity for - the particles is set after this. */ - p->conserved.momentum[0] += dt_grav * p->conserved.mass * a_grav[0]; - p->conserved.momentum[1] += dt_grav * p->conserved.mass * a_grav[1]; - p->conserved.momentum[2] += dt_grav * p->conserved.mass * a_grav[2]; - } - - /* Set the velocities: */ - /* We first set the particle velocity */ - if (p->conserved.mass > 0.0f && p->rho > 0.0f) { - - const float inverse_mass = 1.0f / p->conserved.mass; + hydro_gizmo_mfv_update_gpart_mass(p); + hydro_velocities_set(p, xp); - /* Normal case: set particle velocity to fluid velocity. */ - xp->v_full[0] = p->conserved.momentum[0] * inverse_mass; - xp->v_full[1] = p->conserved.momentum[1] * inverse_mass; - xp->v_full[2] = p->conserved.momentum[2] * inverse_mass; - - } else { - /* Vacuum particles have no fluid velocity. */ - xp->v_full[0] = 0.0f; - xp->v_full[1] = 0.0f; - xp->v_full[2] = 0.0f; - } - - if (p->gpart) { - p->gpart->v_full[0] = xp->v_full[0]; - p->gpart->v_full[1] = xp->v_full[1]; - p->gpart->v_full[2] = xp->v_full[2]; - } + /* undo the flux exchange and kick the particles towards their centroid */ + hydro_gizmo_lloyd_kick(p, xp, dt_therm); /* reset wcorr */ p->geometry.wcorr = 1.0f; } -/** - * @brief Returns the comoving internal energy of a particle - * - * @param p The particle of interest. - */ -__attribute__((always_inline)) INLINE static float -hydro_get_comoving_internal_energy(const struct part* restrict p) { - - if (p->rho > 0.0f) { - return gas_internal_energy_from_pressure(p->rho, p->P); - } else { - return 0.0f; - } -} - -/** - * @brief Returns the physical internal energy of a particle - * - * @param p The particle of interest. - * @param xp The extended data of the particle of interest. - * @param cosmo The cosmological model. - */ -__attribute__((always_inline)) INLINE static float -hydro_get_physical_internal_energy(const struct part* restrict p, - const struct xpart* restrict xp, - const struct cosmology* cosmo) { - - return cosmo->a_factor_internal_energy * - 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 - * - * @param p The particle of interest. - */ -__attribute__((always_inline)) INLINE static float hydro_get_comoving_entropy( - const struct part* restrict p) { - - if (p->rho > 0.0f) { - return gas_entropy_from_pressure(p->rho, p->P); - } else { - return 0.0f; - } -} - -/** - * @brief Returns the physical internal energy of a particle - * - * @param p The particle of interest. - * @param xp The extended data of the particle of interest. - * @param cosmo The cosmological model. - */ -__attribute__((always_inline)) INLINE static float hydro_get_physical_entropy( - const struct part* restrict p, const struct xpart* restrict xp, - const struct cosmology* cosmo) { - - /* Note: no cosmological conversion required here with our choice of - * coordinates. */ - 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 - * - * @param p The particle of interest. - */ -__attribute__((always_inline)) INLINE static float -hydro_get_comoving_soundspeed(const struct part* restrict p) { - - if (p->rho > 0.0f) { - return gas_soundspeed_from_pressure(p->rho, p->P); - } else { - return 0.0f; - } -} - -/** - * @brief Returns the physical sound speed of a particle - * - * @param p The particle of interest. - * @param cosmo The cosmological model. - */ -__attribute__((always_inline)) INLINE static float -hydro_get_physical_soundspeed(const struct part* restrict p, - const struct cosmology* cosmo) { - - return cosmo->a_factor_sound_speed * hydro_get_comoving_soundspeed(p); -} - -/** - * @brief Returns the comoving pressure of a particle - * - * @param p The particle of interest - */ -__attribute__((always_inline)) INLINE static float hydro_get_comoving_pressure( - const struct part* restrict p) { - - return p->P; -} - -/** - * @brief Returns the comoving pressure of a particle - * - * @param p The particle of interest. - * @param cosmo The cosmological model. - */ -__attribute__((always_inline)) INLINE static float hydro_get_physical_pressure( - const struct part* restrict p, const struct cosmology* cosmo) { - - return cosmo->a_factor_pressure * p->P; -} - -/** - * @brief Returns the mass of a particle - * - * @param p The particle of interest - */ -__attribute__((always_inline)) INLINE static float hydro_get_mass( - const struct part* restrict p) { - - return p->conserved.mass; -} - -/** - * @brief Sets the mass of a particle - * - * @param p The particle of interest - * @param m The mass to set. - */ -__attribute__((always_inline)) INLINE static void hydro_set_mass( - struct part* restrict p, float m) { - - p->conserved.mass = m; -} - -/** - * @brief Returns the velocities drifted to the current time of a particle. - * - * @param p The particle of interest - * @param xp The extended data of the particle. - * @param dt_kick_hydro The time (for hydro accelerations) since the last kick. - * @param dt_kick_grav The time (for gravity accelerations) since the last kick. - * @param v (return) The velocities at the current time. - */ -__attribute__((always_inline)) INLINE static void hydro_get_drifted_velocities( - const struct part* restrict p, const struct xpart* xp, float dt_kick_hydro, - float dt_kick_grav, float v[3]) { - - if (p->conserved.mass > 0.0f) { - const float inverse_mass = 1.0f / p->conserved.mass; - v[0] = p->v[0] + p->flux.momentum[0] * dt_kick_hydro * inverse_mass; - v[1] = p->v[1] + p->flux.momentum[1] * dt_kick_hydro * inverse_mass; - v[2] = p->v[2] + p->flux.momentum[2] * dt_kick_hydro * inverse_mass; - } else { - v[0] = p->v[0]; - v[1] = p->v[1]; - v[2] = p->v[2]; - } - - v[0] += xp->a_grav[0] * dt_kick_grav; - v[1] += xp->a_grav[1] * dt_kick_grav; - v[2] += xp->a_grav[2] * dt_kick_grav; -} - -/** - * @brief Returns the 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_comoving_internal_energy_dt(const struct part* restrict p) { - - error("Needs implementing"); - return 0.f; -} - -/** - * @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) { - error("Needs implementing"); - return 0.f; -} - -/** - * @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 comoving internal energy. - */ -__attribute__((always_inline)) INLINE static void -hydro_set_comoving_internal_energy_dt(struct part* restrict p, - const float du_dt) { - error("Needs implementing"); -} - -/** - * @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 physical internal energy. - */ -__attribute__((always_inline)) INLINE static void -hydro_set_physical_internal_energy_dt(struct part* restrict p, - const struct cosmology* restrict cosmo, - const float du_dt) { - error("Needs implementing"); -} -/** - * @brief Sets the physical entropy of a particle - * - * @param p The particle of interest. - * @param xp The extended particle data. - * @param cosmo Cosmology data structure - * @param entropy The physical entropy - */ -__attribute__((always_inline)) INLINE static void hydro_set_physical_entropy( - struct part* p, struct xpart* xp, const struct cosmology* cosmo, - const float entropy) { - - error("Needs implementing"); -} - -/** - * @brief Sets the physical internal energy of a particle - * - * @param p The particle of interest. - * @param xp The extended particle data. - * @param cosmo Cosmology data structure - * @param u The physical internal energy - */ -__attribute__((always_inline)) INLINE static void -hydro_set_physical_internal_energy(struct part* p, struct xpart* xp, - const struct cosmology* cosmo, - const float u) { - error("Need implementing"); -} - -/** - * @brief Sets the drifted physical internal energy of a particle - * - * @param p The particle of interest. - * @param cosmo Cosmology data structure - * @param u The physical internal energy - */ -__attribute__((always_inline)) INLINE static void -hydro_set_drifted_physical_internal_energy(struct part* p, - const struct cosmology* cosmo, - const float u) { - error("Need implementing"); -} - -/** - * @brief Update the value of the viscosity alpha for the scheme. - * - * @param p the particle of interest - * @param alpha the new value for the viscosity coefficient. - */ -__attribute__((always_inline)) INLINE static void hydro_set_viscosity_alpha( - struct part* restrict p, float alpha) { - /* Purposefully left empty */ -} - -/** - * @brief Update the value of the viscosity alpha to the - * feedback reset value for the scheme. - * - * @param p the particle of interest - */ -__attribute__((always_inline)) INLINE static void -hydro_diffusive_feedback_reset(struct part* restrict p) { - /* Purposefully left empty */ -} - -/** - * @brief Returns the comoving density of a particle - * - * @param p The particle of interest - */ -__attribute__((always_inline)) INLINE static float hydro_get_comoving_density( - const struct part* restrict p) { - - return p->rho; -} - -/** - * @brief Returns the physical density of a particle - * - * @param p The particle of interest - * @param cosmo The cosmological model. - */ -__attribute__((always_inline)) INLINE static float hydro_get_physical_density( - const struct part* restrict p, const struct cosmology* cosmo) { - - return cosmo->a3_inv * p->rho; -} - -/** - * @brief Modifies the thermal state of a particle to the imposed internal - * energy - * - * This overrides the current state of the particle but does *not* change its - * time-derivatives - * - * @param p The particle - * @param u The new internal energy - */ -__attribute__((always_inline)) INLINE static void hydro_set_internal_energy( - struct part* restrict p, float u) { - - /* conserved.energy is NOT the specific energy (u), but the total thermal - energy (u*m) */ - p->conserved.energy = u * p->conserved.mass; -#ifdef GIZMO_TOTAL_ENERGY - /* add the kinetic energy */ - p->conserved.energy += - 0.5f * p->conserved.mass * - (p->conserved.momentum[0] * p->v[0] + p->conserved.momentum[1] * p->v[1] + - p->conserved.momentum[2] * p->v[2]); -#endif - p->P = hydro_gamma_minus_one * p->rho * u; -} - -/** - * @brief Modifies the thermal state of a particle to the imposed entropy - * - * This overrides the current state of the particle but does *not* change its - * time-derivatives - * - * @param p The particle - * @param S The new entropy - */ -__attribute__((always_inline)) INLINE static void hydro_set_entropy( - struct part* restrict p, float S) { - - p->conserved.energy = S * pow_gamma_minus_one(p->rho) * - hydro_one_over_gamma_minus_one * p->conserved.mass; -#ifdef GIZMO_TOTAL_ENERGY - /* add the kinetic energy */ - p->conserved.energy += - 0.5f * p->conserved.mass * - (p->conserved.momentum[0] * p->v[0] + p->conserved.momentum[1] * p->v[1] + - p->conserved.momentum[2] * p->v[2]); -#endif - p->P = S * pow_gamma(p->rho); -} - -/** - * @brief Overwrite the initial internal energy of a particle. - * - * Note that in the cases where the thermodynamic variable is not - * internal energy but gets converted later, we must overwrite that - * field. The conversion to the actual variable happens later after - * the initial fake time-step. - * - * @param p The #part to write to. - * @param u_init The new initial internal energy. - */ -__attribute__((always_inline)) INLINE static void -hydro_set_init_internal_energy(struct part* p, float u_init) { - - /* We store the initial energy per unit mass in the energy - * variable as the conversion to energy will be done later, - * in hydro_first_init_part(). */ - p->conserved.energy = u_init; -} - /** * @brief Operations performed when a particle gets removed from the * simulation volume. @@ -1158,4 +751,4 @@ hydro_set_init_internal_energy(struct part* p, float u_init) { __attribute__((always_inline)) INLINE static void hydro_remove_part( const struct part* p, const struct xpart* xp) {} -#endif /* SWIFT_GIZMO_MFM_HYDRO_H */ +#endif /* SWIFT_GIZMO_HYDRO_H */ diff --git a/src/hydro/Gizmo/hydro_debug.h b/src/hydro/Gizmo/hydro_debug.h new file mode 100644 index 0000000000000000000000000000000000000000..e64bce00fa8536dbae002ae0bb5790bc474d1f3c --- /dev/null +++ b/src/hydro/Gizmo/hydro_debug.h @@ -0,0 +1,29 @@ +/******************************************************************************* + * This file is part of SWIFT. + * Copyright (c) 2019 Bert Vandenbroucke (bert.vandenbroucke@gmail.com) + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published + * by the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this program. If not, see <http://www.gnu.org/licenses/>. + * + ******************************************************************************/ +#ifndef SWIFT_GIZMO_HYDRO_DEBUG_H +#define SWIFT_GIZMO_HYDRO_DEBUG_H + +/* Import the right definition */ +#if defined(GIZMO_MFV_SPH) +#include "MFV/hydro_debug.h" +#elif defined(GIZMO_MFM_SPH) +#include "MFM/hydro_debug.h" +#endif + +#endif /* SWIFT_GIZMO_HYDRO_DEBUG_H */ diff --git a/src/hydro/Gizmo/hydro_flux.h b/src/hydro/Gizmo/hydro_flux.h new file mode 100644 index 0000000000000000000000000000000000000000..0fba48fe6aafa6073d8af90ac57a4a6cc44508a7 --- /dev/null +++ b/src/hydro/Gizmo/hydro_flux.h @@ -0,0 +1,28 @@ +/******************************************************************************* + * This file is part of SWIFT. + * Coypright (c) 2019 Bert Vandenbroucke (bert.vandenbroucke@gmail.com) + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published + * by the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this program. If not, see <http://www.gnu.org/licenses/>. + * + ******************************************************************************/ +#ifndef SWIFT_GIZMO_HYDRO_FLUX_H +#define SWIFT_GIZMO_HYDRO_FLUX_H + +#if defined(GIZMO_MFV_SPH) +#include "MFV/hydro_flux.h" +#elif defined(GIZMO_MFM_SPH) +#include "MFM/hydro_flux.h" +#endif + +#endif /* SWIFT_GIZMO_HYDRO_FLUX_H */ diff --git a/src/hydro/Gizmo/hydro_getters.h b/src/hydro/Gizmo/hydro_getters.h new file mode 100644 index 0000000000000000000000000000000000000000..86aa79ab98ad13bb4d4d6e08bce255171c216daf --- /dev/null +++ b/src/hydro/Gizmo/hydro_getters.h @@ -0,0 +1,331 @@ +/******************************************************************************* + * This file is part of SWIFT. + * Coypright (c) 2019 Bert Vandenbroucke (bert.vandenbroucke@gmail.com) + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published + * by the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this program. If not, see <http://www.gnu.org/licenses/>. + * + ******************************************************************************/ +#ifndef SWIFT_GIZMO_HYDRO_GETTERS_H +#define SWIFT_GIZMO_HYDRO_GETTERS_H + +#include "cosmology.h" +#include "equation_of_state.h" + +/** + * @brief Get a 5-element state vector W containing the primitive hydrodynamic + * variables. + * + * @param p Particle. + * @param W Pointer to the array in which the result needs to be stored (of size + * 5 or more). + */ +__attribute__((always_inline)) INLINE static void +hydro_part_get_primitive_variables(const struct part* restrict p, float* W) { + + W[0] = p->rho; + W[1] = p->fluid_v[0]; + W[2] = p->fluid_v[1]; + W[3] = p->fluid_v[2]; + W[4] = p->P; +} + +/** + * @brief Get the gradients of the primitive variables for the given particle. + * + * @param p Particle. + * @param drho Density gradient (of size 3 or more). + * @param ddvx x velocity gradient (of size 3 or more). + * @param ddvy y velocity gradient (of size 3 or more). + * @param ddvz z velocity gradient (of size 3 or more). + * @param dP Pressure gradient (of size 3 or more). + */ +__attribute__((always_inline)) INLINE static void hydro_part_get_gradients( + const struct part* restrict p, float* drho, float* dvx, float* dvy, + float* dvz, float* dP) { + + drho[0] = p->gradients.rho[0]; + drho[1] = p->gradients.rho[1]; + drho[2] = p->gradients.rho[2]; + + dvx[0] = p->gradients.v[0][0]; + dvx[1] = p->gradients.v[0][1]; + dvx[2] = p->gradients.v[0][2]; + dvy[0] = p->gradients.v[1][0]; + dvy[1] = p->gradients.v[1][1]; + dvy[2] = p->gradients.v[1][2]; + dvz[0] = p->gradients.v[2][0]; + dvz[1] = p->gradients.v[2][1]; + dvz[2] = p->gradients.v[2][2]; + + dP[0] = p->gradients.P[0]; + dP[1] = p->gradients.P[1]; + dP[2] = p->gradients.P[2]; +} + +/** + * @brief Get the slope limiter variables for the given particle. + * + * @param p Particle. + * @param rholim Minimum and maximum density of neighbours (of size 2 or more). + * @param vxlim Minimum and maximum x velocity of neighbours (of size 2 or + * more). + * @param vylim Minimum and maximum y velocity of neighbours (of size 2 or + * more). + * @param vzlim Minimum and maximum z velocity of neighbours (of size 2 or + * more). + * @param Plim Minimum and maximum pressure of neighbours (of size 2 or more). + * @param rmax Maximum distance of any neighbour (of size 1 or more). + */ +__attribute__((always_inline)) INLINE static void hydro_part_get_slope_limiter( + const struct part* restrict p, float* rholim, float* vxlim, float* vylim, + float* vzlim, float* Plim, float* rmax) { + + rholim[0] = p->limiter.rho[0]; + rholim[1] = p->limiter.rho[1]; + + vxlim[0] = p->limiter.v[0][0]; + vxlim[1] = p->limiter.v[0][1]; + vylim[0] = p->limiter.v[1][0]; + vylim[1] = p->limiter.v[1][1]; + vzlim[0] = p->limiter.v[2][0]; + vzlim[1] = p->limiter.v[2][1]; + + Plim[0] = p->limiter.P[0]; + Plim[1] = p->limiter.P[1]; + + rmax[0] = p->limiter.maxr; +} + +/** + * @brief Returns the comoving internal energy of a particle + * + * @param p The particle of interest. + */ +__attribute__((always_inline)) INLINE static float +hydro_get_comoving_internal_energy(const struct part* restrict p) { + + if (p->rho > 0.0f) + return gas_internal_energy_from_pressure(p->rho, p->P); + else + return 0.; +} + +/** + * @brief Returns the physical internal energy of a particle + * + * @param p The particle of interest. + * @param xp The extended data of the particle of interest. + * @param cosmo The cosmological model. + */ +__attribute__((always_inline)) INLINE static float +hydro_get_physical_internal_energy(const struct part* restrict p, + const struct xpart* restrict xp, + const struct cosmology* cosmo) { + + return cosmo->a_factor_internal_energy * + 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, /*xp=*/NULL, cosmo); +} + +/** + * @brief Returns the comoving entropy of a particle + * + * @param p The particle of interest. + */ +__attribute__((always_inline)) INLINE static float hydro_get_comoving_entropy( + const struct part* restrict p) { + + if (p->rho > 0.0f) { + return gas_entropy_from_pressure(p->rho, p->P); + } else { + return 0.; + } +} + +/** + * @brief Returns the physical internal energy of a particle + * + * @param p The particle of interest. + * @param xp The extended data of the particle of interest. + * @param cosmo The cosmological model. + */ +__attribute__((always_inline)) INLINE static float hydro_get_physical_entropy( + const struct part* restrict p, const struct xpart* restrict xp, + const struct cosmology* cosmo) { + + /* Note: no cosmological conversion required here with our choice of + * coordinates. */ + 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 + * + * @param p The particle of interest. + */ +__attribute__((always_inline)) INLINE static float +hydro_get_comoving_soundspeed(const struct part* restrict p) { + + if (p->rho > 0.0f) + return gas_soundspeed_from_pressure(p->rho, p->P); + else + return 0.; +} + +/** + * @brief Returns the physical sound speed of a particle + * + * @param p The particle of interest. + * @param cosmo The cosmological model. + */ +__attribute__((always_inline)) INLINE static float +hydro_get_physical_soundspeed(const struct part* restrict p, + const struct cosmology* cosmo) { + + return cosmo->a_factor_sound_speed * hydro_get_comoving_soundspeed(p); +} + +/** + * @brief Returns the comoving pressure of a particle + * + * @param p The particle of interest + */ +__attribute__((always_inline)) INLINE static float hydro_get_comoving_pressure( + const struct part* restrict p) { + + return p->P; +} + +/** + * @brief Returns the comoving pressure of a particle + * + * @param p The particle of interest. + * @param cosmo The cosmological model. + */ +__attribute__((always_inline)) INLINE static float hydro_get_physical_pressure( + const struct part* restrict p, const struct cosmology* cosmo) { + + return cosmo->a_factor_pressure * p->P; +} + +/** + * @brief Returns the mass of a particle + * + * @param p The particle of interest + */ +__attribute__((always_inline)) INLINE static float hydro_get_mass( + const struct part* restrict p) { + + return p->conserved.mass; +} + +/** + * @brief Returns the velocities drifted to the current time of a particle. + * + * @param p The particle of interest + * @param xp The extended data of the particle. + * @param dt_kick_hydro The time (for hydro accelerations) since the last kick. + * @param dt_kick_grav The time (for gravity accelerations) since the last kick. + * @param v (return) The velocities at the current time. + */ +__attribute__((always_inline)) INLINE static void hydro_get_drifted_velocities( + const struct part* restrict p, const struct xpart* xp, float dt_kick_hydro, + float dt_kick_grav, float v[3]) { + + if (p->conserved.mass > 0.) { + const float m_inv = 1.0f / p->conserved.mass; + v[0] = p->fluid_v[0] + p->flux.momentum[0] * dt_kick_hydro * m_inv; + v[1] = p->fluid_v[1] + p->flux.momentum[1] * dt_kick_hydro * m_inv; + v[2] = p->fluid_v[2] + p->flux.momentum[2] * dt_kick_hydro * m_inv; + } else { + v[0] = p->fluid_v[0]; + v[1] = p->fluid_v[1]; + v[2] = p->fluid_v[2]; + } + + // MATTHIEU: Bert is this correct? + v[0] += xp->a_grav[0] * dt_kick_grav; + v[1] += xp->a_grav[1] * dt_kick_grav; + v[2] += xp->a_grav[2] * dt_kick_grav; +} + +/** + * @brief Returns the 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_comoving_internal_energy_dt(const struct part* restrict p) { + + error("Needs implementing"); + return 0.0f; +} + +/** + * @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) { + error("Needs implementing"); + return 0.0f; +} + +/** + * @brief Check if the gradient matrix for this particle is well behaved. + * + * @param p Particle. + * @return 1 if the gradient matrix is well behaved, 0 otherwise. + */ +__attribute__((always_inline)) INLINE static int +hydro_part_geometry_well_behaved(const struct part* restrict p) { + + return p->geometry.wcorr > const_gizmo_min_wcorr; +} + +#endif /* SWIFT_GIZMO_HYDRO_GETTERS_H */ diff --git a/src/hydro/GizmoMFM/hydro_gradients.h b/src/hydro/Gizmo/hydro_gradients.h similarity index 67% rename from src/hydro/GizmoMFM/hydro_gradients.h rename to src/hydro/Gizmo/hydro_gradients.h index 6f751d970287ca7ba137c1138ca6f3bf00e6c4cb..eb23e3609fb1aca36e8f50387fe12ab78470314e 100644 --- a/src/hydro/GizmoMFM/hydro_gradients.h +++ b/src/hydro/Gizmo/hydro_gradients.h @@ -1,6 +1,6 @@ /******************************************************************************* * This file is part of SWIFT. - * Copyright (c) 2016 Bert Vandenbroucke (bert.vandenbroucke@gmail.com) + * Coypright (c) 2019 Bert Vandenbroucke (bert.vandenbroucke@gmail.com) * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU Lesser General Public License as published @@ -16,13 +16,12 @@ * along with this program. If not, see <http://www.gnu.org/licenses/>. * ******************************************************************************/ +#ifndef SWIFT_GIZMO_HYDRO_GRADIENTS_H +#define SWIFT_GIZMO_HYDRO_GRADIENTS_H -#ifndef SWIFT_HYDRO_GIZMO_MFM_GRADIENTS_H -#define SWIFT_HYDRO_GIZMO_MFM_GRADIENTS_H - +#include "hydro_getters.h" #include "hydro_slope_limiters.h" #include "hydro_unphysical.h" -#include "riemann.h" #if defined(GRADIENTS_SPH) @@ -45,7 +44,7 @@ * @param p Particle. */ __attribute__((always_inline)) INLINE static void hydro_gradients_init( - struct part *p) {} + struct part* p) {} /** * @brief Gradient calculations done during the neighbour loop @@ -58,8 +57,8 @@ __attribute__((always_inline)) INLINE static void hydro_gradients_init( * @param pj Particle j. */ __attribute__((always_inline)) INLINE static void hydro_gradients_collect( - float r2, const float *dx, float hi, float hj, struct part *restrict pi, - struct part *restrict pj) {} + float r2, const float* dx, float hi, float hj, struct part* restrict pi, + struct part* restrict pj) {} /** * @brief Gradient calculations done during the neighbour loop: non-symmetric @@ -73,9 +72,9 @@ __attribute__((always_inline)) INLINE static void hydro_gradients_collect( * @param pj Particle j. */ __attribute__((always_inline)) INLINE static void -hydro_gradients_nonsym_collect(float r2, const float *dx, float hi, float hj, - struct part *restrict pi, - struct part *restrict pj) {} +hydro_gradients_nonsym_collect(float r2, const float* dx, float hi, float hj, + struct part* restrict pi, + struct part* restrict pj) {} /** * @brief Finalize the gradient variables after all data have been collected @@ -83,10 +82,24 @@ hydro_gradients_nonsym_collect(float r2, const float *dx, float hi, float hj, * @param p Particle. */ __attribute__((always_inline)) INLINE static void hydro_gradients_finalize( - struct part *p) {} + struct part* p) {} #endif +/** + * @brief Extrapolate the given gradient over the given distance. + * + * @param gradient Gradient of a quantity. + * @param dx Distance vector. + * @return Change in the quantity after a displacement along the given distance + * vector. + */ +__attribute__((always_inline)) INLINE static float hydro_gradients_extrapolate( + const float* gradient, const float* dx) { + + return gradient[0] * dx[0] + gradient[1] * dx[1] + gradient[2] * dx[2]; +} + /** * @brief Gradients reconstruction. Is the same for all gradient types (although * gradients_none does nothing, since all gradients are zero -- are they?). @@ -100,29 +113,24 @@ __attribute__((always_inline)) INLINE static void hydro_gradients_predict( * position) eqn. (8) */ const float xij_j[3] = {xij_i[0] + dx[0], xij_i[1] + dx[1], xij_i[2] + dx[2]}; + float drho_i[3], dvx_i[3], dvy_i[3], dvz_i[3], dP_i[3]; + float drho_j[3], dvx_j[3], dvy_j[3], dvz_j[3], dP_j[3]; + hydro_part_get_gradients(pi, drho_i, dvx_i, dvy_i, dvz_i, dP_i); + hydro_part_get_gradients(pj, drho_j, dvx_j, dvy_j, dvz_j, dP_j); + float dWi[5]; - dWi[0] = pi->gradients.rho[0] * xij_i[0] + pi->gradients.rho[1] * xij_i[1] + - pi->gradients.rho[2] * xij_i[2]; - dWi[1] = pi->gradients.v[0][0] * xij_i[0] + pi->gradients.v[0][1] * xij_i[1] + - pi->gradients.v[0][2] * xij_i[2]; - dWi[2] = pi->gradients.v[1][0] * xij_i[0] + pi->gradients.v[1][1] * xij_i[1] + - pi->gradients.v[1][2] * xij_i[2]; - dWi[3] = pi->gradients.v[2][0] * xij_i[0] + pi->gradients.v[2][1] * xij_i[1] + - pi->gradients.v[2][2] * xij_i[2]; - dWi[4] = pi->gradients.P[0] * xij_i[0] + pi->gradients.P[1] * xij_i[1] + - pi->gradients.P[2] * xij_i[2]; + dWi[0] = hydro_gradients_extrapolate(drho_i, xij_i); + dWi[1] = hydro_gradients_extrapolate(dvx_i, xij_i); + dWi[2] = hydro_gradients_extrapolate(dvy_i, xij_i); + dWi[3] = hydro_gradients_extrapolate(dvz_i, xij_i); + dWi[4] = hydro_gradients_extrapolate(dP_i, xij_i); float dWj[5]; - dWj[0] = pj->gradients.rho[0] * xij_j[0] + pj->gradients.rho[1] * xij_j[1] + - pj->gradients.rho[2] * xij_j[2]; - dWj[1] = pj->gradients.v[0][0] * xij_j[0] + pj->gradients.v[0][1] * xij_j[1] + - pj->gradients.v[0][2] * xij_j[2]; - dWj[2] = pj->gradients.v[1][0] * xij_j[0] + pj->gradients.v[1][1] * xij_j[1] + - pj->gradients.v[1][2] * xij_j[2]; - dWj[3] = pj->gradients.v[2][0] * xij_j[0] + pj->gradients.v[2][1] * xij_j[1] + - pj->gradients.v[2][2] * xij_j[2]; - dWj[4] = pj->gradients.P[0] * xij_j[0] + pj->gradients.P[1] * xij_j[1] + - pj->gradients.P[2] * xij_j[2]; + dWj[0] = hydro_gradients_extrapolate(drho_j, xij_j); + dWj[1] = hydro_gradients_extrapolate(dvx_j, xij_j); + dWj[2] = hydro_gradients_extrapolate(dvy_j, xij_j); + dWj[3] = hydro_gradients_extrapolate(dvz_j, xij_j); + dWj[4] = hydro_gradients_extrapolate(dP_j, xij_j); /* Apply the slope limiter at this interface */ hydro_slope_limit_face(Wi, Wj, dWi, dWj, xij_i, xij_j, r); @@ -145,4 +153,4 @@ __attribute__((always_inline)) INLINE static void hydro_gradients_predict( Wj[3], Wj[4]); } -#endif /* SWIFT_HYDRO_GIZMO_MFM_GRADIENTS_H */ +#endif /* SWIFT_GIZMO_HYDRO_GRADIENTS_H */ diff --git a/src/hydro/GizmoMFM/hydro_gradients_gizmo.h b/src/hydro/Gizmo/hydro_gradients_gizmo.h similarity index 62% rename from src/hydro/GizmoMFM/hydro_gradients_gizmo.h rename to src/hydro/Gizmo/hydro_gradients_gizmo.h index 90c8096a85b3418c8ee4c5382d6f087c14f8907e..c8914129bc58e32104ce400a59f1ac94b5a83b36 100644 --- a/src/hydro/GizmoMFM/hydro_gradients_gizmo.h +++ b/src/hydro/Gizmo/hydro_gradients_gizmo.h @@ -25,28 +25,13 @@ #ifndef SWIFT_GIZMO_MFM_HYDRO_GRADIENTS_H #define SWIFT_GIZMO_MFM_HYDRO_GRADIENTS_H +#include "hydro_getters.h" +#include "hydro_setters.h" + __attribute__((always_inline)) INLINE static void hydro_gradients_init( struct part *p) { - p->gradients.rho[0] = 0.0f; - p->gradients.rho[1] = 0.0f; - p->gradients.rho[2] = 0.0f; - - p->gradients.v[0][0] = 0.0f; - p->gradients.v[0][1] = 0.0f; - p->gradients.v[0][2] = 0.0f; - - p->gradients.v[1][0] = 0.0f; - p->gradients.v[1][1] = 0.0f; - p->gradients.v[1][2] = 0.0f; - - p->gradients.v[2][0] = 0.0f; - p->gradients.v[2][1] = 0.0f; - p->gradients.v[2][2] = 0.0f; - - p->gradients.P[0] = 0.0f; - p->gradients.P[1] = 0.0f; - p->gradients.P[2] = 0.0f; + hydro_part_reset_gradients(p); hydro_slope_limit_cell_init(p); } @@ -80,16 +65,8 @@ __attribute__((always_inline)) INLINE static void hydro_gradients_collect( Bj[k][l] = pj->geometry.matrix_E[k][l]; } } - Wi[0] = pi->rho; - Wi[1] = pi->v[0]; - Wi[2] = pi->v[1]; - Wi[3] = pi->v[2]; - Wi[4] = pi->P; - Wj[0] = pj->rho; - Wj[1] = pj->v[0]; - Wj[2] = pj->v[1]; - Wj[3] = pj->v[2]; - Wj[4] = pj->P; + hydro_part_get_primitive_variables(pi, Wi); + hydro_part_get_primitive_variables(pj, Wj); /* Compute kernel of pi. */ const float hi_inv = 1.0f / hi; @@ -100,7 +77,7 @@ __attribute__((always_inline)) INLINE static void hydro_gradients_collect( Wi[3] - Wj[3], Wi[4] - Wj[4]}; float wiBidx[3]; - if (pi->geometry.wcorr > const_gizmo_min_wcorr) { + if (hydro_part_geometry_well_behaved(pi)) { wiBidx[0] = wi * (Bi[0][0] * dx[0] + Bi[0][1] * dx[1] + Bi[0][2] * dx[2]); wiBidx[1] = wi * (Bi[1][0] * dx[0] + Bi[1][1] * dx[1] + Bi[1][2] * dx[2]); wiBidx[2] = wi * (Bi[2][0] * dx[0] + Bi[2][1] * dx[1] + Bi[2][2] * dx[2]); @@ -114,23 +91,28 @@ __attribute__((always_inline)) INLINE static void hydro_gradients_collect( /* Compute gradients for pi */ /* there is a sign difference w.r.t. eqn. (6) because of the inverse * definition of dx */ - pi->gradients.rho[0] += dW[0] * wiBidx[0]; - pi->gradients.rho[1] += dW[0] * wiBidx[1]; - pi->gradients.rho[2] += dW[0] * wiBidx[2]; - - pi->gradients.v[0][0] += dW[1] * wiBidx[0]; - pi->gradients.v[0][1] += dW[1] * wiBidx[1]; - pi->gradients.v[0][2] += dW[1] * wiBidx[2]; - pi->gradients.v[1][0] += dW[2] * wiBidx[0]; - pi->gradients.v[1][1] += dW[2] * wiBidx[1]; - pi->gradients.v[1][2] += dW[2] * wiBidx[2]; - pi->gradients.v[2][0] += dW[3] * wiBidx[0]; - pi->gradients.v[2][1] += dW[3] * wiBidx[1]; - pi->gradients.v[2][2] += dW[3] * wiBidx[2]; - - pi->gradients.P[0] += dW[4] * wiBidx[0]; - pi->gradients.P[1] += dW[4] * wiBidx[1]; - pi->gradients.P[2] += dW[4] * wiBidx[2]; + + float drho_i[3], dvx_i[3], dvy_i[3], dvz_i[3], dP_i[3]; + + drho_i[0] = dW[0] * wiBidx[0]; + drho_i[1] = dW[0] * wiBidx[1]; + drho_i[2] = dW[0] * wiBidx[2]; + + dvx_i[0] = dW[1] * wiBidx[0]; + dvx_i[1] = dW[1] * wiBidx[1]; + dvx_i[2] = dW[1] * wiBidx[2]; + dvy_i[0] = dW[2] * wiBidx[0]; + dvy_i[1] = dW[2] * wiBidx[1]; + dvy_i[2] = dW[2] * wiBidx[2]; + dvz_i[0] = dW[3] * wiBidx[0]; + dvz_i[1] = dW[3] * wiBidx[1]; + dvz_i[2] = dW[3] * wiBidx[2]; + + dP_i[0] = dW[4] * wiBidx[0]; + dP_i[1] = dW[4] * wiBidx[1]; + dP_i[2] = dW[4] * wiBidx[2]; + + hydro_part_update_gradients(pi, drho_i, dvx_i, dvy_i, dvz_i, dP_i); hydro_slope_limit_cell_collect(pi, pj, r); @@ -140,7 +122,7 @@ __attribute__((always_inline)) INLINE static void hydro_gradients_collect( kernel_deval(xj, &wj, &wj_dx); float wjBjdx[3]; - if (pj->geometry.wcorr > const_gizmo_min_wcorr) { + if (hydro_part_geometry_well_behaved(pj)) { wjBjdx[0] = wj * (Bj[0][0] * dx[0] + Bj[0][1] * dx[1] + Bj[0][2] * dx[2]); wjBjdx[1] = wj * (Bj[1][0] * dx[0] + Bj[1][1] * dx[1] + Bj[1][2] * dx[2]); @@ -153,26 +135,30 @@ __attribute__((always_inline)) INLINE static void hydro_gradients_collect( wjBjdx[2] = norm * dx[2]; } + float drho_j[3], dvx_j[3], dvy_j[3], dvz_j[3], dP_j[3]; + /* Compute gradients for pj */ /* there is no sign difference w.r.t. eqn. (6) because dx is now what we * want it to be */ - pj->gradients.rho[0] += dW[0] * wjBjdx[0]; - pj->gradients.rho[1] += dW[0] * wjBjdx[1]; - pj->gradients.rho[2] += dW[0] * wjBjdx[2]; - - pj->gradients.v[0][0] += dW[1] * wjBjdx[0]; - pj->gradients.v[0][1] += dW[1] * wjBjdx[1]; - pj->gradients.v[0][2] += dW[1] * wjBjdx[2]; - pj->gradients.v[1][0] += dW[2] * wjBjdx[0]; - pj->gradients.v[1][1] += dW[2] * wjBjdx[1]; - pj->gradients.v[1][2] += dW[2] * wjBjdx[2]; - pj->gradients.v[2][0] += dW[3] * wjBjdx[0]; - pj->gradients.v[2][1] += dW[3] * wjBjdx[1]; - pj->gradients.v[2][2] += dW[3] * wjBjdx[2]; - - pj->gradients.P[0] += dW[4] * wjBjdx[0]; - pj->gradients.P[1] += dW[4] * wjBjdx[1]; - pj->gradients.P[2] += dW[4] * wjBjdx[2]; + drho_j[0] = dW[0] * wjBjdx[0]; + drho_j[1] = dW[0] * wjBjdx[1]; + drho_j[2] = dW[0] * wjBjdx[2]; + + dvx_j[0] = dW[1] * wjBjdx[0]; + dvx_j[1] = dW[1] * wjBjdx[1]; + dvx_j[2] = dW[1] * wjBjdx[2]; + dvy_j[0] = dW[2] * wjBjdx[0]; + dvy_j[1] = dW[2] * wjBjdx[1]; + dvy_j[2] = dW[2] * wjBjdx[2]; + dvz_j[0] = dW[3] * wjBjdx[0]; + dvz_j[1] = dW[3] * wjBjdx[1]; + dvz_j[2] = dW[3] * wjBjdx[2]; + + dP_j[0] = dW[4] * wjBjdx[0]; + dP_j[1] = dW[4] * wjBjdx[1]; + dP_j[2] = dW[4] * wjBjdx[2]; + + hydro_part_update_gradients(pj, drho_j, dvx_j, dvy_j, dvz_j, dP_j); hydro_slope_limit_cell_collect(pj, pi, r); } @@ -204,16 +190,8 @@ hydro_gradients_nonsym_collect(float r2, const float *dx, float hi, float hj, Bi[k][l] = pi->geometry.matrix_E[k][l]; } } - Wi[0] = pi->rho; - Wi[1] = pi->v[0]; - Wi[2] = pi->v[1]; - Wi[3] = pi->v[2]; - Wi[4] = pi->P; - Wj[0] = pj->rho; - Wj[1] = pj->v[0]; - Wj[2] = pj->v[1]; - Wj[3] = pj->v[2]; - Wj[4] = pj->P; + hydro_part_get_primitive_variables(pi, Wi); + hydro_part_get_primitive_variables(pj, Wj); /* Compute kernel of pi. */ float wi, wi_dx; @@ -225,7 +203,7 @@ hydro_gradients_nonsym_collect(float r2, const float *dx, float hi, float hj, Wi[3] - Wj[3], Wi[4] - Wj[4]}; float wiBidx[3]; - if (pi->geometry.wcorr > const_gizmo_min_wcorr) { + if (hydro_part_geometry_well_behaved(pi)) { wiBidx[0] = wi * (Bi[0][0] * dx[0] + Bi[0][1] * dx[1] + Bi[0][2] * dx[2]); wiBidx[1] = wi * (Bi[1][0] * dx[0] + Bi[1][1] * dx[1] + Bi[1][2] * dx[2]); wiBidx[2] = wi * (Bi[2][0] * dx[0] + Bi[2][1] * dx[1] + Bi[2][2] * dx[2]); @@ -236,26 +214,30 @@ hydro_gradients_nonsym_collect(float r2, const float *dx, float hi, float hj, wiBidx[2] = norm * dx[2]; } + float drho_i[3], dvx_i[3], dvy_i[3], dvz_i[3], dP_i[3]; + /* Compute gradients for pi */ /* there is a sign difference w.r.t. eqn. (6) because of the inverse * definition of dx */ - pi->gradients.rho[0] += dW[0] * wiBidx[0]; - pi->gradients.rho[1] += dW[0] * wiBidx[1]; - pi->gradients.rho[2] += dW[0] * wiBidx[2]; - - pi->gradients.v[0][0] += dW[1] * wiBidx[0]; - pi->gradients.v[0][1] += dW[1] * wiBidx[1]; - pi->gradients.v[0][2] += dW[1] * wiBidx[2]; - pi->gradients.v[1][0] += dW[2] * wiBidx[0]; - pi->gradients.v[1][1] += dW[2] * wiBidx[1]; - pi->gradients.v[1][2] += dW[2] * wiBidx[2]; - pi->gradients.v[2][0] += dW[3] * wiBidx[0]; - pi->gradients.v[2][1] += dW[3] * wiBidx[1]; - pi->gradients.v[2][2] += dW[3] * wiBidx[2]; - - pi->gradients.P[0] += dW[4] * wiBidx[0]; - pi->gradients.P[1] += dW[4] * wiBidx[1]; - pi->gradients.P[2] += dW[4] * wiBidx[2]; + drho_i[0] = dW[0] * wiBidx[0]; + drho_i[1] = dW[0] * wiBidx[1]; + drho_i[2] = dW[0] * wiBidx[2]; + + dvx_i[0] = dW[1] * wiBidx[0]; + dvx_i[1] = dW[1] * wiBidx[1]; + dvx_i[2] = dW[1] * wiBidx[2]; + dvy_i[0] = dW[2] * wiBidx[0]; + dvy_i[1] = dW[2] * wiBidx[1]; + dvy_i[2] = dW[2] * wiBidx[2]; + dvz_i[0] = dW[3] * wiBidx[0]; + dvz_i[1] = dW[3] * wiBidx[1]; + dvz_i[2] = dW[3] * wiBidx[2]; + + dP_i[0] = dW[4] * wiBidx[0]; + dP_i[1] = dW[4] * wiBidx[1]; + dP_i[2] = dW[4] * wiBidx[2]; + + hydro_part_update_gradients(pi, drho_i, dvx_i, dvy_i, dvz_i, dP_i); hydro_slope_limit_cell_collect(pi, pj, r); } @@ -275,30 +257,14 @@ __attribute__((always_inline)) INLINE static void hydro_gradients_finalize( const float ihdim = pow_dimension(h_inv); float norm; - if (p->geometry.wcorr > const_gizmo_min_wcorr) { + if (hydro_part_geometry_well_behaved(p)) { norm = ihdim; } else { const float ihdimp1 = pow_dimension_plus_one(h_inv); norm = ihdimp1 * volume; } - p->gradients.rho[0] *= norm; - p->gradients.rho[1] *= norm; - p->gradients.rho[2] *= norm; - - p->gradients.v[0][0] *= norm; - p->gradients.v[0][1] *= norm; - p->gradients.v[0][2] *= norm; - p->gradients.v[1][0] *= norm; - p->gradients.v[1][1] *= norm; - p->gradients.v[1][2] *= norm; - p->gradients.v[2][0] *= norm; - p->gradients.v[2][1] *= norm; - p->gradients.v[2][2] *= norm; - - p->gradients.P[0] *= norm; - p->gradients.P[1] *= norm; - p->gradients.P[2] *= norm; + hydro_part_normalise_gradients(p, norm); hydro_slope_limit_cell(p); } diff --git a/src/hydro/GizmoMFM/hydro_gradients_sph.h b/src/hydro/Gizmo/hydro_gradients_sph.h similarity index 52% rename from src/hydro/GizmoMFM/hydro_gradients_sph.h rename to src/hydro/Gizmo/hydro_gradients_sph.h index 58233c3b75b22c4ba6347bb6e5db5e4e0e2ebe71..9ece14c32d3c1ca7cd91a668c3142bac5f9b6010 100644 --- a/src/hydro/GizmoMFM/hydro_gradients_sph.h +++ b/src/hydro/Gizmo/hydro_gradients_sph.h @@ -22,30 +22,16 @@ * * @param p Particle. */ -#ifndef SWIFT_GIZMO_MFM_HYDRO_SPH_GRADIENTS_H -#define SWIFT_GIZMO_MFM_HYDRO_SPH_GRADIENTS_H +#ifndef SWIFT_GIZMO_HYDRO_SPH_GRADIENTS_H +#define SWIFT_GIZMO_HYDRO_SPH_GRADIENTS_H + +#include "hydro_getters.h" +#include "hydro_setters.h" __attribute__((always_inline)) INLINE static void hydro_gradients_init( struct part *p) { - p->gradients.rho[0] = 0.0f; - p->gradients.rho[1] = 0.0f; - p->gradients.rho[2] = 0.0f; - - p->gradients.v[0][0] = 0.0f; - p->gradients.v[0][1] = 0.0f; - p->gradients.v[0][2] = 0.0f; - - p->gradients.v[1][0] = 0.0f; - p->gradients.v[1][1] = 0.0f; - p->gradients.v[1][2] = 0.0f; - p->gradients.v[2][0] = 0.0f; - p->gradients.v[2][1] = 0.0f; - p->gradients.v[2][2] = 0.0f; - - p->gradients.P[0] = 0.0f; - p->gradients.P[1] = 0.0f; - p->gradients.P[2] = 0.0f; + hydro_part_reset_gradients(p); hydro_slope_limit_cell_init(p); } @@ -72,29 +58,37 @@ __attribute__((always_inline)) INLINE static void hydro_gradients_collect( const float xi = r * hi_inv; kernel_deval(xi, &wi, &wi_dx); - const float dW[5] = {pi->rho - pj->rho, pi->v[0] - pj->v[0], - pi->v[1] - pj->v[1], pi->v[2] - pj->v[2], pi->P - pj->P}; + float Wi[5], Wj[5]; + hydro_part_get_primitive_variables(pi, Wi); + hydro_part_get_primitive_variables(pj, Wj); + + const float dW[5] = {Wi[0] - Wj[0], Wi[1] - Wj[1], Wi[2] - Wj[2], + Wi[3] - Wj[3], Wi[4] - Wj[4]}; const float normi = wi_dx * r_inv; const float nidx[3] = {normi * dx[0], normi * dx[1], normi * dx[2]}; - pi->gradients.rho[0] -= dW[0] * nidx[0]; - pi->gradients.rho[1] -= dW[0] * nidx[1]; - pi->gradients.rho[2] -= dW[0] * nidx[2]; + float drho_i[3], dvx_i[3], dvy_i[3], dvz_i[3], dP_i[3]; + + drho_i[0] = -dW[0] * nidx[0]; + drho_i[1] = -dW[0] * nidx[1]; + drho_i[2] = -dW[0] * nidx[2]; - pi->gradients.v[0][0] -= dW[1] * nidx[0]; - pi->gradients.v[0][1] -= dW[1] * nidx[1]; - pi->gradients.v[0][2] -= dW[1] * nidx[2]; - pi->gradients.v[1][0] -= dW[2] * nidx[0]; - pi->gradients.v[1][1] -= dW[2] * nidx[1]; - pi->gradients.v[1][2] -= dW[2] * nidx[2]; - pi->gradients.v[2][0] -= dW[3] * nidx[0]; - pi->gradients.v[2][1] -= dW[3] * nidx[1]; - pi->gradients.v[2][2] -= dW[3] * nidx[2]; + dvx_i[0] = -dW[1] * nidx[0]; + dvx_i[1] = -dW[1] * nidx[1]; + dvx_i[2] = -dW[1] * nidx[2]; + dvy_i[0] = -dW[2] * nidx[0]; + dvy_i[1] = -dW[2] * nidx[1]; + dvy_i[2] = -dW[2] * nidx[2]; + dvz_i[0] = -dW[3] * nidx[0]; + dvz_i[1] = -dW[3] * nidx[1]; + dvz_i[2] = -dW[3] * nidx[2]; - pi->gradients.P[0] -= dW[4] * nidx[0]; - pi->gradients.P[1] -= dW[4] * nidx[1]; - pi->gradients.P[2] -= dW[4] * nidx[2]; + dP_i[0] = -dW[4] * nidx[0]; + dP_i[1] = -dW[4] * nidx[1]; + dP_i[2] = -dW[4] * nidx[2]; + + hydro_part_update_gradients(pi, drho_i, dvx_i, dvy_i, dvz_i, dP_i); hydro_slope_limit_cell_collect(pi, pj, r); @@ -106,24 +100,28 @@ __attribute__((always_inline)) INLINE static void hydro_gradients_collect( const float normj = wj_dx * r_inv; const float njdx[3] = {normj * dx[0], normj * dx[1], normj * dx[2]}; + float drho_j[3], dvx_j[3], dvy_j[3], dvz_j[3], dP_j[3]; + /* signs are the same as before, since we swap i and j twice */ - pj->gradients.rho[0] -= dW[0] * njdx[0]; - pj->gradients.rho[1] -= dW[0] * njdx[1]; - pj->gradients.rho[2] -= dW[0] * njdx[2]; - - pj->gradients.v[0][0] -= dW[1] * njdx[0]; - pj->gradients.v[0][1] -= dW[1] * njdx[1]; - pj->gradients.v[0][2] -= dW[1] * njdx[2]; - pj->gradients.v[1][0] -= dW[2] * njdx[0]; - pj->gradients.v[1][1] -= dW[2] * njdx[1]; - pj->gradients.v[1][2] -= dW[2] * njdx[2]; - pj->gradients.v[2][0] -= dW[3] * njdx[0]; - pj->gradients.v[2][1] -= dW[3] * njdx[1]; - pj->gradients.v[2][2] -= dW[3] * njdx[2]; - - pj->gradients.P[0] -= dW[4] * njdx[0]; - pj->gradients.P[1] -= dW[4] * njdx[1]; - pj->gradients.P[2] -= dW[4] * njdx[2]; + drho_j[0] = -dW[0] * njdx[0]; + drho_j[1] = -dW[0] * njdx[1]; + drho_j[2] = -dW[0] * njdx[2]; + + dvx_j[0] = -dW[1] * njdx[0]; + dvx_j[1] = -dW[1] * njdx[1]; + dvx_j[2] = -dW[1] * njdx[2]; + dvy_j[0] = -dW[2] * njdx[0]; + dvy_j[1] = -dW[2] * njdx[1]; + dvy_j[2] = -dW[2] * njdx[2]; + dvz_j[0] = -dW[3] * njdx[0]; + dvz_j[1] = -dW[3] * njdx[1]; + dvz_j[2] = -dW[3] * njdx[2]; + + dP_j[0] = -dW[4] * njdx[0]; + dP_j[1] = -dW[4] * njdx[1]; + dP_j[2] = -dW[4] * njdx[2]; + + hydro_part_update_gradients(pj, drho_j, dvx_j, dvy_j, dvz_j, dP_j); hydro_slope_limit_cell_collect(pj, pi, r); } @@ -152,29 +150,37 @@ hydro_gradients_nonsym_collect(float r2, const float *dx, float hi, float hj, const float xi = r * hi_inv; kernel_deval(xi, &wi, &wi_dx); - const float dW[5] = {pi->rho - pj->rho, pi->v[0] - pj->v[0], - pi->v[1] - pj->v[1], pi->v[2] - pj->v[2], pi->P - pj->P}; + float Wi[5], Wj[5]; + hydro_part_get_primitive_variables(pi, Wi); + hydro_part_get_primitive_variables(pj, Wj); + + const float dW[5] = {Wi[0] - Wj[0], Wi[1] - Wj[1], Wi[2] - Wj[2], + Wi[3] - Wj[3], Wi[4] - Wj[4]}; const float normi = wi_dx * r_inv; const float nidx[3] = {normi * dx[0], normi * dx[1], normi * dx[2]}; - pi->gradients.rho[0] -= dW[0] * nidx[0]; - pi->gradients.rho[1] -= dW[0] * nidx[1]; - pi->gradients.rho[2] -= dW[0] * nidx[2]; + float drho_i[3], dvx_i[3], dvy_i[3], dvz_i[3], dP_i[3]; + + drho_i[0] = -dW[0] * nidx[0]; + drho_i[1] = -dW[0] * nidx[1]; + drho_i[2] = -dW[0] * nidx[2]; - pi->gradients.v[0][0] -= dW[1] * nidx[0]; - pi->gradients.v[0][1] -= dW[1] * nidx[1]; - pi->gradients.v[0][2] -= dW[1] * nidx[2]; - pi->gradients.v[1][0] -= dW[2] * nidx[0]; - pi->gradients.v[1][1] -= dW[2] * nidx[1]; - pi->gradients.v[1][2] -= dW[2] * nidx[2]; - pi->gradients.v[2][0] -= dW[3] * nidx[0]; - pi->gradients.v[2][1] -= dW[3] * nidx[1]; - pi->gradients.v[2][2] -= dW[3] * nidx[2]; + dvx_i[0] = -dW[1] * nidx[0]; + dvx_i[1] = -dW[1] * nidx[1]; + dvx_i[2] = -dW[1] * nidx[2]; + dvy_i[0] = -dW[2] * nidx[0]; + dvy_i[1] = -dW[2] * nidx[1]; + dvy_i[2] = -dW[2] * nidx[2]; + dvz_i[0] = -dW[3] * nidx[0]; + dvz_i[1] = -dW[3] * nidx[1]; + dvz_i[2] = -dW[3] * nidx[2]; - pi->gradients.P[0] -= dW[4] * nidx[0]; - pi->gradients.P[1] -= dW[4] * nidx[1]; - pi->gradients.P[2] -= dW[4] * nidx[2]; + dP_i[0] = -dW[4] * nidx[0]; + dP_i[1] = -dW[4] * nidx[1]; + dP_i[2] = -dW[4] * nidx[2]; + + hydro_part_update_gradients(pi, drho_i, dvx_i, dvy_i, dvz_i, dP_i); hydro_slope_limit_cell_collect(pi, pj, r); } @@ -192,30 +198,10 @@ __attribute__((always_inline)) INLINE static void hydro_gradients_finalize( const float ihdimp1 = pow_dimension_plus_one(ih); const float volume = p->geometry.volume; - const float norm = ihdimp1 * volume; - /* finalize gradients by multiplying with volume */ - p->gradients.rho[0] *= norm; - p->gradients.rho[1] *= norm; - p->gradients.rho[2] *= norm; - - p->gradients.v[0][0] *= norm; - p->gradients.v[0][1] *= norm; - p->gradients.v[0][2] *= norm; - - p->gradients.v[1][0] *= norm; - p->gradients.v[1][1] *= norm; - p->gradients.v[1][2] *= norm; - - p->gradients.v[2][0] *= norm; - p->gradients.v[2][1] *= norm; - p->gradients.v[2][2] *= norm; - - p->gradients.P[0] *= norm; - p->gradients.P[1] *= norm; - p->gradients.P[2] *= norm; + hydro_part_normalise_gradients(p, ihdimp1 * volume); hydro_slope_limit_cell(p); } -#endif /* SWIFT_GIZMO_MFM_HYDRO_SPH_GRADIENTS_H */ +#endif /* SWIFT_GIZMO_HYDRO_SPH_GRADIENTS_H */ diff --git a/src/hydro/GizmoMFM/hydro_iact.h b/src/hydro/Gizmo/hydro_iact.h similarity index 82% rename from src/hydro/GizmoMFM/hydro_iact.h rename to src/hydro/Gizmo/hydro_iact.h index 08e3de538a5e2cd775a69abab9bcb11fb09e7a9b..4a36fb2f9710212de647717c4177dd99146deac5 100644 --- a/src/hydro/GizmoMFM/hydro_iact.h +++ b/src/hydro/Gizmo/hydro_iact.h @@ -1,8 +1,6 @@ /******************************************************************************* * This file is part of SWIFT. - * Coypright (c) 2012 Pedro Gonnet (pedro.gonnet@durham.ac.uk) - * Matthieu Schaller (matthieu.schaller@durham.ac.uk) - * Bert Vandenbroucke (bert.vandenbroucke@ugent.be) + * Coypright (c) 2019 Bert Vandenbroucke (bert.vandenbroucke@gmail.com) * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU Lesser General Public License as published @@ -18,14 +16,13 @@ * along with this program. If not, see <http://www.gnu.org/licenses/>. * ******************************************************************************/ -#ifndef SWIFT_GIZMO_MFM_HYDRO_IACT_H -#define SWIFT_GIZMO_MFM_HYDRO_IACT_H +#ifndef SWIFT_GIZMO_HYDRO_IACT_H +#define SWIFT_GIZMO_HYDRO_IACT_H -#include "adiabatic_index.h" +#include "hydro_flux.h" +#include "hydro_getters.h" #include "hydro_gradients.h" -#include "riemann.h" - -#include "./hydro_parameters.h" +#include "hydro_setters.h" #define GIZMO_VOLUME_CORRECTION @@ -72,9 +69,7 @@ __attribute__((always_inline)) INLINE static void runner_iact_density( for (int l = 0; l < 3; l++) pi->geometry.matrix_E[k][l] += dx[k] * dx[l] * wi; - pi->geometry.centroid[0] -= dx[0] * wi; - pi->geometry.centroid[1] -= dx[1] * wi; - pi->geometry.centroid[2] -= dx[2] * wi; + hydro_velocities_update_centroid_left(pi, dx, wi); /* Compute density of pj. */ const float hj_inv = 1.0f / hj; @@ -90,9 +85,7 @@ __attribute__((always_inline)) INLINE static void runner_iact_density( for (int l = 0; l < 3; l++) pj->geometry.matrix_E[k][l] += dx[k] * dx[l] * wj; - pj->geometry.centroid[0] += dx[0] * wj; - pj->geometry.centroid[1] += dx[1] * wj; - pj->geometry.centroid[2] += dx[2] * wj; + hydro_velocities_update_centroid_right(pi, dx, wi); } /** @@ -138,9 +131,7 @@ __attribute__((always_inline)) INLINE static void runner_iact_nonsym_density( for (int l = 0; l < 3; l++) pi->geometry.matrix_E[k][l] += dx[k] * dx[l] * wi; - pi->geometry.centroid[0] -= dx[0] * wi; - pi->geometry.centroid[1] -= dx[1] * wi; - pi->geometry.centroid[2] -= dx[2] * wi; + hydro_velocities_update_centroid_left(pi, dx, wi); } /** @@ -240,16 +231,8 @@ __attribute__((always_inline)) INLINE static void runner_iact_fluxes_common( const float Vi = pi->geometry.volume; const float Vj = pj->geometry.volume; float Wi[5], Wj[5]; - Wi[0] = pi->rho; - Wi[1] = pi->v[0]; - Wi[2] = pi->v[1]; - Wi[3] = pi->v[2]; - Wi[4] = pi->P; - Wj[0] = pj->rho; - Wj[1] = pj->v[0]; - Wj[2] = pj->v[1]; - Wj[3] = pj->v[2]; - Wj[4] = pj->P; + hydro_part_get_primitive_variables(pi, Wi); + hydro_part_get_primitive_variables(pj, Wj); /* calculate the maximal signal velocity */ float vmax; @@ -257,23 +240,31 @@ __attribute__((always_inline)) INLINE static void runner_iact_fluxes_common( const float ci = gas_soundspeed_from_pressure(Wi[0], Wi[4]); const float cj = gas_soundspeed_from_pressure(Wj[0], Wj[4]); vmax = ci + cj; - } else + } else { vmax = 0.0f; + } + + float dvdr = (pi->v[0] - pj->v[0]) * dx[0] + (pi->v[1] - pj->v[1]) * dx[1] + + (pi->v[2] - pj->v[2]) * dx[2]; /* Velocity on the axis linking the particles */ - float dvdr = (Wi[1] - Wj[1]) * dx[0] + (Wi[2] - Wj[2]) * dx[1] + - (Wi[3] - Wj[3]) * dx[2]; + /* This velocity will be the same as dvdr for MFM, so hopefully this gets + optimised out. */ + float dvdotdx = (Wi[1] - Wj[1]) * dx[0] + (Wi[2] - Wj[2]) * dx[1] + + (Wi[3] - Wj[3]) * dx[2]; - /* We only care about this velocity for particles moving towards each other + /* We only care about this velocity for particles moving towards each others */ - const float dvdotdx = min(dvdr, 0.0f); + dvdotdx = min3(dvdr, dvdotdx, 0.f); /* Get the signal velocity */ vmax -= const_viscosity_beta * dvdotdx * r_inv; /* Store the signal velocity */ pi->timestepvars.vmax = max(pi->timestepvars.vmax, vmax); - if (mode == 1) pj->timestepvars.vmax = max(pj->timestepvars.vmax, vmax); + if (mode == 1) { + pj->timestepvars.vmax = max(pj->timestepvars.vmax, vmax); + } /* Compute kernel of pi. */ float wi, wi_dx; @@ -295,17 +286,19 @@ __attribute__((always_inline)) INLINE static void runner_iact_fluxes_common( const float wi_dr = hidp1 * wi_dx; const float wj_dr = hjdp1 * wj_dx; dvdr *= r_inv; - if (pj->rho > 0.0f) - pi->force.h_dt -= pj->conserved.mass * dvdr / pj->rho * wi_dr; - if (mode == 1 && pi->rho > 0.0f) - pj->force.h_dt -= pi->conserved.mass * dvdr / pi->rho * wj_dr; + if (Wj[0] > 0.0f) { + pi->force.h_dt -= pj->conserved.mass * dvdr / Wj[0] * wi_dr; + } + if (mode == 1 && Wi[0] > 0.0f) { + pj->force.h_dt -= pi->conserved.mass * dvdr / Wi[0] * wj_dr; + } /* Compute (square of) area */ /* eqn. (7) */ float Anorm2 = 0.0f; float A[3]; - if (pi->geometry.wcorr > const_gizmo_min_wcorr && - pj->geometry.wcorr > const_gizmo_min_wcorr) { + if (hydro_part_geometry_well_behaved(pi) && + hydro_part_geometry_well_behaved(pj)) { /* in principle, we use Vi and Vj as weights for the left and right contributions to the generalized surface vector. However, if Vi and Vj are very different (because they have very @@ -339,7 +332,9 @@ __attribute__((always_inline)) INLINE static void runner_iact_fluxes_common( /* if the interface has no area, nothing happens and we return */ /* continuing results in dividing by zero and NaN's... */ - if (Anorm2 == 0.0f) return; + if (Anorm2 == 0.0f) { + return; + } /* Compute the area */ const float Anorm_inv = 1.0f / sqrtf(Anorm2); @@ -401,28 +396,9 @@ __attribute__((always_inline)) INLINE static void runner_iact_fluxes_common( * itself (see GIZMO) */ float totflux[5]; - riemann_solve_for_middle_state_flux(Wi, Wj, n_unit, vij, totflux); - - /* Multiply with the interface surface area */ - totflux[1] *= Anorm; - totflux[2] *= Anorm; - totflux[3] *= Anorm; - totflux[4] *= Anorm; - - /* Update conserved variables */ - /* We shamelessly exploit the fact that the mass flux is zero and omit all - terms involving it */ - /* eqn. (16) */ - pi->flux.momentum[0] -= totflux[1]; - pi->flux.momentum[1] -= totflux[2]; - pi->flux.momentum[2] -= totflux[3]; - pi->flux.energy -= totflux[4]; - -#ifndef GIZMO_TOTAL_ENERGY - pi->flux.energy += totflux[1] * pi->v[0]; - pi->flux.energy += totflux[2] * pi->v[1]; - pi->flux.energy += totflux[3] * pi->v[2]; -#endif + hydro_compute_flux(Wi, Wj, n_unit, vij, Anorm, totflux); + + hydro_part_update_fluxes_left(pi, totflux, dx); /* Note that this used to be much more complicated in early implementations of * the GIZMO scheme, as we wanted manifest conservation of conserved variables @@ -430,16 +406,7 @@ __attribute__((always_inline)) INLINE static void runner_iact_fluxes_common( * conservation anymore and just assume the current fluxes are representative * for the flux over the entire time step. */ if (mode == 1) { - pj->flux.momentum[0] += totflux[1]; - pj->flux.momentum[1] += totflux[2]; - pj->flux.momentum[2] += totflux[3]; - pj->flux.energy += totflux[4]; - -#ifndef GIZMO_TOTAL_ENERGY - pj->flux.energy -= totflux[1] * pj->v[0]; - pj->flux.energy -= totflux[2] * pj->v[1]; - pj->flux.energy -= totflux[3] * pj->v[2]; -#endif + hydro_part_update_fluxes_right(pj, totflux, dx); } } @@ -488,29 +455,4 @@ __attribute__((always_inline)) INLINE static void runner_iact_nonsym_force( runner_iact_fluxes_common(r2, dx, hi, hj, pi, pj, 0, a, H); } -/** - * @brief Timestep limiter loop - */ -__attribute__((always_inline)) INLINE static void runner_iact_limiter( - float r2, const float *dx, float hi, float hj, struct part *restrict pi, - struct part *restrict pj, float a, float H) { - - /* Nothing to do here if both particles are active */ -} - -/** - * @brief Timestep limiter loop (non-symmetric version) - */ -__attribute__((always_inline)) INLINE static void runner_iact_nonsym_limiter( - float r2, const float *dx, float hi, float hj, struct part *restrict pi, - struct part *restrict pj, float a, float H) { - - /* Wake up the neighbour? */ - if (pi->timestepvars.vmax > - const_limiter_max_v_sig_ratio * pj->timestepvars.vmax) { - - pj->wakeup = time_bin_awake; - } -} - -#endif /* SWIFT_GIZMO_MFM_HYDRO_IACT_H */ +#endif /* SWIFT_GIZMO_HYDRO_IACT_H */ diff --git a/src/hydro/GizmoMFM/hydro_io.h b/src/hydro/Gizmo/hydro_io.h similarity index 95% rename from src/hydro/GizmoMFM/hydro_io.h rename to src/hydro/Gizmo/hydro_io.h index 711eee9e3117c220e6ab5a27a6d8f3557ec7ce13..3fc8d78ef0bddb67262173ea0f17d2ee962efb40 100644 --- a/src/hydro/GizmoMFM/hydro_io.h +++ b/src/hydro/Gizmo/hydro_io.h @@ -16,8 +16,8 @@ * along with this program. If not, see <http://www.gnu.org/licenses/>. * ******************************************************************************/ -#ifndef SWIFT_GIZMO_MFM_HYDRO_IO_H -#define SWIFT_GIZMO_MFM_HYDRO_IO_H +#ifndef SWIFT_GIZMO_HYDRO_IO_H +#define SWIFT_GIZMO_HYDRO_IO_H #include "adiabatic_index.h" #include "hydro.h" @@ -116,11 +116,11 @@ INLINE static void convert_Etot(const struct engine* e, const struct part* p, INLINE static void convert_part_pos(const struct engine* e, const struct part* p, const struct xpart* xp, double* ret) { - - if (e->s->periodic) { - ret[0] = box_wrap(p->x[0], 0.0, e->s->dim[0]); - ret[1] = box_wrap(p->x[1], 0.0, e->s->dim[1]); - ret[2] = box_wrap(p->x[2], 0.0, e->s->dim[2]); + const struct space* s = e->s; + if (s->periodic) { + ret[0] = box_wrap(p->x[0] - s->pos_dithering[0], 0.0, s->dim[0]); + ret[1] = box_wrap(p->x[1] - s->pos_dithering[1], 0.0, s->dim[1]); + ret[2] = box_wrap(p->x[2] - s->pos_dithering[2], 0.0, s->dim[2]); } else { ret[0] = p->x[0]; ret[1] = p->x[1]; @@ -207,7 +207,7 @@ INLINE static void hydro_write_particles(const struct part* parts, "Co-moving smoothing lengths (FWHM of the kernel) of the particles"); list[4] = io_make_output_field_convert_part( - "InternalEnergy", FLOAT, 1, UNIT_CONV_ENERGY_PER_UNIT_MASS, + "InternalEnergies", FLOAT, 1, UNIT_CONV_ENERGY_PER_UNIT_MASS, 3.f * hydro_gamma_minus_one, parts, xparts, convert_u, "Co-moving thermal energies per unit mass of the particles"); @@ -266,4 +266,4 @@ INLINE static void hydro_write_flavour(hid_t h_grpsph) { */ INLINE static int writeEntropyFlag(void) { return 0; } -#endif /* SWIFT_GIZMO_MFM_HYDRO_IO_H */ +#endif /* SWIFT_GIZMO_HYDRO_IO_H */ diff --git a/src/hydro/Gizmo/hydro_lloyd.h b/src/hydro/Gizmo/hydro_lloyd.h new file mode 100644 index 0000000000000000000000000000000000000000..4c281e479d170ab17f2efffd0f451cdd77d6a578 --- /dev/null +++ b/src/hydro/Gizmo/hydro_lloyd.h @@ -0,0 +1,152 @@ +/******************************************************************************* + * This file is part of SWIFT. + * Coypright (c) 2019 Bert Vandenbroucke (bert.vandenbroucke@gmail.com) + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published + * by the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this program. If not, see <http://www.gnu.org/licenses/>. + * + ******************************************************************************/ +#ifndef SWIFT_GIZMO_HYDRO_LLOYD_H +#define SWIFT_GIZMO_HYDRO_LLOYD_H + +#ifdef GIZMO_LLOYD_ITERATION + +#if !defined(GIZMO_MFV_SPH) +#error "LLoyd's algorithm only works if you use GIZMO MFV!" +#endif + +/*! @brief Set the time step for each particle to the CFL condition. */ +#define hydro_gizmo_lloyd_skip_timestep(CFL_condition) return CFL_condition; + +/*! @brief Skip the drift for Lloyd's algorithm. */ +#define hydro_gizmo_lloyd_skip_drift() return; + +/** + * @brief Set the initial values for the primitive and conserved variables and + * the particle velocity to safe values for use with Lloyd's algorithm. + * + * @param W Primitive variable array (size 5 or more). + * @param Q Conserved variable array (size 5 or more). + * @param v Particle velocity array (size 3 or more). + */ +__attribute__((always_inline)) INLINE static void +hydro_gizmo_lloyd_initialize_particle(float *W, float *Q, float *v) { + + W[0] = 1.0f; + W[1] = 0.0f; + W[2] = 0.0f; + W[3] = 0.0f; + W[4] = 1.0f; + + Q[0] = 1.0f; + Q[1] = 0.0f; + Q[2] = 0.0f; + Q[3] = 0.0f; + Q[4] = 1.0f; + + v[0] = 0.0f; + v[1] = 0.0f; + v[2] = 0.0f; +} + +/** + * @brief Reset the primitive variables after they have been updated to make + * sure they still have safe values for use with Lloyd's algorithm. + * + * @param W Primitive variable array (size 5 or more). + */ +__attribute__((always_inline)) INLINE static void +hydro_gizmo_lloyd_reset_primitive_variables(float *W) { + + W[0] = 1.0f; + W[1] = 0.0f; + W[2] = 0.0f; + W[3] = 0.0f; + W[4] = 1.0f; +} + +/** + * @brief Reset the gradients to 0 after they have been computed, since we don't + * use them for Lloyd's algorithm. + * + * @param p Particle. + */ +__attribute__((always_inline)) INLINE static void +hydro_gizmo_lloyd_reset_gradients(struct part *restrict p) { + hydro_gradients_init(p); +} + +/** + * @brief Reset the force variables to safe values for use with Lloyd's + * algorithm. + * + * @param p Particle. + */ +__attribute__((always_inline)) INLINE static void hydro_gizmo_lloyd_end_force( + struct part *restrict p) { + + p->force.h_dt = 0.0f; +} + +/** + * @brief Reset the conserved variables after the flux exchange and "kick" the + * particle towards its centroid using the given kick time step. + * + * @param p Particle. + * @param xp Extended particle data. + * @param dt Kick time step. + */ +__attribute__((always_inline)) INLINE static void hydro_gizmo_lloyd_kick( + struct part *restrict p, struct xpart *restrict xp, const float dt) { + + /* reset conserved variables to safe values */ + p->conserved.mass = 1.; + p->conserved.momentum[0] = 0.; + p->conserved.momentum[1] = 0.; + p->conserved.momentum[2] = 0.; + p->conserved.energy = 1.; + + /* set the particle velocities to the Lloyd velocities */ + /* note that centroid is the relative position of the centroid w.r.t. the + particle position (position - centroid) */ + xp->v_full[0] = -p->geometry.centroid[0] / dt; + xp->v_full[1] = -p->geometry.centroid[1] / dt; + xp->v_full[2] = -p->geometry.centroid[2] / dt; + p->v[0] = xp->v_full[0]; + p->v[1] = xp->v_full[1]; + p->v[2] = xp->v_full[2]; +} + +#else /* no GIZMO_LLOYD_ITERATION */ + +#define hydro_gizmo_lloyd_skip_timestep(CFL_condition) +#define hydro_gizmo_lloyd_skip_drift() + +__attribute__((always_inline)) INLINE static void +hydro_gizmo_lloyd_initialize_particle(float *W, float *Q, float *v) {} + +__attribute__((always_inline)) INLINE static void +hydro_gizmo_lloyd_reset_primitive_variables(float *W) {} + +__attribute__((always_inline)) INLINE static void +hydro_gizmo_lloyd_reset_gradients(struct part *restrict p) {} + +__attribute__((always_inline)) INLINE static void hydro_gizmo_lloyd_end_force( + struct part *restrict p) {} + +__attribute__((always_inline)) INLINE static void hydro_gizmo_lloyd_kick( + struct part *restrict p, struct xpart *restrict xp, const float dt) {} + +#endif /* GIZMO_LLOYD_ITERATION */ + +#endif /* SWIFT_GIZMO_HYDRO_LLOYD_H */ diff --git a/src/hydro/GizmoMFM/hydro_parameters.h b/src/hydro/Gizmo/hydro_parameters.h similarity index 96% rename from src/hydro/GizmoMFM/hydro_parameters.h rename to src/hydro/Gizmo/hydro_parameters.h index c3135c10c8052da82cf897ef9b66cb52f1263212..148d5e604643035808c6ce12974cafcb0edf992c 100644 --- a/src/hydro/GizmoMFM/hydro_parameters.h +++ b/src/hydro/Gizmo/hydro_parameters.h @@ -18,8 +18,8 @@ * ******************************************************************************/ -#ifndef SWIFT_GIZMOMFM_HYDRO_PARAMETERS_H -#define SWIFT_GIZMOMFM_HYDRO_PARAMETERS_H +#ifndef SWIFT_GIZMO_HYDRO_PARAMETERS_H +#define SWIFT_GIZMO_HYDRO_PARAMETERS_H /* Configuration file */ #include "config.h" @@ -35,8 +35,8 @@ #include "inline.h" /** - * @file GizmoMFM/hydro_parameters.h - * @brief Gizmo-MFM scheme. (default parameters) + * @file Gizmo/hydro_parameters.h + * @brief Gizmo schemes. (default parameters) * * This file defines a number of things that are used in * hydro_properties.c as defaults for run-time parameters @@ -159,4 +159,4 @@ static INLINE void diffusion_print_snapshot( hid_t h_grpsph, const struct diffusion_global_data* diffusion) {} #endif -#endif /* SWIFT_GIZMOMFM_HYDRO_PARAMETERS_H */ +#endif /* SWIFT_GIZMO_HYDRO_PARAMETERS_H */ diff --git a/src/hydro/Gizmo/hydro_part.h b/src/hydro/Gizmo/hydro_part.h new file mode 100644 index 0000000000000000000000000000000000000000..c1228f576eac2c93aac5465701e6d93b89932119 --- /dev/null +++ b/src/hydro/Gizmo/hydro_part.h @@ -0,0 +1,66 @@ +/******************************************************************************* + * This file is part of SWIFT. + * Copyright (c) 2019 Bert Vandenbroucke (bert.vandenbroucke@gmail.com) + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published + * by the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this program. If not, see <http://www.gnu.org/licenses/>. + * + ******************************************************************************/ +#ifndef SWIFT_GIZMO_HYDRO_PART_H +#define SWIFT_GIZMO_HYDRO_PART_H + +#include "black_holes_struct.h" +#include "chemistry_struct.h" +#include "cooling_struct.h" +#include "feedback_struct.h" +#include "star_formation_struct.h" +#include "timestep_limiter_struct.h" +#include "tracers_struct.h" + +/* Extra particle data not needed during the computation. */ +struct xpart { + + /* Offset between current position and position at last tree rebuild. */ + float x_diff[3]; + + /* Offset between the current position and position at the last sort. */ + float x_diff_sort[3]; + + /* Velocity at the last full step. */ + float v_full[3]; + + /* Gravitational acceleration at the last full step. */ + float a_grav[3]; + + /* Additional data used to record cooling information */ + struct cooling_xpart_data cooling_data; + + /* Additional data used by the tracers */ + struct tracers_xpart_data tracers_data; + + /* Additional data used by the star formation */ + struct star_formation_xpart_data sf_data; + + /* Additional data used by the feedback */ + struct feedback_part_data feedback_data; + +} SWIFT_STRUCT_ALIGN; + +/* Import the right hydro particle definition */ +#if defined(GIZMO_MFV_SPH) +#include "MFV/hydro_part.h" +#elif defined(GIZMO_MFM_SPH) +#include "MFM/hydro_part.h" +#endif + +#endif /* SWIFT_GIZMO_HYDRO_PART_H */ diff --git a/src/hydro/Gizmo/hydro_setters.h b/src/hydro/Gizmo/hydro_setters.h new file mode 100644 index 0000000000000000000000000000000000000000..91219da87f08a3f694976c0c18258de8c3b6b98a --- /dev/null +++ b/src/hydro/Gizmo/hydro_setters.h @@ -0,0 +1,375 @@ +/******************************************************************************* + * This file is part of SWIFT. + * Coypright (c) 2019 Bert Vandenbroucke (bert.vandenbroucke@gmail.com) + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published + * by the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this program. If not, see <http://www.gnu.org/licenses/>. + * + ******************************************************************************/ +#ifndef SWIFT_GIZMO_HYDRO_SETTERS_H +#define SWIFT_GIZMO_HYDRO_SETTERS_H + +/** + * @brief Set the primitive variables for the given particle to the given + * values. + * + * @param p Particle. + * @param W Primitive variables. + */ +__attribute__((always_inline)) INLINE static void +hydro_part_set_primitive_variables(struct part* restrict p, const float* W) { + + p->rho = W[0]; + p->fluid_v[0] = W[1]; + p->fluid_v[1] = W[2]; + p->fluid_v[2] = W[3]; + p->P = W[4]; +} + +/** + * @brief Set the conserved variables for the given particle to the given + * values. + * + * @param p Particle. + * @param Q Conserved variables. + */ +__attribute__((always_inline)) INLINE static void +hydro_part_set_conserved_variables(struct part* restrict p, const float* Q) { + + p->conserved.mass = Q[0]; + p->conserved.momentum[0] = Q[1]; + p->conserved.momentum[1] = Q[2]; + p->conserved.momentum[2] = Q[3]; + p->conserved.energy = Q[4]; +} + +/** + * @brief Set the gradients for the given particle to zero. + * + * @param p Particle. + */ +__attribute__((always_inline)) INLINE static void hydro_part_reset_gradients( + struct part* restrict p) { + + p->gradients.rho[0] = 0.0f; + p->gradients.rho[1] = 0.0f; + p->gradients.rho[2] = 0.0f; + + p->gradients.v[0][0] = 0.0f; + p->gradients.v[0][1] = 0.0f; + p->gradients.v[0][2] = 0.0f; + p->gradients.v[1][0] = 0.0f; + p->gradients.v[1][1] = 0.0f; + p->gradients.v[1][2] = 0.0f; + p->gradients.v[2][0] = 0.0f; + p->gradients.v[2][1] = 0.0f; + p->gradients.v[2][2] = 0.0f; + + p->gradients.P[0] = 0.0f; + p->gradients.P[1] = 0.0f; + p->gradients.P[2] = 0.0f; +} + +/** + * @brief Set the gradients for the given particle to the given values. + * + * @param p Particle. + */ +__attribute__((always_inline)) INLINE static void hydro_part_set_gradients( + struct part* restrict p, const float* gradrho, const float* gradvx, + const float* gradvy, const float* gradvz, const float* gradP) { + + p->gradients.rho[0] = gradrho[0]; + p->gradients.rho[1] = gradrho[1]; + p->gradients.rho[2] = gradrho[2]; + + p->gradients.v[0][0] = gradvx[0]; + p->gradients.v[0][1] = gradvx[1]; + p->gradients.v[0][2] = gradvx[2]; + p->gradients.v[1][0] = gradvy[0]; + p->gradients.v[1][1] = gradvy[1]; + p->gradients.v[1][2] = gradvy[2]; + p->gradients.v[2][0] = gradvz[0]; + p->gradients.v[2][1] = gradvz[1]; + p->gradients.v[2][2] = gradvz[2]; + + p->gradients.P[0] = gradP[0]; + p->gradients.P[1] = gradP[1]; + p->gradients.P[2] = gradP[2]; +} + +/** + * @brief Update the gradients for the given particle with the given + * contributions. + * + * @param p Particle. + * @param drho Density gradient contribution. + * @param dvx x velocity gradient contribution. + * @param dvy y velocity gradient contribution. + * @param dvz z velocity gradient contribution. + * @param dP Pressure gradient contribution. + */ +__attribute__((always_inline)) INLINE static void hydro_part_update_gradients( + struct part* restrict p, const float* drho, const float* dvx, + const float* dvy, const float* dvz, const float* dP) { + + p->gradients.rho[0] += drho[0]; + p->gradients.rho[1] += drho[1]; + p->gradients.rho[2] += drho[2]; + + p->gradients.v[0][0] += dvx[0]; + p->gradients.v[0][1] += dvx[1]; + p->gradients.v[0][2] += dvx[2]; + p->gradients.v[1][0] += dvy[0]; + p->gradients.v[1][1] += dvy[1]; + p->gradients.v[1][2] += dvy[2]; + p->gradients.v[2][0] += dvz[0]; + p->gradients.v[2][1] += dvz[1]; + p->gradients.v[2][2] += dvz[2]; + + p->gradients.P[0] += dP[0]; + p->gradients.P[1] += dP[1]; + p->gradients.P[2] += dP[2]; +} + +/** + * @brief Normalise the gradients for the given particle with the given + * normalisation factor. + * + * @param p Particle. + * @param norm Normalisation factor. + */ +__attribute__((always_inline)) INLINE static void +hydro_part_normalise_gradients(struct part* restrict p, const float norm) { + + p->gradients.rho[0] *= norm; + p->gradients.rho[1] *= norm; + p->gradients.rho[2] *= norm; + + p->gradients.v[0][0] *= norm; + p->gradients.v[0][1] *= norm; + p->gradients.v[0][2] *= norm; + p->gradients.v[1][0] *= norm; + p->gradients.v[1][1] *= norm; + p->gradients.v[1][2] *= norm; + p->gradients.v[2][0] *= norm; + p->gradients.v[2][1] *= norm; + p->gradients.v[2][2] *= norm; + + p->gradients.P[0] *= norm; + p->gradients.P[1] *= norm; + p->gradients.P[2] *= norm; +} + +/** + * @brief Sets the mass of a particle + * + * @param p The particle of interest + * @param m The mass to set. + */ +__attribute__((always_inline)) INLINE static void hydro_set_mass( + struct part* restrict p, float m) { + + p->conserved.mass = m; +} + +/** + * @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 comoving internal energy. + */ +__attribute__((always_inline)) INLINE static void +hydro_set_comoving_internal_energy_dt(struct part* restrict p, + const float du_dt) { + error("Needs implementing"); +} + +/** + * @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 physical internal energy. + */ +__attribute__((always_inline)) INLINE static void +hydro_set_physical_internal_energy_dt(struct part* restrict p, + const struct cosmology* restrict cosmo, + const float du_dt) { + error("Needs implementing"); +} +/** + * @brief Sets the physical entropy of a particle + * + * @param p The particle of interest. + * @param xp The extended particle data. + * @param cosmo Cosmology data structure + * @param entropy The physical entropy + */ +__attribute__((always_inline)) INLINE static void hydro_set_physical_entropy( + struct part* p, struct xpart* xp, const struct cosmology* cosmo, + const float entropy) { + + error("Needs implementing"); +} + +/** + * @brief Sets the physical internal energy of a particle + * + * @param p The particle of interest. + * @param xp The extended particle data. + * @param cosmo Cosmology data structure + * @param u The physical internal energy + */ +__attribute__((always_inline)) INLINE static void +hydro_set_physical_internal_energy(struct part* p, struct xpart* xp, + const struct cosmology* cosmo, + const float u) { + error("Need implementing"); +} + +/** + * @brief Sets the drifted physical internal energy of a particle + * + * @param p The particle of interest. + * @param cosmo Cosmology data structure + * @param u The physical internal energy + */ +__attribute__((always_inline)) INLINE static void +hydro_set_drifted_physical_internal_energy(struct part* p, + const struct cosmology* cosmo, + const float u) { + error("Need implementing"); +} + +/** + * @brief Update the value of the viscosity alpha for the scheme. + * + * @param p the particle of interest + * @param alpha the new value for the viscosity coefficient. + */ +__attribute__((always_inline)) INLINE static void hydro_set_viscosity_alpha( + struct part* restrict p, float alpha) { + /* Purposefully left empty */ +} + +/** + * @brief Update the value of the viscosity alpha to the + * feedback reset value for the scheme. + * + * @param p the particle of interest + */ +__attribute__((always_inline)) INLINE static void +hydro_diffusive_feedback_reset(struct part* restrict p) { + /* Purposefully left empty */ +} + +/** + * @brief Returns the comoving density of a particle + * + * @param p The particle of interest + */ +__attribute__((always_inline)) INLINE static float hydro_get_comoving_density( + const struct part* restrict p) { + + return p->rho; +} + +/** + * @brief Returns the physical density of a particle + * + * @param p The particle of interest + * @param cosmo The cosmological model. + */ +__attribute__((always_inline)) INLINE static float hydro_get_physical_density( + const struct part* restrict p, const struct cosmology* cosmo) { + + return cosmo->a3_inv * p->rho; +} + +/** + * @brief Modifies the thermal state of a particle to the imposed internal + * energy + * + * This overrides the current state of the particle but does *not* change its + * time-derivatives + * + * @param p The particle + * @param u The new internal energy + */ +__attribute__((always_inline)) INLINE static void hydro_set_internal_energy( + struct part* restrict p, float u) { + + /* conserved.energy is NOT the specific energy (u), but the total thermal + energy (u*m) */ + p->conserved.energy = u * p->conserved.mass; +#ifdef GIZMO_TOTAL_ENERGY + /* add the kinetic energy */ + p->conserved.energy += 0.5f * p->conserved.mass * + (p->conserved.momentum[0] * p->fluid_v[0] + + p->conserved.momentum[1] * p->fluid_v[1] + + p->conserved.momentum[2] * p->fluid_v[2]); +#endif + p->P = hydro_gamma_minus_one * p->rho * u; +} + +/** + * @brief Modifies the thermal state of a particle to the imposed entropy + * + * This overrides the current state of the particle but does *not* change its + * time-derivatives + * + * @param p The particle + * @param S The new entropy + */ +__attribute__((always_inline)) INLINE static void hydro_set_entropy( + struct part* restrict p, float S) { + + p->conserved.energy = S * pow_gamma_minus_one(p->rho) * + hydro_one_over_gamma_minus_one * p->conserved.mass; +#ifdef GIZMO_TOTAL_ENERGY + /* add the kinetic energy */ + p->conserved.energy += 0.5f * p->conserved.mass * + (p->conserved.momentum[0] * p->fluid_v[0] + + p->conserved.momentum[1] * p->fluid_v[1] + + p->conserved.momentum[2] * p->fluid_v[2]); +#endif + p->P = S * pow_gamma(p->rho); +} + +/** + * @brief Overwrite the initial internal energy of a particle. + * + * Note that in the cases where the thermodynamic variable is not + * internal energy but gets converted later, we must overwrite that + * field. The conversion to the actual variable happens later after + * the initial fake time-step. + * + * @param p The #part to write to. + * @param u_init The new initial internal energy. + */ +__attribute__((always_inline)) INLINE static void +hydro_set_init_internal_energy(struct part* p, float u_init) { + + /* We store the initial energy per unit mass in the energy + * variable as the conversion to energy will be done later, + * in hydro_first_init_part(). */ + p->conserved.energy = u_init; +} + +#endif /* SWIFT_GIZMO_HYDRO_SETTERS_H */ diff --git a/src/hydro/GizmoMFM/hydro_slope_limiters.h b/src/hydro/Gizmo/hydro_slope_limiters.h similarity index 99% rename from src/hydro/GizmoMFM/hydro_slope_limiters.h rename to src/hydro/Gizmo/hydro_slope_limiters.h index 7c9c759830a4b0ee98412d5a200700c0a148d316..67f60da5c803c76a6d64c5d87dcc00b755676c6d 100644 --- a/src/hydro/GizmoMFM/hydro_slope_limiters.h +++ b/src/hydro/Gizmo/hydro_slope_limiters.h @@ -56,6 +56,7 @@ __attribute__((always_inline)) INLINE static void hydro_slope_limit_face( #define HYDRO_SLOPE_LIMITER_CELL_IMPLEMENTATION \ "Cell wide slope limiter (Springel 2010)" + #include "hydro_slope_limiters_cell.h" #else diff --git a/src/hydro/Gizmo/hydro_slope_limiters_cell.h b/src/hydro/Gizmo/hydro_slope_limiters_cell.h new file mode 100644 index 0000000000000000000000000000000000000000..a47da9e005429e180e8813db33499463cb855425 --- /dev/null +++ b/src/hydro/Gizmo/hydro_slope_limiters_cell.h @@ -0,0 +1,124 @@ +/******************************************************************************* + * This file is part of SWIFT. + * Copyright (c) 2016 Bert Vandenbroucke (bert.vandenbroucke@gmail.com) + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published + * by the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this program. If not, see <http://www.gnu.org/licenses/>. + * + ******************************************************************************/ +#ifndef SWIFT_GIZMO_SLOPE_LIMITER_CELL_H +#define SWIFT_GIZMO_SLOPE_LIMITER_CELL_H + +#include <float.h> +#include "hydro_getters.h" +#include "hydro_setters.h" + +/** + * @brief Initialize variables for the cell wide slope limiter + * + * @param p Particle. + */ +__attribute__((always_inline)) INLINE static void hydro_slope_limit_cell_init( + struct part* p) { + + p->limiter.rho[0] = FLT_MAX; + p->limiter.rho[1] = -FLT_MAX; + p->limiter.v[0][0] = FLT_MAX; + p->limiter.v[0][1] = -FLT_MAX; + p->limiter.v[1][0] = FLT_MAX; + p->limiter.v[1][1] = -FLT_MAX; + p->limiter.v[2][0] = FLT_MAX; + p->limiter.v[2][1] = -FLT_MAX; + p->limiter.P[0] = FLT_MAX; + p->limiter.P[1] = -FLT_MAX; + + p->limiter.maxr = -FLT_MAX; +} + +/** + * @brief Collect information for the cell wide slope limiter during the + * neighbour loop + * + * @param pi Particle i. + * @param pj Particle j. + * @param r Distance between particle i and particle j. + */ +__attribute__((always_inline)) INLINE static void +hydro_slope_limit_cell_collect(struct part* pi, struct part* pj, float r) { + + /* basic slope limiter: collect the maximal and the minimal value for the + * primitive variables among the ngbs */ + pi->limiter.rho[0] = min(pj->rho, pi->limiter.rho[0]); + pi->limiter.rho[1] = max(pj->rho, pi->limiter.rho[1]); + + pi->limiter.v[0][0] = min(pj->fluid_v[0], pi->limiter.v[0][0]); + pi->limiter.v[0][1] = max(pj->fluid_v[0], pi->limiter.v[0][1]); + pi->limiter.v[1][0] = min(pj->fluid_v[1], pi->limiter.v[1][0]); + pi->limiter.v[1][1] = max(pj->fluid_v[1], pi->limiter.v[1][1]); + pi->limiter.v[2][0] = min(pj->fluid_v[2], pi->limiter.v[2][0]); + pi->limiter.v[2][1] = max(pj->fluid_v[2], pi->limiter.v[2][1]); + + pi->limiter.P[0] = min(pj->P, pi->limiter.P[0]); + pi->limiter.P[1] = max(pj->P, pi->limiter.P[1]); + + pi->limiter.maxr = max(r, pi->limiter.maxr); +} + +/** + * @brief Slope-limit the given quantity. + */ +__attribute__((always_inline)) INLINE static void hydro_slope_limit_quantity( + float* gradient, const float maxr, const float value, const float valmin, + const float valmax) { + + float gradtrue = sqrtf(gradient[0] * gradient[0] + gradient[1] * gradient[1] + + gradient[2] * gradient[2]); + if (gradtrue != 0.0f) { + gradtrue *= maxr; + const float gradmax = valmax - value; + const float gradmin = value - valmin; + const float gradtrue_inv = 1.0f / gradtrue; + const float alpha = + min3(1.0f, gradmax * gradtrue_inv, gradmin * gradtrue_inv); + gradient[0] *= alpha; + gradient[1] *= alpha; + gradient[2] *= alpha; + } +} + +/** + * @brief Slope limit cell gradients + * + * @param p Particle. + */ +__attribute__((always_inline)) INLINE static void hydro_slope_limit_cell( + struct part* p) { + + float W[5]; + float gradrho[3], gradvx[3], gradvy[3], gradvz[3], gradP[3]; + float rholim[2], vxlim[2], vylim[2], vzlim[2], Plim[2], maxr; + + hydro_part_get_primitive_variables(p, W); + hydro_part_get_gradients(p, gradrho, gradvx, gradvy, gradvz, gradP); + hydro_part_get_slope_limiter(p, rholim, vxlim, vylim, vzlim, Plim, &maxr); + + hydro_slope_limit_quantity(gradrho, maxr, W[0], rholim[0], rholim[1]); + hydro_slope_limit_quantity(gradvx, maxr, W[1], vxlim[0], vxlim[1]); + hydro_slope_limit_quantity(gradvy, maxr, W[2], vylim[0], vylim[1]); + hydro_slope_limit_quantity(gradvz, maxr, W[3], vzlim[0], vzlim[1]); + hydro_slope_limit_quantity(gradP, maxr, W[4], Plim[0], Plim[1]); + + hydro_part_set_gradients(p, gradrho, gradvx, gradvy, gradvz, gradP); +} + +#endif /* SWIFT_GIZMO_SLOPE_LIMITER_CELL_H */ diff --git a/src/hydro/GizmoMFM/hydro_slope_limiters_face.h b/src/hydro/Gizmo/hydro_slope_limiters_face.h similarity index 97% rename from src/hydro/GizmoMFM/hydro_slope_limiters_face.h rename to src/hydro/Gizmo/hydro_slope_limiters_face.h index a7c0e37d3953d1d385128b4a1c72dd2311ac00ae..0b58c6e2482c1381b022df972ec46fb1c6f29df6 100644 --- a/src/hydro/GizmoMFM/hydro_slope_limiters_face.h +++ b/src/hydro/Gizmo/hydro_slope_limiters_face.h @@ -29,8 +29,8 @@ * @return The slope limited difference between the quantity at the particle * position and the quantity at the interface position. */ -#ifndef SWIFT_GIZMO_MFM_SLOPE_LIMITER_FACE_H -#define SWIFT_GIZMO_MFM_SLOPE_LIMITER_FACE_H +#ifndef SWIFT_GIZMO_SLOPE_LIMITER_FACE_H +#define SWIFT_GIZMO_SLOPE_LIMITER_FACE_H /* Some standard headers. */ #include <float.h> @@ -127,4 +127,4 @@ __attribute__((always_inline)) INLINE static void hydro_slope_limit_face( xij_j_norm, r_inv); } -#endif /* SWIFT_GIZMO_MFM_SLOPE_LIMITER_FACE_H */ +#endif /* SWIFT_GIZMO_SLOPE_LIMITER_FACE_H */ diff --git a/src/hydro/GizmoMFM/hydro_unphysical.h b/src/hydro/Gizmo/hydro_unphysical.h similarity index 96% rename from src/hydro/GizmoMFM/hydro_unphysical.h rename to src/hydro/Gizmo/hydro_unphysical.h index 81c644e6cce00e0d871aafc39140e420e042a926..c1e417213799069bd6106a65c86328fb55861f20 100644 --- a/src/hydro/GizmoMFM/hydro_unphysical.h +++ b/src/hydro/Gizmo/hydro_unphysical.h @@ -16,8 +16,8 @@ * along with this program. If not, see <http://www.gnu.org/licenses/>. * ******************************************************************************/ -#ifndef SWIFT_HYDRO_UNPHYSICAL_H -#define SWIFT_HYDRO_UNPHYSICAL_H +#ifndef SWIFT_GIZMO_HYDRO_UNPHYSICAL_H +#define SWIFT_GIZMO_HYDRO_UNPHYSICAL_H #if defined(GIZMO_UNPHYSICAL_ERROR) || defined(GIZMO_UNPHYSICAL_RESCUE) @@ -66,4 +66,4 @@ #endif // defined(GIZMO_UNPHYSICAL_ERROR) || defined(GIZMO_UNPHYSICAL_RESCUE) -#endif /* SWIFT_HYDRO_UNPHYSICAL_H */ +#endif /* SWIFT_GIZMO_HYDRO_UNPHYSICAL_H */ diff --git a/src/hydro/Gizmo/hydro_velocities.h b/src/hydro/Gizmo/hydro_velocities.h new file mode 100644 index 0000000000000000000000000000000000000000..bb385f31728ac95ac478a1ff15852edf388a7d5e --- /dev/null +++ b/src/hydro/Gizmo/hydro_velocities.h @@ -0,0 +1,28 @@ +/******************************************************************************* + * This file is part of SWIFT. + * Coypright (c) 2017 Bert Vandenbroucke (bert.vandenbroucke@gmail.com) + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published + * by the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this program. If not, see <http://www.gnu.org/licenses/>. + * + ******************************************************************************/ +#ifndef SWIFT_GIZMO_HYDRO_VELOCITIES_H +#define SWIFT_GIZMO_HYDRO_VELOCITIES_H + +#if defined(GIZMO_MFV_SPH) +#include "MFV/hydro_velocities.h" +#elif defined(GIZMO_MFM_SPH) +#include "MFM/hydro_velocities.h" +#endif + +#endif /* SWIFT_GIZMO_HYDRO_VELOCITIES_H */ diff --git a/src/hydro/GizmoMFM/hydro_slope_limiters_cell.h b/src/hydro/GizmoMFM/hydro_slope_limiters_cell.h deleted file mode 100644 index 329ca5fda4510a3672bfe698bed52c8f0bebc895..0000000000000000000000000000000000000000 --- a/src/hydro/GizmoMFM/hydro_slope_limiters_cell.h +++ /dev/null @@ -1,176 +0,0 @@ -/******************************************************************************* - * This file is part of SWIFT. - * Copyright (c) 2016 Bert Vandenbroucke (bert.vandenbroucke@gmail.com) - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU Lesser General Public License as published - * by the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public License - * along with this program. If not, see <http://www.gnu.org/licenses/>. - * - ******************************************************************************/ -#ifndef SWIFT_GIZMO_MFM_SLOPE_LIMITER_CELL_H -#define SWIFT_GIZMO_MFM_SLOPE_LIMITER_CELL_H - -#include <float.h> - -/** - * @brief Initialize variables for the cell wide slope limiter - * - * @param p Particle. - */ -__attribute__((always_inline)) INLINE static void hydro_slope_limit_cell_init( - struct part* p) { - - p->limiter.rho[0] = FLT_MAX; - p->limiter.rho[1] = -FLT_MAX; - p->limiter.v[0][0] = FLT_MAX; - p->limiter.v[0][1] = -FLT_MAX; - p->limiter.v[1][0] = FLT_MAX; - p->limiter.v[1][1] = -FLT_MAX; - p->limiter.v[2][0] = FLT_MAX; - p->limiter.v[2][1] = -FLT_MAX; - p->limiter.P[0] = FLT_MAX; - p->limiter.P[1] = -FLT_MAX; - - p->limiter.maxr = -FLT_MAX; -} - -/** - * @brief Collect information for the cell wide slope limiter during the - * neighbour loop - * - * @param pi Particle i. - * @param pj Particle j. - * @param r Distance between particle i and particle j. - */ -__attribute__((always_inline)) INLINE static void -hydro_slope_limit_cell_collect(struct part* pi, struct part* pj, float r) { - - /* basic slope limiter: collect the maximal and the minimal value for the - * primitive variables among the ngbs */ - pi->limiter.rho[0] = min(pj->rho, pi->limiter.rho[0]); - pi->limiter.rho[1] = max(pj->rho, pi->limiter.rho[1]); - - pi->limiter.v[0][0] = min(pj->v[0], pi->limiter.v[0][0]); - pi->limiter.v[0][1] = max(pj->v[0], pi->limiter.v[0][1]); - pi->limiter.v[1][0] = min(pj->v[1], pi->limiter.v[1][0]); - pi->limiter.v[1][1] = max(pj->v[1], pi->limiter.v[1][1]); - pi->limiter.v[2][0] = min(pj->v[2], pi->limiter.v[2][0]); - pi->limiter.v[2][1] = max(pj->v[2], pi->limiter.v[2][1]); - - pi->limiter.P[0] = min(pj->P, pi->limiter.P[0]); - pi->limiter.P[1] = max(pj->P, pi->limiter.P[1]); - - pi->limiter.maxr = max(r, pi->limiter.maxr); -} - -/** - * @brief Slope limit cell gradients - * - * @param p Particle. - */ -__attribute__((always_inline)) INLINE static void hydro_slope_limit_cell( - struct part* p) { - - float gradtrue, gradrho[3], gradv[3][3], gradP[3]; - - gradrho[0] = p->gradients.rho[0]; - gradrho[1] = p->gradients.rho[1]; - gradrho[2] = p->gradients.rho[2]; - - gradv[0][0] = p->gradients.v[0][0]; - gradv[0][1] = p->gradients.v[0][1]; - gradv[0][2] = p->gradients.v[0][2]; - - gradv[1][0] = p->gradients.v[1][0]; - gradv[1][1] = p->gradients.v[1][1]; - gradv[1][2] = p->gradients.v[1][2]; - - gradv[2][0] = p->gradients.v[2][0]; - gradv[2][1] = p->gradients.v[2][1]; - gradv[2][2] = p->gradients.v[2][2]; - - gradP[0] = p->gradients.P[0]; - gradP[1] = p->gradients.P[1]; - gradP[2] = p->gradients.P[2]; - - gradtrue = sqrtf(gradrho[0] * gradrho[0] + gradrho[1] * gradrho[1] + - gradrho[2] * gradrho[2]); - if (gradtrue) { - gradtrue *= p->limiter.maxr; - const float gradmax = p->limiter.rho[1] - p->rho; - const float gradmin = p->rho - p->limiter.rho[0]; - const float gradtrue_inv = 1.0f / gradtrue; - const float alpha = - min3(1.0f, gradmax * gradtrue_inv, gradmin * gradtrue_inv); - p->gradients.rho[0] *= alpha; - p->gradients.rho[1] *= alpha; - p->gradients.rho[2] *= alpha; - } - - gradtrue = sqrtf(gradv[0][0] * gradv[0][0] + gradv[0][1] * gradv[0][1] + - gradv[0][2] * gradv[0][2]); - if (gradtrue) { - gradtrue *= p->limiter.maxr; - const float gradmax = p->limiter.v[0][1] - p->v[0]; - const float gradmin = p->v[0] - p->limiter.v[0][0]; - const float gradtrue_inv = 1.0f / gradtrue; - const float alpha = - min3(1.0f, gradmax * gradtrue_inv, gradmin * gradtrue_inv); - p->gradients.v[0][0] *= alpha; - p->gradients.v[0][1] *= alpha; - p->gradients.v[0][2] *= alpha; - } - - gradtrue = sqrtf(gradv[1][0] * gradv[1][0] + gradv[1][1] * gradv[1][1] + - gradv[1][2] * gradv[1][2]); - if (gradtrue) { - gradtrue *= p->limiter.maxr; - const float gradmax = p->limiter.v[1][1] - p->v[1]; - const float gradmin = p->v[1] - p->limiter.v[1][0]; - const float gradtrue_inv = 1.0f / gradtrue; - const float alpha = - min3(1.0f, gradmax * gradtrue_inv, gradmin * gradtrue_inv); - p->gradients.v[1][0] *= alpha; - p->gradients.v[1][1] *= alpha; - p->gradients.v[1][2] *= alpha; - } - - gradtrue = sqrtf(gradv[2][0] * gradv[2][0] + gradv[2][1] * gradv[2][1] + - gradv[2][2] * gradv[2][2]); - if (gradtrue) { - gradtrue *= p->limiter.maxr; - const float gradmax = p->limiter.v[2][1] - p->v[2]; - const float gradmin = p->v[2] - p->limiter.v[2][0]; - const float gradtrue_inv = 1.0f / gradtrue; - const float alpha = - min3(1.0f, gradmax * gradtrue_inv, gradmin * gradtrue_inv); - p->gradients.v[2][0] *= alpha; - p->gradients.v[2][1] *= alpha; - p->gradients.v[2][2] *= alpha; - } - - gradtrue = - sqrtf(gradP[0] * gradP[0] + gradP[1] * gradP[1] + gradP[2] * gradP[2]); - if (gradtrue) { - gradtrue *= p->limiter.maxr; - const float gradmax = p->limiter.P[1] - p->P; - const float gradmin = p->P - p->limiter.P[0]; - const float gradtrue_inv = 1.0f / gradtrue; - const float alpha = - min3(1.0f, gradmax * gradtrue_inv, gradmin * gradtrue_inv); - p->gradients.P[0] *= alpha; - p->gradients.P[1] *= alpha; - p->gradients.P[2] *= alpha; - } -} - -#endif /* SWIFT_GIZMO_MFM_SLOPE_LIMITER_CELL_H */ diff --git a/src/hydro/GizmoMFV/hydro.h b/src/hydro/GizmoMFV/hydro.h deleted file mode 100644 index a0c3b0d59f7fa8843d4b190f1348e77e2331c23b..0000000000000000000000000000000000000000 --- a/src/hydro/GizmoMFV/hydro.h +++ /dev/null @@ -1,1232 +0,0 @@ -/******************************************************************************* - * This file is part of SWIFT. - * Coypright (c) 2015 Matthieu Schaller (matthieu.schaller@durham.ac.uk) - * 2016, 2017 Bert Vandenbroucke (bert.vandenbroucke@gmail.com) - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU Lesser General Public License as published - * by the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public License - * along with this program. If not, see <http://www.gnu.org/licenses/>. - * - ******************************************************************************/ -#ifndef SWIFT_GIZMO_MFV_HYDRO_H -#define SWIFT_GIZMO_MFV_HYDRO_H - -#include "adiabatic_index.h" -#include "approx_math.h" -#include "cosmology.h" -#include "entropy_floor.h" -#include "equation_of_state.h" -#include "hydro_gradients.h" -#include "hydro_properties.h" -#include "hydro_space.h" -#include "hydro_unphysical.h" -#include "hydro_velocities.h" -#include "minmax.h" -#include "riemann.h" - -#include <float.h> - -//#define GIZMO_LLOYD_ITERATION - -/** - * @brief Computes the hydro time-step of a given particle - * - * @param p Pointer to the particle data. - * @param xp Pointer to the extended particle data. - * @param hydro_properties Pointer to the hydro parameters. - * @param cosmo The cosmological model. - */ -__attribute__((always_inline)) INLINE static float hydro_compute_timestep( - const struct part* restrict p, const struct xpart* restrict xp, - const struct hydro_props* restrict hydro_properties, - const struct cosmology* restrict cosmo) { - - const float CFL_condition = hydro_properties->CFL_condition; - -#ifdef GIZMO_LLOYD_ITERATION - return CFL_condition; -#endif - - /* v_full is the actual velocity of the particle, primitives.v is its - hydrodynamical velocity. The time step depends on the relative difference - of the two. */ - float vrel[3]; - vrel[0] = p->primitives.v[0] - xp->v_full[0]; - vrel[1] = p->primitives.v[1] - xp->v_full[1]; - vrel[2] = p->primitives.v[2] - xp->v_full[2]; - float vmax = - sqrtf(vrel[0] * vrel[0] + vrel[1] * vrel[1] + vrel[2] * vrel[2]) + - sqrtf(hydro_gamma * p->primitives.P / p->primitives.rho); - vmax = max(vmax, p->timestepvars.vmax); - - // MATTHIEU: Bert is this correct? Do we need more cosmology terms here? - const float psize = powf(p->geometry.volume / hydro_dimension_unit_sphere, - hydro_dimension_inv); - float dt = FLT_MAX; - if (vmax > 0.) { - dt = psize / vmax; - } - return cosmo->a * cosmo->a * CFL_condition * dt; -} - -/** - * @brief Does some extra hydro operations once the actual physical time step - * for the particle is known. - * - * This method is no longer used, as Gizmo is now unaware of the actual particle - * time step. - * - * @param p The particle to act upon. - * @param dt Physical time step of the particle during the next step. - */ -__attribute__((always_inline)) INLINE static void hydro_timestep_extra( - struct part* p, float dt) { - -#ifdef SWIFT_DEBUG_CHECKS - if (dt == 0.) { - error("Zero time step assigned to particle!"); - } - - if (dt != dt) { - error("NaN time step assigned to particle!"); - } -#endif -} - -/** - * @brief Initialises the particles for the first time - * - * This function is called only once just after the ICs have been - * read in to do some conversions. - * - * In this case, we copy the particle velocities into the corresponding - * primitive variable field. We do this because the particle velocities in GIZMO - * can be independent of the actual fluid velocity. The latter is stored as a - * primitive variable and integrated using the linear momentum, a conserved - * variable. - * - * @param p The particle to act upon - * @param xp The extended particle data to act upon - */ -__attribute__((always_inline)) INLINE static void hydro_first_init_part( - struct part* p, struct xpart* xp) { - - const float mass = p->conserved.mass; - - p->time_bin = 0; - p->wakeup = time_bin_not_awake; - - p->primitives.v[0] = p->v[0]; - p->primitives.v[1] = p->v[1]; - p->primitives.v[2] = p->v[2]; - - /* we can already initialize the momentum */ - p->conserved.momentum[0] = mass * p->primitives.v[0]; - p->conserved.momentum[1] = mass * p->primitives.v[1]; - p->conserved.momentum[2] = mass * p->primitives.v[2]; - -/* and the thermal energy */ -/* remember that we store the total thermal energy, not the specific thermal - energy (as in Gadget) */ -#if defined(EOS_ISOTHERMAL_GAS) - /* this overwrites the internal energy from the initial condition file - * Note that we call the EoS function just to get the constant u here. */ - p->conserved.energy = mass * gas_internal_energy_from_entropy(0.f, 0.f); -#else - p->conserved.energy *= mass; -#endif - -#ifdef GIZMO_TOTAL_ENERGY - /* add the total kinetic energy */ - p->conserved.energy += 0.5f * (p->conserved.momentum[0] * p->primitives.v[0] + - p->conserved.momentum[1] * p->primitives.v[1] + - p->conserved.momentum[2] * p->primitives.v[2]); -#endif - -#ifdef GIZMO_LLOYD_ITERATION - /* overwrite all variables to make sure they have safe values */ - p->primitives.rho = 1.; - p->primitives.v[0] = 0.; - p->primitives.v[1] = 0.; - p->primitives.v[2] = 0.; - p->primitives.P = 1.; - - p->conserved.mass = 1.; - p->conserved.momentum[0] = 0.; - p->conserved.momentum[1] = 0.; - p->conserved.momentum[2] = 0.; - p->conserved.energy = 1.; - - p->v[0] = 0.; - p->v[1] = 0.; - p->v[2] = 0.; -#endif - - /* initialize the particle velocity based on the primitive fluid velocity */ - hydro_velocities_init(p, xp); - - /* ignore accelerations present in the initial condition */ - p->a_hydro[0] = 0.0f; - p->a_hydro[1] = 0.0f; - p->a_hydro[2] = 0.0f; - - /* we cannot initialize wcorr in init_part, as init_part gets called every - time the density loop is repeated, and the whole point of storing wcorr - is to have a way of remembering that we need more neighbours for this - particle */ - p->density.wcorr = 1.0f; -} - -/** - * @brief Prepares a particle for the volume calculation. - * - * Simply makes sure all necessary variables are initialized to zero. - * - * @param p The particle to act upon - * @param hs #hydro_space containing hydro specific space information. - */ -__attribute__((always_inline)) INLINE static void hydro_init_part( - struct part* p, const struct hydro_space* hs) { - - p->density.wcount = 0.0f; - p->density.wcount_dh = 0.0f; - p->geometry.volume = 0.0f; - p->geometry.matrix_E[0][0] = 0.0f; - p->geometry.matrix_E[0][1] = 0.0f; - p->geometry.matrix_E[0][2] = 0.0f; - p->geometry.matrix_E[1][0] = 0.0f; - p->geometry.matrix_E[1][1] = 0.0f; - p->geometry.matrix_E[1][2] = 0.0f; - p->geometry.matrix_E[2][0] = 0.0f; - p->geometry.matrix_E[2][1] = 0.0f; - p->geometry.matrix_E[2][2] = 0.0f; - p->geometry.centroid[0] = 0.0f; - p->geometry.centroid[1] = 0.0f; - p->geometry.centroid[2] = 0.0f; -} - -/** - * @brief Finishes the volume calculation. - * - * Multiplies the density and number of neighbours by the appropiate constants - * and adds the self-contribution term. Calculates the volume and uses it to - * update the primitive variables (based on the conserved variables). The latter - * should only be done for active particles. This is okay, since this method is - * only called for active particles. - * - * Multiplies the components of the matrix E with the appropriate constants and - * inverts it. Initializes the variables used during the gradient loop. This - * cannot be done in hydro_prepare_force, since that method is called for all - * particles, and not just the active ones. If we would initialize the - * variables there, gradients for passive particles would be zero, while we - * actually use the old gradients in the flux calculation between active and - * passive particles. - * - * @param p The particle to act upon. - * @param cosmo The cosmological model. - */ -__attribute__((always_inline)) INLINE static void hydro_end_density( - struct part* restrict p, const struct cosmology* cosmo) { - - /* Some smoothing length multiples. */ - const float h = p->h; - const float ih = 1.0f / h; - const float ihdim = pow_dimension(ih); - const float ihdim_plus_one = ihdim * ih; - - /* Final operation on the density. */ - p->density.wcount += kernel_root; - p->density.wcount *= ihdim; - - p->density.wcount_dh -= hydro_dimension * kernel_root; - p->density.wcount_dh *= ihdim_plus_one; - - /* Final operation on the geometry. */ - /* we multiply with the smoothing kernel normalization ih3 and calculate the - * volume */ - const float volume = 1.f / (ihdim * (p->geometry.volume + kernel_root)); - p->geometry.volume = volume; - - /* we multiply with the smoothing kernel normalization */ - p->geometry.matrix_E[0][0] = ihdim * p->geometry.matrix_E[0][0]; - p->geometry.matrix_E[0][1] = ihdim * p->geometry.matrix_E[0][1]; - p->geometry.matrix_E[0][2] = ihdim * p->geometry.matrix_E[0][2]; - p->geometry.matrix_E[1][0] = ihdim * p->geometry.matrix_E[1][0]; - p->geometry.matrix_E[1][1] = ihdim * p->geometry.matrix_E[1][1]; - p->geometry.matrix_E[1][2] = ihdim * p->geometry.matrix_E[1][2]; - p->geometry.matrix_E[2][0] = ihdim * p->geometry.matrix_E[2][0]; - p->geometry.matrix_E[2][1] = ihdim * p->geometry.matrix_E[2][1]; - p->geometry.matrix_E[2][2] = ihdim * p->geometry.matrix_E[2][2]; - - p->geometry.centroid[0] *= kernel_norm; - p->geometry.centroid[1] *= kernel_norm; - p->geometry.centroid[2] *= kernel_norm; - - p->geometry.centroid[0] /= p->density.wcount; - p->geometry.centroid[1] /= p->density.wcount; - p->geometry.centroid[2] /= p->density.wcount; - - /* Check the condition number to see if we have a stable geometry. */ - float condition_number_E = 0.0f; - int i, j; - for (i = 0; i < 3; ++i) { - for (j = 0; j < 3; ++j) { - condition_number_E += - p->geometry.matrix_E[i][j] * p->geometry.matrix_E[i][j]; - } - } - - invert_dimension_by_dimension_matrix(p->geometry.matrix_E); - - float condition_number_Einv = 0.0f; - for (i = 0; i < 3; ++i) { - for (j = 0; j < 3; ++j) { - condition_number_Einv += - p->geometry.matrix_E[i][j] * p->geometry.matrix_E[i][j]; - } - } - - float condition_number = - hydro_dimension_inv * sqrtf(condition_number_E * condition_number_Einv); - - if (condition_number > const_gizmo_max_condition_number && - p->density.wcorr > const_gizmo_min_wcorr) { -#ifdef GIZMO_PATHOLOGICAL_ERROR - error("Condition number larger than %g (%g)!", - const_gizmo_max_condition_number, condition_number); -#endif -#ifdef GIZMO_PATHOLOGICAL_WARNING - message("Condition number too large: %g (> %g, p->id: %llu)!", - condition_number, const_gizmo_max_condition_number, p->id); -#endif - /* add a correction to the number of neighbours for this particle */ - p->density.wcorr *= const_gizmo_w_correction_factor; - } - - hydro_gradients_init(p); - - /* compute primitive variables */ - /* eqns (3)-(5) */ - const float m = p->conserved.mass; - -#ifdef SWIFT_DEBUG_CHECKS - if (m < 0.) { - error("Mass is negative!"); - } - - if (volume == 0.) { - error("Volume is 0!"); - } -#endif - - // MATTHIEU: Bert is this correct? Do we need cosmology terms here? - float momentum[3]; - momentum[0] = p->conserved.momentum[0]; - momentum[1] = p->conserved.momentum[1]; - momentum[2] = p->conserved.momentum[2]; - p->primitives.rho = m / volume; - if (m == 0.) { - p->primitives.v[0] = 0.; - p->primitives.v[1] = 0.; - p->primitives.v[2] = 0.; - } else { - p->primitives.v[0] = momentum[0] / m; - p->primitives.v[1] = momentum[1] / m; - p->primitives.v[2] = momentum[2] / m; - } - -#ifdef EOS_ISOTHERMAL_GAS - /* although the pressure is not formally used anywhere if an isothermal eos - has been selected, we still make sure it is set to the correct value */ - p->primitives.P = gas_pressure_from_internal_energy(p->primitives.rho, 0.); -#else - - float energy = p->conserved.energy; - -#ifdef GIZMO_TOTAL_ENERGY - /* subtract the kinetic energy; we want the thermal energy */ - energy -= 0.5f * (momentum[0] * p->primitives.v[0] + - momentum[1] * p->primitives.v[1] + - momentum[2] * p->primitives.v[2]); -#endif - - /* energy contains the total thermal energy, we want the specific energy. - this is why we divide by the volume, and not by the density */ - p->primitives.P = hydro_gamma_minus_one * energy / volume; -#endif - - /* sanity checks */ - gizmo_check_physical_quantities("density", "pressure", p->primitives.rho, - p->primitives.v[0], p->primitives.v[1], - p->primitives.v[2], p->primitives.P); - -#ifdef GIZMO_LLOYD_ITERATION - /* overwrite primitive variables to make sure they still have safe values */ - p->primitives.rho = 1.; - p->primitives.v[0] = 0.; - p->primitives.v[1] = 0.; - p->primitives.v[2] = 0.; - p->primitives.P = 1.; -#endif - - /* Add a correction factor to wcount (to force a neighbour number increase if - the geometry matrix is close to singular) */ - p->density.wcount *= p->density.wcorr; - p->density.wcount_dh *= p->density.wcorr; -} - -/** - * @brief Sets all particle fields to sensible values when the #part has 0 ngbs. - * - * @param p The particle to act upon - * @param xp The extended particle data to act upon - * @param cosmo The cosmological model. - */ -__attribute__((always_inline)) INLINE static void hydro_part_has_no_neighbours( - struct part* restrict p, struct xpart* restrict xp, - const struct cosmology* cosmo) { - - /* Some smoothing length multiples. */ - const float h = p->h; - const float h_inv = 1.0f / h; /* 1/h */ - const float h_inv_dim = pow_dimension(h_inv); /* 1/h^d */ - - /* Re-set problematic values */ - p->density.wcount = kernel_root * h_inv_dim; - p->density.wcount_dh = 0.f; - p->geometry.volume = 1.0f; - p->geometry.matrix_E[0][0] = 1.0f; - p->geometry.matrix_E[0][1] = 0.0f; - p->geometry.matrix_E[0][2] = 0.0f; - p->geometry.matrix_E[1][0] = 0.0f; - p->geometry.matrix_E[1][1] = 1.0f; - p->geometry.matrix_E[1][2] = 0.0f; - p->geometry.matrix_E[2][0] = 0.0f; - p->geometry.matrix_E[2][1] = 0.0f; - p->geometry.matrix_E[2][2] = 1.0f; - /* centroid is relative w.r.t. particle position */ - /* by setting the centroid to 0.0f, we make sure no velocity correction is - applied */ - p->geometry.centroid[0] = 0.0f; - p->geometry.centroid[1] = 0.0f; - p->geometry.centroid[2] = 0.0f; -} - -/** - * @brief Prepare a particle for the gradient calculation. - * - * This function is called after the density loop and before the gradient loop. - * - * We use it to set the physical timestep for the particle and to copy the - * actual velocities, which we need to boost our interfaces during the flux - * calculation. We also initialize the variables used for the time step - * calculation. - * - * @param p The particle to act upon. - * @param xp The extended particle data to act upon. - * @param cosmo The cosmological model. - * @param hydro_props Hydrodynamic properties. - */ -__attribute__((always_inline)) INLINE static void hydro_prepare_gradient( - struct part* restrict p, struct xpart* restrict xp, - const struct cosmology* cosmo, const struct hydro_props* hydro_props) { - - /* Initialize time step criterion variables */ - p->timestepvars.vmax = 0.; - - // MATTHIEU: Bert is this correct? Do we need cosmology terms here? - - /* Set the actual velocity of the particle */ - hydro_velocities_prepare_force(p, xp); -} - -/** - * @brief Finishes the gradient calculation. - * - * Just a wrapper around hydro_gradients_finalize, which can be an empty method, - * in which case no gradients are used. - * - * @param p The particle to act upon. - */ -__attribute__((always_inline)) INLINE static void hydro_end_gradient( - struct part* p) { - - hydro_gradients_finalize(p); - -#ifdef GIZMO_LLOYD_ITERATION - /* reset the gradients to zero, as we don't want them */ - hydro_gradients_init(p); -#endif -} - -/** - * @brief Prepare a particle for the force calculation. - * - * This function is called in the ghost task to convert some quantities coming - * from the density loop over neighbours into quantities ready to be used in the - * force loop over neighbours. Quantities are typically read from the density - * sub-structure and written to the force sub-structure. - * Examples of calculations done here include the calculation of viscosity term - * constants, thermal conduction terms, hydro conversions, etc. - * - * @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 struct hydro_props* hydro_props, - const float dt_alpha) { - - /* Initialise values that are used in the force loop */ - p->gravity.mflux[0] = 0.0f; - p->gravity.mflux[1] = 0.0f; - p->gravity.mflux[2] = 0.0f; - - p->conserved.flux.mass = 0.0f; - p->conserved.flux.momentum[0] = 0.0f; - p->conserved.flux.momentum[1] = 0.0f; - p->conserved.flux.momentum[2] = 0.0f; - p->conserved.flux.energy = 0.0f; -} - -/** - * @brief Reset acceleration fields of a particle - * - * This is actually not necessary for GIZMO, since we just set the accelerations - * after the flux calculation. - * - * @param p The particle to act upon. - */ -__attribute__((always_inline)) INLINE static void hydro_reset_acceleration( - struct part* p) { - - /* Reset the acceleration. */ - p->a_hydro[0] = 0.0f; - p->a_hydro[1] = 0.0f; - p->a_hydro[2] = 0.0f; - - /* Reset the time derivatives. */ - p->force.h_dt = 0.0f; -} - -/** - * @brief Resets the variables that are required for a gradient calculation. - * - * This function is called after hydro_prepare_gradient. - * - * @param p The particle to act upon. - * @param xp The extended particle data to act upon. - * @param cosmo The cosmological model. - */ -__attribute__((always_inline)) INLINE static void hydro_reset_gradient( - struct part* restrict p) {} - -/** - * @brief Sets the values to be predicted in the drifts to their values at a - * kick time - * - * @param p The particle. - * @param xp The extended data of this particle. - * @param cosmo The cosmological model. - */ -__attribute__((always_inline)) INLINE static void hydro_reset_predicted_values( - struct part* restrict p, const struct xpart* restrict xp, - const struct cosmology* cosmo) { - // MATTHIEU: Apply the entropy floor here. -} - -/** - * @brief Converts the hydrodynamic variables from the initial condition file to - * conserved variables that can be used during the integration - * - * We no longer do this, as the mass needs to be provided in the initial - * condition file, and the mass alone is enough to initialize all conserved - * variables. This is now done in hydro_first_init_part. - * - * @param p The particle to act upon. - */ -__attribute__((always_inline)) INLINE static void hydro_convert_quantities( - struct part* p, struct xpart* xp, const struct cosmology* cosmo, - const struct hydro_props* hydro_props) { - - p->conserved.energy /= cosmo->a_factor_internal_energy; -} - -/** - * @brief Extra operations to be done during the drift - * - * @param p Particle to act upon. - * @param xp The extended particle data to act upon. - * @param dt_drift The drift time-step for positions. - * @param dt_therm The drift time-step for thermal quantities. - */ -__attribute__((always_inline)) INLINE static void hydro_predict_extra( - struct part* p, struct xpart* xp, float dt_drift, float dt_therm, - const struct cosmology* cosmo, const struct hydro_props* hydro_props, - const struct entropy_floor_properties* floor_props) { - -#ifdef GIZMO_LLOYD_ITERATION - return; -#endif - - const float h_inv = 1.0f / p->h; - - /* Predict smoothing length */ - const float w1 = p->force.h_dt * h_inv * dt_drift; - float h_corr; - if (fabsf(w1) < 0.2f) - h_corr = approx_expf(w1); /* 4th order expansion of exp(w) */ - else - h_corr = expf(w1); - - /* Limit the smoothing length correction (and make sure it is always - positive). */ - if (h_corr < 2.0f && h_corr > 0.) { - p->h *= h_corr; - } - - /* drift the primitive variables based on the old fluxes */ - if (p->geometry.volume > 0.) { - p->primitives.rho += p->conserved.flux.mass * dt_therm / p->geometry.volume; - } - - if (p->conserved.mass > 0.) { - p->primitives.v[0] += - p->conserved.flux.momentum[0] * dt_therm / p->conserved.mass; - p->primitives.v[1] += - p->conserved.flux.momentum[1] * dt_therm / p->conserved.mass; - p->primitives.v[2] += - p->conserved.flux.momentum[2] * dt_therm / p->conserved.mass; - -#if !defined(EOS_ISOTHERMAL_GAS) -#ifdef GIZMO_TOTAL_ENERGY - const float Etot = - p->conserved.energy + p->conserved.flux.energy * dt_therm; - const float v2 = (p->primitives.v[0] * p->primitives.v[0] + - p->primitives.v[1] * p->primitives.v[1] + - p->primitives.v[2] * p->primitives.v[2]); - const float u = (Etot / p->conserved.mass - 0.5 * v2); -#else - const float u = - (p->conserved.energy + p->conserved.flux.energy * dt_therm) / - p->conserved.mass; -#endif - p->primitives.P = hydro_gamma_minus_one * u * p->primitives.rho; -#endif - } - - // MATTHIEU: Apply the entropy floor here. - - /* we use a sneaky way to get the gravitational contribution to the - velocity update */ - p->primitives.v[0] += p->v[0] - xp->v_full[0]; - p->primitives.v[1] += p->v[1] - xp->v_full[1]; - p->primitives.v[2] += p->v[2] - xp->v_full[2]; - -#ifdef SWIFT_DEBUG_CHECKS - if (p->h <= 0.) { - error("Zero or negative smoothing length (%g)!", p->h); - } -#endif - - gizmo_check_physical_quantities("density", "pressure", p->primitives.rho, - p->primitives.v[0], p->primitives.v[1], - p->primitives.v[2], p->primitives.P); -} - -/** - * @brief Set the particle acceleration after the flux loop - * - * We use the new conserved variables to calculate the new velocity of the - * particle, and use that to derive the change of the velocity over the particle - * time step. - * - * If the particle time step is zero, we set the accelerations to zero. This - * should only happen at the start of the simulation. - * - * @param p Particle to act upon. - * @param cosmo The cosmological model. - */ -__attribute__((always_inline)) INLINE static void hydro_end_force( - struct part* p, const struct cosmology* cosmo) { - - /* set the variables that are used to drift the primitive variables */ - - // MATTHIEU: Bert is this correct? Do we need cosmology terms here? - hydro_velocities_end_force(p); -} - -/** - * @brief Extra operations done during the kick - * - * @param p Particle to act upon. - * @param xp Extended particle data to act upon. - * @param dt_therm Thermal energy time-step @f$\frac{dt}{a^2}@f$. - * @param dt_grav Gravity time-step @f$\frac{dt}{a}@f$. - * @param dt_hydro Hydro acceleration time-step - * @f$\frac{dt}{a^{3(\gamma{}-1)}}@f$. - * @param dt_kick_corr Gravity correction time-step @f$adt@f$. - * @param cosmo Cosmology. - * @param hydro_props Additional hydro properties. - * @param floor_props The properties of the entropy floor. - */ -__attribute__((always_inline)) INLINE static void hydro_kick_extra( - struct part* p, struct xpart* xp, float dt_therm, float dt_grav, - float dt_hydro, float dt_kick_corr, const struct cosmology* cosmo, - const struct hydro_props* hydro_props, - const struct entropy_floor_properties* floor_props) { - - float a_grav[3]; - - /* Add gravity. We only do this if we have gravity activated. */ - if (p->gpart) { - /* Retrieve the current value of the gravitational acceleration from the - gpart. We are only allowed to do this because this is the kick. We still - need to check whether gpart exists though.*/ - a_grav[0] = p->gpart->a_grav[0]; - a_grav[1] = p->gpart->a_grav[1]; - a_grav[2] = p->gpart->a_grav[2]; - -#ifdef GIZMO_TOTAL_ENERGY - p->conserved.energy += dt_grav * (p->conserved.momentum[0] * a_grav[0] + - p->conserved.momentum[1] * a_grav[1] + - p->conserved.momentum[2] * a_grav[2]); -#endif - - /* Kick the momentum for half a time step */ - /* Note that this also affects the particle movement, as the velocity for - the particles is set after this. */ - p->conserved.momentum[0] += p->conserved.mass * a_grav[0] * dt_grav; - p->conserved.momentum[1] += p->conserved.mass * a_grav[1] * dt_grav; - p->conserved.momentum[2] += p->conserved.mass * a_grav[2] * dt_grav; - - p->conserved.energy -= - 0.5f * dt_kick_corr * - (p->gravity.mflux[0] * a_grav[0] + p->gravity.mflux[1] * a_grav[1] + - p->gravity.mflux[2] * a_grav[2]); - } - - /* Update conserved variables. */ - p->conserved.mass += p->conserved.flux.mass * dt_therm; - p->conserved.momentum[0] += p->conserved.flux.momentum[0] * dt_therm; - p->conserved.momentum[1] += p->conserved.flux.momentum[1] * dt_therm; - p->conserved.momentum[2] += p->conserved.flux.momentum[2] * dt_therm; -#if defined(EOS_ISOTHERMAL_GAS) - /* We use the EoS equation in a sneaky way here just to get the constant u */ - p->conserved.energy = - p->conserved.mass * gas_internal_energy_from_entropy(0.f, 0.f); -#else - p->conserved.energy += p->conserved.flux.energy * dt_therm; -#endif - -#ifndef HYDRO_GAMMA_5_3 - const float Pcorr = (dt_hydro - dt_therm) * p->geometry.volume; - p->conserved.momentum[0] -= Pcorr * p->primitives.gradients.P[0]; - p->conserved.momentum[1] -= Pcorr * p->primitives.gradients.P[1]; - p->conserved.momentum[2] -= Pcorr * p->primitives.gradients.P[2]; -#ifdef GIZMO_TOTAL_ENERGY - p->conserved.energy -= - Pcorr * (p->primitives.v[0] * p->primitives.gradients.P[0] + - p->primitives.v[1] * p->primitives.gradients.P[1] + - p->primitives.v[2] * p->primitives.gradients.P[2]); -#endif -#endif - - /* Apply the minimal energy limit */ - const float min_energy = - hydro_props->minimal_internal_energy / cosmo->a_factor_internal_energy; - if (p->conserved.energy < min_energy * p->conserved.mass) { - p->conserved.energy = min_energy * p->conserved.mass; - p->conserved.flux.energy = 0.f; - } - - // MATTHIEU: Apply the entropy floor here. - - gizmo_check_physical_quantities( - "mass", "energy", p->conserved.mass, p->conserved.momentum[0], - p->conserved.momentum[1], p->conserved.momentum[2], p->conserved.energy); - -#ifdef SWIFT_DEBUG_CHECKS - /* Note that this check will only have effect if no GIZMO_UNPHYSICAL option - was selected. */ - if (p->conserved.mass < 0.) { - error( - "Negative mass after conserved variables update (mass: %g, dmass: %g)!", - p->conserved.mass, p->conserved.flux.mass); - } - - if (p->conserved.energy < 0.) { - error( - "Negative energy after conserved variables update (energy: %g, " - "denergy: %g)!", - p->conserved.energy, p->conserved.flux.energy); - } -#endif - - if (p->gpart) { - /* Make sure the gpart knows the mass has changed. */ - p->gpart->mass = p->conserved.mass; - } - - hydro_velocities_set(p, xp); - -#ifdef GIZMO_LLOYD_ITERATION - /* reset conserved variables to safe values */ - p->conserved.mass = 1.; - p->conserved.momentum[0] = 0.; - p->conserved.momentum[1] = 0.; - p->conserved.momentum[2] = 0.; - p->conserved.energy = 1.; - - /* set the particle velocities to the Lloyd velocities */ - /* note that centroid is the relative position of the centroid w.r.t. the - particle position (position - centroid) */ - xp->v_full[0] = -p->geometry.centroid[0] / p->force.dt; - xp->v_full[1] = -p->geometry.centroid[1] / p->force.dt; - xp->v_full[2] = -p->geometry.centroid[2] / p->force.dt; - p->v[0] = xp->v_full[0]; - p->v[1] = xp->v_full[1]; - p->v[2] = xp->v_full[2]; -#endif - - /* reset wcorr */ - p->density.wcorr = 1.0f; -} - -/** - * @brief Returns the comoving internal energy of a particle - * - * @param p The particle of interest. - */ -__attribute__((always_inline)) INLINE static float -hydro_get_comoving_internal_energy(const struct part* restrict p) { - - if (p->primitives.rho > 0.) - return gas_internal_energy_from_pressure(p->primitives.rho, - p->primitives.P); - else - return 0.; -} - -/** - * @brief Returns the physical internal energy of a particle - * - * @param p The particle of interest. - * @param xp The extended data of the particle of interest. - * @param cosmo The cosmological model. - */ -__attribute__((always_inline)) INLINE static float -hydro_get_physical_internal_energy(const struct part* restrict p, - const struct xpart* restrict xp, - const struct cosmology* cosmo) { - - return cosmo->a_factor_internal_energy * - 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, /*xp=*/NULL, cosmo); -} - -/** - * @brief Returns the comoving entropy of a particle - * - * @param p The particle of interest. - */ -__attribute__((always_inline)) INLINE static float hydro_get_comoving_entropy( - const struct part* restrict p) { - - if (p->primitives.rho > 0.) { - return gas_entropy_from_pressure(p->primitives.rho, p->primitives.P); - } else { - return 0.; - } -} - -/** - * @brief Returns the physical internal energy of a particle - * - * @param p The particle of interest. - * @param xp The extended data of the particle of interest. - * @param cosmo The cosmological model. - */ -__attribute__((always_inline)) INLINE static float hydro_get_physical_entropy( - const struct part* restrict p, const struct xpart* restrict xp, - const struct cosmology* cosmo) { - - /* Note: no cosmological conversion required here with our choice of - * coordinates. */ - 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 - * - * @param p The particle of interest. - */ -__attribute__((always_inline)) INLINE static float -hydro_get_comoving_soundspeed(const struct part* restrict p) { - - if (p->primitives.rho > 0.) - return gas_soundspeed_from_pressure(p->primitives.rho, p->primitives.P); - else - return 0.; -} - -/** - * @brief Returns the physical sound speed of a particle - * - * @param p The particle of interest. - * @param cosmo The cosmological model. - */ -__attribute__((always_inline)) INLINE static float -hydro_get_physical_soundspeed(const struct part* restrict p, - const struct cosmology* cosmo) { - - return cosmo->a_factor_sound_speed * hydro_get_comoving_soundspeed(p); -} - -/** - * @brief Returns the comoving pressure of a particle - * - * @param p The particle of interest - */ -__attribute__((always_inline)) INLINE static float hydro_get_comoving_pressure( - const struct part* restrict p) { - - return p->primitives.P; -} - -/** - * @brief Returns the comoving pressure of a particle - * - * @param p The particle of interest. - * @param cosmo The cosmological model. - */ -__attribute__((always_inline)) INLINE static float hydro_get_physical_pressure( - const struct part* restrict p, const struct cosmology* cosmo) { - - return cosmo->a_factor_pressure * p->primitives.P; -} - -/** - * @brief Returns the mass of a particle - * - * @param p The particle of interest - */ -__attribute__((always_inline)) INLINE static float hydro_get_mass( - const struct part* restrict p) { - - return p->conserved.mass; -} - -/** - * @brief Sets the mass of a particle - * - * @param p The particle of interest - * @param m The mass to set. - */ -__attribute__((always_inline)) INLINE static void hydro_set_mass( - struct part* restrict p, float m) { - - p->conserved.mass = m; -} - -/** - * @brief Returns the velocities drifted to the current time of a particle. - * - * @param p The particle of interest - * @param xp The extended data of the particle. - * @param dt_kick_hydro The time (for hydro accelerations) since the last kick. - * @param dt_kick_grav The time (for gravity accelerations) since the last kick. - * @param v (return) The velocities at the current time. - */ -__attribute__((always_inline)) INLINE static void hydro_get_drifted_velocities( - const struct part* restrict p, const struct xpart* xp, float dt_kick_hydro, - float dt_kick_grav, float v[3]) { - - if (p->conserved.mass > 0.) { - v[0] = p->primitives.v[0] + - p->conserved.flux.momentum[0] * dt_kick_hydro / p->conserved.mass; - v[1] = p->primitives.v[1] + - p->conserved.flux.momentum[1] * dt_kick_hydro / p->conserved.mass; - v[2] = p->primitives.v[2] + - p->conserved.flux.momentum[2] * dt_kick_hydro / p->conserved.mass; - } else { - v[0] = p->primitives.v[0]; - v[1] = p->primitives.v[1]; - v[2] = p->primitives.v[2]; - } - - // MATTHIEU: Bert is this correct? - v[0] += xp->a_grav[0] * dt_kick_grav; - v[1] += xp->a_grav[1] * dt_kick_grav; - v[2] += xp->a_grav[2] * dt_kick_grav; -} - -/** - * @brief Returns the 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_comoving_internal_energy_dt(const struct part* restrict p) { - - error("Needs implementing"); - return 0.f; -} - -/** - * @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) { - error("Needs implementing"); - return 0.f; -} - -/** - * @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 comoving internal energy. - */ -__attribute__((always_inline)) INLINE static void -hydro_set_comoving_internal_energy_dt(struct part* restrict p, - const float du_dt) { - error("Needs implementing"); -} - -/** - * @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 physical internal energy. - */ -__attribute__((always_inline)) INLINE static void -hydro_set_physical_internal_energy_dt(struct part* restrict p, - const struct cosmology* restrict cosmo, - const float du_dt) { - error("Needs implementing"); -} -/** - * @brief Sets the physical entropy of a particle - * - * @param p The particle of interest. - * @param xp The extended particle data. - * @param cosmo Cosmology data structure - * @param entropy The physical entropy - */ -__attribute__((always_inline)) INLINE static void hydro_set_physical_entropy( - struct part* p, struct xpart* xp, const struct cosmology* cosmo, - const float entropy) { - - error("Needs implementing"); -} - -/** - * @brief Sets the physical internal energy of a particle - * - * @param p The particle of interest. - * @param xp The extended particle data. - * @param cosmo Cosmology data structure - * @param u The physical internal energy - */ -__attribute__((always_inline)) INLINE static void -hydro_set_physical_internal_energy(struct part* p, struct xpart* xp, - const struct cosmology* cosmo, - const float u) { - error("Need implementing"); -} - -/** - * @brief Sets the drifted physical internal energy of a particle - * - * @param p The particle of interest. - * @param cosmo Cosmology data structure - * @param u The physical internal energy - */ -__attribute__((always_inline)) INLINE static void -hydro_set_drifted_physical_internal_energy(struct part* p, - const struct cosmology* cosmo, - const float u) { - error("Need implementing"); -} - -/** - * @brief Update the value of the viscosity alpha for the scheme. - * - * @param p the particle of interest - * @param alpha the new value for the viscosity coefficient. - */ -__attribute__((always_inline)) INLINE static void hydro_set_viscosity_alpha( - struct part* restrict p, float alpha) { - /* Purposefully left empty */ -} - -/** - * @brief Update the value of the viscosity alpha to the - * feedback reset value for the scheme. - * - * @param p the particle of interest - */ -__attribute__((always_inline)) INLINE static void -hydro_diffusive_feedback_reset(struct part* restrict p) { - /* Purposefully left empty */ -} - -/** - * @brief Returns the comoving density of a particle - * - * @param p The particle of interest - */ -__attribute__((always_inline)) INLINE static float hydro_get_comoving_density( - const struct part* restrict p) { - - return p->primitives.rho; -} - -/** - * @brief Returns the physical density of a particle - * - * @param p The particle of interest - * @param cosmo The cosmological model. - */ -__attribute__((always_inline)) INLINE static float hydro_get_physical_density( - const struct part* restrict p, const struct cosmology* cosmo) { - - return cosmo->a3_inv * p->primitives.rho; -} - -/** - * @brief Modifies the thermal state of a particle to the imposed internal - * energy - * - * This overrides the current state of the particle but does *not* change its - * time-derivatives - * - * @param p The particle - * @param u The new internal energy - */ -__attribute__((always_inline)) INLINE static void hydro_set_internal_energy( - struct part* restrict p, float u) { - - /* conserved.energy is NOT the specific energy (u), but the total thermal - energy (u*m) */ - p->conserved.energy = u * p->conserved.mass; -#ifdef GIZMO_TOTAL_ENERGY - /* add the kinetic energy */ - p->conserved.energy += 0.5f * p->conserved.mass * - (p->conserved.momentum[0] * p->primitives.v[0] + - p->conserved.momentum[1] * p->primitives.v[1] + - p->conserved.momentum[2] * p->primitives.v[2]); -#endif - p->primitives.P = hydro_gamma_minus_one * p->primitives.rho * u; -} - -/** - * @brief Modifies the thermal state of a particle to the imposed entropy - * - * This overrides the current state of the particle but does *not* change its - * time-derivatives - * - * @param p The particle - * @param S The new entropy - */ -__attribute__((always_inline)) INLINE static void hydro_set_entropy( - struct part* restrict p, float S) { - - p->conserved.energy = S * pow_gamma_minus_one(p->primitives.rho) * - hydro_one_over_gamma_minus_one * p->conserved.mass; -#ifdef GIZMO_TOTAL_ENERGY - /* add the kinetic energy */ - p->conserved.energy += 0.5f * p->conserved.mass * - (p->conserved.momentum[0] * p->primitives.v[0] + - p->conserved.momentum[1] * p->primitives.v[1] + - p->conserved.momentum[2] * p->primitives.v[2]); -#endif - p->primitives.P = S * pow_gamma(p->primitives.rho); -} - -/** - * @brief Overwrite the initial internal energy of a particle. - * - * Note that in the cases where the thermodynamic variable is not - * internal energy but gets converted later, we must overwrite that - * field. The conversion to the actual variable happens later after - * the initial fake time-step. - * - * @param p The #part to write to. - * @param u_init The new initial internal energy. - */ -__attribute__((always_inline)) INLINE static void -hydro_set_init_internal_energy(struct part* p, float u_init) { - - /* We store the initial energy per unit mass in the energy - * variable as the conversion to energy will be done later, - * in hydro_first_init_part(). */ - p->conserved.energy = u_init; -} - -/** - * @brief Operations performed when a particle gets removed from the - * simulation volume. - * - * @param p The particle. - * @param xp The extended particle data. - */ -__attribute__((always_inline)) INLINE static void hydro_remove_part( - const struct part* p, const struct xpart* xp) {} - -#endif /* SWIFT_GIZMO_MFV_HYDRO_H */ diff --git a/src/hydro/GizmoMFV/hydro_gradients.h b/src/hydro/GizmoMFV/hydro_gradients.h deleted file mode 100644 index 4046e121bad9e329fecc30afb435bffca2815346..0000000000000000000000000000000000000000 --- a/src/hydro/GizmoMFV/hydro_gradients.h +++ /dev/null @@ -1,158 +0,0 @@ -/******************************************************************************* - * This file is part of SWIFT. - * Copyright (c) 2016 Bert Vandenbroucke (bert.vandenbroucke@gmail.com) - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU Lesser General Public License as published - * by the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public License - * along with this program. If not, see <http://www.gnu.org/licenses/>. - * - ******************************************************************************/ - -#ifndef SWIFT_HYDRO_GIZMO_MFV_GRADIENTS_H -#define SWIFT_HYDRO_GIZMO_MFV_GRADIENTS_H - -#include "hydro_slope_limiters.h" -#include "hydro_unphysical.h" -#include "riemann.h" - -#if defined(GRADIENTS_SPH) - -#define HYDRO_GRADIENT_IMPLEMENTATION "SPH gradients (Price 2012)" -#include "hydro_gradients_sph.h" - -#elif defined(GRADIENTS_GIZMO) - -#define HYDRO_GRADIENT_IMPLEMENTATION "GIZMO gradients (Hopkins 2015)" -#include "hydro_gradients_gizmo.h" - -#else - -/* No gradients. Perfectly acceptable, but we have to provide empty functions */ -#define HYDRO_GRADIENT_IMPLEMENTATION "No gradients (first order scheme)" - -/** - * @brief Initialize gradient variables - * - * @param p Particle. - */ -__attribute__((always_inline)) INLINE static void hydro_gradients_init( - struct part *p) {} - -/** - * @brief Gradient calculations done during the neighbour loop - * - * @param r2 Squared distance between the two particles. - * @param dx Distance vector (pi->x - pj->x). - * @param hi Smoothing length of particle i. - * @param hj Smoothing length of particle j. - * @param pi Particle i. - * @param pj Particle j. - */ -__attribute__((always_inline)) INLINE static void hydro_gradients_collect( - float r2, const float *dx, float hi, float hj, struct part *restrict pi, - struct part *restrict pj) {} - -/** - * @brief Gradient calculations done during the neighbour loop: non-symmetric - * version - * - * @param r2 Squared distance between the two particles. - * @param dx Distance vector (pi->x - pj->x). - * @param hi Smoothing length of particle i. - * @param hj Smoothing length of particle j. - * @param pi Particle i. - * @param pj Particle j. - */ -__attribute__((always_inline)) INLINE static void -hydro_gradients_nonsym_collect(float r2, const float *dx, float hi, float hj, - struct part *restrict pi, - struct part *restrict pj) {} - -/** - * @brief Finalize the gradient variables after all data have been collected - * - * @param p Particle. - */ -__attribute__((always_inline)) INLINE static void hydro_gradients_finalize( - struct part *p) {} - -#endif - -/** - * @brief Gradients reconstruction. Is the same for all gradient types (although - * gradients_none does nothing, since all gradients are zero -- are they?). - */ -__attribute__((always_inline)) INLINE static void hydro_gradients_predict( - struct part* restrict pi, struct part* restrict pj, float hi, float hj, - const float* dx, float r, const float* xij_i, float* Wi, float* Wj) { - - /* perform gradient reconstruction in space and time */ - /* Compute interface position (relative to pj, since we don't need the actual - * position) eqn. (8) */ - const float xij_j[3] = {xij_i[0] + dx[0], xij_i[1] + dx[1], xij_i[2] + dx[2]}; - - float dWi[5]; - dWi[0] = pi->primitives.gradients.rho[0] * xij_i[0] + - pi->primitives.gradients.rho[1] * xij_i[1] + - pi->primitives.gradients.rho[2] * xij_i[2]; - dWi[1] = pi->primitives.gradients.v[0][0] * xij_i[0] + - pi->primitives.gradients.v[0][1] * xij_i[1] + - pi->primitives.gradients.v[0][2] * xij_i[2]; - dWi[2] = pi->primitives.gradients.v[1][0] * xij_i[0] + - pi->primitives.gradients.v[1][1] * xij_i[1] + - pi->primitives.gradients.v[1][2] * xij_i[2]; - dWi[3] = pi->primitives.gradients.v[2][0] * xij_i[0] + - pi->primitives.gradients.v[2][1] * xij_i[1] + - pi->primitives.gradients.v[2][2] * xij_i[2]; - dWi[4] = pi->primitives.gradients.P[0] * xij_i[0] + - pi->primitives.gradients.P[1] * xij_i[1] + - pi->primitives.gradients.P[2] * xij_i[2]; - - float dWj[5]; - dWj[0] = pj->primitives.gradients.rho[0] * xij_j[0] + - pj->primitives.gradients.rho[1] * xij_j[1] + - pj->primitives.gradients.rho[2] * xij_j[2]; - dWj[1] = pj->primitives.gradients.v[0][0] * xij_j[0] + - pj->primitives.gradients.v[0][1] * xij_j[1] + - pj->primitives.gradients.v[0][2] * xij_j[2]; - dWj[2] = pj->primitives.gradients.v[1][0] * xij_j[0] + - pj->primitives.gradients.v[1][1] * xij_j[1] + - pj->primitives.gradients.v[1][2] * xij_j[2]; - dWj[3] = pj->primitives.gradients.v[2][0] * xij_j[0] + - pj->primitives.gradients.v[2][1] * xij_j[1] + - pj->primitives.gradients.v[2][2] * xij_j[2]; - dWj[4] = pj->primitives.gradients.P[0] * xij_j[0] + - pj->primitives.gradients.P[1] * xij_j[1] + - pj->primitives.gradients.P[2] * xij_j[2]; - - /* Apply the slope limiter at this interface */ - hydro_slope_limit_face(Wi, Wj, dWi, dWj, xij_i, xij_j, r); - - Wi[0] += dWi[0]; - Wi[1] += dWi[1]; - Wi[2] += dWi[2]; - Wi[3] += dWi[3]; - Wi[4] += dWi[4]; - - Wj[0] += dWj[0]; - Wj[1] += dWj[1]; - Wj[2] += dWj[2]; - Wj[3] += dWj[3]; - Wj[4] += dWj[4]; - - gizmo_check_physical_quantities("density", "pressure", Wi[0], Wi[1], Wi[2], - Wi[3], Wi[4]); - gizmo_check_physical_quantities("density", "pressure", Wj[0], Wj[1], Wj[2], - Wj[3], Wj[4]); -} - -#endif /* SWIFT_HYDRO_GIZMO_MFV_GRADIENTS_H */ diff --git a/src/hydro/GizmoMFV/hydro_gradients_gizmo.h b/src/hydro/GizmoMFV/hydro_gradients_gizmo.h deleted file mode 100644 index 2592f46da9a8c118d18beba933f98f477ec5a3b2..0000000000000000000000000000000000000000 --- a/src/hydro/GizmoMFV/hydro_gradients_gizmo.h +++ /dev/null @@ -1,488 +0,0 @@ -/******************************************************************************* - * This file is part of SWIFT. - * Copyright (c) 2016 Bert Vandenbroucke (bert.vandenbroucke@gmail.com) - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU Lesser General Public License as published - * by the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public License - * along with this program. If not, see <http://www.gnu.org/licenses/>. - * - ******************************************************************************/ - -/** - * @brief Initialize gradient variables - * - * @param p Particle. - */ -#ifndef SWIFT_GIZMO_MFV_HYDRO_GRADIENTS_H -#define SWIFT_GIZMO_MFV_HYDRO_GRADIENTS_H - -__attribute__((always_inline)) INLINE static void hydro_gradients_init( - struct part *p) { - - p->primitives.gradients.rho[0] = 0.0f; - p->primitives.gradients.rho[1] = 0.0f; - p->primitives.gradients.rho[2] = 0.0f; - - p->primitives.gradients.v[0][0] = 0.0f; - p->primitives.gradients.v[0][1] = 0.0f; - p->primitives.gradients.v[0][2] = 0.0f; - - p->primitives.gradients.v[1][0] = 0.0f; - p->primitives.gradients.v[1][1] = 0.0f; - p->primitives.gradients.v[1][2] = 0.0f; - - p->primitives.gradients.v[2][0] = 0.0f; - p->primitives.gradients.v[2][1] = 0.0f; - p->primitives.gradients.v[2][2] = 0.0f; - - p->primitives.gradients.P[0] = 0.0f; - p->primitives.gradients.P[1] = 0.0f; - p->primitives.gradients.P[2] = 0.0f; - - hydro_slope_limit_cell_init(p); -} - -/** - * @brief Gradient calculations done during the neighbour loop - * - * @param r2 Squared distance between the two particles. - * @param dx Distance vector (pi->x - pj->x). - * @param hi Smoothing length of particle i. - * @param hj Smoothing length of particle j. - * @param pi Particle i. - * @param pj Particle j. - */ -__attribute__((always_inline)) INLINE static void hydro_gradients_collect( - float r2, const float *dx, float hi, float hj, struct part *restrict pi, - struct part *restrict pj) { - - const float r_inv = 1.f / sqrtf(r2); - const float r = r2 * r_inv; - - float wi, wj, wi_dx, wj_dx; - float Bi[3][3]; - float Bj[3][3]; - float Wi[5], Wj[5]; - - /* Initialize local variables */ - for (int k = 0; k < 3; k++) { - for (int l = 0; l < 3; l++) { - Bi[k][l] = pi->geometry.matrix_E[k][l]; - Bj[k][l] = pj->geometry.matrix_E[k][l]; - } - } - Wi[0] = pi->primitives.rho; - Wi[1] = pi->primitives.v[0]; - Wi[2] = pi->primitives.v[1]; - Wi[3] = pi->primitives.v[2]; - Wi[4] = pi->primitives.P; - Wj[0] = pj->primitives.rho; - Wj[1] = pj->primitives.v[0]; - Wj[2] = pj->primitives.v[1]; - Wj[3] = pj->primitives.v[2]; - Wj[4] = pj->primitives.P; - - /* Compute kernel of pi. */ - const float hi_inv = 1.f / hi; - const float xi = r * hi_inv; - kernel_deval(xi, &wi, &wi_dx); - - if (pi->density.wcorr > const_gizmo_min_wcorr) { - /* Compute gradients for pi */ - /* there is a sign difference w.r.t. eqn. (6) because of the inverse - * definition of dx */ - pi->primitives.gradients.rho[0] += - (Wi[0] - Wj[0]) * wi * - (Bi[0][0] * dx[0] + Bi[0][1] * dx[1] + Bi[0][2] * dx[2]); - pi->primitives.gradients.rho[1] += - (Wi[0] - Wj[0]) * wi * - (Bi[1][0] * dx[0] + Bi[1][1] * dx[1] + Bi[1][2] * dx[2]); - pi->primitives.gradients.rho[2] += - (Wi[0] - Wj[0]) * wi * - (Bi[2][0] * dx[0] + Bi[2][1] * dx[1] + Bi[2][2] * dx[2]); - - pi->primitives.gradients.v[0][0] += - (Wi[1] - Wj[1]) * wi * - (Bi[0][0] * dx[0] + Bi[0][1] * dx[1] + Bi[0][2] * dx[2]); - pi->primitives.gradients.v[0][1] += - (Wi[1] - Wj[1]) * wi * - (Bi[1][0] * dx[0] + Bi[1][1] * dx[1] + Bi[1][2] * dx[2]); - pi->primitives.gradients.v[0][2] += - (Wi[1] - Wj[1]) * wi * - (Bi[2][0] * dx[0] + Bi[2][1] * dx[1] + Bi[2][2] * dx[2]); - pi->primitives.gradients.v[1][0] += - (Wi[2] - Wj[2]) * wi * - (Bi[0][0] * dx[0] + Bi[0][1] * dx[1] + Bi[0][2] * dx[2]); - pi->primitives.gradients.v[1][1] += - (Wi[2] - Wj[2]) * wi * - (Bi[1][0] * dx[0] + Bi[1][1] * dx[1] + Bi[1][2] * dx[2]); - pi->primitives.gradients.v[1][2] += - (Wi[2] - Wj[2]) * wi * - (Bi[2][0] * dx[0] + Bi[2][1] * dx[1] + Bi[2][2] * dx[2]); - pi->primitives.gradients.v[2][0] += - (Wi[3] - Wj[3]) * wi * - (Bi[0][0] * dx[0] + Bi[0][1] * dx[1] + Bi[0][2] * dx[2]); - pi->primitives.gradients.v[2][1] += - (Wi[3] - Wj[3]) * wi * - (Bi[1][0] * dx[0] + Bi[1][1] * dx[1] + Bi[1][2] * dx[2]); - pi->primitives.gradients.v[2][2] += - (Wi[3] - Wj[3]) * wi * - (Bi[2][0] * dx[0] + Bi[2][1] * dx[1] + Bi[2][2] * dx[2]); - - pi->primitives.gradients.P[0] += - (Wi[4] - Wj[4]) * wi * - (Bi[0][0] * dx[0] + Bi[0][1] * dx[1] + Bi[0][2] * dx[2]); - pi->primitives.gradients.P[1] += - (Wi[4] - Wj[4]) * wi * - (Bi[1][0] * dx[0] + Bi[1][1] * dx[1] + Bi[1][2] * dx[2]); - pi->primitives.gradients.P[2] += - (Wi[4] - Wj[4]) * wi * - (Bi[2][0] * dx[0] + Bi[2][1] * dx[1] + Bi[2][2] * dx[2]); - - } else { - /* The gradient matrix was not well-behaved, switch to SPH gradients */ - - pi->primitives.gradients.rho[0] -= - wi_dx * dx[0] * (pi->primitives.rho - pj->primitives.rho) * r_inv; - pi->primitives.gradients.rho[1] -= - wi_dx * dx[1] * (pi->primitives.rho - pj->primitives.rho) * r_inv; - pi->primitives.gradients.rho[2] -= - wi_dx * dx[2] * (pi->primitives.rho - pj->primitives.rho) * r_inv; - - pi->primitives.gradients.v[0][0] -= - wi_dx * dx[0] * (pi->primitives.v[0] - pj->primitives.v[0]) * r_inv; - pi->primitives.gradients.v[0][1] -= - wi_dx * dx[1] * (pi->primitives.v[0] - pj->primitives.v[0]) * r_inv; - pi->primitives.gradients.v[0][2] -= - wi_dx * dx[2] * (pi->primitives.v[0] - pj->primitives.v[0]) * r_inv; - - pi->primitives.gradients.v[1][0] -= - wi_dx * dx[0] * (pi->primitives.v[1] - pj->primitives.v[1]) * r_inv; - pi->primitives.gradients.v[1][1] -= - wi_dx * dx[1] * (pi->primitives.v[1] - pj->primitives.v[1]) * r_inv; - pi->primitives.gradients.v[1][2] -= - wi_dx * dx[2] * (pi->primitives.v[1] - pj->primitives.v[1]) * r_inv; - - pi->primitives.gradients.v[2][0] -= - wi_dx * dx[0] * (pi->primitives.v[2] - pj->primitives.v[2]) * r_inv; - pi->primitives.gradients.v[2][1] -= - wi_dx * dx[1] * (pi->primitives.v[2] - pj->primitives.v[2]) * r_inv; - pi->primitives.gradients.v[2][2] -= - wi_dx * dx[2] * (pi->primitives.v[2] - pj->primitives.v[2]) * r_inv; - - pi->primitives.gradients.P[0] -= - wi_dx * dx[0] * (pi->primitives.P - pj->primitives.P) * r_inv; - pi->primitives.gradients.P[1] -= - wi_dx * dx[1] * (pi->primitives.P - pj->primitives.P) * r_inv; - pi->primitives.gradients.P[2] -= - wi_dx * dx[2] * (pi->primitives.P - pj->primitives.P) * r_inv; - } - - hydro_slope_limit_cell_collect(pi, pj, r); - - /* Compute kernel of pj. */ - const float hj_inv = 1.f / hj; - const float xj = r * hj_inv; - kernel_deval(xj, &wj, &wj_dx); - - if (pj->density.wcorr > const_gizmo_min_wcorr) { - /* Compute gradients for pj */ - /* there is no sign difference w.r.t. eqn. (6) because dx is now what we - * want - * it to be */ - pj->primitives.gradients.rho[0] += - (Wi[0] - Wj[0]) * wj * - (Bj[0][0] * dx[0] + Bj[0][1] * dx[1] + Bj[0][2] * dx[2]); - pj->primitives.gradients.rho[1] += - (Wi[0] - Wj[0]) * wj * - (Bj[1][0] * dx[0] + Bj[1][1] * dx[1] + Bj[1][2] * dx[2]); - pj->primitives.gradients.rho[2] += - (Wi[0] - Wj[0]) * wj * - (Bj[2][0] * dx[0] + Bj[2][1] * dx[1] + Bj[2][2] * dx[2]); - - pj->primitives.gradients.v[0][0] += - (Wi[1] - Wj[1]) * wj * - (Bj[0][0] * dx[0] + Bj[0][1] * dx[1] + Bj[0][2] * dx[2]); - pj->primitives.gradients.v[0][1] += - (Wi[1] - Wj[1]) * wj * - (Bj[1][0] * dx[0] + Bj[1][1] * dx[1] + Bj[1][2] * dx[2]); - pj->primitives.gradients.v[0][2] += - (Wi[1] - Wj[1]) * wj * - (Bj[2][0] * dx[0] + Bj[2][1] * dx[1] + Bj[2][2] * dx[2]); - pj->primitives.gradients.v[1][0] += - (Wi[2] - Wj[2]) * wj * - (Bj[0][0] * dx[0] + Bj[0][1] * dx[1] + Bj[0][2] * dx[2]); - pj->primitives.gradients.v[1][1] += - (Wi[2] - Wj[2]) * wj * - (Bj[1][0] * dx[0] + Bj[1][1] * dx[1] + Bj[1][2] * dx[2]); - pj->primitives.gradients.v[1][2] += - (Wi[2] - Wj[2]) * wj * - (Bj[2][0] * dx[0] + Bj[2][1] * dx[1] + Bj[2][2] * dx[2]); - pj->primitives.gradients.v[2][0] += - (Wi[3] - Wj[3]) * wj * - (Bj[0][0] * dx[0] + Bj[0][1] * dx[1] + Bj[0][2] * dx[2]); - pj->primitives.gradients.v[2][1] += - (Wi[3] - Wj[3]) * wj * - (Bj[1][0] * dx[0] + Bj[1][1] * dx[1] + Bj[1][2] * dx[2]); - pj->primitives.gradients.v[2][2] += - (Wi[3] - Wj[3]) * wj * - (Bj[2][0] * dx[0] + Bj[2][1] * dx[1] + Bj[2][2] * dx[2]); - - pj->primitives.gradients.P[0] += - (Wi[4] - Wj[4]) * wj * - (Bj[0][0] * dx[0] + Bj[0][1] * dx[1] + Bj[0][2] * dx[2]); - pj->primitives.gradients.P[1] += - (Wi[4] - Wj[4]) * wj * - (Bj[1][0] * dx[0] + Bj[1][1] * dx[1] + Bj[1][2] * dx[2]); - pj->primitives.gradients.P[2] += - (Wi[4] - Wj[4]) * wj * - (Bj[2][0] * dx[0] + Bj[2][1] * dx[1] + Bj[2][2] * dx[2]); - - } else { - /* SPH gradients */ - - pj->primitives.gradients.rho[0] -= - wj_dx * dx[0] * (pi->primitives.rho - pj->primitives.rho) * r_inv; - pj->primitives.gradients.rho[1] -= - wj_dx * dx[1] * (pi->primitives.rho - pj->primitives.rho) * r_inv; - pj->primitives.gradients.rho[2] -= - wj_dx * dx[2] * (pi->primitives.rho - pj->primitives.rho) * r_inv; - - pj->primitives.gradients.v[0][0] -= - wj_dx * dx[0] * (pi->primitives.v[0] - pj->primitives.v[0]) * r_inv; - pj->primitives.gradients.v[0][1] -= - wj_dx * dx[1] * (pi->primitives.v[0] - pj->primitives.v[0]) * r_inv; - pj->primitives.gradients.v[0][2] -= - wj_dx * dx[2] * (pi->primitives.v[0] - pj->primitives.v[0]) * r_inv; - - pj->primitives.gradients.v[1][0] -= - wj_dx * dx[0] * (pi->primitives.v[1] - pj->primitives.v[1]) * r_inv; - pj->primitives.gradients.v[1][1] -= - wj_dx * dx[1] * (pi->primitives.v[1] - pj->primitives.v[1]) * r_inv; - pj->primitives.gradients.v[1][2] -= - wj_dx * dx[2] * (pi->primitives.v[1] - pj->primitives.v[1]) * r_inv; - pj->primitives.gradients.v[2][0] -= - wj_dx * dx[0] * (pi->primitives.v[2] - pj->primitives.v[2]) * r_inv; - pj->primitives.gradients.v[2][1] -= - wj_dx * dx[1] * (pi->primitives.v[2] - pj->primitives.v[2]) * r_inv; - pj->primitives.gradients.v[2][2] -= - wj_dx * dx[2] * (pi->primitives.v[2] - pj->primitives.v[2]) * r_inv; - - pj->primitives.gradients.P[0] -= - wj_dx * dx[0] * (pi->primitives.P - pj->primitives.P) * r_inv; - pj->primitives.gradients.P[1] -= - wj_dx * dx[1] * (pi->primitives.P - pj->primitives.P) * r_inv; - pj->primitives.gradients.P[2] -= - wj_dx * dx[2] * (pi->primitives.P - pj->primitives.P) * r_inv; - } - - hydro_slope_limit_cell_collect(pj, pi, r); -} - -/** - * @brief Gradient calculations done during the neighbour loop - * - * @param r2 Squared distance between the two particles. - * @param dx Distance vector (pi->x - pj->x). - * @param hi Smoothing length of particle i. - * @param hj Smoothing length of particle j. - * @param pi Particle i. - * @param pj Particle j. - */ -__attribute__((always_inline)) INLINE static void -hydro_gradients_nonsym_collect(float r2, const float *dx, float hi, float hj, - struct part *restrict pi, - struct part *restrict pj) { - - const float r_inv = 1.f / sqrtf(r2); - const float r = r2 * r_inv; - - float Bi[3][3]; - float Wi[5], Wj[5]; - - /* Initialize local variables */ - for (int k = 0; k < 3; k++) { - for (int l = 0; l < 3; l++) { - Bi[k][l] = pi->geometry.matrix_E[k][l]; - } - } - Wi[0] = pi->primitives.rho; - Wi[1] = pi->primitives.v[0]; - Wi[2] = pi->primitives.v[1]; - Wi[3] = pi->primitives.v[2]; - Wi[4] = pi->primitives.P; - Wj[0] = pj->primitives.rho; - Wj[1] = pj->primitives.v[0]; - Wj[2] = pj->primitives.v[1]; - Wj[3] = pj->primitives.v[2]; - Wj[4] = pj->primitives.P; - - /* Compute kernel of pi. */ - float wi, wi_dx; - const float hi_inv = 1.f / hi; - const float xi = r * hi_inv; - kernel_deval(xi, &wi, &wi_dx); - - if (pi->density.wcorr > const_gizmo_min_wcorr) { - /* Compute gradients for pi */ - /* there is a sign difference w.r.t. eqn. (6) because of the inverse - * definition of dx */ - pi->primitives.gradients.rho[0] += - (Wi[0] - Wj[0]) * wi * - (Bi[0][0] * dx[0] + Bi[0][1] * dx[1] + Bi[0][2] * dx[2]); - pi->primitives.gradients.rho[1] += - (Wi[0] - Wj[0]) * wi * - (Bi[1][0] * dx[0] + Bi[1][1] * dx[1] + Bi[1][2] * dx[2]); - pi->primitives.gradients.rho[2] += - (Wi[0] - Wj[0]) * wi * - (Bi[2][0] * dx[0] + Bi[2][1] * dx[1] + Bi[2][2] * dx[2]); - - pi->primitives.gradients.v[0][0] += - (Wi[1] - Wj[1]) * wi * - (Bi[0][0] * dx[0] + Bi[0][1] * dx[1] + Bi[0][2] * dx[2]); - pi->primitives.gradients.v[0][1] += - (Wi[1] - Wj[1]) * wi * - (Bi[1][0] * dx[0] + Bi[1][1] * dx[1] + Bi[1][2] * dx[2]); - pi->primitives.gradients.v[0][2] += - (Wi[1] - Wj[1]) * wi * - (Bi[2][0] * dx[0] + Bi[2][1] * dx[1] + Bi[2][2] * dx[2]); - pi->primitives.gradients.v[1][0] += - (Wi[2] - Wj[2]) * wi * - (Bi[0][0] * dx[0] + Bi[0][1] * dx[1] + Bi[0][2] * dx[2]); - pi->primitives.gradients.v[1][1] += - (Wi[2] - Wj[2]) * wi * - (Bi[1][0] * dx[0] + Bi[1][1] * dx[1] + Bi[1][2] * dx[2]); - pi->primitives.gradients.v[1][2] += - (Wi[2] - Wj[2]) * wi * - (Bi[2][0] * dx[0] + Bi[2][1] * dx[1] + Bi[2][2] * dx[2]); - pi->primitives.gradients.v[2][0] += - (Wi[3] - Wj[3]) * wi * - (Bi[0][0] * dx[0] + Bi[0][1] * dx[1] + Bi[0][2] * dx[2]); - pi->primitives.gradients.v[2][1] += - (Wi[3] - Wj[3]) * wi * - (Bi[1][0] * dx[0] + Bi[1][1] * dx[1] + Bi[1][2] * dx[2]); - pi->primitives.gradients.v[2][2] += - (Wi[3] - Wj[3]) * wi * - (Bi[2][0] * dx[0] + Bi[2][1] * dx[1] + Bi[2][2] * dx[2]); - - pi->primitives.gradients.P[0] += - (Wi[4] - Wj[4]) * wi * - (Bi[0][0] * dx[0] + Bi[0][1] * dx[1] + Bi[0][2] * dx[2]); - pi->primitives.gradients.P[1] += - (Wi[4] - Wj[4]) * wi * - (Bi[1][0] * dx[0] + Bi[1][1] * dx[1] + Bi[1][2] * dx[2]); - pi->primitives.gradients.P[2] += - (Wi[4] - Wj[4]) * wi * - (Bi[2][0] * dx[0] + Bi[2][1] * dx[1] + Bi[2][2] * dx[2]); - - } else { - /* Gradient matrix is not well-behaved, switch to SPH gradients */ - - pi->primitives.gradients.rho[0] -= - wi_dx * dx[0] * (pi->primitives.rho - pj->primitives.rho) * r_inv; - pi->primitives.gradients.rho[1] -= - wi_dx * dx[1] * (pi->primitives.rho - pj->primitives.rho) * r_inv; - pi->primitives.gradients.rho[2] -= - wi_dx * dx[2] * (pi->primitives.rho - pj->primitives.rho) * r_inv; - - pi->primitives.gradients.v[0][0] -= - wi_dx * dx[0] * (pi->primitives.v[0] - pj->primitives.v[0]) * r_inv; - pi->primitives.gradients.v[0][1] -= - wi_dx * dx[1] * (pi->primitives.v[0] - pj->primitives.v[0]) * r_inv; - pi->primitives.gradients.v[0][2] -= - wi_dx * dx[2] * (pi->primitives.v[0] - pj->primitives.v[0]) * r_inv; - pi->primitives.gradients.v[1][0] -= - wi_dx * dx[0] * (pi->primitives.v[1] - pj->primitives.v[1]) * r_inv; - pi->primitives.gradients.v[1][1] -= - wi_dx * dx[1] * (pi->primitives.v[1] - pj->primitives.v[1]) * r_inv; - pi->primitives.gradients.v[1][2] -= - wi_dx * dx[2] * (pi->primitives.v[1] - pj->primitives.v[1]) * r_inv; - - pi->primitives.gradients.v[2][0] -= - wi_dx * dx[0] * (pi->primitives.v[2] - pj->primitives.v[2]) * r_inv; - pi->primitives.gradients.v[2][1] -= - wi_dx * dx[1] * (pi->primitives.v[2] - pj->primitives.v[2]) * r_inv; - pi->primitives.gradients.v[2][2] -= - wi_dx * dx[2] * (pi->primitives.v[2] - pj->primitives.v[2]) * r_inv; - - pi->primitives.gradients.P[0] -= - wi_dx * dx[0] * (pi->primitives.P - pj->primitives.P) * r_inv; - pi->primitives.gradients.P[1] -= - wi_dx * dx[1] * (pi->primitives.P - pj->primitives.P) * r_inv; - pi->primitives.gradients.P[2] -= - wi_dx * dx[2] * (pi->primitives.P - pj->primitives.P) * r_inv; - } - - hydro_slope_limit_cell_collect(pi, pj, r); -} - -/** - * @brief Finalize the gradient variables after all data have been collected - * - * @param p Particle. - */ -__attribute__((always_inline)) INLINE static void hydro_gradients_finalize( - struct part *p) { - - /* add kernel normalization to gradients */ - const float volume = p->geometry.volume; - const float h = p->h; - const float h_inv = 1.0f / h; - const float ihdim = pow_dimension(h_inv); - const float ihdimp1 = pow_dimension_plus_one(h_inv); - - if (p->density.wcorr > const_gizmo_min_wcorr) { - p->primitives.gradients.rho[0] *= ihdim; - p->primitives.gradients.rho[1] *= ihdim; - p->primitives.gradients.rho[2] *= ihdim; - - p->primitives.gradients.v[0][0] *= ihdim; - p->primitives.gradients.v[0][1] *= ihdim; - p->primitives.gradients.v[0][2] *= ihdim; - p->primitives.gradients.v[1][0] *= ihdim; - p->primitives.gradients.v[1][1] *= ihdim; - p->primitives.gradients.v[1][2] *= ihdim; - p->primitives.gradients.v[2][0] *= ihdim; - p->primitives.gradients.v[2][1] *= ihdim; - p->primitives.gradients.v[2][2] *= ihdim; - - p->primitives.gradients.P[0] *= ihdim; - p->primitives.gradients.P[1] *= ihdim; - p->primitives.gradients.P[2] *= ihdim; - - } else { - - /* finalize gradients by multiplying with volume */ - p->primitives.gradients.rho[0] *= ihdimp1 * volume; - p->primitives.gradients.rho[1] *= ihdimp1 * volume; - p->primitives.gradients.rho[2] *= ihdimp1 * volume; - - p->primitives.gradients.v[0][0] *= ihdimp1 * volume; - p->primitives.gradients.v[0][1] *= ihdimp1 * volume; - p->primitives.gradients.v[0][2] *= ihdimp1 * volume; - - p->primitives.gradients.v[1][0] *= ihdimp1 * volume; - p->primitives.gradients.v[1][1] *= ihdimp1 * volume; - p->primitives.gradients.v[1][2] *= ihdimp1 * volume; - p->primitives.gradients.v[2][0] *= ihdimp1 * volume; - p->primitives.gradients.v[2][1] *= ihdimp1 * volume; - p->primitives.gradients.v[2][2] *= ihdimp1 * volume; - - p->primitives.gradients.P[0] *= ihdimp1 * volume; - p->primitives.gradients.P[1] *= ihdimp1 * volume; - p->primitives.gradients.P[2] *= ihdimp1 * volume; - } - - hydro_slope_limit_cell(p); -} - -#endif /* SWIFT_GIZMO_MFV_HYDRO_GRADIENTS_H */ diff --git a/src/hydro/GizmoMFV/hydro_gradients_sph.h b/src/hydro/GizmoMFV/hydro_gradients_sph.h deleted file mode 100644 index 7b2b89ae688622ff017e4188f9e8fd2c7cee9d7a..0000000000000000000000000000000000000000 --- a/src/hydro/GizmoMFV/hydro_gradients_sph.h +++ /dev/null @@ -1,256 +0,0 @@ -/******************************************************************************* - * This file is part of SWIFT. - * Copyright (c) 2016 Bert Vandenbroucke (bert.vandenbroucke@gmail.com) - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU Lesser General Public License as published - * by the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public License - * along with this program. If not, see <http://www.gnu.org/licenses/>. - * - ******************************************************************************/ - -/** - * @brief Initialize gradient variables - * - * @param p Particle. - */ -#ifndef SWIFT_GIZMO_MFV_HYDRO_SPH_GRADIENTS_H -#define SWIFT_GIZMO_MFV_HYDRO_SPH_GRADIENTS_H - -__attribute__((always_inline)) INLINE static void hydro_gradients_init( - struct part *p) { - - p->primitives.gradients.rho[0] = 0.0f; - p->primitives.gradients.rho[1] = 0.0f; - p->primitives.gradients.rho[2] = 0.0f; - - p->primitives.gradients.v[0][0] = 0.0f; - p->primitives.gradients.v[0][1] = 0.0f; - p->primitives.gradients.v[0][2] = 0.0f; - - p->primitives.gradients.v[1][0] = 0.0f; - p->primitives.gradients.v[1][1] = 0.0f; - p->primitives.gradients.v[1][2] = 0.0f; - p->primitives.gradients.v[2][0] = 0.0f; - p->primitives.gradients.v[2][1] = 0.0f; - p->primitives.gradients.v[2][2] = 0.0f; - - p->primitives.gradients.P[0] = 0.0f; - p->primitives.gradients.P[1] = 0.0f; - p->primitives.gradients.P[2] = 0.0f; - - hydro_slope_limit_cell_init(p); -} - -/** - * @brief Gradient calculations done during the neighbour loop - * - * @param r2 Squared distance between the two particles. - * @param dx Distance vector (pi->x - pj->x). - * @param hi Smoothing length of particle i. - * @param hj Smoothing length of particle j. - * @param pi Particle i. - * @param pj Particle j. - */ -__attribute__((always_inline)) INLINE static void hydro_gradients_collect( - float r2, const float *dx, float hi, float hj, struct part *restrict pi, - struct part *restrict pj) { - - const float r_inv = 1.f / sqrtf(r2); - const float r = r2 * r_inv; - - float wi, wi_dx; - const float hi_inv = 1.0f / hi; - const float xi = r * hi_inv; - kernel_deval(xi, &wi, &wi_dx); - - /* very basic gradient estimate */ - pi->primitives.gradients.rho[0] -= - wi_dx * dx[0] * (pi->primitives.rho - pj->primitives.rho) * r_inv; - pi->primitives.gradients.rho[1] -= - wi_dx * dx[1] * (pi->primitives.rho - pj->primitives.rho) * r_inv; - pi->primitives.gradients.rho[2] -= - wi_dx * dx[2] * (pi->primitives.rho - pj->primitives.rho) * r_inv; - - pi->primitives.gradients.v[0][0] -= - wi_dx * dx[0] * (pi->primitives.v[0] - pj->primitives.v[0]) * r_inv; - pi->primitives.gradients.v[0][1] -= - wi_dx * dx[1] * (pi->primitives.v[0] - pj->primitives.v[0]) * r_inv; - pi->primitives.gradients.v[0][2] -= - wi_dx * dx[2] * (pi->primitives.v[0] - pj->primitives.v[0]) * r_inv; - - pi->primitives.gradients.v[1][0] -= - wi_dx * dx[0] * (pi->primitives.v[1] - pj->primitives.v[1]) * r_inv; - pi->primitives.gradients.v[1][1] -= - wi_dx * dx[1] * (pi->primitives.v[1] - pj->primitives.v[1]) * r_inv; - pi->primitives.gradients.v[1][2] -= - wi_dx * dx[2] * (pi->primitives.v[1] - pj->primitives.v[1]) * r_inv; - - pi->primitives.gradients.v[2][0] -= - wi_dx * dx[0] * (pi->primitives.v[2] - pj->primitives.v[2]) * r_inv; - pi->primitives.gradients.v[2][1] -= - wi_dx * dx[1] * (pi->primitives.v[2] - pj->primitives.v[2]) * r_inv; - pi->primitives.gradients.v[2][2] -= - wi_dx * dx[2] * (pi->primitives.v[2] - pj->primitives.v[2]) * r_inv; - - pi->primitives.gradients.P[0] -= - wi_dx * dx[0] * (pi->primitives.P - pj->primitives.P) * r_inv; - pi->primitives.gradients.P[1] -= - wi_dx * dx[1] * (pi->primitives.P - pj->primitives.P) * r_inv; - pi->primitives.gradients.P[2] -= - wi_dx * dx[2] * (pi->primitives.P - pj->primitives.P) * r_inv; - - hydro_slope_limit_cell_collect(pi, pj, r); - - float wj, wj_dx; - const float hj_inv = 1.0f / hj; - const float xj = r * hj_inv; - kernel_deval(xj, &wj, &wj_dx); - - /* signs are the same as before, since we swap i and j twice */ - pj->primitives.gradients.rho[0] -= - wj_dx * dx[0] * (pi->primitives.rho - pj->primitives.rho) * r_inv; - pj->primitives.gradients.rho[1] -= - wj_dx * dx[1] * (pi->primitives.rho - pj->primitives.rho) * r_inv; - pj->primitives.gradients.rho[2] -= - wj_dx * dx[2] * (pi->primitives.rho - pj->primitives.rho) * r_inv; - - pj->primitives.gradients.v[0][0] -= - wj_dx * dx[0] * (pi->primitives.v[0] - pj->primitives.v[0]) * r_inv; - pj->primitives.gradients.v[0][1] -= - wj_dx * dx[1] * (pi->primitives.v[0] - pj->primitives.v[0]) * r_inv; - pj->primitives.gradients.v[0][2] -= - wj_dx * dx[2] * (pi->primitives.v[0] - pj->primitives.v[0]) * r_inv; - - pj->primitives.gradients.v[1][0] -= - wj_dx * dx[0] * (pi->primitives.v[1] - pj->primitives.v[1]) * r_inv; - pj->primitives.gradients.v[1][1] -= - wj_dx * dx[1] * (pi->primitives.v[1] - pj->primitives.v[1]) * r_inv; - pj->primitives.gradients.v[1][2] -= - wj_dx * dx[2] * (pi->primitives.v[1] - pj->primitives.v[1]) * r_inv; - pj->primitives.gradients.v[2][0] -= - wj_dx * dx[0] * (pi->primitives.v[2] - pj->primitives.v[2]) * r_inv; - pj->primitives.gradients.v[2][1] -= - wj_dx * dx[1] * (pi->primitives.v[2] - pj->primitives.v[2]) * r_inv; - pj->primitives.gradients.v[2][2] -= - wj_dx * dx[2] * (pi->primitives.v[2] - pj->primitives.v[2]) * r_inv; - - pj->primitives.gradients.P[0] -= - wj_dx * dx[0] * (pi->primitives.P - pj->primitives.P) * r_inv; - pj->primitives.gradients.P[1] -= - wj_dx * dx[1] * (pi->primitives.P - pj->primitives.P) * r_inv; - pj->primitives.gradients.P[2] -= - wj_dx * dx[2] * (pi->primitives.P - pj->primitives.P) * r_inv; - - hydro_slope_limit_cell_collect(pj, pi, r); -} - -/** - * @brief Gradient calculations done during the neighbour loop: non-symmetric - * version - * - * @param r2 Squared distance between the two particles. - * @param dx Distance vector (pi->x - pj->x). - * @param hi Smoothing length of particle i. - * @param hj Smoothing length of particle j. - * @param pi Particle i. - * @param pj Particle j. - */ -__attribute__((always_inline)) INLINE static void -hydro_gradients_nonsym_collect(float r2, const float *dx, float hi, float hj, - struct part *restrict pi, - struct part *restrict pj) { - - const float r_inv = 1.f / sqrtf(r2); - const float r = r2 * r_inv; - - float wi, wi_dx; - const float hi_inv = 1.0f / hi; - const float xi = r * hi_inv; - kernel_deval(xi, &wi, &wi_dx); - - /* very basic gradient estimate */ - pi->primitives.gradients.rho[0] -= - wi_dx * dx[0] * (pi->primitives.rho - pj->primitives.rho) * r_inv; - pi->primitives.gradients.rho[1] -= - wi_dx * dx[1] * (pi->primitives.rho - pj->primitives.rho) * r_inv; - pi->primitives.gradients.rho[2] -= - wi_dx * dx[2] * (pi->primitives.rho - pj->primitives.rho) * r_inv; - - pi->primitives.gradients.v[0][0] -= - wi_dx * dx[0] * (pi->primitives.v[0] - pj->primitives.v[0]) * r_inv; - pi->primitives.gradients.v[0][1] -= - wi_dx * dx[1] * (pi->primitives.v[0] - pj->primitives.v[0]) * r_inv; - pi->primitives.gradients.v[0][2] -= - wi_dx * dx[2] * (pi->primitives.v[0] - pj->primitives.v[0]) * r_inv; - - pi->primitives.gradients.v[1][0] -= - wi_dx * dx[0] * (pi->primitives.v[1] - pj->primitives.v[1]) * r_inv; - pi->primitives.gradients.v[1][1] -= - wi_dx * dx[1] * (pi->primitives.v[1] - pj->primitives.v[1]) * r_inv; - pi->primitives.gradients.v[1][2] -= - wi_dx * dx[2] * (pi->primitives.v[1] - pj->primitives.v[1]) * r_inv; - - pi->primitives.gradients.v[2][0] -= - wi_dx * dx[0] * (pi->primitives.v[2] - pj->primitives.v[2]) * r_inv; - pi->primitives.gradients.v[2][1] -= - wi_dx * dx[1] * (pi->primitives.v[2] - pj->primitives.v[2]) * r_inv; - pi->primitives.gradients.v[2][2] -= - wi_dx * dx[2] * (pi->primitives.v[2] - pj->primitives.v[2]) * r_inv; - - pi->primitives.gradients.P[0] -= - wi_dx * dx[0] * (pi->primitives.P - pj->primitives.P) * r_inv; - pi->primitives.gradients.P[1] -= - wi_dx * dx[1] * (pi->primitives.P - pj->primitives.P) * r_inv; - pi->primitives.gradients.P[2] -= - wi_dx * dx[2] * (pi->primitives.P - pj->primitives.P) * r_inv; - - hydro_slope_limit_cell_collect(pi, pj, r); -} - -/** - * @brief Finalize the gradient variables after all data have been collected - * - * @param p Particle. - */ -__attribute__((always_inline)) INLINE static void hydro_gradients_finalize( - struct part *p) { - - const float h = p->h; - const float ih = 1.0f / h; - const float ihdimp1 = pow_dimension_plus_one(ih); - const float volume = p->geometry.volume; - - /* finalize gradients by multiplying with volume */ - p->primitives.gradients.rho[0] *= ihdimp1 * volume; - p->primitives.gradients.rho[1] *= ihdimp1 * volume; - p->primitives.gradients.rho[2] *= ihdimp1 * volume; - - p->primitives.gradients.v[0][0] *= ihdimp1 * volume; - p->primitives.gradients.v[0][1] *= ihdimp1 * volume; - p->primitives.gradients.v[0][2] *= ihdimp1 * volume; - - p->primitives.gradients.v[1][0] *= ihdimp1 * volume; - p->primitives.gradients.v[1][1] *= ihdimp1 * volume; - p->primitives.gradients.v[1][2] *= ihdimp1 * volume; - - p->primitives.gradients.v[2][0] *= ihdimp1 * volume; - p->primitives.gradients.v[2][1] *= ihdimp1 * volume; - p->primitives.gradients.v[2][2] *= ihdimp1 * volume; - - p->primitives.gradients.P[0] *= ihdimp1 * volume; - p->primitives.gradients.P[1] *= ihdimp1 * volume; - p->primitives.gradients.P[2] *= ihdimp1 * volume; - - hydro_slope_limit_cell(p); -} - -#endif /* SWIFT_GIZMO_MFV_HYDRO_SPH_GRADIENTS_H */ diff --git a/src/hydro/GizmoMFV/hydro_iact.h b/src/hydro/GizmoMFV/hydro_iact.h deleted file mode 100644 index 2ac5474f0e767879656129f486fb276608d13622..0000000000000000000000000000000000000000 --- a/src/hydro/GizmoMFV/hydro_iact.h +++ /dev/null @@ -1,531 +0,0 @@ -/******************************************************************************* - * This file is part of SWIFT. - * Coypright (c) 2012 Pedro Gonnet (pedro.gonnet@durham.ac.uk) - * Matthieu Schaller (matthieu.schaller@durham.ac.uk) - * Bert Vandenbroucke (bert.vandenbroucke@ugent.be) - * - * 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_GIZMO_MFV_HYDRO_IACT_H -#define SWIFT_GIZMO_MFV_HYDRO_IACT_H - -#include "adiabatic_index.h" -#include "hydro_gradients.h" -#include "riemann.h" - -#include "./hydro_parameters.h" - -#define GIZMO_VOLUME_CORRECTION - -/** - * @brief Calculate the volume interaction between particle i and particle j - * - * The volume is in essence the same as the weighted number of neighbours in a - * classical SPH density calculation. - * - * We also calculate the components of the matrix E, which is used for second - * order accurate gradient calculations and for the calculation of the interface - * surface areas. - * - * @param r2 Comoving squared distance between particle i and particle j. - * @param dx Comoving distance vector between the particles (dx = pi->x - - * pj->x). - * @param hi Comoving smoothing-length of particle i. - * @param hj Comoving smoothing-length of particle j. - * @param pi Particle i. - * @param pj Particle j. - * @param a Current scale factor. - * @param H Current Hubble parameter. - */ -__attribute__((always_inline)) INLINE static void runner_iact_density( - float r2, const float *dx, float hi, float hj, struct part *restrict pi, - struct part *restrict pj, float a, float H) { - - float wi, wj, wi_dx, wj_dx; - - /* Get r and h inverse. */ - const float r = sqrtf(r2); - - /* Compute density of pi. */ - const float hi_inv = 1.f / hi; - const float xi = r * hi_inv; - kernel_deval(xi, &wi, &wi_dx); - - pi->density.wcount += wi; - pi->density.wcount_dh -= (hydro_dimension * wi + xi * wi_dx); - - /* these are eqns. (1) and (2) in the summary */ - pi->geometry.volume += wi; - for (int k = 0; k < 3; k++) - for (int l = 0; l < 3; l++) - pi->geometry.matrix_E[k][l] += dx[k] * dx[l] * wi; - - pi->geometry.centroid[0] -= dx[0] * wi; - pi->geometry.centroid[1] -= dx[1] * wi; - pi->geometry.centroid[2] -= dx[2] * wi; - - /* Compute density of pj. */ - const float hj_inv = 1.f / hj; - const float xj = r * hj_inv; - kernel_deval(xj, &wj, &wj_dx); - - pj->density.wcount += wj; - pj->density.wcount_dh -= (hydro_dimension * wj + xj * wj_dx); - - /* these are eqns. (1) and (2) in the summary */ - pj->geometry.volume += wj; - for (int k = 0; k < 3; k++) - for (int l = 0; l < 3; l++) - pj->geometry.matrix_E[k][l] += dx[k] * dx[l] * wj; - - pj->geometry.centroid[0] += dx[0] * wj; - pj->geometry.centroid[1] += dx[1] * wj; - pj->geometry.centroid[2] += dx[2] * wj; -} - -/** - * @brief Calculate the volume interaction between particle i and particle j: - * non-symmetric version - * - * The volume is in essence the same as the weighted number of neighbours in a - * classical SPH density calculation. - * - * We also calculate the components of the matrix E, which is used for second - * order accurate gradient calculations and for the calculation of the interface - * surface areas. - * - * @param r2 Comoving squared distance between particle i and particle j. - * @param dx Comoving distance vector between the particles (dx = pi->x - - * pj->x). - * @param hi Comoving smoothing-length of particle i. - * @param hj Comoving smoothing-length of particle j. - * @param pi Particle i. - * @param pj Particle j. - * @param a Current scale factor. - * @param H Current Hubble parameter. - */ -__attribute__((always_inline)) INLINE static void runner_iact_nonsym_density( - float r2, const float *dx, float hi, float hj, struct part *restrict pi, - const struct part *restrict pj, float a, float H) { - - float wi, wi_dx; - - /* Get r and h inverse. */ - const float r = sqrtf(r2); - - const float hi_inv = 1.f / hi; - const float xi = r * hi_inv; - kernel_deval(xi, &wi, &wi_dx); - - pi->density.wcount += wi; - pi->density.wcount_dh -= (hydro_dimension * wi + xi * wi_dx); - - /* these are eqns. (1) and (2) in the summary */ - pi->geometry.volume += wi; - for (int k = 0; k < 3; k++) - for (int l = 0; l < 3; l++) - pi->geometry.matrix_E[k][l] += dx[k] * dx[l] * wi; - - pi->geometry.centroid[0] -= dx[0] * wi; - pi->geometry.centroid[1] -= dx[1] * wi; - pi->geometry.centroid[2] -= dx[2] * wi; -} - -/** - * @brief Calculate the gradient interaction between particle i and particle j - * - * This method wraps around hydro_gradients_collect, which can be an empty - * method, in which case no gradients are used. - * - * @param r2 Comoving squared distance between particle i and particle j. - * @param dx Comoving distance vector between the particles (dx = pi->x - - * pj->x). - * @param hi Comoving smoothing-length of particle i. - * @param hj Comoving smoothing-length of particle j. - * @param pi Particle i. - * @param pj Particle j. - * @param a Current scale factor. - * @param H Current Hubble parameter. - */ -__attribute__((always_inline)) INLINE static void runner_iact_gradient( - float r2, const float *dx, float hi, float hj, struct part *restrict pi, - struct part *restrict pj, float a, float H) { - - hydro_gradients_collect(r2, dx, hi, hj, pi, pj); -} - -/** - * @brief Calculate the gradient interaction between particle i and particle j: - * non-symmetric version - * - * This method wraps around hydro_gradients_nonsym_collect, which can be an - * empty method, in which case no gradients are used. - * - * @param r2 Comoving squared distance between particle i and particle j. - * @param dx Comoving distance vector between the particles (dx = pi->x - - * pj->x). - * @param hi Comoving smoothing-length of particle i. - * @param hj Comoving smoothing-length of particle j. - * @param pi Particle i. - * @param pj Particle j. - * @param a Current scale factor. - * @param H Current Hubble parameter. - */ -__attribute__((always_inline)) INLINE static void runner_iact_nonsym_gradient( - float r2, const float *dx, float hi, float hj, struct part *restrict pi, - struct part *restrict pj, float a, float H) { - - hydro_gradients_nonsym_collect(r2, dx, hi, hj, pi, pj); -} - -/** - * @brief Common part of the flux calculation between particle i and j - * - * Since the only difference between the symmetric and non-symmetric version - * of the flux calculation is in the update of the conserved variables at the - * very end (which is not done for particle j if mode is 0), both - * runner_iact_force and runner_iact_nonsym_force call this method, with an - * appropriate mode. - * - * This method calculates the surface area of the interface between particle i - * and particle j, as well as the interface position and velocity. These are - * then used to reconstruct and predict the primitive variables, which are then - * fed to a Riemann solver that calculates a flux. This flux is used to update - * the conserved variables of particle i or both particles. - * - * This method also calculates the maximal velocity used to calculate the time - * step. - * - * @param r2 Comoving squared distance between particle i and particle j. - * @param dx Comoving distance vector between the particles (dx = pi->x - - * pj->x). - * @param hi Comoving smoothing-length of particle i. - * @param hj Comoving smoothing-length of particle j. - * @param pi Particle i. - * @param pj Particle j. - * @param a Current scale factor. - * @param H Current Hubble parameter. - */ -__attribute__((always_inline)) INLINE static void runner_iact_fluxes_common( - float r2, const float *dx, float hi, float hj, struct part *restrict pi, - struct part *restrict pj, int mode, float a, float H) { - - const float r_inv = 1.f / sqrtf(r2); - const float r = r2 * r_inv; - - /* Initialize local variables */ - float Bi[3][3]; - float Bj[3][3]; - float vi[3], vj[3]; - for (int k = 0; k < 3; k++) { - for (int l = 0; l < 3; l++) { - Bi[k][l] = pi->geometry.matrix_E[k][l]; - Bj[k][l] = pj->geometry.matrix_E[k][l]; - } - vi[k] = pi->v[k]; /* particle velocities */ - vj[k] = pj->v[k]; - } - const float Vi = pi->geometry.volume; - const float Vj = pj->geometry.volume; - float Wi[5], Wj[5]; - Wi[0] = pi->primitives.rho; - Wi[1] = pi->primitives.v[0]; - Wi[2] = pi->primitives.v[1]; - Wi[3] = pi->primitives.v[2]; - Wi[4] = pi->primitives.P; - Wj[0] = pj->primitives.rho; - Wj[1] = pj->primitives.v[0]; - Wj[2] = pj->primitives.v[1]; - Wj[3] = pj->primitives.v[2]; - Wj[4] = pj->primitives.P; - - /* calculate the maximal signal velocity */ - float vmax; - if (Wi[0] > 0.0f && Wj[0] > 0.0f) { - const float ci = gas_soundspeed_from_pressure(Wi[0], Wi[4]); - const float cj = gas_soundspeed_from_pressure(Wj[0], Wj[4]); - vmax = ci + cj; - } else - vmax = 0.0f; - - float dvdr = (pi->v[0] - pj->v[0]) * dx[0] + (pi->v[1] - pj->v[1]) * dx[1] + - (pi->v[2] - pj->v[2]) * dx[2]; - - /* Velocity on the axis linking the particles */ - float dvdotdx = (Wi[1] - Wj[1]) * dx[0] + (Wi[2] - Wj[2]) * dx[1] + - (Wi[3] - Wj[3]) * dx[2]; - dvdotdx = min(dvdotdx, dvdr); - - /* We only care about this velocity for particles moving towards each others - */ - dvdotdx = min(dvdotdx, 0.f); - - /* Get the signal velocity */ - vmax -= const_viscosity_beta * dvdotdx * r_inv; - - /* Store the signal velocity */ - pi->timestepvars.vmax = max(pi->timestepvars.vmax, vmax); - if (mode == 1) pj->timestepvars.vmax = max(pj->timestepvars.vmax, vmax); - - /* Compute kernel of pi. */ - float wi, wi_dx; - const float hi_inv = 1.f / hi; - const float hi_inv_dim = pow_dimension(hi_inv); - const float xi = r * hi_inv; - kernel_deval(xi, &wi, &wi_dx); - - /* Compute kernel of pj. */ - float wj, wj_dx; - const float hj_inv = 1.f / hj; - const float hj_inv_dim = pow_dimension(hj_inv); - const float xj = r * hj_inv; - kernel_deval(xj, &wj, &wj_dx); - - /* Compute h_dt. We are going to use an SPH-like estimate of div_v for that */ - const float hidp1 = pow_dimension_plus_one(hi_inv); - const float hjdp1 = pow_dimension_plus_one(hj_inv); - const float wi_dr = hidp1 * wi_dx; - const float wj_dr = hjdp1 * wj_dx; - dvdr *= r_inv; - if (pj->primitives.rho > 0.) - pi->force.h_dt -= pj->conserved.mass * dvdr / pj->primitives.rho * wi_dr; - if (mode == 1 && pi->primitives.rho > 0.) - pj->force.h_dt -= pi->conserved.mass * dvdr / pi->primitives.rho * wj_dr; - - /* Compute (square of) area */ - /* eqn. (7) */ - float Anorm2 = 0.0f; - float A[3]; - if (pi->density.wcorr > const_gizmo_min_wcorr && - pj->density.wcorr > const_gizmo_min_wcorr) { - /* in principle, we use Vi and Vj as weights for the left and right - contributions to the generalized surface vector. - However, if Vi and Vj are very different (because they have very - different - smoothing lengths), then the expressions below are more stable. */ - float Xi = Vi; - float Xj = Vj; -#ifdef GIZMO_VOLUME_CORRECTION - if (fabsf(Vi - Vj) / min(Vi, Vj) > 1.5f * hydro_dimension) { - Xi = (Vi * hj + Vj * hi) / (hi + hj); - Xj = Xi; - } -#endif - for (int k = 0; k < 3; k++) { - /* we add a minus sign since dx is pi->x - pj->x */ - A[k] = -Xi * (Bi[k][0] * dx[0] + Bi[k][1] * dx[1] + Bi[k][2] * dx[2]) * - wi * hi_inv_dim - - Xj * (Bj[k][0] * dx[0] + Bj[k][1] * dx[1] + Bj[k][2] * dx[2]) * - wj * hj_inv_dim; - Anorm2 += A[k] * A[k]; - } - } else { - /* ill condition gradient matrix: revert to SPH face area */ - const float Anorm = - -(hidp1 * Vi * Vi * wi_dx + hjdp1 * Vj * Vj * wj_dx) * r_inv; - A[0] = -Anorm * dx[0]; - A[1] = -Anorm * dx[1]; - A[2] = -Anorm * dx[2]; - Anorm2 = Anorm * Anorm * r2; - } - - /* if the interface has no area, nothing happens and we return */ - /* continuing results in dividing by zero and NaN's... */ - if (Anorm2 == 0.f) return; - - /* Compute the area */ - const float Anorm_inv = 1. / sqrtf(Anorm2); - const float Anorm = Anorm2 * Anorm_inv; - -#ifdef SWIFT_DEBUG_CHECKS - /* For stability reasons, we do require A and dx to have opposite - directions (basically meaning that the surface normal for the surface - always points from particle i to particle j, as it would in a real - moving-mesh code). If not, our scheme is no longer upwind and hence can - become unstable. */ - const float dA_dot_dx = A[0] * dx[0] + A[1] * dx[1] + A[2] * dx[2]; - /* In GIZMO, Phil Hopkins reverts to an SPH integration scheme if this - happens. We curently just ignore this case and display a message. */ - const float rdim = pow_dimension(r); - if (dA_dot_dx > 1.e-6f * rdim) { - message("Ill conditioned gradient matrix (%g %g %g %g %g)!", dA_dot_dx, - Anorm, Vi, Vj, r); - } -#endif - - /* compute the normal vector of the interface */ - const float n_unit[3] = {A[0] * Anorm_inv, A[1] * Anorm_inv, - A[2] * Anorm_inv}; - - /* Compute interface position (relative to pi, since we don't need the actual - * position) eqn. (8) */ - const float xfac = -hi / (hi + hj); - const float xij_i[3] = {xfac * dx[0], xfac * dx[1], xfac * dx[2]}; - - /* Compute interface velocity */ - /* eqn. (9) */ - const float vij[3] = {vi[0] + xfac * (vi[0] - vj[0]), - vi[1] + xfac * (vi[1] - vj[1]), - vi[2] + xfac * (vi[2] - vj[2])}; - - hydro_gradients_predict(pi, pj, hi, hj, dx, r, xij_i, Wi, Wj); - - /* Boost the primitive variables to the frame of reference of the interface */ - /* Note that velocities are indices 1-3 in W */ - Wi[1] -= vij[0]; - Wi[2] -= vij[1]; - Wi[3] -= vij[2]; - Wj[1] -= vij[0]; - Wj[2] -= vij[1]; - Wj[3] -= vij[2]; - - /* we don't need to rotate, we can use the unit vector in the Riemann problem - * itself (see GIZMO) */ - - float totflux[5]; - riemann_solve_for_flux(Wi, Wj, n_unit, vij, totflux); - - /* Multiply with the interface surface area */ - totflux[0] *= Anorm; - totflux[1] *= Anorm; - totflux[2] *= Anorm; - totflux[3] *= Anorm; - totflux[4] *= Anorm; - - /* Store mass flux */ - const float mflux_i = totflux[0]; - pi->gravity.mflux[0] += mflux_i * dx[0]; - pi->gravity.mflux[1] += mflux_i * dx[1]; - pi->gravity.mflux[2] += mflux_i * dx[2]; - - /* Update conserved variables */ - /* eqn. (16) */ - pi->conserved.flux.mass -= totflux[0]; - pi->conserved.flux.momentum[0] -= totflux[1]; - pi->conserved.flux.momentum[1] -= totflux[2]; - pi->conserved.flux.momentum[2] -= totflux[3]; - pi->conserved.flux.energy -= totflux[4]; - -#ifndef GIZMO_TOTAL_ENERGY - const float ekin_i = 0.5f * (pi->primitives.v[0] * pi->primitives.v[0] + - pi->primitives.v[1] * pi->primitives.v[1] + - pi->primitives.v[2] * pi->primitives.v[2]); - pi->conserved.flux.energy += totflux[1] * pi->primitives.v[0]; - pi->conserved.flux.energy += totflux[2] * pi->primitives.v[1]; - pi->conserved.flux.energy += totflux[3] * pi->primitives.v[2]; - pi->conserved.flux.energy -= totflux[0] * ekin_i; -#endif - - /* Note that this used to be much more complicated in early implementations of - * the GIZMO scheme, as we wanted manifest conservation of conserved variables - * and had to do symmetric flux exchanges. Now we don't care about manifest - * conservation anymore and just assume the current fluxes are representative - * for the flux over the entire time step. */ - if (mode == 1) { - /* Store mass flux */ - const float mflux_j = totflux[0]; - pj->gravity.mflux[0] += mflux_j * dx[0]; - pj->gravity.mflux[1] += mflux_j * dx[1]; - pj->gravity.mflux[2] += mflux_j * dx[2]; - - pj->conserved.flux.mass += totflux[0]; - pj->conserved.flux.momentum[0] += totflux[1]; - pj->conserved.flux.momentum[1] += totflux[2]; - pj->conserved.flux.momentum[2] += totflux[3]; - pj->conserved.flux.energy += totflux[4]; - -#ifndef GIZMO_TOTAL_ENERGY - const float ekin_j = 0.5f * (pj->primitives.v[0] * pj->primitives.v[0] + - pj->primitives.v[1] * pj->primitives.v[1] + - pj->primitives.v[2] * pj->primitives.v[2]); - pj->conserved.flux.energy -= totflux[1] * pj->primitives.v[0]; - pj->conserved.flux.energy -= totflux[2] * pj->primitives.v[1]; - pj->conserved.flux.energy -= totflux[3] * pj->primitives.v[2]; - pj->conserved.flux.energy += totflux[0] * ekin_j; -#endif - } -} - -/** - * @brief Flux calculation between particle i and particle j - * - * This method calls runner_iact_fluxes_common with mode 1. - * - * @param r2 Comoving squared distance between particle i and particle j. - * @param dx Comoving distance vector between the particles (dx = pi->x - - * pj->x). - * @param hi Comoving smoothing-length of particle i. - * @param hj Comoving smoothing-length of particle j. - * @param pi Particle i. - * @param pj Particle j. - * @param a Current scale factor. - * @param H Current Hubble parameter. - */ -__attribute__((always_inline)) INLINE static void runner_iact_force( - float r2, const float *dx, float hi, float hj, struct part *restrict pi, - struct part *restrict pj, float a, float H) { - - runner_iact_fluxes_common(r2, dx, hi, hj, pi, pj, 1, a, H); -} - -/** - * @brief Flux calculation between particle i and particle j: non-symmetric - * version - * - * This method calls runner_iact_fluxes_common with mode 0. - * - * @param r2 Comoving squared distance between particle i and particle j. - * @param dx Comoving distance vector between the particles (dx = pi->x - - * pj->x). - * @param hi Comoving smoothing-length of particle i. - * @param hj Comoving smoothing-length of particle j. - * @param pi Particle i. - * @param pj Particle j. - * @param a Current scale factor. - * @param H Current Hubble parameter. - */ -__attribute__((always_inline)) INLINE static void runner_iact_nonsym_force( - float r2, const float *dx, float hi, float hj, struct part *restrict pi, - struct part *restrict pj, float a, float H) { - - runner_iact_fluxes_common(r2, dx, hi, hj, pi, pj, 0, a, H); -} - -/** - * @brief Timestep limiter loop - */ -__attribute__((always_inline)) INLINE static void runner_iact_limiter( - float r2, const float *dx, float hi, float hj, struct part *restrict pi, - struct part *restrict pj, float a, float H) { - - /* Nothing to do here if both particles are active */ -} - -/** - * @brief Timestep limiter loop (non-symmetric version) - */ -__attribute__((always_inline)) INLINE static void runner_iact_nonsym_limiter( - float r2, const float *dx, float hi, float hj, struct part *restrict pi, - struct part *restrict pj, float a, float H) { - - /* Wake up the neighbour? */ - if (pi->timestepvars.vmax > - const_limiter_max_v_sig_ratio * pj->timestepvars.vmax) { - - pj->wakeup = time_bin_awake; - } -} - -#endif /* SWIFT_GIZMO_MFV_HYDRO_IACT_H */ diff --git a/src/hydro/GizmoMFV/hydro_io.h b/src/hydro/GizmoMFV/hydro_io.h deleted file mode 100644 index 11b8e95867495ccbc9df6a67b3045a09052fb161..0000000000000000000000000000000000000000 --- a/src/hydro/GizmoMFV/hydro_io.h +++ /dev/null @@ -1,268 +0,0 @@ -/******************************************************************************* - * This file is part of SWIFT. - * Coypright (c) 2016 Bert Vandenbroucke (bert.vandenbroucke@gmail.com) - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU Lesser General Public License as published - * by the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public License - * along with this program. If not, see <http://www.gnu.org/licenses/>. - * - ******************************************************************************/ -#ifndef SWIFT_GIZMO_MFV_HYDRO_IO_H -#define SWIFT_GIZMO_MFV_HYDRO_IO_H - -#include "adiabatic_index.h" -#include "hydro.h" -#include "hydro_gradients.h" -#include "hydro_slope_limiters.h" -#include "io_properties.h" -#include "riemann.h" - -/* Set the description of the particle movement. */ -#if defined(GIZMO_FIX_PARTICLES) -#define GIZMO_PARTICLE_MOVEMENT "Fixed particles." -#else -#define GIZMO_PARTICLE_MOVEMENT "Particles move with flow velocity." -#endif - -/** - * @brief Specifies which particle fields to read from a dataset - * - * @param parts The particle array. - * @param list The list of i/o properties to read. - * @param num_fields The number of i/o fields to read. - */ -INLINE static void hydro_read_particles(struct part* parts, - struct io_props* list, - int* num_fields) { - - *num_fields = 8; - - /* List what we want to read */ - list[0] = io_make_input_field("Coordinates", DOUBLE, 3, COMPULSORY, - UNIT_CONV_LENGTH, parts, x); - list[1] = io_make_input_field("Velocities", FLOAT, 3, COMPULSORY, - UNIT_CONV_SPEED, parts, v); - list[2] = io_make_input_field("Masses", FLOAT, 1, COMPULSORY, UNIT_CONV_MASS, - parts, conserved.mass); - list[3] = io_make_input_field("SmoothingLength", FLOAT, 1, COMPULSORY, - UNIT_CONV_LENGTH, parts, h); - list[4] = io_make_input_field("InternalEnergy", FLOAT, 1, COMPULSORY, - UNIT_CONV_ENERGY_PER_UNIT_MASS, parts, - conserved.energy); - list[5] = io_make_input_field("ParticleIDs", ULONGLONG, 1, COMPULSORY, - UNIT_CONV_NO_UNITS, parts, id); - list[6] = io_make_input_field("Accelerations", FLOAT, 3, OPTIONAL, - UNIT_CONV_ACCELERATION, parts, a_hydro); - list[7] = io_make_input_field("Density", FLOAT, 1, OPTIONAL, - UNIT_CONV_DENSITY, parts, primitives.rho); -} - -/** - * @brief Get the internal energy of a particle - * - * @param e #engine. - * @param p Particle. - * @param ret (return) Internal energy of the particle - */ -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); -} - -/** - * @brief Get the entropic function of a particle - * - * @param e #engine. - * @param p Particle. - * @param ret (return) Entropic function of the particle - */ -INLINE static void convert_A(const struct engine* e, const struct part* p, - const struct xpart* xp, float* ret) { - ret[0] = hydro_get_comoving_entropy(p); -} - -/** - * @brief Get the total energy of a particle - * - * @param e #engine. - * @param p Particle. - * @return Total energy of the particle - */ -INLINE static void convert_Etot(const struct engine* e, const struct part* p, - const struct xpart* xp, float* ret) { -#ifdef GIZMO_TOTAL_ENERGY - ret[0] = p->conserved.energy; -#else - float momentum2; - - momentum2 = p->conserved.momentum[0] * p->conserved.momentum[0] + - p->conserved.momentum[1] * p->conserved.momentum[1] + - p->conserved.momentum[2] * p->conserved.momentum[2]; - - ret[0] = p->conserved.energy + 0.5f * momentum2 / p->conserved.mass; -#endif -} - -INLINE static void convert_part_pos(const struct engine* e, - const struct part* p, - const struct xpart* xp, double* ret) { - - if (e->s->periodic) { - ret[0] = box_wrap(p->x[0], 0.0, e->s->dim[0]); - ret[1] = box_wrap(p->x[1], 0.0, e->s->dim[1]); - ret[2] = box_wrap(p->x[2], 0.0, e->s->dim[2]); - } else { - ret[0] = p->x[0]; - ret[1] = p->x[1]; - ret[2] = p->x[2]; - } -} - -INLINE static void convert_part_vel(const struct engine* e, - const struct part* p, - const struct xpart* xp, float* ret) { - - const int with_cosmology = (e->policy & engine_policy_cosmology); - const struct cosmology* cosmo = e->cosmology; - const integertime_t ti_current = e->ti_current; - const double time_base = e->time_base; - - const integertime_t ti_beg = get_integer_time_begin(ti_current, p->time_bin); - const integertime_t ti_end = get_integer_time_end(ti_current, p->time_bin); - - /* Get time-step since the last kick */ - float dt_kick_grav, dt_kick_hydro; - if (with_cosmology) { - dt_kick_grav = cosmology_get_grav_kick_factor(cosmo, ti_beg, ti_current); - dt_kick_grav -= - cosmology_get_grav_kick_factor(cosmo, ti_beg, (ti_beg + ti_end) / 2); - dt_kick_hydro = cosmology_get_hydro_kick_factor(cosmo, ti_beg, ti_current); - dt_kick_hydro -= - cosmology_get_hydro_kick_factor(cosmo, ti_beg, (ti_beg + ti_end) / 2); - } else { - dt_kick_grav = (ti_current - ((ti_beg + ti_end) / 2)) * time_base; - dt_kick_hydro = (ti_current - ((ti_beg + ti_end) / 2)) * time_base; - } - - /* Extrapolate the velocites to the current time */ - hydro_get_drifted_velocities(p, xp, dt_kick_hydro, dt_kick_grav, ret); - - /* Conversion from internal units to peculiar velocities */ - ret[0] *= cosmo->a_inv; - ret[1] *= cosmo->a_inv; - ret[2] *= cosmo->a_inv; -} - -INLINE static void convert_part_potential(const struct engine* e, - const struct part* p, - const struct xpart* xp, float* ret) { - - if (p->gpart != NULL) - ret[0] = gravity_get_comoving_potential(p->gpart); - else - ret[0] = 0.f; -} - -/** - * @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. - */ -INLINE static void hydro_write_particles(const struct part* parts, - const struct xpart* xparts, - struct io_props* list, - int* num_fields) { - *num_fields = 11; - - /* List what we want to write */ - list[0] = io_make_output_field_convert_part( - "Coordinates", DOUBLE, 3, UNIT_CONV_LENGTH, 1.f, parts, xparts, - convert_part_pos, "Co-moving positions of the particles"); - - list[1] = io_make_output_field_convert_part( - "Velocities", FLOAT, 3, UNIT_CONV_SPEED, 0.f, parts, xparts, - convert_part_vel, - "Peculiar velocities of the stars. This is (a * dx/dt) where x is the " - "co-moving positions of the particles"); - - list[2] = - io_make_output_field("Masses", FLOAT, 1, UNIT_CONV_MASS, 1.f, parts, - conserved.mass, "Co-moving masses of the particles"); - - list[3] = io_make_output_field( - "SmoothingLengths", FLOAT, 1, UNIT_CONV_LENGTH, 1.f, parts, h, - "Co-moving smoothing lengths (FWHM of the kernel) of the particles"); - - list[4] = io_make_output_field_convert_part( - "InternalEnergy", FLOAT, 1, UNIT_CONV_ENERGY_PER_UNIT_MASS, - 3.f * hydro_gamma_minus_one, parts, xparts, convert_u, - "Co-moving thermal energies per unit mass of the particles"); - - list[5] = - io_make_output_field("ParticleIDs", ULONGLONG, 1, UNIT_CONV_NO_UNITS, 0.f, - parts, id, "Unique IDs of the particles"); - - list[6] = io_make_output_field("Densities", FLOAT, 1, UNIT_CONV_DENSITY, -3.f, - parts, primitives.rho, - "Co-moving mass densities of the particles"); - - list[7] = io_make_output_field_convert_part( - "Entropies", FLOAT, 1, UNIT_CONV_ENTROPY, 0.f, parts, xparts, convert_A, - "Co-moving entropies of the particles"); - - list[8] = io_make_output_field("Pressures", FLOAT, 1, UNIT_CONV_PRESSURE, - -3.f * hydro_gamma, parts, primitives.P, - "Co-moving pressures of the particles"); - - list[9] = io_make_output_field_convert_part( - "TotalEnergies", FLOAT, 1, UNIT_CONV_ENERGY, -3.f * hydro_gamma_minus_one, - parts, xparts, convert_Etot, "Total (co-moving) energy of the particles"); - - list[10] = io_make_output_field_convert_part( - "Potentials", FLOAT, 1, UNIT_CONV_POTENTIAL, -1.f, parts, xparts, - convert_part_potential, "Gravitational potentials of the particles"); -} - -/** - * @brief Writes the current model of SPH to the file - * @param h_grpsph The HDF5 group in which to write - */ -INLINE static void hydro_write_flavour(hid_t h_grpsph) { - /* Gradient information */ - io_write_attribute_s(h_grpsph, "Gradient reconstruction model", - HYDRO_GRADIENT_IMPLEMENTATION); - - /* Slope limiter information */ - io_write_attribute_s(h_grpsph, "Cell wide slope limiter model", - HYDRO_SLOPE_LIMITER_CELL_IMPLEMENTATION); - io_write_attribute_s(h_grpsph, "Piecewise slope limiter model", - HYDRO_SLOPE_LIMITER_FACE_IMPLEMENTATION); - - /* Riemann solver information */ - io_write_attribute_s(h_grpsph, "Riemann solver type", - RIEMANN_SOLVER_IMPLEMENTATION); - - /* Particle movement information */ - io_write_attribute_s(h_grpsph, "Particle movement", GIZMO_PARTICLE_MOVEMENT); -} - -/** - * @brief Are we writing entropy in the internal energy field ? - * - * @return 1 if entropy is in 'internal energy', 0 otherwise. - */ -INLINE static int writeEntropyFlag(void) { return 0; } - -#endif /* SWIFT_GIZMO_MFV_HYDRO_IO_H */ diff --git a/src/hydro/GizmoMFV/hydro_parameters.h b/src/hydro/GizmoMFV/hydro_parameters.h deleted file mode 100644 index 7726de75d0b2d41cf4310c9441f21e04e10af0b0..0000000000000000000000000000000000000000 --- a/src/hydro/GizmoMFV/hydro_parameters.h +++ /dev/null @@ -1,162 +0,0 @@ -/******************************************************************************* - * This file is part of SWIFT. - * Coypright (c) 2019 Josh Borrow (joshua.borrow@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_GIZMOMFV_HYDRO_PARAMETERS_H -#define SWIFT_GIZMOMFV_HYDRO_PARAMETERS_H - -/* Configuration file */ -#include "config.h" - -/* Global headers */ -#if defined(HAVE_HDF5) -#include <hdf5.h> -#endif - -/* Local headers */ -#include "common_io.h" -#include "error.h" -#include "inline.h" - -/** - * @file GizmoMFV/hydro_parameters.h - * @brief Gizmo-MFV scheme. (default parameters) - * - * This file defines a number of things that are used in - * hydro_properties.c as defaults for run-time parameters - * as well as a number of compile-time parameters. - * - * These aren't really used in GIZMO but must be defined. - */ - -/* Viscosity parameters -- FIXED -- MUST BE DEFINED AT COMPILE-TIME */ - -/* Cosmology default beta=3.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 - -/* Structs that store the relevant variables */ - -/*! Artificial viscosity parameters */ -struct viscosity_global_data {}; - -/*! Thermal diffusion parameters */ -struct diffusion_global_data {}; - -/* Functions for reading from parameter file */ - -/* Forward declartions */ -struct swift_params; -struct phys_const; -struct unit_system; - -/* Viscosity */ - -/** - * @brief Initialises the viscosity parameters in the struct from - * the parameter file, or sets them to defaults. - * - * @param params: the pointer to the swift_params file - * @param unit_system: pointer to the unit system - * @param phys_const: pointer to the physical constants system - * @param viscosity: pointer to the viscosity_global_data struct to be filled. - **/ -static INLINE void viscosity_init(struct swift_params* params, - const struct unit_system* us, - const struct phys_const* phys_const, - struct viscosity_global_data* viscosity) {} - -/** - * @brief Initialises a viscosity struct to sensible numbers for mocking - * purposes. - * - * @param viscosity: pointer to the viscosity_global_data struct to be filled. - **/ -static INLINE void viscosity_init_no_hydro( - struct viscosity_global_data* viscosity) {} - -/** - * @brief Prints out the viscosity parameters at the start of a run. - * - * @param viscosity: pointer to the viscosity_global_data struct found in - * hydro_properties - **/ -static INLINE void viscosity_print( - const struct viscosity_global_data* viscosity) {} - -#if defined(HAVE_HDF5) -/** - * @brief Prints the viscosity information to the snapshot when writing. - * - * @param h_grpsph: the SPH group in the ICs to write attributes to. - * @param viscosity: pointer to the viscosity_global_data struct. - **/ -static INLINE void viscosity_print_snapshot( - hid_t h_grpsph, const struct viscosity_global_data* viscosity) { - io_write_attribute_f(h_grpsph, "Beta viscosity", const_viscosity_beta); -} -#endif - -/* Diffusion */ - -/** - * @brief Initialises the diffusion parameters in the struct from - * the parameter file, or sets them to defaults. - * - * @param params: the pointer to the swift_params file - * @param unit_system: pointer to the unit system - * @param phys_const: pointer to the physical constants system - * @param diffusion_global_data: pointer to the diffusion struct to be filled. - **/ -static INLINE void diffusion_init(struct swift_params* params, - const struct unit_system* us, - const struct phys_const* phys_const, - struct diffusion_global_data* diffusion) {} - -/** - * @brief Initialises a diffusion struct to sensible numbers for mocking - * purposes. - * - * @param diffusion: pointer to the diffusion_global_data struct to be filled. - **/ -static INLINE void diffusion_init_no_hydro( - struct diffusion_global_data* diffusion) {} - -/** - * @brief Prints out the diffusion parameters at the start of a run. - * - * @param diffusion: pointer to the diffusion_global_data struct found in - * hydro_properties - **/ -static INLINE void diffusion_print( - const struct diffusion_global_data* diffusion) {} - -#ifdef HAVE_HDF5 -/** - * @brief Prints the diffusion information to the snapshot when writing. - * - * @param h_grpsph: the SPH group in the ICs to write attributes to. - * @param diffusion: pointer to the diffusion_global_data struct. - **/ -static INLINE void diffusion_print_snapshot( - hid_t h_grpsph, const struct diffusion_global_data* diffusion) {} -#endif - -#endif /* SWIFT_GIZMOMFV_HYDRO_PARAMETERS_H */ diff --git a/src/hydro/GizmoMFV/hydro_slope_limiters.h b/src/hydro/GizmoMFV/hydro_slope_limiters.h deleted file mode 100644 index 78f2785cdae5dc2334d37e3924dd5b259cca8c05..0000000000000000000000000000000000000000 --- a/src/hydro/GizmoMFV/hydro_slope_limiters.h +++ /dev/null @@ -1,94 +0,0 @@ -/******************************************************************************* - * This file is part of SWIFT. - * Copyright (c) 2016 Bert Vandenbroucke (bert.vandenbroucke@gmail.com) - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU Lesser General Public License as published - * by the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public License - * along with this program. If not, see <http://www.gnu.org/licenses/>. - * - ******************************************************************************/ - -#ifndef SWIFT_HYDRO_SLOPE_LIMITERS_H -#define SWIFT_HYDRO_SLOPE_LIMITERS_H - -#include "dimension.h" -#include "kernel_hydro.h" - -#ifdef SLOPE_LIMITER_PER_FACE - -#define HYDRO_SLOPE_LIMITER_FACE_IMPLEMENTATION \ - "GIZMO piecewise slope limiter (Hopkins 2015)" -#include "hydro_slope_limiters_face.h" - -#else - -#define HYDRO_SLOPE_LIMITER_FACE_IMPLEMENTATION "No piecewise slope limiter" - -/** - * @brief Slope limit the slopes at the interface between two particles - * - * @param Wi Hydrodynamic variables of particle i. - * @param Wj Hydrodynamic variables of particle j. - * @param dWi Difference between the hydrodynamic variables of particle i at the - * position of particle i and at the interface position. - * @param dWj Difference between the hydrodynamic variables of particle j at the - * position of particle j and at the interface position. - * @param xij_i Relative position vector of the interface w.r.t. particle i. - * @param xij_j Relative position vector of the interface w.r.t. partilce j. - * @param r Distance between particle i and particle j. - */ -__attribute__((always_inline)) INLINE static void hydro_slope_limit_face( - float *Wi, float *Wj, float *dWi, float *dWj, float *xij_i, float *xij_j, - float r) {} - -#endif - -#ifdef SLOPE_LIMITER_CELL_WIDE - -#define HYDRO_SLOPE_LIMITER_CELL_IMPLEMENTATION \ - "Cell wide slope limiter (Springel 2010)" -#include "hydro_slope_limiters_cell.h" - -#else - -#define HYDRO_SLOPE_LIMITER_CELL_IMPLEMENTATION "No cell wide slope limiter" - -/** - * @brief Initialize variables for the cell wide slope limiter - * - * @param p Particle. - */ -__attribute__((always_inline)) INLINE static void hydro_slope_limit_cell_init( - struct part *p) {} - -/** - * @brief Collect information for the cell wide slope limiter during the - * neighbour loop - * - * @param pi Particle i. - * @param pj Particle j. - * @param r Distance between particle i and particle j. - */ -__attribute__((always_inline)) INLINE static void -hydro_slope_limit_cell_collect(struct part *pi, struct part *pj, float r) {} - -/** - * @brief Slope limit cell gradients - * - * @param p Particle. - */ -__attribute__((always_inline)) INLINE static void hydro_slope_limit_cell( - struct part *p) {} - -#endif - -#endif /* SWIFT_HYDRO_SLOPE_LIMITERS_H */ diff --git a/src/hydro/GizmoMFV/hydro_slope_limiters_cell.h b/src/hydro/GizmoMFV/hydro_slope_limiters_cell.h deleted file mode 100644 index 130a87def95a3198f0871ce485f0a9d377a96cd5..0000000000000000000000000000000000000000 --- a/src/hydro/GizmoMFV/hydro_slope_limiters_cell.h +++ /dev/null @@ -1,186 +0,0 @@ -/******************************************************************************* - * This file is part of SWIFT. - * Copyright (c) 2016 Bert Vandenbroucke (bert.vandenbroucke@gmail.com) - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU Lesser General Public License as published - * by the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public License - * along with this program. If not, see <http://www.gnu.org/licenses/>. - * - ******************************************************************************/ -#ifndef SWIFT_GIZMO_MFV_SLOPE_LIMITER_CELL_H -#define SWIFT_GIZMO_MFV_SLOPE_LIMITER_CELL_H - -#include <float.h> - -/** - * @brief Initialize variables for the cell wide slope limiter - * - * @param p Particle. - */ -__attribute__((always_inline)) INLINE static void hydro_slope_limit_cell_init( - struct part* p) { - - p->primitives.limiter.rho[0] = FLT_MAX; - p->primitives.limiter.rho[1] = -FLT_MAX; - p->primitives.limiter.v[0][0] = FLT_MAX; - p->primitives.limiter.v[0][1] = -FLT_MAX; - p->primitives.limiter.v[1][0] = FLT_MAX; - p->primitives.limiter.v[1][1] = -FLT_MAX; - p->primitives.limiter.v[2][0] = FLT_MAX; - p->primitives.limiter.v[2][1] = -FLT_MAX; - p->primitives.limiter.P[0] = FLT_MAX; - p->primitives.limiter.P[1] = -FLT_MAX; - - p->primitives.limiter.maxr = -FLT_MAX; -} - -/** - * @brief Collect information for the cell wide slope limiter during the - * neighbour loop - * - * @param pi Particle i. - * @param pj Particle j. - * @param r Distance between particle i and particle j. - */ -__attribute__((always_inline)) INLINE static void -hydro_slope_limit_cell_collect(struct part* pi, struct part* pj, float r) { - - /* basic slope limiter: collect the maximal and the minimal value for the - * primitive variables among the ngbs */ - pi->primitives.limiter.rho[0] = - min(pj->primitives.rho, pi->primitives.limiter.rho[0]); - pi->primitives.limiter.rho[1] = - max(pj->primitives.rho, pi->primitives.limiter.rho[1]); - - pi->primitives.limiter.v[0][0] = - min(pj->primitives.v[0], pi->primitives.limiter.v[0][0]); - pi->primitives.limiter.v[0][1] = - max(pj->primitives.v[0], pi->primitives.limiter.v[0][1]); - pi->primitives.limiter.v[1][0] = - min(pj->primitives.v[1], pi->primitives.limiter.v[1][0]); - pi->primitives.limiter.v[1][1] = - max(pj->primitives.v[1], pi->primitives.limiter.v[1][1]); - pi->primitives.limiter.v[2][0] = - min(pj->primitives.v[2], pi->primitives.limiter.v[2][0]); - pi->primitives.limiter.v[2][1] = - max(pj->primitives.v[2], pi->primitives.limiter.v[2][1]); - - pi->primitives.limiter.P[0] = - min(pj->primitives.P, pi->primitives.limiter.P[0]); - pi->primitives.limiter.P[1] = - max(pj->primitives.P, pi->primitives.limiter.P[1]); - - pi->primitives.limiter.maxr = max(r, pi->primitives.limiter.maxr); -} - -/** - * @brief Slope limit cell gradients - * - * @param p Particle. - */ -__attribute__((always_inline)) INLINE static void hydro_slope_limit_cell( - struct part* p) { - - float gradtrue, gradrho[3], gradv[3][3], gradP[3]; - - gradrho[0] = p->primitives.gradients.rho[0]; - gradrho[1] = p->primitives.gradients.rho[1]; - gradrho[2] = p->primitives.gradients.rho[2]; - - gradv[0][0] = p->primitives.gradients.v[0][0]; - gradv[0][1] = p->primitives.gradients.v[0][1]; - gradv[0][2] = p->primitives.gradients.v[0][2]; - - gradv[1][0] = p->primitives.gradients.v[1][0]; - gradv[1][1] = p->primitives.gradients.v[1][1]; - gradv[1][2] = p->primitives.gradients.v[1][2]; - - gradv[2][0] = p->primitives.gradients.v[2][0]; - gradv[2][1] = p->primitives.gradients.v[2][1]; - gradv[2][2] = p->primitives.gradients.v[2][2]; - - gradP[0] = p->primitives.gradients.P[0]; - gradP[1] = p->primitives.gradients.P[1]; - gradP[2] = p->primitives.gradients.P[2]; - - gradtrue = sqrtf(gradrho[0] * gradrho[0] + gradrho[1] * gradrho[1] + - gradrho[2] * gradrho[2]); - if (gradtrue) { - gradtrue *= p->primitives.limiter.maxr; - const float gradmax = p->primitives.limiter.rho[1] - p->primitives.rho; - const float gradmin = p->primitives.rho - p->primitives.limiter.rho[0]; - const float gradtrue_inv = 1.f / gradtrue; - const float alpha = - min3(1.0f, gradmax * gradtrue_inv, gradmin * gradtrue_inv); - p->primitives.gradients.rho[0] *= alpha; - p->primitives.gradients.rho[1] *= alpha; - p->primitives.gradients.rho[2] *= alpha; - } - - gradtrue = sqrtf(gradv[0][0] * gradv[0][0] + gradv[0][1] * gradv[0][1] + - gradv[0][2] * gradv[0][2]); - if (gradtrue) { - gradtrue *= p->primitives.limiter.maxr; - const float gradmax = p->primitives.limiter.v[0][1] - p->primitives.v[0]; - const float gradmin = p->primitives.v[0] - p->primitives.limiter.v[0][0]; - const float gradtrue_inv = 1.f / gradtrue; - const float alpha = - min3(1.0f, gradmax * gradtrue_inv, gradmin * gradtrue_inv); - p->primitives.gradients.v[0][0] *= alpha; - p->primitives.gradients.v[0][1] *= alpha; - p->primitives.gradients.v[0][2] *= alpha; - } - - gradtrue = sqrtf(gradv[1][0] * gradv[1][0] + gradv[1][1] * gradv[1][1] + - gradv[1][2] * gradv[1][2]); - if (gradtrue) { - gradtrue *= p->primitives.limiter.maxr; - const float gradmax = p->primitives.limiter.v[1][1] - p->primitives.v[1]; - const float gradmin = p->primitives.v[1] - p->primitives.limiter.v[1][0]; - const float gradtrue_inv = 1.f / gradtrue; - const float alpha = - min3(1.0f, gradmax * gradtrue_inv, gradmin * gradtrue_inv); - p->primitives.gradients.v[1][0] *= alpha; - p->primitives.gradients.v[1][1] *= alpha; - p->primitives.gradients.v[1][2] *= alpha; - } - - gradtrue = sqrtf(gradv[2][0] * gradv[2][0] + gradv[2][1] * gradv[2][1] + - gradv[2][2] * gradv[2][2]); - if (gradtrue) { - gradtrue *= p->primitives.limiter.maxr; - const float gradmax = p->primitives.limiter.v[2][1] - p->primitives.v[2]; - const float gradmin = p->primitives.v[2] - p->primitives.limiter.v[2][0]; - const float gradtrue_inv = 1.f / gradtrue; - const float alpha = - min3(1.0f, gradmax * gradtrue_inv, gradmin * gradtrue_inv); - p->primitives.gradients.v[2][0] *= alpha; - p->primitives.gradients.v[2][1] *= alpha; - p->primitives.gradients.v[2][2] *= alpha; - } - - gradtrue = - sqrtf(gradP[0] * gradP[0] + gradP[1] * gradP[1] + gradP[2] * gradP[2]); - if (gradtrue) { - gradtrue *= p->primitives.limiter.maxr; - const float gradmax = p->primitives.limiter.P[1] - p->primitives.P; - const float gradmin = p->primitives.P - p->primitives.limiter.P[0]; - const float gradtrue_inv = 1.f / gradtrue; - const float alpha = - min3(1.0f, gradmax * gradtrue_inv, gradmin * gradtrue_inv); - p->primitives.gradients.P[0] *= alpha; - p->primitives.gradients.P[1] *= alpha; - p->primitives.gradients.P[2] *= alpha; - } -} - -#endif /* SWIFT_GIZMO_MFV_SLOPE_LIMITER_CELL_H */ diff --git a/src/hydro/GizmoMFV/hydro_slope_limiters_face.h b/src/hydro/GizmoMFV/hydro_slope_limiters_face.h deleted file mode 100644 index b12f15590f51c16f494978d9501401709b2cbf59..0000000000000000000000000000000000000000 --- a/src/hydro/GizmoMFV/hydro_slope_limiters_face.h +++ /dev/null @@ -1,128 +0,0 @@ -/******************************************************************************* - * This file is part of SWIFT. - * Copyright (c) 2016 Bert Vandenbroucke (bert.vandenbroucke@gmail.com) - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU Lesser General Public License as published - * by the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public License - * along with this program. If not, see <http://www.gnu.org/licenses/>. - * - ******************************************************************************/ - -/** - * @brief Slope limit a single quantity at the interface - * - * @param phi_i Value of the quantity at the particle position. - * @param phi_j Value of the quantity at the neighbouring particle position. - * @param phi_mid0 Extrapolated value of the quantity at the interface position. - * @param xij_norm Distance between the particle position and the interface - * position. - * @param r Distance between the particle and its neighbour. - * @return The slope limited difference between the quantity at the particle - * position and the quantity at the interface position. - */ -#ifndef SWIFT_GIZMO_MFV_SLOPE_LIMITER_FACE_H -#define SWIFT_GIZMO_MFV_SLOPE_LIMITER_FACE_H - -/* Some standard headers. */ -#include <float.h> - -/* Local headers. */ -#include "minmax.h" -#include "sign.h" - -__attribute__((always_inline)) INLINE static float -hydro_slope_limit_face_quantity(float phi_i, float phi_j, float phi_mid0, - float xij_norm, float r_inv) { - - const float psi1 = 0.5f; - const float psi2 = 0.25f; - - const float delta1 = psi1 * fabsf(phi_i - phi_j); - const float delta2 = psi2 * fabsf(phi_i - phi_j); - - const float phimin = min(phi_i, phi_j); - const float phimax = max(phi_i, phi_j); - - const float phibar = phi_i + xij_norm * r_inv * (phi_j - phi_i); - - float phiplus, phiminus, phi_mid; - - if (same_signf(phimax + delta1, phimax)) - phiplus = phimax + delta1; - else - phiplus = phimax / (1.0f + delta1 / (fabsf(phimax) + FLT_MIN)); - - if (same_signf(phimin - delta1, phimin)) - phiminus = phimin - delta1; - else - phiminus = phimin / (1.0f + delta1 / (fabsf(phimin) + FLT_MIN)); - - if (phi_i < phi_j) { - const float temp = min(phibar + delta2, phi_mid0); - phi_mid = max(phiminus, temp); - } else { - const float temp = max(phibar - delta2, phi_mid0); - phi_mid = min(phiplus, temp); - } - - return phi_mid - phi_i; -} - -/** - * @brief Slope limit the slopes at the interface between two particles - * - * @param Wi Hydrodynamic variables of particle i. - * @param Wj Hydrodynamic variables of particle j. - * @param dWi Difference between the hydrodynamic variables of particle i at the - * position of particle i and at the interface position. - * @param dWj Difference between the hydrodynamic variables of particle j at the - * position of particle j and at the interface position. - * @param xij_i Relative position vector of the interface w.r.t. particle i. - * @param xij_j Relative position vector of the interface w.r.t. partilce j. - * @param r Distance between particle i and particle j. - */ -__attribute__((always_inline)) INLINE static void hydro_slope_limit_face( - float *Wi, float *Wj, float *dWi, float *dWj, const float *xij_i, - const float *xij_j, float r) { - - const float xij_i_norm = - sqrtf(xij_i[0] * xij_i[0] + xij_i[1] * xij_i[1] + xij_i[2] * xij_i[2]); - - const float xij_j_norm = - sqrtf(xij_j[0] * xij_j[0] + xij_j[1] * xij_j[1] + xij_j[2] * xij_j[2]); - - const float r_inv = 1.f / r; - - dWi[0] = hydro_slope_limit_face_quantity(Wi[0], Wj[0], Wi[0] + dWi[0], - xij_i_norm, r_inv); - dWi[1] = hydro_slope_limit_face_quantity(Wi[1], Wj[1], Wi[1] + dWi[1], - xij_i_norm, r_inv); - dWi[2] = hydro_slope_limit_face_quantity(Wi[2], Wj[2], Wi[2] + dWi[2], - xij_i_norm, r_inv); - dWi[3] = hydro_slope_limit_face_quantity(Wi[3], Wj[3], Wi[3] + dWi[3], - xij_i_norm, r_inv); - dWi[4] = hydro_slope_limit_face_quantity(Wi[4], Wj[4], Wi[4] + dWi[4], - xij_i_norm, r_inv); - - dWj[0] = hydro_slope_limit_face_quantity(Wj[0], Wi[0], Wj[0] + dWj[0], - xij_j_norm, r_inv); - dWj[1] = hydro_slope_limit_face_quantity(Wj[1], Wi[1], Wj[1] + dWj[1], - xij_j_norm, r_inv); - dWj[2] = hydro_slope_limit_face_quantity(Wj[2], Wi[2], Wj[2] + dWj[2], - xij_j_norm, r_inv); - dWj[3] = hydro_slope_limit_face_quantity(Wj[3], Wi[3], Wj[3] + dWj[3], - xij_j_norm, r_inv); - dWj[4] = hydro_slope_limit_face_quantity(Wj[4], Wi[4], Wj[4] + dWj[4], - xij_j_norm, r_inv); -} - -#endif /* SWIFT_GIZMO_MFV_SLOPE_LIMITER_FACE_H */ diff --git a/src/hydro/GizmoMFV/hydro_unphysical.h b/src/hydro/GizmoMFV/hydro_unphysical.h deleted file mode 100644 index 81c644e6cce00e0d871aafc39140e420e042a926..0000000000000000000000000000000000000000 --- a/src/hydro/GizmoMFV/hydro_unphysical.h +++ /dev/null @@ -1,69 +0,0 @@ -/******************************************************************************* - * This file is part of SWIFT. - * Copyright (c) 2017 Bert Vandenbroucke (bert.vandenbroucke@gmail.com) - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU Lesser General Public License as published - * by the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public License - * along with this program. If not, see <http://www.gnu.org/licenses/>. - * - ******************************************************************************/ -#ifndef SWIFT_HYDRO_UNPHYSICAL_H -#define SWIFT_HYDRO_UNPHYSICAL_H - -#if defined(GIZMO_UNPHYSICAL_ERROR) || defined(GIZMO_UNPHYSICAL_RESCUE) - -#if defined(GIZMO_UNPHYSICAL_ERROR) - -/*! @brief Crash whenever an unphysical value is detected. */ -#define gizmo_unphysical_message(name, quantity) \ - error("Unphysical " name " detected (%g)!", quantity); - -#elif defined(GIZMO_UNPHYSICAL_WARNING) - -/*! @brief Show a warning whenever an unphysical value is detected. */ -#define gizmo_unphysical_message(name, quantity) \ - message("Unphysical " name " detected (%g), reset to 0!", quantity); - -#else - -/*! @brief Don't tell anyone an unphysical value was detected. */ -#define gizmo_unphysical_message(name, quantity) - -#endif - -#define gizmo_check_physical_quantity(name, quantity) \ - if (quantity < 0.f) { \ - gizmo_unphysical_message(name, quantity); \ - quantity = 0.f; \ - } - -#define gizmo_check_physical_quantities( \ - mass_name, energy_name, mass, momentum_x, momentum_y, momentum_z, energy) \ - gizmo_check_physical_quantity(mass_name, mass); \ - gizmo_check_physical_quantity(energy_name, energy); \ - /* now check for vacuum and make sure we have a real vacuum */ \ - if (mass == 0.f || energy == 0.f) { \ - mass = 0.f; \ - momentum_x = 0.f; \ - momentum_y = 0.f; \ - momentum_z = 0.f; \ - energy = 0.f; \ - } - -#else // defined(GIZMO_UNPHYSICAL_ERROR) || defined(GIZMO_UNPHYSICAL_RESCUE) - -#define gizmo_check_physical_quantities( \ - mass_name, energy_name, mass, momentum_x, momentum_y, momentum_z, energy) - -#endif // defined(GIZMO_UNPHYSICAL_ERROR) || defined(GIZMO_UNPHYSICAL_RESCUE) - -#endif /* SWIFT_HYDRO_UNPHYSICAL_H */ diff --git a/src/hydro/Minimal/hydro.h b/src/hydro/Minimal/hydro.h index 533597e820f51837dcaca6ca22aa843fc983b129..e49575e769461de259285d92433f6dc1f6ac266c 100644 --- a/src/hydro/Minimal/hydro.h +++ b/src/hydro/Minimal/hydro.h @@ -863,7 +863,6 @@ __attribute__((always_inline)) INLINE static void hydro_first_init_part( struct part *restrict p, struct xpart *restrict xp) { p->time_bin = 0; - p->wakeup = time_bin_not_awake; xp->v_full[0] = p->v[0]; xp->v_full[1] = p->v[1]; xp->v_full[2] = p->v[2]; diff --git a/src/hydro/Minimal/hydro_debug.h b/src/hydro/Minimal/hydro_debug.h index 3fadd05f9b93e53f1855c5daa7727d272ffe0fa5..514fcad2cb1ee646d0f69dabf9c79fbaf1e8427a 100644 --- a/src/hydro/Minimal/hydro_debug.h +++ b/src/hydro/Minimal/hydro_debug.h @@ -46,7 +46,8 @@ __attribute__((always_inline)) INLINE static void hydro_debug_particle( xp->v_full[1], xp->v_full[2], p->a_hydro[0], p->a_hydro[1], p->a_hydro[2], p->mass, p->u, p->u_dt, hydro_get_comoving_pressure(p), p->force.soundspeed, p->force.v_sig, p->h, p->force.h_dt, - p->density.wcount, p->rho, p->density.rho_dh, p->time_bin, p->wakeup); + p->density.wcount, p->rho, p->density.rho_dh, p->time_bin, + p->limiter_data.wakeup); } #endif /* SWIFT_MINIMAL_HYDRO_DEBUG_H */ diff --git a/src/hydro/Minimal/hydro_iact.h b/src/hydro/Minimal/hydro_iact.h index 8929ede0ac8ef736776e745323d33bb0b2265021..e37edbe445942ae1f3de32a05c7421da460d1f3d 100644 --- a/src/hydro/Minimal/hydro_iact.h +++ b/src/hydro/Minimal/hydro_iact.h @@ -426,28 +426,4 @@ __attribute__((always_inline)) INLINE static void runner_iact_nonsym_force( pi->force.v_sig = max(pi->force.v_sig, v_sig); } -/** - * @brief Timestep limiter loop - */ -__attribute__((always_inline)) INLINE static void runner_iact_limiter( - float r2, const float *dx, float hi, float hj, struct part *restrict pi, - struct part *restrict pj, float a, float H) { - - /* Nothing to do here if both particles are active */ -} - -/** - * @brief Timestep limiter loop (non-symmetric version) - */ -__attribute__((always_inline)) INLINE static void runner_iact_nonsym_limiter( - float r2, const float *dx, float hi, float hj, struct part *restrict pi, - struct part *restrict pj, float a, float H) { - - /* Wake up the neighbour? */ - if (pi->force.v_sig > const_limiter_max_v_sig_ratio * pj->force.v_sig) { - - pj->wakeup = time_bin_awake; - } -} - #endif /* SWIFT_MINIMAL_HYDRO_IACT_H */ diff --git a/src/hydro/Minimal/hydro_io.h b/src/hydro/Minimal/hydro_io.h index ba62489bcc8a7bff3b9d3cd45d9b9d0881772194..9239de218e513fc2e9ae9e03d08dd421b6923d38 100644 --- a/src/hydro/Minimal/hydro_io.h +++ b/src/hydro/Minimal/hydro_io.h @@ -88,10 +88,11 @@ INLINE static void convert_part_pos(const struct engine* e, const struct part* p, const struct xpart* xp, double* ret) { - if (e->s->periodic) { - ret[0] = box_wrap(p->x[0], 0.0, e->s->dim[0]); - ret[1] = box_wrap(p->x[1], 0.0, e->s->dim[1]); - ret[2] = box_wrap(p->x[2], 0.0, e->s->dim[2]); + const struct space* s = e->s; + if (s->periodic) { + ret[0] = box_wrap(p->x[0] - s->pos_dithering[0], 0.0, s->dim[0]); + ret[1] = box_wrap(p->x[1] - s->pos_dithering[1], 0.0, s->dim[1]); + ret[2] = box_wrap(p->x[2] - s->pos_dithering[2], 0.0, s->dim[2]); } else { ret[0] = p->x[0]; ret[1] = p->x[1]; @@ -210,10 +211,6 @@ INLINE static void hydro_write_flavour(hid_t h_grpsph) { io_write_attribute_s(h_grpsph, "Thermal Conductivity Model", "No treatment"); io_write_attribute_s(h_grpsph, "Viscosity Model", "Minimal treatment as in Monaghan (1992)"); - - /* Time integration properties */ - io_write_attribute_f(h_grpsph, "Maximal Delta u change over dt", - const_max_u_change); } /** diff --git a/src/hydro/Minimal/hydro_part.h b/src/hydro/Minimal/hydro_part.h index 0e61b95cc164690b178806c9906a195cb86a01ac..9b31c4976d9a61e4a085df4059aea9b62380d181 100644 --- a/src/hydro/Minimal/hydro_part.h +++ b/src/hydro/Minimal/hydro_part.h @@ -35,7 +35,9 @@ #include "black_holes_struct.h" #include "chemistry_struct.h" #include "cooling_struct.h" +#include "feedback_struct.h" #include "star_formation_struct.h" +#include "timestep_limiter_struct.h" #include "tracers_struct.h" /** @@ -71,6 +73,9 @@ struct xpart { /* Additional data used by the tracers */ struct star_formation_xpart_data sf_data; + /* Additional data used by the feedback */ + struct feedback_part_data feedback_data; + } SWIFT_STRUCT_ALIGN; /** @@ -180,8 +185,8 @@ struct part { /*! Time-step length */ timebin_t time_bin; - /* Need waking-up ? */ - timebin_t wakeup; + /*! Time-step limiter information */ + struct timestep_limiter_data limiter_data; #ifdef SWIFT_DEBUG_CHECKS diff --git a/src/hydro/Planetary/hydro.h b/src/hydro/Planetary/hydro.h index 3891bf3df8245b63ec40985910aa7d827b0c00b7..7da89f0018a7bb9a1a0d0c7fc4c788416189d128 100644 --- a/src/hydro/Planetary/hydro.h +++ b/src/hydro/Planetary/hydro.h @@ -831,7 +831,6 @@ __attribute__((always_inline)) INLINE static void hydro_first_init_part( struct part *restrict p, struct xpart *restrict xp) { p->time_bin = 0; - p->wakeup = time_bin_not_awake; xp->v_full[0] = p->v[0]; xp->v_full[1] = p->v[1]; xp->v_full[2] = p->v[2]; diff --git a/src/hydro/Planetary/hydro_debug.h b/src/hydro/Planetary/hydro_debug.h index 6d0a226f49ab9d1b57f00cba646c7cb38eae180e..db3e60d0864837db2caad4f627e635f4932f0799 100644 --- a/src/hydro/Planetary/hydro_debug.h +++ b/src/hydro/Planetary/hydro_debug.h @@ -47,8 +47,8 @@ __attribute__((always_inline)) INLINE static void hydro_debug_particle( xp->v_full[1], xp->v_full[2], p->a_hydro[0], p->a_hydro[1], p->a_hydro[2], p->mass, p->u, p->u_dt, hydro_get_comoving_pressure(p), p->force.soundspeed, p->force.v_sig, p->h, p->force.h_dt, - p->density.wcount, p->rho, p->density.rho_dh, p->time_bin, p->wakeup, - p->mat_id); + p->density.wcount, p->rho, p->density.rho_dh, p->time_bin, + p->limiter_data.wakeup, p->mat_id); } #endif /* SWIFT_PLANETARY_HYDRO_DEBUG_H */ diff --git a/src/hydro/Planetary/hydro_iact.h b/src/hydro/Planetary/hydro_iact.h index 3a8d1f4e88fa9df0a1dcea500baf56e46bae7cd1..15340d302d55bbdbe37fc28d72b1e7f37b1269bf 100644 --- a/src/hydro/Planetary/hydro_iact.h +++ b/src/hydro/Planetary/hydro_iact.h @@ -348,28 +348,4 @@ __attribute__((always_inline)) INLINE static void runner_iact_nonsym_force( pi->force.v_sig = max(pi->force.v_sig, v_sig); } -/** - * @brief Timestep limiter loop - */ -__attribute__((always_inline)) INLINE static void runner_iact_limiter( - float r2, const float *dx, float hi, float hj, struct part *restrict pi, - struct part *restrict pj, float a, float H) { - - /* Nothing to do here if both particles are active */ -} - -/** - * @brief Timestep limiter loop (non-symmetric version) - */ -__attribute__((always_inline)) INLINE static void runner_iact_nonsym_limiter( - float r2, const float *dx, float hi, float hj, struct part *restrict pi, - struct part *restrict pj, float a, float H) { - - /* Wake up the neighbour? */ - if (pi->force.v_sig > const_limiter_max_v_sig_ratio * pj->force.v_sig) { - - pj->wakeup = time_bin_awake; - } -} - #endif /* SWIFT_PLANETARY_HYDRO_IACT_H */ diff --git a/src/hydro/Planetary/hydro_io.h b/src/hydro/Planetary/hydro_io.h index 782e4de6dc05c8d5b485f9f4d2dadd685e44e3a7..bf939ffa2c0052eb728abb182e5719bb914df122 100644 --- a/src/hydro/Planetary/hydro_io.h +++ b/src/hydro/Planetary/hydro_io.h @@ -61,15 +61,15 @@ INLINE static void hydro_read_particles(struct part* parts, UNIT_CONV_SPEED, parts, v); list[2] = io_make_input_field("Masses", FLOAT, 1, COMPULSORY, UNIT_CONV_MASS, parts, mass); - list[3] = io_make_input_field("SmoothingLength", FLOAT, 1, COMPULSORY, + list[3] = io_make_input_field("SmoothingLengths", FLOAT, 1, COMPULSORY, UNIT_CONV_LENGTH, parts, h); - list[4] = io_make_input_field("InternalEnergy", FLOAT, 1, COMPULSORY, + list[4] = io_make_input_field("InternalEnergies", FLOAT, 1, COMPULSORY, UNIT_CONV_ENERGY_PER_UNIT_MASS, parts, u); list[5] = io_make_input_field("ParticleIDs", ULONGLONG, 1, COMPULSORY, UNIT_CONV_NO_UNITS, parts, id); list[6] = io_make_input_field("Accelerations", FLOAT, 3, OPTIONAL, UNIT_CONV_ACCELERATION, parts, a_hydro); - list[7] = io_make_input_field("Density", FLOAT, 1, OPTIONAL, + list[7] = io_make_input_field("Densities", FLOAT, 1, OPTIONAL, UNIT_CONV_DENSITY, parts, rho); list[8] = io_make_input_field("MaterialIDs", INT, 1, COMPULSORY, UNIT_CONV_NO_UNITS, parts, mat_id); @@ -90,11 +90,11 @@ INLINE static void convert_P(const struct engine* e, const struct part* p, INLINE static void convert_part_pos(const struct engine* e, const struct part* p, const struct xpart* xp, double* ret) { - - if (e->s->periodic) { - ret[0] = box_wrap(p->x[0], 0.0, e->s->dim[0]); - ret[1] = box_wrap(p->x[1], 0.0, e->s->dim[1]); - ret[2] = box_wrap(p->x[2], 0.0, e->s->dim[2]); + const struct space* s = e->s; + if (s->periodic) { + ret[0] = box_wrap(p->x[0] - s->pos_dithering[0], 0.0, s->dim[0]); + ret[1] = box_wrap(p->x[1] - s->pos_dithering[1], 0.0, s->dim[1]); + ret[2] = box_wrap(p->x[2] - s->pos_dithering[2], 0.0, s->dim[2]); } else { ret[0] = p->x[0]; ret[1] = p->x[1]; @@ -214,10 +214,6 @@ INLINE static void hydro_write_flavour(hid_t h_grpsph) { h_grpsph, "Viscosity Model", "as in Springel (2005), i.e. Monaghan (1992) with Balsara (1995) switch"); #endif - - /* Time integration properties */ - io_write_attribute_f(h_grpsph, "Maximal Delta u change over dt", - const_max_u_change); } /** diff --git a/src/hydro/Planetary/hydro_part.h b/src/hydro/Planetary/hydro_part.h index db0396f7af06335e1e17b1255941781db1300a78..4c0c4b786c7010a1d8080dbc934d661ca61c6c75 100644 --- a/src/hydro/Planetary/hydro_part.h +++ b/src/hydro/Planetary/hydro_part.h @@ -37,7 +37,9 @@ #include "chemistry_struct.h" #include "cooling_struct.h" #include "equation_of_state.h" // For enum material_id +#include "feedback_struct.h" #include "star_formation_struct.h" +#include "timestep_limiter_struct.h" #include "tracers_struct.h" /** @@ -73,6 +75,9 @@ struct xpart { /* Additional data used by the star formation */ struct star_formation_xpart_data sf_data; + /* Additional data used by the feedback */ + struct feedback_part_data feedback_data; + } SWIFT_STRUCT_ALIGN; /** @@ -185,8 +190,8 @@ struct part { /*! Time-step length */ timebin_t time_bin; - /* Need waking-up ? */ - timebin_t wakeup; + /*! Time-step limiter information */ + struct timestep_limiter_data limiter_data; #ifdef SWIFT_DEBUG_CHECKS diff --git a/src/hydro/PressureEnergy/hydro.h b/src/hydro/PressureEnergy/hydro.h index 0dcad242774d88ce5b4c6aa6f2bf947b2d73a7fe..fddafa52a93fe5823c7808660858b83768efec85 100644 --- a/src/hydro/PressureEnergy/hydro.h +++ b/src/hydro/PressureEnergy/hydro.h @@ -442,6 +442,10 @@ hydro_set_drifted_physical_internal_energy(struct part *p, /* Update variables. */ hydro_update_soundspeed(p, cosmo); + + const float comoving_pressure_with_floor = + pressure_floor_get_comoving_pressure(p, p->pressure_bar, cosmo); + p->force.pressure_bar_with_floor = comoving_pressure_with_floor; } /** @@ -908,7 +912,6 @@ __attribute__((always_inline)) INLINE static void hydro_first_init_part( struct part *restrict p, struct xpart *restrict xp) { p->time_bin = 0; - p->wakeup = time_bin_not_awake; xp->v_full[0] = p->v[0]; xp->v_full[1] = p->v[1]; xp->v_full[2] = p->v[2]; diff --git a/src/hydro/PressureEnergy/hydro_debug.h b/src/hydro/PressureEnergy/hydro_debug.h index 861b16299f824abbee759c80e79d99d449a348c5..9c9fdd7bd6b3932a3753a92fad6b8e4c5bbcd2e4 100644 --- a/src/hydro/PressureEnergy/hydro_debug.h +++ b/src/hydro/PressureEnergy/hydro_debug.h @@ -37,7 +37,8 @@ __attribute__((always_inline)) INLINE static void hydro_debug_particle( xp->v_full[1], xp->v_full[2], p->a_hydro[0], p->a_hydro[1], p->a_hydro[2], p->u, p->u_dt, p->force.v_sig, hydro_get_comoving_pressure(p), p->h, p->force.h_dt, (int)p->density.wcount, p->mass, p->rho, - p->density.pressure_bar_dh, p->pressure_bar, p->time_bin, p->wakeup); + p->density.pressure_bar_dh, p->pressure_bar, p->time_bin, + p->limiter_data.wakeup); } #endif /* SWIFT_MINIMAL_HYDRO_DEBUG_H */ diff --git a/src/hydro/PressureEnergy/hydro_iact.h b/src/hydro/PressureEnergy/hydro_iact.h index f0bd99152202f613cefc2efe7dcb713fbffac509..f40253a08170e9af7c4b0be708c0c605ead469cf 100644 --- a/src/hydro/PressureEnergy/hydro_iact.h +++ b/src/hydro/PressureEnergy/hydro_iact.h @@ -437,28 +437,5 @@ __attribute__((always_inline)) INLINE static void runner_iact_nonsym_force( /* Update the signal velocity. */ pi->force.v_sig = max(pi->force.v_sig, v_sig); } -/** - * @brief Timestep limiter loop - */ -__attribute__((always_inline)) INLINE static void runner_iact_limiter( - float r2, const float* dx, float hi, float hj, struct part* restrict pi, - struct part* restrict pj, float a, float H) { - - /* Nothing to do here if both particles are active */ -} - -/** - * @brief Timestep limiter loop (non-symmetric version) - */ -__attribute__((always_inline)) INLINE static void runner_iact_nonsym_limiter( - float r2, const float* dx, float hi, float hj, struct part* restrict pi, - struct part* restrict pj, float a, float H) { - - /* Wake up the neighbour? */ - if (pi->force.v_sig > const_limiter_max_v_sig_ratio * pj->force.v_sig) { - - pj->wakeup = time_bin_awake; - } -} #endif /* SWIFT_PRESSURE_ENERGY_HYDRO_IACT_H */ diff --git a/src/hydro/PressureEnergy/hydro_io.h b/src/hydro/PressureEnergy/hydro_io.h index 896d0137ca7aae2d17159e4dbf335a9263dce3a7..2be85e79b67eba1d9d6306a64f7639cae4bac291 100644 --- a/src/hydro/PressureEnergy/hydro_io.h +++ b/src/hydro/PressureEnergy/hydro_io.h @@ -85,11 +85,11 @@ INLINE static void convert_P(const struct engine* e, const struct part* p, INLINE static void convert_part_pos(const struct engine* e, const struct part* p, const struct xpart* xp, double* ret) { - - if (e->s->periodic) { - ret[0] = box_wrap(p->x[0], 0.0, e->s->dim[0]); - ret[1] = box_wrap(p->x[1], 0.0, e->s->dim[1]); - ret[2] = box_wrap(p->x[2], 0.0, e->s->dim[2]); + const struct space* s = e->s; + if (s->periodic) { + ret[0] = box_wrap(p->x[0] - s->pos_dithering[0], 0.0, s->dim[0]); + ret[1] = box_wrap(p->x[1] - s->pos_dithering[1], 0.0, s->dim[1]); + ret[2] = box_wrap(p->x[2] - s->pos_dithering[2], 0.0, s->dim[2]); } else { ret[0] = p->x[0]; ret[1] = p->x[1]; @@ -210,10 +210,6 @@ INLINE static void hydro_write_flavour(hid_t h_grpsph) { io_write_attribute_s(h_grpsph, "Thermal Conductivity Model", "No treatment"); io_write_attribute_s(h_grpsph, "Viscosity Model", "Minimal treatment as in Monaghan (1992)"); - - /* Time integration properties */ - io_write_attribute_f(h_grpsph, "Maximal Delta u change over dt", - const_max_u_change); } /** diff --git a/src/hydro/PressureEnergy/hydro_part.h b/src/hydro/PressureEnergy/hydro_part.h index 6458d37e829076dc1fee1aa41ba91fed1622550b..82a6275f9c057479b5cdcddbdd31237c2b284885 100644 --- a/src/hydro/PressureEnergy/hydro_part.h +++ b/src/hydro/PressureEnergy/hydro_part.h @@ -34,8 +34,10 @@ #include "black_holes_struct.h" #include "chemistry_struct.h" #include "cooling_struct.h" +#include "feedback_struct.h" #include "pressure_floor_struct.h" #include "star_formation_struct.h" +#include "timestep_limiter_struct.h" #include "tracers_struct.h" /** @@ -71,6 +73,9 @@ struct xpart { /*! Additional data used by the star formation */ struct star_formation_xpart_data sf_data; + /* Additional data used by the feedback */ + struct feedback_part_data feedback_data; + } SWIFT_STRUCT_ALIGN; /** @@ -187,8 +192,8 @@ struct part { /*! Time-step length */ timebin_t time_bin; - /* Need waking-up ? */ - timebin_t wakeup; + /*! Time-step limiter information */ + struct timestep_limiter_data limiter_data; #ifdef SWIFT_DEBUG_CHECKS @@ -202,4 +207,4 @@ struct part { } SWIFT_STRUCT_ALIGN; -#endif /* SWIFT_MINIMAL_HYDRO_PART_H */ +#endif /* SWIFT_PRESSURE_ENERGY_HYDRO_PART_H */ diff --git a/src/hydro/PressureEnergyMorrisMonaghanAV/hydro.h b/src/hydro/PressureEnergyMorrisMonaghanAV/hydro.h index 80a6c7a021a518c7086218b8e3146c9ed5f4b4ac..27508dd7ea3db86cf4c65e3762694488a53616bf 100644 --- a/src/hydro/PressureEnergyMorrisMonaghanAV/hydro.h +++ b/src/hydro/PressureEnergyMorrisMonaghanAV/hydro.h @@ -911,7 +911,6 @@ __attribute__((always_inline)) INLINE static void hydro_first_init_part( struct part *restrict p, struct xpart *restrict xp) { p->time_bin = 0; - p->wakeup = time_bin_not_awake; xp->v_full[0] = p->v[0]; xp->v_full[1] = p->v[1]; xp->v_full[2] = p->v[2]; diff --git a/src/hydro/PressureEnergyMorrisMonaghanAV/hydro_debug.h b/src/hydro/PressureEnergyMorrisMonaghanAV/hydro_debug.h index 7f728e9a5d390a8508730725ff2f8eb82126f616..0f0b974252b4d3290366af9e65913ff92b666ee6 100644 --- a/src/hydro/PressureEnergyMorrisMonaghanAV/hydro_debug.h +++ b/src/hydro/PressureEnergyMorrisMonaghanAV/hydro_debug.h @@ -41,8 +41,8 @@ __attribute__((always_inline)) INLINE static void hydro_debug_particle( xp->v_full[1], xp->v_full[2], p->a_hydro[0], p->a_hydro[1], p->a_hydro[2], p->u, p->u_dt, p->force.v_sig, hydro_get_comoving_pressure(p), p->h, p->force.h_dt, (int)p->density.wcount, p->mass, p->density.rho_dh, p->rho, - p->density.pressure_bar_dh, p->pressure_bar, p->time_bin, p->wakeup, - p->alpha); + p->density.pressure_bar_dh, p->pressure_bar, p->time_bin, + p->limiter_data.wakeup, p->alpha); } #endif /* SWIFT_PRESSURE_ENERGY_MORRIS_HYDRO_DEBUG_H */ diff --git a/src/hydro/PressureEnergyMorrisMonaghanAV/hydro_iact.h b/src/hydro/PressureEnergyMorrisMonaghanAV/hydro_iact.h index 3e0fec0459e7ac17b90d49007c7b38a18f4d8dbc..6ed6dd2c36dd81a69ef1116a3f101c80b2c90f1e 100644 --- a/src/hydro/PressureEnergyMorrisMonaghanAV/hydro_iact.h +++ b/src/hydro/PressureEnergyMorrisMonaghanAV/hydro_iact.h @@ -426,28 +426,4 @@ __attribute__((always_inline)) INLINE static void runner_iact_nonsym_force( pi->force.v_sig = max(pi->force.v_sig, v_sig); } -/** - * @brief Timestep limiter loop - */ -__attribute__((always_inline)) INLINE static void runner_iact_limiter( - float r2, const float* dx, float hi, float hj, struct part* restrict pi, - struct part* restrict pj, float a, float H) { - - /* Nothing to do here if both particles are active */ -} - -/** - * @brief Timestep limiter loop (non-symmetric version) - */ -__attribute__((always_inline)) INLINE static void runner_iact_nonsym_limiter( - float r2, const float* dx, float hi, float hj, struct part* restrict pi, - struct part* restrict pj, float a, float H) { - - /* Wake up the neighbour? */ - if (pi->force.v_sig > const_limiter_max_v_sig_ratio * pj->force.v_sig) { - - pj->wakeup = time_bin_awake; - } -} - #endif /* SWIFT_PRESSURE_ENERGY_MORRIS_HYDRO_IACT_H */ diff --git a/src/hydro/PressureEnergyMorrisMonaghanAV/hydro_io.h b/src/hydro/PressureEnergyMorrisMonaghanAV/hydro_io.h index 7da369847a5d684ebe30dbf7428ea3da9a8c216f..69385e5609609a6fe9451d2b3f2aa8fad1e50830 100644 --- a/src/hydro/PressureEnergyMorrisMonaghanAV/hydro_io.h +++ b/src/hydro/PressureEnergyMorrisMonaghanAV/hydro_io.h @@ -86,11 +86,11 @@ INLINE static void convert_P(const struct engine* e, const struct part* p, INLINE static void convert_part_pos(const struct engine* e, const struct part* p, const struct xpart* xp, double* ret) { - - if (e->s->periodic) { - ret[0] = box_wrap(p->x[0], 0.0, e->s->dim[0]); - ret[1] = box_wrap(p->x[1], 0.0, e->s->dim[1]); - ret[2] = box_wrap(p->x[2], 0.0, e->s->dim[2]); + const struct space* s = e->s; + if (s->periodic) { + ret[0] = box_wrap(p->x[0] - s->pos_dithering[0], 0.0, s->dim[0]); + ret[1] = box_wrap(p->x[1] - s->pos_dithering[1], 0.0, s->dim[1]); + ret[2] = box_wrap(p->x[2] - s->pos_dithering[2], 0.0, s->dim[2]); } else { ret[0] = p->x[0]; ret[1] = p->x[1]; @@ -215,10 +215,6 @@ INLINE static void hydro_write_flavour(hid_t h_grpsph) { io_write_attribute_s(h_grpsph, "Thermal Conductivity Model", "No treatment"); io_write_attribute_s(h_grpsph, "Viscosity Model", "Variable viscosity as in Morris and Monaghan (1997)"); - - /* Time integration properties */ - io_write_attribute_f(h_grpsph, "Maximal Delta u change over dt", - const_max_u_change); } /** diff --git a/src/hydro/PressureEnergyMorrisMonaghanAV/hydro_part.h b/src/hydro/PressureEnergyMorrisMonaghanAV/hydro_part.h index 644b30234ad40d0571249726f96358453e06956a..b21dbc6e81239a23f481c598dc16eea98f572fe2 100644 --- a/src/hydro/PressureEnergyMorrisMonaghanAV/hydro_part.h +++ b/src/hydro/PressureEnergyMorrisMonaghanAV/hydro_part.h @@ -35,7 +35,9 @@ #include "black_holes_struct.h" #include "chemistry_struct.h" #include "cooling_struct.h" +#include "feedback_struct.h" #include "star_formation_struct.h" +#include "timestep_limiter_struct.h" #include "tracers_struct.h" /** @@ -71,6 +73,9 @@ struct xpart { /*! Additional data used by the star formation */ struct star_formation_xpart_data sf_data; + /* Additional data used by the feedback */ + struct feedback_part_data feedback_data; + } SWIFT_STRUCT_ALIGN; /** @@ -184,8 +189,8 @@ struct part { /*! Time-step length */ timebin_t time_bin; - /* Need waking-up ? */ - timebin_t wakeup; + /*! Time-step limiter information */ + struct timestep_limiter_data limiter_data; #ifdef SWIFT_DEBUG_CHECKS diff --git a/src/hydro/PressureEntropy/hydro.h b/src/hydro/PressureEntropy/hydro.h index 759202204bfb667bbc5d7b9495e2d51d1aeae9ca..fd19256ebf2c6fc746dfeb367ae242794bcb69cb 100644 --- a/src/hydro/PressureEntropy/hydro.h +++ b/src/hydro/PressureEntropy/hydro.h @@ -832,7 +832,6 @@ __attribute__((always_inline)) INLINE static void hydro_first_init_part( struct part *restrict p, struct xpart *restrict xp) { p->time_bin = 0; - p->wakeup = time_bin_not_awake; p->rho_bar = 0.f; p->entropy_one_over_gamma = pow_one_over_gamma(p->entropy); xp->v_full[0] = p->v[0]; diff --git a/src/hydro/PressureEntropy/hydro_debug.h b/src/hydro/PressureEntropy/hydro_debug.h index 2163b70b94dde4e88f010d962358dccbde7960a3..c2c250c11f6f932c665c37f6f1c78bff8d3444d1 100644 --- a/src/hydro/PressureEntropy/hydro_debug.h +++ b/src/hydro/PressureEntropy/hydro_debug.h @@ -43,7 +43,7 @@ __attribute__((always_inline)) INLINE static void hydro_debug_particle( p->rho, p->rho_bar, hydro_get_comoving_pressure(p), p->density.pressure_dh, p->force.P_over_rho2, p->entropy, p->entropy_one_over_gamma, p->entropy_dt, p->force.soundspeed, - p->force.v_sig, p->force.h_dt, p->time_bin, p->wakeup); + p->force.v_sig, p->force.h_dt, p->time_bin, p->limiter_data.wakeup); } #endif /* SWIFT_PRESSURE_ENTROPY_HYDRO_DEBUG_H */ diff --git a/src/hydro/PressureEntropy/hydro_iact.h b/src/hydro/PressureEntropy/hydro_iact.h index d5045d77f2850408b33a70e9b9d6d880577bea0f..194932f65e14a649b0c64d1f72e93c540521e717 100644 --- a/src/hydro/PressureEntropy/hydro_iact.h +++ b/src/hydro/PressureEntropy/hydro_iact.h @@ -404,28 +404,4 @@ __attribute__((always_inline)) INLINE static void runner_iact_nonsym_force( pi->entropy_dt += mj * visc_term * r_inv * dvdr; } -/** - * @brief Timestep limiter loop - */ -__attribute__((always_inline)) INLINE static void runner_iact_limiter( - float r2, const float *dx, float hi, float hj, struct part *restrict pi, - struct part *restrict pj, float a, float H) { - - /* Nothing to do here if both particles are active */ -} - -/** - * @brief Timestep limiter loop (non-symmetric version) - */ -__attribute__((always_inline)) INLINE static void runner_iact_nonsym_limiter( - float r2, const float *dx, float hi, float hj, struct part *restrict pi, - struct part *restrict pj, float a, float H) { - - /* Wake up the neighbour? */ - if (pi->force.v_sig > const_limiter_max_v_sig_ratio * pj->force.v_sig) { - - pj->wakeup = time_bin_awake; - } -} - #endif /* SWIFT_PRESSURE_ENTROPY_HYDRO_IACT_H */ diff --git a/src/hydro/PressureEntropy/hydro_io.h b/src/hydro/PressureEntropy/hydro_io.h index 8ac77f31efde3b708cbf631c792404b135e4c112..d3c800e03ff46920d203ef0831fa2d7a5c48b077 100644 --- a/src/hydro/PressureEntropy/hydro_io.h +++ b/src/hydro/PressureEntropy/hydro_io.h @@ -86,10 +86,11 @@ INLINE static void convert_part_pos(const struct engine* e, const struct part* p, const struct xpart* xp, double* ret) { - if (e->s->periodic) { - ret[0] = box_wrap(p->x[0], 0.0, e->s->dim[0]); - ret[1] = box_wrap(p->x[1], 0.0, e->s->dim[1]); - ret[2] = box_wrap(p->x[2], 0.0, e->s->dim[2]); + const struct space* s = e->s; + if (s->periodic) { + ret[0] = box_wrap(p->x[0] - s->pos_dithering[0], 0.0, s->dim[0]); + ret[1] = box_wrap(p->x[1] - s->pos_dithering[1], 0.0, s->dim[1]); + ret[2] = box_wrap(p->x[2] - s->pos_dithering[2], 0.0, s->dim[2]); } else { ret[0] = p->x[0]; ret[1] = p->x[1]; @@ -216,10 +217,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"); - - /* Time integration properties */ - io_write_attribute_f(h_grpsph, "Maximal Delta u change over dt", - const_max_u_change); } /** diff --git a/src/hydro/PressureEntropy/hydro_part.h b/src/hydro/PressureEntropy/hydro_part.h index cf7204ba1e157ce69f523414ab0321f61d110a94..7c77bf88a727832270d644f289d9a60b273cdd80 100644 --- a/src/hydro/PressureEntropy/hydro_part.h +++ b/src/hydro/PressureEntropy/hydro_part.h @@ -33,7 +33,9 @@ #include "black_holes_struct.h" #include "chemistry_struct.h" #include "cooling_struct.h" +#include "feedback_struct.h" #include "star_formation_struct.h" +#include "timestep_limiter_struct.h" #include "tracers_struct.h" /* Extra particle data not needed during the SPH loops over neighbours. */ @@ -63,6 +65,9 @@ struct xpart { /*! Additional data used by the star formation */ struct star_formation_xpart_data sf_data; + /* Additional data used by the feedback */ + struct feedback_part_data feedback_data; + } SWIFT_STRUCT_ALIGN; /* Data of a single particle. */ @@ -160,8 +165,8 @@ struct part { /* Time-step length */ timebin_t time_bin; - /* Need waking-up ? */ - timebin_t wakeup; + /*! Time-step limiter information */ + struct timestep_limiter_data limiter_data; #ifdef SWIFT_DEBUG_CHECKS diff --git a/src/hydro/AnarchyDU/hydro.h b/src/hydro/SPHENIX/hydro.h similarity index 95% rename from src/hydro/AnarchyDU/hydro.h rename to src/hydro/SPHENIX/hydro.h index 984e67d036cb71a70d33266a279447c20b18447b..496a5b8e6b8f13e2ec8b13e4da7ec48b6c02ea62 100644 --- a/src/hydro/AnarchyDU/hydro.h +++ b/src/hydro/SPHENIX/hydro.h @@ -17,14 +17,13 @@ * along with this program. If not, see <http://www.gnu.org/licenses/>. * ******************************************************************************/ -#ifndef SWIFT_ANARCHY_DU_HYDRO_H -#define SWIFT_ANARCHY_DU_HYDRO_H +#ifndef SWIFT_SPHENIX_HYDRO_H +#define SWIFT_SPHENIX_HYDRO_H /** - * @file AnarchyDU/hydro.h + * @file SPHENIX/hydro.h * @brief Density-Energy conservative implementation of SPH, - * with added ANARCHY physics (Cullen & Denhen 2011 AV, - * Price 2008 thermal diffusion (Non-neighbour loop + * with added SPHENIX physics (Borrow 2020) (Non-neighbour loop * equations) */ @@ -38,6 +37,7 @@ #include "hydro_space.h" #include "kernel_hydro.h" #include "minmax.h" +#include "pressure_floor.h" #include "./hydro_parameters.h" @@ -408,11 +408,14 @@ hydro_set_drifted_physical_internal_energy(struct part *p, /* Compute the sound speed */ const float pressure = gas_pressure_from_internal_energy(p->rho, p->u); - const float soundspeed = gas_soundspeed_from_pressure(p->rho, pressure); + const float pressure_including_floor = + pressure_floor_get_comoving_pressure(p, pressure, cosmo); + const float soundspeed = + gas_soundspeed_from_pressure(p->rho, pressure_including_floor); /* Update variables. */ p->force.soundspeed = soundspeed; - p->force.pressure = pressure; + p->force.pressure = pressure_including_floor; p->viscosity.v_sig = max(p->viscosity.v_sig, 2.f * soundspeed); } @@ -590,9 +593,12 @@ __attribute__((always_inline)) INLINE static void hydro_prepare_gradient( /* Compute the norm of div v */ const float abs_div_v = fabsf(p->viscosity.div_v); - /* Compute the sound speed -- see theory section for justification */ - const float soundspeed = hydro_get_comoving_soundspeed(p); + /* Compute the sound speed */ const float pressure = hydro_get_comoving_pressure(p); + const float pressure_including_floor = + pressure_floor_get_comoving_pressure(p, pressure, cosmo); + const float soundspeed = + gas_soundspeed_from_pressure(p->rho, pressure_including_floor); /* Compute the Balsara switch */ const float balsara = @@ -611,7 +617,7 @@ __attribute__((always_inline)) INLINE static void hydro_prepare_gradient( /* Update variables. */ p->force.f = grad_h_term; - p->force.pressure = pressure; + p->force.pressure = pressure_including_floor; p->force.soundspeed = soundspeed; p->force.balsara = balsara; } @@ -720,7 +726,12 @@ __attribute__((always_inline)) INLINE static void hydro_prepare_force( const float kernel_support_physical = p->h * cosmo->a * kernel_gamma; const float kernel_support_physical_inv = 1.f / kernel_support_physical; const float v_sig_physical = p->viscosity.v_sig * cosmo->a_factor_sound_speed; - const float soundspeed_physical = hydro_get_physical_soundspeed(p, cosmo); + const float pressure = hydro_get_comoving_pressure(p); + const float pressure_including_floor = + pressure_floor_get_comoving_pressure(p, pressure, cosmo); + const float soundspeed_physical = + gas_soundspeed_from_pressure(p->rho, pressure_including_floor) * + cosmo->a_factor_sound_speed; const float sound_crossing_time_inverse = soundspeed_physical * kernel_support_physical_inv; @@ -851,9 +862,12 @@ __attribute__((always_inline)) INLINE static void hydro_reset_predicted_values( /* Compute the sound speed */ const float pressure = gas_pressure_from_internal_energy(p->rho, p->u); - const float soundspeed = hydro_get_comoving_soundspeed(p); + const float pressure_including_floor = + pressure_floor_get_comoving_pressure(p, pressure, cosmo); + const float soundspeed = + gas_soundspeed_from_pressure(p->rho, pressure_including_floor); - p->force.pressure = pressure; + p->force.pressure = pressure_including_floor; p->force.soundspeed = soundspeed; /* Update the signal velocity, if we need to. */ @@ -919,9 +933,12 @@ __attribute__((always_inline)) INLINE static void hydro_predict_extra( /* Compute the new sound speed */ const float pressure = gas_pressure_from_internal_energy(p->rho, p->u); - const float soundspeed = gas_soundspeed_from_pressure(p->rho, pressure); + const float pressure_including_floor = + pressure_floor_get_comoving_pressure(p, pressure, cosmo); + const float soundspeed = + gas_soundspeed_from_pressure(p->rho, pressure_including_floor); - p->force.pressure = pressure; + p->force.pressure = pressure_including_floor; p->force.soundspeed = soundspeed; /* Update signal velocity if we need to */ @@ -1034,9 +1051,12 @@ __attribute__((always_inline)) INLINE static void hydro_convert_quantities( p->diffusion.alpha = hydro_props->diffusion.alpha; const float pressure = gas_pressure_from_internal_energy(p->rho, p->u); - const float soundspeed = gas_soundspeed_from_internal_energy(p->rho, p->u); + const float pressure_including_floor = + pressure_floor_get_comoving_pressure(p, pressure, cosmo); + const float soundspeed = + gas_soundspeed_from_pressure(p->rho, pressure_including_floor); - p->force.pressure = pressure; + p->force.pressure = pressure_including_floor; p->force.soundspeed = soundspeed; } @@ -1054,7 +1074,6 @@ __attribute__((always_inline)) INLINE static void hydro_first_init_part( struct part *restrict p, struct xpart *restrict xp) { p->time_bin = 0; - p->wakeup = time_bin_not_awake; xp->v_full[0] = p->v[0]; xp->v_full[1] = p->v[1]; xp->v_full[2] = p->v[2]; @@ -1084,4 +1103,4 @@ hydro_set_init_internal_energy(struct part *p, float u_init) { p->u = u_init; } -#endif /* SWIFT_ANARCHY_DU_HYDRO_H */ +#endif /* SWIFT_SPHENIX_HYDRO_H */ diff --git a/src/hydro/AnarchyDU/hydro_debug.h b/src/hydro/SPHENIX/hydro_debug.h similarity index 86% rename from src/hydro/AnarchyDU/hydro_debug.h rename to src/hydro/SPHENIX/hydro_debug.h index bc72bec62f8ddff6086516a32a4b86651e6aa66a..62d134f4e19411be3405bd29453bf2f20592fa8e 100644 --- a/src/hydro/AnarchyDU/hydro_debug.h +++ b/src/hydro/SPHENIX/hydro_debug.h @@ -18,14 +18,13 @@ * ******************************************************************************/ -#ifndef SWIFT_ANARCHY_DU_HYDRO_DEBUG_H -#define SWIFT_ANARCHY_DU_HYDRO_DEBUG_H +#ifndef SWIFT_SPHENIX_HYDRO_DEBUG_H +#define SWIFT_SPHENIX_HYDRO_DEBUG_H /** - * @file AnarchyDU/hydro_debug.h + * @file SPHENIX/hydro_debug.h * @brief Density-Energy conservative implementation of SPH, - * with added ANARCHY physics (Cullen & Denhen 2011 AV, - * Price 2008 thermal diffusion (Debugging routines) + * with added SPHENIX physics (Borrow 2020) (Debugging routines) */ __attribute__((always_inline)) INLINE static void hydro_debug_particle( @@ -44,4 +43,4 @@ __attribute__((always_inline)) INLINE static void hydro_debug_particle( p->viscosity.alpha, p->time_bin); } -#endif /* SWIFT_ANARCHY_DU_HYDRO_DEBUG_H */ +#endif /* SWIFT_SPHENIX_HYDRO_DEBUG_H */ diff --git a/src/hydro/AnarchyDU/hydro_iact.h b/src/hydro/SPHENIX/hydro_iact.h similarity index 90% rename from src/hydro/AnarchyDU/hydro_iact.h rename to src/hydro/SPHENIX/hydro_iact.h index 09ecde01d44cfef1c0edbfe0d3f1aa909d553a95..012f70200405b998c12944cbfdb86e27f123c7f0 100644 --- a/src/hydro/AnarchyDU/hydro_iact.h +++ b/src/hydro/SPHENIX/hydro_iact.h @@ -17,14 +17,13 @@ * along with this program. If not, see <http://www.gnu.org/licenses/>. * ******************************************************************************/ -#ifndef SWIFT_ANARCHY_DU_HYDRO_IACT_H -#define SWIFT_ANARCHY_DU_HYDRO_IACT_H +#ifndef SWIFT_SPHENIX_HYDRO_IACT_H +#define SWIFT_SPHENIX_HYDRO_IACT_H /** - * @file AnarchyDU/hydro_iact.h + * @file SPHENIX/hydro_iact.h * @brief Density-Energy conservative implementation of SPH, - * with added ANARCHY physics (Cullen & Denhen 2011 AV, - * Price 2008 thermal diffusion (interaction routines) + * with added SPHENIX physics (Borrow 2020) (interaction routines) */ #include "adiabatic_index.h" @@ -409,7 +408,13 @@ __attribute__((always_inline)) INLINE static void runner_iact_force( const float visc_du_term = 0.5f * visc_acc_term * dvdr_Hubble; /* Diffusion term */ - const float alpha_diff = 0.5f * (pi->diffusion.alpha + pj->diffusion.alpha); + /* Combine the alpha_diff into a pressure-based switch -- this allows the + * alpha from the highest pressure particle to dominate, so that the + * diffusion limited particles always take precedence - another trick to + * allow the scheme to work with thermal feedback. */ + const float alpha_diff = + (pressurei * pi->diffusion.alpha + pressurej * pj->diffusion.alpha) / + (pressurei + pressurej); const float v_diff = alpha_diff * 0.5f * (sqrtf(2.f * fabsf(pressurei - pressurej) / rho_ij) + fabsf(fac_mu * r_inv * dvdr_Hubble)); @@ -537,7 +542,13 @@ __attribute__((always_inline)) INLINE static void runner_iact_nonsym_force( const float visc_du_term = 0.5f * visc_acc_term * dvdr_Hubble; /* Diffusion term */ - const float alpha_diff = 0.5f * (pi->diffusion.alpha + pj->diffusion.alpha); + /* Combine the alpha_diff into a pressure-based switch -- this allows the + * alpha from the highest pressure particle to dominate, so that the + * diffusion limited particles always take precedence - another trick to + * allow the scheme to work with thermal feedback. */ + const float alpha_diff = + (pressurei * pi->diffusion.alpha + pressurej * pj->diffusion.alpha) / + (pressurei + pressurej); const float v_diff = alpha_diff * 0.5f * (sqrtf(2.f * fabsf(pressurei - pressurej) / rho_ij) + fabsf(fac_mu * r_inv * dvdr_Hubble)); @@ -560,49 +571,4 @@ __attribute__((always_inline)) INLINE static void runner_iact_nonsym_force( pi->viscosity.v_sig = max(pi->viscosity.v_sig, v_sig); } -/** - * @brief Timestep limiter loop - * - * @param r2 Comoving square distance between the two particles. - * @param dx Comoving vector separating both particles (pi - pj). - * @param hi Comoving smoothing-length of part*icle i. - * @param hj Comoving smoothing-length of part*icle j. - * @param pi First part*icle. - * @param pj Second part*icle (not updated). - * @param a Current scale factor. - * @param H Current Hubble parameter. - * - */ -__attribute__((always_inline)) INLINE static void runner_iact_limiter( - float r2, const float* dx, float hi, float hj, struct part* restrict pi, - struct part* restrict pj, float a, float H) { - - /* Nothing to do here if both particles are active */ -} - -/** - * @brief Timestep limiter loop (non-symmetric version) - * - * @param r2 Comoving square distance between the two particles. - * @param dx Comoving vector separating both particles (pi - pj). - * @param hi Comoving smoothing-length of part*icle i. - * @param hj Comoving smoothing-length of part*icle j. - * @param pi First part*icle. - * @param pj Second part*icle (not updated). - * @param a Current scale factor. - * @param H Current Hubble parameter. - * - */ -__attribute__((always_inline)) INLINE static void runner_iact_nonsym_limiter( - float r2, const float* dx, float hi, float hj, struct part* restrict pi, - struct part* restrict pj, float a, float H) { - - /* Wake up the neighbour? */ - if (pi->viscosity.v_sig > - const_limiter_max_v_sig_ratio * pj->viscosity.v_sig) { - - pj->wakeup = time_bin_awake; - } -} - -#endif /* SWIFT_ANARCHY_DU_HYDRO_IACT_H */ +#endif /* SWIFT_SPHENIX_HYDRO_IACT_H */ diff --git a/src/hydro/AnarchyDU/hydro_io.h b/src/hydro/SPHENIX/hydro_io.h similarity index 93% rename from src/hydro/AnarchyDU/hydro_io.h rename to src/hydro/SPHENIX/hydro_io.h index 4044a0c1f1cdbf4263de03071b046cd4c0884d2e..1b2d31a0ff3d8b244372f538b785109d9f1191a8 100644 --- a/src/hydro/AnarchyDU/hydro_io.h +++ b/src/hydro/SPHENIX/hydro_io.h @@ -17,14 +17,13 @@ * along with this program. If not, see <http://www.gnu.org/licenses/>. * ******************************************************************************/ -#ifndef SWIFT_ANARCHY_DU_HYDRO_IO_H -#define SWIFT_ANARCHY_DU_HYDRO_IO_H +#ifndef SWIFT_SPHENIX_HYDRO_IO_H +#define SWIFT_SPHENIX_HYDRO_IO_H /** - * @file AnarchyDU/hydro_io.h + * @file SPHENIX/hydro_io.h * @brief Density-Energy conservative implementation of SPH, - * with added ANARCHY physics (Cullen & Denhen 2011 AV, - * Price 2008 thermal diffusion (i/o routines) + * with added SPHENIX physics (Borrow 2020) (i/o routines) */ #include "adiabatic_index.h" @@ -82,10 +81,11 @@ INLINE static void convert_part_pos(const struct engine* e, const struct part* p, const struct xpart* xp, double* ret) { - if (e->s->periodic) { - ret[0] = box_wrap(p->x[0], 0.0, e->s->dim[0]); - ret[1] = box_wrap(p->x[1], 0.0, e->s->dim[1]); - ret[2] = box_wrap(p->x[2], 0.0, e->s->dim[2]); + const struct space* s = e->s; + if (s->periodic) { + ret[0] = box_wrap(p->x[0] - s->pos_dithering[0], 0.0, s->dim[0]); + ret[1] = box_wrap(p->x[1] - s->pos_dithering[1], 0.0, s->dim[1]); + ret[2] = box_wrap(p->x[2] - s->pos_dithering[2], 0.0, s->dim[2]); } else { ret[0] = p->x[0]; ret[1] = p->x[1]; @@ -222,10 +222,6 @@ INLINE static void hydro_write_flavour(hid_t h_grpsph) { "Simple treatment as in Price (2008)"); io_write_attribute_s(h_grpsph, "Viscosity Model", "Simplified version of Cullen & Denhen (2011)"); - - /* Time integration properties */ - io_write_attribute_f(h_grpsph, "Maximal Delta u change over dt", - const_max_u_change); } /** @@ -235,4 +231,4 @@ INLINE static void hydro_write_flavour(hid_t h_grpsph) { */ INLINE static int writeEntropyFlag(void) { return 0; } -#endif /* SWIFT_ANARCHY_DU_HYDRO_IO_H */ +#endif /* SWIFT_SPHENIX_HYDRO_IO_H */ diff --git a/src/hydro/AnarchyDU/hydro_parameters.h b/src/hydro/SPHENIX/hydro_parameters.h similarity index 95% rename from src/hydro/AnarchyDU/hydro_parameters.h rename to src/hydro/SPHENIX/hydro_parameters.h index 63af6503145066e757f3a3827db0f71d9f841770..d77693a50e2b33c4e5917badbd937af50da4892e 100644 --- a/src/hydro/AnarchyDU/hydro_parameters.h +++ b/src/hydro/SPHENIX/hydro_parameters.h @@ -18,8 +18,8 @@ * ******************************************************************************/ -#ifndef SWIFT_ANARCHY_DU_HYDRO_PARAMETERS_H -#define SWIFT_ANARCHY_DU_HYDRO_PARAMETERS_H +#ifndef SWIFT_SPHENIX_HYDRO_PARAMETERS_H +#define SWIFT_SPHENIX_HYDRO_PARAMETERS_H /* Configuration file */ #include "config.h" @@ -35,10 +35,9 @@ #include "inline.h" /** - * @file AnarchyDU/hydro_parameters.h + * @file SPHENIX/hydro_parameters.h * @brief Density-Energy conservative implementation of SPH, - * with added ANARCHY physics (Cullen & Denhen 2011 AV, - * Price 2008 thermal diffusion (default compile-time + * with added SPHENIX physics (Borrow 2020) (default compile-time * parameters). * * This file defines a number of things that are used in @@ -71,9 +70,7 @@ /*! Maximal value for the viscosity alpha in variable schemes. */ #define hydro_props_default_viscosity_alpha_max 2.0f -/*! Decay length for the viscosity scheme. This is scheme dependent. In - * non-variable schemes this must be defined but is not used. This also - * sets the decay length for the diffusion. */ +/*! Decay length for the viscosity scheme. This is scheme dependent. */ #define hydro_props_default_viscosity_length 0.25f /* Diffusion parameters -- FIXED -- MUST BE DEFINED AT COMPILE-TIME */ @@ -95,7 +92,7 @@ * very small in schemes where little diffusion is needed, 0.2-1.0 in * schemes (e.g. density-energy) where diffusion is needed to solve * the contact discontinuity problem. */ -#define hydro_props_default_diffusion_beta 0.25f +#define hydro_props_default_diffusion_beta 1.0f /*! Maximal value for the diffusion alpha in variable schemes. */ #define hydro_props_default_diffusion_alpha_max 1.0f @@ -303,4 +300,4 @@ static INLINE void diffusion_print_snapshot( } #endif -#endif /* SWIFT_ANARCHY_DU_HYDRO_PARAMETERS_H */ +#endif /* SWIFT_SPHENIX_HYDRO_PARAMETERS_H */ diff --git a/src/hydro/AnarchyDU/hydro_part.h b/src/hydro/SPHENIX/hydro_part.h similarity index 89% rename from src/hydro/AnarchyDU/hydro_part.h rename to src/hydro/SPHENIX/hydro_part.h index 4b4cc187a96f5111389cde8c50f535a545e9e7f5..e7f9a60545d7b0dedc3aa7163aaceb2e8047d234 100644 --- a/src/hydro/AnarchyDU/hydro_part.h +++ b/src/hydro/SPHENIX/hydro_part.h @@ -17,20 +17,22 @@ * along with this program. If not, see <http://www.gnu.org/licenses/>. * ******************************************************************************/ -#ifndef SWIFT_ANARCHY_DU_HYDRO_PART_H -#define SWIFT_ANARCHY_DU_HYDRO_PART_H +#ifndef SWIFT_SPHENIX_HYDRO_PART_H +#define SWIFT_SPHENIX_HYDRO_PART_H /** - * @file AnarchyDU/hydro_part.h + * @file SPHENIX/hydro_part.h * @brief Density-Energy conservative implementation of SPH, - * with added ANARCHY physics (Cullen & Denhen 2011 AV, - * Price 2008 thermal diffusion (particle definition) + * with added SPHENIX physics (Borrow 2020) (particle definition) */ #include "black_holes_struct.h" #include "chemistry_struct.h" #include "cooling_struct.h" +#include "feedback_struct.h" +#include "pressure_floor_struct.h" #include "star_formation_struct.h" +#include "timestep_limiter_struct.h" #include "tracers_struct.h" /** @@ -66,6 +68,9 @@ struct xpart { /* Additional data used by the tracers */ struct star_formation_xpart_data sf_data; + /* Additional data used by the feedback */ + struct feedback_part_data feedback_data; + } SWIFT_STRUCT_ALIGN; /** @@ -197,11 +202,14 @@ struct part { /*! Black holes information (e.g. swallowing ID) */ struct black_holes_part_data black_holes_data; + /* Additional data used by the pressure floor */ + struct pressure_floor_part_data pressure_floor_data; + /*! Time-step length */ timebin_t time_bin; - /* Need waking up ? */ - timebin_t wakeup; + /*! Time-step limiter information */ + struct timestep_limiter_data limiter_data; #ifdef SWIFT_DEBUG_CHECKS @@ -215,4 +223,4 @@ struct part { } SWIFT_STRUCT_ALIGN; -#endif /* SWIFT_ANARCHY_DU_HYDRO_PART_H */ +#endif /* SWIFT_SPHENIX_HYDRO_PART_H */ diff --git a/src/hydro/Shadowswift/hydro.h b/src/hydro/Shadowswift/hydro.h index b1d47a3711df7cc9e034f50e7a4f15c5349276be..0fb06b5ea3633df158e4aae0446d22a12b63160f 100644 --- a/src/hydro/Shadowswift/hydro.h +++ b/src/hydro/Shadowswift/hydro.h @@ -105,7 +105,6 @@ __attribute__((always_inline)) INLINE static void hydro_first_init_part( const float mass = p->conserved.mass; p->time_bin = 0; - p->wakeup = time_bin_not_awake; p->primitives.v[0] = p->v[0]; p->primitives.v[1] = p->v[1]; diff --git a/src/hydro/Shadowswift/hydro_debug.h b/src/hydro/Shadowswift/hydro_debug.h index 8ff85d62fc7d58d53220b1f77a7afb44c00c33b0..3ee8dddc54bf16b8fc5c07f8924b4a5e2a6bd45c 100644 --- a/src/hydro/Shadowswift/hydro_debug.h +++ b/src/hydro/Shadowswift/hydro_debug.h @@ -49,7 +49,7 @@ __attribute__((always_inline)) INLINE static void hydro_debug_particle( "wcount_dh=%.3e, " "wcount=%.3e}", p->x[0], p->x[1], p->x[2], p->v[0], p->v[1], p->v[2], p->a_hydro[0], - p->a_hydro[1], p->a_hydro[2], p->time_bin, p->wakeup, p->h, + p->a_hydro[1], p->a_hydro[2], p->time_bin, p->limiter_data.wakeup, p->h, p->primitives.v[0], p->primitives.v[1], p->primitives.v[2], p->primitives.rho, p->primitives.P, p->primitives.gradients.rho[0], p->primitives.gradients.rho[1], p->primitives.gradients.rho[2], diff --git a/src/hydro/Shadowswift/hydro_iact.h b/src/hydro/Shadowswift/hydro_iact.h index 791e4c7924df9806fa9150d03c08a543771a7049..eda8e3759d9e08dac8073ebed9fb36dd0c5b99f6 100644 --- a/src/hydro/Shadowswift/hydro_iact.h +++ b/src/hydro/Shadowswift/hydro_iact.h @@ -342,28 +342,3 @@ __attribute__((always_inline)) INLINE static void runner_iact_nonsym_force( runner_iact_fluxes_common(r2, dx, hi, hj, pi, pj, 0, a, H); } - -/** - * @brief Timestep limiter loop - */ -__attribute__((always_inline)) INLINE static void runner_iact_limiter( - float r2, const float *dx, float hi, float hj, struct part *restrict pi, - struct part *restrict pj, float a, float H) { - - /* Nothing to do here if both particles are active */ -} - -/** - * @brief Timestep limiter loop (non-symmetric version) - */ -__attribute__((always_inline)) INLINE static void runner_iact_nonsym_limiter( - float r2, const float *dx, float hi, float hj, struct part *restrict pi, - struct part *restrict pj, float a, float H) { - - /* Wake up the neighbour? */ - if (pi->timestepvars.vmax > - const_limiter_max_v_sig_ratio * pj->timestepvars.vmax) { - - pj->wakeup = time_bin_awake; - } -} diff --git a/src/hydro/Shadowswift/hydro_io.h b/src/hydro/Shadowswift/hydro_io.h index 31840a05ee436d5b535ae022bd79118851ef4e5b..b4b352fc0151d0967778a9d75e55fb61f3bf7c6c 100644 --- a/src/hydro/Shadowswift/hydro_io.h +++ b/src/hydro/Shadowswift/hydro_io.h @@ -111,11 +111,11 @@ INLINE static void convert_Etot(const struct engine* e, const struct part* p, INLINE static void convert_part_pos(const struct engine* e, const struct part* p, const struct xpart* xp, double* ret) { - - if (e->s->periodic) { - ret[0] = box_wrap(p->x[0], 0.0, e->s->dim[0]); - ret[1] = box_wrap(p->x[1], 0.0, e->s->dim[1]); - ret[2] = box_wrap(p->x[2], 0.0, e->s->dim[2]); + const struct space* s = e->s; + if (s->periodic) { + ret[0] = box_wrap(p->x[0] - s->pos_dithering[0], 0.0, s->dim[0]); + ret[1] = box_wrap(p->x[1] - s->pos_dithering[1], 0.0, s->dim[1]); + ret[2] = box_wrap(p->x[2] - s->pos_dithering[2], 0.0, s->dim[2]); } else { ret[0] = p->x[0]; ret[1] = p->x[1]; diff --git a/src/hydro/Shadowswift/hydro_part.h b/src/hydro/Shadowswift/hydro_part.h index 4d8c44a3637b6ca67ba00d3c6f654692504207f6..bd43ab43db7325a3cb65672b946720342903d08f 100644 --- a/src/hydro/Shadowswift/hydro_part.h +++ b/src/hydro/Shadowswift/hydro_part.h @@ -24,6 +24,8 @@ #include "black_holes_struct.h" #include "chemistry_struct.h" #include "cooling_struct.h" +#include "feedback_struct.h" +#include "timestep_limiter_struct.h" #include "tracers_struct.h" #include "voronoi_cell.h" @@ -48,6 +50,9 @@ struct xpart { /* Additional data used by the tracers */ struct tracers_xpart_data tracers_data; + /* Additional data used by the feedback */ + struct feedback_part_data feedback_data; + } SWIFT_STRUCT_ALIGN; /* Data of a single particle. */ @@ -189,8 +194,8 @@ struct part { /* Time-step length */ timebin_t time_bin; - /* Need waking-up ? */ - timebin_t wakeup; + /*! Time-step limiter information */ + struct timestep_limiter_data limiter_data; #ifdef SWIFT_DEBUG_CHECKS diff --git a/src/hydro_io.h b/src/hydro_io.h index ccfb57371ac28ba4931fc14d547b0b674c77d48d..d3e98771898f6cfdd8b7758932fd65b8534b5f27 100644 --- a/src/hydro_io.h +++ b/src/hydro_io.h @@ -35,16 +35,14 @@ #include "./hydro/PressureEnergyMorrisMonaghanAV/hydro_io.h" #elif defined(DEFAULT_SPH) #include "./hydro/Default/hydro_io.h" -#elif defined(GIZMO_MFV_SPH) -#include "./hydro/GizmoMFV/hydro_io.h" -#elif defined(GIZMO_MFM_SPH) -#include "./hydro/GizmoMFM/hydro_io.h" +#elif defined(GIZMO_MFV_SPH) || defined(GIZMO_MFM_SPH) +#include "./hydro/Gizmo/hydro_io.h" #elif defined(SHADOWFAX_SPH) #include "./hydro/Shadowswift/hydro_io.h" #elif defined(PLANETARY_SPH) #include "./hydro/Planetary/hydro_io.h" -#elif defined(ANARCHY_DU_SPH) -#include "./hydro/AnarchyDU/hydro_io.h" +#elif defined(SPHENIX_SPH) +#include "./hydro/SPHENIX/hydro_io.h" #elif defined(ANARCHY_PU_SPH) #include "./hydro/AnarchyPU/hydro_io.h" #else diff --git a/src/hydro_parameters.h b/src/hydro_parameters.h index 322bea5496893965fc727f957f54a19e57ee3e44..852e510c1a46fb72bf1f949dd3dea753aeabe75a 100644 --- a/src/hydro_parameters.h +++ b/src/hydro_parameters.h @@ -41,16 +41,14 @@ #include "./hydro/PressureEnergyMorrisMonaghanAV/hydro_parameters.h" #elif defined(DEFAULT_SPH) #include "./hydro/Default/hydro_parameters.h" -#elif defined(GIZMO_MFV_SPH) -#include "./hydro/GizmoMFV/hydro_parameters.h" -#elif defined(GIZMO_MFM_SPH) -#include "./hydro/GizmoMFM/hydro_parameters.h" +#elif defined(GIZMO_MFV_SPH) || defined(GIZMO_MFM_SPH) +#include "./hydro/Gizmo/hydro_parameters.h" #elif defined(SHADOWFAX_SPH) #include "./hydro/Shadowswift/hydro_parameters.h" #elif defined(PLANETARY_SPH) #include "./hydro/Planetary/hydro_parameters.h" -#elif defined(ANARCHY_DU_SPH) -#include "./hydro/AnarchyDU/hydro_parameters.h" +#elif defined(SPHENIX_SPH) +#include "./hydro/SPHENIX/hydro_parameters.h" #elif defined(ANARCHY_PU_SPH) #include "./hydro/AnarchyPU/hydro_parameters.h" #else diff --git a/src/hydro_properties.c b/src/hydro_properties.c index db4c60eb045662193efd552573a9e17666951c81..12549d47fdfb909e4fcbfd50f6abac6579e17942 100644 --- a/src/hydro_properties.c +++ b/src/hydro_properties.c @@ -59,6 +59,8 @@ void hydro_props_init(struct hydro_props *p, const struct unit_system *us, struct swift_params *params) { + /* ------ Smoothing lengths parameters ---------- */ + /* Kernel properties */ p->eta_neighbours = parser_get_param_float(params, "SPH:resolution_eta"); @@ -98,6 +100,8 @@ void hydro_props_init(struct hydro_props *p, if (p->max_smoothing_iterations <= 10) error("The number of smoothing length iterations should be > 10"); + /* ------ Neighbour number definition ------------ */ + /* Non-conventional neighbour number definition */ p->use_mass_weighted_num_ngb = parser_get_opt_param_int(params, "SPH:use_mass_weighted_num_ngb", 0); @@ -108,6 +112,8 @@ void hydro_props_init(struct hydro_props *p, #endif } + /* ------ Time integration parameters ------------ */ + /* Time integration properties */ p->CFL_condition = parser_get_param_float(params, "SPH:CFL_condition"); const float max_volume_change = parser_get_opt_param_float( @@ -121,6 +127,8 @@ void hydro_props_init(struct hydro_props *p, if (p->initial_temperature < 0.f) error("ERROR: Initial temperature set to a negative value!!!"); + /* ------ Temperature parameters ----------------- */ + /* Minimal temperature */ p->minimal_temperature = parser_get_opt_param_float( params, "SPH:minimal_temperature", hydro_props_default_min_temp); @@ -185,6 +193,17 @@ void hydro_props_init(struct hydro_props *p, mean_molecular_weight = 4. / (1. + 3. * p->hydrogen_mass_fraction); p->minimal_internal_energy = u_min / mean_molecular_weight; + + /* ------ Particle splitting parameters ---------- */ + + /* Are we doing particle splitting? */ + p->particle_splitting = + parser_get_opt_param_int(params, "SPH:particle_splitting", 0); + + if (p->particle_splitting) { + p->particle_splitting_mass_threshold = + parser_get_param_float(params, "SPH:particle_splitting_mass_threshold"); + } } /** @@ -225,6 +244,9 @@ void hydro_props_print(const struct hydro_props *p) { if (p->h_max != hydro_props_default_h_max) message("Maximal smoothing length allowed: %.4f", p->h_max); + message("Maximal time-bin difference between neighbours: %d", + time_bin_neighbour_max_delta_bin); + if (p->max_smoothing_iterations != hydro_props_default_max_iterations) message("Maximal iterations in ghost task set to %d (default is %d)", p->max_smoothing_iterations, hydro_props_default_max_iterations); @@ -235,6 +257,12 @@ void hydro_props_print(const struct hydro_props *p) { if (p->minimal_temperature != hydro_props_default_min_temp) message("Minimal gas temperature set to %f", p->minimal_temperature); + if (p->particle_splitting) + message("Splitting particles with mass > %e U_M", + p->particle_splitting_mass_threshold); + else + message("No particle splitting"); + /* Print out the implementation-dependent viscosity parameters * (see hydro/SCHEME/hydro_parameters.h for this implementation) */ viscosity_print(&(p->viscosity)); @@ -271,6 +299,7 @@ void hydro_props_print_snapshot(hid_t h_grpsph, const struct hydro_props *p) { io_write_attribute_f(h_grpsph, "Kernel target N_ngb", p->target_neighbours); io_write_attribute_f(h_grpsph, "Kernel delta N_ngb", p->delta_neighbours); io_write_attribute_f(h_grpsph, "Kernel eta", p->eta_neighbours); + io_write_attribute_f(h_grpsph, "Kernel gamma", kernel_gamma); io_write_attribute_f(h_grpsph, "Smoothing length tolerance", p->h_tolerance); io_write_attribute_f(h_grpsph, "Maximal smoothing length [internal units]", p->h_max); @@ -293,8 +322,9 @@ 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, "Max v_sig ratio (limiter)", - const_limiter_max_v_sig_ratio); + io_write_attribute_i(h_grpsph, + "Maximal time-bin difference between neighbours", + time_bin_neighbour_max_delta_bin); /* Write out the implementation-dependent viscosity parameters * (see hydro/SCHEME/hydro_parameters.h for this implementation) */ diff --git a/src/hydro_properties.h b/src/hydro_properties.h index 54949eb91c03ed80e55d0a5a7156214b6e0e01c7..daba471b884f7d9fd24d1d85a086c59ec0431196 100644 --- a/src/hydro_properties.h +++ b/src/hydro_properties.h @@ -47,6 +47,8 @@ struct unit_system; */ struct hydro_props { + /* ------ Smoothing lengths parameters ---------- */ + /*! Resolution parameter */ float eta_neighbours; @@ -59,37 +61,43 @@ struct hydro_props { /*! Tolerance on neighbour number (for info only)*/ float delta_neighbours; - /*! Maximal smoothing length */ + /*! Maximal smoothing length (internal units) */ float h_max; /*! Minimal smoothing length expressed as ratio to softening length */ float h_min_ratio; - /*! Minimal smoothing length */ + /*! Minimal smoothing length (internal units) */ float h_min; /*! Maximal number of iterations to converge h */ int max_smoothing_iterations; + /* ------ Neighbour number definition ------------ */ + /*! Are we using the mass-weighted definition of neighbour number? */ int use_mass_weighted_num_ngb; + /* ------ Time integration parameters ------------ */ + /*! Time integration properties */ float CFL_condition; /*! Maximal change of h over one time-step */ float log_max_h_change; + /* ------ Temperature parameters ----------------- */ + /*! Minimal temperature allowed */ float minimal_temperature; - /*! Minimal physical internal energy per unit mass */ + /*! Minimal physical internal energy per unit mass (internal units) */ float minimal_internal_energy; /*! Initial temperature */ float initial_temperature; - /*! Initial physical internal energy per unit mass */ + /*! Initial physical internal energy per unit mass (internal units) */ float initial_internal_energy; /*! Primordial hydrogen mass fraction for initial energy conversion */ @@ -104,6 +112,16 @@ struct hydro_props { /*! Mean molecular weight above hydrogen ionization temperature */ float mu_ionised; + /* ------ Particle splitting parameters ---------- */ + + /*! Is particle splitting activated? */ + int particle_splitting; + + /*! Mass above which particles get split (internal units) */ + float particle_splitting_mass_threshold; + + /* ------ Viscosity and diffusion ---------------- */ + /*! Artificial viscosity parameters */ struct viscosity_global_data viscosity; diff --git a/src/kernel_hydro.h b/src/kernel_hydro.h index 3d5ec6ac84a77941739f5d3b57ed0340c831c061..6e3d964a348cf65d4ed427951f643f8c0c4ad240 100644 --- a/src/kernel_hydro.h +++ b/src/kernel_hydro.h @@ -194,7 +194,7 @@ static const float kernel_coeffs[(kernel_degree + 1) * (kernel_ivals + 1)] /* ------------------------------------------------------------------------- */ #else -#error "A kernel function must be chosen in const.h !!" +#error "A kernel function must be chosen at configure time !!" /* ------------------------------------------------------------------------- */ #endif @@ -519,7 +519,8 @@ __attribute__((always_inline)) INLINE static void kernel_deval_1_vec( dw_dx->v = vec_blend(mask_reg, dw_dx->v, dw_dx2.v); #else -#error "Vectorisation not supported for this kernel!!!" +#error \ + "Vectorisation not supported for this kernel!!! Choose a different one or configure with --disable-hand-vec." #endif /* Return everyting */ @@ -706,7 +707,8 @@ __attribute__((always_inline)) INLINE static void kernel_eval_W_vec(vector *u, w->v = vec_blend(mask_reg, w->v, w2.v); #else -#error "Vectorisation not supported for this kernel!!!" +#error \ + "Vectorisation not supported for this kernel!!! Choose a different one or configure with --disable-hand-vec." #endif /* Return everything */ @@ -765,7 +767,8 @@ __attribute__((always_inline)) INLINE static void kernel_eval_dWdx_vec( /* Added both dwdx and dwdx2 together to form complete result. */ dw_dx->v = vec_add(dw_dx->v, dw_dx2.v); #else -#error "Vectorisation not supported for this kernel!!!" +#error \ + "Vectorisation not supported for this kernel!!! Choose a different one or configure with --disable-hand-vec." #endif /* Return everything */ @@ -826,7 +829,8 @@ __attribute__((always_inline)) INLINE static void kernel_eval_dWdx_force_vec( dw_dx->v = vec_blend(mask_reg, dw_dx->v, dw_dx2.v); #else -#error "Vectorisation not supported for this kernel!!!" +#error \ + "Vectorisation not supported for this kernel!!! Choose a different one or configure with --disable-hand-vec." #endif /* Mask out result for particles that lie outside of the kernel function. */ @@ -910,7 +914,8 @@ __attribute__((always_inline)) INLINE static void kernel_eval_dWdx_force_2_vec( dw_dx_2->v = vec_blend(mask_reg_v2, dw_dx_2->v, dw_dx2_2.v); #else -#error "Vectorisation not supported for this kernel!!!" +#error \ + "Vectorisation not supported for this kernel!!! Choose a different one or configure with --disable-hand-vec." #endif /* Mask out result for particles that lie outside of the kernel function. */ diff --git a/src/kick.h b/src/kick.h index 0e28e271aad04e9b16a4e988112aa95b36cb4f20..16cde83952d23698cc20783af6a44c7a728274e6 100644 --- a/src/kick.h +++ b/src/kick.h @@ -23,6 +23,7 @@ #include "../config.h" /* Local headers. */ +#include "black_holes.h" #include "const.h" #include "debug.h" #include "stars.h" @@ -88,7 +89,8 @@ __attribute__((always_inline)) INLINE static void kick_part( error( "particle has not been kicked to the current time p->ti_kick=%lld, " "ti_start=%lld, ti_end=%lld id=%lld time_bin=%d wakeup=%d", - p->ti_kick, ti_start, ti_end, p->id, p->time_bin, p->wakeup); + p->ti_kick, ti_start, ti_end, p->id, p->time_bin, + p->limiter_data.wakeup); p->ti_kick = ti_end; #endif diff --git a/src/logger.c b/src/logger.c index 762eb516077ef82f08b6c34da09cd7bc9eb6a280..d31c5b58b1e0bdcdc7cafc953b0e9dbd4fb649d4 100644 --- a/src/logger.c +++ b/src/logger.c @@ -46,7 +46,7 @@ */ /* Number of bytes for a mask. */ // TODO change this to number of bits -#define logger_mask_size 1 +#define logger_mask_size 2 /* Number of bits for chunk header. */ #define logger_header_bytes 8 @@ -77,10 +77,13 @@ const struct mask_data logger_mask_data[logger_count_mask] = { {sizeof(float), 1 << logger_rho, "density"}, /* Particle's constants: mass (float) and ID (long long). */ {sizeof(float) + sizeof(long long), 1 << logger_consts, "consts"}, + /* Flag for special cases (e.g. change of MPI rank, star formation, ...) */ + {sizeof(int), 1 << logger_special_flags, "special flags"}, /* Simulation time stamp: integertime and double time (e.g. scale factor or time). */ {sizeof(integertime_t) + sizeof(double), 1 << logger_timestamp, - "timestamp"}}; + "timestamp"}, +}; /** * @brief Write the header of a chunk (offset + mask). @@ -101,7 +104,7 @@ char *logger_write_chunk_header(char *buff, const unsigned int *mask, buff += logger_mask_size; /* write offset. */ - size_t diff_offset = offset_new - *offset; + uint64_t diff_offset = offset_new - *offset; memcpy(buff, &diff_offset, logger_offset_size); buff += logger_offset_size; @@ -165,50 +168,73 @@ int logger_compute_chunk_size(unsigned int mask) { /** * @brief log all particles in the engine. * - * @param log The #logger + * @param log The #logger_writer * @param e The #engine */ void logger_log_all(struct logger_writer *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 + logger_ensure_size(log, e->s->nr_parts, e->s->nr_gparts, e->s->nr_sparts); /* some constants. */ const struct space *s = e->s; - const unsigned int mask = + const unsigned int mask_hydro = logger_mask_data[logger_x].mask | logger_mask_data[logger_v].mask | logger_mask_data[logger_a].mask | logger_mask_data[logger_u].mask | logger_mask_data[logger_h].mask | logger_mask_data[logger_rho].mask | logger_mask_data[logger_consts].mask; /* 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); + for (size_t i = 0; i < s->nr_parts; i++) { + logger_log_part(log, &s->parts[i], mask_hydro, + &s->xparts[i].logger_data.last_offset, + /* Special flags */ 0); s->xparts[i].logger_data.steps_since_last_output = 0; } - /* loop over all gparts. */ - if (e->total_nr_gparts > 0) error("Not implemented"); + const unsigned int mask_grav = + logger_mask_data[logger_x].mask | logger_mask_data[logger_v].mask | + logger_mask_data[logger_a].mask | logger_mask_data[logger_consts].mask; + + /* loop over all gparts */ + for (size_t i = 0; i < s->nr_gparts; i++) { + /* Log only the dark matter */ + if (s->gparts[i].type != swift_type_dark_matter) continue; + + logger_log_gpart(log, &s->gparts[i], mask_grav, + &s->gparts[i].logger_data.last_offset, + /* Special flags */ 0); + s->gparts[i].logger_data.steps_since_last_output = 0; + } + + const unsigned int mask_stars = logger_mask_data[logger_x].mask | + logger_mask_data[logger_v].mask | + logger_mask_data[logger_consts].mask; - /* loop over all sparts. */ - // TODO + /* loop over all sparts */ + for (size_t i = 0; i < s->nr_sparts; i++) { + logger_log_spart(log, &s->sparts[i], mask_stars, + &s->sparts[i].logger_data.last_offset, + /* Special flags */ 0); + s->sparts[i].logger_data.steps_since_last_output = 0; + } + + if (e->total_nr_bparts > 0) error("Not implemented"); } /** * @brief Dump a #part to the log. * - * @param log The #logger + * @param log The #logger_writer * @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 special_flags The value of the special flag. * (return) offset of this log. */ void logger_log_part(struct logger_writer *log, const struct part *p, - unsigned int mask, size_t *offset) { + unsigned int mask, size_t *offset, + const int special_flags) { /* Make sure we're not writing a timestamp. */ if (mask & logger_mask_data[logger_timestamp].mask) @@ -267,12 +293,85 @@ void logger_log_part(struct logger_writer *log, const struct part *p, // TODO make it dependent of logger_mask_data memcpy(buff, &p->mass, sizeof(float)); buff += sizeof(float); - memcpy(buff, &p->id, sizeof(long long)); - buff += sizeof(long long); + const int64_t id = p->id; + memcpy(buff, &id, sizeof(int64_t)); + buff += sizeof(int64_t); } #endif + /* Special flags */ + if (mask & logger_mask_data[logger_special_flags].mask) { + memcpy(buff, &special_flags, logger_mask_data[logger_special_flags].size); + buff += logger_mask_data[logger_special_flags].size; + } + + /* Update the log message offset. */ + *offset = offset_new; +} + +/** + * @brief Dump a #spart to the log. + * + * @param log The #logger_writer + * @param sp The #spart 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 special_flags The value of the special flag. + * (return) offset of this log. + */ +void logger_log_spart(struct logger_writer *log, const struct spart *sp, + unsigned int mask, size_t *offset, + const int special_flags) { + + /* Make sure we're not writing a timestamp. */ + if (mask & logger_mask_data[logger_timestamp].mask) + error("You should not log particles as timestamps."); + + /* Make sure we're not looging fields not supported by gparts. */ + if (mask & + (logger_mask_data[logger_u].mask | logger_mask_data[logger_rho].mask | + logger_mask_data[logger_a].mask)) + error("Can't log SPH quantities for sparts."); + + /* Start by computing the size of the message. */ + 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(&log->dump, size, &offset_new); + + /* Write the header. */ + buff = logger_write_chunk_header(buff, &mask, offset, offset_new); + + /* Particle position as three doubles. */ + if (mask & logger_mask_data[logger_x].mask) { + memcpy(buff, sp->x, logger_mask_data[logger_x].size); + buff += logger_mask_data[logger_x].size; + } + + /* Particle velocity as three floats. */ + if (mask & logger_mask_data[logger_v].mask) { + memcpy(buff, sp->v, logger_mask_data[logger_v].size); + buff += logger_mask_data[logger_v].size; + } + + /* Particle constants, which is a bit more complicated. */ + if (mask & logger_mask_data[logger_consts].mask) { + // TODO make it dependent of logger_mask_data + memcpy(buff, &sp->mass, sizeof(float)); + buff += sizeof(float); + const int64_t id = sp->id; + memcpy(buff, &id, sizeof(int64_t)); + buff += sizeof(int64_t); + } + + /* Special flags */ + if (mask & logger_mask_data[logger_special_flags].mask) { + memcpy(buff, &special_flags, logger_mask_data[logger_special_flags].size); + buff += logger_mask_data[logger_special_flags].size; + } + /* Update the log message offset. */ *offset = offset_new; } @@ -280,14 +379,22 @@ void logger_log_part(struct logger_writer *log, const struct part *p, /** * @brief Dump a #gpart to the log. * - * @param log The #logger + * @param log The #logger_writer * @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 special_flags The value of the special flags. * (return) offset of this log. */ void logger_log_gpart(struct logger_writer *log, const struct gpart *p, - unsigned int mask, size_t *offset) { + unsigned int mask, size_t *offset, + const int special_flags) { + +#ifdef SWIFT_DEBUG_CHECKS + if (p->id_or_neg_offset < 0) { + error("Cannot log a gpart attached to another particle"); + } +#endif /* Make sure we're not writing a timestamp. */ if (mask & logger_mask_data[logger_timestamp].mask) @@ -331,8 +438,15 @@ void logger_log_gpart(struct logger_writer *log, const struct gpart *p, // TODO make it dependent of logger_mask_data. memcpy(buff, &p->mass, sizeof(float)); buff += sizeof(float); - memcpy(buff, &p->id_or_neg_offset, sizeof(long long)); - buff += sizeof(long long); + const int64_t id = p->id_or_neg_offset; + memcpy(buff, &id, sizeof(int64_t)); + buff += sizeof(int64_t); + } + + /* Special flags */ + if (mask & logger_mask_data[logger_special_flags].mask) { + memcpy(buff, &special_flags, logger_mask_data[logger_special_flags].size); + buff += logger_mask_data[logger_special_flags].size; } /* Update the log message offset. */ @@ -342,7 +456,7 @@ void logger_log_gpart(struct logger_writer *log, const struct gpart *p, /** * @brief write a timestamp * - * @param log The #logger + * @param log The #logger_writer * @param timestamp time to write * @param time time or scale factor * @param offset Pointer to the offset of the previous log of this particle; @@ -382,7 +496,7 @@ void logger_log_timestamp(struct logger_writer *log, integertime_t timestamp, * 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 log The #logger_writer * @param total_nr_parts total number of part * @param total_nr_gparts total number of gpart * @param total_nr_sparts total number of spart @@ -390,25 +504,29 @@ void logger_log_timestamp(struct logger_writer *log, integertime_t timestamp, void logger_ensure_size(struct logger_writer *log, size_t total_nr_parts, size_t total_nr_gparts, size_t total_nr_sparts) { - /* count part memory. */ - size_t limit = log->max_chunk_size; + /* count part memory */ + size_t limit = 0; - limit *= total_nr_parts; + /* count part memory */ + limit += total_nr_parts; - /* count gpart memory. */ - if (total_nr_gparts > 0) error("Not implemented"); + /* count gpart memory */ + limit += total_nr_gparts; /* count spart memory. */ - if (total_nr_sparts > 0) error("Not implemented"); + limit += total_nr_sparts; - /* ensure enough space in dump. */ + // TODO improve estimate with the size of each particle + limit *= log->max_chunk_size; + + /* ensure enough space in dump */ dump_ensure(&log->dump, limit, log->buffer_scale * limit); } /** * @brief intialize the logger structure * - * @param log The #logger + * @param log The #logger_writer * @param params The #swift_params */ void logger_init(struct logger_writer *log, struct swift_params *params) { @@ -421,8 +539,12 @@ void logger_init(struct logger_writer *log, struct swift_params *params) { parser_get_opt_param_float(params, "Logger:buffer_scale", 10); parser_get_param_string(params, "Logger:basename", log->base_name); + log->index.mem_frac = + parser_get_opt_param_float(params, "Logger:index_mem_frac", 0.05); + /* set initial value of parameters. */ log->timestamp_offset = 0; + log->index.dump_size_last_output = 0; /* generate dump filename. */ char logger_name_file[PARSER_MAX_LINE_SIZE]; @@ -445,14 +567,14 @@ void logger_init(struct logger_writer *log, struct swift_params *params) { /** * @brief Close dump file and desallocate memory * - * @param log The #logger + * @param log The #logger_writer */ void logger_free(struct logger_writer *log) { dump_close(&log->dump); } /** * @brief Write a file header to a logger file * - * @param log The #logger + * @param log The #logger_writer * */ void logger_write_file_header(struct logger_writer *log) { @@ -460,7 +582,7 @@ void logger_write_file_header(struct logger_writer *log) { /* get required variables. */ struct dump *dump = &log->dump; - size_t file_offset = dump->file_offset; + uint64_t file_offset = dump->file_offset; if (file_offset != 0) error( @@ -516,7 +638,7 @@ void logger_write_file_header(struct logger_writer *log) { * @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 + * @param cur_offset The current chunk offset * * @return Number of bytes read */ @@ -599,8 +721,10 @@ int logger_read_part(struct part *p, size_t *offset, const char *buff) { // TODO make it dependent of logger_mask_data. memcpy(&p->mass, buff, sizeof(float)); buff += sizeof(float); - memcpy(&p->id, buff, sizeof(long long)); - buff += sizeof(long long); + int64_t id = 0; + memcpy(&id, buff, sizeof(int64_t)); + p->id = id; + buff += sizeof(int64_t); } #endif @@ -661,8 +785,9 @@ int logger_read_gpart(struct gpart *p, size_t *offset, const char *buff) { // TODO make it dependent of logger_mask_data memcpy(&p->mass, buff, sizeof(float)); buff += sizeof(float); - memcpy(&p->id_or_neg_offset, buff, sizeof(long long)); - buff += sizeof(long long); + int64_t id = p->id_or_neg_offset; + memcpy(&id, buff, sizeof(int64_t)); + buff += sizeof(int64_t); } /* Finally, return the mask of the values we just read. */ @@ -673,6 +798,7 @@ int logger_read_gpart(struct gpart *p, size_t *offset, const char *buff) { * @brief Read a logger message for a timestamp. * * @param t The timestamp in which to store the value. + * @param time The time in which to store the value. * @param offset Pointer to the offset of the logger message in the buffer, * will be overwritten with the offset of the previous message. * @param buff Pointer to the start of an encoded logger message. @@ -710,6 +836,37 @@ int logger_read_timestamp(unsigned long long int *t, double *time, return mask; } +/** + * @brief Write a swift_params struct to the given FILE as a stream of bytes. + * + * @param log the struct + * @param stream the file stream + */ +void logger_struct_dump(const struct logger_writer *log, FILE *stream) { + restart_write_blocks((void *)log, sizeof(struct logger_writer), 1, stream, + "logger", "logger"); +} + +/** + * @brief Restore a logger struct from the given FILE as a stream of + * bytes. + * + * @param logger the struct + * @param stream the file stream + */ +void logger_struct_restore(struct logger_writer *log, FILE *stream) { + /* Read the block */ + restart_read_blocks((void *)log, sizeof(struct logger_writer), 1, stream, + NULL, "logger"); + + /* generate dump filename */ + char logger_name_file[PARSER_MAX_LINE_SIZE]; + strcpy(logger_name_file, log->base_name); + strcat(logger_name_file, ".dump"); + + dump_restart(&log->dump, logger_name_file); +} + #endif /* WITH_LOGGER */ #endif /* HAVE_POSIX_FALLOCATE */ diff --git a/src/logger.h b/src/logger.h index ed2d6374fa9031f526e79e790572c89f6176df4b..54c19758163a2595913b907323af9c81c804be96 100644 --- a/src/logger.h +++ b/src/logger.h @@ -1,6 +1,7 @@ /******************************************************************************* * This file is part of SWIFT. * Copyright (c) 2017 Pedro Gonnet (pedro.gonnet@durham.ac.uk) + * 2018 Loic Hausammann (loic.hausammann@epfl.ch) * * 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 @@ -19,6 +20,8 @@ #ifndef SWIFT_LOGGER_H #define SWIFT_LOGGER_H +#include "../config.h" + #ifdef WITH_LOGGER /* Includes. */ @@ -35,7 +38,7 @@ struct part; struct engine; #define logger_major_version 0 -#define logger_minor_version 1 +#define logger_minor_version 2 /** * Logger entries contain messages representing the particle data at a given @@ -84,8 +87,11 @@ enum logger_masks_number { logger_h = 4, logger_rho = 5, logger_consts = 6, - logger_timestamp = 7, /* expect it to be before count. */ - logger_count_mask = 8, /* Need to be the last. */ + logger_special_flags = + 7, /* < 0 for MPI rank changes, 0 for none, + > 0 for particle type changes, > part_type for deletion */ + logger_timestamp = 8, /* expect it to be before count. */ + logger_count_mask = 9, /* Need to be the last. */ } __attribute__((packed)); struct mask_data { @@ -104,7 +110,9 @@ extern const struct mask_data logger_mask_data[logger_count_mask]; /* Size of the strings. */ #define logger_string_length 200 -/* structure containing global data. */ +/** + * @brief structure containing global data for the particle logger. + */ struct logger_writer { /* Number of particle steps between dumping a chunk of data. */ short int delta_step; @@ -112,6 +120,14 @@ struct logger_writer { /* Logger basename. */ char base_name[logger_string_length]; + struct { + /* The total memory fraction reserved for the index files. */ + float mem_frac; + + /* Size of the dump since at the last output */ + size_t dump_size_last_output; + } index; + /* Dump file (In the reader, the dump is cleaned, therefore it is renamed * logfile). */ struct dump dump; @@ -133,16 +149,21 @@ struct logger_part_data { int steps_since_last_output; /* offset of last particle log entry. */ - size_t last_offset; + uint64_t last_offset; }; /* Function prototypes. */ int logger_compute_chunk_size(unsigned int mask); void logger_log_all(struct logger_writer *log, const struct engine *e); void logger_log_part(struct logger_writer *log, const struct part *p, - unsigned int mask, size_t *offset); + unsigned int mask, size_t *offset, + const int special_flags); +void logger_log_spart(struct logger_writer *log, const struct spart *p, + unsigned int mask, size_t *offset, + const int special_flags); void logger_log_gpart(struct logger_writer *log, const struct gpart *p, - unsigned int mask, size_t *offset); + unsigned int mask, size_t *offset, + const int special_flags); void logger_init(struct logger_writer *log, struct swift_params *params); void logger_free(struct logger_writer *log); void logger_log_timestamp(struct logger_writer *log, integertime_t t, @@ -155,6 +176,8 @@ 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, double *time, size_t *offset, const char *buff); +void logger_struct_dump(const struct logger_writer *log, FILE *stream); +void logger_struct_restore(struct logger_writer *log, FILE *stream); /** * @brief Initialize the logger data for a particle. @@ -170,9 +193,9 @@ INLINE static void logger_part_data_init(struct logger_part_data *logger) { * @brief Should this particle write its data now ? * * @param logger_data The #logger_part_data of a particle. - * @param log The #logger. + * @param log The #logger_writer. * - * @return 1 if the particule should be writen, 0 otherwise. + * @return 1 if the particle should be writen, 0 otherwise. */ __attribute__((always_inline)) INLINE static int logger_should_write( const struct logger_part_data *logger_data, diff --git a/src/logger_io.c b/src/logger_io.c index c6be1f292434c759e20064542e91caa2cd238a4d..e227db3b169767ad4a88514d136a9593b476b64d 100644 --- a/src/logger_io.c +++ b/src/logger_io.c @@ -21,7 +21,7 @@ /* Config parameters. */ #include "../config.h" -#if defined(WITH_LOGGER) && defined(HAVE_HDF5) && !defined(WITH_MPI) +#if defined(WITH_LOGGER) /* Some standard headers. */ #include <hdf5.h> @@ -31,13 +31,15 @@ #include <stdlib.h> #include <string.h> +#include "common_io.h" + /* This object's header. */ #include "logger_io.h" /* Local includes. */ #include "chemistry_io.h" #include "common_io.h" -#include "cooling.h" +#include "cooling_io.h" #include "dimension.h" #include "engine.h" #include "error.h" @@ -52,248 +54,336 @@ #include "serial_io.h" #include "single_io.h" #include "stars_io.h" +#include "tracers_io.h" #include "units.h" +#include "version.h" #include "xmf.h" /** - * @brief Writes an HDF5 index file + * @brief Mapper function to copy #part or #gpart fields into a buffer. + * WARNING Assumes two io_props in extra_data. + */ +void logger_io_copy_mapper(void* restrict temp, int N, + void* restrict extra_data) { + + /* Get the io_props */ + const struct io_props* props = (const struct io_props*)(extra_data); + const struct io_props props1 = props[0]; + const struct io_props props2 = props[1]; + + /* Get the sizes */ + const size_t typeSize1 = io_sizeof_type(props1.type); + const size_t copySize1 = typeSize1 * props1.dimension; + const size_t typeSize2 = io_sizeof_type(props2.type); + const size_t copySize2 = typeSize2 * props2.dimension; + const size_t copySize = copySize1 + copySize2; + + /* How far are we with this chunk? */ + char* restrict temp_c = (char*)temp; + const ptrdiff_t delta = (temp_c - props1.start_temp_c) / copySize; + + /* Copy the memory to the buffer */ + for (int k = 0; k < N; k++) { + memcpy(&temp_c[k * copySize], props1.field + (delta + k) * props1.partSize, + copySize1); + memcpy(&temp_c[k * copySize + copySize1], + props2.field + (delta + k) * props2.partSize, copySize2); + } +} +/** + * @brief Writes the data array in the index file. + * + * @param e The #engine we are writing from. + * @param f The file to use. + * @param props The #io_props array. + * @param n_props The number of element in @props. + * @param N The number of particles to write. + */ +void writeIndexArray(const struct engine* e, FILE* f, struct io_props* props, + size_t n_props, size_t N) { + + /* Check that the assumptions are corrects */ + if (n_props != 2) + error("Not implemented: The index file can only write two props."); + + if (props[0].dimension != 1 || props[1].dimension != 1) + error("Not implemented: cannot use multidimensional data"); + + /* Get a few variables */ + const size_t typeSize = + io_sizeof_type(props[0].type) + io_sizeof_type(props[1].type); + + const size_t num_elements = N; + + /* Allocate temporary buffer */ + void* temp = NULL; + if (posix_memalign((void**)&temp, IO_BUFFER_ALIGNMENT, + num_elements * typeSize) != 0) + error("Unable to allocate temporary i/o buffer"); + + /* Copy the particle data to the temporary buffer */ + /* Set initial buffer position */ + props[0].start_temp_c = temp; + props[1].start_temp_c = temp; + + /* Copy the whole thing into a buffer */ + threadpool_map((struct threadpool*)&e->threadpool, logger_io_copy_mapper, + temp, N, typeSize, 0, props); + + /* Write data to file */ + fwrite(temp, typeSize, num_elements, f); + + /* Free everything */ + free(temp); +} + +/** + * @brief Writes a logger index file * + * @param log The #logger_writer. * @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 + * Creates an 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. * + * An index file is constructed by writing first a few variables (e.g. time, + * number of particles, if the file is sorted, ...) and then an array of index + * and offset for each particle type. + * * 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) { +void logger_write_index_file(struct logger_writer* log, struct engine* e) { - 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; - const 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; + struct gpart* gparts = e->s->gparts; + struct spart* sparts = e->s->sparts; static int outputCount = 0; - struct logger_writer* 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}; + /* 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 Nblackholes = e->s->nr_bparts; */ + + /* Number of particles that we will write */ + const size_t Ntot_written = + e->s->nr_gparts - e->s->nr_inhibited_gparts - e->s->nr_extra_gparts; + const size_t Ngas_written = + e->s->nr_parts - e->s->nr_inhibited_parts - e->s->nr_extra_parts; + const size_t Nstars_written = + e->s->nr_sparts - e->s->nr_inhibited_sparts - e->s->nr_extra_sparts; + const size_t Nblackholes_written = + e->s->nr_bparts - e->s->nr_inhibited_bparts - e->s->nr_extra_bparts; + const size_t Nbaryons_written = + Ngas_written + Nstars_written + Nblackholes_written; + const size_t Ndm_written = + Ntot_written > 0 ? Ntot_written - Nbaryons_written : 0; + + /* Format things in a Gadget-friendly array */ + uint64_t N_total[swift_type_count] = { + (uint64_t)Ngas_written, (uint64_t)Ndm_written, 0, 0, + (uint64_t)Nstars_written, (uint64_t)Nblackholes_written}; /* File name */ char fileName[FILENAME_BUFFER_SIZE]; - snprintf(fileName, FILENAME_BUFFER_SIZE, "%s_%04i.hdf5", baseName, - outputCount); + snprintf(fileName, FILENAME_BUFFER_SIZE, "%.100s_%04i.index", + e->logger->base_name, 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); - } + FILE* f = NULL; + f = fopen(fileName, "wb"); - /* 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); + if (f == NULL) { + error("Failed to open file %s", fileName); } - /* 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); - } + /* Write double time */ + fwrite(&e->time, sizeof(double), 1, f); - /* 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); - } + /* Write integer time */ + fwrite(&e->ti_current, sizeof(integertime_t), 1, f); + + /* Write number of particles */ + fwrite(N_total, sizeof(uint64_t), swift_type_count, f); + + /* Write if the file is sorted */ + const char sorted = 0; + fwrite(&sorted, sizeof(char), 1, f); + + /* Ensure the data to be aligned */ + size_t cur_pos = ftell(f); + size_t d_align = ((cur_pos + 7) & ~7) - cur_pos; + if (d_align > 0) { + long int tmp = 0; + /* Fill the memory with garbage */ + fwrite(&tmp, d_align, 1, f); } /* 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"); - } + if (N_total[ptype] == 0) continue; - int num_fields = 0; - struct io_props list[100]; + /* Number of properties (the code cannot deal with more than two props + per particle type) */ size_t N = 0; + int num_fields = 0; + struct io_props list[2]; + + struct part* parts_written = NULL; + struct xpart* xparts_written = NULL; + struct gpart* gparts_written = NULL; + struct velociraptor_gpart_data* gpart_group_data_written = NULL; + struct spart* sparts_written = NULL; + struct bpart* bparts_written = NULL; /* Write particle fields from the particle structure */ switch (ptype) { case swift_type_gas: - N = Ngas; - hydro_write_index(parts, xparts, list, &num_fields); + if (Ngas == Ngas_written) { + + /* No inhibted particles: easy case */ + N = Ngas; + num_fields += hydro_write_index(parts, xparts, list); + + } else { + + /* Ok, we need to fish out the particles we want */ + N = Ngas_written; + + /* Allocate temporary arrays */ + if (swift_memalign("parts_written", (void**)&parts_written, + part_align, + Ngas_written * sizeof(struct part)) != 0) + error("Error while allocating temporary memory for parts"); + if (swift_memalign("xparts_written", (void**)&xparts_written, + xpart_align, + Ngas_written * sizeof(struct xpart)) != 0) + error("Error while allocating temporary 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 */ + num_fields += hydro_write_index(parts_written, xparts_written, list); + } break; case swift_type_dark_matter: - error("TODO"); + if (Ntot == Ndm_written) { + + /* This is a DM-only run without inhibited particles */ + N = Ntot; + num_fields += darkmatter_write_index(gparts, list); + } else { + + /* Ok, we need to fish out the particles we want */ + N = Ndm_written; + + /* Allocate temporary array */ + if (swift_memalign("gparts_written", (void**)&gparts_written, + gpart_align, + Ndm_written * sizeof(struct gpart)) != 0) + error("Error while allocating temporary memory for gparts"); + + /* Collect the non-inhibited DM particles from gpart */ + const int with_stf = 0; + io_collect_gparts_to_write(gparts, e->s->gpart_group_data, + gparts_written, gpart_group_data_written, + Ntot, Ndm_written, with_stf); + + /* Select the fields to write */ + num_fields += darkmatter_write_index(gparts_written, list); + } break; case swift_type_stars: - N = Nstars; - error("TODO"); - // star_write_index(sparts, list, &num_fields); + if (Nstars == Nstars_written) { + + /* No inhibted particles: easy case */ + N = Nstars; + num_fields += stars_write_index(sparts, list); + + } else { + + /* Ok, we need to fish out the particles we want */ + N = Nstars_written; + + /* Allocate temporary arrays */ + if (swift_memalign("sparts_written", (void**)&sparts_written, + spart_align, + Nstars_written * sizeof(struct spart)) != 0) + error("Error while allocating temporary 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 */ + num_fields += stars_write_index(sparts_written, list); + } 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; + if (num_fields != 2) { + error( + "The code expects only two fields per particle type for the logger"); } - /* Close particle group */ - H5Gclose(h_grp); + /* Write ids */ + writeIndexArray(e, f, list, num_fields, N); + + /* Free temporary arrays */ + if (parts_written) swift_free("parts_written", parts_written); + if (xparts_written) swift_free("xparts_written", xparts_written); + if (gparts_written) swift_free("gparts_written", gparts_written); + if (gpart_group_data_written) + swift_free("gpart_group_written", gpart_group_data_written); + if (sparts_written) swift_free("sparts_written", sparts_written); + if (bparts_written) swift_free("bparts_written", bparts_written); } - /* message("Done writing particles..."); */ - /* Close file */ - H5Fclose(h_file); + fclose(f); ++outputCount; } -#endif /* WITH_LOGGER && HAVE_HDF5 && !WITH_MPI */ +/** + * @brief Write the parameters into a yaml file. + * + * @params log The #logger. + * @params e The #engine. + */ +void logger_write_description(struct logger_writer* log, struct engine* e) { + /* const struct unit_system *internal_units = e->internal_units; */ + /* const struct unit_system *snapshot_units = e->snapshot_units; */ + + /* File name */ + char fileName[FILENAME_BUFFER_SIZE]; + snprintf(fileName, FILENAME_BUFFER_SIZE, "%.100s.yml", e->logger->base_name); + + /* Open file */ + FILE* f = NULL; + f = fopen(fileName, "wb"); + + if (f == NULL) { + error("Failed to open file %s", fileName); + } + + /* TODO Write stuff */ + + /* Close file */ + fclose(f); +} + +#endif /* WITH_LOGGER */ diff --git a/src/logger_io.h b/src/logger_io.h index a424c5c104b9f1090c69f7e0bb37e72635636f82..f1a0415ab6967f04e85375f26dd9b080530cc05e 100644 --- a/src/logger_io.h +++ b/src/logger_io.h @@ -30,34 +30,77 @@ #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); +void logger_write_index_file(struct logger_writer* log, struct engine* e); +void logger_write_description(struct logger_writer* log, struct engine* e); /** * @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. + * @param xparts The extra particle array. + * @param list (out) The parameters 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) { +__attribute__((always_inline)) INLINE static int hydro_write_index( + const struct part* parts, const struct xpart* xparts, + struct io_props* list) { - *num_fields = 2; + /* List what we want to write */ + list[0] = + io_make_output_field("ParticleIDs", ULONGLONG, 1, UNIT_CONV_NO_UNITS, 0.f, + parts, id, "Field not used"); + list[1] = + io_make_output_field("Offset", UINT64, 1, UNIT_CONV_NO_UNITS, 0.f, xparts, + logger_data.last_offset, "Field not used"); + + return 2; +} + +/** + * @brief Specifies which particle fields to write to a dataset + * + * @param gparts The gparticle array. + * @param list (out) The parameters to write. + * + * In this version, we only want the ids and the offset. + */ +__attribute__((always_inline)) INLINE static int darkmatter_write_index( + const struct gpart* gparts, struct io_props* list) { /* List what we want to write */ list[0] = io_make_output_field("ParticleIDs", ULONGLONG, 1, UNIT_CONV_NO_UNITS, 0.f, - parts, id, "will be erased"); + gparts, id_or_neg_offset, "Field not used"); + list[1] = + io_make_output_field("Offset", UINT64, 1, UNIT_CONV_NO_UNITS, 0.f, gparts, + logger_data.last_offset, "Field not used"); + return 2; +} + +/** + * @brief Specifies which particle fields to write to a dataset + * + * @param sparts The sparticle array. + * @param list (out) The parameters to write. + * + * In this version, we only want the ids and the offset. + */ +__attribute__((always_inline)) INLINE static int stars_write_index( + const struct spart* sparts, struct io_props* list) { + + /* List what we want to write */ + list[0] = + io_make_output_field("ParticleIDs", ULONGLONG, 1, UNIT_CONV_NO_UNITS, 0.f, + sparts, id, "Field not used"); list[1] = - io_make_output_field("Offset", ULONGLONG, 1, UNIT_CONV_NO_UNITS, 0.f, - xparts, logger_data.last_offset, "will be erased"); + io_make_output_field("Offset", UINT64, 1, UNIT_CONV_NO_UNITS, 0.f, sparts, + logger_data.last_offset, "Field not used"); + + return 2; } + #endif #endif /* SWIFT_LOGGER_IO_H */ diff --git a/src/outputlist.c b/src/outputlist.c index 2ff2263a17dad3e54cf2ed286da026813edb0ae6..da841103d2ce35b849112d62ffd523f632cc457b 100644 --- a/src/outputlist.c +++ b/src/outputlist.c @@ -137,6 +137,9 @@ void output_list_read_file(struct output_list *outputlist, const char *filename, /* set current indice to 0 */ outputlist->cur_ind = 0; + /* We check if this is true later */ + outputlist->final_step_dump = 0; + fclose(file); } @@ -162,7 +165,7 @@ void output_list_read_next_time(struct output_list *t, const struct engine *e, /* Find next snasphot above current time */ double time = t->times[t->cur_ind]; size_t ind = t->cur_ind; - while (time < time_end) { + while (time <= time_end) { /* Output time on the integer timeline */ if (is_cosmo) @@ -180,10 +183,23 @@ void output_list_read_next_time(struct output_list *t, const struct engine *e, t->cur_ind = ind; } + /* Do we need to do a dump at the end of the last timestep? */ + if (time == time_end) { + t->final_step_dump = 1; + if (e->verbose) { + if (is_cosmo) { + message("Next output time for %s set to a=%e.", name, time_end); + } else { + message("Next output time for %s set to t=%e.", name, time_end); + } + } + } + /* Deal with last statistics */ if (*ti_next >= max_nr_timesteps || ind == t->size || time >= time_end) { *ti_next = -1; - if (e->verbose) message("No further output time for %s.", name); + if (e->verbose && t->final_step_dump != 1) + message("No further output time for %s.", name); } else { /* Be nice, talk... */ diff --git a/src/outputlist.h b/src/outputlist.h index b7b12ca32f469c70f716553b30a15f48198f8e5e..8ca6bc6fecba772d3bae41bbb63358e6f33eb0a5 100644 --- a/src/outputlist.h +++ b/src/outputlist.h @@ -49,6 +49,9 @@ struct output_list { /* Current index */ size_t cur_ind; + + /* Dump on final timestep? */ + int final_step_dump; }; void output_list_read_file(struct output_list *outputlist, const char *filename, @@ -61,5 +64,7 @@ void output_list_print(const 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); +int output_list_check_duplicates(const struct output_list *list_a, + const struct output_list *list_b); #endif /* SWIFT_OUTPUT_LIST_H */ diff --git a/src/parallel_io.c b/src/parallel_io.c index a33dd14331f220a29345f73047f039234f1c3bcb..5a8605dbcdbb2f50891c80c25762f85962a629cb 100644 --- a/src/parallel_io.c +++ b/src/parallel_io.c @@ -45,6 +45,7 @@ #include "engine.h" #include "entropy_floor.h" #include "error.h" +#include "feedback.h" #include "fof_io.h" #include "gravity_io.h" #include "gravity_properties.h" @@ -342,6 +343,8 @@ void readArray(hid_t grp, struct io_props props, size_t N, long long N_total, props.parts += max_chunk_size; /* part* on the part */ props.xparts += max_chunk_size; /* xpart* on the xpart */ props.gparts += max_chunk_size; /* gpart* on the gpart */ + props.sparts += max_chunk_size; /* spart* on the spart */ + props.bparts += max_chunk_size; /* bpart* on the bpart */ offset += max_chunk_size; redo = 1; } else { @@ -646,6 +649,8 @@ void writeArray(struct engine* e, hid_t grp, char* fileName, props.parts += max_chunk_size; /* part* on the part */ props.xparts += max_chunk_size; /* xpart* on the xpart */ props.gparts += max_chunk_size; /* gpart* on the gpart */ + props.sparts += max_chunk_size; /* spart* on the spart */ + props.bparts += max_chunk_size; /* bpart* on the bpart */ offset += max_chunk_size; redo = 1; } else { @@ -1073,9 +1078,13 @@ void prepare_file(struct engine* e, const char* baseName, long long N_total[6], if (e->snapshot_int_time_label_on) snprintf(fileName, FILENAME_BUFFER_SIZE, "%s_%06i.hdf5", baseName, (int)round(e->time)); - else + else if (e->snapshot_invoke_stf) { + snprintf(fileName, FILENAME_BUFFER_SIZE, "%s_%04i.hdf5", baseName, + e->stf_output_count); + } else { snprintf(fileName, FILENAME_BUFFER_SIZE, "%s_%04i.hdf5", baseName, e->snapshot_output_count); + } /* Open HDF5 file with the chosen parameters */ hid_t h_file = H5Fcreate(fileName, H5F_ACC_TRUNC, H5P_DEFAULT, H5P_DEFAULT); @@ -1162,6 +1171,7 @@ void prepare_file(struct engine* e, const char* baseName, long long N_total[6], cooling_write_flavour(h_grp, e->cooling_func); chemistry_write_flavour(h_grp); tracers_write_flavour(h_grp); + feedback_write_flavour(e->feedback_props, h_grp); H5Gclose(h_grp); /* Print the gravity parameters */ @@ -1415,13 +1425,13 @@ void write_output_parallel(struct engine* e, const char* baseName, Nstars_written, Nblackholes_written}; 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); + MPI_Exscan(N, offset, swift_type_count, MPI_LONG_LONG_INT, MPI_SUM, comm); for (int ptype = 0; ptype < swift_type_count; ++ptype) N_total[ptype] = offset[ptype] + N[ptype]; /* The last rank now has the correct N_total. Let's * broadcast from there */ - MPI_Bcast(&N_total, 6, MPI_LONG_LONG_INT, mpi_size - 1, comm); + MPI_Bcast(N_total, 6, MPI_LONG_LONG_INT, mpi_size - 1, comm); /* Now everybody konws its offset and the total number of * particles of each type */ @@ -1449,9 +1459,13 @@ void write_output_parallel(struct engine* e, const char* baseName, if (e->snapshot_int_time_label_on) snprintf(fileName, FILENAME_BUFFER_SIZE, "%s_%06i.hdf5", baseName, (int)round(e->time)); - else + else if (e->snapshot_invoke_stf) { + snprintf(fileName, FILENAME_BUFFER_SIZE, "%s_%04i.hdf5", baseName, + e->stf_output_count); + } else { snprintf(fileName, FILENAME_BUFFER_SIZE, "%s_%04i.hdf5", baseName, e->snapshot_output_count); + } /* Now write the top-level cell structure */ hid_t h_file_cells = 0, h_grp_cells = 0; @@ -1469,9 +1483,9 @@ void write_output_parallel(struct engine* e, const char* baseName, } /* Write the location of the particles in the arrays */ - io_write_cell_offsets(h_grp_cells, e->s->cdim, e->s->cells_top, - e->s->nr_cells, e->s->width, mpi_rank, N_total, offset, - internal_units, snapshot_units); + io_write_cell_offsets(h_grp_cells, e->s->cdim, e->s->dim, e->s->pos_dithering, + e->s->cells_top, e->s->nr_cells, e->s->width, mpi_rank, + N_total, offset, internal_units, snapshot_units); /* Close everything */ if (mpi_rank == 0) { @@ -1787,9 +1801,10 @@ void write_output_parallel(struct engine* e, const char* baseName, /* Select the fields to write */ stars_write_particles(sparts_written, list, &num_fields, with_cosmology); - num_fields += chemistry_write_sparticles(sparts, list + num_fields); - num_fields += tracers_write_sparticles(sparts, list + num_fields, - with_cosmology); + num_fields += + chemistry_write_sparticles(sparts_written, list + num_fields); + num_fields += tracers_write_sparticles( + sparts_written, list + num_fields, with_cosmology); if (with_fof) { num_fields += fof_write_sparts(sparts_written, list + num_fields); } @@ -1919,6 +1934,7 @@ void write_output_parallel(struct engine* e, const char* baseName, #endif e->snapshot_output_count++; + if (e->snapshot_invoke_stf) e->stf_output_count++; } #endif /* HAVE_HDF5 */ diff --git a/src/part.h b/src/part.h index eb8489daae5f408b40a85ec07561232c0a325496..d0ff99089526c223f148d32058003edaf474126d 100644 --- a/src/part.h +++ b/src/part.h @@ -63,12 +63,8 @@ #include "./hydro/Default/hydro_part.h" #define EXTRA_HYDRO_LOOP #define hydro_need_extra_init_loop 0 -#elif defined(GIZMO_MFV_SPH) -#include "./hydro/GizmoMFV/hydro_part.h" -#define hydro_need_extra_init_loop 0 -#define EXTRA_HYDRO_LOOP -#elif defined(GIZMO_MFM_SPH) -#include "./hydro/GizmoMFM/hydro_part.h" +#elif defined(GIZMO_MFV_SPH) || defined(GIZMO_MFM_SPH) +#include "./hydro/Gizmo/hydro_part.h" #define hydro_need_extra_init_loop 0 #define EXTRA_HYDRO_LOOP #elif defined(SHADOWFAX_SPH) @@ -78,8 +74,8 @@ #elif defined(PLANETARY_SPH) #include "./hydro/Planetary/hydro_part.h" #define hydro_need_extra_init_loop 0 -#elif defined(ANARCHY_DU_SPH) -#include "./hydro/AnarchyDU/hydro_part.h" +#elif defined(SPHENIX_SPH) +#include "./hydro/SPHENIX/hydro_part.h" #define hydro_need_extra_init_loop 0 #define EXTRA_HYDRO_LOOP #elif defined(ANARCHY_PU_SPH) diff --git a/src/physical_constants_cgs.h b/src/physical_constants_cgs.h index 4d1a54f68ba557c74fb489a9343eaf3846c481f4..e0a9445d661a42f5f13e71cd97dd05230f35d5ac 100644 --- a/src/physical_constants_cgs.h +++ b/src/physical_constants_cgs.h @@ -36,6 +36,8 @@ * Phys. C, 40, 100001 (2016) and 2017 update. * http://pdg.lbl.gov/2017/reviews/rpp2017-rev-phys-constants.pdf * http://pdg.lbl.gov/2017/reviews/rpp2017-rev-astrophysical-constants.pdf + * + * The primordial Helium fraction is the value obtained by WMAP7. */ /*! Newton's gravitation constant [g^-1 cm^3 s^-2] */ @@ -95,8 +97,8 @@ 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 [-] */ -const double const_primordial_He_fraction_cgs = 0.245; +/*! Primordial Helium fraction (from WMAP7) [-] */ +const double const_primordial_He_fraction_cgs = 0.248; /*! Reduced Hubble constant units (i.e. H_0 / h == 100 km / s / Mpc in CGS) * [s^-1] */ diff --git a/src/pressure_floor.h b/src/pressure_floor.h index 4389dfe0891dd6bfbc1e6730cac1c6ddcc920547..8880d82c68962d80fbe8e0c434e81c19200dccd3 100644 --- a/src/pressure_floor.h +++ b/src/pressure_floor.h @@ -29,7 +29,6 @@ /* Local includes */ #include "common_io.h" -#include "cosmology.h" #include "error.h" #include "inline.h" @@ -37,7 +36,7 @@ extern struct pressure_floor_properties pressure_floor_props; /* Check if pressure floor is implemented in hydro */ #ifndef PRESSURE_FLOOR_NONE -#if defined(GADGET2_SPH) || defined(HOPKINS_PU_SPH) +#if defined(GADGET2_SPH) || defined(HOPKINS_PU_SPH) || defined(SPHENIX_SPH) /* Implemented */ #else #error Pressure floor not implemented with this hydro scheme diff --git a/src/pressure_floor/GEAR/pressure_floor.h b/src/pressure_floor/GEAR/pressure_floor.h index de9ad6cf4450005becade48022be1be481fc1cc9..2d00b9b6c2d5a9120f7359b5fc18a35ec4be3799 100644 --- a/src/pressure_floor/GEAR/pressure_floor.h +++ b/src/pressure_floor/GEAR/pressure_floor.h @@ -20,6 +20,7 @@ #define SWIFT_PRESSURE_FLOOR_GEAR_H /* Forward declaration */ +struct cosmology; __attribute__((always_inline)) static INLINE float pressure_floor_get_comoving_pressure(const struct part* p, const float pressure, const struct cosmology* cosmo); @@ -129,7 +130,7 @@ __attribute__((always_inline)) static INLINE void pressure_floor_init( /* Read the Jeans factor */ props->n_jeans = - parser_get_param_float(params, "GEARPressureFloor:Jeans_factor"); + parser_get_param_float(params, "GEARPressureFloor:jeans_factor"); /* Compute the constants */ props->constants = @@ -160,8 +161,10 @@ __attribute__((always_inline)) INLINE static void pressure_floor_print_snapshot( io_write_attribute_s(h_grp, "Pressure floor", "GEAR"); } +#endif + /** - * @brief Finishes the density calculation. + * @brief Finishes the density calculation for the pressure floor properties. * * @param p The particle to act upon * @param cosmo The current cosmological model. @@ -178,7 +181,8 @@ __attribute__((always_inline)) INLINE static void pressure_floor_end_density( } /** - * @brief Sets all particle fields to sensible values when the #part has 0 ngbs. + * @brief Sets all the pressure floor fields to sensible values when the #part + * has 0 ngbs. * * @param p The particle to act upon * @param xp The extended particle data to act upon @@ -225,5 +229,4 @@ pressure_floor_first_init_part(const struct phys_const* restrict phys_const, pressure_floor_init_part(p, xp); } -#endif #endif /* SWIFT_PRESSURE_FLOOR_GEAR_H */ diff --git a/src/pressure_floor/none/pressure_floor.h b/src/pressure_floor/none/pressure_floor.h index 84db9cbaf682b36fa68abc7d26273e15cd1da191..491c02a14b0cb06b1640b00fac534325b299dca6 100644 --- a/src/pressure_floor/none/pressure_floor.h +++ b/src/pressure_floor/none/pressure_floor.h @@ -19,13 +19,14 @@ #ifndef SWIFT_PRESSURE_FLOOR_NONE_H #define SWIFT_PRESSURE_FLOOR_NONE_H -#include "adiabatic_index.h" -#include "cosmology.h" -#include "equation_of_state.h" -#include "hydro_properties.h" -#include "parser.h" -#include "part.h" -#include "units.h" +/* Pre-declarations */ +struct cosmology; +struct hydro_props; +struct phys_const; +struct part; +struct xpart; +struct swift_params; +struct unit_system; /** * @file src/pressure_floor/none/pressure_floor.h @@ -42,6 +43,9 @@ struct pressure_floor_properties {}; * * Note that the particle is not updated!! * + * Since this is the 'none' model for floor, there is no floor and + * we just return the physical pressure that was received. + * * @param p The #part. * @param physical_pressure The physical pressure without any pressure floor. * @param cosmo The #cosmology model. @@ -59,6 +63,9 @@ static INLINE float pressure_floor_get_physical_pressure( * * Note that the particle is not updated!! * + * Since this is the 'none' model for floor, there is no floor and + * we just return the comoving pressure that was received. + * * @param p The #part. * @param comoving_pressure The comoving pressure without any pressure floor. * @param cosmo The #cosmology model. @@ -75,8 +82,7 @@ static INLINE float pressure_floor_get_comoving_pressure( * @brief Initialise the pressure floor by reading the parameters and converting * to internal units. * - * The input temperatures and number densities are converted to pressure and - * density assuming a neutral gas of primoridal abundance. + * Nothing to do here. * * @param params The YAML parameter file. * @param us The system of units used internally. @@ -96,7 +102,10 @@ static INLINE void pressure_floor_init(struct pressure_floor_properties* props, * @param props The pressure floor properties. */ static INLINE void pressure_floor_print( - const struct pressure_floor_properties* props) {} + const struct pressure_floor_properties* props) { + + message("Pressure floor is 'none'"); +} #ifdef HAVE_HDF5 @@ -111,7 +120,9 @@ INLINE static void pressure_floor_print_snapshot(hid_t h_grp) { #endif /** - * @brief Finishes the density calculation. + * @brief Finishes the density calculation for the pressure floor properties. + * + * Nothing to do here. * * @param p The particle to act upon * @param cosmo The current cosmological model. @@ -120,7 +131,10 @@ __attribute__((always_inline)) INLINE static void pressure_floor_end_density( struct part* restrict p, const struct cosmology* cosmo) {} /** - * @brief Sets all particle fields to sensible values when the #part has 0 ngbs. + * @brief Sets all the pressure floor fields to sensible values when the #part + * has 0 ngbs. + * + * Nothing to do here. * * @param p The particle to act upon * @param xp The extended particle data to act upon @@ -135,6 +149,8 @@ pressure_floor_part_has_no_neighbours(struct part* restrict p, * @brief Sets the pressure_floor properties of the (x-)particles to a valid * start state. * + * Nothing to do here. + * * @param p Pointer to the particle data. * @param xp Pointer to the extended particle data. */ @@ -145,6 +161,8 @@ __attribute__((always_inline)) INLINE static void pressure_floor_init_part( * @brief Sets the pressure_floor properties of the (x-)particles to a valid * start state. * + * Nothing to do here. + * * @param phys_const The physical constant in internal units. * @param us The unit system. * @param cosmo The current cosmological model. diff --git a/src/random.h b/src/random.h index 832c95a884ae9ae624b3f7723f3b11bc6052f646..99174f7e665533ef2587fc7e58f3359cf2ed9c78 100644 --- a/src/random.h +++ b/src/random.h @@ -42,11 +42,12 @@ * generator. * In case new numbers need to be added other possible * numbers could be: - * 5947309451, 6977309513 + * 5947309451 */ enum random_number_type { random_number_star_formation = 0LL, - random_number_stellar_feedback = 3947008991LL, + random_number_stellar_feedback_1 = 3947008991LL, + random_number_stellar_feedback_2 = 6977309513LL, random_number_stellar_enrichment = 2936881973LL, random_number_BH_feedback = 1640531371LL, random_number_BH_swallow = 4947009007LL @@ -107,7 +108,7 @@ INLINE static double inl_erand48(uint16_t xsubi[3]) { temp.ieee.negative = 0; temp.ieee.exponent = IEEE754_DOUBLE_BIAS; temp.ieee.mantissa0 = (xsubi[2] << 4) | (xsubi[1] >> 12); - temp.ieee.mantissa1 = ((xsubi[1] & 0xfff) << 20) | (xsubi[0] << 4); + temp.ieee.mantissa1 = (((uint32_t)xsubi[1] & 0xfff) << 20) | (xsubi[0] << 4); /* Please note the lower 4 bits of mantissa1 are always 0. */ return temp.d - 1.0; @@ -140,6 +141,7 @@ INLINE static double inl_erand48(uint16_t xsubi[3]) { return erand48(xsubi); } INLINE static double random_unit_interval(int64_t id, const integertime_t ti_current, const enum random_number_type type) { + /* Start by packing the state into a sequence of 16-bit seeds for rand_r. */ uint16_t buff[9]; id += type; @@ -151,6 +153,9 @@ INLINE static double random_unit_interval(int64_t id, value to get 18 bytes of state. */ buff[8] = 6178; + /* Use the random seed to generate a new random number */ + buff[0] = buff[0] ^ (uint16_t)SWIFT_RANDOM_SEED_XOR; + /* Shuffle the buffer values, this will be our source of entropy for the erand48 generator. */ uint32_t seed16 = 0; diff --git a/src/runner.h b/src/runner.h index 7e8d0459efb5485ea1301c923e8c7a3396b6fc7e..6990dacd46938c4ff16de0e95e3d74155d0d5f72 100644 --- a/src/runner.h +++ b/src/runner.h @@ -107,6 +107,7 @@ void runner_do_end_grav_force(struct runner *r, struct cell *c, int timer); void runner_do_init(struct runner *r, struct cell *c, int timer); void runner_do_cooling(struct runner *r, struct cell *c, int timer); void runner_do_limiter(struct runner *r, struct cell *c, int force, int timer); +void runner_do_sync(struct runner *r, struct cell *c, int force, int timer); void runner_do_grav_mesh(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); diff --git a/src/runner_black_holes.c b/src/runner_black_holes.c index d9bb62201d7b087670aef0ce2346a51bf61a3868..354b01e2e00fc0985a25bc958c0ec13af929f5b4 100644 --- a/src/runner_black_holes.c +++ b/src/runner_black_holes.c @@ -275,6 +275,8 @@ void runner_do_bh_swallow(struct runner *r, struct cell *c, int timer) { struct engine *e = r->e; struct space *s = e->s; + const int with_cosmology = (e->policy & engine_policy_cosmology); + const struct black_holes_props *props = e->black_holes_properties; struct bpart *bparts = s->bparts; const size_t nr_bpart = s->nr_bparts; #ifdef WITH_MPI @@ -349,7 +351,8 @@ void runner_do_bh_swallow(struct runner *r, struct cell *c, int timer) { lock_lock(&s->lock); /* Swallow the gas particle (i.e. update the BH properties) */ - black_holes_swallow_bpart(bp, cell_bp, e->cosmology); + black_holes_swallow_bpart(bp, cell_bp, e->cosmology, e->time, + with_cosmology, props); /* Release the space as we are done updating the bpart */ if (lock_unlock(&s->lock) != 0) diff --git a/src/runner_doiact_functions_hydro.h b/src/runner_doiact_functions_hydro.h index fcbd72af443c63cfa63f1a00b80372408fa2dbde..9794956bd7368a6fada2147754ecb4332e6baff8 100644 --- a/src/runner_doiact_functions_hydro.h +++ b/src/runner_doiact_functions_hydro.h @@ -116,6 +116,9 @@ void DOPAIR1_NAIVE(struct runner *r, struct cell *restrict ci, runner_iact_nonsym_chemistry(r2, dx, hi, hj, pi, pj, a, H); runner_iact_nonsym_pressure_floor(r2, dx, hi, hj, pi, pj, a, H); runner_iact_nonsym_star_formation(r2, dx, hi, hj, pi, pj, a, H); +#endif +#if (FUNCTION_TASK_LOOP == TASK_LOOP_FORCE) + runner_iact_nonsym_timebin(r2, dx, hi, hj, pi, pj, a, H); #endif } if (r2 < hjg2 && pj_active) { @@ -129,9 +132,11 @@ void DOPAIR1_NAIVE(struct runner *r, struct cell *restrict ci, runner_iact_nonsym_chemistry(r2, dx, hj, hi, pj, pi, a, H); runner_iact_nonsym_pressure_floor(r2, dx, hj, hi, pj, pi, a, H); runner_iact_nonsym_star_formation(r2, dx, hj, hi, pj, pi, a, H); +#endif +#if (FUNCTION_TASK_LOOP == TASK_LOOP_FORCE) + runner_iact_nonsym_timebin(r2, dx, hj, hi, pj, pi, a, H); #endif } - } /* loop over the parts in cj. */ } /* loop over the parts in ci. */ @@ -230,6 +235,9 @@ void DOPAIR2_NAIVE(struct runner *r, struct cell *restrict ci, runner_iact_chemistry(r2, dx, hi, hj, pi, pj, a, H); runner_iact_pressure_floor(r2, dx, hi, hj, pi, pj, a, H); runner_iact_star_formation(r2, dx, hi, hj, pi, pj, a, H); +#endif +#if (FUNCTION_TASK_LOOP == TASK_LOOP_FORCE) + runner_iact_timebin(r2, dx, hi, hj, pi, pj, a, H); #endif } else if (pi_active) { @@ -238,6 +246,9 @@ void DOPAIR2_NAIVE(struct runner *r, struct cell *restrict ci, runner_iact_nonsym_chemistry(r2, dx, hi, hj, pi, pj, a, H); runner_iact_nonsym_pressure_floor(r2, dx, hi, hj, pi, pj, a, H); runner_iact_nonsym_star_formation(r2, dx, hi, hj, pi, pj, a, H); +#endif +#if (FUNCTION_TASK_LOOP == TASK_LOOP_FORCE) + runner_iact_nonsym_timebin(r2, dx, hi, hj, pi, pj, a, H); #endif } else if (pj_active) { @@ -250,6 +261,9 @@ void DOPAIR2_NAIVE(struct runner *r, struct cell *restrict ci, runner_iact_nonsym_chemistry(r2, dx, hj, hi, pj, pi, a, H); runner_iact_nonsym_pressure_floor(r2, dx, hj, hi, pj, pi, a, H); runner_iact_nonsym_star_formation(r2, dx, hj, hi, pj, pi, a, H); +#endif +#if (FUNCTION_TASK_LOOP == TASK_LOOP_FORCE) + runner_iact_nonsym_timebin(r2, dx, hj, hi, pj, pi, a, H); #endif } } @@ -339,6 +353,9 @@ void DOSELF1_NAIVE(struct runner *r, struct cell *restrict c) { runner_iact_chemistry(r2, dx, hi, hj, pi, pj, a, H); runner_iact_pressure_floor(r2, dx, hi, hj, pi, pj, a, H); runner_iact_star_formation(r2, dx, hi, hj, pi, pj, a, H); +#endif +#if (FUNCTION_TASK_LOOP == TASK_LOOP_FORCE) + runner_iact_timebin(r2, dx, hi, hj, pi, pj, a, H); #endif } else if (doi) { @@ -347,6 +364,9 @@ void DOSELF1_NAIVE(struct runner *r, struct cell *restrict c) { runner_iact_nonsym_chemistry(r2, dx, hi, hj, pi, pj, a, H); runner_iact_nonsym_pressure_floor(r2, dx, hi, hj, pi, pj, a, H); runner_iact_nonsym_star_formation(r2, dx, hi, hj, pi, pj, a, H); +#endif +#if (FUNCTION_TASK_LOOP == TASK_LOOP_FORCE) + runner_iact_nonsym_timebin(r2, dx, hi, hj, pi, pj, a, H); #endif } else if (doj) { @@ -359,6 +379,9 @@ void DOSELF1_NAIVE(struct runner *r, struct cell *restrict c) { runner_iact_nonsym_chemistry(r2, dx, hj, hi, pj, pi, a, H); runner_iact_nonsym_pressure_floor(r2, dx, hj, hi, pj, pi, a, H); runner_iact_nonsym_star_formation(r2, dx, hj, hi, pj, pi, a, H); +#endif +#if (FUNCTION_TASK_LOOP == TASK_LOOP_FORCE) + runner_iact_nonsym_timebin(r2, dx, hj, hi, pj, pi, a, H); #endif } } /* loop over the parts in cj. */ @@ -447,6 +470,9 @@ void DOSELF2_NAIVE(struct runner *r, struct cell *restrict c) { runner_iact_chemistry(r2, dx, hi, hj, pi, pj, a, H); runner_iact_pressure_floor(r2, dx, hi, hj, pi, pj, a, H); runner_iact_star_formation(r2, dx, hi, hj, pi, pj, a, H); +#endif +#if (FUNCTION_TASK_LOOP == TASK_LOOP_FORCE) + runner_iact_timebin(r2, dx, hi, hj, pi, pj, a, H); #endif } else if (doi) { @@ -455,6 +481,9 @@ void DOSELF2_NAIVE(struct runner *r, struct cell *restrict c) { runner_iact_nonsym_chemistry(r2, dx, hi, hj, pi, pj, a, H); runner_iact_nonsym_pressure_floor(r2, dx, hi, hj, pi, pj, a, H); runner_iact_nonsym_star_formation(r2, dx, hi, hj, pi, pj, a, H); +#endif +#if (FUNCTION_TASK_LOOP == TASK_LOOP_FORCE) + runner_iact_nonsym_timebin(r2, dx, hi, hj, pi, pj, a, H); #endif } else if (doj) { @@ -467,6 +496,9 @@ void DOSELF2_NAIVE(struct runner *r, struct cell *restrict c) { runner_iact_nonsym_chemistry(r2, dx, hj, hi, pj, pi, a, H); runner_iact_nonsym_pressure_floor(r2, dx, hj, hi, pj, pi, a, H); runner_iact_nonsym_star_formation(r2, dx, hj, hi, pj, pi, a, H); +#endif +#if (FUNCTION_TASK_LOOP == TASK_LOOP_FORCE) + runner_iact_nonsym_timebin(r2, dx, hj, hi, pj, pi, a, H); #endif } } /* loop over the parts in cj. */ @@ -554,6 +586,9 @@ void DOPAIR_SUBSET_NAIVE(struct runner *r, struct cell *restrict ci, runner_iact_nonsym_chemistry(r2, dx, hi, pj->h, pi, pj, a, H); runner_iact_nonsym_pressure_floor(r2, dx, hi, pj->h, pi, pj, a, H); runner_iact_nonsym_star_formation(r2, dx, hi, pj->h, pi, pj, a, H); +#endif +#if (FUNCTION_TASK_LOOP == TASK_LOOP_FORCE) + runner_iact_nonsym_timebin(r2, dx, hi, pj->h, pi, pj, a, H); #endif } } /* loop over the parts in cj. */ @@ -648,6 +683,9 @@ void DOPAIR_SUBSET(struct runner *r, struct cell *restrict ci, runner_iact_nonsym_chemistry(r2, dx, hi, hj, pi, pj, a, H); runner_iact_nonsym_pressure_floor(r2, dx, hi, hj, pi, pj, a, H); runner_iact_nonsym_star_formation(r2, dx, hi, hj, pi, pj, a, H); +#endif +#if (FUNCTION_TASK_LOOP == TASK_LOOP_FORCE) + runner_iact_nonsym_timebin(r2, dx, hi, hj, pi, pj, a, H); #endif } } /* loop over the parts in cj. */ @@ -705,6 +743,9 @@ void DOPAIR_SUBSET(struct runner *r, struct cell *restrict ci, runner_iact_nonsym_chemistry(r2, dx, hi, hj, pi, pj, a, H); runner_iact_nonsym_pressure_floor(r2, dx, hi, hj, pi, pj, a, H); runner_iact_nonsym_star_formation(r2, dx, hi, hj, pi, pj, a, H); +#endif +#if (FUNCTION_TASK_LOOP == TASK_LOOP_FORCE) + runner_iact_nonsym_timebin(r2, dx, hi, hj, pi, pj, a, H); #endif } } /* loop over the parts in cj. */ @@ -848,6 +889,9 @@ void DOSELF_SUBSET(struct runner *r, struct cell *restrict ci, runner_iact_nonsym_chemistry(r2, dx, hi, hj, pi, pj, a, H); runner_iact_nonsym_pressure_floor(r2, dx, hi, hj, pi, pj, a, H); runner_iact_nonsym_star_formation(r2, dx, hi, hj, pi, pj, a, H); +#endif +#if (FUNCTION_TASK_LOOP == TASK_LOOP_FORCE) + runner_iact_nonsym_timebin(r2, dx, hi, hj, pi, pj, a, H); #endif } } /* loop over the parts in cj. */ @@ -1013,6 +1057,9 @@ void DOPAIR1(struct runner *r, struct cell *ci, struct cell *cj, const int sid, runner_iact_nonsym_chemistry(r2, dx, hi, hj, pi, pj, a, H); runner_iact_nonsym_pressure_floor(r2, dx, hi, hj, pi, pj, a, H); runner_iact_nonsym_star_formation(r2, dx, hi, hj, pi, pj, a, H); +#endif +#if (FUNCTION_TASK_LOOP == TASK_LOOP_FORCE) + runner_iact_nonsym_timebin(r2, dx, hi, hj, pi, pj, a, H); #endif } } /* loop over the parts in cj. */ @@ -1102,6 +1149,9 @@ void DOPAIR1(struct runner *r, struct cell *ci, struct cell *cj, const int sid, runner_iact_nonsym_chemistry(r2, dx, hj, hi, pj, pi, a, H); runner_iact_nonsym_pressure_floor(r2, dx, hj, hi, pj, pi, a, H); runner_iact_nonsym_star_formation(r2, dx, hj, hi, pj, pi, a, H); +#endif +#if (FUNCTION_TASK_LOOP == TASK_LOOP_FORCE) + runner_iact_nonsym_timebin(r2, dx, hj, hi, pj, pi, a, H); #endif } } /* loop over the parts in ci. */ @@ -1270,7 +1320,8 @@ void DOPAIR2(struct runner *r, struct cell *ci, struct cell *cj, const int sid, struct sort_entry *restrict sort_active_i = NULL, *restrict sort_active_j = NULL; - if (cell_is_all_active_hydro(ci, e)) { + // MATTHIEU: temporary disable this optimization + if (0 && cell_is_all_active_hydro(ci, e)) { /* If everybody is active don't bother copying */ sort_active_i = sort_i; count_active_i = count_i; @@ -1288,7 +1339,8 @@ void DOPAIR2(struct runner *r, struct cell *ci, struct cell *cj, const int sid, } } - if (cell_is_all_active_hydro(cj, e)) { + // MATTHIEU: temporary disable this optimization + if (0 && cell_is_all_active_hydro(cj, e)) { /* If everybody is active don't bother copying */ sort_active_j = sort_j; count_active_j = count_j; @@ -1403,6 +1455,9 @@ void DOPAIR2(struct runner *r, struct cell *ci, struct cell *cj, const int sid, runner_iact_nonsym_chemistry(r2, dx, hj, hi, pj, pi, a, H); runner_iact_nonsym_pressure_floor(r2, dx, hj, hi, pj, pi, a, H); runner_iact_nonsym_star_formation(r2, dx, hj, hi, pj, pi, a, H); +#endif +#if (FUNCTION_TASK_LOOP == TASK_LOOP_FORCE) + runner_iact_nonsym_timebin(r2, dx, hj, hi, pj, pi, a, H); #endif } } /* loop over the active parts in cj. */ @@ -1475,6 +1530,9 @@ void DOPAIR2(struct runner *r, struct cell *ci, struct cell *cj, const int sid, runner_iact_chemistry(r2, dx, hi, hj, pi, pj, a, H); runner_iact_pressure_floor(r2, dx, hi, hj, pi, pj, a, H); runner_iact_star_formation(r2, dx, hi, hj, pi, pj, a, H); +#endif +#if (FUNCTION_TASK_LOOP == TASK_LOOP_FORCE) + runner_iact_timebin(r2, dx, hi, hj, pi, pj, a, H); #endif } else { IACT_NONSYM(r2, dx, hi, hj, pi, pj, a, H); @@ -1482,6 +1540,9 @@ void DOPAIR2(struct runner *r, struct cell *ci, struct cell *cj, const int sid, runner_iact_nonsym_chemistry(r2, dx, hi, hj, pi, pj, a, H); runner_iact_nonsym_pressure_floor(r2, dx, hi, hj, pi, pj, a, H); runner_iact_nonsym_star_formation(r2, dx, hi, hj, pi, pj, a, H); +#endif +#if (FUNCTION_TASK_LOOP == TASK_LOOP_FORCE) + runner_iact_nonsym_timebin(r2, dx, hi, hj, pi, pj, a, H); #endif } } @@ -1586,6 +1647,9 @@ void DOPAIR2(struct runner *r, struct cell *ci, struct cell *cj, const int sid, runner_iact_nonsym_chemistry(r2, dx, hi, hj, pi, pj, a, H); runner_iact_nonsym_pressure_floor(r2, dx, hi, hj, pi, pj, a, H); runner_iact_nonsym_star_formation(r2, dx, hi, hj, pi, pj, a, H); +#endif +#if (FUNCTION_TASK_LOOP == TASK_LOOP_FORCE) + runner_iact_nonsym_timebin(r2, dx, hi, hj, pi, pj, a, H); #endif } } /* loop over the active parts in ci. */ @@ -1660,6 +1724,9 @@ void DOPAIR2(struct runner *r, struct cell *ci, struct cell *cj, const int sid, runner_iact_chemistry(r2, dx, hj, hi, pj, pi, a, H); runner_iact_pressure_floor(r2, dx, hj, hi, pj, pi, a, H); runner_iact_star_formation(r2, dx, hj, hi, pj, pi, a, H); +#endif +#if (FUNCTION_TASK_LOOP == TASK_LOOP_FORCE) + runner_iact_timebin(r2, dx, hj, hi, pj, pi, a, H); #endif } else { IACT_NONSYM(r2, dx, hj, hi, pj, pi, a, H); @@ -1667,6 +1734,9 @@ void DOPAIR2(struct runner *r, struct cell *ci, struct cell *cj, const int sid, runner_iact_nonsym_chemistry(r2, dx, hj, hi, pj, pi, a, H); runner_iact_nonsym_pressure_floor(r2, dx, hj, hi, pj, pi, a, H); runner_iact_nonsym_star_formation(r2, dx, hj, hi, pj, pi, a, H); +#endif +#if (FUNCTION_TASK_LOOP == TASK_LOOP_FORCE) + runner_iact_nonsym_timebin(r2, dx, hj, hi, pj, pi, a, H); #endif } } @@ -1674,10 +1744,10 @@ void DOPAIR2(struct runner *r, struct cell *ci, struct cell *cj, const int sid, } /* Is pj active? */ } /* Loop over all cj */ - /* Clean-up if necessary */ - if (cell_is_active_hydro(ci, e) && !cell_is_all_active_hydro(ci, e)) + /* Clean-up if necessary */ // MATTHIEU: temporary disable this optimization + if (cell_is_active_hydro(ci, e)) // && !cell_is_all_active_hydro(ci, e)) free(sort_active_i); - if (cell_is_active_hydro(cj, e) && !cell_is_all_active_hydro(cj, e)) + if (cell_is_active_hydro(cj, e)) // && !cell_is_all_active_hydro(cj, e)) free(sort_active_j); TIMER_TOC(TIMER_DOPAIR); @@ -1857,6 +1927,9 @@ void DOSELF1(struct runner *r, struct cell *restrict c) { runner_iact_nonsym_chemistry(r2, dx, hj, hi, pj, pi, a, H); runner_iact_nonsym_pressure_floor(r2, dx, hj, hi, pj, pi, a, H); runner_iact_nonsym_star_formation(r2, dx, hj, hi, pj, pi, a, H); +#endif +#if (FUNCTION_TASK_LOOP == TASK_LOOP_FORCE) + runner_iact_nonsym_timebin(r2, dx, hj, hi, pj, pi, a, H); #endif } } /* loop over all other particles. */ @@ -1910,6 +1983,9 @@ void DOSELF1(struct runner *r, struct cell *restrict c) { runner_iact_chemistry(r2, dx, hi, hj, pi, pj, a, H); runner_iact_pressure_floor(r2, dx, hi, hj, pi, pj, a, H); runner_iact_star_formation(r2, dx, hi, hj, pi, pj, a, H); +#endif +#if (FUNCTION_TASK_LOOP == TASK_LOOP_FORCE) + runner_iact_timebin(r2, dx, hi, hj, pi, pj, a, H); #endif } else if (doi) { @@ -1918,6 +1994,9 @@ void DOSELF1(struct runner *r, struct cell *restrict c) { runner_iact_nonsym_chemistry(r2, dx, hi, hj, pi, pj, a, H); runner_iact_nonsym_pressure_floor(r2, dx, hi, hj, pi, pj, a, H); runner_iact_nonsym_star_formation(r2, dx, hi, hj, pi, pj, a, H); +#endif +#if (FUNCTION_TASK_LOOP == TASK_LOOP_FORCE) + runner_iact_nonsym_timebin(r2, dx, hi, hj, pi, pj, a, H); #endif } else if (doj) { @@ -1929,6 +2008,9 @@ void DOSELF1(struct runner *r, struct cell *restrict c) { runner_iact_nonsym_chemistry(r2, dx, hj, hi, pj, pi, a, H); runner_iact_nonsym_pressure_floor(r2, dx, hj, hi, pj, pi, a, H); runner_iact_nonsym_star_formation(r2, dx, hj, hi, pj, pi, a, H); +#endif +#if (FUNCTION_TASK_LOOP == TASK_LOOP_FORCE) + runner_iact_nonsym_timebin(r2, dx, hj, hi, pj, pi, a, H); #endif } } @@ -2057,6 +2139,9 @@ void DOSELF2(struct runner *r, struct cell *restrict c) { runner_iact_nonsym_chemistry(r2, dx, hj, hi, pj, pi, a, H); runner_iact_nonsym_pressure_floor(r2, dx, hj, hi, pj, pi, a, H); runner_iact_nonsym_star_formation(r2, dx, hj, hi, pj, pi, a, H); +#endif +#if (FUNCTION_TASK_LOOP == TASK_LOOP_FORCE) + runner_iact_nonsym_timebin(r2, dx, hj, hi, pj, pi, a, H); #endif } } /* loop over all other particles. */ @@ -2105,6 +2190,9 @@ void DOSELF2(struct runner *r, struct cell *restrict c) { runner_iact_chemistry(r2, dx, hi, hj, pi, pj, a, H); runner_iact_pressure_floor(r2, dx, hi, hj, pi, pj, a, H); runner_iact_star_formation(r2, dx, hi, hj, pi, pj, a, H); +#endif +#if (FUNCTION_TASK_LOOP == TASK_LOOP_FORCE) + runner_iact_timebin(r2, dx, hi, hj, pi, pj, a, H); #endif } else { IACT_NONSYM(r2, dx, hi, hj, pi, pj, a, H); @@ -2112,6 +2200,9 @@ void DOSELF2(struct runner *r, struct cell *restrict c) { runner_iact_nonsym_chemistry(r2, dx, hi, hj, pi, pj, a, H); runner_iact_nonsym_pressure_floor(r2, dx, hi, hj, pi, pj, a, H); runner_iact_nonsym_star_formation(r2, dx, hi, hj, pi, pj, a, H); +#endif +#if (FUNCTION_TASK_LOOP == TASK_LOOP_FORCE) + runner_iact_nonsym_timebin(r2, dx, hi, hj, pi, pj, a, H); #endif } } diff --git a/src/runner_doiact_functions_limiter.h b/src/runner_doiact_functions_limiter.h new file mode 100644 index 0000000000000000000000000000000000000000..e2ecadbc52e838748c6538d1303fc50dc16a92e5 --- /dev/null +++ b/src/runner_doiact_functions_limiter.h @@ -0,0 +1,828 @@ +/******************************************************************************* + * This file is part of SWIFT. + * Copyright (c) 2012 Pedro Gonnet (pedro.gonnet@durham.ac.uk) + * 2016 Matthieu Schaller (matthieu.schaller@durham.ac.uk) + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published + * by the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this program. If not, see <http://www.gnu.org/licenses/>. + * + ******************************************************************************/ + +/* Before including this file, define FUNCTION, which is the + name of the interaction function. This creates the interaction functions + runner_dopair_FUNCTION, runner_dopair_FUNCTION_naive, runner_doself_FUNCTION, + and runner_dosub_FUNCTION calling the pairwise interaction function + runner_iact_FUNCTION. */ + +#include "runner_doiact_limiter.h" + +/** + * @brief Compute the interactions between a cell pair (non-symmetric case). + * + * Inefficient version using a brute-force algorithm. + * + * @param r The #runner. + * @param ci The first #cell. + * @param cj The second #cell. + */ +void DOPAIR1_NAIVE(struct runner *r, struct cell *restrict ci, + struct cell *restrict cj) { + + const struct engine *e = r->e; + const struct cosmology *cosmo = e->cosmology; + + TIMER_TIC; + + /* Anything to do here? */ + if (!cell_is_starting_hydro(ci, e) && !cell_is_starting_hydro(cj, e)) return; + + 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; + + /* Get the relative distance between the pairs, wrapping. */ + double shift[3] = {0.0, 0.0, 0.0}; + for (int k = 0; k < 3; k++) { + if (cj->loc[k] - ci->loc[k] < -e->s->dim[k] / 2) + shift[k] = e->s->dim[k]; + else if (cj->loc[k] - ci->loc[k] > e->s->dim[k] / 2) + shift[k] = -e->s->dim[k]; + } + + /* Loop over the parts in ci. */ + for (int pid = 0; pid < count_i; pid++) { + + /* Get a hold of the ith part in ci. */ + struct part *restrict pi = &parts_i[pid]; + + /* Skip inhibited particles. */ + if (part_is_inhibited(pi, e)) continue; + + const int pi_active = part_is_starting(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])), + (float)(pi->x[1] - (cj->loc[1] + shift[1])), + (float)(pi->x[2] - (cj->loc[2] + shift[2]))}; + + /* Loop over the parts in cj. */ + for (int pjd = 0; pjd < count_j; pjd++) { + + /* Get a pointer to the jth particle. */ + struct part *restrict pj = &parts_j[pjd]; + + /* Skip inhibited particles. */ + if (part_is_inhibited(pj, e)) continue; + + const float hj = pj->h; + const float hjg2 = hj * hj * kernel_gamma2; + const int pj_active = part_is_starting(pj, e); + + /* Compute the pairwise distance. */ + const float pjx[3] = {(float)(pj->x[0] - cj->loc[0]), + (float)(pj->x[1] - cj->loc[1]), + (float)(pj->x[2] - cj->loc[2])}; + 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]; + +#ifdef SWIFT_DEBUG_CHECKS + /* 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) + error("Particle pj not drifted to current time"); +#endif + + /* Hit or miss? */ + if (r2 < hig2 && pi_active) { + + IACT_NONSYM(r2, dx, hi, hj, pi, pj, a, H); + } + if (r2 < hjg2 && pj_active) { + + dx[0] = -dx[0]; + dx[1] = -dx[1]; + dx[2] = -dx[2]; + + IACT_NONSYM(r2, dx, hj, hi, pj, pi, a, H); + } + + } /* loop over the parts in cj. */ + } /* loop over the parts in ci. */ + + TIMER_TOC(TIMER_DOPAIR); +} + +/** + * @brief Compute the interactions within a cell (non-symmetric case). + * + * Inefficient version using a brute-force algorithm. + * + * @param r The #runner. + * @param c The #cell. + */ +void DOSELF1_NAIVE(struct runner *r, struct cell *restrict c) { + + const struct engine *e = r->e; + const struct cosmology *cosmo = e->cosmology; + + TIMER_TIC; + + /* Anything to do here? */ + if (!cell_is_starting_hydro(c, e)) return; + + /* Cosmological terms */ + const float a = cosmo->a; + const float H = cosmo->H; + + 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++) { + + /* Get a hold of the ith part in ci. */ + struct part *restrict pi = &parts[pid]; + + /* Skip inhibited particles. */ + if (part_is_inhibited(pi, e)) continue; + + const int pi_active = part_is_starting(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]), + (float)(pi->x[1] - c->loc[1]), + (float)(pi->x[2] - c->loc[2])}; + + /* Loop over the parts in cj. */ + for (int pjd = pid + 1; pjd < count; pjd++) { + + /* Get a pointer to the jth particle. */ + struct part *restrict pj = &parts[pjd]; + + /* Skip inhibited particles. */ + if (part_is_inhibited(pj, e)) continue; + + const float hj = pj->h; + const float hjg2 = hj * hj * kernel_gamma2; + const int pj_active = part_is_starting(pj, e); + + /* Compute the pairwise distance. */ + const float pjx[3] = {(float)(pj->x[0] - c->loc[0]), + (float)(pj->x[1] - c->loc[1]), + (float)(pj->x[2] - c->loc[2])}; + 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); + +#ifdef SWIFT_DEBUG_CHECKS + /* 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) + error("Particle pj not drifted to current time"); +#endif + + /* Hit or miss? */ + if (doi && doj) { + + IACT(r2, dx, hi, hj, pi, pj, a, H); + } else if (doi) { + + IACT_NONSYM(r2, dx, hi, hj, pi, pj, a, H); + } else if (doj) { + + dx[0] = -dx[0]; + dx[1] = -dx[1]; + dx[2] = -dx[2]; + + IACT_NONSYM(r2, dx, hj, hi, pj, pi, a, H); + } + } /* loop over the parts in cj. */ + } /* loop over the parts in ci. */ + + TIMER_TOC(TIMER_DOSELF); +} + +/** + * @brief Compute the interactions between a cell pair (non-symmetric). + * + * @param r The #runner. + * @param ci The first #cell. + * @param cj The second #cell. + * @param sid The direction of the pair. + * @param shift The shift vector to apply to the particles in ci. + */ +void DOPAIR1(struct runner *r, struct cell *ci, struct cell *cj, const int sid, + const double *shift) { + + const struct engine *restrict e = r->e; + const struct cosmology *restrict cosmo = e->cosmology; + + TIMER_TIC; + + /* Get the cutoff shift. */ + double rshift = 0.0; + for (int k = 0; k < 3; k++) rshift += shift[k] * runner_shift[sid][k]; + + /* Pick-out the sorted lists. */ + const struct sort_entry *restrict sort_i = ci->hydro.sort[sid]; + const struct sort_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->hydro.dx_max_part, cj->hydro.dx_max_part); + const float shift_threshold_y = + 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->hydro.dx_max_part, cj->hydro.dx_max_part); +#endif /* SWIFT_DEBUG_CHECKS */ + + /* Get some other useful values. */ + 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->hydro.dx_max_sort + cj->hydro.dx_max_sort); + + /* Cosmological terms */ + const float a = cosmo->a; + const float H = cosmo->H; + + if (cell_is_starting_hydro(ci, e)) { + + /* Loop over the parts in ci. */ + for (int pid = count_i - 1; + pid >= 0 && sort_i[pid].d + hi_max + dx_max > dj_min; pid--) { + + /* Get a hold of the ith part in ci. */ + struct part *restrict pi = &parts_i[sort_i[pid].i]; + const float hi = pi->h; + + /* Skip inactive particles */ + if (!part_is_starting(pi, e)) continue; + + /* Is there anything we need to interact with ? */ + const double di = sort_i[pid].d + hi * kernel_gamma + dx_max - rshift; + if (di < dj_min) continue; + + /* Get some additional information about pi */ + const float hig2 = hi * hi * kernel_gamma2; + const float pix = pi->x[0] - (cj->loc[0] + shift[0]); + const float piy = pi->x[1] - (cj->loc[1] + shift[1]); + const float piz = pi->x[2] - (cj->loc[2] + shift[2]); + + /* Loop over the parts in cj. */ + for (int pjd = 0; pjd < count_j && sort_j[pjd].d < di; pjd++) { + + /* Recover pj */ + struct part *pj = &parts_j[sort_j[pjd].i]; + + /* Skip inhibited particles. */ + if (part_is_inhibited(pj, e)) continue; + + const float hj = pj->h; + const float pjx = pj->x[0] - cj->loc[0]; + const float pjy = pj->x[1] - cj->loc[1]; + const float pjz = pj->x[2] - cj->loc[2]; + + /* Compute the pairwise distance. */ + 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 + /* Check that particles are in the correct frame after the shifts */ + if (pix > shift_threshold_x || pix < -shift_threshold_x) + error( + "Invalid particle position in X for pi (pix=%e ci->width[0]=%e)", + pix, ci->width[0]); + if (piy > shift_threshold_y || piy < -shift_threshold_y) + error( + "Invalid particle position in Y for pi (piy=%e ci->width[1]=%e)", + piy, ci->width[1]); + if (piz > shift_threshold_z || piz < -shift_threshold_z) + error( + "Invalid particle position in Z for pi (piz=%e ci->width[2]=%e)", + piz, ci->width[2]); + if (pjx > shift_threshold_x || pjx < -shift_threshold_x) + error( + "Invalid particle position in X for pj (pjx=%e ci->width[0]=%e)", + pjx, ci->width[0]); + if (pjy > shift_threshold_y || pjy < -shift_threshold_y) + error( + "Invalid particle position in Y for pj (pjy=%e ci->width[1]=%e)", + pjy, ci->width[1]); + if (pjz > shift_threshold_z || pjz < -shift_threshold_z) + error( + "Invalid particle position in Z for pj (pjz=%e ci->width[2]=%e)", + pjz, ci->width[2]); + + /* 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) + error("Particle pj not drifted to current time"); +#endif + + /* Hit or miss? */ + if (r2 < hig2) { + + IACT_NONSYM(r2, dx, hi, hj, pi, pj, a, H); + } + } /* loop over the parts in cj. */ + } /* loop over the parts in ci. */ + } /* Cell ci is active */ + + if (cell_is_starting_hydro(cj, e)) { + + /* Loop over the parts in cj. */ + for (int pjd = 0; pjd < count_j && sort_j[pjd].d - hj_max - dx_max < di_max; + pjd++) { + + /* Get a hold of the jth part in cj. */ + struct part *pj = &parts_j[sort_j[pjd].i]; + const float hj = pj->h; + + /* Skip inactive particles */ + if (!part_is_starting(pj, e)) continue; + + /* Is there anything we need to interact with ? */ + const double dj = sort_j[pjd].d - hj * kernel_gamma - dx_max + rshift; + if (dj - rshift > di_max) continue; + + /* Get some additional information about pj */ + const float hjg2 = hj * hj * kernel_gamma2; + const float pjx = pj->x[0] - cj->loc[0]; + const float pjy = pj->x[1] - cj->loc[1]; + const float pjz = pj->x[2] - cj->loc[2]; + + /* Loop over the parts in ci. */ + for (int pid = count_i - 1; pid >= 0 && sort_i[pid].d > dj; pid--) { + + /* Recover pi */ + struct part *pi = &parts_i[sort_i[pid].i]; + + /* Skip inhibited particles. */ + if (part_is_inhibited(pi, e)) continue; + + 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]); + const float piz = pi->x[2] - (cj->loc[2] + shift[2]); + + /* Compute the pairwise distance. */ + 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 + /* Check that particles are in the correct frame after the shifts */ + if (pix > shift_threshold_x || pix < -shift_threshold_x) + error( + "Invalid particle position in X for pi (pix=%e ci->width[0]=%e)", + pix, ci->width[0]); + if (piy > shift_threshold_y || piy < -shift_threshold_y) + error( + "Invalid particle position in Y for pi (piy=%e ci->width[1]=%e)", + piy, ci->width[1]); + if (piz > shift_threshold_z || piz < -shift_threshold_z) + error( + "Invalid particle position in Z for pi (piz=%e ci->width[2]=%e)", + piz, ci->width[2]); + if (pjx > shift_threshold_x || pjx < -shift_threshold_x) + error( + "Invalid particle position in X for pj (pjx=%e ci->width[0]=%e)", + pjx, ci->width[0]); + if (pjy > shift_threshold_y || pjy < -shift_threshold_y) + error( + "Invalid particle position in Y for pj (pjy=%e ci->width[1]=%e)", + pjy, ci->width[1]); + if (pjz > shift_threshold_z || pjz < -shift_threshold_z) + error( + "Invalid particle position in Z for pj (pjz=%e ci->width[2]=%e)", + pjz, ci->width[2]); + + /* 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) + error("Particle pj not drifted to current time"); +#endif + + /* Hit or miss? */ + if (r2 < hjg2) { + + IACT_NONSYM(r2, dx, hj, hi, pj, pi, a, H); + } + } /* loop over the parts in ci. */ + } /* loop over the parts in cj. */ + } /* Cell cj is active */ + + TIMER_TOC(TIMER_DOPAIR); +} + +/** + * @brief Determine which version of DOPAIR1 needs to be called depending on the + * orientation of the cells or whether DOPAIR1 needs to be called at all. + * + * @param r #runner + * @param ci #cell ci + * @param cj #cell cj + * + */ +void DOPAIR1_BRANCH(struct runner *r, struct cell *ci, struct cell *cj) { + + const struct engine *restrict e = r->e; + + /* Anything to do here? */ + if (ci->hydro.count == 0 || cj->hydro.count == 0) return; + + /* Anything to do here? */ + if (!cell_is_starting_hydro(ci, e) && !cell_is_starting_hydro(cj, e)) return; + + /* Check that cells are drifted. */ + if (!cell_are_part_drifted(ci, e) || !cell_are_part_drifted(cj, e)) + error("Interacting undrifted cells."); + + /* Get the sort ID. */ + double shift[3] = {0.0, 0.0, 0.0}; + const int sid = space_getsid(e->s, &ci, &cj, shift); + + /* Have the cells been sorted? */ + if (!(ci->hydro.sorted & (1 << sid)) || + ci->hydro.dx_max_sort_old > space_maxreldx * ci->dmin) + error("Interacting unsorted cells."); + 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 sort_entry *restrict sort_i = ci->hydro.sort[sid]; + const struct sort_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->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->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->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->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->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->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 */ + +#if defined(SWIFT_USE_NAIVE_INTERACTIONS) + DOPAIR1_NAIVE(r, ci, cj); +#else + DOPAIR1(r, ci, cj, sid, shift); +#endif +} + +/** + * @brief Compute the cell self-interaction (non-symmetric). + * + * @param r The #runner. + * @param c The #cell. + */ +void DOSELF1(struct runner *r, struct cell *restrict c) { + + const struct engine *e = r->e; + const struct cosmology *cosmo = e->cosmology; + + TIMER_TIC; + + struct part *restrict parts = c->hydro.parts; + const int count = c->hydro.count; + + /* Set up indt. */ + int *indt = NULL; + int countdt = 0, firstdt = 0; + if (posix_memalign((void **)&indt, VEC_SIZE * sizeof(int), + count * sizeof(int)) != 0) + error("Failed to allocate indt."); + for (int k = 0; k < count; k++) + if (part_is_starting(&parts[k], e)) { + indt[countdt] = k; + countdt += 1; + } + + /* Cosmological terms */ + const float a = cosmo->a; + const float H = cosmo->H; + + /* Loop over the particles in the cell. */ + for (int pid = 0; pid < count; pid++) { + + /* Get a pointer to the ith particle. */ + struct part *restrict pi = &parts[pid]; + + /* Skip inhibited particles. */ + if (part_is_inhibited(pi, e)) continue; + + /* Get the particle position and radius. */ + double pix[3]; + for (int k = 0; k < 3; k++) pix[k] = pi->x[k]; + const float hi = pi->h; + const float hig2 = hi * hi * kernel_gamma2; + + /* Is the ith particle inactive? */ + if (!part_is_starting(pi, e)) { + + /* Loop over the other particles .*/ + for (int pjd = firstdt; pjd < countdt; pjd++) { + + /* Get a pointer to the jth particle. */ + struct part *restrict pj = &parts[indt[pjd]]; + const float hj = pj->h; + +#ifdef SWIFT_DEBUG_CHECKS + /* 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) + error("Particle pj not drifted to current time"); +#endif + + /* Compute the pairwise distance. */ + float r2 = 0.0f; + float dx[3]; + for (int k = 0; k < 3; k++) { + dx[k] = pj->x[k] - pix[k]; + r2 += dx[k] * dx[k]; + } + + /* Hit or miss? */ + if (r2 < hj * hj * kernel_gamma2) { + + IACT_NONSYM(r2, dx, hj, hi, pj, pi, a, H); + } + } /* loop over all other particles. */ + } + + /* Otherwise, interact with all candidates. */ + else { + + /* We caught a live one! */ + firstdt += 1; + + /* Loop over the other particles .*/ + for (int pjd = pid + 1; pjd < count; pjd++) { + + /* Get a pointer to the jth particle. */ + struct part *restrict pj = &parts[pjd]; + + /* Skip inhibited particles. */ + if (part_is_inhibited(pj, e)) continue; + + const float hj = pj->h; + + /* Compute the pairwise distance. */ + float r2 = 0.0f; + float dx[3]; + for (int k = 0; k < 3; k++) { + dx[k] = pix[k] - pj->x[k]; + r2 += dx[k] * dx[k]; + } + const int doj = + (part_is_starting(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) + 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 (doi || doj) { + + /* Which parts need to be updated? */ + if (doi && doj) { + + IACT(r2, dx, hi, hj, pi, pj, a, H); + } else if (doi) { + + IACT_NONSYM(r2, dx, hi, hj, pi, pj, a, H); + } else if (doj) { + + dx[0] = -dx[0]; + dx[1] = -dx[1]; + dx[2] = -dx[2]; + IACT_NONSYM(r2, dx, hj, hi, pj, pi, a, H); + } + } + } /* loop over all other particles. */ + } + } /* loop over all particles. */ + + free(indt); + + TIMER_TOC(TIMER_DOSELF); +} + +/** + * @brief Determine which version of DOSELF1 needs to be called depending on the + * optimisation level. + * + * @param r #runner + * @param c #cell c + * + */ +void DOSELF1_BRANCH(struct runner *r, struct cell *c) { + + const struct engine *restrict e = r->e; + + /* Anything to do here? */ + if (c->hydro.count == 0) return; + + /* Anything to do here? */ + if (!cell_is_starting_hydro(c, e)) return; + + /* Did we mess up the recursion? */ + if (c->hydro.h_max_old * kernel_gamma > c->dmin) + error("Cell smaller than smoothing length"); + + /* Check that cells are drifted. */ + if (!cell_are_part_drifted(c, e)) error("Interacting undrifted cell."); + +#if defined(SWIFT_USE_NAIVE_INTERACTIONS) + DOSELF1_NAIVE(r, c); +#else + DOSELF1(r, c); +#endif +} + +/** + * @brief Compute grouped sub-cell interactions for pairs + * + * @param r The #runner. + * @param ci The first #cell. + * @param cj The second #cell. + * @param gettimer Do we have a timer ? + * + * @todo Hard-code the sid on the recursive calls to avoid the + * redundant computations to find the sid on-the-fly. + */ +void DOSUB_PAIR1(struct runner *r, struct cell *ci, struct cell *cj, + int gettimer) { + + struct space *s = r->e->s; + const struct engine *e = r->e; + + TIMER_TIC; + + /* Get the type of pair and flip ci/cj if needed. */ + double shift[3]; + const int sid = space_getsid(s, &ci, &cj, shift); + + /* Should we even bother? */ + const int do_i = cell_get_flag(ci, cell_flag_do_hydro_limiter); + const int do_j = cell_get_flag(cj, cell_flag_do_hydro_limiter); + const int do_sub_i = cell_get_flag(ci, cell_flag_do_hydro_sub_limiter); + const int do_sub_j = cell_get_flag(cj, cell_flag_do_hydro_sub_limiter); + + if (!do_i && !do_j && !do_sub_i && !do_sub_j) return; + if (!cell_is_starting_hydro(ci, e) && !cell_is_starting_hydro(cj, e)) return; + if (ci->hydro.count == 0 || cj->hydro.count == 0) return; + + /* Recurse? */ + if (cell_can_recurse_in_pair_hydro_task(ci) && + cell_can_recurse_in_pair_hydro_task(cj)) { + struct cell_split_pair *csp = &cell_split_pairs[sid]; + for (int k = 0; k < csp->count; k++) { + const int pid = csp->pairs[k].pid; + const int pjd = csp->pairs[k].pjd; + if (ci->progeny[pid] != NULL && cj->progeny[pjd] != NULL) + DOSUB_PAIR1(r, ci->progeny[pid], cj->progeny[pjd], 0); + } + } + + /* Otherwise, compute the pair directly. */ + else if ((cell_is_starting_hydro(ci, e) && (do_i || do_sub_i)) || + (cell_is_starting_hydro(cj, e) && (do_j || do_sub_j))) { + + /* Make sure both cells are drifted to the current timestep. */ + if (!cell_are_part_drifted(ci, e) || !cell_are_part_drifted(cj, e)) + error("Interacting undrifted cells."); + + /* Do any of the cells need to be sorted first? */ + if (!(ci->hydro.sorted & (1 << sid)) || + ci->hydro.dx_max_sort_old > ci->dmin * space_maxreldx) + error( + "Interacting unsorted cell. ci->hydro.dx_max_sort_old=%e ci->dmin=%e " + "ci->sorted=%d sid=%d", + 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->hydro.dx_max_sort_old=%e cj->dmin=%e " + "cj->sorted=%d sid=%d", + cj->hydro.dx_max_sort_old, cj->dmin, cj->hydro.sorted, sid); + + /* Compute the interactions. */ + DOPAIR1_BRANCH(r, ci, cj); + } + + if (gettimer) TIMER_TOC(TIMER_DOSUB_PAIR); +} + +/** + * @brief Compute grouped sub-cell interactions for self tasks + * + * @param r The #runner. + * @param ci The first #cell. + * @param gettimer Do we have a timer ? + */ +void DOSUB_SELF1(struct runner *r, struct cell *ci, int gettimer) { + + TIMER_TIC; + + /* Should we even bother? */ + const int do_i = cell_get_flag(ci, cell_flag_do_hydro_limiter); + const int do_sub_i = cell_get_flag(ci, cell_flag_do_hydro_sub_limiter); + + if (!do_i && !do_sub_i) return; + if (!cell_is_starting_hydro(ci, r->e)) return; + if (ci->hydro.count == 0) return; + + /* Recurse? */ + if (cell_can_recurse_in_self_hydro_task(ci)) { + + /* Loop over all progeny. */ + for (int k = 0; k < 8; k++) + if (ci->progeny[k] != NULL) { + DOSUB_SELF1(r, ci->progeny[k], 0); + for (int j = k + 1; j < 8; j++) + if (ci->progeny[j] != NULL) + DOSUB_PAIR1(r, ci->progeny[k], ci->progeny[j], 0); + } + } + + /* Otherwise, compute self-interaction. */ + else { + + /* Drift the cell to the current timestep if needed. */ + if (!cell_are_part_drifted(ci, r->e)) error("Interacting undrifted cell."); + + DOSELF1_BRANCH(r, ci); + } + + if (gettimer) TIMER_TOC(TIMER_DOSUB_SELF); +} diff --git a/src/runner_doiact_functions_stars.h b/src/runner_doiact_functions_stars.h index d452fba01b38de09d71ca4a121dcd5d92388bc08..22b2118d36eb57e1e026adb8e506970ec0cbeedd 100644 --- a/src/runner_doiact_functions_stars.h +++ b/src/runner_doiact_functions_stars.h @@ -298,9 +298,8 @@ void DO_SYM_PAIR1_STARS(struct runner *r, struct cell *ci, struct cell *cj, struct xpart *restrict xparts_j = cj->hydro.xparts; #endif const double dj_min = sort_j[0].d; - const float dx_max_rshift = - (ci->stars.dx_max_sort + cj->hydro.dx_max_sort) - rshift; const float dx_max = (ci->stars.dx_max_sort + cj->hydro.dx_max_sort); + const float hydro_dx_max_rshift = cj->hydro.dx_max_sort - rshift; /* Loop over the sparts in ci. */ for (int pid = count_i - 1; @@ -322,7 +321,7 @@ void DO_SYM_PAIR1_STARS(struct runner *r, struct cell *ci, struct cell *cj, px[2] * runner_shift[sid][2]; /* Is there anything we need to interact with ? */ - const double di = dist + hi * kernel_gamma + dx_max_rshift; + const double di = dist + hi * kernel_gamma + hydro_dx_max_rshift; if (di < dj_min) continue; /* Get some additional information about pi */ @@ -428,9 +427,8 @@ void DO_SYM_PAIR1_STARS(struct runner *r, struct cell *ci, struct cell *cj, struct xpart *restrict xparts_i = ci->hydro.xparts; struct spart *restrict sparts_j = cj->stars.parts; const double di_max = sort_i[count_i - 1].d - rshift; - const float dx_max_rshift = - (ci->hydro.dx_max_sort + cj->stars.dx_max_sort) + rshift; const float dx_max = (ci->hydro.dx_max_sort + cj->stars.dx_max_sort); + const float hydro_dx_max_rshift = ci->hydro.dx_max_sort - rshift; /* Loop over the parts in cj. */ for (int pjd = 0; pjd < count_j && sort_j[pjd].d - hj_max - dx_max < di_max; @@ -452,7 +450,7 @@ void DO_SYM_PAIR1_STARS(struct runner *r, struct cell *ci, struct cell *cj, px[2] * runner_shift[sid][2]; /* Is there anything we need to interact with ? */ - const double dj = dist - hj * kernel_gamma - dx_max_rshift; + const double dj = dist - hj * kernel_gamma - hydro_dx_max_rshift; if (dj - rshift > di_max) continue; /* Get some additional information about pj */ @@ -577,7 +575,6 @@ void DOPAIR1_SUBSET_STARS(struct runner *r, struct cell *restrict ci, const int flipped, const double *shift) { const struct engine *e = r->e; - const integertime_t ti_current = e->ti_current; const struct cosmology *cosmo = e->cosmology; /* Cosmological terms */ @@ -586,9 +583,6 @@ void DOPAIR1_SUBSET_STARS(struct runner *r, struct cell *restrict ci, const int count_j = cj->hydro.count; struct part *restrict parts_j = cj->hydro.parts; -#if (FUNCTION_TASK_LOOP == TASK_LOOP_FEEDBACK) - struct xpart *restrict xparts_j = cj->hydro.xparts; -#endif /* Early abort? */ if (count_j == 0) return; @@ -618,9 +612,6 @@ void DOPAIR1_SUBSET_STARS(struct runner *r, struct cell *restrict ci, /* Get a pointer to the jth particle. */ struct part *restrict pj = &parts_j[sort_j[pjd].i]; -#if (FUNCTION_TASK_LOOP == TASK_LOOP_FEEDBACK) - struct xpart *restrict xpj = &xparts_j[sort_j[pjd].i]; -#endif /* Skip inhibited particles. */ if (part_is_inhibited(pj, e)) continue; @@ -649,10 +640,11 @@ void DOPAIR1_SUBSET_STARS(struct runner *r, struct cell *restrict ci, #if (FUNCTION_TASK_LOOP == TASK_LOOP_DENSITY) runner_iact_nonsym_feedback_density(r2, dx, hi, hj, spi, pj, NULL, - cosmo, ti_current); + cosmo, e->ti_current); #elif (FUNCTION_TASK_LOOP == TASK_LOOP_FEEDBACK) - runner_iact_nonsym_feedback_apply(r2, dx, hi, hj, spi, pj, xpj, cosmo, - ti_current); + error("No subset feedback iact functions do (or should) exist!"); + /* runner_iact_nonsym_feedback_apply(r2, dx, hi, hj, spi, pj, xpj, + * cosmo, ti_current); */ #endif } } /* loop over the parts in cj. */ @@ -680,9 +672,6 @@ void DOPAIR1_SUBSET_STARS(struct runner *r, struct cell *restrict ci, /* Get a pointer to the jth particle. */ struct part *restrict pj = &parts_j[sort_j[pjd].i]; -#if (FUNCTION_TASK_LOOP == TASK_LOOP_FEEDBACK) - struct xpart *restrict xpj = &xparts_j[sort_j[pjd].i]; -#endif /* Skip inhibited particles. */ if (part_is_inhibited(pj, e)) continue; @@ -711,10 +700,11 @@ void DOPAIR1_SUBSET_STARS(struct runner *r, struct cell *restrict ci, #if (FUNCTION_TASK_LOOP == TASK_LOOP_DENSITY) runner_iact_nonsym_feedback_density(r2, dx, hi, hj, spi, pj, NULL, - cosmo, ti_current); + cosmo, e->ti_current); #elif (FUNCTION_TASK_LOOP == TASK_LOOP_FEEDBACK) - runner_iact_nonsym_feedback_apply(r2, dx, hi, hj, spi, pj, xpj, cosmo, - ti_current); + error("No subset feedback iact functions do (or should) exist!"); + /* runner_iact_nonsym_feedback_apply(r2, dx, hi, hj, spi, pj, xpj, + * cosmo, ti_current); */ #endif } } /* loop over the parts in cj. */ @@ -746,7 +736,6 @@ void DOPAIR1_SUBSET_STARS_NAIVE(struct runner *r, struct cell *restrict ci, #endif const struct engine *e = r->e; - const integertime_t ti_current = e->ti_current; const struct cosmology *cosmo = e->cosmology; /* Cosmological terms */ @@ -755,9 +744,6 @@ void DOPAIR1_SUBSET_STARS_NAIVE(struct runner *r, struct cell *restrict ci, const int count_j = cj->hydro.count; struct part *restrict parts_j = cj->hydro.parts; -#if (FUNCTION_TASK_LOOP == TASK_LOOP_FEEDBACK) - struct xpart *restrict xparts_j = cj->hydro.xparts; -#endif /* Early abort? */ if (count_j == 0) return; @@ -784,9 +770,6 @@ void DOPAIR1_SUBSET_STARS_NAIVE(struct runner *r, struct cell *restrict ci, /* Get a pointer to the jth particle. */ struct part *restrict pj = &parts_j[pjd]; -#if (FUNCTION_TASK_LOOP == TASK_LOOP_FEEDBACK) - struct xpart *restrict xpj = &xparts_j[pjd]; -#endif /* Skip inhibited particles */ if (part_is_inhibited(pj, e)) continue; @@ -812,10 +795,11 @@ void DOPAIR1_SUBSET_STARS_NAIVE(struct runner *r, struct cell *restrict ci, #if (FUNCTION_TASK_LOOP == TASK_LOOP_DENSITY) runner_iact_nonsym_feedback_density(r2, dx, hi, hj, spi, pj, NULL, - cosmo, ti_current); + cosmo, e->ti_current); #elif (FUNCTION_TASK_LOOP == TASK_LOOP_FEEDBACK) - runner_iact_nonsym_feedback_apply(r2, dx, hi, hj, spi, pj, xpj, cosmo, - ti_current); + error("No subset feedback iact functions do (or should) exist! ."); + /* runner_iact_nonsym_feedback_apply(r2, dx, hi, hj, spi, pj, xpj, + * cosmo, ti_current); */ #endif } } /* loop over the parts in cj. */ @@ -835,13 +819,11 @@ void DOPAIR1_SUBSET_STARS_NAIVE(struct runner *r, struct cell *restrict ci, void DOSELF1_SUBSET_STARS(struct runner *r, struct cell *restrict ci, struct spart *restrict sparts, int *restrict ind, int scount) { - #ifdef SWIFT_DEBUG_CHECKS if (ci->nodeID != engine_rank) error("Should be run on a different node"); #endif const struct engine *e = r->e; - const integertime_t ti_current = e->ti_current; const struct cosmology *cosmo = e->cosmology; /* Cosmological terms */ @@ -850,9 +832,6 @@ void DOSELF1_SUBSET_STARS(struct runner *r, struct cell *restrict ci, const int count_i = ci->hydro.count; struct part *restrict parts_j = ci->hydro.parts; -#if (FUNCTION_TASK_LOOP == TASK_LOOP_FEEDBACK) - struct xpart *restrict xparts_j = ci->hydro.xparts; -#endif /* Early abort? */ if (count_i == 0) return; @@ -878,9 +857,6 @@ void DOSELF1_SUBSET_STARS(struct runner *r, struct cell *restrict ci, /* Get a pointer to the jth particle. */ struct part *restrict pj = &parts_j[pjd]; -#if (FUNCTION_TASK_LOOP == TASK_LOOP_FEEDBACK) - struct xpart *restrict xpj = &xparts_j[pjd]; -#endif /* Early abort? */ if (part_is_inhibited(pj, e)) continue; @@ -903,10 +879,11 @@ void DOSELF1_SUBSET_STARS(struct runner *r, struct cell *restrict ci, IACT_STARS(r2, dx, hi, pj->h, spi, pj, a, H); #if (FUNCTION_TASK_LOOP == TASK_LOOP_DENSITY) runner_iact_nonsym_feedback_density(r2, dx, hi, pj->h, spi, pj, NULL, - cosmo, ti_current); + cosmo, e->ti_current); #elif (FUNCTION_TASK_LOOP == TASK_LOOP_FEEDBACK) - runner_iact_nonsym_feedback_apply(r2, dx, hi, pj->h, spi, pj, xpj, - cosmo, ti_current); + error("No subset feedback iact functions do (or should) exist!"); + /* runner_iact_nonsym_feedback_apply(r2, dx, hi, pj->h, spi, pj, xpj, */ + /* cosmo, e, ti_current); */ #endif } } /* loop over the parts in cj. */ diff --git a/src/runner_doiact_hydro.c b/src/runner_doiact_hydro.c index 4638513c718257e99b39b1c9b17368e6a2b4bfa2..f51a5d7370a10289ab19b4dc6bbe4b280dfe24cc 100644 --- a/src/runner_doiact_hydro.c +++ b/src/runner_doiact_hydro.c @@ -25,6 +25,7 @@ /* Local headers. */ #include "active.h" #include "cell.h" +#include "chemistry.h" #include "engine.h" #include "pressure_floor_iact.h" #include "runner.h" @@ -32,6 +33,7 @@ #include "space_getsid.h" #include "star_formation_iact.h" #include "timers.h" +#include "timestep_limiter_iact.h" /* Import the density loop functions. */ #define FUNCTION density @@ -55,10 +57,3 @@ #include "runner_doiact_functions_hydro.h" #undef FUNCTION #undef FUNCTION_TASK_LOOP - -/* Import the limiter loop functions. */ -#define FUNCTION limiter -#define FUNCTION_TASK_LOOP TASK_LOOP_LIMITER -#include "runner_doiact_functions_hydro.h" -#undef FUNCTION -#undef FUNCTION_TASK_LOOP diff --git a/src/runner_doiact_limiter.c b/src/runner_doiact_limiter.c new file mode 100644 index 0000000000000000000000000000000000000000..ac65ca063cffd89e26673b0a8d4df6fbfa263e56 --- /dev/null +++ b/src/runner_doiact_limiter.c @@ -0,0 +1,39 @@ +/******************************************************************************* + * 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) + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published + * by the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this program. If not, see <http://www.gnu.org/licenses/>. + * + ******************************************************************************/ + +/* Config parameters. */ +#include "../config.h" + +/* Local headers. */ +#include "active.h" +#include "cell.h" +#include "engine.h" +#include "runner.h" +#include "space_getsid.h" +#include "timers.h" +#include "timestep_limiter_iact.h" + +/* Import the limiter loop functions. */ +#define FUNCTION limiter +#define FUNCTION_TASK_LOOP TASK_LOOP_LIMITER +#include "runner_doiact_functions_limiter.h" +#undef FUNCTION +#undef FUNCTION_TASK_LOOP diff --git a/src/runner_doiact_limiter.h b/src/runner_doiact_limiter.h new file mode 100644 index 0000000000000000000000000000000000000000..a0daaf426174c3653ba95ba7d0e36a07899b2a89 --- /dev/null +++ b/src/runner_doiact_limiter.h @@ -0,0 +1,102 @@ +/******************************************************************************* + * This file is part of SWIFT. + * Copyright (c) 2012 Pedro Gonnet (pedro.gonnet@durham.ac.uk) + * 2016 Matthieu Schaller (matthieu.schaller@durham.ac.uk) + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published + * by the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this program. If not, see <http://www.gnu.org/licenses/>. + * + ******************************************************************************/ + +/* Before including this file, define FUNCTION, which is the + name of the interaction function. This creates the interaction functions + runner_dopair_FUNCTION, runner_dopair_FUNCTION_naive, runner_doself_FUNCTION, + and runner_dosub_FUNCTION calling the pairwise interaction function + runner_iact_FUNCTION. */ + +#define PASTE(x, y) x##_##y + +#define _DOPAIR1_BRANCH(f) PASTE(runner_dopair1_branch, f) +#define DOPAIR1_BRANCH _DOPAIR1_BRANCH(FUNCTION) + +#define _DOPAIR1(f) PASTE(runner_dopair1, f) +#define DOPAIR1 _DOPAIR1(FUNCTION) + +#define _DOPAIR2_BRANCH(f) PASTE(runner_dopair2_branch, f) +#define DOPAIR2_BRANCH _DOPAIR2_BRANCH(FUNCTION) + +#define _DOPAIR2(f) PASTE(runner_dopair2, f) +#define DOPAIR2 _DOPAIR2(FUNCTION) + +#define _DOPAIR1_NAIVE(f) PASTE(runner_dopair1_naive, f) +#define DOPAIR1_NAIVE _DOPAIR1_NAIVE(FUNCTION) + +#define _DOPAIR2_NAIVE(f) PASTE(runner_dopair2_naive, f) +#define DOPAIR2_NAIVE _DOPAIR2_NAIVE(FUNCTION) + +#define _DOSELF1_NAIVE(f) PASTE(runner_doself1_naive, f) +#define DOSELF1_NAIVE _DOSELF1_NAIVE(FUNCTION) + +#define _DOSELF2_NAIVE(f) PASTE(runner_doself2_naive, f) +#define DOSELF2_NAIVE _DOSELF2_NAIVE(FUNCTION) + +#define _DOSELF1_BRANCH(f) PASTE(runner_doself1_branch, f) +#define DOSELF1_BRANCH _DOSELF1_BRANCH(FUNCTION) + +#define _DOSELF1(f) PASTE(runner_doself1, f) +#define DOSELF1 _DOSELF1(FUNCTION) + +#define _DOSELF2_BRANCH(f) PASTE(runner_doself2_branch, f) +#define DOSELF2_BRANCH _DOSELF2_BRANCH(FUNCTION) + +#define _DOSELF2(f) PASTE(runner_doself2, f) +#define DOSELF2 _DOSELF2(FUNCTION) + +#define _DOSUB_SELF1(f) PASTE(runner_dosub_self1, f) +#define DOSUB_SELF1 _DOSUB_SELF1(FUNCTION) + +#define _DOSUB_PAIR1(f) PASTE(runner_dosub_pair1, f) +#define DOSUB_PAIR1 _DOSUB_PAIR1(FUNCTION) + +#define _DOSUB_SELF2(f) PASTE(runner_dosub_self2, f) +#define DOSUB_SELF2 _DOSUB_SELF2(FUNCTION) + +#define _DOSUB_PAIR2(f) PASTE(runner_dosub_pair2, f) +#define DOSUB_PAIR2 _DOSUB_PAIR2(FUNCTION) + +#define _IACT_NONSYM(f) PASTE(runner_iact_nonsym, f) +#define IACT_NONSYM _IACT_NONSYM(FUNCTION) + +#define _IACT(f) PASTE(runner_iact, f) +#define IACT _IACT(FUNCTION) + +#define _TIMER_DOSELF(f) PASTE(timer_doself, f) +#define TIMER_DOSELF _TIMER_DOSELF(FUNCTION) + +#define _TIMER_DOPAIR(f) PASTE(timer_dopair, f) +#define TIMER_DOPAIR _TIMER_DOPAIR(FUNCTION) + +#define _TIMER_DOSUB_SELF(f) PASTE(timer_dosub_self, f) +#define TIMER_DOSUB_SELF _TIMER_DOSUB_SELF(FUNCTION) + +#define _TIMER_DOSUB_PAIR(f) PASTE(timer_dosub_pair, f) +#define TIMER_DOSUB_PAIR _TIMER_DOSUB_PAIR(FUNCTION) + +void DOSELF1_BRANCH(struct runner *r, struct cell *c); + +void DOPAIR1_BRANCH(struct runner *r, struct cell *ci, struct cell *cj); + +void DOSUB_SELF1(struct runner *r, struct cell *ci, int gettimer); + +void DOSUB_PAIR1(struct runner *r, struct cell *ci, struct cell *cj, + int gettimer); diff --git a/src/runner_ghost.c b/src/runner_ghost.c index 7f9ce92fb6809919e59cff8dd27149cf9e25bacf..2aaf172ea46aa285603270ca5f8fdb1d2b10c1c7 100644 --- a/src/runner_ghost.c +++ b/src/runner_ghost.c @@ -37,6 +37,7 @@ #include "star_formation.h" #include "stars.h" #include "timers.h" +#include "timestep_limiter.h" #include "tracers.h" /* Import the density loop functions. */ @@ -73,6 +74,7 @@ void runner_do_stars_ghost(struct runner *r, struct cell *c, int timer) { struct spart *restrict sparts = c->stars.parts; const struct engine *e = r->e; const struct unit_system *us = e->internal_units; + const struct phys_const *phys_const = e->physical_constants; const int with_cosmology = (e->policy & engine_policy_cosmology); const struct cosmology *cosmo = e->cosmology; const struct feedback_props *feedback_props = e->feedback_props; @@ -203,19 +205,19 @@ void runner_do_stars_ghost(struct runner *r, struct cell *c, int timer) { stars_reset_feedback(sp); /* Only do feedback if stars have a reasonable birth time */ - if (feedback_do_feedback(sp)) { + if (feedback_is_active(sp, e->time, cosmo, with_cosmology)) { const integertime_t ti_step = get_integer_timestep(sp->time_bin); const integertime_t ti_begin = get_integer_time_begin(e->ti_current - 1, sp->time_bin); /* Get particle time-step */ - double dt; + double dt_star; if (with_cosmology) { - dt = cosmology_get_delta_time(e->cosmology, ti_begin, - ti_begin + ti_step); + dt_star = cosmology_get_delta_time(e->cosmology, ti_begin, + ti_begin + ti_step); } else { - dt = get_timestep(sp->time_bin, e->time_base); + dt_star = get_timestep(sp->time_bin, e->time_base); } /* Calculate age of the star at current time */ @@ -225,19 +227,22 @@ void runner_do_stars_ghost(struct runner *r, struct cell *c, int timer) { cosmology_get_delta_time_from_scale_factors( cosmo, (double)sp->birth_scale_factor, cosmo->a); } else { - star_age_end_of_step = (float)e->time - sp->birth_time; + star_age_end_of_step = e->time - (double)sp->birth_time; } /* Has this star been around for a while ? */ if (star_age_end_of_step > 0.) { - /* Age of the star at the start of the step */ + /* Get the length of the enrichment time-step */ + const double dt_enrichment = feedback_get_enrichment_timestep( + sp, with_cosmology, cosmo, e->time, dt_star); const double star_age_beg_of_step = - max(star_age_end_of_step - dt, 0.); + star_age_end_of_step - dt_enrichment; /* Compute the stellar evolution */ - feedback_evolve_spart(sp, feedback_props, cosmo, us, - star_age_beg_of_step, dt); + feedback_evolve_spart(sp, feedback_props, cosmo, us, phys_const, + star_age_beg_of_step, dt_enrichment, + e->time, ti_begin, with_cosmology); } else { /* Reset the feedback fields of the star particle */ @@ -344,40 +349,43 @@ void runner_do_stars_ghost(struct runner *r, struct cell *c, int timer) { stars_reset_feedback(sp); /* Only do feedback if stars have a reasonable birth time */ - if (feedback_do_feedback(sp)) { + if (feedback_is_active(sp, e->time, cosmo, with_cosmology)) { const integertime_t ti_step = get_integer_timestep(sp->time_bin); const integertime_t ti_begin = get_integer_time_begin(e->ti_current - 1, sp->time_bin); /* Get particle time-step */ - double dt; + double dt_star; if (with_cosmology) { - dt = cosmology_get_delta_time(e->cosmology, ti_begin, - ti_begin + ti_step); + dt_star = cosmology_get_delta_time(e->cosmology, ti_begin, + ti_begin + ti_step); } else { - dt = get_timestep(sp->time_bin, e->time_base); + dt_star = get_timestep(sp->time_bin, e->time_base); } /* Calculate age of the star at current time */ double star_age_end_of_step; if (with_cosmology) { star_age_end_of_step = cosmology_get_delta_time_from_scale_factors( - cosmo, sp->birth_scale_factor, (float)cosmo->a); + cosmo, (double)sp->birth_scale_factor, cosmo->a); } else { - star_age_end_of_step = (float)e->time - sp->birth_time; + star_age_end_of_step = e->time - (double)sp->birth_time; } /* Has this star been around for a while ? */ if (star_age_end_of_step > 0.) { - /* Age of the star at the start of the step */ + /* Get the length of the enrichment time-step */ + const double dt_enrichment = feedback_get_enrichment_timestep( + sp, with_cosmology, cosmo, e->time, dt_star); const double star_age_beg_of_step = - max(star_age_end_of_step - dt, 0.); + star_age_end_of_step - dt_enrichment; /* Compute the stellar evolution */ - feedback_evolve_spart(sp, feedback_props, cosmo, us, - star_age_beg_of_step, dt); + feedback_evolve_spart(sp, feedback_props, cosmo, us, phys_const, + star_age_beg_of_step, dt_enrichment, e->time, + ti_begin, with_cosmology); } else { /* Reset the feedback fields of the star particle */ @@ -837,7 +845,8 @@ void runner_do_black_holes_swallow_ghost(struct runner *r, struct cell *c, /* Compute variables required for the feedback loop */ black_holes_prepare_feedback(bp, e->black_holes_properties, - e->physical_constants, e->cosmology, dt); + e->physical_constants, e->cosmology, + e->time, with_cosmology, dt); } } } @@ -910,6 +919,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, hydro_props, dt_alpha); + timestep_limiter_prepare_force(p, xp); /* The particle force values are now set. Do _NOT_ try to read any particle density variables! */ @@ -1045,7 +1055,7 @@ void runner_do_ghost(struct runner *r, struct cell *c, int timer) { hydro_end_density(p, cosmo); chemistry_end_density(p, chemistry, cosmo); pressure_floor_end_density(p, cosmo); - star_formation_end_density(p, star_formation, cosmo); + star_formation_end_density(p, xp, star_formation, cosmo); /* Are we using the alternative definition of the number of neighbours? */ @@ -1128,6 +1138,7 @@ void runner_do_ghost(struct runner *r, struct cell *c, int timer) { /* Compute variables required for the force loop */ hydro_prepare_force(p, xp, cosmo, hydro_props, dt_alpha); + timestep_limiter_prepare_force(p, xp); /* The particle force values are now set. Do _NOT_ try to read any particle density variables! */ @@ -1283,6 +1294,7 @@ void runner_do_ghost(struct runner *r, struct cell *c, int timer) { /* Compute variables required for the force loop */ hydro_prepare_force(p, xp, cosmo, hydro_props, dt_alpha); + timestep_limiter_prepare_force(p, xp); /* The particle force values are now set. Do _NOT_ try to read any particle density variables! */ diff --git a/src/runner_main.c b/src/runner_main.c index a674b64ae671bf33df0b5ba9eaa951097d738ba9..effcdf3cda94c5b74276af40f69c0e384aecadf4 100644 --- a/src/runner_main.c +++ b/src/runner_main.c @@ -65,7 +65,7 @@ /* Import the limiter loop functions. */ #define FUNCTION limiter #define FUNCTION_TASK_LOOP TASK_LOOP_LIMITER -#include "runner_doiact_hydro.h" +#include "runner_doiact_limiter.h" #undef FUNCTION #undef FUNCTION_TASK_LOOP @@ -182,7 +182,7 @@ void *runner_main(void *data) { else if (t->subtype == task_subtype_force) runner_doself2_branch_force(r, ci); else if (t->subtype == task_subtype_limiter) - runner_doself2_branch_limiter(r, ci); + runner_doself1_branch_limiter(r, ci); else if (t->subtype == task_subtype_grav) runner_doself_recursive_grav(r, ci, 1); else if (t->subtype == task_subtype_external_grav) @@ -216,7 +216,7 @@ void *runner_main(void *data) { else if (t->subtype == task_subtype_force) runner_dopair2_branch_force(r, ci, cj); else if (t->subtype == task_subtype_limiter) - runner_dopair2_branch_limiter(r, ci, cj); + runner_dopair1_branch_limiter(r, ci, cj); else if (t->subtype == task_subtype_grav) runner_dopair_recursive_grav(r, ci, cj, 1); else if (t->subtype == task_subtype_stars_density) @@ -248,7 +248,7 @@ void *runner_main(void *data) { else if (t->subtype == task_subtype_force) runner_dosub_self2_force(r, ci, 1); else if (t->subtype == task_subtype_limiter) - runner_dosub_self2_limiter(r, ci, 1); + runner_dosub_self1_limiter(r, ci, 1); else if (t->subtype == task_subtype_stars_density) runner_dosub_self_stars_density(r, ci, 1); else if (t->subtype == task_subtype_stars_feedback) @@ -278,7 +278,7 @@ void *runner_main(void *data) { else if (t->subtype == task_subtype_force) runner_dosub_pair2_force(r, ci, cj, 1); else if (t->subtype == task_subtype_limiter) - runner_dosub_pair2_limiter(r, ci, cj, 1); + runner_dosub_pair1_limiter(r, ci, cj, 1); else if (t->subtype == task_subtype_stars_density) runner_dosub_pair_stars_density(r, ci, cj, 1); else if (t->subtype == task_subtype_stars_feedback) @@ -367,6 +367,9 @@ void *runner_main(void *data) { case task_type_timestep_limiter: runner_do_limiter(r, ci, 0, 1); break; + case task_type_timestep_sync: + runner_do_sync(r, ci, 0, 1); + break; #ifdef WITH_MPI case task_type_send: if (t->subtype == task_subtype_tend_part) { diff --git a/src/runner_others.c b/src/runner_others.c index 5ffaf7aa321f658b6e0e7e10a9cb8ad2f4a5a541..2f7a82e2ff0158e99987b25c3bc9c6e7f3c15dec 100644 --- a/src/runner_others.c +++ b/src/runner_others.c @@ -44,6 +44,7 @@ #include "cooling.h" #include "engine.h" #include "error.h" +#include "feedback.h" #include "gravity.h" #include "hydro.h" #include "logger.h" @@ -52,7 +53,9 @@ #include "star_formation.h" #include "star_formation_logger.h" #include "stars.h" +#include "task_order.h" #include "timers.h" +#include "timestep_limiter.h" #include "tracers.h" /** @@ -142,7 +145,6 @@ void runner_do_grav_mesh(struct runner *r, struct cell *c, int timer) { * @param timer 1 if the time is to be recorded. */ void runner_do_cooling(struct runner *r, struct cell *c, int timer) { - const struct engine *e = r->e; const struct cosmology *cosmo = e->cosmology; const int with_cosmology = (e->policy & engine_policy_cosmology); @@ -156,11 +158,14 @@ void runner_do_cooling(struct runner *r, struct cell *c, int timer) { struct part *restrict parts = c->hydro.parts; struct xpart *restrict xparts = c->hydro.xparts; const int count = c->hydro.count; + const double time = e->time; TIMER_TIC; - /* Anything to do here? */ - if (!cell_is_active_hydro(c, e)) return; + /* Anything to do here? (i.e. does this cell need updating?) */ + if (!((task_order_cooling_after_timestep && cell_is_starting_hydro(c, e)) || + (!task_order_cooling_after_timestep && cell_is_active_hydro(c, e)))) + return; /* Recurse? */ if (c->split) { @@ -175,7 +180,9 @@ void runner_do_cooling(struct runner *r, struct cell *c, int timer) { struct part *restrict p = &parts[i]; struct xpart *restrict xp = &xparts[i]; - if (part_is_active(p, e)) { + /* Anything to do here? (i.e. does this particle need updating?) */ + if ((task_order_cooling_after_timestep && part_is_starting(p, e)) || + (!task_order_cooling_after_timestep && part_is_active(p, e))) { double dt_cool, dt_therm; if (with_cosmology) { @@ -195,8 +202,13 @@ void runner_do_cooling(struct runner *r, struct cell *c, int timer) { /* Let's cool ! */ cooling_cool_part(constants, us, cosmo, hydro_props, - entropy_floor_props, cooling_func, p, xp, dt_cool, - dt_therm); + entropy_floor_props, cooling_func, p, xp, time, + dt_cool, dt_therm); + + /* Apply the effects of feedback on this particle + * (Note: Only used in schemes that have a delayed feedback mechanism + * otherwise just an empty function) */ + feedback_update_part(p, xp, e); } } } @@ -287,8 +299,8 @@ void runner_do_star_formation(struct runner *r, struct cell *c, int timer) { } /* Compute the SF rate of the particle */ - star_formation_compute_SFR(p, xp, sf_props, phys_const, cosmo, - dt_star); + star_formation_compute_SFR(p, xp, sf_props, phys_const, hydro_props, + cosmo, dt_star); /* Add the SFR and SFR*dt to the SFH struct of this cell */ star_formation_logger_log_active_part(p, xp, &c->stars.sfh, dt_star); @@ -297,6 +309,23 @@ void runner_do_star_formation(struct runner *r, struct cell *c, int timer) { if (star_formation_should_convert_to_star(p, xp, sf_props, e, dt_star)) { +#ifdef WITH_LOGGER + /* Write the particle */ + /* Logs all the fields request by the user */ + // TODO select only the requested fields + logger_log_part(e->logger, p, + logger_mask_data[logger_x].mask | + logger_mask_data[logger_v].mask | + logger_mask_data[logger_a].mask | + logger_mask_data[logger_u].mask | + logger_mask_data[logger_h].mask | + logger_mask_data[logger_rho].mask | + logger_mask_data[logger_consts].mask | + logger_mask_data[logger_special_flags].mask, + &xp->logger_data.last_offset, + /* special flags */ swift_type_stars); +#endif + /* Convert the gas particle to a star particle */ struct spart *sp = cell_convert_part_to_spart(e, c, p, xp); @@ -313,6 +342,22 @@ void runner_do_star_formation(struct runner *r, struct cell *c, int timer) { /* Update the Star formation history */ star_formation_logger_log_new_spart(sp, &c->stars.sfh); + +#ifdef WITH_LOGGER + /* Copy the properties back to the stellar particle */ + sp->logger_data = xp->logger_data; + + /* Write the s-particle */ + logger_log_spart(e->logger, sp, + logger_mask_data[logger_x].mask | + logger_mask_data[logger_v].mask | + logger_mask_data[logger_consts].mask, + &sp->logger_data.last_offset, + /* special flags */ 0); + + /* Set counter back to zero */ + sp->logger_data.steps_since_last_output = 0; +#endif } } @@ -381,6 +426,7 @@ void runner_do_end_hydro_force(struct runner *r, struct cell *c, int timer) { /* Finish the force loop */ hydro_end_force(p, cosmo); + timestep_limiter_end_force(p); chemistry_end_force(p, cosmo); #ifdef SWIFT_BOUNDARY_PARTICLES @@ -420,6 +466,8 @@ void runner_do_end_hydro_force(struct runner *r, struct cell *c, int timer) { void runner_do_end_grav_force(struct runner *r, struct cell *c, int timer) { const struct engine *e = r->e; + const int with_self_gravity = (e->policy & engine_policy_self_gravity); + const int with_black_holes = (e->policy & engine_policy_black_holes); TIMER_TIC; @@ -438,7 +486,7 @@ void runner_do_end_grav_force(struct runner *r, struct cell *c, int timer) { /* Potential normalisation in the case of periodic gravity */ float potential_normalisation = 0.; - if (periodic && (e->policy & engine_policy_self_gravity)) { + if (periodic && with_self_gravity) { const double volume = s->dim[0] * s->dim[1] * s->dim[2]; const double r_s = e->mesh->r_s; potential_normalisation = 4. * M_PI * e->total_mass * r_s * r_s / volume; @@ -522,6 +570,17 @@ void runner_do_end_grav_force(struct runner *r, struct cell *c, int timer) { } } #endif + + /* Deal with black holes' need of potentials */ + if (with_black_holes && gp->type == swift_type_black_hole) { + const size_t offset = -gp->id_or_neg_offset; + black_holes_store_potential_in_bpart(&s->bparts[offset], gp); + } + if (with_black_holes && gp->type == swift_type_gas) { + const size_t offset = -gp->id_or_neg_offset; + black_holes_store_potential_in_part( + &s->parts[offset].black_holes_data, gp); + } } } } @@ -543,10 +602,16 @@ void runner_do_logger(struct runner *r, struct cell *c, int timer) { const struct engine *e = r->e; 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; /* Anything to do here? */ - if (!cell_is_active_hydro(c, e) && !cell_is_active_gravity(c, e)) return; + if (!cell_is_active_hydro(c, e) && !cell_is_active_gravity(c, e) && + !cell_is_active_stars(c, e)) + return; /* Recurse? Avoid spending too much time in useless cells. */ if (c->split) { @@ -562,8 +627,6 @@ void runner_do_logger(struct runner *r, struct cell *c, int timer) { 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_active(p, e)) { if (logger_should_write(&xp->logger_data, e->logger)) { @@ -577,7 +640,8 @@ void runner_do_logger(struct runner *r, struct cell *c, int timer) { logger_mask_data[logger_h].mask | logger_mask_data[logger_rho].mask | logger_mask_data[logger_consts].mask, - &xp->logger_data.last_offset); + &xp->logger_data.last_offset, + /* special flags */ 0); /* Set counter back to zero */ xp->logger_data.steps_since_last_output = 0; @@ -586,11 +650,65 @@ void runner_do_logger(struct runner *r, struct cell *c, int timer) { xp->logger_data.steps_since_last_output += 1; } } - } - if (c->grav.count > 0) error("gparts not implemented"); + /* Loop over the gparts in this cell. */ + for (int k = 0; k < gcount; k++) { + + /* Get a handle on the part. */ + struct gpart *restrict gp = &gparts[k]; + + /* Write only the dark matter particles */ + if (gp->type != swift_type_dark_matter) continue; - if (c->stars.count > 0) error("sparts not implemented"); + /* If particle needs to be log */ + if (gpart_is_active(gp, e)) { + + if (logger_should_write(&gp->logger_data, e->logger)) { + /* Write particle */ + /* Currently writing everything, should adapt it through time */ + logger_log_gpart(e->logger, gp, + logger_mask_data[logger_x].mask | + logger_mask_data[logger_v].mask | + logger_mask_data[logger_a].mask | + logger_mask_data[logger_consts].mask, + &gp->logger_data.last_offset, + /* Special flags */ 0); + + /* Set counter back to zero */ + gp->logger_data.steps_since_last_output = 0; + } else + /* Update counter */ + gp->logger_data.steps_since_last_output += 1; + } + } + + /* Loop over the sparts in this cell. */ + for (int k = 0; k < scount; k++) { + + /* Get a handle on the part. */ + struct spart *restrict sp = &sparts[k]; + + /* If particle needs to be log */ + if (spart_is_active(sp, e)) { + + if (logger_should_write(&sp->logger_data, e->logger)) { + /* Write particle */ + /* Currently writing everything, should adapt it through time */ + logger_log_spart(e->logger, sp, + logger_mask_data[logger_x].mask | + logger_mask_data[logger_v].mask | + logger_mask_data[logger_consts].mask, + &sp->logger_data.last_offset, + /* Special flags */ 0); + + /* Set counter back to zero */ + sp->logger_data.steps_since_last_output = 0; + } else + /* Update counter */ + sp->logger_data.steps_since_last_output += 1; + } + } + } if (timer) TIMER_TOC(timer_logger); diff --git a/src/runner_recv.c b/src/runner_recv.c index 803e68c2106933684109e798e24952a0dbdfea6e..a00e3d2dc506d45bebaee4c1682ba7942efea768 100644 --- a/src/runner_recv.c +++ b/src/runner_recv.c @@ -96,7 +96,9 @@ void runner_do_recv_part(struct runner *r, struct cell *c, int clear_sorts, } #ifdef SWIFT_DEBUG_CHECKS - if (ti_hydro_end_min < ti_current) + if (!(r->e->policy & engine_policy_timestep_sync) && + !(r->e->policy & engine_policy_timestep_limiter) && + ti_hydro_end_min < ti_current) error( "Received a cell at an incorrect time c->ti_end_min=%lld, " "e->ti_current=%lld.", @@ -171,7 +173,9 @@ void runner_do_recv_gpart(struct runner *r, struct cell *c, int timer) { } #ifdef SWIFT_DEBUG_CHECKS - if (ti_gravity_end_min < ti_current) + if (!(r->e->policy & engine_policy_timestep_sync) && + !(r->e->policy & engine_policy_timestep_limiter) && + ti_gravity_end_min < ti_current) error( "Received a cell at an incorrect time c->ti_end_min=%lld, " "e->ti_current=%lld.", @@ -228,7 +232,7 @@ void runner_do_recv_spart(struct runner *r, struct cell *c, int clear_sorts, /* Collect everything... */ for (size_t k = 0; k < nr_sparts; k++) { #ifdef DEBUG_INTERACTIONS_STARS - sparts[k].num_ngb_force = 0; + sparts[k].num_ngb_feedback = 0; #endif if (sparts[k].time_bin == time_bin_inhibited) continue; time_bin_min = min(time_bin_min, sparts[k].time_bin); diff --git a/src/runner_sort.c b/src/runner_sort.c index 914b64f93b970000885b1b578d762d3f15455332..21626d2a6e1b1e208ff3889b7b09b454eea4bd96 100644 --- a/src/runner_sort.c +++ b/src/runner_sort.c @@ -29,6 +29,7 @@ #include "active.h" #include "cell.h" #include "engine.h" +#include "task_order.h" #include "timers.h" /** @@ -45,6 +46,8 @@ void runner_do_stars_resort(struct runner *r, struct cell *c, const int timer) { #ifdef SWIFT_DEBUG_CHECKS if (c->nodeID != r->e->nodeID) error("Task must be run locally!"); + if (!task_order_star_formation_before_feedback) + error("Resorting when not needed"); #endif TIMER_TIC; @@ -65,14 +68,21 @@ void runner_do_stars_resort(struct runner *r, struct cell *c, const int timer) { * @param N The number of entries. */ void runner_do_sort_ascending(struct sort_entry *sort, int N) { + const int stack_size = 10; struct { short int lo, hi; - } qstack[10]; + } qstack[stack_size]; int qpos, i, j, lo, hi, imin; struct sort_entry temp; float pivot; + if (N >= (1LL << stack_size)) { + error( + "The stack size for sorting is too small." + "Either increase it or reduce the number of parts per cell."); + } + /* Sort parts in cell_i in decreasing order with quicksort */ qstack[0].lo = 0; qstack[0].hi = N - 1; @@ -81,11 +91,18 @@ void runner_do_sort_ascending(struct sort_entry *sort, int N) { lo = qstack[qpos].lo; hi = qstack[qpos].hi; qpos -= 1; + /* Do we have a low number of element to sort? */ if (hi - lo < 15) { + /* Sort the last elements. */ for (i = lo; i < hi; i++) { imin = i; - for (j = i + 1; j <= hi; j++) - if (sort[j].d < sort[imin].d) imin = j; + /* Find the minimal value. */ + for (j = i + 1; j <= hi; j++) { + if (sort[j].d < sort[imin].d) { + imin = j; + } + } + /* Swap the elements if a smaller element exists. */ if (imin != i) { temp = sort[imin]; sort[imin] = sort[i]; @@ -93,14 +110,21 @@ void runner_do_sort_ascending(struct sort_entry *sort, int N) { } } } else { + /* Select a pivot */ pivot = sort[(lo + hi) / 2].d; i = lo; j = hi; + /* Ensure that the elements before/after the pivot + are smaller/larger than the pivot. */ while (i <= j) { + /* Find the first elements that do not respect + the order. */ while (sort[i].d < pivot) i++; while (sort[j].d > pivot) j--; + /* Did we get two different elements */ if (i <= j) { if (i < j) { + /* Swap the elements */ temp = sort[i]; sort[i] = sort[j]; sort[j] = temp; @@ -109,6 +133,9 @@ void runner_do_sort_ascending(struct sort_entry *sort, int N) { j -= 1; } } + /* Add the next operations to the stack. + * The order is important in order to decrease the stack size. + */ if (j > (lo + hi) / 2) { if (lo < j) { qpos += 1; diff --git a/src/runner_time_integration.c b/src/runner_time_integration.c index 7fd22424a8c5cb5a5d87d60c5a234feb892906a3..edb307442cfae0d3fc466706fc3c2f3ab024521f 100644 --- a/src/runner_time_integration.c +++ b/src/runner_time_integration.c @@ -30,10 +30,12 @@ #include "black_holes.h" #include "cell.h" #include "engine.h" +#include "feedback.h" #include "kick.h" #include "timers.h" #include "timestep.h" #include "timestep_limiter.h" +#include "timestep_sync.h" #include "tracers.h" /** @@ -120,13 +122,10 @@ void runner_do_kick1(struct runner *r, struct cell *c, int timer) { if (part_is_starting(p, e)) { #ifdef SWIFT_DEBUG_CHECKS - if (p->wakeup == time_bin_awake) + if (p->limiter_data.wakeup != time_bin_not_awake) error("Woken-up particle that has not been processed in kick1"); #endif - /* Skip particles that have been woken up and treated by the limiter. */ - if (p->wakeup != time_bin_not_awake) continue; - 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); @@ -138,7 +137,8 @@ void runner_do_kick1(struct runner *r, struct cell *c, int timer) { error( "Particle in wrong time-bin, ti_end=%lld, ti_begin=%lld, " "ti_step=%lld time_bin=%d wakeup=%d ti_current=%lld", - ti_end, ti_begin, ti_step, p->time_bin, p->wakeup, ti_current); + ti_end, ti_begin, ti_step, p->time_bin, p->limiter_data.wakeup, + ti_current); #endif /* Time interval for this half-kick */ @@ -195,7 +195,7 @@ void runner_do_kick1(struct runner *r, struct cell *c, int timer) { if (ti_begin != ti_current) error( - "Particle in wrong time-bin, ti_end=%lld, ti_begin=%lld, " + "G-particle in wrong time-bin, ti_end=%lld, ti_begin=%lld, " "ti_step=%lld time_bin=%d ti_current=%lld", ti_end, ti_begin, ti_step, gp->time_bin, ti_current); #endif @@ -233,7 +233,7 @@ void runner_do_kick1(struct runner *r, struct cell *c, int timer) { if (ti_begin != ti_current) error( - "Particle in wrong time-bin, ti_end=%lld, ti_begin=%lld, " + "S-particle in wrong time-bin, ti_end=%lld, ti_begin=%lld, " "ti_step=%lld time_bin=%d ti_current=%lld", ti_end, ti_begin, ti_step, sp->time_bin, ti_current); #endif @@ -271,7 +271,7 @@ void runner_do_kick1(struct runner *r, struct cell *c, int timer) { if (ti_begin != ti_current) error( - "Particle in wrong time-bin, ti_end=%lld, ti_begin=%lld, " + "B-particle in wrong time-bin, ti_end=%lld, ti_begin=%lld, " "ti_step=%lld time_bin=%d ti_current=%lld", ti_end, ti_begin, ti_step, bp->time_bin, ti_current); #endif @@ -348,34 +348,22 @@ void runner_do_kick2(struct runner *r, struct cell *c, int timer) { integertime_t ti_begin, ti_end, ti_step; #ifdef SWIFT_DEBUG_CHECKS - if (p->wakeup == time_bin_awake) + if (p->limiter_data.wakeup != time_bin_not_awake) error("Woken-up particle that has not been processed in kick1"); #endif - if (p->wakeup == time_bin_not_awake) { - - /* Time-step from a regular kick */ - ti_step = get_integer_timestep(p->time_bin); - ti_begin = get_integer_time_begin(ti_current, p->time_bin); - ti_end = ti_begin + ti_step; - - } else { - - /* Time-step that follows a wake-up call */ - ti_begin = get_integer_time_begin(ti_current, p->wakeup); - ti_end = get_integer_time_end(ti_current, p->time_bin); - ti_step = ti_end - ti_begin; - - /* Reset the flag. Everything is back to normal from now on. */ - p->wakeup = time_bin_awake; - } + /* Time-step length on the integer timeline */ + ti_step = get_integer_timestep(p->time_bin); + ti_begin = get_integer_time_begin(ti_current, p->time_bin); + ti_end = ti_begin + ti_step; #ifdef SWIFT_DEBUG_CHECKS if (ti_begin + ti_step != ti_current) error( "Particle in wrong time-bin, ti_begin=%lld, ti_step=%lld " "time_bin=%d wakeup=%d ti_current=%lld", - ti_begin, ti_step, p->time_bin, p->wakeup, ti_current); + ti_begin, ti_step, p->time_bin, p->limiter_data.wakeup, + ti_current); #endif /* Time interval for this half-kick */ double dt_kick_grav, dt_kick_hydro, dt_kick_therm, dt_kick_corr; @@ -554,6 +542,7 @@ 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 with_cosmology = (e->policy & engine_policy_cosmology); + const int with_feedback = (e->policy & engine_policy_feedback); const int count = c->hydro.count; const int gcount = c->grav.count; const int scount = c->stars.count; @@ -759,6 +748,11 @@ void runner_do_timestep(struct runner *r, struct cell *c, int timer) { sp->time_bin = get_time_bin(ti_new_step); sp->gpart->time_bin = get_time_bin(ti_new_step); + /* Update feedback related counters */ + if (with_feedback) + feedback_will_do_feedback(sp, e->feedback_props, with_cosmology, + e->cosmology, e->time); + /* Number of updated s-particles */ s_updated++; g_updated++; @@ -882,8 +876,8 @@ void runner_do_timestep(struct runner *r, struct cell *c, int timer) { ti_gravity_beg_max = max(cp->grav.ti_beg_max, ti_gravity_beg_max); ti_stars_end_min = min(cp->stars.ti_end_min, ti_stars_end_min); - ti_stars_end_max = max(cp->grav.ti_end_max, ti_stars_end_max); - ti_stars_beg_max = max(cp->grav.ti_beg_max, ti_stars_beg_max); + ti_stars_end_max = max(cp->stars.ti_end_max, ti_stars_end_max); + ti_stars_beg_max = max(cp->stars.ti_beg_max, ti_stars_beg_max); ti_black_holes_end_min = min(cp->black_holes.ti_end_min, ti_black_holes_end_min); @@ -944,7 +938,6 @@ void runner_do_timestep(struct runner *r, struct cell *c, int timer) { void runner_do_limiter(struct runner *r, struct cell *c, int force, int timer) { const struct engine *e = r->e; - const integertime_t ti_current = e->ti_current; const int count = c->hydro.count; struct part *restrict parts = c->hydro.parts; struct xpart *restrict xparts = c->hydro.xparts; @@ -1019,15 +1012,173 @@ void runner_do_limiter(struct runner *r, struct cell *c, int force, int timer) { /* Avoid inhibited particles */ if (part_is_inhibited(p, e)) continue; - /* If the particle will be active no need to wake it up */ - if (part_is_active(p, e) && p->wakeup != time_bin_not_awake) - p->wakeup = time_bin_not_awake; - /* Bip, bip, bip... wake-up time */ - if (p->wakeup <= time_bin_awake) { + if (p->limiter_data.wakeup != time_bin_not_awake) { + + // message("Limiting particle %lld in cell %d", p->id, c->cellID); + + /* Apply the limiter and get the new end of time-step */ + const integertime_t ti_end_new = timestep_limit_part(p, xp, e); + const timebin_t new_bin = p->time_bin; + const integertime_t ti_beg_new = + ti_end_new - get_integer_timestep(new_bin); + + /* Mark this particle has not needing synchronization */ + p->limiter_data.to_be_synchronized = 0; + + /* What is the next sync-point ? */ + ti_hydro_end_min = min(ti_end_new, ti_hydro_end_min); + ti_hydro_end_max = max(ti_end_new, ti_hydro_end_max); + + /* What is the next starting point for this cell ? */ + ti_hydro_beg_max = max(ti_beg_new, ti_hydro_beg_max); + + /* Also limit the gpart counter-part */ + if (p->gpart != NULL) { + + /* Register the time-bin */ + p->gpart->time_bin = p->time_bin; + + /* What is the next sync-point ? */ + ti_gravity_end_min = min(ti_end_new, ti_gravity_end_min); + ti_gravity_end_max = max(ti_end_new, ti_gravity_end_max); + + /* What is the next starting point for this cell ? */ + ti_gravity_beg_max = max(ti_beg_new, ti_gravity_beg_max); + } + } + } + + /* Store the updated values */ + c->hydro.ti_end_min = min(c->hydro.ti_end_min, ti_hydro_end_min); + c->hydro.ti_end_max = max(c->hydro.ti_end_max, ti_hydro_end_max); + c->hydro.ti_beg_max = max(c->hydro.ti_beg_max, ti_hydro_beg_max); + c->grav.ti_end_min = min(c->grav.ti_end_min, ti_gravity_end_min); + c->grav.ti_end_max = max(c->grav.ti_end_max, ti_gravity_end_max); + c->grav.ti_beg_max = max(c->grav.ti_beg_max, ti_gravity_beg_max); + } + + /* Clear the limiter flags. */ + cell_clear_flag(c, + cell_flag_do_hydro_limiter | cell_flag_do_hydro_sub_limiter); + + if (timer) TIMER_TOC(timer_do_limiter); +} + +/** + * @brief Apply the time-step synchronization proceduere to all flagged + * particles in a cell hierarchy. + * + * @param r The task #runner. + * @param c The #cell. + * @param force Limit the particles irrespective of the #cell flags. + * @param timer Are we timing this ? + */ +void runner_do_sync(struct runner *r, struct cell *c, int force, int timer) { + + const struct engine *e = r->e; + const integertime_t ti_current = e->ti_current; + const struct cosmology *cosmo = e->cosmology; + const int with_cosmology = (e->policy & engine_policy_cosmology); + const int count = c->hydro.count; + struct part *restrict parts = c->hydro.parts; + struct xpart *restrict xparts = c->hydro.xparts; + + TIMER_TIC; + +#ifdef SWIFT_DEBUG_CHECKS + /* Check that we only sync local cells. */ + if (c->nodeID != engine_rank) error("Syncing of a foreign cell is nope."); +#endif + + 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; + + /* Limit irrespective of cell flags? */ + force = (force || cell_get_flag(c, cell_flag_do_hydro_sync)); + + /* Early abort? */ + if (c->hydro.count == 0) { + + /* Clear the sync flags. */ + cell_clear_flag(c, cell_flag_do_hydro_sync | cell_flag_do_hydro_sub_sync); + return; + } + + /* Loop over the progeny ? */ + if (c->split && (force || cell_get_flag(c, cell_flag_do_hydro_sub_sync))) { + for (int k = 0; k < 8; k++) { + if (c->progeny[k] != NULL) { + struct cell *restrict cp = c->progeny[k]; + + /* Recurse */ + runner_do_sync(r, cp, force, 0); + + /* And aggregate */ + 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 updated values */ + c->hydro.ti_end_min = min(c->hydro.ti_end_min, ti_hydro_end_min); + c->hydro.ti_end_max = max(c->hydro.ti_end_max, ti_hydro_end_max); + c->hydro.ti_beg_max = max(c->hydro.ti_beg_max, ti_hydro_beg_max); + c->grav.ti_end_min = min(c->grav.ti_end_min, ti_gravity_end_min); + c->grav.ti_end_max = max(c->grav.ti_end_max, ti_gravity_end_max); + c->grav.ti_beg_max = max(c->grav.ti_beg_max, ti_gravity_beg_max); - /* Apply the limiter and get the new time-step size */ - const integertime_t ti_new_step = timestep_limit_part(p, xp, e); + } else if (!c->split && force) { + + ti_hydro_end_min = c->hydro.ti_end_min; + ti_hydro_end_max = c->hydro.ti_end_max; + ti_hydro_beg_max = c->hydro.ti_beg_max; + ti_gravity_end_min = c->grav.ti_end_min; + ti_gravity_end_max = c->grav.ti_end_max; + ti_gravity_beg_max = c->grav.ti_beg_max; + + /* 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]; + + /* Avoid inhibited particles */ + if (part_is_inhibited(p, e)) continue; + + /* If the particle is active no need to sync it */ + if (part_is_active(p, e) && p->limiter_data.to_be_synchronized) { + p->limiter_data.to_be_synchronized = 0; + } + + if (p->limiter_data.to_be_synchronized) { + + /* Finish this particle's time-step */ + timestep_process_sync_part(p, xp, e, cosmo); + + /* Get new time-step */ + integertime_t ti_new_step = get_part_timestep(p, xp, e); + timebin_t new_time_bin = get_time_bin(ti_new_step); + + /* Limit the time-bin to what is allowed in this step */ + new_time_bin = min(new_time_bin, e->max_active_bin); + ti_new_step = get_integer_timestep(new_time_bin); + + /* Update particle */ + p->time_bin = new_time_bin; + if (p->gpart != NULL) p->gpart->time_bin = new_time_bin; + + /* Update the tracers properties */ + tracers_after_timestep(p, xp, e->internal_units, e->physical_constants, + with_cosmology, e->cosmology, + e->hydro_properties, e->cooling_func, e->time); /* What is the next sync-point ? */ ti_hydro_end_min = min(ti_current + ti_new_step, ti_hydro_end_min); @@ -1063,9 +1214,8 @@ void runner_do_limiter(struct runner *r, struct cell *c, int force, int timer) { c->grav.ti_beg_max = max(c->grav.ti_beg_max, ti_gravity_beg_max); } - /* Clear the limiter flags. */ - cell_clear_flag(c, - cell_flag_do_hydro_limiter | cell_flag_do_hydro_sub_limiter); + /* Clear the sync flags. */ + cell_clear_flag(c, cell_flag_do_hydro_sync | cell_flag_do_hydro_sub_sync); - if (timer) TIMER_TOC(timer_do_limiter); + if (timer) TIMER_TOC(timer_do_sync); } diff --git a/src/scheduler.c b/src/scheduler.c index 2fe978cb34efb54b81a7bb781e692c741119d584..6d076d11461bc25f4d7c3ae90b66ec7df0085e7f 100644 --- a/src/scheduler.c +++ b/src/scheduler.c @@ -614,7 +614,7 @@ static void scheduler_splittask_hydro(struct task *t, struct scheduler *s) { /* Do we have a non-empty progenitor? */ if (ci->progeny[k] != NULL && (ci->progeny[k]->hydro.count || - (with_feedback && ci->progeny[k]->stars.count))) { + (with_stars && ci->progeny[k]->stars.count))) { scheduler_splittask_hydro( scheduler_addtask(s, task_type_self, t->subtype, 0, 0, ci->progeny[k], NULL), @@ -1133,11 +1133,11 @@ struct task *scheduler_addtask(struct scheduler *s, enum task_types type, */ void scheduler_set_unlocks(struct scheduler *s) { /* Store the counts for each task. */ - short int *counts; - if ((counts = (short int *)swift_malloc( - "counts", sizeof(short int) * s->nr_tasks)) == NULL) + int *counts; + if ((counts = (int *)swift_malloc("counts", sizeof(int) * s->nr_tasks)) == + NULL) error("Failed to allocate temporary counts array."); - bzero(counts, sizeof(short int) * s->nr_tasks); + bzero(counts, sizeof(int) * s->nr_tasks); for (int k = 0; k < s->nr_unlocks; k++) { counts[s->unlock_ind[k]] += 1; @@ -1151,7 +1151,7 @@ void scheduler_set_unlocks(struct scheduler *s) { "the difference in task depths.", taskID_names[s->tasks[s->unlock_ind[k]].type], subtaskID_names[s->tasks[s->unlock_ind[k]].subtype], - (1LL << (8 * sizeof(short int) - 1)) - 1); + (1LL << (8 * sizeof(int) - 1)) - 1); } /* Compute the offset for each unlock block. */ @@ -1741,7 +1741,8 @@ void scheduler_enqueue(struct scheduler *s, struct task *t) { } else if (t->subtype == task_subtype_xv || t->subtype == task_subtype_rho || - t->subtype == task_subtype_gradient) { + t->subtype == task_subtype_gradient || + t->subtype == task_subtype_limiter) { count = t->ci->hydro.count; size = count * sizeof(struct part); @@ -1857,7 +1858,8 @@ void scheduler_enqueue(struct scheduler *s, struct task *t) { } else if (t->subtype == task_subtype_xv || t->subtype == task_subtype_rho || - t->subtype == task_subtype_gradient) { + t->subtype == task_subtype_gradient || + t->subtype == task_subtype_limiter) { count = t->ci->hydro.count; size = count * sizeof(struct part); diff --git a/src/serial_io.c b/src/serial_io.c index 0035ba89efb73e0e6d585bbc4b1e180aae507530..d028d79dc2986e901befb6c5e50d5e8d30d92d34 100644 --- a/src/serial_io.c +++ b/src/serial_io.c @@ -45,6 +45,7 @@ #include "engine.h" #include "entropy_floor.h" #include "error.h" +#include "feedback.h" #include "fof_io.h" #include "gravity_io.h" #include "gravity_properties.h" @@ -648,7 +649,7 @@ 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(&N_total, swift_type_count, MPI_LONG_LONG_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); @@ -918,9 +919,13 @@ void write_output_serial(struct engine* e, const char* baseName, if (e->snapshot_int_time_label_on) snprintf(fileName, FILENAME_BUFFER_SIZE, "%s_%06i.hdf5", baseName, (int)round(e->time)); - else + else if (e->snapshot_invoke_stf) { + snprintf(fileName, FILENAME_BUFFER_SIZE, "%s_%04i.hdf5", baseName, + e->stf_output_count); + } else { snprintf(fileName, FILENAME_BUFFER_SIZE, "%s_%04i.hdf5", baseName, e->snapshot_output_count); + } /* Compute offset in the file and total number of particles */ size_t N[swift_type_count] = {Ngas_written, Ndm_written, @@ -928,12 +933,12 @@ void write_output_serial(struct engine* e, const char* baseName, Nstars_written, Nblackholes_written}; 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); + MPI_Exscan(N, offset, swift_type_count, MPI_LONG_LONG_INT, MPI_SUM, comm); for (int ptype = 0; ptype < swift_type_count; ++ptype) N_total[ptype] = offset[ptype] + N[ptype]; /* The last rank now has the correct N_total. Let's broadcast from there */ - MPI_Bcast(&N_total, 6, MPI_LONG_LONG_INT, mpi_size - 1, comm); + MPI_Bcast(N_total, 6, MPI_LONG_LONG_INT, mpi_size - 1, comm); /* Now everybody konws its offset and the total number of particles of each * type */ @@ -1031,6 +1036,7 @@ void write_output_serial(struct engine* e, const char* baseName, cooling_write_flavour(h_grp, e->cooling_func); chemistry_write_flavour(h_grp); tracers_write_flavour(h_grp); + feedback_write_flavour(e->feedback_props, h_grp); H5Gclose(h_grp); /* Print the gravity parameters */ @@ -1153,9 +1159,9 @@ void write_output_serial(struct engine* e, const char* baseName, } /* Write the location of the particles in the arrays */ - io_write_cell_offsets(h_grp_cells, e->s->cdim, e->s->cells_top, - e->s->nr_cells, e->s->width, mpi_rank, N_total, offset, - internal_units, snapshot_units); + io_write_cell_offsets(h_grp_cells, e->s->cdim, e->s->dim, e->s->pos_dithering, + e->s->cells_top, e->s->nr_cells, e->s->width, mpi_rank, + N_total, offset, internal_units, snapshot_units); /* Close everything */ if (mpi_rank == 0) { @@ -1516,6 +1522,7 @@ void write_output_serial(struct engine* e, const char* baseName, /* message("Done writing particles..."); */ e->snapshot_output_count++; + if (e->snapshot_invoke_stf) e->stf_output_count++; } #endif /* HAVE_HDF5 && HAVE_MPI */ diff --git a/src/single_io.c b/src/single_io.c index ad2560db96f7bf2b4c60141bf9ff945b2bb745b0..2a8a589757cd45f79356e330355145085a6716cf 100644 --- a/src/single_io.c +++ b/src/single_io.c @@ -44,6 +44,7 @@ #include "engine.h" #include "entropy_floor.h" #include "error.h" +#include "feedback.h" #include "fof_io.h" #include "gravity_io.h" #include "gravity_properties.h" @@ -782,7 +783,10 @@ void write_output_single(struct engine* e, const char* baseName, if (e->snapshot_int_time_label_on) snprintf(fileName, FILENAME_BUFFER_SIZE, "%s_%06i.hdf5", baseName, (int)round(e->time)); - else + else if (e->snapshot_invoke_stf) { + snprintf(fileName, FILENAME_BUFFER_SIZE, "%s_%04i.hdf5", baseName, + e->stf_output_count); + } else snprintf(fileName, FILENAME_BUFFER_SIZE, "%s_%04i.hdf5", baseName, e->snapshot_output_count); @@ -877,6 +881,7 @@ void write_output_single(struct engine* e, const char* baseName, cooling_write_flavour(h_grp, e->cooling_func); chemistry_write_flavour(h_grp); tracers_write_flavour(h_grp); + feedback_write_flavour(e->feedback_props, h_grp); H5Gclose(h_grp); /* Print the gravity parameters */ @@ -934,9 +939,10 @@ void write_output_single(struct engine* e, const char* baseName, if (h_grp < 0) error("Error while creating cells group"); /* Write the location of the particles in the arrays */ - io_write_cell_offsets(h_grp, e->s->cdim, e->s->cells_top, e->s->nr_cells, - e->s->width, e->nodeID, N_total, global_offsets, - internal_units, snapshot_units); + io_write_cell_offsets(h_grp, e->s->cdim, e->s->dim, e->s->pos_dithering, + e->s->cells_top, e->s->nr_cells, e->s->width, e->nodeID, + N_total, global_offsets, internal_units, + snapshot_units); H5Gclose(h_grp); /* Tell the user if a conversion will be needed */ @@ -1293,6 +1299,7 @@ void write_output_single(struct engine* e, const char* baseName, H5Fclose(h_file); e->snapshot_output_count++; + if (e->snapshot_invoke_stf) e->stf_output_count++; } #endif /* HAVE_HDF5 && !WITH_MPI */ diff --git a/src/space.c b/src/space.c index 8ff331883b9366ea25405854ce74860f7f7b5bf7..3fffafc4b7cd27827d6a24e116676581c8ae9413 100644 --- a/src/space.c +++ b/src/space.c @@ -111,20 +111,6 @@ struct qstack { volatile int ready; }; -/** - * @brief Parallel particle-sorting stack - */ -struct parallel_sort { - struct part *parts; - struct gpart *gparts; - struct xpart *xparts; - struct spart *sparts; - int *ind; - struct qstack *stack; - unsigned int stack_size; - volatile unsigned int first, last, waiting; -}; - /** * @brief Information required to compute the particle cell indices. */ @@ -252,6 +238,7 @@ void space_rebuild_recycle_mapper(void *map_data, int num_elements, c->kick2 = NULL; c->timestep = NULL; c->timestep_limiter = NULL; + c->timestep_sync = NULL; c->hydro.end_force = NULL; c->hydro.drift = NULL; c->stars.drift = NULL; @@ -714,7 +701,7 @@ void space_allocate_extras(struct space *s, int verbose) { /* Anything to do here? (Abort if we don't want extras)*/ if (space_extra_parts == 0 && space_extra_gparts == 0 && - space_extra_sparts == 0) + space_extra_sparts == 0 && space_extra_bparts == 0) return; /* The top-level cells */ @@ -746,7 +733,7 @@ void space_allocate_extras(struct space *s, int verbose) { error("Failed to allocate list of local top-level cells"); /* List the local cells */ - int nr_local_cells = 0; + size_t nr_local_cells = 0; for (int i = 0; i < s->nr_cells; ++i) { if (s->cells_top[i].nodeID == local_nodeID) { local_cells[nr_local_cells] = i; @@ -778,6 +765,8 @@ void space_allocate_extras(struct space *s, int verbose) { error("Reduction in top-level cells number not handled."); if (expected_num_extra_sparts < s->nr_extra_sparts) error("Reduction in top-level cells number not handled."); + if (expected_num_extra_bparts < s->nr_extra_bparts) + error("Reduction in top-level cells number not handled."); /* Do we have enough space for the extra gparts (i.e. we haven't used up any) * ? */ @@ -829,7 +818,7 @@ void space_allocate_extras(struct space *s, int verbose) { } /* Put the spare particles in their correct cell */ - int local_cell_id = 0; + size_t local_cell_id = 0; int current_cell = local_cells[local_cell_id]; int count_in_cell = 0; size_t count_extra_gparts = 0; @@ -875,7 +864,7 @@ void space_allocate_extras(struct space *s, int verbose) { /* Do we have enough space for the extra parts (i.e. we haven't used up any) ? */ - if (expected_num_extra_parts > s->nr_extra_parts) { + if (nr_actual_parts + expected_num_extra_parts > nr_parts) { /* Ok... need to put some more in the game */ @@ -917,11 +906,11 @@ void space_allocate_extras(struct space *s, int verbose) { bzero(&s->parts[i], sizeof(struct part)); bzero(&s->xparts[i], sizeof(struct xpart)); s->parts[i].time_bin = time_bin_not_created; - s->parts[i].id = -1; + s->parts[i].id = -42; } /* Put the spare particles in their correct cell */ - int local_cell_id = 0; + size_t local_cell_id = 0; int current_cell = local_cells[local_cell_id]; int count_in_cell = 0; size_t count_extra_parts = 0; @@ -1003,7 +992,7 @@ void space_allocate_extras(struct space *s, int verbose) { } /* Put the spare particles in their correct cell */ - int local_cell_id = 0; + size_t local_cell_id = 0; int current_cell = local_cells[local_cell_id]; int count_in_cell = 0; size_t count_extra_sparts = 0; @@ -1085,7 +1074,7 @@ void space_allocate_extras(struct space *s, int verbose) { } /* Put the spare particles in their correct cell */ - int local_cell_id = 0; + size_t local_cell_id = 0; int current_cell = local_cells[local_cell_id]; int count_in_cell = 0; size_t count_extra_bparts = 0; @@ -1141,6 +1130,44 @@ void space_allocate_extras(struct space *s, int verbose) { free(local_cells); } +/** + * @brief Compute a new dithering vector to apply to all the particles + * in the simulation. + * + * @param s The #space. + * @param verbose Are we talkative? + */ +void space_dither(struct space *s, int verbose) { + + /* Store the old dithering vector */ + s->pos_dithering_old[0] = s->pos_dithering[0]; + s->pos_dithering_old[1] = s->pos_dithering[1]; + s->pos_dithering_old[2] = s->pos_dithering[2]; + + if (s->e->nodeID == 0) { + + const double dithering_ratio = s->e->gravity_properties->dithering_ratio; + + /* Compute the new dithering vector */ + const double rand_x = rand() / ((double)RAND_MAX); + const double rand_y = rand() / ((double)RAND_MAX); + const double rand_z = rand() / ((double)RAND_MAX); + + s->pos_dithering[0] = dithering_ratio * s->width[0] * rand_x; + s->pos_dithering[1] = dithering_ratio * s->width[1] * rand_y; + s->pos_dithering[2] = dithering_ratio * s->width[2] * rand_z; + } + +#ifdef WITH_MPI + /* Tell everyone what value to use */ + MPI_Bcast(s->pos_dithering, 3, MPI_DOUBLE, 0, MPI_COMM_WORLD); +#endif + + if (verbose) + message("Dithering the particle positions by [%e %e %e]", + s->pos_dithering[0], s->pos_dithering[1], s->pos_dithering[2]); +} + /** * @brief Re-build the cells as well as the tasks. * @@ -1164,6 +1191,10 @@ void space_rebuild(struct space *s, int repartitioned, int verbose) { /* Re-grid if necessary, or just re-set the cell data. */ space_regrid(s, verbose); + /* Are we dithering the particles? */ + const int with_dithering = s->e->gravity_properties->with_dithering; + if (s->with_self_gravity && with_dithering) space_dither(s, verbose); + /* Allocate extra space for particles that will be created */ if (s->with_star_formation) space_allocate_extras(s, verbose); @@ -1280,14 +1311,15 @@ void space_rebuild(struct space *s, int repartitioned, int verbose) { #endif /* Move non-local parts and inhibited parts to the end of the list. */ - if (!repartitioned && (s->e->nr_nodes > 1 || count_inhibited_parts > 0)) { + if ((with_dithering || !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 (h_index[k] == -1 || cells_top[h_index[k]].nodeID != local_nodeID) { /* One fewer particle */ - nr_parts -= 1; /* Swap the particle */ @@ -1332,7 +1364,9 @@ void space_rebuild(struct space *s, int repartitioned, int verbose) { #endif /* SWIFT_DEBUG_CHECKS */ /* Move non-local sparts and inhibited sparts to the end of the list. */ - if (!repartitioned && (s->e->nr_nodes > 1 || count_inhibited_sparts > 0)) { + if ((with_dithering || !repartitioned) && + (s->e->nr_nodes > 1 || count_inhibited_sparts > 0)) { + for (size_t k = 0; k < nr_sparts; /* void */) { /* Inhibited particle or foreign particle */ @@ -1381,7 +1415,9 @@ void space_rebuild(struct space *s, int repartitioned, int verbose) { #endif /* SWIFT_DEBUG_CHECKS */ /* Move non-local bparts and inhibited bparts to the end of the list. */ - if (!repartitioned && (s->e->nr_nodes > 1 || count_inhibited_bparts > 0)) { + if ((with_dithering || !repartitioned) && + (s->e->nr_nodes > 1 || count_inhibited_bparts > 0)) { + for (size_t k = 0; k < nr_bparts; /* void */) { /* Inhibited particle or foreign particle */ @@ -1430,7 +1466,9 @@ void space_rebuild(struct space *s, int repartitioned, int verbose) { #endif /* SWIFT_DEBUG_CHECKS */ /* Move non-local gparts and inhibited parts to the end of the list. */ - if (!repartitioned && (s->e->nr_nodes > 1 || count_inhibited_gparts > 0)) { + if ((with_dithering || !repartitioned) && + (s->e->nr_nodes > 1 || count_inhibited_gparts > 0)) { + for (size_t k = 0; k < nr_gparts; /* void */) { /* Inhibited particle or foreign particle */ @@ -1494,7 +1532,7 @@ void space_rebuild(struct space *s, int repartitioned, int verbose) { /* Exchange the strays, note that this potentially re-allocates the parts arrays. This can be skipped if we just repartitioned space as there should be no strays in that case */ - if (!repartitioned) { + if (with_dithering || !repartitioned) { size_t nr_parts_exchanged = s->nr_parts - nr_parts; size_t nr_gparts_exchanged = s->nr_gparts - nr_gparts; @@ -2029,6 +2067,10 @@ void space_reorder_extras(struct space *s, int verbose) { if (space_extra_sparts) threadpool_map(&s->e->threadpool, space_reorder_extra_sparts_mapper, s->local_cells_top, s->nr_local_cells, sizeof(int), 0, s); + + /* Re-order the black hole particles */ + if (space_extra_bparts) + error("Missing implementation of BH extra reordering"); } /** @@ -2078,6 +2120,14 @@ void space_parts_get_cell_index_mapper(void *map_data, int nr_parts, int *const ind = data->ind + (ptrdiff_t)(parts - s->parts); /* Get some constants */ + const int periodic = s->periodic; + const int dithering = s->e->gravity_properties->with_dithering; + const double delta_dithering_x = + s->pos_dithering[0] - s->pos_dithering_old[0]; + const double delta_dithering_y = + s->pos_dithering[1] - s->pos_dithering_old[1]; + const double delta_dithering_z = + s->pos_dithering[2] - s->pos_dithering_old[2]; const double dim_x = s->dim[0]; const double dim_y = s->dim[1]; const double dim_z = s->dim[2]; @@ -2103,12 +2153,18 @@ void space_parts_get_cell_index_mapper(void *map_data, int nr_parts, /* Get the particle */ struct part *restrict p = &parts[k]; - const double old_pos_x = p->x[0]; - const double old_pos_y = p->x[1]; - const double old_pos_z = p->x[2]; + double old_pos_x = p->x[0]; + double old_pos_y = p->x[1]; + double old_pos_z = p->x[2]; + + if (periodic && dithering && p->time_bin != time_bin_not_created) { + old_pos_x += delta_dithering_x; + old_pos_y += delta_dithering_y; + old_pos_z += delta_dithering_z; + } #ifdef SWIFT_DEBUG_CHECKS - if (!s->periodic && p->time_bin != time_bin_inhibited) { + if (!periodic && p->time_bin != time_bin_inhibited) { if (old_pos_x < 0. || old_pos_x > dim_x) error("Particle outside of volume along X."); if (old_pos_y < 0. || old_pos_y > dim_y) @@ -2147,6 +2203,7 @@ void space_parts_get_cell_index_mapper(void *map_data, int nr_parts, ind[k] = index; cell_counts[index]++; ++count_extra_part; + } else { /* Normal case: list its top-level cell index */ ind[k] = index; @@ -2197,6 +2254,14 @@ void space_gparts_get_cell_index_mapper(void *map_data, int nr_gparts, int *const ind = data->ind + (ptrdiff_t)(gparts - s->gparts); /* Get some constants */ + const int periodic = s->periodic; + const int dithering = s->e->gravity_properties->with_dithering; + const double delta_dithering_x = + s->pos_dithering[0] - s->pos_dithering_old[0]; + const double delta_dithering_y = + s->pos_dithering[1] - s->pos_dithering_old[1]; + const double delta_dithering_z = + s->pos_dithering[2] - s->pos_dithering_old[2]; const double dim_x = s->dim[0]; const double dim_y = s->dim[1]; const double dim_z = s->dim[2]; @@ -2221,12 +2286,18 @@ void space_gparts_get_cell_index_mapper(void *map_data, int nr_gparts, /* Get the particle */ struct gpart *restrict gp = &gparts[k]; - const double old_pos_x = gp->x[0]; - const double old_pos_y = gp->x[1]; - const double old_pos_z = gp->x[2]; + double old_pos_x = gp->x[0]; + double old_pos_y = gp->x[1]; + double old_pos_z = gp->x[2]; + + if (periodic && dithering && gp->time_bin != time_bin_not_created) { + old_pos_x += delta_dithering_x; + old_pos_y += delta_dithering_y; + old_pos_z += delta_dithering_z; + } #ifdef SWIFT_DEBUG_CHECKS - if (!s->periodic && gp->time_bin != time_bin_inhibited) { + if (!periodic && gp->time_bin != time_bin_inhibited) { if (old_pos_x < 0. || old_pos_x > dim_x) error("Particle outside of volume along X."); if (old_pos_y < 0. || old_pos_y > dim_y) @@ -2265,6 +2336,7 @@ void space_gparts_get_cell_index_mapper(void *map_data, int nr_gparts, ind[k] = index; cell_counts[index]++; ++count_extra_gpart; + } else { /* List its top-level cell index */ ind[k] = index; @@ -2321,6 +2393,14 @@ void space_sparts_get_cell_index_mapper(void *map_data, int nr_sparts, int *const ind = data->ind + (ptrdiff_t)(sparts - s->sparts); /* Get some constants */ + const int periodic = s->periodic; + const int dithering = s->e->gravity_properties->with_dithering; + const double delta_dithering_x = + s->pos_dithering[0] - s->pos_dithering_old[0]; + const double delta_dithering_y = + s->pos_dithering[1] - s->pos_dithering_old[1]; + const double delta_dithering_z = + s->pos_dithering[2] - s->pos_dithering_old[2]; const double dim_x = s->dim[0]; const double dim_y = s->dim[1]; const double dim_z = s->dim[2]; @@ -2345,12 +2425,18 @@ void space_sparts_get_cell_index_mapper(void *map_data, int nr_sparts, /* Get the particle */ struct spart *restrict sp = &sparts[k]; - const double old_pos_x = sp->x[0]; - const double old_pos_y = sp->x[1]; - const double old_pos_z = sp->x[2]; + double old_pos_x = sp->x[0]; + double old_pos_y = sp->x[1]; + double old_pos_z = sp->x[2]; + + if (periodic && dithering && sp->time_bin != time_bin_not_created) { + old_pos_x += delta_dithering_x; + old_pos_y += delta_dithering_y; + old_pos_z += delta_dithering_z; + } #ifdef SWIFT_DEBUG_CHECKS - if (!s->periodic && sp->time_bin != time_bin_inhibited) { + if (!periodic && sp->time_bin != time_bin_inhibited) { if (old_pos_x < 0. || old_pos_x > dim_x) error("Particle outside of volume along X."); if (old_pos_y < 0. || old_pos_y > dim_y) @@ -2389,6 +2475,7 @@ void space_sparts_get_cell_index_mapper(void *map_data, int nr_sparts, ind[k] = index; cell_counts[index]++; ++count_extra_spart; + } else { /* List its top-level cell index */ ind[k] = index; @@ -2441,6 +2528,14 @@ void space_bparts_get_cell_index_mapper(void *map_data, int nr_bparts, int *const ind = data->ind + (ptrdiff_t)(bparts - s->bparts); /* Get some constants */ + const int periodic = s->periodic; + const int dithering = s->e->gravity_properties->with_dithering; + const double delta_dithering_x = + s->pos_dithering[0] - s->pos_dithering_old[0]; + const double delta_dithering_y = + s->pos_dithering[1] - s->pos_dithering_old[1]; + const double delta_dithering_z = + s->pos_dithering[2] - s->pos_dithering_old[2]; const double dim_x = s->dim[0]; const double dim_y = s->dim[1]; const double dim_z = s->dim[2]; @@ -2465,12 +2560,18 @@ void space_bparts_get_cell_index_mapper(void *map_data, int nr_bparts, /* Get the particle */ struct bpart *restrict bp = &bparts[k]; - const double old_pos_x = bp->x[0]; - const double old_pos_y = bp->x[1]; - const double old_pos_z = bp->x[2]; + double old_pos_x = bp->x[0]; + double old_pos_y = bp->x[1]; + double old_pos_z = bp->x[2]; + + if (periodic && dithering && bp->time_bin != time_bin_not_created) { + old_pos_x += delta_dithering_x; + old_pos_y += delta_dithering_y; + old_pos_z += delta_dithering_z; + } #ifdef SWIFT_DEBUG_CHECKS - if (!s->periodic) { + if (!periodic && bp->time_bin != time_bin_inhibited) { if (old_pos_x < 0. || old_pos_x > dim_x) error("Particle outside of volume along X."); if (old_pos_y < 0. || old_pos_y > dim_y) @@ -2509,6 +2610,7 @@ void space_bparts_get_cell_index_mapper(void *map_data, int nr_bparts, ind[k] = index; cell_counts[index]++; ++count_extra_bpart; + } else { /* List its top-level cell index */ ind[k] = index; @@ -3320,6 +3422,7 @@ void space_split_recursive(struct space *s, struct cell *c, cp->hydro.super = NULL; cp->grav.super = NULL; cp->flags = 0; + star_formation_logger_init(&cp->stars.sfh); #ifdef WITH_MPI cp->mpi.tag = -1; #endif // WITH_MPI @@ -3364,6 +3467,7 @@ void space_split_recursive(struct space *s, struct cell *c, h_max = max(h_max, cp->hydro.h_max); stars_h_max = max(stars_h_max, cp->stars.h_max); black_holes_h_max = max(black_holes_h_max, cp->black_holes.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); @@ -3371,14 +3475,15 @@ void space_split_recursive(struct space *s, struct cell *c, 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); ti_stars_end_min = min(ti_stars_end_min, cp->stars.ti_end_min); - ti_stars_end_max = min(ti_stars_end_max, cp->stars.ti_end_max); - ti_stars_beg_max = min(ti_stars_beg_max, cp->stars.ti_beg_max); + ti_stars_end_max = max(ti_stars_end_max, cp->stars.ti_end_max); + ti_stars_beg_max = max(ti_stars_beg_max, cp->stars.ti_beg_max); ti_black_holes_end_min = min(ti_black_holes_end_min, cp->black_holes.ti_end_min); ti_black_holes_end_max = - min(ti_black_holes_end_max, cp->black_holes.ti_end_max); + max(ti_black_holes_end_max, cp->black_holes.ti_end_max); ti_black_holes_beg_max = - min(ti_black_holes_beg_max, cp->black_holes.ti_beg_max); + max(ti_black_holes_beg_max, cp->black_holes.ti_beg_max); + star_formation_logger_add(&c->stars.sfh, &cp->stars.sfh); /* Increase the depth */ @@ -3504,11 +3609,21 @@ void space_split_recursive(struct space *s, struct cell *c, c->split = 0; maxdepth = c->depth; - timebin_t hydro_time_bin_min = num_time_bins, hydro_time_bin_max = 0; - timebin_t gravity_time_bin_min = num_time_bins, gravity_time_bin_max = 0; - timebin_t stars_time_bin_min = num_time_bins, stars_time_bin_max = 0; - timebin_t black_holes_time_bin_min = num_time_bins, - black_holes_time_bin_max = 0; + ti_hydro_end_min = max_nr_timesteps; + ti_hydro_end_max = 0; + ti_hydro_beg_max = 0; + + ti_gravity_end_min = max_nr_timesteps; + ti_gravity_end_max = 0; + ti_gravity_beg_max = 0; + + ti_stars_end_min = max_nr_timesteps; + ti_stars_end_max = 0; + ti_stars_beg_max = 0; + + ti_black_holes_end_min = max_nr_timesteps; + ti_black_holes_end_max = 0; + ti_black_holes_beg_max = 0; /* parts: Get dt_min/dt_max and h_max. */ for (int k = 0; k < count; k++) { @@ -3518,9 +3633,18 @@ void space_split_recursive(struct space *s, struct cell *c, if (parts[k].time_bin == time_bin_inhibited) error("Inhibited particle present in space_split()"); #endif - hydro_time_bin_min = min(hydro_time_bin_min, parts[k].time_bin); - hydro_time_bin_max = max(hydro_time_bin_max, parts[k].time_bin); + + /* When does this particle's time-step start and end? */ + const timebin_t time_bin = parts[k].time_bin; + const integertime_t ti_end = get_integer_time_end(ti_current, time_bin); + const integertime_t ti_beg = get_integer_time_begin(ti_current, time_bin); + + ti_hydro_end_min = min(ti_hydro_end_min, ti_end); + ti_hydro_end_max = max(ti_hydro_end_max, ti_end); + ti_hydro_beg_max = max(ti_hydro_beg_max, ti_beg); + h_max = max(h_max, parts[k].h); + /* Collect SFR from the particles after rebuilt */ star_formation_logger_log_inactive_part(&parts[k], &xparts[k], &c->stars.sfh); @@ -3541,8 +3665,15 @@ void space_split_recursive(struct space *s, struct cell *c, if (gparts[k].time_bin == time_bin_inhibited) error("Inhibited g-particle present in space_split()"); #endif - gravity_time_bin_min = min(gravity_time_bin_min, gparts[k].time_bin); - gravity_time_bin_max = max(gravity_time_bin_max, gparts[k].time_bin); + + /* When does this particle's time-step start and end? */ + const timebin_t time_bin = gparts[k].time_bin; + const integertime_t ti_end = get_integer_time_end(ti_current, time_bin); + const integertime_t ti_beg = get_integer_time_begin(ti_current, time_bin); + + ti_gravity_end_min = min(ti_gravity_end_min, ti_end); + ti_gravity_end_max = max(ti_gravity_end_max, ti_end); + ti_gravity_beg_max = max(ti_gravity_beg_max, ti_beg); } /* sparts: Get dt_min/dt_max */ @@ -3553,8 +3684,16 @@ void space_split_recursive(struct space *s, struct cell *c, if (sparts[k].time_bin == time_bin_inhibited) error("Inhibited s-particle present in space_split()"); #endif - stars_time_bin_min = min(stars_time_bin_min, sparts[k].time_bin); - stars_time_bin_max = max(stars_time_bin_max, sparts[k].time_bin); + + /* When does this particle's time-step start and end? */ + const timebin_t time_bin = sparts[k].time_bin; + const integertime_t ti_end = get_integer_time_end(ti_current, time_bin); + const integertime_t ti_beg = get_integer_time_begin(ti_current, time_bin); + + ti_stars_end_min = min(ti_stars_end_min, ti_end); + ti_stars_end_max = max(ti_stars_end_max, ti_end); + ti_stars_beg_max = max(ti_stars_beg_max, ti_beg); + stars_h_max = max(stars_h_max, sparts[k].h); /* Reset x_diff */ @@ -3567,14 +3706,20 @@ void space_split_recursive(struct space *s, struct cell *c, for (int k = 0; k < bcount; k++) { #ifdef SWIFT_DEBUG_CHECKS if (bparts[k].time_bin == time_bin_not_created) - error("Extra s-particle present in space_split()"); + error("Extra b-particle present in space_split()"); if (bparts[k].time_bin == time_bin_inhibited) - error("Inhibited s-particle present in space_split()"); + error("Inhibited b-particle present in space_split()"); #endif - black_holes_time_bin_min = - min(black_holes_time_bin_min, bparts[k].time_bin); - black_holes_time_bin_max = - max(black_holes_time_bin_max, bparts[k].time_bin); + + /* When does this particle's time-step start and end? */ + const timebin_t time_bin = bparts[k].time_bin; + const integertime_t ti_end = get_integer_time_end(ti_current, time_bin); + const integertime_t ti_beg = get_integer_time_begin(ti_current, time_bin); + + ti_black_holes_end_min = min(ti_black_holes_end_min, ti_end); + ti_black_holes_end_max = max(ti_black_holes_end_max, ti_end); + ti_black_holes_beg_max = max(ti_black_holes_beg_max, ti_beg); + black_holes_h_max = max(black_holes_h_max, bparts[k].h); /* Reset x_diff */ @@ -3583,26 +3728,6 @@ void space_split_recursive(struct space *s, struct cell *c, bparts[k].x_diff[2] = 0.f; } - /* Convert into integer times */ - ti_hydro_end_min = get_integer_time_end(ti_current, hydro_time_bin_min); - ti_hydro_end_max = get_integer_time_end(ti_current, hydro_time_bin_max); - ti_hydro_beg_max = - get_integer_time_begin(ti_current + 1, hydro_time_bin_max); - ti_gravity_end_min = get_integer_time_end(ti_current, gravity_time_bin_min); - ti_gravity_end_max = get_integer_time_end(ti_current, gravity_time_bin_max); - ti_gravity_beg_max = - get_integer_time_begin(ti_current + 1, gravity_time_bin_max); - ti_stars_end_min = get_integer_time_end(ti_current, stars_time_bin_min); - ti_stars_end_max = get_integer_time_end(ti_current, stars_time_bin_max); - ti_stars_beg_max = - get_integer_time_begin(ti_current + 1, stars_time_bin_max); - ti_black_holes_end_min = - get_integer_time_end(ti_current, black_holes_time_bin_min); - ti_black_holes_end_max = - get_integer_time_end(ti_current, black_holes_time_bin_max); - ti_black_holes_beg_max = - get_integer_time_begin(ti_current + 1, black_holes_time_bin_max); - /* Construct the multipole and the centre of mass*/ if (s->with_self_gravity) { if (gcount > 0) { @@ -3936,82 +4061,138 @@ void space_list_useful_top_level_cells(struct space *s) { clocks_getunit()); } -void space_synchronize_particle_positions_mapper(void *map_data, int nr_gparts, - void *extra_data) { +void space_synchronize_part_positions_mapper(void *map_data, int nr_parts, + void *extra_data) { /* Unpack the data */ - struct gpart *restrict gparts = (struct gpart *)map_data; + const struct part *parts = (struct part *)map_data; struct space *s = (struct space *)extra_data; + const ptrdiff_t offset = parts - s->parts; + const struct xpart *xparts = s->xparts + offset; - for (int k = 0; k < nr_gparts; k++) { + for (int k = 0; k < nr_parts; k++) { /* Get the particle */ - struct gpart *restrict gp = &gparts[k]; + const struct part *p = &parts[k]; + const struct xpart *xp = &xparts[k]; - if (gp->type == swift_type_dark_matter) + /* Skip unimportant particles */ + if (p->time_bin == time_bin_not_created || + p->time_bin == time_bin_inhibited) continue; - else if (gp->type == swift_type_dark_matter_background) + /* Get its gravity friend */ + struct gpart *gp = p->gpart; + +#ifdef SWIFT_DEBUG_CHECKS + if (gp == NULL) error("Unlinked particle!"); +#endif + + /* Synchronize positions, velocities and masses */ + gp->x[0] = p->x[0]; + gp->x[1] = p->x[1]; + gp->x[2] = p->x[2]; + + gp->v_full[0] = xp->v_full[0]; + gp->v_full[1] = xp->v_full[1]; + gp->v_full[2] = xp->v_full[2]; + + gp->mass = hydro_get_mass(p); + } +} + +void space_synchronize_spart_positions_mapper(void *map_data, int nr_sparts, + void *extra_data) { + /* Unpack the data */ + const struct spart *sparts = (struct spart *)map_data; + + for (int k = 0; k < nr_sparts; k++) { + + /* Get the particle */ + const struct spart *sp = &sparts[k]; + + /* Skip unimportant particles */ + if (sp->time_bin == time_bin_not_created || + sp->time_bin == time_bin_inhibited) continue; - else if (gp->type == swift_type_gas) { + /* Get its gravity friend */ + struct gpart *gp = sp->gpart; - /* Get its gassy friend */ - struct part *p = &s->parts[-gp->id_or_neg_offset]; - struct xpart *xp = &s->xparts[-gp->id_or_neg_offset]; +#ifdef SWIFT_DEBUG_CHECKS + if (gp == NULL) error("Unlinked particle!"); +#endif - /* Synchronize positions and velocities */ - p->x[0] = gp->x[0]; - p->x[1] = gp->x[1]; - p->x[2] = gp->x[2]; + /* Synchronize positions, velocities and masses */ + gp->x[0] = sp->x[0]; + gp->x[1] = sp->x[1]; + gp->x[2] = sp->x[2]; - xp->v_full[0] = gp->v_full[0]; - xp->v_full[1] = gp->v_full[1]; - xp->v_full[2] = gp->v_full[2]; + gp->v_full[0] = sp->v[0]; + gp->v_full[1] = sp->v[1]; + gp->v_full[2] = sp->v[2]; - gp->mass = hydro_get_mass(p); - } + gp->mass = sp->mass; + } +} - else if (gp->type == swift_type_stars) { +void space_synchronize_bpart_positions_mapper(void *map_data, int nr_bparts, + void *extra_data) { + /* Unpack the data */ + const struct bpart *bparts = (struct bpart *)map_data; - /* Get its stellar friend */ - struct spart *sp = &s->sparts[-gp->id_or_neg_offset]; + for (int k = 0; k < nr_bparts; k++) { - /* Synchronize positions */ - sp->x[0] = gp->x[0]; - sp->x[1] = gp->x[1]; - sp->x[2] = gp->x[2]; + /* Get the particle */ + const struct bpart *bp = &bparts[k]; - gp->mass = sp->mass; - } + /* Skip unimportant particles */ + if (bp->time_bin == time_bin_not_created || + bp->time_bin == time_bin_inhibited) + continue; - else if (gp->type == swift_type_black_hole) { + /* Get its gravity friend */ + struct gpart *gp = bp->gpart; - /* Get its black hole friend */ - struct bpart *bp = &s->bparts[-gp->id_or_neg_offset]; +#ifdef SWIFT_DEBUG_CHECKS + if (gp == NULL) error("Unlinked particle!"); +#endif - /* Synchronize positions */ - bp->x[0] = gp->x[0]; - bp->x[1] = gp->x[1]; - bp->x[2] = gp->x[2]; + /* Synchronize positions, velocities and masses */ + gp->x[0] = bp->x[0]; + gp->x[1] = bp->x[1]; + gp->x[2] = bp->x[2]; - gp->mass = bp->mass; - } + gp->v_full[0] = bp->v[0]; + gp->v_full[1] = bp->v[1]; + gp->v_full[2] = bp->v[2]; - else { - error("Invalid type!"); - } + gp->mass = bp->mass; } } +/** + * @brief Make sure the baryon particles are at the same position and + * have the same velocity and mass as their #gpart friends. + * + * We copy the baryon particle properties to the #gpart type-by-type. + * + * @param s The #space. + */ 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->nr_gparts > 0 && s->nr_parts > 0) + threadpool_map(&s->e->threadpool, space_synchronize_part_positions_mapper, + s->parts, s->nr_parts, sizeof(struct part), 0, (void *)s); + + if (s->nr_gparts > 0 && s->nr_sparts > 0) + threadpool_map(&s->e->threadpool, space_synchronize_spart_positions_mapper, + s->sparts, s->nr_sparts, sizeof(struct spart), 0, NULL); + + if (s->nr_gparts > 0 && s->nr_bparts > 0) + threadpool_map(&s->e->threadpool, space_synchronize_bpart_positions_mapper, + s->bparts, s->nr_bparts, sizeof(struct bpart), 0, NULL); if (s->e->verbose) message("took %.3f %s.", clocks_from_ticks(getticks() - tic), @@ -4086,6 +4267,10 @@ 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]); + p[k].limiter_data.min_ngb_time_bin = num_time_bins + 1; + p[k].limiter_data.wakeup = time_bin_not_awake; + p[k].limiter_data.to_be_synchronized = 0; + #ifdef WITH_LOGGER logger_part_data_init(&xp[k].logger_data); #endif @@ -4101,7 +4286,8 @@ void space_first_init_parts_mapper(void *restrict map_data, int count, &xp[k]); /* And the cooling */ - cooling_first_init_part(phys_const, us, cosmo, cool_func, &p[k], &xp[k]); + cooling_first_init_part(phys_const, us, hydro_props, cosmo, cool_func, + &p[k], &xp[k]); /* And the tracers */ tracers_first_init_xpart(&p[k], &xp[k], us, phys_const, cosmo, hydro_props, @@ -4173,6 +4359,10 @@ void space_first_init_gparts_mapper(void *restrict map_data, int count, gravity_first_init_gpart(&gp[k], grav_props); +#ifdef WITH_LOGGER + logger_part_data_init(&gp[k].logger_data); +#endif + #ifdef SWIFT_DEBUG_CHECKS /* Initialise the time-integration check variables */ gp[k].ti_drift = 0; @@ -4214,6 +4404,7 @@ void space_first_init_sparts_mapper(void *restrict map_data, int count, const float initial_h = s->initial_spart_h; const int with_feedback = (e->policy & engine_policy_feedback); + const int with_cosmology = (e->policy & engine_policy_cosmology); const struct cosmology *cosmo = e->cosmology; const struct stars_props *stars_properties = e->stars_properties; @@ -4252,7 +4443,12 @@ void space_first_init_sparts_mapper(void *restrict map_data, int count, /* Initialise the rest */ for (int k = 0; k < count; k++) { - stars_first_init_spart(&sp[k], stars_properties); + stars_first_init_spart(&sp[k], stars_properties, with_cosmology, cosmo->a, + e->time); + +#ifdef WITH_LOGGER + logger_part_data_init(&sp[k].logger_data); +#endif /* Also initialise the chemistry */ chemistry_first_init_spart(chemistry, &sp[k]); @@ -4379,6 +4575,7 @@ void space_init_parts_mapper(void *restrict map_data, int count, for (int k = 0; k < count; k++) { hydro_init_part(&parts[k], hs); + black_holes_init_potential(&parts[k].black_holes_data); chemistry_init_part(&parts[k], e->chemistry); pressure_floor_init_part(&parts[k], &xparts[k]); star_formation_init_part(&parts[k], e->star_formation); @@ -4601,6 +4798,9 @@ void space_init(struct space *s, struct swift_params *params, s->sum_bpart_vel_norm = 0.f; s->nr_queues = 1; /* Temporary value until engine construction */ + /* Initiate some basic randomness */ + srand(42); + /* Are we generating gas from the DM-only ICs? */ if (generate_gas_in_ics) { space_generate_gas(s, cosmo, periodic, DM_background, dim, verbose); @@ -5269,10 +5469,13 @@ void space_check_top_multipoles_drift_point(struct space *s, * * @param s The #space to check. */ -void space_check_timesteps(struct space *s) { +void space_check_timesteps(const struct space *s) { #ifdef SWIFT_DEBUG_CHECKS for (int i = 0; i < s->nr_cells; ++i) { - cell_check_timesteps(&s->cells_top[i]); + if (s->cells_top[i].nodeID == engine_rank) { + cell_check_timesteps(&s->cells_top[i], s->e->ti_current, + s->e->max_active_bin); + } } #else error("Calling debugging code without debugging flag activated."); @@ -5287,14 +5490,26 @@ void space_check_limiter_mapper(void *map_data, int nr_parts, #ifdef SWIFT_DEBUG_CHECKS /* Unpack the data */ struct part *restrict parts = (struct part *)map_data; + const struct space *s = (struct space *)extra_data; + const int with_timestep_limiter = + (s->e->policy & engine_policy_timestep_limiter); + const int with_timestep_sync = (s->e->policy & engine_policy_timestep_sync); /* Verify that all limited particles have been treated */ for (int k = 0; k < nr_parts; k++) { if (parts[k].time_bin == time_bin_inhibited) continue; - if (parts[k].wakeup == time_bin_awake) - error("Particle still woken up! id=%lld", parts[k].id); + if (parts[k].time_bin < 0) error("Particle has negative time-bin!"); + + if (with_timestep_limiter && + parts[k].limiter_data.wakeup != time_bin_not_awake) + error("Particle still woken up! id=%lld wakeup=%d", parts[k].id, + parts[k].limiter_data.wakeup); + + if (with_timestep_sync && parts[k].limiter_data.to_be_synchronized != 0) + error("Synchronized particle not treated! id=%lld synchronized=%d", + parts[k].id, parts[k].limiter_data.to_be_synchronized); if (parts[k].gpart != NULL) if (parts[k].time_bin != parts[k].gpart->time_bin) @@ -5316,7 +5531,7 @@ void space_check_limiter(struct space *s) { #ifdef SWIFT_DEBUG_CHECKS threadpool_map(&s->e->threadpool, space_check_limiter_mapper, s->parts, - s->nr_parts, sizeof(struct part), 1000, NULL); + s->nr_parts, sizeof(struct part), 1000, s); #else error("Calling debugging code without debugging flag activated."); #endif diff --git a/src/space.h b/src/space.h index d13abddfcda729067ab40fbba21b93f4b2cc3b88..5ce9a3429939edec57def1e551d7db09bedcbcf5 100644 --- a/src/space.h +++ b/src/space.h @@ -30,7 +30,6 @@ #include <stddef.h> /* Includes. */ -#include "gravity_properties.h" #include "hydro_space.h" #include "lock.h" #include "parser.h" @@ -40,6 +39,7 @@ /* Avoid cyclic inclusions */ struct cell; struct cosmology; +struct gravity_props; /* Some constants. */ #define space_cellallocchunk 1000 @@ -112,6 +112,14 @@ struct space { /*! Inverse of the top-level cell width */ double iwidth[3]; + /*! Position vector added to all the particles at rebuild + time */ + double pos_dithering[3]; + + /*! Position vector added to all the particles at rebuild + time (value at the previous rebuild) */ + double pos_dithering_old[3]; + /*! The minimum top-level cell width allowed. */ double cell_min; @@ -357,7 +365,7 @@ void space_check_drift_point(struct space *s, integertime_t ti_drift, int multipole); void space_check_top_multipoles_drift_point(struct space *s, integertime_t ti_drift); -void space_check_timesteps(struct space *s); +void space_check_timesteps(const struct space *s); void space_check_limiter(struct space *s); void space_check_swallow(struct space *s); void space_check_sort_flags(struct space *s); diff --git a/src/star_formation/EAGLE/star_formation.h b/src/star_formation/EAGLE/star_formation.h index 392f261e684d56eeaa9bd45d14392b2e85556e70..ce680d4ec1f6287300bae00e2cc1f53d0dfabc60 100644 --- a/src/star_formation/EAGLE/star_formation.h +++ b/src/star_formation/EAGLE/star_formation.h @@ -21,6 +21,7 @@ /* Local includes */ #include "adiabatic_index.h" +#include "chemistry.h" #include "cooling.h" #include "cosmology.h" #include "engine.h" @@ -69,11 +70,11 @@ struct star_formation { /*! Critical overdensity */ double min_over_den; - /*! Dalla Vecchia & Schaye temperature criteria */ - double temperature_margin_threshold_dex; + /*! Dalla Vecchia & Schaye entropy differnce criterion */ + double entropy_margin_threshold_dex; - /*! 10^Tdex of Dalla Vecchia & SChaye temperature criteria */ - double ten_to_temperature_margin_threshold_dex; + /*! 10^Tdex of Dalla Vecchia & Schaye entropy difference criterion */ + double ten_to_entropy_margin_threshold_dex; /*! gas fraction */ double fgas; @@ -248,14 +249,12 @@ INLINE static int star_formation_is_star_forming( * because we also need to check if the physical density exceeded * the appropriate limit */ + /* Get the Hydrogen number density (assuming primordial H abundance) */ + const double n_H = physical_density * hydro_props->hydrogen_mass_fraction; + + /* Get the density threshold for star formation */ const double Z = chemistry_get_total_metal_mass_fraction_for_star_formation(p); - const float* const metal_fraction = - chemistry_get_metal_mass_fraction_for_star_formation(p); - const double X_H = metal_fraction[chemistry_element_H]; - const double n_H = physical_density * X_H; - - /* Get the density threshold */ const double density_threshold = star_formation_threshold(Z, starform, phys_const); @@ -273,7 +272,7 @@ INLINE static int star_formation_is_star_forming( /* Check the Scahye & Dalla Vecchia 2012 EOS-based temperature critrion */ return (entropy < - entropy_eos * starform->ten_to_temperature_margin_threshold_dex); + entropy_eos * starform->ten_to_entropy_margin_threshold_dex); } /** @@ -284,13 +283,15 @@ INLINE static int star_formation_is_star_forming( * @param xp the #xpart. * @param starform the star formation law properties to use * @param phys_const the physical constants in internal units. + * @param hydro_props The properties of the hydro scheme. * @param cosmo the cosmological parameters and properties. * @param dt_star The time-step of this particle. */ INLINE static void star_formation_compute_SFR( const struct part* restrict p, struct xpart* restrict xp, const struct star_formation* starform, const struct phys_const* phys_const, - const struct cosmology* cosmo, const double dt_star) { + const struct hydro_props* hydro_props, const struct cosmology* cosmo, + const double dt_star) { /* Abort early if time-step size is 0 */ if (dt_star == 0.) { @@ -299,12 +300,10 @@ INLINE static void star_formation_compute_SFR( return; } - /* Hydrogen number density of this particle */ + /* Hydrogen number density of this particle (assuming primordial H abundance) + */ const double physical_density = hydro_get_physical_density(p, cosmo); - const float* const metal_fraction = - chemistry_get_metal_mass_fraction_for_star_formation(p); - const double X_H = metal_fraction[chemistry_element_H]; - const double n_H = physical_density * X_H / phys_const->const_proton_mass; + const double n_H = physical_density * hydro_props->hydrogen_mass_fraction; /* Are we above the threshold for automatic star formation? */ if (physical_density > @@ -324,7 +323,7 @@ INLINE static void star_formation_compute_SFR( /* Calculate the specific star formation rate */ double SFRpergasmass; - if (hydro_get_physical_density(p, cosmo) < + if (physical_density < starform->KS_high_den_thresh * phys_const->const_proton_mass) { SFRpergasmass = @@ -448,6 +447,8 @@ INLINE static void star_formation_copy_properties( /* Flag that this particle has not done feedback yet */ sp->f_E = -1.f; + sp->last_enrichment_time = sp->birth_time; + sp->count_since_last_enrichment = -1; } /** @@ -587,11 +588,11 @@ INLINE static void starformation_init_backend( starform->max_gas_density = starform->max_gas_density_HpCM3 * number_density_from_cgs; - starform->temperature_margin_threshold_dex = parser_get_opt_param_double( - parameter_file, "EAGLEStarFormation:EOS_temperature_margin_dex", FLT_MAX); + starform->entropy_margin_threshold_dex = parser_get_opt_param_double( + parameter_file, "EAGLEStarFormation:EOS_entropy_margin_dex", FLT_MAX); - starform->ten_to_temperature_margin_threshold_dex = - exp10(starform->temperature_margin_threshold_dex); + starform->ten_to_entropy_margin_threshold_dex = + exp10(starform->entropy_margin_threshold_dex); /* Read the normalization of the metallicity dependent critical * density*/ @@ -651,7 +652,7 @@ INLINE static void starformation_print_backend( starform->density_threshold_max_HpCM3); message("Temperature threshold is given by Dalla Vecchia and Schaye (2012)"); message("The temperature threshold offset from the EOS is given by: %e dex", - starform->temperature_margin_threshold_dex); + starform->entropy_margin_threshold_dex); message("Running with a maximum gas density given by: %e #/cm^3", starform->max_gas_density_HpCM3); } @@ -663,12 +664,13 @@ INLINE static void starformation_print_backend( * density loop for the EAGLE star formation model. * * @param p The particle to act upon + * @param xp The extra particle to act upon * @param cd The global star_formation information. * @param cosmo The current cosmological model. */ __attribute__((always_inline)) INLINE static void star_formation_end_density( - struct part* restrict p, const struct star_formation* cd, - const struct cosmology* cosmo) {} + struct part* restrict p, struct xpart* restrict xp, + const struct star_formation* cd, const struct cosmology* cosmo) {} /** * @brief Sets all particle fields to sensible values when the #part has 0 ngbs. @@ -721,4 +723,20 @@ star_formation_first_init_part(const struct phys_const* restrict phys_const, const struct part* restrict p, struct xpart* restrict xp) {} +/** + * @brief Split the star formation content of a particle into n pieces + * + * We only need to split the SFR if it is positive, i.e. it is not + * storing the redshift/time of last SF event. + * + * @param p The #part. + * @param xp The #xpart. + * @param n The number of pieces to split into. + */ +__attribute__((always_inline)) INLINE static void star_formation_split_part( + struct part* p, struct xpart* xp, const double n) { + + if (xp->sf_data.SFR > 0.) xp->sf_data.SFR /= n; +} + #endif /* SWIFT_EAGLE_STAR_FORMATION_H */ diff --git a/src/star_formation/EAGLE/star_formation_struct.h b/src/star_formation/EAGLE/star_formation_struct.h index 41247e160a3eddbc9184c59b67cfa2a1d7259a05..f5f0f76e8d59f73148f51f462cc619ec70e82192 100644 --- a/src/star_formation/EAGLE/star_formation_struct.h +++ b/src/star_formation/EAGLE/star_formation_struct.h @@ -25,7 +25,8 @@ */ struct star_formation_xpart_data { - /*! Star formation rate */ + /*! Star formation rate (internal units) or (if negative) time/scale-factor of + * last SF episode */ float SFR; }; diff --git a/src/star_formation/GEAR/star_formation.h b/src/star_formation/GEAR/star_formation.h index da43778ee958019120665c54210be9ef9c2953e0..8eb60bf38fc6a6a9e0683de07833621211894054 100644 --- a/src/star_formation/GEAR/star_formation.h +++ b/src/star_formation/GEAR/star_formation.h @@ -59,6 +59,11 @@ INLINE static int star_formation_is_star_forming( const struct cooling_function_data* restrict cooling, const struct entropy_floor_properties* restrict entropy_floor) { + /* Check if collapsing particles */ + if (xp->sf_data.div_v > 0) { + return 0; + } + const float temperature = cooling_get_temperature(phys_const, hydro_props, us, cosmo, cooling, p, xp); @@ -73,7 +78,7 @@ INLINE static int star_formation_is_star_forming( const float sigma2 = p->pressure_floor_data.sigma2 * cosmo->a * cosmo->a; const float n_jeans_2_3 = starform->n_jeans_2_3; - const float h = p->h; + const float h = p->h * kernel_gamma; const float density = hydro_get_physical_density(p, cosmo); // TODO use GRACKLE */ @@ -101,13 +106,15 @@ INLINE static int star_formation_is_star_forming( * @param xp the #xpart. * @param starform the star formation law properties to use * @param phys_const the physical constants in internal units. + * @param hydro_props The properties of the hydro scheme. * @param cosmo the cosmological parameters and properties. * @param dt_star The time-step of this particle. */ INLINE static void star_formation_compute_SFR( struct part* restrict p, struct xpart* restrict xp, const struct star_formation* starform, const struct phys_const* phys_const, - const struct cosmology* cosmo, const double dt_star) {} + const struct hydro_props* hydro_props, const struct cosmology* cosmo, + const double dt_star) {} /** * @brief Decides whether a particle should be converted into a @@ -198,10 +205,6 @@ INLINE static void star_formation_copy_properties( sp->birth_time = e->time; } - // TODO copy only metals - /* Store the chemistry struct in the star particle */ - sp->chemistry_data = p->chemistry_data; - /* Store the tracers data */ sp->tracers_data = xp->tracers_data; @@ -211,6 +214,9 @@ INLINE static void star_formation_copy_properties( /* Store the birth temperature*/ sp->birth.temperature = cooling_get_temperature(phys_const, hydro_props, us, cosmo, cooling, p, xp); + + /* Copy the chemistry properties */ + chemistry_copy_star_formation_properties(p, xp, sp); } /** @@ -229,12 +235,17 @@ INLINE static void starformation_print_backend( * Nothing to do here. * * @param p The particle to act upon + * @param xp The extra particle to act upon * @param cd The global star_formation information. * @param cosmo The current cosmological model. */ __attribute__((always_inline)) INLINE static void star_formation_end_density( - struct part* restrict p, const struct star_formation* cd, - const struct cosmology* cosmo) {} + struct part* restrict p, struct xpart* restrict xp, + const struct star_formation* cd, const struct cosmology* cosmo) { + + /* Copy the velocity divergence */ + xp->sf_data.div_v = p->density.div_v; +} /** * @brief Sets all particle fields to sensible values when the #part has 0 ngbs. @@ -285,4 +296,17 @@ star_formation_first_init_part(const struct phys_const* restrict phys_const, const struct part* restrict p, struct xpart* restrict xp) {} +/** + * @brief Split the star formation content of a particle into n pieces + * + * + * @param p The #part. + * @param xp The #xpart. + * @param n The number of pieces to split into. + */ +__attribute__((always_inline)) INLINE static void star_formation_split_part( + struct part* p, struct xpart* xp, const double n) { + error("Loic: to be implemented"); +} + #endif /* SWIFT_GEAR_STAR_FORMATION_H */ diff --git a/src/star_formation/GEAR/star_formation_struct.h b/src/star_formation/GEAR/star_formation_struct.h index 50a735ff45f27ccb197ae6089f13237f67a59e3f..9d6d78df5c5c1037658885d311eb87aa760be303 100644 --- a/src/star_formation/GEAR/star_formation_struct.h +++ b/src/star_formation/GEAR/star_formation_struct.h @@ -23,7 +23,10 @@ * @brief Star-formation-related properties stored in the extended particle * data. */ -struct star_formation_xpart_data {}; +struct star_formation_xpart_data { + /*! Particle velocity divergence. */ + float div_v; +}; /** * @brief Global star formation properties diff --git a/src/star_formation/none/star_formation.h b/src/star_formation/none/star_formation.h index 96b1315ffe1c6a78e2375999c0cc447c0474aad2..6155d415645dd9829aa2faaec2cadb3cad7bdee3 100644 --- a/src/star_formation/none/star_formation.h +++ b/src/star_formation/none/star_formation.h @@ -70,13 +70,15 @@ INLINE static int star_formation_is_star_forming( * @param xp the #xpart. * @param starform the star formation law properties to use * @param phys_const the physical constants in internal units. + * @param hydro_props The properties of the hydro scheme. * @param cosmo the cosmological parameters and properties. * @param dt_star The time-step of this particle. */ INLINE static void star_formation_compute_SFR( const struct part* restrict p, struct xpart* restrict xp, const struct star_formation* starform, const struct phys_const* phys_const, - const struct cosmology* cosmo, const double dt_star) {} + const struct hydro_props* hydro_props, const struct cosmology* cosmo, + const double dt_star) {} /** * @brief Decides whether a particle should be converted into a @@ -169,12 +171,13 @@ INLINE static void starformation_print_backend( * Nothing to do here. * * @param p The particle to act upon + * @param xp The extra particle to act upon * @param cd The global star_formation information. * @param cosmo The current cosmological model. */ __attribute__((always_inline)) INLINE static void star_formation_end_density( - struct part* restrict p, const struct star_formation* cd, - const struct cosmology* cosmo) {} + struct part* restrict p, struct xpart* restrict xp, + const struct star_formation* cd, const struct cosmology* cosmo) {} /** * @brief Sets all particle fields to sensible values when the #part has 0 ngbs. @@ -225,4 +228,14 @@ star_formation_first_init_part(const struct phys_const* restrict phys_const, const struct part* restrict p, struct xpart* restrict xp) {} +/** + * @brief Split the star formation content of a particle into n pieces + * + * @param p The #part. + * @param xp The #xpart. + * @param n The number of pieces to split into. + */ +__attribute__((always_inline)) INLINE static void star_formation_split_part( + struct part* p, struct xpart* xp, const double n) {} + #endif /* SWIFT_NONE_STAR_FORMATION_H */ diff --git a/src/stars/Default/stars.h b/src/stars/Default/stars.h index 804fe6085d7b420955ab04c099c12e32f6a6929c..85e92c199b08f21d09b2713a3d09537812c510b0 100644 --- a/src/stars/Default/stars.h +++ b/src/stars/Default/stars.h @@ -41,9 +41,14 @@ __attribute__((always_inline)) INLINE static float stars_compute_timestep( * * @param sp The particle to act upon * @param stars_properties The properties of the stellar model. + * @param with_cosmology Are we running with cosmological time integration. + * @param scale_factor The current scale-factor (used if running with + * cosmology). + * @param time The current time (used if running without cosmology). */ __attribute__((always_inline)) INLINE static void stars_first_init_spart( - struct spart* sp, const struct stars_props* stars_properties) { + struct spart* sp, const struct stars_props* stars_properties, + const int with_cosmology, const double scale_factor, const double time) { sp->time_bin = 0; } diff --git a/src/stars/Default/stars_io.h b/src/stars/Default/stars_io.h index 54e6b5d05a823cb8401ec01c4fe962bbc8f01ca8..ebabc3e0f555a8055f67b402674945e28dae6747 100644 --- a/src/stars/Default/stars_io.h +++ b/src/stars/Default/stars_io.h @@ -52,10 +52,11 @@ INLINE static void stars_read_particles(struct spart *sparts, INLINE static void convert_spart_pos(const struct engine *e, const struct spart *sp, double *ret) { - if (e->s->periodic) { - ret[0] = box_wrap(sp->x[0], 0.0, e->s->dim[0]); - ret[1] = box_wrap(sp->x[1], 0.0, e->s->dim[1]); - ret[2] = box_wrap(sp->x[2], 0.0, e->s->dim[2]); + const struct space *s = e->s; + if (s->periodic) { + ret[0] = box_wrap(sp->x[0] - s->pos_dithering[0], 0.0, s->dim[0]); + ret[1] = box_wrap(sp->x[1] - s->pos_dithering[1], 0.0, s->dim[1]); + ret[2] = box_wrap(sp->x[2] - s->pos_dithering[2], 0.0, s->dim[2]); } else { ret[0] = sp->x[0]; ret[1] = sp->x[1]; diff --git a/src/stars/Default/stars_part.h b/src/stars/Default/stars_part.h index 05035039d22c7767bde99b5148b49c4b72492f09..29bf1409879cbde54ee75979fa14fad7e2c195cb 100644 --- a/src/stars/Default/stars_part.h +++ b/src/stars/Default/stars_part.h @@ -87,6 +87,11 @@ struct spart { /*! Chemistry structure */ struct chemistry_part_data chemistry_data; +#ifdef WITH_LOGGER + /* Additional data for the particle logger */ + struct logger_part_data logger_data; +#endif + #ifdef SWIFT_DEBUG_CHECKS /* Time of the last drift */ diff --git a/src/stars/EAGLE/stars.h b/src/stars/EAGLE/stars.h index 82ad2e25f474e6c66e6cf5e09f39188faa09b084..9567af1bceebb3c5f622695afbdbe0c0e3416b1f 100644 --- a/src/stars/EAGLE/stars.h +++ b/src/stars/EAGLE/stars.h @@ -58,16 +58,28 @@ __attribute__((always_inline)) INLINE static void stars_init_spart( * * @param sp The particle to act upon. * @param stars_properties Properties of the stars model. + * @param with_cosmology Are we running with cosmological time integration. + * @param scale_factor The current scale-factor (used if running with + * cosmology). + * @param time The current time (used if running without cosmology). */ __attribute__((always_inline)) INLINE static void stars_first_init_spart( - struct spart* sp, const struct stars_props* stars_properties) { + struct spart* sp, const struct stars_props* stars_properties, + const int with_cosmology, const double scale_factor, const double time) { sp->time_bin = 0; sp->birth_density = 0.f; sp->f_E = -1.f; + sp->count_since_last_enrichment = -1; + if (stars_properties->overwrite_birth_time) sp->birth_time = stars_properties->spart_first_init_birth_time; + if (with_cosmology) + sp->last_enrichment_time = scale_factor; + else + sp->last_enrichment_time = time; + stars_init_spart(sp); } @@ -155,7 +167,7 @@ __attribute__((always_inline)) INLINE static void stars_reset_acceleration( struct spart* restrict p) { #ifdef DEBUG_INTERACTIONS_STARS - p->num_ngb_force = 0; + p->num_ngb_feedback = 0; #endif } @@ -172,8 +184,8 @@ __attribute__((always_inline)) INLINE static void stars_reset_feedback( #ifdef DEBUG_INTERACTIONS_STARS for (int i = 0; i < MAX_NUM_OF_NEIGHBOURS_STARS; ++i) - p->ids_ngbs_force[i] = -1; - p->num_ngb_force = 0; + p->ids_ngbs_feedback[i] = -1; + p->num_ngb_feedback = 0; #endif } diff --git a/src/stars/EAGLE/stars_iact.h b/src/stars/EAGLE/stars_iact.h index 784fe241dcc19139596ba9d28955838f362518bf..8e70adfbc1f2505e8a4cb183885adf89fae2cbfe 100644 --- a/src/stars/EAGLE/stars_iact.h +++ b/src/stars/EAGLE/stars_iact.h @@ -42,9 +42,8 @@ runner_iact_nonsym_stars_density(const float r2, const float *dx, float wi, wi_dx; - /* Get r and 1/r. */ - const float r_inv = 1.0f / sqrtf(r2); - const float r = r2 * r_inv; + /* Get r. */ + const float r = sqrtf(r2); /* Compute the kernel function */ const float hi_inv = 1.0f / hi; diff --git a/src/stars/EAGLE/stars_io.h b/src/stars/EAGLE/stars_io.h index 0baafd380addfa1d6f8d60491be3da4c30b2a3aa..a7fd91f51355245ec9164df9fd1aa9366ff6e917 100644 --- a/src/stars/EAGLE/stars_io.h +++ b/src/stars/EAGLE/stars_io.h @@ -57,10 +57,11 @@ INLINE static void stars_read_particles(struct spart *sparts, INLINE static void convert_spart_pos(const struct engine *e, const struct spart *sp, double *ret) { - if (e->s->periodic) { - ret[0] = box_wrap(sp->x[0], 0.0, e->s->dim[0]); - ret[1] = box_wrap(sp->x[1], 0.0, e->s->dim[1]); - ret[2] = box_wrap(sp->x[2], 0.0, e->s->dim[2]); + const struct space *s = e->s; + if (s->periodic) { + ret[0] = box_wrap(sp->x[0] - s->pos_dithering[0], 0.0, s->dim[0]); + ret[1] = box_wrap(sp->x[1] - s->pos_dithering[1], 0.0, s->dim[1]); + ret[2] = box_wrap(sp->x[2] - s->pos_dithering[2], 0.0, s->dim[2]); } else { ret[0] = sp->x[0]; ret[1] = sp->x[1]; diff --git a/src/stars/EAGLE/stars_part.h b/src/stars/EAGLE/stars_part.h index 9114cb9107e1259698c365be82e5318d60d37ac7..15613d077a3ac27d7484fbc47fe0dc3a5901c395 100644 --- a/src/stars/EAGLE/stars_part.h +++ b/src/stars/EAGLE/stars_part.h @@ -56,9 +56,6 @@ struct spart { /*! Star mass */ float mass; - /*! Initial star mass */ - float mass_init; - /*! Particle smoothing length. */ float h; @@ -82,6 +79,12 @@ struct spart { float birth_scale_factor; }; + /*! Scale-factor / time at which this particle last did enrichment */ + float last_enrichment_time; + + /*! Initial star mass */ + float mass_init; + /*! Birth density */ float birth_density; @@ -103,6 +106,14 @@ struct spart { /*! Particle time bin */ timebin_t time_bin; + /*! Number of time-steps since the last enrichment step */ + char count_since_last_enrichment; + +#ifdef WITH_LOGGER + /* Additional data for the particle logger */ + struct logger_part_data logger_data; +#endif + #ifdef SWIFT_DEBUG_CHECKS /* Time of the last drift */ @@ -121,11 +132,11 @@ struct spart { /*! List of interacting particles in the density SELF and PAIR */ long long ids_ngbs_density[MAX_NUM_OF_NEIGHBOURS_STARS]; - /*! Number of interactions in the force SELF and PAIR */ - int num_ngb_force; + /*! Number of interactions in the feedback SELF and PAIR */ + int num_ngb_feedback; - /*! List of interacting particles in the force SELF and PAIR */ - long long ids_ngbs_force[MAX_NUM_OF_NEIGHBOURS_STARS]; + /*! List of interacting particles in the feedback SELF and PAIR */ + long long ids_ngbs_feedback[MAX_NUM_OF_NEIGHBOURS_STARS]; #endif } SWIFT_STRUCT_ALIGN; @@ -144,7 +155,7 @@ struct stars_props { /*! Smoothing length tolerance */ float h_tolerance; - /*! Tolerance on neighbour number (for info only) */ + /*! Tolerance on neighbour number (for info only)*/ float delta_neighbours; /*! Maximal number of iterations to converge h */ diff --git a/src/stars/GEAR/stars.h b/src/stars/GEAR/stars.h index 467aaa164ba9762d85f8dfae85db86ff76ae779e..1c5bdf591661b46a0ce0849d4f5c37c401d2b62f 100644 --- a/src/stars/GEAR/stars.h +++ b/src/stars/GEAR/stars.h @@ -33,21 +33,6 @@ __attribute__((always_inline)) INLINE static float stars_compute_timestep( return FLT_MAX; } -/** - * @brief Initialises the s-particles for the first time - * - * This function is called only once just after the ICs have been - * read in to do some conversions. - * - * @param sp The particle to act upon - * @param stars_properties The properties of the stellar model. - */ -__attribute__((always_inline)) INLINE static void stars_first_init_spart( - struct spart* sp, const struct stars_props* stars_properties) { - - sp->time_bin = 0; -} - /** * @brief Prepares a s-particle for its interactions * @@ -66,6 +51,26 @@ __attribute__((always_inline)) INLINE static void stars_init_spart( sp->density.wcount_dh = 0.f; } +/** + * @brief Initialises the s-particles for the first time + * + * This function is called only once just after the ICs have been + * read in to do some conversions. + * + * @param sp The particle to act upon. + * @param stars_properties Properties of the stars model. + */ +__attribute__((always_inline)) INLINE static void stars_first_init_spart( + struct spart* sp, const struct stars_props* stars_properties, + const int with_cosmology, const double scale_factor, const double time) { + + sp->time_bin = 0; + sp->birth.density = 0.f; + // sp->birth_time = 0.; + + stars_init_spart(sp); +} + /** * @brief Predict additional particle fields forward in time when drifting * @@ -87,6 +92,8 @@ __attribute__((always_inline)) INLINE static void stars_reset_predicted_values( /** * @brief Finishes the calculation of (non-gravity) forces acting on stars * + * Multiplies the forces and accelerations by the appropiate constants + * * @param sp The particle to act upon */ __attribute__((always_inline)) INLINE static void stars_end_feedback( @@ -131,13 +138,8 @@ __attribute__((always_inline)) INLINE static void stars_end_density( __attribute__((always_inline)) INLINE static void stars_spart_has_no_neighbours( struct spart* restrict sp, const struct cosmology* cosmo) { - /* Some smoothing length multiples. */ - const float h = sp->h; - const float h_inv = 1.0f / h; /* 1/h */ - const float h_inv_dim = pow_dimension(h_inv); /* 1/h^d */ - /* Re-set problematic values */ - sp->density.wcount = kernel_root * h_inv_dim; + sp->density.wcount = 0.f; sp->density.wcount_dh = 0.f; } @@ -149,24 +151,30 @@ __attribute__((always_inline)) INLINE static void stars_spart_has_no_neighbours( * * @param p The particle to act upon */ -__attribute__((always_inline)) INLINE static void stars_reset_feedback( +__attribute__((always_inline)) INLINE static void stars_reset_acceleration( struct spart* restrict p) { #ifdef DEBUG_INTERACTIONS_STARS - for (int i = 0; i < MAX_NUM_OF_NEIGHBOURS_STARS; ++i) - p->ids_ngbs_force[i] = -1; - p->num_ngb_force = 0; + p->num_ngb_feedback = 0; #endif } /** - * @brief Initializes constants related to stellar evolution, initializes imf, - * reads and processes yield tables + * @brief Reset acceleration fields of a particle * - * @param params swift_params parameters structure - * @param stars stars_props data structure + * This is the equivalent of hydro_reset_acceleration. + * We do not compute the acceleration on star, therefore no need to use it. + * + * @param p The particle to act upon */ -inline static void stars_evolve_init(struct swift_params* params, - struct stars_props* restrict stars) {} +__attribute__((always_inline)) INLINE static void stars_reset_feedback( + struct spart* restrict p) { + +#ifdef DEBUG_INTERACTIONS_STARS + for (int i = 0; i < MAX_NUM_OF_NEIGHBOURS_STARS; ++i) + p->ids_ngbs_feedback[i] = -1; + p->num_ngb_feedback = 0; +#endif +} #endif /* SWIFT_GEAR_STARS_H */ diff --git a/src/stars/GEAR/stars_iact.h b/src/stars/GEAR/stars_iact.h index c7bda43fc0c66fcc890e6b05bacf871edfd10b5a..024ac7a9b9fff9ed707298d60ec2e562a5edf6bd 100644 --- a/src/stars/GEAR/stars_iact.h +++ b/src/stars/GEAR/stars_iact.h @@ -65,13 +65,14 @@ runner_iact_nonsym_stars_density(const float r2, const float *dx, /** * @brief Feedback interaction between two particles (non-symmetric). + * Used for updating properties of gas particles neighbouring a star particle * * @param r2 Comoving square distance between the two particles. - * @param dx Comoving vector separating both particles (pi - pj). + * @param dx Comoving vector separating both particles (si - pj). * @param hi Comoving smoothing-length of particle i. * @param hj Comoving smoothing-length of particle j. - * @param si First sparticle. - * @param pj Second particle (not updated). + * @param si First (star) particle (not updated). + * @param pj Second (gas) particle. * @param a Current scale factor. * @param H Current Hubble parameter. */ @@ -91,4 +92,4 @@ runner_iact_nonsym_stars_feedback(const float r2, const float *dx, #endif } -#endif +#endif /* SWIFT_GEAR_STARS_IACT_H */ diff --git a/src/stars/GEAR/stars_io.h b/src/stars/GEAR/stars_io.h index dc40e86e29b19a370d549576fd955464bf0e609d..a5a6e7368b8102530c4282d177e90075cc619d61 100644 --- a/src/stars/GEAR/stars_io.h +++ b/src/stars/GEAR/stars_io.h @@ -34,7 +34,7 @@ INLINE static void stars_read_particles(struct spart *sparts, int *num_fields) { /* Say how much we want to read */ - *num_fields = 5; + *num_fields = 7; /* List what we want to read */ list[0] = io_make_input_field("Coordinates", DOUBLE, 3, COMPULSORY, @@ -47,6 +47,63 @@ INLINE static void stars_read_particles(struct spart *sparts, UNIT_CONV_NO_UNITS, sparts, id); list[4] = io_make_input_field("SmoothingLength", FLOAT, 1, OPTIONAL, UNIT_CONV_LENGTH, sparts, h); + // TODO take it from initial mass + list[5] = io_make_input_field("BirthMass", FLOAT, 1, COMPULSORY, + UNIT_CONV_MASS, sparts, birth.mass); + + // TODO make it optional + list[6] = io_make_input_field("BirthTime", FLOAT, 1, OPTIONAL, UNIT_CONV_MASS, + sparts, birth_time); + + // TODO read birth density +} + +INLINE static void convert_spart_pos(const struct engine *e, + const struct spart *sp, double *ret) { + + const struct space *s = e->s; + if (s->periodic) { + ret[0] = box_wrap(sp->x[0] - s->pos_dithering[0], 0.0, s->dim[0]); + ret[1] = box_wrap(sp->x[1] - s->pos_dithering[1], 0.0, s->dim[1]); + ret[2] = box_wrap(sp->x[2] - s->pos_dithering[2], 0.0, s->dim[2]); + } else { + ret[0] = sp->x[0]; + ret[1] = sp->x[1]; + ret[2] = sp->x[2]; + } +} + +INLINE static void convert_spart_vel(const struct engine *e, + const struct spart *sp, float *ret) { + + const int with_cosmology = (e->policy & engine_policy_cosmology); + const struct cosmology *cosmo = e->cosmology; + const integertime_t ti_current = e->ti_current; + const double time_base = e->time_base; + + const integertime_t ti_beg = get_integer_time_begin(ti_current, sp->time_bin); + const integertime_t ti_end = get_integer_time_end(ti_current, sp->time_bin); + + /* Get time-step since the last kick */ + float dt_kick_grav; + if (with_cosmology) { + dt_kick_grav = cosmology_get_grav_kick_factor(cosmo, ti_beg, ti_current); + dt_kick_grav -= + cosmology_get_grav_kick_factor(cosmo, ti_beg, (ti_beg + ti_end) / 2); + } else { + dt_kick_grav = (ti_current - ((ti_beg + ti_end) / 2)) * time_base; + } + + /* Extrapolate the velocites to the current time */ + const struct gpart *gp = sp->gpart; + ret[0] = gp->v_full[0] + gp->a_grav[0] * dt_kick_grav; + ret[1] = gp->v_full[1] + gp->a_grav[1] * dt_kick_grav; + ret[2] = gp->v_full[2] + gp->a_grav[2] * dt_kick_grav; + + /* Conversion from internal units to peculiar velocities */ + ret[0] *= cosmo->a_inv; + ret[1] *= cosmo->a_inv; + ret[2] *= cosmo->a_inv; } /** @@ -65,14 +122,14 @@ INLINE static void stars_write_particles(const struct spart *sparts, *num_fields = 9; /* List what we want to write */ - list[0] = - io_make_output_field("Coordinates", DOUBLE, 3, UNIT_CONV_LENGTH, 1., - sparts, x, "Co-moving positions of the particles"); - - list[1] = io_make_output_field( - "Velocities", FLOAT, 3, UNIT_CONV_SPEED, 0.f, sparts, v, - "Peculiar velocities of the stars. This is (a * dx/dt) where x is the " - "co-moving positions of the particles"); + list[0] = io_make_output_field_convert_spart( + "Coordinates", DOUBLE, 3, UNIT_CONV_LENGTH, 1.f, sparts, + convert_spart_pos, "Co-moving position of the particles"); + + list[1] = io_make_output_field_convert_spart( + "Velocities", FLOAT, 3, UNIT_CONV_SPEED, 0.f, sparts, convert_spart_vel, + "Peculiar velocities of the particles. This is a * dx/dt where x is the " + "co-moving position of the particles."); list[2] = io_make_output_field("Masses", FLOAT, 1, UNIT_CONV_MASS, 0.f, sparts, mass, "Masses of the particles"); diff --git a/src/stars/GEAR/stars_part.h b/src/stars/GEAR/stars_part.h index bf68a580ef009f5a814fa17123301b5585d6084c..bee9b5c6a374b80dc6330341a411d6438e0254f1 100644 --- a/src/stars/GEAR/stars_part.h +++ b/src/stars/GEAR/stars_part.h @@ -55,22 +55,9 @@ struct spart { /*! Star mass */ float mass; - /* Particle cutoff radius. */ + /*! Particle smoothing length. */ float h; - /*! Union for the birth time and birth scale factor */ - union { - - /*! Birth time */ - float birth_time; - - /*! Birth scale factor */ - float birth_scale_factor; - }; - - /*! Particle time bin */ - timebin_t time_bin; - struct { /* Number of neighbours. */ @@ -92,6 +79,16 @@ struct spart { float mass; } birth; + /*! Union for the birth time and birth scale factor */ + union { + + /*! Birth time */ + float birth_time; + + /*! Birth scale factor */ + float birth_scale_factor; + }; + /*! Feedback structure */ struct feedback_spart_data feedback_data; @@ -99,7 +96,10 @@ struct spart { struct tracers_xpart_data tracers_data; /*! Chemistry structure */ - struct chemistry_part_data chemistry_data; + struct chemistry_spart_data chemistry_data; + + /*! Particle time bin */ + timebin_t time_bin; #ifdef SWIFT_DEBUG_CHECKS @@ -118,11 +118,11 @@ struct spart { /*! List of interacting particles in the density SELF and PAIR */ long long ids_ngbs_density[MAX_NUM_OF_NEIGHBOURS_STARS]; - /*! Number of interactions in the force SELF and PAIR */ - int num_ngb_force; + /*! Number of interactions in the feedback SELF and PAIR */ + int num_ngb_feedback; /*! List of interacting particles in the force SELF and PAIR */ - long long ids_ngbs_force[MAX_NUM_OF_NEIGHBOURS_STARS]; + long long ids_ngbs_feedback[MAX_NUM_OF_NEIGHBOURS_STARS]; #endif } SWIFT_STRUCT_ALIGN; @@ -135,7 +135,7 @@ struct stars_props { /*! Resolution parameter */ float eta_neighbours; - /*! Target weightd number of neighbours (for info only)*/ + /*! Target weighted number of neighbours (for info only)*/ float target_neighbours; /*! Smoothing length tolerance */ diff --git a/src/task.c b/src/task.c index 02102d9ba8a0a176aedf59db216ae88d4c8f8cd3..1f91ce2fb926892edf9b8e3ff9cf457c6d6c03a8 100644 --- a/src/task.c +++ b/src/task.c @@ -71,6 +71,7 @@ const char *taskID_names[task_type_count] = {"none", "kick2", "timestep", "timestep_limiter", + "timestep_sync", "send", "recv", "grav_long_range", @@ -164,7 +165,6 @@ __attribute__((always_inline)) INLINE static enum task_actions task_acts_on( case task_type_sort: case task_type_ghost: case task_type_extra_ghost: - case task_type_timestep_limiter: case task_type_cooling: case task_type_end_hydro_force: return task_action_part; @@ -236,6 +236,8 @@ __attribute__((always_inline)) INLINE static enum task_actions task_acts_on( case task_type_fof_self: case task_type_fof_pair: case task_type_timestep: + case task_type_timestep_limiter: + case task_type_timestep_sync: case task_type_send: case task_type_recv: if (t->ci->hydro.count > 0 && t->ci->grav.count > 0) @@ -431,6 +433,7 @@ void task_unlock(struct task *t) { case task_type_extra_ghost: case task_type_end_hydro_force: case task_type_timestep_limiter: + case task_type_timestep_sync: cell_unlocktree(ci); break; @@ -583,6 +586,7 @@ int task_lock(struct task *t) { case task_type_extra_ghost: case task_type_end_hydro_force: case task_type_timestep_limiter: + case task_type_timestep_sync: if (ci->hydro.hold) return 0; if (cell_locktree(ci) != 0) return 0; break; @@ -819,7 +823,11 @@ void task_get_group_name(int type, int subtype, char *cluster) { strcpy(cluster, "Gravity"); break; case task_subtype_limiter: - strcpy(cluster, "Timestep_limiter"); + if (type == task_type_send || type == task_type_recv) { + strcpy(cluster, "None"); + } else { + strcpy(cluster, "Timestep_limiter"); + } break; case task_subtype_stars_density: strcpy(cluster, "StarsDensity"); diff --git a/src/task.h b/src/task.h index 10b6c0910d72f43d7b95663ebd8e31d82978b2aa..02e1c5ca385749c3dff347b44d8e1f0e984fadd0 100644 --- a/src/task.h +++ b/src/task.h @@ -65,6 +65,7 @@ enum task_types { task_type_kick2, task_type_timestep, task_type_timestep_limiter, + task_type_timestep_sync, task_type_send, task_type_recv, task_type_grav_long_range, @@ -194,10 +195,10 @@ struct task { float weight; /*! Number of tasks unlocked by this one */ - short int nr_unlock_tasks; + int nr_unlock_tasks; /*! Number of unsatisfied dependencies */ - short int wait; + int wait; /*! Type of the task */ enum task_types type; diff --git a/src/task_order.h b/src/task_order.h new file mode 100644 index 0000000000000000000000000000000000000000..7924bc2ee3b33b8195a43926b197a2c5f0ba3d9e --- /dev/null +++ b/src/task_order.h @@ -0,0 +1,37 @@ +/******************************************************************************* + * This file is part of SWIFT. + * Copyright (c) 2019 Loic Hausammann (loic.hausammann@epfl.ch) + * + * 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_TASK_ORDER_H +#define SWIFT_TASK_ORDER_H + +#include "../config.h" + +/* Local includes */ +#include "scheduler.h" + +#ifdef TASK_ORDER_NONE +#include "task_order/none/task_order.h" +#elif TASK_ORDER_GEAR +#include "task_order/GEAR/task_order.h" +#elif TASK_ORDER_EAGLE +#include "task_order/EAGLE/task_order.h" +#else +#error undefined task order +#endif + +#endif /* SWIFT_TASK_ORDER_H */ diff --git a/src/task_order/EAGLE/task_order.h b/src/task_order/EAGLE/task_order.h new file mode 100644 index 0000000000000000000000000000000000000000..b3769d65e83b110ed7c3bfe2a957c02f747a30fe --- /dev/null +++ b/src/task_order/EAGLE/task_order.h @@ -0,0 +1,69 @@ +/******************************************************************************* + * This file is part of SWIFT. + * Copyright (c) 2019 Loic Hausammann (loic.hausammann@epfl.ch) + * + * 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_TASK_ORDER_EAGLE_H +#define SWIFT_TASK_ORDER_EAGLE_H + +/** + * Is the star-formation task running before the feedback task? + */ +#define task_order_star_formation_before_feedback 1 + +/** + * Is the cooling task running after the time-step calculation task? + */ +#define task_order_cooling_after_timestep 0 + +/** + * @brief Place the star formation cell at the right place in the dependency + * graph. + * + * In EAGLE, star formation takes place before the feedback tasks (that are + * launched after the stars_in task). + * + * @param s The #scheduler. + * @param c The #cell on which to act. + * @param star_resort_cell The #cell where the stars re-sorting task is in this + * hierarchy. + */ +INLINE static void task_order_addunlock_star_formation_feedback( + struct scheduler *s, struct cell *c, struct cell *star_resort_cell) { + + scheduler_addunlock(s, star_resort_cell->hydro.stars_resort, + c->stars.stars_in); +} + +/** + * @brief Place the cooling cell at the right place in the dependency + * graph. + * + * The default model follows EAGLE. + * + * In EAGLE, the cooling takes place between the hydro and the kick2. + * + * @param s The #scheduler. + * @param c The #cell on which to act. + */ +INLINE static void task_order_addunlock_cooling(struct scheduler *s, + struct cell *c) { + + scheduler_addunlock(s, c->hydro.end_force, c->hydro.cooling); + scheduler_addunlock(s, c->hydro.cooling, c->super->kick2); +} + +#endif /* SWIFT_TASK_ORDER_EAGLE_H */ diff --git a/src/task_order/GEAR/task_order.h b/src/task_order/GEAR/task_order.h new file mode 100644 index 0000000000000000000000000000000000000000..461068c6e459269e6f9a5bbf8fd39c0ff42ddc57 --- /dev/null +++ b/src/task_order/GEAR/task_order.h @@ -0,0 +1,66 @@ +/******************************************************************************* + * This file is part of SWIFT. + * Copyright (c) 2019 Loic Hausammann (loic.hausammann@epfl.ch) + * + * 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_TASK_ORDER_GEAR_H +#define SWIFT_TASK_ORDER_GEAR_H + +/** + * Is the star-formation task running before the feedback task? + */ +#define task_order_star_formation_before_feedback 0 + +/** + * Is the cooling task running after the time-step calculation task? + */ +#define task_order_cooling_after_timestep 1 + +/** + * @brief Place the star formation cell at the right place in the dependency + * graph. + * + * In GEAR, star formation takes place after the feedback tasks (that are + * finishing with the stars_out task). + * + * @param s The #scheduler. + * @param c The #cell on which to act. + * @param star_resort_cell The #cell where the stars re-sorting task is in this + * hierarchy. + */ +INLINE static void task_order_addunlock_star_formation_feedback( + struct scheduler *s, struct cell *c, struct cell *star_resort_cell) { + + scheduler_addunlock(s, c->stars.stars_out, c->top->hydro.star_formation); +} + +/** + * @brief Place the cooling cell at the right place in the dependency + * graph. + * + * In GEAR, the cooling takes place after the kick1. + * + * @param s The #scheduler. + * @param c The #cell on which to act. + */ +INLINE static void task_order_addunlock_cooling(struct scheduler *s, + struct cell *c) { + + scheduler_addunlock(s, c->super->kick1, c->hydro.cooling); + scheduler_addunlock(s, c->hydro.end_force, c->super->kick2); +} + +#endif /* SWIFT_TASK_ORDER_GEAR_H */ diff --git a/src/task_order/none/task_order.h b/src/task_order/none/task_order.h new file mode 100644 index 0000000000000000000000000000000000000000..826999f9dcccf222c67612c50ac3b3c81469b026 --- /dev/null +++ b/src/task_order/none/task_order.h @@ -0,0 +1,77 @@ +/******************************************************************************* + * This file is part of SWIFT. + * Copyright (c) 2019 Loic Hausammann (loic.hausammann@epfl.ch) + * + * 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_TASK_ORDER_NONE_H +#define SWIFT_TASK_ORDER_NONE_H + +/** + * @file task_order/none/task_order.h + * @brief Defines the order of the subgrid tasks when no subgrid model has + * been specified. Defaults to the EAGLE model. + */ + +/** + * Is the star-formation task running before the feedback task? + */ +#define task_order_star_formation_before_feedback 1 + +/** + * Is the cooling task running after the time-step calculation task? + */ +#define task_order_cooling_after_timestep 0 + +/** + * @brief Place the star formation cell at the right place in the dependency + * graph. + * + * The default model follows EAGLE. + * + * In EAGLE, star formation takes place before the feedback tasks (that are + * launched after the stars_in task). + * + * @param s The #scheduler. + * @param c The #cell on which to act. + * @param star_resort_cell The #cell where the stars re-sorting task is in this + * hierarchy. + */ +INLINE static void task_order_addunlock_star_formation_feedback( + struct scheduler *s, struct cell *c, struct cell *star_resort_cell) { + + scheduler_addunlock(s, star_resort_cell->hydro.stars_resort, + c->stars.stars_in); +} + +/** + * @brief Place the cooling cell at the right place in the dependency + * graph. + * + * The default model follows EAGLE. + * + * In EAGLE, the cooling takes place between the hydro and the kick2. + * + * @param s The #scheduler. + * @param c The #cell on which to act. + */ +INLINE static void task_order_addunlock_cooling(struct scheduler *s, + struct cell *c) { + + scheduler_addunlock(s, c->hydro.end_force, c->hydro.cooling); + scheduler_addunlock(s, c->hydro.cooling, c->super->kick2); +} + +#endif /* SWIFT_TASK_ORDER_NONE_H */ diff --git a/src/timeline.h b/src/timeline.h index a2bb8da6e8c5c92288541c206b453af141bf094e..25605614be2aa079e96176cb6f0a221c828f5e3d 100644 --- a/src/timeline.h +++ b/src/timeline.h @@ -45,10 +45,10 @@ typedef int8_t timebin_t; #define time_bin_not_created (num_time_bins + 3) /*! Fictitious time-bin for particles not awaken */ -#define time_bin_not_awake (0) +#define time_bin_not_awake (-num_time_bins) -/*! Fictitious time-bin for particles woken up */ -#define time_bin_awake (-1) +/* Maximal difference in time-bins between neighbouring particles */ +#define time_bin_neighbour_max_delta_bin 2 /** * @brief Returns the integer time interval corresponding to a time bin diff --git a/src/timestep.h b/src/timestep.h index cd9faaea612c8a666ae9077ccc5e3d85fd4677f9..24e0a02cb64183b6df8daa608dca03dae514d7bd 100644 --- a/src/timestep.h +++ b/src/timestep.h @@ -30,21 +30,35 @@ /** * @brief Compute a valid integer time-step form a given time-step * + * We consider the minimal time-bin of any neighbours and prevent particles + * to differ from it by a fixed constant `time_bin_neighbour_max_delta_bin`. + * + * If min_ngb_bin is set to `num_time_bins`, then no limit from the neighbours + * is imposed. + * * @param new_dt The time-step to convert. * @param old_bin The old time bin. + * @param min_ngb_bin Minimal time-bin of any neighbour of this particle. * @param ti_current The current time on the integer time-line. * @param time_base_inv The inverse of the system's minimal time-step. */ -__attribute__((always_inline)) INLINE static integertime_t -make_integer_timestep(float new_dt, timebin_t old_bin, integertime_t ti_current, - double time_base_inv) { +__attribute__((always_inline, const)) INLINE static integertime_t +make_integer_timestep(const float new_dt, const timebin_t old_bin, + const timebin_t min_ngb_bin, + const integertime_t ti_current, + const double time_base_inv) { /* Convert to integer time */ integertime_t new_dti = (integertime_t)(new_dt * time_base_inv); + /* Are we allowed to use this bin given the neighbours? */ + timebin_t new_bin = get_time_bin(new_dti); + new_bin = min(new_bin, min_ngb_bin + time_bin_neighbour_max_delta_bin); + new_dti = get_integer_timestep(new_bin); + /* Current time-step */ - integertime_t current_dti = get_integer_timestep(old_bin); - integertime_t ti_end = get_integer_time_end(ti_current, old_bin); + const integertime_t current_dti = get_integer_timestep(old_bin); + const integertime_t ti_end = get_integer_time_end(ti_current, old_bin); /* Limit timestep increase */ if (old_bin > 0) new_dti = min(new_dti, 2 * current_dti); @@ -103,7 +117,7 @@ __attribute__((always_inline)) INLINE static integertime_t get_gpart_timestep( /* Convert to integer time */ const integertime_t new_dti = make_integer_timestep( - new_dt, gp->time_bin, e->ti_current, e->time_base_inv); + new_dt, gp->time_bin, num_time_bins, e->ti_current, e->time_base_inv); return new_dti; } @@ -178,7 +192,8 @@ __attribute__((always_inline)) INLINE static integertime_t get_part_timestep( /* Convert to integer time */ const integertime_t new_dti = make_integer_timestep( - new_dt, p->time_bin, e->ti_current, e->time_base_inv); + new_dt, p->time_bin, p->limiter_data.min_ngb_time_bin, e->ti_current, + e->time_base_inv); return new_dti; } @@ -225,7 +240,7 @@ __attribute__((always_inline)) INLINE static integertime_t get_spart_timestep( /* Convert to integer time */ const integertime_t new_dti = make_integer_timestep( - new_dt, sp->time_bin, e->ti_current, e->time_base_inv); + new_dt, sp->time_bin, num_time_bins, e->ti_current, e->time_base_inv); return new_dti; } @@ -272,7 +287,7 @@ __attribute__((always_inline)) INLINE static integertime_t get_bpart_timestep( /* Convert to integer time */ const integertime_t new_dti = make_integer_timestep( - new_dt, bp->time_bin, e->ti_current, e->time_base_inv); + new_dt, bp->time_bin, num_time_bins, e->ti_current, e->time_base_inv); return new_dti; } diff --git a/src/timestep_limiter.h b/src/timestep_limiter.h index 01b72daea5599b662c38fdc4b3ada8b2ac5b3d11..8aa081ecc46adcd91f98f7f8165590050d421530 100644 --- a/src/timestep_limiter.h +++ b/src/timestep_limiter.h @@ -25,6 +25,32 @@ /* Local headers. */ #include "kick.h" +/** + * @brief Prepare the limiter-quantities for a hydro force calculation. + * + * @param p The #part. + * @param xp The #xpart. + */ +__attribute__((always_inline)) INLINE static void +timestep_limiter_prepare_force(struct part *restrict p, + struct xpart *restrict xp) { + + p->limiter_data.min_ngb_time_bin = num_time_bins + 1; +} + +/** + * @brief Terminate the limiter-quantities after a hydro force calculation. + * + * @param p The #part. + */ +__attribute__((always_inline)) INLINE static void timestep_limiter_end_force( + struct part *restrict p) { +#ifdef SWIFT_DEBUG_CHECKS + if (p->limiter_data.min_ngb_time_bin == 0) + error("Minimal time-bin of neighbours is 0"); +#endif +} + /** * @brief Wakes up a particle by rewinding it's kick1 back in time and applying * a new one such that the particle becomes active again in the next time-step. @@ -32,6 +58,8 @@ * @param p The #part to update. * @param xp Its #xpart companion. * @param e The #engine (to extract time-line information). + * + * @return The updated integer end-of-step of the particle. */ __attribute__((always_inline)) INLINE static integertime_t timestep_limit_part( struct part *restrict p, struct xpart *restrict xp, @@ -40,109 +68,157 @@ __attribute__((always_inline)) INLINE static integertime_t timestep_limit_part( const struct cosmology *cosmo = e->cosmology; const int with_cosmology = e->policy & engine_policy_cosmology; const double time_base = e->time_base; + const integertime_t ti_current = e->ti_current; - integertime_t old_ti_beg, old_ti_end; - timebin_t old_time_bin; + if (part_is_active(p, e)) { - /* Let's see when this particle started and used to end */ - if (p->wakeup == time_bin_awake) { + /* First case, the particle was active so we only need to update the length + of its next time-step */ - /* Normal case */ - old_ti_beg = get_integer_time_begin(e->ti_current, p->time_bin); - old_ti_end = get_integer_time_end(e->ti_current, p->time_bin); - old_time_bin = p->time_bin; - } else { + /* New time-bin of this particle */ + p->time_bin = -p->limiter_data.wakeup + 2; - /* Particle that was limited in the previous step already */ - old_ti_beg = get_integer_time_begin(e->ti_current, -p->wakeup); - old_ti_end = get_integer_time_end(e->ti_current, p->time_bin); - old_time_bin = -p->wakeup; - } + /* Mark the particle as being rady to be time integrated */ + p->limiter_data.wakeup = time_bin_not_awake; - const integertime_t old_dti = old_ti_end - old_ti_beg; + /* Return the new end-of-step for this particle */ + return ti_current + get_integer_timestep(p->time_bin); - /* The new fake time-step the particle will be on */ - const integertime_t new_fake_ti_step = - get_integer_timestep(e->min_active_bin); + } else { - /* The actual time-step size this particle will use */ - const integertime_t new_ti_beg = old_ti_beg; - const integertime_t new_ti_end = e->ti_current + new_fake_ti_step; - const integertime_t new_dti = new_ti_end - new_ti_beg; + /* Second case, the particle was inactive so we need to interrupt its + time-step, undo the "kick" operator and assign a new time-step size */ -#ifdef SWIFT_DEBUG_CHECKS - /* Some basic safety checks */ - if (old_ti_beg >= e->ti_current) - error( - "Incorrect value for old time-step beginning ti_current=%lld, " - "old_ti_beg=%lld", - e->ti_current, old_ti_beg); + /* The timebins to play with */ + const timebin_t old_bin = p->time_bin; + const timebin_t new_bin = -p->limiter_data.wakeup + 2; - if (old_ti_end <= e->ti_current) - error( - "Incorrect value for old time-step end ti_current=%lld, " - "old_ti_end=%lld", - e->ti_current, old_ti_end); + /* Current start and end time of this particle */ + const integertime_t ti_beg_old = + get_integer_time_begin(ti_current, old_bin); + const integertime_t ti_end_old = get_integer_time_end(ti_current, old_bin); - if (new_ti_end > old_ti_end) error("New end of time-step after the old one"); + /* Length of the old and new time-step */ + const integertime_t dti_old = ti_end_old - ti_beg_old; + const integertime_t dti_new = get_integer_timestep(new_bin); - if (new_dti > old_dti) error("New time-step larger than old one"); + /* Let's now search for the starting point of the new step */ + int k = 0; + while (ti_beg_old + k * dti_new <= ti_current) k++; - if (new_fake_ti_step == 0) error("Wakeup call too early"); -#endif + const integertime_t ti_beg_new = ti_beg_old + (k - 1) * dti_new; - double dt_kick_grav = 0., dt_kick_hydro = 0., dt_kick_therm = 0., - dt_kick_corr = 0.; - - /* Now we need to reverse the kick1... (the dt are negative here) */ - if (with_cosmology) { - dt_kick_hydro = -cosmology_get_hydro_kick_factor(cosmo, old_ti_beg, - old_ti_beg + old_dti / 2); - dt_kick_grav = -cosmology_get_grav_kick_factor(cosmo, old_ti_beg, - old_ti_beg + old_dti / 2); - dt_kick_therm = -cosmology_get_therm_kick_factor(cosmo, old_ti_beg, - old_ti_beg + old_dti / 2); - dt_kick_corr = -cosmology_get_corr_kick_factor(cosmo, old_ti_beg, - old_ti_beg + old_dti / 2); - } else { - dt_kick_hydro = -(old_dti / 2) * time_base; - dt_kick_grav = -(old_dti / 2) * time_base; - dt_kick_therm = -(old_dti / 2) * time_base; - dt_kick_corr = -(old_dti / 2) * time_base; - } +#ifdef SWIFT_DEBUG_CHECKS + /* Some basic safety checks */ + if (ti_beg_old >= e->ti_current) + error( + "Incorrect value for old time-step beginning ti_current=%lld, " + "ti_beg_old=%lld", + e->ti_current, ti_beg_old); + + if (ti_end_old <= e->ti_current) + error( + "Incorrect value for old time-step end ti_current=%lld, " + "ti_end_old=%lld", + e->ti_current, ti_end_old); + + if (ti_beg_new < ti_beg_old) + error("New beg of time-step before the old one"); + + if (dti_new > dti_old) error("New time-step larger than old one"); +#endif - kick_part(p, xp, dt_kick_hydro, dt_kick_grav, dt_kick_therm, dt_kick_corr, - e->cosmology, e->hydro_properties, e->entropy_floor, - old_ti_beg + old_dti / 2, old_ti_beg); - - /* ...and apply the new one (dt is positiive) */ - if (with_cosmology) { - dt_kick_hydro = cosmology_get_hydro_kick_factor(cosmo, new_ti_beg, - new_ti_beg + new_dti / 2); - dt_kick_grav = cosmology_get_grav_kick_factor(cosmo, new_ti_beg, - new_ti_beg + new_dti / 2); - dt_kick_therm = cosmology_get_therm_kick_factor(cosmo, new_ti_beg, - new_ti_beg + new_dti / 2); - dt_kick_corr = cosmology_get_corr_kick_factor(cosmo, new_ti_beg, - new_ti_beg + new_dti / 2); - } else { - dt_kick_hydro = (new_dti / 2) * time_base; - dt_kick_grav = (new_dti / 2) * time_base; - dt_kick_therm = (new_dti / 2) * time_base; - dt_kick_corr = (new_dti / 2) * time_base; + double dt_kick_grav = 0., dt_kick_hydro = 0., dt_kick_therm = 0., + dt_kick_corr = 0.; + + /* Now we need to reverse the kick1... (the dt are negative here) */ + if (with_cosmology) { + dt_kick_hydro = -cosmology_get_hydro_kick_factor( + cosmo, ti_beg_old, ti_beg_old + dti_old / 2); + dt_kick_grav = -cosmology_get_grav_kick_factor(cosmo, ti_beg_old, + ti_beg_old + dti_old / 2); + dt_kick_therm = -cosmology_get_therm_kick_factor( + cosmo, ti_beg_old, ti_beg_old + dti_old / 2); + dt_kick_corr = -cosmology_get_corr_kick_factor(cosmo, ti_beg_old, + ti_beg_old + dti_old / 2); + } else { + dt_kick_hydro = -(dti_old / 2) * time_base; + dt_kick_grav = -(dti_old / 2) * time_base; + dt_kick_therm = -(dti_old / 2) * time_base; + dt_kick_corr = -(dti_old / 2) * time_base; + } + + kick_part(p, xp, dt_kick_hydro, dt_kick_grav, dt_kick_therm, dt_kick_corr, + e->cosmology, e->hydro_properties, e->entropy_floor, + ti_beg_old + dti_old / 2, ti_beg_old); + + /* ...and apply the new one (dt is positiive). + * This brings us to the current time. */ + if (with_cosmology) { + dt_kick_hydro = cosmology_get_hydro_kick_factor(cosmo, ti_beg_new, + ti_beg_new + dti_new / 2); + dt_kick_grav = cosmology_get_grav_kick_factor(cosmo, ti_beg_new, + ti_beg_new + dti_new / 2); + dt_kick_therm = cosmology_get_therm_kick_factor(cosmo, ti_beg_new, + ti_beg_new + dti_new / 2); + dt_kick_corr = cosmology_get_corr_kick_factor(cosmo, ti_beg_new, + ti_beg_new + dti_new / 2); + } else { + dt_kick_hydro = (ti_beg_new - ti_beg_old) * time_base; + dt_kick_grav = (ti_beg_new - ti_beg_old) * time_base; + dt_kick_therm = (ti_beg_new - ti_beg_old) * time_base; + dt_kick_corr = (ti_beg_new - ti_beg_old) * time_base; + } + + kick_part(p, xp, dt_kick_hydro, dt_kick_grav, dt_kick_therm, dt_kick_corr, + e->cosmology, e->hydro_properties, e->entropy_floor, ti_beg_old, + ti_beg_new); + + /* The particle has now been kicked to the current time */ + + /* New time-bin of this particle */ + p->time_bin = new_bin; + + /* Mark the particle as being ready to be time integrated */ + p->limiter_data.wakeup = time_bin_not_awake; + + /* Do we need to apply the mising kick1 or is this bin active and + it will be done in the kick task? */ + if (new_bin > e->max_active_bin) { + + /* Apply the missing kick1 */ + + if (with_cosmology) { + dt_kick_hydro = cosmology_get_hydro_kick_factor( + cosmo, ti_beg_new, ti_beg_new + dti_new / 2); + dt_kick_grav = cosmology_get_grav_kick_factor(cosmo, ti_beg_new, + ti_beg_new + dti_new / 2); + dt_kick_therm = cosmology_get_therm_kick_factor( + cosmo, ti_beg_new, ti_beg_new + dti_new / 2); + dt_kick_corr = cosmology_get_corr_kick_factor(cosmo, ti_beg_new, + ti_beg_new + dti_new / 2); + } else { + dt_kick_hydro = (dti_new / 2) * time_base; + dt_kick_grav = (dti_new / 2) * time_base; + dt_kick_therm = (dti_new / 2) * time_base; + dt_kick_corr = (dti_new / 2) * time_base; + } + + kick_part(p, xp, dt_kick_hydro, dt_kick_grav, dt_kick_therm, dt_kick_corr, + e->cosmology, e->hydro_properties, e->entropy_floor, ti_beg_new, + ti_beg_new + dti_new / 2); + + /* Return the new end-of-step for this particle */ + return ti_beg_new + dti_new; + + } else { + + /* No kick to do here */ + + /* Return the new end-of-step for this particle */ + return ti_current + get_integer_timestep(p->time_bin); + } } - - kick_part(p, xp, dt_kick_hydro, dt_kick_grav, dt_kick_therm, dt_kick_corr, - e->cosmology, e->hydro_properties, e->entropy_floor, new_ti_beg, - new_ti_beg + new_dti / 2); - - /* Remember the old time-bin */ - p->wakeup = old_time_bin; - - /* Update the time bin of this particle */ - p->time_bin = e->min_active_bin; - - return new_fake_ti_step; } #endif /* SWIFT_TIMESTEP_LIMITER_H */ diff --git a/src/timestep_limiter_iact.h b/src/timestep_limiter_iact.h new file mode 100644 index 0000000000000000000000000000000000000000..a4f5c7c1af48db7f6926f0fac1c09a4db2a0c492 --- /dev/null +++ b/src/timestep_limiter_iact.h @@ -0,0 +1,95 @@ +/******************************************************************************* + * 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_TIMESTEP_LIMITER_IACT_H +#define SWIFT_TIMESTEP_LIMITER_IACT_H + +/** + * @brief Force interaction between two particles. + * + * @param r2 Comoving square distance between the two particles. + * @param dx Comoving vector separating both particles (pi - pj). + * @param hi Comoving smoothing-length of particle i. + * @param hj Comoving smoothing-length of particle j. + * @param pi First particle. + * @param pj Second particle. + * @param a Current scale factor. + * @param H Current Hubble parameter. + */ +__attribute__((always_inline)) INLINE static void runner_iact_timebin( + float r2, const float *dx, float hi, float hj, struct part *restrict pi, + struct part *restrict pj, float a, float H) { + + /* Update the minimal time-bin */ + if (pj->time_bin > 0) + pi->limiter_data.min_ngb_time_bin = + min(pi->limiter_data.min_ngb_time_bin, pj->time_bin); + + if (pi->time_bin > 0) + pj->limiter_data.min_ngb_time_bin = + min(pj->limiter_data.min_ngb_time_bin, pi->time_bin); +} + +/** + * @brief Timebin interaction between two particles (non-symmetric). + * + * @param r2 Comoving square distance between the two particles. + * @param dx Comoving vector separating both particles (pi - pj). + * @param hi Comoving smoothing-length of particle i. + * @param hj Comoving smoothing-length of particle j. + * @param pi First particle. + * @param pj Second particle (not updated). + * @param a Current scale factor. + * @param H Current Hubble parameter. + */ +__attribute__((always_inline)) INLINE static void runner_iact_nonsym_timebin( + float r2, const float *dx, float hi, float hj, struct part *restrict pi, + const struct part *restrict pj, float a, float H) { + + /* Update the minimal time-bin */ + if (pj->time_bin > 0) + pi->limiter_data.min_ngb_time_bin = + min(pi->limiter_data.min_ngb_time_bin, pj->time_bin); +} + +/** + * @brief Timestep limiter loop + */ +__attribute__((always_inline)) INLINE static void runner_iact_limiter( + float r2, const float *dx, float hi, float hj, struct part *restrict pi, + struct part *restrict pj, float a, float H) { + + /* Nothing to do here if both particles are active */ +} + +/** + * @brief Timestep limiter loop (non-symmetric version) + */ +__attribute__((always_inline)) INLINE static void runner_iact_nonsym_limiter( + float r2, const float *dx, float hi, float hj, struct part *restrict pi, + struct part *restrict pj, float a, float H) { + + /* Wake up the neighbour? */ + if (pj->time_bin > pi->time_bin + time_bin_neighbour_max_delta_bin) { + + /* Store the smallest time bin that woke up this particle */ + pj->limiter_data.wakeup = max(pj->limiter_data.wakeup, -pi->time_bin); + } +} + +#endif /* SWIFT_TIMESTEP_LIMITER_IACT_H */ diff --git a/src/timestep_limiter_struct.h b/src/timestep_limiter_struct.h new file mode 100644 index 0000000000000000000000000000000000000000..7f63a6e7920344dcac0d11b1e95e4b0842930976 --- /dev/null +++ b/src/timestep_limiter_struct.h @@ -0,0 +1,48 @@ +/******************************************************************************* + * 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_TIMESTEP_LIMITER_STRUCT_H +#define SWIFT_TIMESTEP_LIMITER_STRUCT_H + +/** + * @file src/chemistry_struct.h + * @brief Branches between the different chemistry functions. + */ + +/* Config parameters. */ +#include "../config.h" + +/* Local includes */ +#include "timeline.h" + +/** + * @brief #part-carried quantities for the time-step limiter + */ +struct timestep_limiter_data { + + /* Need waking-up ? */ + timebin_t wakeup; + + /*! Minimal time-bin across all neighbours */ + timebin_t min_ngb_time_bin; + + /* Do we want this particle to be synched back on the time-line? */ + char to_be_synchronized; +}; + +#endif /* SWIFT_TIMESTEP_LIMITER_STRUCT_H */ diff --git a/src/timestep_sync.h b/src/timestep_sync.h new file mode 100644 index 0000000000000000000000000000000000000000..f40aeb580c199eba85bdee04737def819a9f5106 --- /dev/null +++ b/src/timestep_sync.h @@ -0,0 +1,147 @@ +/******************************************************************************* + * 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_TIMESTEP_SYNC_H +#define SWIFT_TIMESTEP_SYNC_H + +/* Config parameters. */ +#include "../config.h" + +/* Local includes */ +#include "engine.h" +#include "kick.h" + +/** + * @brief Processes a particle that has been flagged for synchronization on the + * time-line. + * + * We revert the particle's kick and apply a new one that ends at the current + * time. The particle is then ready to compute a new time-step and proceed with + * a regular kick1. + * + * @param p The #part. + * @param xp The #xpart. + * @param e The #engine. + * @param cosmo The cosmology model. + */ +INLINE static void timestep_process_sync_part(struct part *p, struct xpart *xp, + const struct engine *e, + const struct cosmology *cosmo) { + + const int with_cosmology = (e->policy & engine_policy_cosmology); + const integertime_t ti_current = e->ti_current; + const timebin_t max_active_bin = e->max_active_bin; + const timebin_t min_active_bin = e->min_active_bin; + const double time_base = e->time_base; + + p->limiter_data.to_be_synchronized = 0; + + /* This particle is already active. Nothing to do here... */ + if (p->time_bin <= max_active_bin) { + return; + } + + // message(" Synchronizing particle! %lld old bin=%d", p->id, p->time_bin); + + /* We want to make the particle finish it's time-step now. */ + + /* Start by recovering the start and end point of the particle's time-step. */ + const integertime_t old_ti_beg = + get_integer_time_begin(ti_current, p->time_bin); + const integertime_t old_ti_end = + get_integer_time_end(ti_current, p->time_bin); + + /* Old time-step length on the time-line */ + const integertime_t old_dti = old_ti_end - old_ti_beg; + + /* The actual time-step size this particle will use */ + const integertime_t new_ti_beg = old_ti_beg; + const integertime_t new_ti_end = ti_current; + const integertime_t new_dti = new_ti_end - new_ti_beg; + +#ifdef SWIFT_DEBUG_CHECKS + /* Some basic safety checks */ + if (old_ti_beg >= ti_current) + error( + "Incorrect value for old time-step beginning ti_current=%lld, " + "old_ti_beg=%lld", + ti_current, old_ti_beg); + + if (old_ti_end <= ti_current) + error( + "Incorrect value for old time-step end ti_current=%lld, " + "old_ti_end=%lld", + ti_current, old_ti_end); + + if (new_ti_end > old_ti_end) error("New end of time-step after the old one"); + + if (new_dti > old_dti) error("New time-step larger than old one"); +#endif + + double dt_kick_grav = 0., dt_kick_hydro = 0., dt_kick_therm = 0., + dt_kick_corr = 0.; + + /* Now we need to reverse the kick1... (the dt are negative here) */ + if (with_cosmology) { + dt_kick_hydro = -cosmology_get_hydro_kick_factor(cosmo, old_ti_beg, + old_ti_beg + old_dti / 2); + dt_kick_grav = -cosmology_get_grav_kick_factor(cosmo, old_ti_beg, + old_ti_beg + old_dti / 2); + dt_kick_therm = -cosmology_get_therm_kick_factor(cosmo, old_ti_beg, + old_ti_beg + old_dti / 2); + dt_kick_corr = -cosmology_get_corr_kick_factor(cosmo, old_ti_beg, + old_ti_beg + old_dti / 2); + } else { + dt_kick_hydro = -(old_dti / 2) * time_base; + dt_kick_grav = -(old_dti / 2) * time_base; + dt_kick_therm = -(old_dti / 2) * time_base; + dt_kick_corr = -(old_dti / 2) * time_base; + } + + kick_part(p, xp, dt_kick_hydro, dt_kick_grav, dt_kick_therm, dt_kick_corr, + e->cosmology, e->hydro_properties, e->entropy_floor, + old_ti_beg + old_dti / 2, old_ti_beg); + + /* We can now produce a kick to the current point */ + if (with_cosmology) { + dt_kick_hydro = cosmology_get_hydro_kick_factor(cosmo, new_ti_beg, + new_ti_beg + new_dti); + dt_kick_grav = + cosmology_get_grav_kick_factor(cosmo, old_ti_beg, new_ti_beg + new_dti); + dt_kick_therm = cosmology_get_therm_kick_factor(cosmo, old_ti_beg, + new_ti_beg + new_dti); + dt_kick_corr = + cosmology_get_corr_kick_factor(cosmo, old_ti_beg, new_ti_beg + new_dti); + } else { + dt_kick_hydro = (new_dti)*time_base; + dt_kick_grav = (new_dti)*time_base; + dt_kick_therm = (new_dti)*time_base; + dt_kick_corr = (new_dti)*time_base; + } + + kick_part(p, xp, dt_kick_hydro, dt_kick_grav, dt_kick_therm, dt_kick_corr, + e->cosmology, e->hydro_properties, e->entropy_floor, new_ti_beg, + new_ti_beg + new_dti); + + /* The particle is now ready to compute its new time-step size and for the + * next kick */ + p->time_bin = -min_active_bin; + p->limiter_data.wakeup = time_bin_not_awake; +} + +#endif /* SWIFT_TIMESTEP_SYNC_H */ diff --git a/src/timestep_sync_part.h b/src/timestep_sync_part.h new file mode 100644 index 0000000000000000000000000000000000000000..09042158f85ee3c68ee9cfae9eeff000b9478bf3 --- /dev/null +++ b/src/timestep_sync_part.h @@ -0,0 +1,36 @@ +/******************************************************************************* + * 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_TIMESTEP_SYNC_PART_H +#define SWIFT_TIMESTEP_SYNC_PART_H + +/* Config parameters. */ +#include "../config.h" + +/** + * @brief Flag a particle for synchronization on the time-line. + * + * @param p The #part. + */ +__attribute__((always_inline)) INLINE static void timestep_sync_part( + struct part *p) { + + p->limiter_data.to_be_synchronized = 1; +} + +#endif /* SWIFT_TIMESTEP_SYNC_PART_H */ diff --git a/src/tracers/EAGLE/tracers.h b/src/tracers/EAGLE/tracers.h index 706a8ad9916bec287ad7aad4853b063d44cc37da..57947b37f0c3c85a37ca0d6e24a9575d58348b80 100644 --- a/src/tracers/EAGLE/tracers.h +++ b/src/tracers/EAGLE/tracers.h @@ -113,10 +113,7 @@ static INLINE void tracers_after_timestep( } /** - * @brief Update the particle tracers just after its time-step has been - * computed. - * - * Set the maximal temperature to a valid initial state + * @brief Initialise the tracer data at the start of a calculation. * * @param p Pointer to the particle data. * @param xp Pointer to the extended particle data (containing the tracers @@ -135,6 +132,42 @@ static INLINE void tracers_first_init_xpart( xp->tracers_data.maximum_temperature = -1.f; xp->tracers_data.maximum_temperature_time = -1.f; + xp->tracers_data.hit_by_SNII_feedback = 0; + xp->tracers_data.hit_by_AGN_feedback = 0; +} + +/** + * @brief Update the particles' tracer data after a stellar feedback + * event. + * + * @param xp The extended particle data. + */ +static INLINE void tracers_after_feedback(struct xpart *xp) { + + xp->tracers_data.hit_by_SNII_feedback = 1; +} + +/** + * @brief Update the particles' tracer data after an AGN feedback + * event. + * + * @param xp The extended particle data. + */ +static INLINE void tracers_after_black_holes_feedback(struct xpart *xp) { + + xp->tracers_data.hit_by_AGN_feedback = 1; } +/** + * @brief Split the tracer content of a particle into n pieces + * + * Nothing to do here. + * + * @param p The #part. + * @param xp The #xpart. + * @param n The number of pieces to split into. + */ +__attribute__((always_inline)) INLINE static void tracers_split_part( + struct part *p, struct xpart *xp, const double n) {} + #endif /* SWIFT_TRACERS_EAGLE_H */ diff --git a/src/tracers/EAGLE/tracers_io.h b/src/tracers/EAGLE/tracers_io.h index e058a02749a86f12838268af1aa719c9bc0cdeeb..d4c10d8a8831248d5754acf0fd290be976c78db6 100644 --- a/src/tracers/EAGLE/tracers_io.h +++ b/src/tracers/EAGLE/tracers_io.h @@ -73,7 +73,19 @@ __attribute__((always_inline)) INLINE static int tracers_write_particles( "Times at which the maximal temperature was reached"); } - return 2; + list[2] = + io_make_output_field("HeatedBySNIIFeedback", CHAR, 1, UNIT_CONV_NO_UNITS, + 0.f, xparts, tracers_data.hit_by_SNII_feedback, + "Flags the particles that have been directly hit by " + "a SNII feedback event at some point in the past."); + + list[3] = + io_make_output_field("HeatedByAGNFeedback", CHAR, 1, UNIT_CONV_NO_UNITS, + 0.f, xparts, tracers_data.hit_by_AGN_feedback, + "Flags the particles that have been directly hit by " + "an AGN feedback event at some point in the past."); + + return 4; } __attribute__((always_inline)) INLINE static int tracers_write_sparticles( @@ -100,7 +112,21 @@ __attribute__((always_inline)) INLINE static int tracers_write_sparticles( "Times at which the maximal temperature was reached"); } - return 2; + list[2] = + io_make_output_field("HeatedBySNIIFeedback", CHAR, 1, UNIT_CONV_NO_UNITS, + 0.f, sparts, tracers_data.hit_by_SNII_feedback, + "Flags the particles that have been directly hit by " + "a SNII feedback event at some point in the past " + "when the particle was still a gas particle."); + + list[3] = + io_make_output_field("HeatedByAGNFeedback", CHAR, 1, UNIT_CONV_NO_UNITS, + 0.f, sparts, tracers_data.hit_by_AGN_feedback, + "Flags the particles that have been directly hit by " + "an AGN feedback event at some point in the past " + "when the particle was still a gas particle."); + + return 4; } #endif /* SWIFT_TRACERS_EAGLE_IO_H */ diff --git a/src/tracers/EAGLE/tracers_struct.h b/src/tracers/EAGLE/tracers_struct.h index d893c85bcb65b625743f3cec603560d65efa472d..9d1e233130b9149f66263d6ce8e577ccbf69c845 100644 --- a/src/tracers/EAGLE/tracers_struct.h +++ b/src/tracers/EAGLE/tracers_struct.h @@ -36,6 +36,12 @@ struct tracers_xpart_data { /*! Time at which the maximal temperature was reached */ float maximum_temperature_time; }; + + /*! Has this particle been hit by SNII feedback? */ + char hit_by_SNII_feedback; + + /*! Has this particle been hit by AGN feedback? */ + char hit_by_AGN_feedback; }; #endif /* SWIFT_TRACERS_STRUCT_EAGLE_H */ diff --git a/src/tracers/none/tracers.h b/src/tracers/none/tracers.h index 4cf2fb4ad4380139a392d5d76a0f78162aa6eac9..99bf395b92dbc5185c2aee1e26f41c38971797c7 100644 --- a/src/tracers/none/tracers.h +++ b/src/tracers/none/tracers.h @@ -90,10 +90,7 @@ static INLINE void tracers_after_timestep( const struct cooling_function_data *cooling, const double time) {} /** - * @brief Update the particle tracers just after its time-step has been - * computed. - * - * Nothing to do here in the EAGLE model. + * @brief Initialise the tracer data at the start of a calculation. * * @param us The internal system of units. * @param phys_const The physical constants in internal units. @@ -110,4 +107,35 @@ static INLINE void tracers_first_init_xpart( const struct hydro_props *hydro_props, const struct cooling_function_data *cooling) {} +/** + * @brief Update the particles' tracer data after a stellar feedback + * event. + * + * Nothing to do here. + * + * @param xp The extended particle data. + */ +static INLINE void tracers_after_feedback(struct xpart *xp) {} + +/** + * @brief Update the particles' tracer data after an AGN feedback + * event. + * + * Nothing to do here. + * + * @param xp The extended particle data. + */ +static INLINE void tracers_after_black_holes_feedback(struct xpart *xp) {} + +/** + * @brief Split the tracer content of a particle into n pieces + * + * Nothing to do here. + * + * @param p The #part. + * @param xp The #xpart. + * @param n The number of pieces to split into. + */ +__attribute__((always_inline)) INLINE static void tracers_split_part( + struct part *p, struct xpart *xp, const double n) {} #endif /* SWIFT_TRACERS_NONE_H */ diff --git a/src/units.c b/src/units.c index c7fe549aff5d8cbcec77814f40f0682bd0fc3a8c..ca9e61a29403fce4963a3907df8a5f2948f5bb6f 100644 --- a/src/units.c +++ b/src/units.c @@ -279,6 +279,18 @@ void units_get_base_unit_exponents_array(float baseUnitsExp[5], baseUnitsExp[UNIT_TIME] = -2.f; break; + case UNIT_CONV_MOMENTUM: + baseUnitsExp[UNIT_MASS] = 1.f; + baseUnitsExp[UNIT_LENGTH] = 1.f; + baseUnitsExp[UNIT_TIME] = -1.f; + break; + + case UNIT_CONV_ANGULAR_MOMENTUM: + baseUnitsExp[UNIT_MASS] = 1.f; + baseUnitsExp[UNIT_LENGTH] = 2.f; + baseUnitsExp[UNIT_TIME] = -1.f; + break; + case UNIT_CONV_FORCE: baseUnitsExp[UNIT_MASS] = 1.f; baseUnitsExp[UNIT_LENGTH] = 1.f; diff --git a/src/units.h b/src/units.h index 4769fa80edbe0c10fd24e064528251e551282153..c1a47556df2cc78c872a24fb780ddc321605d099 100644 --- a/src/units.h +++ b/src/units.h @@ -76,6 +76,8 @@ enum unit_conversion_factor { UNIT_CONV_VELOCITY, UNIT_CONV_ACCELERATION, UNIT_CONV_POTENTIAL, + UNIT_CONV_MOMENTUM, + UNIT_CONV_ANGULAR_MOMENTUM, UNIT_CONV_FORCE, UNIT_CONV_ENERGY, UNIT_CONV_ENERGY_PER_UNIT_MASS, diff --git a/src/velociraptor_interface.c b/src/velociraptor_interface.c index 8cb65f6ac13fb6d4f813d68656363640b082123f..6f6f76bc12ea9a78fd661fe8664c054e500c2576 100644 --- a/src/velociraptor_interface.c +++ b/src/velociraptor_interface.c @@ -21,6 +21,10 @@ #include "../config.h" /* Some standard headers. */ +#include <stdio.h> +#include <string.h> +#include <sys/stat.h> +#include <sys/types.h> #include <unistd.h> /* This object's header. */ @@ -483,11 +487,19 @@ void velociraptor_invoke(struct engine *e, const int linked_with_snap) { MPI_COMM_WORLD); #endif + const double Omega_m = e->cosmology->Omega_m; + const double Omega_b = e->cosmology->Omega_b; + const double critical_density_0 = e->cosmology->critical_density_0; + /* Linking length based on the mean DM inter-particle separation * in the zoom region and assuming the mean density of the Universe * is used in the zoom region. */ - const double mean_matter_density = - e->cosmology->Omega_m * e->cosmology->critical_density_0; + double mean_matter_density; + if (s->with_hydro) + mean_matter_density = (Omega_m - Omega_b) * critical_density_0; + else + mean_matter_density = Omega_m * critical_density_0; + sim_info.interparticlespacing = cbrt(high_res_DM_mass / mean_matter_density); @@ -558,25 +570,51 @@ void velociraptor_invoke(struct engine *e, const int linked_with_snap) { "VELOCIraptor conf: MPI rank %d sending %zu gparts to VELOCIraptor.", engine_rank, nr_gparts); - /* Append base name with the current output number */ - char outputFileName[PARSER_MAX_LINE_SIZE + 128]; + /* Generate directory name for this output - start with snapshot directory, if + * specified */ + char outputDirName[FILENAME_BUFFER_SIZE] = ""; + if (strnlen(e->snapshot_subdir, PARSER_MAX_LINE_SIZE) > 0) { + if (snprintf(outputDirName, FILENAME_BUFFER_SIZE, "%s/", + e->snapshot_subdir) >= FILENAME_BUFFER_SIZE) { + error("FILENAME_BUFFER_SIZE is to small for snapshot directory name!"); + } +#ifdef WITH_MPI + if (engine_rank == 0) mkdir(outputDirName, 0777); + MPI_Barrier(MPI_COMM_WORLD); +#else + mkdir(outputDirName, 0777); +#endif + } - /* What should the filename be? */ - if (linked_with_snap) { - snprintf(outputFileName, PARSER_MAX_LINE_SIZE + 128, - "stf_%s_%04i.VELOCIraptor", e->snapshot_base_name, - e->snapshot_output_count); + /* Then create output-specific subdirectory if necessary */ + char subDirName[FILENAME_BUFFER_SIZE] = ""; + if (strnlen(e->stf_subdir_per_output, PARSER_MAX_LINE_SIZE) > 0) { + if (snprintf(subDirName, FILENAME_BUFFER_SIZE, "%s%s_%04i/", outputDirName, + e->stf_subdir_per_output, + e->snapshot_output_count) >= FILENAME_BUFFER_SIZE) { + error( + "FILENAME_BUFFER_SIZE is to small for Velociraptor directory name!"); + } +#ifdef WITH_MPI + if (engine_rank == 0) mkdir(subDirName, 0777); + MPI_Barrier(MPI_COMM_WORLD); +#else + mkdir(subDirName, 0777); +#endif } else { - snprintf(outputFileName, PARSER_MAX_LINE_SIZE + 128, "%s_%04i.VELOCIraptor", - e->stf_base_name, e->stf_output_count); + /* Not making separate directories so subDirName=outputDirName */ + strncpy(subDirName, outputDirName, FILENAME_BUFFER_SIZE); } /* What is the snapshot number? */ - int snapnum; - if (linked_with_snap) { - snapnum = e->snapshot_output_count; - } else { - snapnum = e->stf_output_count; + int snapnum = e->stf_output_count; + + /* What should the filename be? */ + char outputFileName[FILENAME_BUFFER_SIZE]; + if (snprintf(outputFileName, FILENAME_BUFFER_SIZE, "%s%s_%04i.VELOCIraptor", + subDirName, e->stf_base_name, + e->stf_output_count) >= FILENAME_BUFFER_SIZE) { + error("FILENAME_BUFFER_SIZE is too small for Velociraptor file name!"); } tic = getticks(); @@ -653,9 +691,12 @@ void velociraptor_invoke(struct engine *e, const int linked_with_snap) { /* Reset the pthread affinity mask after VELOCIraptor returns. */ pthread_setaffinity_np(thread, sizeof(cpu_set_t), engine_entry_affinity()); - /* Increase output counter (if not linked with snapshots) */ + /* Increase output counter (if not linked with snapshot) */ if (!linked_with_snap) e->stf_output_count++; + /* Record we have ran stf this timestep */ + e->stf_this_timestep = 1; + #else error("SWIFT not configure to run with VELOCIraptor."); #endif /* HAVE_VELOCIRAPTOR */ diff --git a/src/xmf.c b/src/xmf.c index 3c8bb257cca224a06e5b516be46e92dd0006183a..d3d88627b8fe0c0e40df53c6eb79960ef82f1519 100644 --- a/src/xmf.c +++ b/src/xmf.c @@ -107,6 +107,7 @@ void xmf_create_file(const char* baseName) { char fileName[FILENAME_BUFFER_SIZE]; snprintf(fileName, FILENAME_BUFFER_SIZE, "%s.xmf", baseName); FILE* xmfFile = fopen(fileName, "w"); + if (xmfFile == NULL) error("Unable to create XMF file."); fprintf(xmfFile, "<?xml version=\"1.0\" ?> \n"); fprintf(xmfFile, "<!DOCTYPE Xdmf SYSTEM \"Xdmf.dtd\" []> \n"); diff --git a/tests/Makefile.am b/tests/Makefile.am index 425190bc1531f8fa4822a705d6ee5d8656e04586..11426ac89970917cf121351e266aaa67cfd99847 100644 --- a/tests/Makefile.am +++ b/tests/Makefile.am @@ -41,7 +41,7 @@ check_PROGRAMS = testGreetings testReading testTimeIntegration \ testVoronoi1D testVoronoi2D testVoronoi3D testPeriodicBC \ testGravityDerivatives testPotentialSelf testPotentialPair testEOS testUtilities \ testSelectOutput testCbrt testCosmology testOutputList test27cellsStars \ - test27cellsStars_subset testCooling testFeedback testHashmap testHydroMPIrules + test27cellsStars_subset testCooling testComovingCooling testFeedback testHashmap testHydroMPIrules # Rebuild tests when SWIFT is updated. $(check_PROGRAMS): ../src/.libs/libswiftsim.a @@ -130,6 +130,8 @@ testUtilities_SOURCES = testUtilities.c testCooling_SOURCES = testCooling.c +testComovingCooling_SOURCES = testComovingCooling.c + testFeedback_SOURCES = testFeedback.c testHashmap_SOURCES = testHashmap.c diff --git a/tests/test125cells.c b/tests/test125cells.c index 725018316c8ff5834e94633a76a7a4a912446aab..27ba35a16fca416d7829ffb84d5677170b40fbbb 100644 --- a/tests/test125cells.c +++ b/tests/test125cells.c @@ -113,7 +113,7 @@ void set_energy_state(struct part *part, enum pressure_field press, float size, part->u = pressure / (hydro_gamma_minus_one * density); #elif defined(MINIMAL_SPH) || defined(HOPKINS_PU_SPH) || \ defined(HOPKINS_PU_SPH_MONAGHAN) || defined(ANARCHY_PU_SPH) || \ - defined(ANARCHY_DU_SPH) || defined(DEFAULT_SPH) + defined(SPHENIX_SPH) || defined(DEFAULT_SPH) part->u = pressure / (hydro_gamma_minus_one * density); #elif defined(PLANETARY_SPH) part->u = pressure / (hydro_gamma_minus_one * density); @@ -406,7 +406,7 @@ void dump_particle_fields(char *fileName, struct cell *main_cell, defined(GIZMO_MFV_SPH) || defined(SHADOWFAX_SPH) || \ defined(HOPKINS_PU_SPH) || defined(HOPKINS_PU_SPH_MONAGHAN) 0.f, -#elif defined(ANARCHY_PU_SPH) || defined(ANARCHY_DU_SPH) || defined(DEFAULT_SPH) +#elif defined(ANARCHY_PU_SPH) || defined(SPHENIX_SPH) || defined(DEFAULT_SPH) main_cell->hydro.parts[pid].viscosity.div_v, #else main_cell->hydro.parts[pid].density.div_v, @@ -427,7 +427,7 @@ void dump_particle_fields(char *fileName, struct cell *main_cell, defined(HOPKINS_PU_SPH_MONAGHAN) main_cell->hydro.parts[pid].force.v_sig, 0.f, main_cell->hydro.parts[pid].u_dt -#elif defined(ANARCHY_PU_SPH) || defined(ANARCHY_DU_SPH) || defined(DEFAULT_SPH) +#elif defined(ANARCHY_PU_SPH) || defined(SPHENIX_SPH) || defined(DEFAULT_SPH) main_cell->hydro.parts[pid].viscosity.v_sig, 0.f, main_cell->hydro.parts[pid].u_dt #else diff --git a/tests/test27cells.c b/tests/test27cells.c index e403cc1469cb53cdeea5e248bb8b16a301b70e0c..0fc075d11e8144e22712b33ce4fd14ab236ec84c 100644 --- a/tests/test27cells.c +++ b/tests/test27cells.c @@ -289,7 +289,7 @@ void dump_particle_fields(char *fileName, struct cell *main_cell, 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] -#elif defined(ANARCHY_PU_SPH) || defined(ANARCHY_DU_SPH) || defined(DEFAULT_SPH) +#elif defined(ANARCHY_PU_SPH) || defined(SPHENIX_SPH) || defined(DEFAULT_SPH) /* this is required because of the variable AV scheme */ main_cell->hydro.parts[pid].viscosity.div_v, main_cell->hydro.parts[pid].density.rot_v[0], @@ -334,7 +334,7 @@ void dump_particle_fields(char *fileName, struct cell *main_cell, cj->hydro.parts[pjd].density.rot_v[0], cj->hydro.parts[pjd].density.rot_v[1], cj->hydro.parts[pjd].density.rot_v[2] -#elif defined(ANARCHY_PU_SPH) || defined(ANARCHY_DU_SPH) || defined(DEFAULT_SPH) +#elif defined(ANARCHY_PU_SPH) || defined(SPHENIX_SPH) || defined(DEFAULT_SPH) /* this is required because of the variable AV scheme */ cj->hydro.parts[pjd].viscosity.div_v, cj->hydro.parts[pjd].density.rot_v[0], diff --git a/tests/testActivePair.c b/tests/testActivePair.c index ef613d5a68b847b6f379c5667447f1de8bf84c58..6c2c2fee03afef078e9efac991c171b3c36f510f 100644 --- a/tests/testActivePair.c +++ b/tests/testActivePair.c @@ -113,7 +113,7 @@ struct cell *make_cell(size_t n, double *offset, double size, double h, part->entropy = 1.f; #elif defined(MINIMAL_SPH) || defined(HOPKINS_PU_SPH) || \ defined(HOPKINS_PU_SPH_MONAGHAN) || defined(ANARCHY_PU_SPH) || \ - defined(ANARCHY_DU_SPH) || defined(DEFAULT_SPH) + defined(SPHENIX_SPH) || defined(DEFAULT_SPH) part->u = 1.f; #elif defined(HOPKINS_PE_SPH) part->entropy = 1.f; @@ -197,7 +197,7 @@ void zero_particle_fields_force(struct cell *c, const struct cosmology *cosmo, p->density.rot_v[2] = 0.f; p->density.div_v = 0.f; #endif /* GADGET-2 */ -#if defined(MINIMAL_SPH) || defined(ANARCHY_DU_SPH) || defined(DEFAULT_SPH) +#if defined(MINIMAL_SPH) || defined(SPHENIX_SPH) || defined(DEFAULT_SPH) p->rho = 1.f; p->density.rho_dh = 0.f; p->density.wcount = 48.f / (kernel_norm * pow_dimension(p->h)); @@ -220,8 +220,9 @@ void zero_particle_fields_force(struct cell *c, const struct cosmology *cosmo, p->density.wcount = 48.f / (kernel_norm * pow_dimension(p->h)); p->density.wcount_dh = 0.f; #endif /* PRESSURE-ENERGY */ -#if defined(ANARCHY_PU_SPH) || defined(ANARCHY_DU_SPH) +#if defined(ANARCHY_PU_SPH) || defined(SPHENIX_SPH) /* Initialise viscosity variables */ + p->force.pressure = hydro_get_comoving_pressure(p); p->viscosity.alpha = 0.8; p->viscosity.div_v = 0.f; p->viscosity.div_v_previous_step = 0.f; @@ -252,7 +253,8 @@ void end_calculation_density(struct cell *c, const struct cosmology *cosmo) { */ void end_calculation_force(struct cell *c, const struct cosmology *cosmo) { for (int pid = 0; pid < c->hydro.count; pid++) { - hydro_end_force(&c->hydro.parts[pid], cosmo); + struct part *volatile part = &c->hydro.parts[pid]; + hydro_end_force(part, cosmo); } } diff --git a/tests/testCbrt.c b/tests/testCbrt.c index bba379902b2bbc16bd49a5bbba0917100b4d60a7..fc89ea1bda7f68cb2b606eee1c80d6a8c1eee812 100644 --- a/tests/testCbrt.c +++ b/tests/testCbrt.c @@ -50,7 +50,9 @@ int main(int argc, char *argv[]) { message("executing %i runs of each command.", num_vals); /* Create and fill an array of floats. */ - float *data = (float *)malloc(sizeof(float) * num_vals); + float *data = NULL; + if (posix_memalign((void **)&data, 64, num_vals * sizeof(float)) != 0) + error("Failed to allocted memory for the test"); for (int k = 0; k < num_vals; k++) { data[k] = (float)rand() / RAND_MAX; data[k] = (1.0f - data[k]) * range_min + data[k] * range_max; diff --git a/tests/testComovingCooling.c b/tests/testComovingCooling.c new file mode 100644 index 0000000000000000000000000000000000000000..ba8de08384ccb7984a55705e4cc6934c518b7b6a --- /dev/null +++ b/tests/testComovingCooling.c @@ -0,0 +1,242 @@ +/******************************************************************************* + * This file is part of SWIFT. + * Copyright (C) 2015 Matthieu Schaller (matthieu.schaller@durham.ac.uk). + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published + * by the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this program. If not, see <http://www.gnu.org/licenses/>. + * + ******************************************************************************/ +#include "../config.h" + +/* Local headers. */ +#include "swift.h" + +#if defined(CHEMISTRY_EAGLE) && defined(COOLING_EAGLE) && defined(GADGET2_SPH) + +/* + * @brief Assign particle density and entropy corresponding to the + * hydrogen number density and internal energy specified. + * + * @param p Particle data structure + * @param xp extra particle structure + * @param us unit system struct + * @param cooling Cooling function data structure + * @param cosmo Cosmology data structure + * @param phys_const Physical constants data structure + * @param nh_cgs Hydrogen number density (cgs units) + * @param u Internal energy (cgs units) + * @param ti_current integertime to set cosmo quantities + */ +void set_quantities(struct part *restrict p, struct xpart *restrict xp, + const struct unit_system *restrict us, + const struct cooling_function_data *restrict cooling, + struct cosmology *restrict cosmo, + const struct phys_const *restrict phys_const, float nh_cgs, + double u_cgs, integertime_t ti_current) { + /* calculate density */ + double hydrogen_number_density = nh_cgs / cooling->number_density_to_cgs; + p->rho = hydrogen_number_density * phys_const->const_proton_mass / + p->chemistry_data.metal_mass_fraction[chemistry_element_H]; + + /* update entropy based on internal energy */ + float pressure = (u_cgs)*cooling->internal_energy_from_cgs * p->rho * + (hydro_gamma_minus_one); + p->entropy = pressure * (pow(p->rho, -hydro_gamma)); + xp->entropy_full = p->entropy; + + p->entropy_dt = 0.f; +} + +/* + * @brief Tests cooling integration scheme by comparing EAGLE + * integration to subcycled explicit equation. + */ +int main(int argc, char **argv) { + // Declare relevant structs + struct swift_params *params = malloc(sizeof(struct swift_params)); + struct unit_system us; + struct chemistry_global_data chem_data; + struct part p; + struct xpart xp; + struct phys_const phys_const; + struct cooling_function_data cooling; + struct cosmology cosmo; + char *parametersFileName = "./testCooling.yml"; + + float nh_cgs; // hydrogen number density + double u_cgs; // internal energy + + const float seconds_per_year = 3.154e7; + + /* Number of values to test for in redshift, + * hydrogen number density and internal energy */ + const int n_z = 10; + const int n_nh = 10; + const int n_u = 10; + + /* Number of subcycles and tolerance used to compare + * subcycled and implicit solution. Note, high value + * of tolerance due to mismatch between explicit and + * implicit solution for large timesteps */ + const float integration_tolerance = 0.2; + + /* Read the parameter file */ + if (params == NULL) error("Error allocating memory for the parameter file."); + message("Reading runtime parameters from file '%s'", parametersFileName); + parser_read_file(parametersFileName, params); + + /* Init units */ + units_init_from_params(&us, params, "InternalUnitSystem"); + phys_const_init(&us, params, &phys_const); + + /* Init chemistry */ + chemistry_init(params, &us, &phys_const, &chem_data); + chemistry_first_init_part(&phys_const, &us, &cosmo, &chem_data, &p, &xp); + chemistry_part_has_no_neighbours(&p, &xp, &chem_data, &cosmo); + chemistry_print(&chem_data); + + /* Init cosmology */ + cosmology_init(params, &us, &phys_const, &cosmo); + cosmology_print(&cosmo); + + /* Set dt */ + const int timebin = 38; + float dt_cool, dt_therm; + + /* Init hydro_props */ + struct hydro_props hydro_properties; + hydro_props_init(&hydro_properties, &phys_const, &us, params); + + /* Init cooling */ + cooling_init(params, &us, &phys_const, &hydro_properties, &cooling); + cooling_print(&cooling); + cooling_update(&cosmo, &cooling, 0); + + /* Init entropy floor */ + struct entropy_floor_properties floor_props; + entropy_floor_init(&floor_props, &phys_const, &us, &hydro_properties, params); + + /* Cooling function needs to know the minimal energy. Set it to the lowest + * internal energy in the cooling table. */ + hydro_properties.minimal_internal_energy = + exp(M_LN10 * cooling.Therm[0]) * cooling.internal_energy_from_cgs; + + /* Calculate abundance ratios */ + float *abundance_ratio; + abundance_ratio = malloc((chemistry_element_count + 2) * sizeof(float)); + abundance_ratio_to_solar(&p, &cooling, abundance_ratio); + + /* extract mass fractions, calculate table indices and offsets */ + float XH = p.chemistry_data.metal_mass_fraction[chemistry_element_H]; + float HeFrac = + p.chemistry_data.metal_mass_fraction[chemistry_element_He] / + (XH + p.chemistry_data.metal_mass_fraction[chemistry_element_He]); + int He_i; + float d_He; + get_index_1d(cooling.HeFrac, eagle_cooling_N_He_frac, HeFrac, &He_i, &d_He); + + /* calculate spacing in nh and u */ + const float log_u_min_cgs = 11, log_u_max_cgs = 17; + const float log_nh_min_cgs = -6, log_nh_max_cgs = 3; + const float delta_log_nh_cgs = (log_nh_max_cgs - log_nh_min_cgs) / n_nh; + const float delta_log_u_cgs = (log_u_max_cgs - log_u_min_cgs) / n_u; + + /* Declare variables we will be checking */ + double du_dt_implicit, du_dt_check; + integertime_t ti_current; + + /* Loop over values of nh and u */ + for (int nh_i = 0; nh_i < n_nh; nh_i++) { + nh_cgs = exp(M_LN10 * log_nh_min_cgs + delta_log_nh_cgs * nh_i); + for (int u_i = 0; u_i < n_u; u_i++) { + u_cgs = exp(M_LN10 * log_u_min_cgs + delta_log_u_cgs * u_i); + + /* Calculate cooling solution at redshift zero if we're doing the comoving + * check */ + /* reset quantities to nh, u, and z that we want to test */ + ti_current = max_nr_timesteps; + cosmology_update(&cosmo, &phys_const, ti_current); + set_quantities(&p, &xp, &us, &cooling, &cosmo, &phys_const, nh_cgs, u_cgs, + ti_current); + + /* Set dt */ + const integertime_t ti_step = get_integer_timestep(timebin); + const integertime_t ti_begin = + get_integer_time_begin(ti_current - 1, timebin); + dt_cool = cosmology_get_delta_time(&cosmo, ti_begin, ti_begin + ti_step); + dt_therm = + cosmology_get_therm_kick_factor(&cosmo, ti_begin, ti_begin + ti_step); + + cooling_init(params, &us, &phys_const, &hydro_properties, &cooling); + cooling_update(&cosmo, &cooling, 0); + + /* compute implicit solution */ + cooling_cool_part(&phys_const, &us, &cosmo, &hydro_properties, + &floor_props, &cooling, &p, &xp, dt_cool, dt_therm); + du_dt_check = hydro_get_physical_internal_energy_dt(&p, &cosmo); + + /* Now we can test the cooling at various redshifts and compare the result + * to the redshift zero solution */ + for (int z_i = 0; z_i <= n_z; z_i++) { + ti_current = max_nr_timesteps / n_z * z_i + 1; + + /* reset to get the comoving density */ + cosmology_update(&cosmo, &phys_const, ti_current); + cosmo.z = 0.f; + set_quantities(&p, &xp, &us, &cooling, &cosmo, &phys_const, + nh_cgs * cosmo.a * cosmo.a * cosmo.a, + u_cgs / cosmo.a2_inv, ti_current); + + /* Load the appropriate tables */ + cooling_init(params, &us, &phys_const, &hydro_properties, &cooling); + cooling_update(&cosmo, &cooling, 0); + + /* compute implicit solution */ + cooling_cool_part(&phys_const, &us, &cosmo, &hydro_properties, + &floor_props, &cooling, &p, &xp, dt_cool, dt_therm); + du_dt_implicit = hydro_get_physical_internal_energy_dt(&p, &cosmo); + + /* check if the two solutions are consistent */ + if (fabs((du_dt_implicit - du_dt_check) / du_dt_check) > + integration_tolerance || + (du_dt_check == 0.0 && du_dt_implicit != 0.0)) + error( + "Solutions do not match. scale factor %.5e z %.5e nh_cgs %.5e " + "u_cgs %.5e dt (years) %.5e du cgs implicit %.5e reference %.5e " + "error %.5e", + cosmo.a, cosmo.z, nh_cgs, u_cgs, + dt_cool * units_cgs_conversion_factor(&us, UNIT_CONV_TIME) / + seconds_per_year, + du_dt_implicit * + units_cgs_conversion_factor(&us, + UNIT_CONV_ENERGY_PER_UNIT_MASS) * + dt_therm, + du_dt_check * + units_cgs_conversion_factor(&us, + UNIT_CONV_ENERGY_PER_UNIT_MASS) * + dt_therm, + fabs((du_dt_implicit - du_dt_check) / du_dt_check)); + } + } + } + message("done comoving cooling test"); + + free(params); + return 0; +} + +#else + +int main(int argc, char **argv) { return 0; } + +#endif diff --git a/tests/testCooling.c b/tests/testCooling.c index 727a9638b09b871e866fe787438a5707fd43ec6b..227d12d02cab6fa1eb3fe2be7557036f823e4ea7 100644 --- a/tests/testCooling.c +++ b/tests/testCooling.c @@ -21,7 +21,7 @@ /* Local headers. */ #include "swift.h" -#if 0 +#if defined(CHEMISTRY_EAGLE) && defined(COOLING_EAGLE) && defined(GADGET2_SPH) /* * @brief Assign particle density and entropy corresponding to the @@ -42,29 +42,24 @@ void set_quantities(struct part *restrict p, struct xpart *restrict xp, const struct cooling_function_data *restrict cooling, struct cosmology *restrict cosmo, const struct phys_const *restrict phys_const, float nh_cgs, - double u, integertime_t ti_current) { - - /* Update cosmology quantities */ - cosmology_update(cosmo, phys_const, ti_current); - + double u_cgs, integertime_t ti_current) { /* calculate density */ - double hydrogen_number_density = nh_cgs / cooling->number_density_scale; + double hydrogen_number_density = nh_cgs / cooling->number_density_to_cgs; p->rho = hydrogen_number_density * phys_const->const_proton_mass / - p->chemistry_data.metal_mass_fraction[chemistry_element_H] * - (cosmo->a * cosmo->a * cosmo->a); + p->chemistry_data.metal_mass_fraction[chemistry_element_H]; /* update entropy based on internal energy */ - float pressure = (u * cosmo->a * cosmo->a) / cooling->internal_energy_scale * - p->rho * (hydro_gamma_minus_one); + float pressure = (u_cgs)*cooling->internal_energy_from_cgs * p->rho * + (hydro_gamma_minus_one); p->entropy = pressure * (pow(p->rho, -hydro_gamma)); xp->entropy_full = p->entropy; + + p->entropy_dt = 0.f; } /* - * @brief Produces contributions to cooling rates for different - * hydrogen number densities, from different metals, - * tests 1d and 4d table interpolations produce - * same results for cooling rate, dlambda/du and temperature. + * @brief Tests cooling integration scheme by comparing EAGLE + * integration to subcycled explicit equation. */ int main(int argc, char **argv) { // Declare relevant structs @@ -78,14 +73,16 @@ int main(int argc, char **argv) { struct cosmology cosmo; char *parametersFileName = "./testCooling.yml"; - float nh; // hydrogen number density - double u; // internal energy + float nh_cgs; // hydrogen number density + double u_cgs; // internal energy + + const float seconds_per_year = 3.154e7; /* Number of values to test for in redshift, * hydrogen number density and internal energy */ - const int n_z = 50; - const int n_nh = 50; - const int n_u = 50; + const int n_z = 10; + const int n_nh = 10; + const int n_u = 10; /* Number of subcycles and tolerance used to compare * subcycled and implicit solution. Note, high value @@ -94,10 +91,6 @@ int main(int argc, char **argv) { const int n_subcycle = 1000; const float integration_tolerance = 0.2; - /* Set dt */ - const float dt_cool = 1.0e-5; - const float dt_therm = 1.0e-5; - /* Read the parameter file */ if (params == NULL) error("Error allocating memory for the parameter file."); message("Reading runtime parameters from file '%s'", parametersFileName); @@ -110,17 +103,35 @@ int main(int argc, char **argv) { /* Init chemistry */ chemistry_init(params, &us, &phys_const, &chem_data); chemistry_first_init_part(&phys_const, &us, &cosmo, &chem_data, &p, &xp); + chemistry_part_has_no_neighbours(&p, &xp, &chem_data, &cosmo); chemistry_print(&chem_data); /* Init cosmology */ cosmology_init(params, &us, &phys_const, &cosmo); cosmology_print(&cosmo); + /* Set dt */ + const int timebin = 38; + float dt_cool, dt_therm; + + /* Init hydro_props */ + struct hydro_props hydro_properties; + hydro_props_init(&hydro_properties, &phys_const, &us, params); + /* Init cooling */ - cooling_init(params, &us, &phys_const, &cooling); + cooling_init(params, &us, &phys_const, &hydro_properties, &cooling); cooling_print(&cooling); cooling_update(&cosmo, &cooling, 0); + /* Init entropy floor */ + struct entropy_floor_properties floor_props; + entropy_floor_init(&floor_props, &phys_const, &us, &hydro_properties, params); + + /* Cooling function needs to know the minimal energy. Set it to the lowest + * internal energy in the cooling table. */ + hydro_properties.minimal_internal_energy = + exp(M_LN10 * cooling.Therm[0]) * cooling.internal_energy_from_cgs; + /* Calculate abundance ratios */ float *abundance_ratio; abundance_ratio = malloc((chemistry_element_count + 2) * sizeof(float)); @@ -133,65 +144,88 @@ int main(int argc, char **argv) { (XH + p.chemistry_data.metal_mass_fraction[chemistry_element_He]); int He_i; float d_He; - get_index_1d(cooling.HeFrac, cooling.N_He, HeFrac, &He_i, &d_He); - - /* Cooling function needs to know the minimal energy. Set it to the lowest - * internal energy in the cooling table. */ - struct hydro_props hydro_properties; - hydro_properties.minimal_internal_energy = - exp(M_LN10 * cooling.Therm[0]) / cooling.internal_energy_scale; + get_index_1d(cooling.HeFrac, eagle_cooling_N_He_frac, HeFrac, &He_i, &d_He); /* calculate spacing in nh and u */ - const float delta_nh = (cooling.nH[cooling.N_nH - 1] - cooling.nH[0]) / n_nh; - const float delta_u = - (cooling.Therm[cooling.N_Temp - 1] - cooling.Therm[0]) / n_u; + const float log_u_min_cgs = 11, log_u_max_cgs = 17; + const float log_nh_min_cgs = -6, log_nh_max_cgs = 3; + const float delta_log_nh_cgs = (log_nh_max_cgs - log_nh_min_cgs) / n_nh; + const float delta_log_u_cgs = (log_u_max_cgs - log_u_min_cgs) / n_u; + + /* Declare variables we will be checking */ + double du_dt_implicit, du_dt_check; + integertime_t ti_current; + + /* Loop over values of nh and u */ + for (int nh_i = 0; nh_i < n_nh; nh_i++) { + nh_cgs = exp(M_LN10 * log_nh_min_cgs + delta_log_nh_cgs * nh_i); + for (int u_i = 0; u_i < n_u; u_i++) { + u_cgs = exp(M_LN10 * log_u_min_cgs + delta_log_u_cgs * u_i); - for (int z_i = 0; z_i < n_z; z_i++) { - integertime_t ti_current = max_nr_timesteps / n_z * z_i; - for (int nh_i = 0; nh_i < n_nh; nh_i++) { - nh = exp(M_LN10 * cooling.nH[0] + delta_nh * nh_i); - for (int u_i = 0; u_i < n_u; u_i++) { - u = exp(M_LN10 * cooling.Therm[0] + delta_u * u_i); + /* Loop over z */ + for (int z_i = 0; z_i <= n_z; z_i++) { + ti_current = max_nr_timesteps / n_z * z_i + 1; /* update nh, u, z */ - set_quantities(&p, &xp, &us, &cooling, &cosmo, &phys_const, nh, u, - ti_current); + cosmology_update(&cosmo, &phys_const, ti_current); + cooling_init(params, &us, &phys_const, &hydro_properties, &cooling); + cooling_update(&cosmo, &cooling, 0); + set_quantities(&p, &xp, &us, &cooling, &cosmo, &phys_const, nh_cgs, + u_cgs, ti_current); + + /* Set dt */ + const integertime_t ti_step = get_integer_timestep(timebin); + const integertime_t ti_begin = + get_integer_time_begin(ti_current - 1, timebin); + dt_cool = + cosmology_get_delta_time(&cosmo, ti_begin, ti_begin + ti_step); + dt_therm = cosmology_get_therm_kick_factor(&cosmo, ti_begin, + ti_begin + ti_step); /* calculate subcycled solution */ for (int t_subcycle = 0; t_subcycle < n_subcycle; t_subcycle++) { p.entropy_dt = 0; cooling_cool_part(&phys_const, &us, &cosmo, &hydro_properties, - &cooling, &p, &xp, dt_cool / n_subcycle, - dt_therm / n_subcycle); + &floor_props, &cooling, &p, &xp, + dt_cool / n_subcycle, dt_therm / n_subcycle); xp.entropy_full += p.entropy_dt * dt_therm / n_subcycle; } - double u_subcycled = - hydro_get_physical_internal_energy(&p, &xp, &cosmo) * - cooling.internal_energy_scale; + du_dt_check = hydro_get_physical_internal_energy_dt(&p, &cosmo); /* reset quantities to nh, u, and z that we want to test */ - set_quantities(&p, &xp, &us, &cooling, &cosmo, &phys_const, nh, u, - ti_current); + cosmology_update(&cosmo, &phys_const, ti_current); + set_quantities(&p, &xp, &us, &cooling, &cosmo, &phys_const, nh_cgs, + u_cgs, ti_current); /* compute implicit solution */ - cooling_cool_part(&phys_const, &us, &cosmo, &hydro_properties, &cooling, - &p, &xp, dt_cool, dt_therm); - double u_implicit = - hydro_get_physical_internal_energy(&p, &xp, &cosmo) * - cooling.internal_energy_scale; + cooling_cool_part(&phys_const, &us, &cosmo, &hydro_properties, + &floor_props, &cooling, &p, &xp, dt_cool, dt_therm); + du_dt_implicit = hydro_get_physical_internal_energy_dt(&p, &cosmo); /* check if the two solutions are consistent */ - if (fabs((u_implicit - u_subcycled) / u_subcycled) > - integration_tolerance) - message( - "implicit and subcycled solutions do not match. z_i %d nh_i %d " - "u_i %d implicit %.5e subcycled %.5e error %.5e", - z_i, nh_i, u_i, u_implicit, u_subcycled, - fabs((u_implicit - u_subcycled) / u_subcycled)); + if (fabs((du_dt_implicit - du_dt_check) / du_dt_check) > + integration_tolerance || + (du_dt_check == 0.0 && du_dt_implicit != 0.0)) + error( + "Solutions do not match. scale factor %.5e z %.5e nh_cgs %.5e " + "u_cgs %.5e dt (years) %.5e du cgs implicit %.5e reference %.5e " + "error %.5e", + cosmo.a, cosmo.z, nh_cgs, u_cgs, + dt_cool * units_cgs_conversion_factor(&us, UNIT_CONV_TIME) / + seconds_per_year, + du_dt_implicit * + units_cgs_conversion_factor(&us, + UNIT_CONV_ENERGY_PER_UNIT_MASS) * + dt_therm, + du_dt_check * + units_cgs_conversion_factor(&us, + UNIT_CONV_ENERGY_PER_UNIT_MASS) * + dt_therm, + fabs((du_dt_implicit - du_dt_check) / du_dt_check)); } } } - message("done test"); + message("done explicit subcycling cooling test"); free(params); return 0; diff --git a/tests/testCooling.yml b/tests/testCooling.yml index faec32cdfec20b48af7341889c79b60bd2f6bb5b..fab3ae8959112a078e92621a0031ee14dbc2bc0d 100644 --- a/tests/testCooling.yml +++ b/tests/testCooling.yml @@ -9,7 +9,7 @@ InternalUnitSystem: # Cosmological parameters Cosmology: h: 0.6777 # Reduced Hubble constant - a_begin: 0.1 # Initial scale-factor of the simulation + a_begin: 0.5 # Initial scale-factor of the simulation a_end: 1.0 # Final scale factor of the simulation Omega_m: 0.307 # Matter density parameter Omega_lambda: 0.693 # Dark-energy density parameter @@ -81,27 +81,51 @@ GrackleCooling: MaxSteps: 1000 ConvergenceLimit: 1e-2 -EagleCooling: - filename: /cosma5/data/Eagle/BG_Tables/CoolingTables/ - reionisation_redshift: 8.989 +EAGLECooling: + dir_name: ./coolingtables/ + H_reion_z: 11.5 + H_reion_eV_p_H: 2.0 He_reion_z_centre: 3.5 He_reion_z_sigma: 0.5 - He_reion_ev_pH: 2.0 + He_reion_eV_p_H: 2.0 + +#EAGLEChemistry: +# InitMetallicity: 0.014 +# InitAbundance_Hydrogen: 0.70649785 +# InitAbundance_Helium: 0.28055534 +# InitAbundance_Carbon: 2.0665436e-3 +# InitAbundance_Nitrogen: 8.3562563e-4 +# InitAbundance_Oxygen: 5.4926244e-3 +# InitAbundance_Neon: 1.4144605e-3 +# InitAbundance_Magnesium: 5.907064e-4 +# InitAbundance_Silicon: 6.825874e-4 +# InitAbundance_Iron: 1.1032152e-3 +# CalciumOverSilicon: 0.0941736 +# SulphurOverSilicon: 0.6054160 +EAGLEChemistry: # Solar abundances + init_abundance_metal: 0.014 + init_abundance_Hydrogen: 0.70649785 + init_abundance_Helium: 0.28055534 + init_abundance_Carbon: 2.0665436e-3 + init_abundance_Nitrogen: 8.3562563e-4 + init_abundance_Oxygen: 5.4926244e-3 + init_abundance_Neon: 1.4144605e-3 + init_abundance_Magnesium: 5.907064e-4 + init_abundance_Silicon: 6.825874e-4 + init_abundance_Iron: 1.1032152e-3 -EAGLEChemistry: - InitMetallicity: 0.014 - InitAbundance_Hydrogen: 0.70649785 - InitAbundance_Helium: 0.28055534 - InitAbundance_Carbon: 2.0665436e-3 - InitAbundance_Nitrogen: 8.3562563e-4 - InitAbundance_Oxygen: 5.4926244e-3 - InitAbundance_Neon: 1.4144605e-3 - InitAbundance_Magnesium: 5.907064e-4 - InitAbundance_Silicon: 6.825874e-4 - InitAbundance_Iron: 1.1032152e-3 - CalciumOverSilicon: 0.0941736 - SulphurOverSilicon: 0.6054160 GearChemistry: InitialMetallicity: 0.01295 +# Parameters for the EAGLE "equation of state" +EAGLEEntropyFloor: + Jeans_density_threshold_H_p_cm3: 0.1 # Physical density above which the EAGLE Jeans limiter entropy floor kicks in expressed in Hydrogen atoms per cm^3. + Jeans_over_density_threshold: 10. # Overdensity above which the EAGLE Jeans limiter entropy floor can kick in. + Jeans_temperature_norm_K: 8000 # Temperature of the EAGLE Jeans limiter entropy floor at the density threshold expressed in Kelvin. + Jeans_gamma_effective: 1.3333333 # Slope the of the EAGLE Jeans limiter entropy floor + Cool_density_threshold_H_p_cm3: 1e-5 # Physical density above which the EAGLE Cool limiter entropy floor kicks in expressed in Hydrogen atoms per cm^3. + Cool_over_density_threshold: 10. # Overdensity above which the EAGLE Cool limiter entropy floor can kick in. + Cool_temperature_norm_K: 8000 # Temperature of the EAGLE Cool limiter entropy floor at the density threshold expressed in Kelvin. + Cool_gamma_effective: 1. # Slope the of the EAGLE Cool limiter entropy floor + diff --git a/tests/testInteractions.c b/tests/testInteractions.c index ef4f0e4c69e7770b032af7c9fb5dc8335fc48c11..0881d9d27f8990b5eb67ad5b3cbfb7023ebaf5e4 100644 --- a/tests/testInteractions.c +++ b/tests/testInteractions.c @@ -114,8 +114,7 @@ void prepare_force(struct part *parts, size_t count) { #if !defined(GIZMO_MFV_SPH) && !defined(SHADOWFAX_SPH) && \ !defined(MINIMAL_SPH) && !defined(PLANETARY_SPH) && \ !defined(HOPKINS_PU_SPH) && !defined(HOPKINS_PU_SPH_MONAGHAN) && \ - !defined(ANARCHY_PU_SPH) && !defined(ANARCHY_DU_SPH) && \ - !defined(DEFAULT_SPH) + !defined(ANARCHY_PU_SPH) && !defined(SPHENIX_SPH) && !defined(DEFAULT_SPH) struct part *p; for (size_t i = 0; i < count; ++i) { p = &parts[i]; @@ -158,7 +157,7 @@ void dump_indv_particle_fields(char *fileName, struct part *p) { p->force.v_sig, 0.f, p->force.u_dt #elif defined(MINIMAL_SPH) || defined(HOPKINS_PU_SPH) || \ defined(HOPKINS_PU_SPH_MONAGHAN) || defined(ANARCHY_PU_SPH) || \ - defined(ANARCHY_DU_SPH) || defined(DEFAULT_SPH) + defined(SPHENIX_SPH) || defined(DEFAULT_SPH) p->force.v_sig, 0.f, p->u_dt #else 0.f, 0.f, 0.f @@ -563,7 +562,7 @@ void test_force_interactions(struct part test_part, struct part *parts, rhoiq[i] = pi_vec.rho; grad_hiq[i] = pi_vec.force.f; #if !defined(HOPKINS_PU_SPH) && !defined(HOPKINS_PU_SPH_MONAGHAN) && \ - !defined(ANARCHY_PU_SPH) && !defined(ANARCHY_DU_SPH) + !defined(ANARCHY_PU_SPH) && !defined(SPHENIX_SPH) pOrhoi2q[i] = pi_vec.force.P_over_rho2; #endif balsaraiq[i] = pi_vec.force.balsara; @@ -577,7 +576,7 @@ void test_force_interactions(struct part test_part, struct part *parts, rhojq[i] = pj_vec[i].rho; grad_hjq[i] = pj_vec[i].force.f; #if !defined(HOPKINS_PU_SPH) && !defined(HOPKINS_PU_SPH_MONAGHAN) && \ - !defined(ANARCHY_PU_SPH) && !defined(ANARCHY_DU_SPH) + !defined(ANARCHY_PU_SPH) && !defined(SPHENIX_SPH) pOrhoj2q[i] = pj_vec[i].force.P_over_rho2; #endif balsarajq[i] = pj_vec[i].force.balsara; @@ -660,7 +659,7 @@ void test_force_interactions(struct part test_part, struct part *parts, VEC_HADD(h_dtSum, piq[0]->force.h_dt); VEC_HMAX(v_sigSum, piq[0]->force.v_sig); #if !defined(HOPKINS_PU_SPH) && !defined(HOPKINS_PU_SPH_MONAGHAN) && \ - !defined(ANARCHY_PU_SPH) && !defined(ANARCHY_DU_SPH) + !defined(ANARCHY_PU_SPH) && !defined(SPHENIX_SPH) VEC_HADD(entropy_dtSum, piq[0]->entropy_dt); #endif diff --git a/tests/testLogger.c b/tests/testLogger.c index d2c64e7fa3330ebd20cf8abc01a76e1dff08c8fc..5976597054c639a65f827876f1f244bc1a6024ce 100644 --- a/tests/testLogger.c +++ b/tests/testLogger.c @@ -51,12 +51,13 @@ void test_log_parts(struct logger_writer *log) { logger_mask_data[logger_a].mask | logger_mask_data[logger_u].mask | logger_mask_data[logger_h].mask | logger_mask_data[logger_rho].mask | logger_mask_data[logger_consts].mask, - &offset); + &offset, /* special flags */ 0); printf("Wrote part at offset %#016zx.\n", offset); /* Write only the position. */ p.x[0] = 2.0; - logger_log_part(log, &p, logger_mask_data[logger_x].mask, &offset); + logger_log_part(log, &p, logger_mask_data[logger_x].mask, &offset, + /* special flags */ 0); printf("Wrote part at offset %#016zx.\n", offset); /* Write the position and velocity. */ @@ -65,7 +66,7 @@ void test_log_parts(struct logger_writer *log) { logger_log_part( log, &p, logger_mask_data[logger_x].mask | logger_mask_data[logger_v].mask, - &offset); + &offset, /* special flags */ 0); printf("Wrote part at offset %#016zx.\n", offset); /* Recover the last part from the dump. */ @@ -126,12 +127,13 @@ void test_log_gparts(struct logger_writer *log) { logger_mask_data[logger_x].mask | logger_mask_data[logger_v].mask | logger_mask_data[logger_a].mask | logger_mask_data[logger_h].mask | logger_mask_data[logger_consts].mask, - &offset); + &offset, /* special flags */ 0); printf("Wrote gpart at offset %#016zx.\n", offset); /* Write only the position. */ p.x[0] = 2.0; - logger_log_gpart(log, &p, logger_mask_data[logger_x].mask, &offset); + logger_log_gpart(log, &p, logger_mask_data[logger_x].mask, &offset, + /* special flags */ 0); printf("Wrote gpart at offset %#016zx.\n", offset); /* Write the position and velocity. */ @@ -140,7 +142,7 @@ void test_log_gparts(struct logger_writer *log) { logger_log_gpart( log, &p, logger_mask_data[logger_x].mask | logger_mask_data[logger_v].mask, - &offset); + &offset, /* special flags */ 0); printf("Wrote gpart at offset %#016zx.\n", offset); /* Recover the last part from the dump. */ diff --git a/tests/testMaths.c b/tests/testMaths.c index 2abb3aa99902323597b3d20fb19769a8ea1bafbe..8dbae78b78daf33c6d116195e35dec8cda061f02 100644 --- a/tests/testMaths.c +++ b/tests/testMaths.c @@ -45,23 +45,23 @@ int main(int argc, char *argv[]) { printf("Absolute difference too large !\n"); error = 1; } - if (abs > 1.2e-7 && fabsf(x) <= 0.1) { + if (abs > 3e-7 && fabsf(x) <= 0.1) { printf("Absolute difference too large !\n"); - error = 1; + error = 2; } if (rel > 1e-6 && fabsf(x) <= 0.2) { printf("Relative difference too large !\n"); - error = 1; + error = 3; } - if (rel > 4e-8 && fabsf(x) <= 0.1) { + if (rel > 3e-7 && fabsf(x) <= 0.1) { printf("Relative difference too large !\n"); - error = 1; + error = 4; } - if (error) { - printf("%2d: x= %f exp(x)= %e approx_exp(x)=%e abs=%e rel=%e\n", i, x, - exp_correct, exp_approx, abs, rel); + if (error > 0) { + printf("%2d/%d: x= %f exp(x)= %e approx_exp(x)=%e abs=%e rel=%e\n", i, + error, x, exp_correct, exp_approx, abs, rel); return 1; } } diff --git a/tests/testOutputList.c b/tests/testOutputList.c index fd69ef91389758adf87aa48ab983a6cfbd6a89a9..4ef899c7b36ab17ec1da2327d0f0bb81be142d05 100644 --- a/tests/testOutputList.c +++ b/tests/testOutputList.c @@ -40,7 +40,7 @@ const double a_values[Ntest] = { 0.5, }; -void test_no_cosmo(struct engine *e, char *name, int with_assert) { +void test_no_cosmo(struct engine *e, const char *name, const int with_assert) { message("Testing output time for %s without cosmology", name); struct output_list *list; @@ -52,7 +52,7 @@ void test_no_cosmo(struct engine *e, char *name, int with_assert) { e->time_end = 14; e->time_base = (e->time_end - e->time_begin) / max_nr_timesteps; e->ti_current = 0; - e->policy = !engine_policy_cosmology; + e->policy = 0; /* initialize output_list */ output_list_init(&list, e, name, &delta_time, &output_time); @@ -78,7 +78,7 @@ void test_no_cosmo(struct engine *e, char *name, int with_assert) { output_list_clean(&list); }; -void test_cosmo(struct engine *e, char *name, int with_assert) { +void test_cosmo(struct engine *e, const char *name, const int with_assert) { message("Testing output time for %s with cosmology", name); struct output_list *list; @@ -102,7 +102,7 @@ void test_cosmo(struct engine *e, char *name, int with_assert) { /* Set current time */ e->ti_current = log(output_time / e->cosmology->a_begin) / e->time_base; - e->ti_current += 1; + e->ti_current += 16; /* Read next value */ integertime_t ti_next; diff --git a/tests/testPeriodicBC.c b/tests/testPeriodicBC.c index f19ec46620955d29b73113ddae1ab5680f7e7303..729b4d70e45c6e945d54f533e72a17d965f997d8 100644 --- a/tests/testPeriodicBC.c +++ b/tests/testPeriodicBC.c @@ -78,7 +78,10 @@ struct cell *make_cell(size_t n, double *offset, double size, double h, enum velocity_types vel) { const size_t count = n * n * n; const double volume = size * size * size; - struct cell *cell = (struct cell *)malloc(sizeof(struct cell)); + struct cell *cell = NULL; + if (posix_memalign((void **)&cell, cell_align, sizeof(struct cell)) != 0) { + error("couldn't allocate cell"); + } bzero(cell, sizeof(struct cell)); if (posix_memalign((void **)&cell->hydro.parts, part_align, @@ -249,7 +252,7 @@ void dump_particle_fields(char *fileName, struct cell *main_cell, int i, int j, 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] -#elif defined(DEFAULT_SPH) || defined(ANARCHY_PU_SPH) || defined(ANARCHY_DU_SPH) +#elif defined(DEFAULT_SPH) || defined(ANARCHY_PU_SPH) || defined(SPHENIX_SPH) main_cell->hydro.parts[pid].viscosity.div_v, main_cell->hydro.parts[pid].density.rot_v[0], main_cell->hydro.parts[pid].density.rot_v[1], @@ -290,7 +293,7 @@ void runner_dopair1_branch_density(struct runner *r, struct cell *ci, struct cell *cj); void runner_doself1_branch_density(struct runner *r, struct cell *c); -void test_boundary_conditions(struct cell **cells, struct runner runner, +void test_boundary_conditions(struct cell **cells, struct runner *runner, const int loc_i, const int loc_j, const int loc_k, const int dim, char *swiftOutputFileName, char *bruteForceOutputFileName) { @@ -303,10 +306,10 @@ void test_boundary_conditions(struct cell **cells, struct runner runner, /* Run all the pairs */ #ifdef WITH_VECTORIZATION - runner.ci_cache.count = 0; - cache_init(&runner.ci_cache, 512); - runner.cj_cache.count = 0; - cache_init(&runner.cj_cache, 512); + runner->ci_cache.count = 0; + cache_init(&runner->ci_cache, 512); + runner->cj_cache.count = 0; + cache_init(&runner->cj_cache, 512); #endif /* Now loop over all the neighbours of this cell @@ -324,17 +327,17 @@ void test_boundary_conditions(struct cell **cells, struct runner runner, /* Get the neighbouring cell */ struct cell *cj = cells[iii * (dim * dim) + jjj * dim + kkk]; - if (cj != main_cell) DOPAIR1(&runner, main_cell, cj); + if (cj != main_cell) DOPAIR1(runner, main_cell, cj); } } } /* And now the self-interaction */ - DOSELF1(&runner, main_cell); + DOSELF1(runner, main_cell); /* Let's get physical ! */ - end_calculation(main_cell, runner.e->cosmology); + end_calculation(main_cell, runner->e->cosmology); /* Dump particles from the main cell. */ dump_particle_fields(swiftOutputFileName, main_cell, loc_i, loc_j, loc_k); @@ -359,16 +362,16 @@ void test_boundary_conditions(struct cell **cells, struct runner runner, /* Get the neighbouring cell */ struct cell *cj = cells[iii * (dim * dim) + jjj * dim + kkk]; - if (cj != main_cell) pairs_all_density(&runner, main_cell, cj); + if (cj != main_cell) pairs_all_density(runner, main_cell, cj); } } } /* And now the self-interaction */ - self_all_density(&runner, main_cell); + self_all_density(runner, main_cell); /* Let's get physical ! */ - end_calculation(main_cell, runner.e->cosmology); + end_calculation(main_cell, runner->e->cosmology); /* Dump */ dump_particle_fields(bruteForceOutputFileName, main_cell, loc_i, loc_j, @@ -491,8 +494,9 @@ int main(int argc, char *argv[]) { engine.hydro_properties = &hp; engine.nodeID = NODE_ID; - struct runner runner; - runner.e = &engine; + struct runner real_runner; + struct runner *runner = &real_runner; + runner->e = &engine; struct cosmology cosmo; cosmology_init_no_cosmo(&cosmo); @@ -508,9 +512,9 @@ int main(int argc, char *argv[]) { cells[i * (dim * dim) + j * dim + k] = make_cell( particles, offset, size, h, rho, &partId, perturbation, vel); - runner_do_drift_part(&runner, cells[i * (dim * dim) + j * dim + k], 0); + runner_do_drift_part(runner, cells[i * (dim * dim) + j * dim + k], 0); - runner_do_hydro_sort(&runner, cells[i * (dim * dim) + j * dim + k], + runner_do_hydro_sort(runner, cells[i * (dim * dim) + j * dim + k], 0x1FFF, 0, 0); } } diff --git a/tests/testRandom.c b/tests/testRandom.c index 036f58b29115a2e646cea35e873ccdc9a4164e4e..cd8d2092dbd90c7b0f1f922ea28725207b6a1fee 100644 --- a/tests/testRandom.c +++ b/tests/testRandom.c @@ -100,6 +100,9 @@ int main(int argc, char* argv[]) { message("Seed = %d", seed); srand(seed); + /* Log the swift random seed */ + message("SWIFT random seed = %d", SWIFT_RANDOM_SEED_XOR); + /* Time-step size */ const int time_bin = 30; @@ -125,19 +128,22 @@ int main(int argc, char* argv[]) { double total2ID = 0.; /* Pearson correlation for different processes */ - double pearson_star_sf = 0.; + double pearson_star_sf_1 = 0.; + double pearson_star_sf_2 = 0.; double pearson_star_se = 0.; double pearson_star_bh = 0.; - double pearson_sf_se = 0.; - double pearson_sf_bh = 0.; + double pearson_sf_1_se = 0.; + double pearson_sf_1_bh = 0.; double pearson_se_bh = 0.; /* Calculate the mean and <x^2> for these processes */ - double total_sf = 0.; + double total_sf_1 = 0.; + double total_sf_2 = 0.; double total_se = 0.; double total_bh = 0.; - double total2_sf = 0.; + double total2_sf_1 = 0.; + double total2_sf_2 = 0.; double total2_se = 0.; double total2_bh = 0.; @@ -151,7 +157,7 @@ int main(int argc, char* argv[]) { const double r = random_unit_interval(id, ti_current, random_number_star_formation); if (r < 0.0 || r >= 1.0) { - error("Generated random vlaue %f is not in [0, 1).", r); + error("Generated random value %f is not in [0, 1).", r); } total += r; @@ -167,7 +173,7 @@ int main(int argc, char* argv[]) { const double r_2ndid = random_unit_interval(idoffset, ti_current, random_number_star_formation); if (r_2ndid < 0.0 || r_2ndid >= 1.0) { - error("Generated random vlaue %f is not in [0, 1).", r_2ndid); + error("Generated random value %f is not in [0, 1).", r_2ndid); } /* Pearson correlation for small different IDs */ @@ -178,38 +184,47 @@ int main(int argc, char* argv[]) { /* Calculate random numbers for the different processes and check * that they are uncorrelated */ - const double r_sf = - random_unit_interval(id, ti_current, random_number_stellar_feedback); - if (r_sf < 0.0 || r_sf >= 1.0) { - error("Generated random vlaue %f is not in [0, 1).", r_sf); + const double r_sf_1 = random_unit_interval( + id, ti_current, random_number_stellar_feedback_1); + if (r_sf_1 < 0.0 || r_sf_1 >= 1.0) { + error("Generated random value %f is not in [0, 1).", r_sf_1); + } + + const double r_sf_2 = random_unit_interval( + id, ti_current, random_number_stellar_feedback_2); + if (r_sf_2 < 0.0 || r_sf_2 >= 1.0) { + error("Generated random value %f is not in [0, 1).", r_sf_2); } const double r_se = random_unit_interval( id, ti_current, random_number_stellar_enrichment); if (r_se < 0.0 || r_se >= 1.0) { - error("Generated random vlaue %f is not in [0, 1).", r_se); + error("Generated random value %f is not in [0, 1).", r_se); } const double r_bh = random_unit_interval(id, ti_current, random_number_BH_feedback); if (r_bh < 0.0 || r_bh >= 1.0) { - error("Generated random vlaue %f is not in [0, 1).", r_bh); + error("Generated random value %f is not in [0, 1).", r_bh); } /* Calculate the correlation between the different processes */ - total_sf += r_sf; + total_sf_1 += r_sf_1; + total_sf_2 += r_sf_2; total_se += r_se; total_bh += r_bh; - total2_sf += r_sf * r_sf; + total2_sf_1 += r_sf_1 * r_sf_1; + total2_sf_2 += r_sf_2 * r_sf_2; total2_se += r_se * r_se; total2_bh += r_bh * r_bh; - pearson_star_sf += r * r_sf; + pearson_star_sf_1 += r * r_sf_1; + pearson_star_sf_2 += r * r_sf_2; pearson_star_se += r * r_se; pearson_star_bh += r * r_bh; - pearson_sf_se += r_sf * r_se; - pearson_sf_bh += r_sf * r_bh; + pearson_sf_1_se += r_sf_1 * r_se; + pearson_sf_1_bh += r_sf_1 * r_bh; pearson_se_bh += r_se * r_bh; } @@ -231,25 +246,29 @@ int main(int argc, char* argv[]) { pearsonfunc(mean, meanID, pearsonIDs, var, varID, count); /* Mean and <x^2> for different processes */ - const double mean_sf = total_sf / (double)count; + const double mean_sf_1 = total_sf_1 / (double)count; + const double mean_sf_2 = total_sf_2 / (double)count; const double mean_se = total_se / (double)count; const double mean_bh = total_bh / (double)count; - const double var_sf = total2_sf / (double)count - mean_sf * mean_sf; + const double var_sf_1 = total2_sf_1 / (double)count - mean_sf_1 * mean_sf_1; + const double var_sf_2 = total2_sf_2 / (double)count - mean_sf_2 * mean_sf_2; const double var_se = total2_se / (double)count - mean_se * mean_se; const double var_bh = total2_bh / (double)count - mean_bh * mean_bh; /* Correlation between different processes */ - const double corr_star_sf = - pearsonfunc(mean, mean_sf, pearson_star_sf, var, var_sf, count); + const double corr_star_sf_1 = + pearsonfunc(mean, mean_sf_1, pearson_star_sf_1, var, var_sf_1, count); + const double corr_star_sf_2 = + pearsonfunc(mean, mean_sf_2, pearson_star_sf_2, var, var_sf_2, count); const double corr_star_se = pearsonfunc(mean, mean_se, pearson_star_se, var, var_se, count); const double corr_star_bh = pearsonfunc(mean, mean_bh, pearson_star_bh, var, var_bh, count); - const double corr_sf_se = - pearsonfunc(mean_sf, mean_se, pearson_sf_se, var_sf, var_se, count); - const double corr_sf_bh = - pearsonfunc(mean_sf, mean_bh, pearson_sf_bh, var_sf, var_bh, count); + const double corr_sf_1_se = pearsonfunc(mean_sf_1, mean_se, pearson_sf_1_se, + var_sf_1, var_se, count); + const double corr_sf_1_bh = pearsonfunc(mean_sf_1, mean_bh, pearson_sf_1_bh, + var_sf_1, var_bh, count); const double corr_se_bh = pearsonfunc(mean_se, mean_bh, pearson_se_bh, var_se, var_bh, count); @@ -274,11 +293,14 @@ int main(int argc, char* argv[]) { if ((fabs(mean - 0.5) > tolmean) || (fabs(var - 1. / 12.) > tolvar) || (fabs(correlation) > tolcorr) || (fabs(correlationID) > tolcorr) || (fabs(meanID - 0.5) > tolmean) || (fabs(varID - 1. / 12.) > tolvar) || - (fabs(corr_star_sf) > tolcorr) || (fabs(corr_star_se) > tolcorr) || - (fabs(corr_star_bh) > tolcorr) || (fabs(corr_sf_se) > tolcorr) || - (fabs(corr_sf_bh) > tolcorr) || (fabs(corr_se_bh) > tolcorr) || - (fabs(mean_sf - 0.5) > tolmean) || (fabs(mean_se - 0.5) > tolmean) || - (fabs(mean_bh - 0.5) > tolmean) || (fabs(var_sf - 1. / 12.) > tolvar) || + (fabs(corr_star_sf_1) > tolcorr) || (fabs(corr_star_sf_2) > tolcorr) || + (fabs(corr_star_se) > tolcorr) || (fabs(corr_star_bh) > tolcorr) || + (fabs(corr_sf_1_se) > tolcorr) || (fabs(corr_sf_1_bh) > tolcorr) || + (fabs(corr_se_bh) > tolcorr) || (fabs(mean_sf_1 - 0.5) > tolmean) || + (fabs(mean_sf_2 - 0.5) > tolmean) || (fabs(mean_se - 0.5) > tolmean) || + (fabs(mean_bh - 0.5) > tolmean) || + (fabs(var_sf_1 - 1. / 12.) > tolvar) || + (fabs(var_sf_2 - 1. / 12.) > tolvar) || (fabs(var_se - 1. / 12.) > tolvar) || (fabs(var_bh - 1. / 12.) > tolvar)) { message("Test failed!"); @@ -308,7 +330,7 @@ int main(int argc, char* argv[]) { message( "Means: stars=%f stellar feedback=%f stellar " " enrichment=%f black holes=%f", - mean, mean_sf, mean_se, mean_bh); + mean, mean_sf_1, mean_se, mean_bh); message( "Expected: stars=%f stellar feedback=%f stellar " " enrichment=%f black holes=%f", @@ -320,13 +342,13 @@ int main(int argc, char* argv[]) { message( "Diff: stars=%f stellar feedback=%f stellar " " enrichment=%f black holes=%f", - fabs(mean - .5f), fabs(mean_sf - .5f), fabs(mean_se - .5f), + fabs(mean - .5f), fabs(mean_sf_1 - .5f), fabs(mean_se - .5f), fabs(mean_bh - .5f)); message(" "); message( "Var: stars=%f stellar feedback=%f stellar " " enrichment=%f black holes=%f", - var, var_sf, var_se, var_bh); + var, var_sf_1, var_se, var_bh); message( "Expected: stars=%f stellar feedback=%f stellar " " enrichment=%f black holes=%f", @@ -338,14 +360,14 @@ int main(int argc, char* argv[]) { message( "Diff: stars=%f stellar feedback=%f stellar " " enrichment=%f black holes=%f", - fabs(var - 1. / 12.), fabs(var_sf - 1. / 12.), + fabs(var - 1. / 12.), fabs(var_sf_1 - 1. / 12.), fabs(var_se - 1. / 12.), fabs(var_bh - 1. / 12.)); message(" "); message( "Correlation: stars-sf=%f stars-se=%f stars-bh=%f " "sf-se=%f sf-bh=%f se-bh=%f", - corr_star_sf, corr_star_se, corr_star_bh, corr_sf_se, corr_sf_bh, - corr_se_bh); + corr_star_sf_1, corr_star_se, corr_star_bh, corr_sf_1_se, + corr_sf_1_bh, corr_se_bh); message( "Expected: stars-sf=%f stars-se=%f stars-bh=%f " "sf-se=%f sf-bh=%f se-bh=%f", @@ -355,10 +377,11 @@ int main(int argc, char* argv[]) { "sf-se=%f sf-bh=%f se-bh=%f", tolcorr, tolcorr, tolcorr, tolcorr, tolcorr, tolcorr); message( - "Diff: stars-sf=%f stars-se=%f stars-bh=%f " + "Diff: stars-sf1=%f stars-sf2=%f stars-se=%f stars-bh=%f " "sf-se=%f sf-bh=%f se-bh=%f", - fabs(corr_star_sf), fabs(corr_star_se), fabs(corr_star_bh), - fabs(corr_sf_se), fabs(corr_sf_bh), fabs(corr_se_bh)); + fabs(corr_star_sf_1), fabs(corr_star_sf_2), fabs(corr_star_se), + fabs(corr_star_bh), fabs(corr_sf_1_se), fabs(corr_sf_1_bh), + fabs(corr_se_bh)); return 1; } } diff --git a/tests/testRandomSpacing.c b/tests/testRandomSpacing.c index 0d2777ee702458ccaa6170483c48b83ce1a4fc7e..c7435db43e39456607a2986c8467616d67e91784 100644 --- a/tests/testRandomSpacing.c +++ b/tests/testRandomSpacing.c @@ -49,6 +49,9 @@ int main(int argc, char* argv[]) { message("Seed = %d", seed); srand(seed); + /* Log the swift random seed */ + message("SWIFT random seed = %d", SWIFT_RANDOM_SEED_XOR); + /* Time-step size */ const int time_bin = 30; diff --git a/tests/testSelectOutput.c b/tests/testSelectOutput.c index 4ede910ab9d182ebc141988c05eac672ab0fb635..8a08bcf58f0ece5645267a28f59c103506437165 100644 --- a/tests/testSelectOutput.c +++ b/tests/testSelectOutput.c @@ -83,7 +83,7 @@ int main(int argc, char *argv[]) { unsigned long long cpufreq = 0; clocks_set_cpufreq(cpufreq); - char *base_name = "testSelectOutput"; + const char *base_name = "testSelectOutput"; size_t Ngas = 0, Ngpart = 0, Ngpart_background = 0, Nspart = 0, Nbpart = 0; int flag_entropy_ICs = -1; int periodic = 1; @@ -96,7 +96,7 @@ int main(int argc, char *argv[]) { /* parse parameters */ message("Reading parameters."); struct swift_params param_file; - char *input_file = "selectOutput.yml"; + const char *input_file = "selectOutput.yml"; parser_read_file(input_file, ¶m_file); /* Default unit system */ @@ -152,7 +152,8 @@ int main(int argc, char *argv[]) { /* check output selection */ message("Checking output parameters."); - long long N_total[swift_type_count] = {Ngas, Ngpart, 0, 0, Nspart, 0}; + long long N_total[swift_type_count] = { + (long long)Ngas, (long long)Ngpart, 0, 0, (long long)Nspart, 0}; io_check_output_fields(¶m_file, N_total); /* write output file */ diff --git a/tests/testVoronoi2D.c b/tests/testVoronoi2D.c index 5057278efaa3ba0e1ccec2ba6b032cd12b029ff9..57d90b64abeef9beae6abe29bb9fb22f39e96aaa 100644 --- a/tests/testVoronoi2D.c +++ b/tests/testVoronoi2D.c @@ -200,15 +200,24 @@ int main(int argc, char *argv[]) { /* Check the total surface area */ assert(fabs(Atot - 1.0f) < 1.e-6); - /* Check the neighbour relations for an arbitrary cell: cell 44 - We plotted the grid and manually found the correct neighbours and their - order. */ - assert(cells[44].nvert == 4); - assert(cells[44].ngbs[0] == 34); - assert(cells[44].ngbs[1] == 45); - assert(cells[44].ngbs[2] == 54); - assert(cells[44].ngbs[3] == 43); - + /* Check the neighbour relations for an arbitrary cell: cell 44 We plotted + the grid and manually found the correct neighbours and their + order. Variation is found when optimizing, so we have two possible + outcomes... */ + if (cells[44].nvert == 5) { + assert(cells[44].nvert == 5); + assert(cells[44].ngbs[0] == 43); + assert(cells[44].ngbs[1] == 34); + assert(cells[44].ngbs[2] == 45); + assert(cells[44].ngbs[3] == 55); + + } else { + assert(cells[44].nvert == 4); + assert(cells[44].ngbs[0] == 34); + assert(cells[44].ngbs[1] == 45); + assert(cells[44].ngbs[2] == 54); + assert(cells[44].ngbs[3] == 43); + } message("Done."); } diff --git a/tests/tolerance_27_perturbed.dat b/tests/tolerance_27_perturbed.dat index 75974fe8f22a3cbc0d5ccc8e1022f56eaa45d6e7..fddca53228bd01df84b2c2bdfaec46d267987d10 100644 --- a/tests/tolerance_27_perturbed.dat +++ b/tests/tolerance_27_perturbed.dat @@ -1,4 +1,4 @@ # ID pos_x pos_y pos_z v_x v_y v_z rho rho_dh wcount wcount_dh div_v curl_vx curl_vy curl_vz 0 1e-6 1e-6 1e-6 1e-6 1e-6 1e-6 2e-6 1e-4 2e-4 1e-2 1e-5 3e-6 3e-6 7e-6 - 0 1e-6 1e-6 1e-6 1e-6 1e-6 1e-6 1e-6 1.5e-3 1e-5 2e-3 6e-5 3e-3 2e-3 2e-3 + 0 1e-6 1e-6 1e-6 1e-6 1e-6 1e-6 1e-6 3e-3 1e-5 2e-3 6e-5 3e-3 2e-3 2e-3 0 1e-6 1e-6 1e-6 1e-6 1e-6 1e-6 1e-6 2e-3 1e-6 1e0 1e-6 2e-6 2e-6 2e-6 diff --git a/tests/tolerance_27_perturbed_h.dat b/tests/tolerance_27_perturbed_h.dat index a1703f5b296d16f045fd28462fc9c61fc9358585..e8c97de8a0ef6789cd6a3bcdb71a38f002e8d787 100644 --- a/tests/tolerance_27_perturbed_h.dat +++ b/tests/tolerance_27_perturbed_h.dat @@ -1,4 +1,4 @@ # ID pos_x pos_y pos_z v_x v_y v_z rho rho_dh wcount wcount_dh div_v curl_vx curl_vy curl_vz 0 1e-6 1e-6 1e-6 1e-6 1e-6 1e-6 3e-6 1e-4 5e-4 1.4e-2 1.1e-5 3e-6 3e-6 8e-6 - 0 1e-6 1e-6 1e-6 1e-6 1e-6 1e-6 1.5e-6 1.4e-2 1e-5 2e-3 2.5e-4 3e-3 3e-3 3e-3 + 0 1e-6 1e-6 1e-6 1e-6 1e-6 1e-6 1.5e-6 1.7e-2 1e-5 2e-3 2.5e-4 3e-3 3e-3 3e-3 0 1e-6 1e-6 1e-6 1e-6 1e-6 1e-6 1e-6 1e-6 1e-6 1e0 1e-6 4e-6 4e-6 4e-6 diff --git a/tools/analyse_runtime.py b/tools/analyse_runtime.py index fda47afc946405c475b3d3809a2cfd1a2d28d656..6d6c61be463bbc398c612cc9838c0453587e6193 100755 --- a/tools/analyse_runtime.py +++ b/tools/analyse_runtime.py @@ -45,6 +45,7 @@ params = { "lines.markersize": 6, "lines.linewidth": 3.0, "text.latex.unicode": True, + 'hatch.linewidth': 4 } rcParams.update(params) @@ -53,6 +54,7 @@ threshold = 0.008 num_files = len(sys.argv) - 1 labels = [ + ["engine_split_gas_particles:", 1], ["Gpart assignment", 1], ["Mesh comunication", 1], ["Forward Fourier transform", 1], @@ -68,7 +70,6 @@ labels = [ ["Counting and linking tasks", 1], ["Setting super-pointers", 1], ["Making extra hydroloop tasks", 1], - ["Making extra starsloop tasks", 1], ["Linking gravity tasks", 1], ["Creating send tasks", 1], ["Exchanging cell tags", 1], @@ -82,8 +83,10 @@ labels = [ ["space_rebuild:", 1], ["engine_drift_all:", 0], ["engine_unskip:", 0], + ["engine_unskip_timestep_communications:", 0], ["engine_collect_end_of_step:", 0], - ["engine_launch:", 0], + ["engine_launch: \(tasks\)", 0], + ["engine_launch: \(timesteps\)", 0], ["writing particle properties", 0], ["engine_repartition:", 0], ["engine_exchange_cells:", 1], @@ -98,10 +101,16 @@ labels = [ ["space_init", 0], ["engine_init", 0], ["engine_repartition_trigger:", 0], - ["VR Collecting top-level cell info", 0], - ["VR Collecting particle info", 0], - ["VR Invokation of velociraptor", 0], - ["VR Copying group information back", 0] + ["VR Collecting top-level cell info", 3], + ["VR Collecting particle info", 3], + ["VR Invokation of velociraptor", 3], + ["VR Copying group information back", 3], + ["fof_allocate:", 2], + ["engine_make_fof_tasks:", 2], + ["engine_activate_fof_tasks:", 2], + ["fof_search_tree:", 2], + ["engine_launch: \(fof\)", 2], + ["engine_launch: \(fof comms\)", 2], ] times = np.zeros(len(labels)) counts = np.zeros(len(labels)) @@ -142,6 +151,7 @@ for i in range(num_files): # Extract the different blocks if re.search("%s took" % labels[i][0], line): + counts[i] += 1.0 times[i] += float( re.findall(r"[+-]?((\d+\.?\d*)|(\.\d+))", line)[-1][0] @@ -184,10 +194,16 @@ counts = counts[order] time_ratios = time_ratios[order] labels = [labels[i] for i in order] +# Remove the regexp escapes to make the labels prettier +for i in range(len(labels)): + labels[i][0] = labels[i][0].replace("\\","") + # Keep only the important components important_times = [0.0] important_ratios = [0.0] important_is_rebuild = [0] +important_is_fof = [0] +important_is_VR = [0] important_labels = ["Others (all below %.1f\%%)" % (threshold * 100)] need_print = True print("Time spent in the different code sections:") @@ -195,7 +211,9 @@ for i in range(len(labels)): if time_ratios[i] > threshold: important_times.append(times[i]) important_ratios.append(time_ratios[i]) - important_is_rebuild.append(labels[i][1]) + important_is_rebuild.append(labels[i][1] == 1) + important_is_fof.append(labels[i][1] == 2) + important_is_VR.append(labels[i][1] == 3) important_labels.append(labels[i][0]) else: if need_print: @@ -232,6 +250,19 @@ pie, _, _ = pie( startangle=-15, colors=cols, ) + +# Use hashing for the FOF and VR wedges +for i in range(len(pie)): + if (important_is_fof[i]): + pie[i].set_hatch('o') + pie[i].set_edgecolor(pie[i].get_facecolor()) + pie[i].set_fill(False) +for i in range(len(pie)): + if (important_is_VR[i]): + pie[i].set_hatch('+') + pie[i].set_edgecolor(pie[i].get_facecolor()) + pie[i].set_fill(False) + legend(pie, important_labels, title="SWIFT operations", loc="upper left") savefig("time_pie.pdf", dpi=150) diff --git a/tools/stylesheets/README b/tools/stylesheets/README new file mode 100644 index 0000000000000000000000000000000000000000..4b72981e6d55667be54b8389001502b68b59dc99 --- /dev/null +++ b/tools/stylesheets/README @@ -0,0 +1,2 @@ +This folder contains matplotlib stylesheets for use in python +plotting scripts. diff --git a/tools/stylesheets/mnras.mplstyle b/tools/stylesheets/mnras.mplstyle new file mode 100644 index 0000000000000000000000000000000000000000..2b1ff222b5fb3a20782896f23a91275957d9d269 --- /dev/null +++ b/tools/stylesheets/mnras.mplstyle @@ -0,0 +1,30 @@ +# Line Properties +lines.linewidth: 2 + +# Font options +font.size: 8 +font.family: STIXGeneral +mathtext.fontset: stix + +# LaTeX options +text.usetex: False + +# Legend options +legend.frameon: False +legend.fontsize: 8 + +# Figure options for publications +figure.dpi: 300 +figure.figsize: 3.321, 3.0 # Correct width for MNRAS + +# Histogram options +hist.bins: auto + +# Ticks inside plots; more space devoted to plot. +xtick.direction: in +ytick.direction: in +# Always plot ticks on top of data +axes.axisbelow: False + +# Setup colours +axes.prop_cycle: cycler('color', ['00AEFF','FF8C40','CC4314', '5766B3', '68246D']) diff --git a/tools/task_plots/analyse_tasks.py b/tools/task_plots/analyse_tasks.py index 8ba0c6ee5389a7427b6d096f444ddeb15362d71e..c093d18c2dba6bed0a22e9f7279285b45817445d 100755 --- a/tools/task_plots/analyse_tasks.py +++ b/tools/task_plots/analyse_tasks.py @@ -57,9 +57,17 @@ parser.add_argument( default="all", action="store", ) +parser.add_argument( + "--html", + dest="html", + help="Use html titles and anchors in the output (default: False)", + default=False, + action="store_true", +) args = parser.parse_args() infile = args.input +with_html = args.html # Tasks and subtypes. Indexed as in tasks.h. TASKTYPES = [ @@ -301,6 +309,8 @@ for rank in ranks: sidtimes[my_sid] = [] sidtimes[my_sid].append(dt) + if with_html: + print('<div id="thread{}"></div>'.format(i)) print("# Thread : ", i) for key in sorted(tasktimes.keys()): taskmin = min(tasktimes[key]) @@ -319,6 +329,8 @@ for rank in ranks: ) print() + if with_html: + print('<div id="all"></div>') print("# All threads : ") for key in sorted(alltasktimes.keys()): taskmin = min(alltasktimes[key]) @@ -338,6 +350,8 @@ for rank in ranks: print() # For pairs, show stuff sorted by SID + if with_html: + print('<div id="sid"></div>') print("# By SID (all threads): ") print( "# {0:<17s}: {1:>7s} {2:>9s} {3:>9s} {4:>9s} {5:>9s} {6:>9s}".format( @@ -375,6 +389,8 @@ for rank in ranks: # Dead times. print("# Times not in tasks (deadtimes)") print("# ------------------------------") + if with_html: + print('<div id="before"></div>') print("# Time before first task:") print("# no. : {0:>9s} {1:>9s}".format("value", "percent")) predeadtimes = [] @@ -410,6 +426,8 @@ for rank in ranks: ) print() + if with_html: + print('<div id="after"></div>') print("# Time after last task:") print("# no. : {0:>9s} {1:>9s}".format("value", "percent")) postdeadtimes = [] @@ -446,6 +464,8 @@ for rank in ranks: print() # Time in engine, i.e. from first to last tasks. + if with_html: + print('<div id="between"></div>') print("# Time between tasks (engine deadtime):") print( "# no. : {0:>9s} {1:>9s} {2:>9s} {3:>9s} {4:>9s} {5:>9s}".format( @@ -503,6 +523,8 @@ for rank in ranks: print() # All times in step. + if with_html: + print('<div id="dead"></div>') print("# All deadtimes:") print( "# no. : {0:>9s} {1:>9s} {2:>9s} {3:>9s} {4:>9s} {5:>9s}".format( diff --git a/tools/task_plots/analyse_threadpool_tasks.py b/tools/task_plots/analyse_threadpool_tasks.py index af8d88dc1d4dc319fe7506d604e550de22a55a81..425f6bb62e207908f88b748122ff4215e5f1f269 100755 --- a/tools/task_plots/analyse_threadpool_tasks.py +++ b/tools/task_plots/analyse_threadpool_tasks.py @@ -49,9 +49,17 @@ parser.add_argument( default=False, action="store_true", ) +parser.add_argument( + "--html", + dest="html", + help="Use html titles and anchors in the output (default: False)", + default=False, + action="store_true", +) args = parser.parse_args() infile = args.input +with_html = args.html # Read header. First two lines. with open(infile) as infid: @@ -145,6 +153,8 @@ for i in threadids: alltasktimes[key] = [] alltasktimes[key].append(dt) + if with_html: + print('<div id="thread{}"></div>'.format(i)) print("# Thread : ", i) for key in sorted(tasktimes.keys()): taskmin = min(tasktimes[key]) @@ -163,6 +173,8 @@ for i in threadids: ) print() +if with_html: + print('<div id="all"></div>') print("# All threads : ") for key in sorted(alltasktimes.keys()): taskmin = min(alltasktimes[key]) @@ -184,6 +196,8 @@ print() # Dead times. print("# Times not in tasks (deadtimes)") print("# ------------------------------") +if with_html: + print('<div id="before"></div>') print("# Time before first task:") print("# no. : {0:>9s} {1:>9s}".format("value", "percent")) predeadtimes = [] @@ -216,6 +230,8 @@ print( ) print() +if with_html: + print('<div id="after"></div>') print("# Time after last task:") print("# no. : {0:>9s} {1:>9s}".format("value", "percent")) postdeadtimes = [] @@ -249,6 +265,8 @@ print( print() # Time in threadpool, i.e. from first to last tasks. +if with_html: + print('<div id="between"></div>') print("# Time between tasks (threadpool deadtime):") print( "# no. : {0:>9s} {1:>9s} {2:>9s} {3:>9s} {4:>9s} {5:>9s}".format( @@ -303,6 +321,8 @@ print( print() # All times in step. +if with_html: + print('<div id="dead"></div>') print("# All deadtimes:") print( "# no. : {0:>9s} {1:>9s} {2:>9s} {3:>9s} {4:>9s} {5:>9s}".format( diff --git a/tools/task_plots/iplot_tasks.py b/tools/task_plots/iplot_tasks.py index c6f44dcf9d60338e9f738ce235e3e1a16327f498..dcac3ffe319b12d2a0ccf977faecaa05aa5d809a 100755 --- a/tools/task_plots/iplot_tasks.py +++ b/tools/task_plots/iplot_tasks.py @@ -402,7 +402,7 @@ data = data[1:, :] # Exit if no data. if data.size == 0: print(("# Rank ", rank, " has no tasks")) - os.exit(1) + sys.exit(1) start_t = float(tic_step) data[:, ticcol] -= start_t diff --git a/tools/task_plots/process_plot_tasks b/tools/task_plots/process_plot_tasks index 4df04ab46ba38f6346b8e857ba5002317520d3c6..54bb86fb414cb87ccbe2b7c93b18f010e77be465 100755 --- a/tools/task_plots/process_plot_tasks +++ b/tools/task_plots/process_plot_tasks @@ -60,7 +60,7 @@ done # And process them, echo "Processing thread info files..." echo $list | xargs -P $NPROCS -n 3 /bin/bash -c "${SCRIPTHOME}/plot_tasks.py --expand 1 --limit $TIMERANGE --width 16 --height 4 \$0 \$2 " -echo $list | xargs -P $NPROCS -n 3 /bin/bash -c "${SCRIPTHOME}/analyse_tasks.py \$0 > \$2.stats" +echo $list | xargs -P $NPROCS -n 3 /bin/bash -c "${SCRIPTHOME}/analyse_tasks.py --html \$0 > \$2.stats" echo "Writing output index.html file" # Construct document - serial. @@ -88,6 +88,7 @@ EOF <img src="step${s}r${i}.png"> <pre> EOF +echo "<nav>Jump to: <a href="#all">all threads</a> <a href="#dead">dead times</a></nav>" >> step${s}r${i}.html cat step${s}r${i}.stats >> step${s}r${i}.html cat <<EOF >> step${s}r${i}.html </body> diff --git a/tools/task_plots/process_plot_tasks_MPI b/tools/task_plots/process_plot_tasks_MPI index 736aad05b98aea619f79e2b2114815c8e0fbaa1c..d1a3c3c6685cebf0e24ecc355f286e4d26d6dd25 100755 --- a/tools/task_plots/process_plot_tasks_MPI +++ b/tools/task_plots/process_plot_tasks_MPI @@ -66,7 +66,7 @@ nrank=$(($nrank-1)) echo "Processing thread info files..." echo $list | xargs -P $NPROCS -n 3 /bin/bash -c "${SCRIPTHOME}/plot_tasks.py --expand 1 --limit $TIMERANGE \$0 \$2 " for i in $(seq 0 $nrank); do - echo $list | xargs -P $NPROCS -n 3 /bin/bash -c "${SCRIPTHOME}/analyse_tasks.py -r $i \$0 > \$2${i}.stats" + echo $list | xargs -P $NPROCS -n 3 /bin/bash -c "${SCRIPTHOME}/analyse_tasks.py -r $i --html \$0 > \$2${i}.stats" done echo "Writing output index.html file" @@ -110,6 +110,7 @@ EOF3 <img src="step${s}r${i}.png"> <pre> EOF2 +echo "<nav>Jump to: <a href="#all">all threads</a> <a href="#dead">dead times</a></nav>" >> step${s}r${i}.html cat step${s}r${i}.stats >> step${s}r${i}.html cat <<EOF2 >> step${s}r${i}.html </pre> diff --git a/tools/task_plots/process_plot_threadpool b/tools/task_plots/process_plot_threadpool index 0076ec1c4efc96d4a1dc5f9164cca2dd1b19ed5f..b1238b3668067f17b98099f6287fa63fec5d2395 100755 --- a/tools/task_plots/process_plot_threadpool +++ b/tools/task_plots/process_plot_threadpool @@ -65,7 +65,7 @@ done # And process them, echo "Processing threadpool info files..." echo $list | xargs -P $NPROCS -n 3 /bin/bash -c "${SCRIPTHOME}/plot_threadpool.py --expand 1 --limit $TIMERANGE --width 16 --height 4 \$0 \$2 " -echo $list | xargs -P $NPROCS -n 3 /bin/bash -c "${SCRIPTHOME}/analyse_threadpool_tasks.py \$0 > \$2.stats" +echo $list | xargs -P $NPROCS -n 3 /bin/bash -c "${SCRIPTHOME}/analyse_threadpool_tasks.py \$0 --html > \$2.stats" echo "Writing output threadpool-index.html file" # Construct document - serial.