From a651fa110bdb9dc7df89c93aad8ce0e9f58b0727 Mon Sep 17 00:00:00 2001 From: Matthieu Schaller <schaller@strw.leidenuniv.nl> Date: Thu, 23 Apr 2020 11:52:41 +0200 Subject: [PATCH] Implemented the new updated MAC --- src/gravity_properties.c | 3 +- src/gravity_properties.h | 16 ++-- src/multipole_accept.h | 179 +++++++++++++++++++++++++++++---------- 3 files changed, 143 insertions(+), 55 deletions(-) diff --git a/src/gravity_properties.c b/src/gravity_properties.c index cd7a890917..4297ca1b45 100644 --- a/src/gravity_properties.c +++ b/src/gravity_properties.c @@ -32,6 +32,7 @@ #include "gravity.h" #include "kernel_gravity.h" #include "kernel_long_gravity.h" +#include "restart.h" #define gravity_props_default_a_smooth 1.25f #define gravity_props_default_r_cut_max 4.5f @@ -86,8 +87,6 @@ void gravity_props_init(struct gravity_props *p, struct swift_params *params, /* Opening angle */ p->theta_crit = parser_get_param_double(params, "Gravity:theta"); if (p->theta_crit >= 1.) error("Theta too large. FMM won't converge."); - p->theta_crit2 = p->theta_crit * p->theta_crit; - p->theta_crit_inv = 1. / p->theta_crit; /* Mesh dithering */ if (periodic && !with_external_potential) { diff --git a/src/gravity_properties.h b/src/gravity_properties.h index 8a4abe4bd3..56f69bd253 100644 --- a/src/gravity_properties.h +++ b/src/gravity_properties.h @@ -26,10 +26,6 @@ #include <hdf5.h> #endif -/* Local includes. */ -#include "kernel_gravity.h" -#include "restart.h" - /* Forward declarations */ struct cosmology; struct phys_const; @@ -58,14 +54,14 @@ struct gravity_props { /* -------------- Properties of the FFM gravity ---------------------- */ - /*! Tree opening angle (Multipole acceptance criterion) */ - double theta_crit; + /*! Are we using the adaptive opening angle? */ + int use_adaptive_tolerance; - /*! Square of opening angle */ - double theta_crit2; + /*! Accuracy parameter of the advanced MAC */ + float adaptive_tolerance; - /*! Inverse of opening angle */ - double theta_crit_inv; + /*! Tree opening angle (Multipole acceptance criterion) */ + double theta_crit; /* ------------- Properties of the softened gravity ------------------ */ diff --git a/src/multipole_accept.h b/src/multipole_accept.h index a673098639..272b470bd4 100644 --- a/src/multipole_accept.h +++ b/src/multipole_accept.h @@ -23,67 +23,160 @@ #include "../config.h" /* Local includes */ +#include "binomial.h" +#include "integer_power.h" +#include "minmax.h" #include "multipole_struct.h" /** - * @brief Checks whether a cell-cell interaction can be appromixated by a M-M - * interaction using the distance and cell radius. + * @brief Checks whether The multipole in B can be used to update the field + * tensor in A. * - * We use the multipole acceptance criterion of Dehnen, 2002, JCoPh, Volume 179, - * Issue 1, pp.27-42, equation 10. + * We use the MAC of Dehnen 2014 eq. 16. * - * We also additionally check that the distance between the multipoles - * is larger than the softening lengths (here the distance at which - * the gravity becomes Newtonian again, not the Plummer-equivalent quantity). + * Note: this is *not* symmetric in A<->B unless the purely geometric criterion + * is used. * - * @param r_crit_a The size of the multipole A. - * @param r_crit_b The size of the multipole B. - * @param theta_crit2 The square of the critical opening angle. - * @param r2 Square of the distance (periodically wrapped) between the - * multipoles. - * @param epsilon_a The maximal softening length of any particle in A. - * @param epsilon_b The maximal softening length of any particle in B. + * @param props The properties of the gravity scheme. + * @param A The gravity tensors that we want to update (sink). + * @param B The gravity tensors that act as a source. + * @param r2 The square of the distance between the centres of mass of A and B. */ -__attribute__((always_inline, const)) INLINE static int gravity_M2L_accept( - const double r_crit_a, const double r_crit_b, const double theta_crit2, - const double r2, const double epsilon_a, const double epsilon_b) { +__attribute__((nonnull, pure)) INLINE static int gravity_M2L_accept( + const struct gravity_props *props, const struct gravity_tensors *restrict A, + const struct gravity_tensors *restrict B, const float r2) { - const double size = r_crit_a + r_crit_b; - const double size2 = size * size; - const double epsilon_a2 = epsilon_a * epsilon_a; - const double epsilon_b2 = epsilon_b * epsilon_b; + /* Order of the expansion */ + const int p = SELF_GRAVITY_MULTIPOLE_ORDER; - // MATTHIEU: Make this mass-dependent ? + /* Compute the error estimator (without the 1/M_B term that cancels out) */ + float E_BA_term = 0.f; + for (int n = 0; n <= p; ++n) { + E_BA_term += + binomial(p, n) * B->m_pole.power[n] * integer_powf(A->r_max, p - n); + } + E_BA_term *= 8.f; + E_BA_term *= max(A->r_max, B->r_max); + E_BA_term /= (A->r_max + B->r_max); - /* Multipole acceptance criterion (Dehnen 2002, eq.10) */ - return (r2 * theta_crit2 > size2) && (r2 > epsilon_a2) && (r2 > epsilon_b2); + /* Compute r^(p+2) */ +#if SELF_GRAVITY_MULTIPOLE_ORDER % 2 == 1 + const float r_to_p_plus2 = integer_powf(sqrtf(r2), (p + 2)); +#else + const float r_to_p_plus2 = integer_powf(r2, ((p / 2) + 1)); +#endif + + /* Get the mimimal acceleration in A */ + const float min_a_grav = A->m_pole.min_old_a_grav_norm; + + /* Get the maximal softening length in B */ + const float max_softening = B->m_pole.max_softening; + + /* Get the relative tolerance */ + const float eps = props->adaptive_tolerance; + + /* Get the basic geometric critical angle */ + const float theta_crit = props->theta_crit; + const float theta_crit2 = theta_crit * theta_crit; + + /* Get the sum of the multipole sizes */ + const float rho_sum = A->r_max + B->r_max; + + if (props->use_adaptive_tolerance) { + + /* Test the different conditions */ + + /* Condition 1: We are in the converging part of the Taylor expansion */ + const int cond_1 = rho_sum * rho_sum < r2; + + /* Condition 2: We are not below softening */ + const int cond_2 = max_softening * max_softening < r2; + + /* Condition 3: The contribution is accurate enough + * (E_BA / r^(p+2) < eps a_min) */ + const int cond_3 = E_BA_term < eps * min_a_grav * r_to_p_plus2; + + return cond_1 && cond_2 && cond_3; + + } else { + + /* Condition 1: We are in the converging part of the Taylor expansion */ + const int cond_1 = rho_sum * rho_sum < theta_crit2 * r2; + + /* Condition 2: We are not below softening */ + const int cond_2 = max_softening * max_softening < r2; + + return cond_1 && cond_2; + } } /** - * @brief Checks whether a particle-cell interaction can be appromixated by a - * M2P interaction using the distance and cell radius. - * - * We use the multipole acceptance criterion of Dehnen, 2002, JCoPh, Volume 179, - * Issue 1, pp.27-42, equation 10. + * @brief Checks whether The multipole in B can be used to update the particle + * pa * - * We also additionally check that the distance between the particle and the - * multipole is larger than the softening length (here the distance at which - * the gravity becomes Newtonian again, not the Plummer-equivalent quantity). + * We use the MAC of Dehnen 2014 eq. 16. * - * @param r_max2 The square of the size of the multipole. - * @param theta_crit2 The square of the critical opening angle. - * @param r2 Square of the distance (periodically wrapped) between the - * particle and the multipole. - * @param epsilon The softening length of the particle. + * @param props The properties of the gravity scheme. + * @param pa The particle we want to compute forces for (sink) + * @param B The gravity tensors that act as a source. + * @param r2 The square of the distance between pa and the centres of mass of B. */ -__attribute__((always_inline, const)) INLINE static int gravity_M2P_accept( - const float r_max2, const float theta_crit2, const float r2, - const float epsilon) { +__attribute__((nonnull, pure)) INLINE static int gravity_M2P_accept( + const struct gravity_props *props, const struct gpart *pa, + const struct gravity_tensors *B, const float r2) { + + /* Order of the expansion */ + const int p = SELF_GRAVITY_MULTIPOLE_ORDER; + + /* Compute the error estimator (without the 1/M_B term that cancels out) */ + float E_BA_term = 8.f * B->m_pole.power[p]; + + /* Compute r^(p+2) */ +#if SELF_GRAVITY_MULTIPOLE_ORDER % 2 == 1 + const float r_to_p_plus2 = integer_powf(sqrtf(r2), (p + 2)); +#else + const float r_to_p_plus2 = integer_powf(r2, ((p / 2) + 1)); +#endif + + /* Get the estimate of the acceleration */ + const float old_a_grav = pa->old_a_grav_norm; + + /* Get the maximal softening length in B */ + const float max_softening = B->m_pole.max_softening; + + /* Get the relative tolerance */ + const float eps = props->adaptive_tolerance; + + /* Get the basic geometric critical angle */ + const float theta_crit = props->theta_crit; + const float theta_crit2 = theta_crit * theta_crit; + + if (props->use_adaptive_tolerance) { + + /* Test the different conditions */ + + /* Condition 1: We are in the converging part of the Taylor expansion */ + const int cond_1 = (B->r_max) * (B->r_max) < r2; + + /* Condition 2: We are not below softening */ + const int cond_2 = max_softening * max_softening < r2; + + /* Condition 3: The contribution is accurate enough + * (E_BA / r^(p+2) < eps * a) */ + const int cond_3 = E_BA_term < eps * old_a_grav * r_to_p_plus2; + + return cond_1 && cond_2 && cond_3; + + } else { + + /* Condition 1: We are in the converging part of the Taylor expansion */ + const int cond_1 = (B->r_max) * (B->r_max) < theta_crit2 * r2; - // MATTHIEU: Make this mass-dependent ? + /* Condition 2: We are not below softening */ + const int cond_2 = max_softening * max_softening < r2; - /* Multipole acceptance criterion (Dehnen 2002, eq.10) */ - return (r2 * theta_crit2 > r_max2) && (r2 > epsilon * epsilon); + return cond_1 && cond_2; + } } #endif /* SWIFT_MULTIPOLE_ACCEPT_H */ -- GitLab