diff --git a/doc/RTD/source/ParameterFiles/parameter_description.rst b/doc/RTD/source/ParameterFiles/parameter_description.rst index aca912da99771085d9d1068adf2f1587980c013d..acfb303ecf8d88ddd133e4a765f33fdb0022231e 100644 --- a/doc/RTD/source/ParameterFiles/parameter_description.rst +++ b/doc/RTD/source/ParameterFiles/parameter_description.rst @@ -259,14 +259,16 @@ The accuracy of the gravity calculation is governed by the following four parame * The accuracy criterion used in the adaptive MAC: :math:`\epsilon_{\rm fmm}`: ``epsilon_fmm``, * The time-step size pre-factor :math:`\eta`: ``eta``, -The first three parameters govern the way the Fast-Multipole method -tree-walk is done (see the theory documents for full details). The ``MAC`` -parameter can take two values: ``adaptive`` or ``geometric``. In the first -case, the tree recursion decision is based on the estimated accelerations -that a given tree node will produce, trying to recurse to levels where the -fractional contribution of the accelerations to the cell is less than -:math:`\epsilon_{\rm fmm}`. In the second case, a fixed Barnes-Hut-like -opening angle :math:`\theta_{\rm cr}` is used. +The first three parameters govern the way the Fast-Multipole method tree-walk is +done (see the theory documents for full details). The ``MAC`` parameter can +take three values: ``adaptive``, ``geometric``, or ``gadget``. In the first +case, the tree recursion decision is based on the estimated accelerations that a +given tree node will produce, trying to recurse to levels where the fractional +contribution of the accelerations to the cell is less than :math:`\epsilon_{\rm +fmm}`. In the second case, a fixed Barnes-Hut-like opening angle +:math:`\theta_{\rm cr}` is used. The final case corresponds to the choice made +in the Gadget-4 code. It is an implementation using eq. 36 of `Springel et +al. (2021) <https://adsabs.harvard.edu/abs/2021MNRAS.506.2871S>`_. The time-step of a given particle is given by :math:`\Delta t = \sqrt{2\eta\epsilon_i/|\overrightarrow{a}_i|}`, where diff --git a/src/gravity_properties.c b/src/gravity_properties.c index 9dc3805615f5676304ae913429f39877e94664d7..b02e406d40800302ddd6d9520fba7c1af7c97e07 100644 --- a/src/gravity_properties.c +++ b/src/gravity_properties.c @@ -37,7 +37,7 @@ #define gravity_props_default_a_smooth 1.25f #define gravity_props_default_r_cut_max 4.5f -#define gravity_props_default_r_cut_min 0.1f +#define gravity_props_default_r_cut_min 0.0f #define gravity_props_default_rebuild_frequency 0.01f #define gravity_props_default_rebuild_active_fraction 1.01f // > 1 means never #define gravity_props_default_distributed_mesh 0 @@ -124,12 +124,16 @@ void gravity_props_init(struct gravity_props *p, struct swift_params *params, if (strcmp(buffer, "adaptive") == 0) { p->use_adaptive_tolerance = 1; + p->use_gadget_tolerance = 0; + } else if (strcmp(buffer, "gadget") == 0) { + p->use_adaptive_tolerance = 1; + p->use_gadget_tolerance = 1; } else if (strcmp(buffer, "geometric") == 0) { p->use_adaptive_tolerance = 0; } else { error( "Invalid choice of multipole acceptance criterion: '%s'. Should be " - "'adaptive' or 'geometric'", + "'adaptive', 'gadget', or 'geometric'", buffer); } @@ -295,9 +299,15 @@ void gravity_props_print(const struct gravity_props *p) { message("Self-gravity time integration: eta=%.4f", p->eta); if (p->use_adaptive_tolerance) { - message("Self-gravity opening angle scheme: adaptive"); - message("Self-gravity opening angle: epsilon_fmm=%.6f", - p->adaptive_tolerance); + if (p->use_gadget_tolerance) { + message("Self-gravity opening angle scheme: Gadget"); + message("Self-gravity opening angle: epsilon_fmm=%.6f", + p->adaptive_tolerance); + } else { + message("Self-gravity opening angle scheme: adaptive"); + message("Self-gravity opening angle: epsilon_fmm=%.6f", + p->adaptive_tolerance); + } } else { message("Self-gravity opening angle scheme: fixed"); message("Self-gravity opening angle: theta_cr=%.4f", p->theta_crit); diff --git a/src/gravity_properties.h b/src/gravity_properties.h index 9fd4d089ffe572bfd9e8569a864b1e7fff6def54..2a3be6c22497a62d816a34265e8e30951d4a87af 100644 --- a/src/gravity_properties.h +++ b/src/gravity_properties.h @@ -66,6 +66,10 @@ struct gravity_props { /*! Are we using the adaptive opening angle? (as read from param file) */ int use_adaptive_tolerance; + /*! Are we using the Gadget adaptive opening angle? (as read from param file) + */ + int use_gadget_tolerance; + /*! Accuracy parameter of the advanced MAC */ float adaptive_tolerance; diff --git a/src/multipole_accept.h b/src/multipole_accept.h index bf052c19d1d8774f3e0fade7086e77d3032f6930..dd9c899512fd712cdd0deac42c79942e98e70dee 100644 --- a/src/multipole_accept.h +++ b/src/multipole_accept.h @@ -84,12 +84,15 @@ __attribute__((nonnull, pure)) INLINE static int gravity_M2L_accept( const int use_rebuild_sizes, const int periodic) { /* Order of the expansion */ - const int p = SELF_GRAVITY_MULTIPOLE_ORDER; + const int p = 2; /* Sizes of the multipoles */ const float rho_A = use_rebuild_sizes ? A->r_max_rebuild : A->r_max; const float rho_B = use_rebuild_sizes ? B->r_max_rebuild : B->r_max; + /* Max size of both multipoles */ + const float rho_max = max(rho_A, rho_B); + /* Get the softening */ const float max_softening = max(A->m_pole.max_softening, B->m_pole.max_softening); @@ -102,19 +105,16 @@ __attribute__((nonnull, pure)) INLINE static int gravity_M2L_accept( } E_BA_term *= 8.f; if (rho_A + rho_B > 0.f) { - E_BA_term *= max(rho_A, rho_B); + E_BA_term *= rho_max; + ; E_BA_term /= (rho_A + rho_B); } - /* Compute r^p */ -#if SELF_GRAVITY_MULTIPOLE_ORDER % 2 == 1 - const float r_to_p = integer_powf(sqrtf(r2), p); -#else + /* Compute r^p = (r^2)^(p/2) */ const float r_to_p = integer_powf(r2, (p / 2)); -#endif float f_MAC_inv; - if (props->consider_truncation_in_MAC) { + if (periodic && props->consider_truncation_in_MAC) { f_MAC_inv = gravity_f_MAC_inverse(max_softening, props->r_s_inv, r2); } else { f_MAC_inv = r2; @@ -123,6 +123,9 @@ __attribute__((nonnull, pure)) INLINE static int gravity_M2L_accept( /* Get the mimimal acceleration in A */ const float min_a_grav = A->m_pole.min_old_a_grav_norm; + /* Maximal mass */ + const float M_max = max(A->m_pole.M_000, B->m_pole.M_000); + /* Get the relative tolerance */ const float eps = props->adaptive_tolerance; @@ -133,7 +136,19 @@ __attribute__((nonnull, pure)) INLINE static int gravity_M2L_accept( /* Get the sum of the multipole sizes */ const float rho_sum = rho_A + rho_B; - if (props->use_advanced_MAC) { + if (props->use_advanced_MAC && props->use_gadget_tolerance) { + + /* Gadget 4 paper -- eq. 36 */ + const int power = SELF_GRAVITY_MULTIPOLE_ORDER - 1; + const float ratio = integer_powf(rho_max / sqrtf(r2), power); + const int cond_1 = M_max * ratio < eps * min_a_grav * f_MAC_inv; + + const int cond_2 = + props->use_tree_below_softening || max_softening * max_softening < r2; + + return cond_1 && cond_2; + + } else if (props->use_advanced_MAC && !props->use_gadget_tolerance) { #ifdef SWIFT_DEBUG_CHECKS if (min_a_grav == 0.) error("Acceleration is 0"); @@ -277,7 +292,7 @@ __attribute__((nonnull, pure)) INLINE static int gravity_M2P_accept( const struct gravity_tensors *B, const float r2, const int periodic) { /* Order of the expansion */ - const int p = SELF_GRAVITY_MULTIPOLE_ORDER; + const int p = 2; /* Sizes of the multipoles */ const float rho_B = B->r_max; @@ -293,15 +308,11 @@ __attribute__((nonnull, pure)) INLINE static int gravity_M2P_accept( /* Compute the error estimator (without the 1/M_B term that cancels out) */ const float E_BA_term = 8.f * B->m_pole.power[p]; - /* Compute r^p */ -#if SELF_GRAVITY_MULTIPOLE_ORDER % 2 == 1 - const float r_to_p = integer_powf(sqrtf(r2), p); -#else + /* Compute r^p = (r^2)^(p/2) */ const float r_to_p = integer_powf(r2, (p / 2)); -#endif float f_MAC_inv; - if (props->consider_truncation_in_MAC) { + if (periodic && props->consider_truncation_in_MAC) { f_MAC_inv = gravity_f_MAC_inverse(max_softening, props->r_s_inv, r2); } else { f_MAC_inv = r2; @@ -317,7 +328,19 @@ __attribute__((nonnull, pure)) INLINE static int gravity_M2P_accept( const float theta_crit = props->theta_crit; const float theta_crit2 = theta_crit * theta_crit; - if (props->use_advanced_MAC) { + if (props->use_advanced_MAC && props->use_gadget_tolerance) { + + /* Gadget 4 paper -- eq. 12 */ + const int power = SELF_GRAVITY_MULTIPOLE_ORDER; + const float ratio = integer_powf(rho_B / sqrtf(r2), power); + const int cond_1 = B->m_pole.M_000 * ratio < eps * old_a_grav * f_MAC_inv; + + const int cond_2 = + props->use_tree_below_softening || max_softening * max_softening < r2; + + return cond_1 && cond_2; + + } else if (props->use_advanced_MAC && !props->use_gadget_tolerance) { #ifdef SWIFT_DEBUG_CHECKS if (old_a_grav == 0.) error("Acceleration is 0");