diff --git a/src/Makefile.am b/src/Makefile.am index 19af973ef6200e53220447e09236c02535020d73..587b36fc6b5963f48d9cd6d14b20a5c292698eeb 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -54,7 +54,9 @@ nobase_noinst_HEADERS = approx_math.h atomic.h cycle.h error.h inline.h kernel.h hydro/Default/hydro.h hydro/Default/hydro_iact.h hydro/Default/hydro_io.h \ hydro/Default/hydro_debug.h hydro/Default/hydro_part.h \ hydro/Gadget2/hydro.h hydro/Gadget2/hydro_iact.h hydro/Gadget2/hydro_io.h \ - hydro/Gadget2/hydro_debug.h hydro/Gadget2/hydro_part.h + hydro/Gadget2/hydro_debug.h hydro/Gadget2/hydro_part.h \ + hydro/Gizmo/hydro.h hydro/Gizmo/hydro_iact.h hydro/Gizmo/hydro_io.h \ + hydro/Gizmo/hydro_debug.h hydro/Gizmo/hydro_part.h # Sources and flags for regular library libswiftsim_la_SOURCES = $(AM_SOURCES) diff --git a/src/hydro/Gizmo/hydro.h b/src/hydro/Gizmo/hydro.h new file mode 100644 index 0000000000000000000000000000000000000000..f3553a009c22a2f6353796e8a278f0db7d66d294 --- /dev/null +++ b/src/hydro/Gizmo/hydro.h @@ -0,0 +1,621 @@ +/******************************************************************************* + * This file is part of SWIFT. + * Coypright (c) 2015 Matthieu Schaller (matthieu.schaller@durham.ac.uk) + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published + * by the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this program. If not, see <http://www.gnu.org/licenses/>. + * + ******************************************************************************/ + +/** + * @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 + * + */ +__attribute__((always_inline)) INLINE static float hydro_compute_timestep( + struct part* p, struct xpart* xp) { + + return const_cfl * p->h / fabs(p->timestepvars.vmax); +} + +/** + * @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. + * + * @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) { +} + +/** + * @brief Prepares a particle for the volume calculation. + * + * @param p The particle to act upon + */ +__attribute__((always_inline)) + INLINE static void hydro_init_part(struct part* p) { + +#ifdef SPH_GRADIENTS + /* use the old volumes to estimate new primitive variables to be used for the + gradient calculation */ + if (p->conserved.mass) { + p->primitives.rho = p->conserved.mass / p->geometry.volume; + p->primitives.v[0] = p->conserved.momentum[0] / p->conserved.mass; + p->primitives.v[1] = p->conserved.momentum[1] / p->conserved.mass; + p->primitives.v[2] = p->conserved.momentum[2] / p->conserved.mass; + p->primitives.P = + (const_hydro_gamma - 1.) * + (p->conserved.energy - + 0.5 * (p->conserved.momentum[0] * p->conserved.momentum[0] + + p->conserved.momentum[1] * p->conserved.momentum[1] + + p->conserved.momentum[2] * p->conserved.momentum[2]) / + p->conserved.mass) / + p->geometry.volume; + } +#endif + + 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; + +#ifdef SPH_GRADIENTS + 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; + + 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; +#endif +} + +/** + * @brief Finishes the density calculation. + * + * Multiplies the density and number of neighbours by the appropiate constants + * and add the self-contribution term. + * + * @param p The particle to act upon + */ +__attribute__((always_inline)) + INLINE static void hydro_end_volume(struct part* p) { + + /* Some smoothing length multiples. */ + const float h = p->h; + const float ih = 1.0f / h; + + /* Final operation on the density. */ + p->density.wcount = + (p->density.wcount + kernel_root) * (4.0f / 3.0 * M_PI * kernel_gamma3); + p->density.wcount_dh = + p->density.wcount_dh * ih * (4.0f / 3.0 * M_PI * kernel_gamma3); +} + +/** + * @brief Prepare a particle for the force calculation. + * + * Computes viscosity term, conduction term and smoothing length gradient terms. + * + * @param p The particle to act upon + * @param xp The extended particle data to act upon + */ +__attribute__((always_inline)) INLINE static void hydro_prepare_gradient( + struct part* p, struct xpart* xp) { + + /* Some smoothing length multiples. */ + const float h = p->h; + const float ih = 1.0f / h; + const float ih2 = ih * ih; + + float detE, volume; + float E[3][3]; + GFLOAT m, momentum[3], energy; + +#ifndef THERMAL_ENERGY + GFLOAT momentum2; +#endif + +#if defined(SPH_GRADIENTS) && defined(SLOPE_LIMITER) + GFLOAT gradrho[3], gradv[3][3], gradP[3]; + GFLOAT gradtrue, gradmax, gradmin, alpha; +#endif + + /* Final operation on the geometry. */ + /* we multiply with the smoothing kernel normalization ih3 and calculate the + * volume */ + volume = ih * ih2 * (p->geometry.volume + kernel_root); + p->geometry.volume = volume = 1. / volume; + /* we multiply with the smoothing kernel normalization */ + p->geometry.matrix_E[0][0] = E[0][0] = ih * ih2 * p->geometry.matrix_E[0][0]; + p->geometry.matrix_E[0][1] = E[0][1] = ih * ih2 * p->geometry.matrix_E[0][1]; + p->geometry.matrix_E[0][2] = E[0][2] = ih * ih2 * p->geometry.matrix_E[0][2]; + p->geometry.matrix_E[1][0] = E[1][0] = ih * ih2 * p->geometry.matrix_E[1][0]; + p->geometry.matrix_E[1][1] = E[1][1] = ih * ih2 * p->geometry.matrix_E[1][1]; + p->geometry.matrix_E[1][2] = E[1][2] = ih * ih2 * p->geometry.matrix_E[1][2]; + p->geometry.matrix_E[2][0] = E[2][0] = ih * ih2 * p->geometry.matrix_E[2][0]; + p->geometry.matrix_E[2][1] = E[2][1] = ih * ih2 * p->geometry.matrix_E[2][1]; + p->geometry.matrix_E[2][2] = E[2][2] = ih * ih2 * p->geometry.matrix_E[2][2]; + + /* invert the E-matrix */ + /* code shamelessly stolen from the public version of GIZMO */ + /* But since we should never invert a matrix, this code has to be replaced */ + detE = E[0][0] * E[1][1] * E[2][2] + E[0][1] * E[1][2] * E[2][0] + + E[0][2] * E[1][0] * E[2][1] - E[0][2] * E[1][1] * E[2][0] - + E[0][1] * E[1][0] * E[2][2] - E[0][0] * E[1][2] * E[2][1]; + /* check for zero determinant */ + if ((detE != 0) && !isnan(detE)) { + p->geometry.matrix_E[0][0] = (E[1][1] * E[2][2] - E[1][2] * E[2][1]) / detE; + p->geometry.matrix_E[0][1] = (E[0][2] * E[2][1] - E[0][1] * E[2][2]) / detE; + p->geometry.matrix_E[0][2] = (E[0][1] * E[1][2] - E[0][2] * E[1][1]) / detE; + p->geometry.matrix_E[1][0] = (E[1][2] * E[2][0] - E[1][0] * E[2][2]) / detE; + p->geometry.matrix_E[1][1] = (E[0][0] * E[2][2] - E[0][2] * E[2][0]) / detE; + p->geometry.matrix_E[1][2] = (E[0][2] * E[1][0] - E[0][0] * E[1][2]) / detE; + p->geometry.matrix_E[2][0] = (E[1][0] * E[2][1] - E[1][1] * E[2][0]) / detE; + p->geometry.matrix_E[2][1] = (E[0][1] * E[2][0] - E[0][0] * E[2][1]) / detE; + p->geometry.matrix_E[2][2] = (E[0][0] * E[1][1] - E[0][1] * E[1][0]) / detE; + } else { + /* if the E-matrix is not well behaved, we cannot use it */ + 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; + } + +#ifdef SPH_GRADIENTS + /* finalize gradients by multiplying with volume */ + p->primitives.gradients.rho[0] *= ih2 * ih2 * volume; + p->primitives.gradients.rho[1] *= ih2 * ih2 * volume; + p->primitives.gradients.rho[2] *= ih2 * ih2 * volume; + + p->primitives.gradients.v[0][0] *= ih2 * ih2 * volume; + p->primitives.gradients.v[0][1] *= ih2 * ih2 * volume; + p->primitives.gradients.v[0][2] *= ih2 * ih2 * volume; + + p->primitives.gradients.v[1][0] *= ih2 * ih2 * volume; + p->primitives.gradients.v[1][1] *= ih2 * ih2 * volume; + p->primitives.gradients.v[1][2] *= ih2 * ih2 * volume; + + p->primitives.gradients.v[2][0] *= ih2 * ih2 * volume; + p->primitives.gradients.v[2][1] *= ih2 * ih2 * volume; + p->primitives.gradients.v[2][2] *= ih2 * ih2 * volume; + + p->primitives.gradients.P[0] *= ih2 * ih2 * volume; + p->primitives.gradients.P[1] *= ih2 * ih2 * volume; + p->primitives.gradients.P[2] *= ih2 * ih2 * volume; + +/* slope limiter */ +#ifdef SLOPE_LIMITER + 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]); + /* gradtrue might be zero. In this case, there is no gradient and we don't + need to slope limit anything... */ + if (gradtrue) { + gradtrue *= p->primitives.limiter.maxr; + gradmax = p->primitives.limiter.rho[1] - p->primitives.rho; + gradmin = p->primitives.rho - p->primitives.limiter.rho[0]; + alpha = fmin(1.0f, fmin(gradmax / gradtrue, gradmin / gradtrue)); + 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; + gradmax = p->primitives.limiter.v[0][1] - p->primitives.v[0]; + gradmin = p->primitives.v[0] - p->primitives.limiter.v[0][0]; + alpha = fmin(1.0f, fmin(gradmax / gradtrue, gradmin / gradtrue)); + 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; + gradmax = p->primitives.limiter.v[1][1] - p->primitives.v[1]; + gradmin = p->primitives.v[1] - p->primitives.limiter.v[1][0]; + alpha = fmin(1.0f, fmin(gradmax / gradtrue, gradmin / gradtrue)); + 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; + gradmax = p->primitives.limiter.v[2][1] - p->primitives.v[2]; + gradmin = p->primitives.v[2] - p->primitives.limiter.v[2][0]; + alpha = fmin(1.0f, fmin(gradmax / gradtrue, gradmin / gradtrue)); + 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; + gradmax = p->primitives.limiter.P[1] - p->primitives.P; + gradmin = p->primitives.P - p->primitives.limiter.P[0]; + alpha = fmin(1.0f, fmin(gradmax / gradtrue, gradmin / gradtrue)); + p->primitives.gradients.P[0] *= alpha; + p->primitives.gradients.P[1] *= alpha; + p->primitives.gradients.P[2] *= alpha; + } +#endif // SLOPE_LIMITER +#else // SPH_GRADIENTS + 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; + + 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; +#endif // SPH_GRADIENTS + + /* compute primitive variables */ + /* eqns (3)-(5) */ + m = p->conserved.mass; + if (m) { + momentum[0] = p->conserved.momentum[0]; + momentum[1] = p->conserved.momentum[1]; + momentum[2] = p->conserved.momentum[2]; +#ifndef THERMAL_ENERGY + momentum2 = (momentum[0] * momentum[0] + momentum[1] * momentum[1] + + momentum[2] * momentum[2]); +#endif + energy = p->conserved.energy; + p->primitives.rho = m / volume; + p->primitives.v[0] = momentum[0] / m; + p->primitives.v[1] = momentum[1] / m; + p->primitives.v[2] = momentum[2] / m; +#ifndef THERMAL_ENERGY + p->primitives.P = + (const_hydro_gamma - 1.) * (energy - 0.5 * momentum2 / m) / volume; +#else + p->primitives.P = (const_hydro_gamma - 1.) * energy / volume; +#endif + } +} + +/** + * @brief Finishes the gradient calculation. + * + * @param p The particle to act upon + */ +__attribute__((always_inline)) + INLINE static void hydro_end_gradient(struct part* p) { + +#ifndef SPH_GRADIENTS + float h, ih, ih2, ih3; +#ifdef SLOPE_LIMITER + GFLOAT gradrho[3], gradv[3][3], gradP[3]; + GFLOAT gradtrue, gradmax, gradmin, alpha; +#endif + + /* add kernel normalization to gradients */ + h = p->h; + ih = 1.0f / h; + ih2 = ih * ih; + ih3 = ih * ih2; + + p->primitives.gradients.rho[0] *= ih3; + p->primitives.gradients.rho[1] *= ih3; + p->primitives.gradients.rho[2] *= ih3; + + p->primitives.gradients.v[0][0] *= ih3; + p->primitives.gradients.v[0][1] *= ih3; + p->primitives.gradients.v[0][2] *= ih3; + p->primitives.gradients.v[1][0] *= ih3; + p->primitives.gradients.v[1][1] *= ih3; + p->primitives.gradients.v[1][2] *= ih3; + p->primitives.gradients.v[2][0] *= ih3; + p->primitives.gradients.v[2][1] *= ih3; + p->primitives.gradients.v[2][2] *= ih3; + + p->primitives.gradients.P[0] *= ih3; + p->primitives.gradients.P[1] *= ih3; + p->primitives.gradients.P[2] *= ih3; + +/* slope limiter */ +#ifdef SLOPE_LIMITER + 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 = gradrho[0] * gradrho[0] + gradrho[1] * gradrho[1] + + gradrho[2] * gradrho[2]; + /* gradtrue might be zero. In this case, there is no gradient and we don't + need to slope limit anything... */ + if (gradtrue) { + gradtrue = sqrtf(gradtrue); + gradtrue *= p->primitives.limiter.maxr; + gradmax = p->primitives.limiter.rho[1] - p->primitives.rho; + gradmin = p->primitives.rho - p->primitives.limiter.rho[0]; + /* gradmin and gradmax might be negative if the value of the current + particle is larger/smaller than all neighbouring values */ + gradmax = fabs(gradmax); + gradmin = fabs(gradmin); + alpha = fmin(1.0f, fmin(gradmax / gradtrue, gradmin / gradtrue)); + p->primitives.gradients.rho[0] *= alpha; + p->primitives.gradients.rho[1] *= alpha; + p->primitives.gradients.rho[2] *= alpha; + } + + gradtrue = gradv[0][0] * gradv[0][0] + gradv[0][1] * gradv[0][1] + + gradv[0][2] * gradv[0][2]; + if (gradtrue) { + gradtrue = sqrtf(gradtrue); + gradtrue *= p->primitives.limiter.maxr; + gradmax = p->primitives.limiter.v[0][1] - p->primitives.v[0]; + gradmin = p->primitives.v[0] - p->primitives.limiter.v[0][0]; + gradmax = fabs(gradmax); + gradmin = fabs(gradmin); + alpha = fmin(1.0f, fmin(gradmax / gradtrue, gradmin / gradtrue)); + p->primitives.gradients.v[0][0] *= alpha; + p->primitives.gradients.v[0][1] *= alpha; + p->primitives.gradients.v[0][2] *= alpha; + } + + gradtrue = gradv[1][0] * gradv[1][0] + gradv[1][1] * gradv[1][1] + + gradv[1][2] * gradv[1][2]; + if (gradtrue) { + gradtrue = sqrtf(gradtrue); + gradtrue *= p->primitives.limiter.maxr; + gradmax = p->primitives.limiter.v[1][1] - p->primitives.v[1]; + gradmin = p->primitives.v[1] - p->primitives.limiter.v[1][0]; + gradmax = fabs(gradmax); + gradmin = fabs(gradmin); + alpha = fmin(1.0f, fmin(gradmax / gradtrue, gradmin / gradtrue)); + p->primitives.gradients.v[1][0] *= alpha; + p->primitives.gradients.v[1][1] *= alpha; + p->primitives.gradients.v[1][2] *= alpha; + } + + gradtrue = gradv[2][0] * gradv[2][0] + gradv[2][1] * gradv[2][1] + + gradv[2][2] * gradv[2][2]; + if (gradtrue) { + gradtrue = sqrtf(gradtrue); + gradtrue *= p->primitives.limiter.maxr; + gradmax = p->primitives.limiter.v[2][1] - p->primitives.v[2]; + gradmin = p->primitives.v[2] - p->primitives.limiter.v[2][0]; + gradmax = fabs(gradmax); + gradmin = fabs(gradmin); + alpha = fmin(1.0f, fmin(gradmax / gradtrue, gradmin / gradtrue)); + p->primitives.gradients.v[2][0] *= alpha; + p->primitives.gradients.v[2][1] *= alpha; + p->primitives.gradients.v[2][2] *= alpha; + } + + gradtrue = gradP[0] * gradP[0] + gradP[1] * gradP[1] + gradP[2] * gradP[2]; + if (gradtrue) { + gradtrue = sqrtf(gradtrue); + gradtrue *= p->primitives.limiter.maxr; + gradmax = p->primitives.limiter.P[1] - p->primitives.P; + gradmin = p->primitives.P - p->primitives.limiter.P[0]; + gradmax = fabs(gradmax); + gradmin = fabs(gradmin); + alpha = fmin(1.0f, fmin(gradmax / gradtrue, gradmin / gradtrue)); + p->primitives.gradients.P[0] *= alpha; + p->primitives.gradients.P[1] *= alpha; + p->primitives.gradients.P[2] *= alpha; + } +#endif // SLOPE_LIMITER + +#endif // SPH_GRADIENTS +} + +/** + * @brief Prepare a particle for the fluxes calculation. + * + * @param p The particle to act upon + * @param xp The extended particle data to act upon + */ +__attribute__((always_inline)) + INLINE static void hydro_prepare_fluxes(struct part* p, struct xpart* xp) { + + /* initialize variables used for timestep calculation */ + p->timestepvars.vmax = 0.0f; +} + +/** + * @brief Reset acceleration fields of a particle + * + * Resets all hydro acceleration and time derivative fields in preparation + * for the sums taking place in the variaous force tasks + * + * @param p The particle to act upon + */ +__attribute__((always_inline)) + INLINE static void hydro_reset_acceleration(struct part* p) { + + /* figure out what to put here */ +} + +/** + * @brief Finishes the fluxes calculation. + * + * Multiplies the forces and accelerationsby the appropiate constants + * + * @param p The particle to act upon + */ +__attribute__((always_inline)) + INLINE static void hydro_end_fluxes(struct part* p) { + + /* do nothing */ +} + +/** + * @brief Converts hydro quantity of a particle + * + * Requires the volume to be known + * + * @param p The particle to act upon + */ +__attribute__((always_inline)) + INLINE static void hydro_convert_quantities(struct part* p) { + + float volume; + GFLOAT m; + GFLOAT momentum[3]; +#ifndef THERMAL_ENERGY + GFLOAT momentum2; +#endif + volume = p->geometry.volume; + + /* set hydro velocities */ + p->primitives.v[0] = p->v[0]; + p->primitives.v[1] = p->v[1]; + p->primitives.v[2] = p->v[2]; + /* P actually contains internal energy at this point */ + p->primitives.P *= (const_hydro_gamma - 1.) * p->primitives.rho; + + p->conserved.mass = m = p->primitives.rho * volume; + p->conserved.momentum[0] = momentum[0] = m * p->primitives.v[0]; + p->conserved.momentum[1] = momentum[1] = m * p->primitives.v[1]; + p->conserved.momentum[2] = momentum[2] = m * p->primitives.v[2]; +#ifndef THERMAL_ENERGY + momentum2 = momentum[0] * momentum[0] + momentum[1] * momentum[1] + + momentum[2] * momentum[2]; + p->conserved.energy = + p->primitives.P / (const_hydro_gamma - 1.) * volume + 0.5 * momentum2 / m; +#else + p->conserved.energy = p->primitives.P / (const_hydro_gamma - 1.) * volume; +#endif +} + +// MATTHIEU +__attribute__((always_inline)) + INLINE static void hydro_end_density(struct part* p, float time) {} +__attribute__((always_inline)) INLINE static void hydro_prepare_force( + struct part* p, struct xpart* xp, int ti_current, double timeBase) {} +__attribute__((always_inline)) INLINE static void hydro_predict_extra( + struct part* p, struct xpart* xp, int t0, int t1, double timeBase) {} +__attribute__((always_inline)) + INLINE static void hydro_end_force(struct part* p) {} +__attribute__((always_inline)) INLINE static void hydro_kick_extra( + struct part* p, struct xpart* xp, float dt, float half_dt) {} +__attribute__((always_inline)) + INLINE static float hydro_get_internal_energy(struct part* p) { + return 0.f; +} diff --git a/src/hydro/Gizmo/hydro_debug.h b/src/hydro/Gizmo/hydro_debug.h new file mode 100644 index 0000000000000000000000000000000000000000..2cc957ed883436ce57e9d53d00a073693c9495df --- /dev/null +++ b/src/hydro/Gizmo/hydro_debug.h @@ -0,0 +1,27 @@ +/******************************************************************************* + * This file is part of SWIFT. + * Coypright (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/>. + * + ******************************************************************************/ + +__attribute__((always_inline)) + INLINE static void hydro_debug_particle(struct part* p, struct xpart* xp) { + printf( + "x=[%.16e,%.16e,%.16e], " + "v=[%.3e,%.3e,%.3e], a=[%.3e,%.3e,%.3e], volume=%.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->geometry.volume); +} diff --git a/src/hydro/Gizmo/hydro_iact.h b/src/hydro/Gizmo/hydro_iact.h new file mode 100644 index 0000000000000000000000000000000000000000..4fe875d3d07315051ef8b3051665a9ea0ef261b8 --- /dev/null +++ b/src/hydro/Gizmo/hydro_iact.h @@ -0,0 +1,1035 @@ +/******************************************************************************* + * 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/>. + * + ******************************************************************************/ + +#include "riemann.h" + +#define USE_GRADIENTS +#define PER_FACE_LIMITER +/* #define PRINT_ID 0 */ + +/* this corresponds to task_subtype_hydro_loop1 */ +__attribute__((always_inline)) INLINE static void runner_iact_hydro_loop1( + float r2, float *dx, float hi, float hj, struct part *pi, struct part *pj) { + + float r = sqrtf(r2); + float xi, xj; + float h_inv; + float wi, wj, wi_dx, wj_dx; + int k, l; + + /* Compute density of pi. */ + h_inv = 1.0 / hi; + xi = r * h_inv; + kernel_deval(xi, &wi, &wi_dx); + + pi->density.wcount += wi; + pi->density.wcount_dh -= xi * wi_dx; + + /* these are eqns. (1) and (2) in the summary */ + pi->geometry.volume += wi; + for (k = 0; k < 3; k++) + for (l = 0; l < 3; l++) pi->geometry.matrix_E[k][l] += dx[k] * dx[l] * wi; + +#ifdef SPH_GRADIENTS + /* very basic gradient estimate */ + pi->primitives.gradients.rho[0] -= + wi_dx * dx[0] * (pi->primitives.rho - pj->primitives.rho) / r; + pi->primitives.gradients.rho[1] -= + wi_dx * dx[1] * (pi->primitives.rho - pj->primitives.rho) / r; + pi->primitives.gradients.rho[2] -= + wi_dx * dx[2] * (pi->primitives.rho - pj->primitives.rho) / r; + + pi->primitives.gradients.v[0][0] -= + wi_dx * dx[0] * (pi->primitives.v[0] - pj->primitives.v[0]) / r; + pi->primitives.gradients.v[0][1] -= + wi_dx * dx[1] * (pi->primitives.v[0] - pj->primitives.v[0]) / r; + pi->primitives.gradients.v[0][2] -= + wi_dx * dx[2] * (pi->primitives.v[0] - pj->primitives.v[0]) / r; + + pi->primitives.gradients.v[1][0] -= + wi_dx * dx[0] * (pi->primitives.v[1] - pj->primitives.v[1]) / r; + pi->primitives.gradients.v[1][1] -= + wi_dx * dx[1] * (pi->primitives.v[1] - pj->primitives.v[1]) / r; + pi->primitives.gradients.v[1][2] -= + wi_dx * dx[2] * (pi->primitives.v[1] - pj->primitives.v[1]) / r; + + pi->primitives.gradients.v[2][0] -= + wi_dx * dx[0] * (pi->primitives.v[2] - pj->primitives.v[2]) / r; + pi->primitives.gradients.v[2][1] -= + wi_dx * dx[1] * (pi->primitives.v[2] - pj->primitives.v[2]) / r; + pi->primitives.gradients.v[2][2] -= + wi_dx * dx[2] * (pi->primitives.v[2] - pj->primitives.v[2]) / r; + + pi->primitives.gradients.P[0] -= + wi_dx * dx[0] * (pi->primitives.P - pj->primitives.P) / r; + pi->primitives.gradients.P[1] -= + wi_dx * dx[1] * (pi->primitives.P - pj->primitives.P) / r; + pi->primitives.gradients.P[2] -= + wi_dx * dx[2] * (pi->primitives.P - pj->primitives.P) / r; + + /* basic slope limiter: collect the maximal and the minimal value for the + * primitive variables among the ngbs */ + pi->primitives.limiter.rho[0] = + fmin(pj->primitives.rho, pi->primitives.limiter.rho[0]); + pi->primitives.limiter.rho[1] = + fmax(pj->primitives.rho, pi->primitives.limiter.rho[1]); + + pi->primitives.limiter.v[0][0] = + fmin(pj->primitives.v[0], pi->primitives.limiter.v[0][0]); + pi->primitives.limiter.v[0][1] = + fmax(pj->primitives.v[0], pi->primitives.limiter.v[0][1]); + pi->primitives.limiter.v[1][0] = + fmin(pj->primitives.v[1], pi->primitives.limiter.v[1][0]); + pi->primitives.limiter.v[1][1] = + fmax(pj->primitives.v[1], pi->primitives.limiter.v[1][1]); + pi->primitives.limiter.v[2][0] = + fmin(pj->primitives.v[2], pi->primitives.limiter.v[2][0]); + pi->primitives.limiter.v[2][1] = + fmax(pj->primitives.v[2], pi->primitives.limiter.v[2][1]); + + pi->primitives.limiter.P[0] = + fmin(pj->primitives.P, pi->primitives.limiter.P[0]); + pi->primitives.limiter.P[1] = + fmax(pj->primitives.P, pi->primitives.limiter.P[1]); + + pi->primitives.limiter.maxr = fmax(r, pi->primitives.limiter.maxr); +#endif + + /* Compute density of pj. */ + h_inv = 1.0 / hj; + xj = r * h_inv; + kernel_deval(xj, &wj, &wj_dx); + + pj->density.wcount += wj; + pj->density.wcount_dh -= xj * wj_dx; + + /* these are eqns. (1) and (2) in the summary */ + pj->geometry.volume += wj; + for (k = 0; k < 3; k++) + for (l = 0; l < 3; l++) pj->geometry.matrix_E[k][l] += dx[k] * dx[l] * wj; + +#ifdef SPH_GRADIENTS + /* very basic gradient estimate */ + /* 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; + pj->primitives.gradients.rho[1] -= + wj_dx * dx[1] * (pi->primitives.rho - pj->primitives.rho) / r; + pj->primitives.gradients.rho[2] -= + wj_dx * dx[2] * (pi->primitives.rho - pj->primitives.rho) / r; + + pj->primitives.gradients.v[0][0] -= + wj_dx * dx[0] * (pi->primitives.v[0] - pj->primitives.v[0]) / r; + pj->primitives.gradients.v[0][1] -= + wj_dx * dx[1] * (pi->primitives.v[0] - pj->primitives.v[0]) / r; + pj->primitives.gradients.v[0][2] -= + wj_dx * dx[2] * (pi->primitives.v[0] - pj->primitives.v[0]) / r; + + pj->primitives.gradients.v[1][0] -= + wj_dx * dx[0] * (pi->primitives.v[1] - pj->primitives.v[1]) / r; + pj->primitives.gradients.v[1][1] -= + wj_dx * dx[1] * (pi->primitives.v[1] - pj->primitives.v[1]) / r; + pj->primitives.gradients.v[1][2] -= + wj_dx * dx[2] * (pi->primitives.v[1] - pj->primitives.v[1]) / r; + + pj->primitives.gradients.v[2][0] -= + wj_dx * dx[0] * (pi->primitives.v[2] - pj->primitives.v[2]) / r; + pj->primitives.gradients.v[2][1] -= + wj_dx * dx[1] * (pi->primitives.v[2] - pj->primitives.v[2]) / r; + pj->primitives.gradients.v[2][2] -= + wj_dx * dx[2] * (pi->primitives.v[2] - pj->primitives.v[2]) / r; + + pj->primitives.gradients.P[0] -= + wj_dx * dx[0] * (pi->primitives.P - pj->primitives.P) / r; + pj->primitives.gradients.P[1] -= + wj_dx * dx[1] * (pi->primitives.P - pj->primitives.P) / r; + pj->primitives.gradients.P[2] -= + wj_dx * dx[2] * (pi->primitives.P - pj->primitives.P) / r; + + /* basic slope limiter: collect the maximal and the minimal value for the + * primitive variables among the ngbs */ + pj->primitives.limiter.rho[0] = + fmin(pi->primitives.rho, pj->primitives.limiter.rho[0]); + pj->primitives.limiter.rho[1] = + fmax(pi->primitives.rho, pj->primitives.limiter.rho[1]); + + pj->primitives.limiter.v[0][0] = + fmin(pi->primitives.v[0], pj->primitives.limiter.v[0][0]); + pj->primitives.limiter.v[0][1] = + fmax(pi->primitives.v[0], pj->primitives.limiter.v[0][1]); + pj->primitives.limiter.v[1][0] = + fmin(pi->primitives.v[1], pj->primitives.limiter.v[1][0]); + pj->primitives.limiter.v[1][1] = + fmax(pi->primitives.v[1], pj->primitives.limiter.v[1][1]); + pj->primitives.limiter.v[2][0] = + fmin(pi->primitives.v[2], pj->primitives.limiter.v[2][0]); + pj->primitives.limiter.v[2][1] = + fmax(pi->primitives.v[2], pj->primitives.limiter.v[2][1]); + + pj->primitives.limiter.P[0] = + fmin(pi->primitives.P, pj->primitives.limiter.P[0]); + pj->primitives.limiter.P[1] = + fmax(pi->primitives.P, pj->primitives.limiter.P[1]); + + pj->primitives.limiter.maxr = fmax(r, pj->primitives.limiter.maxr); +#endif +} + +/* this corresponds to task_subtype_hydro_loop1 */ +__attribute__((always_inline)) + INLINE static void runner_iact_nonsym_hydro_loop1(float r2, float *dx, + float hi, float hj, + struct part *pi, + struct part *pj) { + + float r; + float xi; + float h_inv; + float wi, wi_dx; + int k, l; + + /* Get r and r inverse. */ + r = sqrtf(r2); + + h_inv = 1.0 / hi; + xi = r * h_inv; + kernel_deval(xi, &wi, &wi_dx); + + pi->density.wcount += wi; + pi->density.wcount_dh -= xi * wi_dx; + + /* these are eqns. (1) and (2) in the summary */ + pi->geometry.volume += wi; + for (k = 0; k < 3; k++) + for (l = 0; l < 3; l++) pi->geometry.matrix_E[k][l] += dx[k] * dx[l] * wi; + +#ifdef SPH_GRADIENTS + /* very basic gradient estimate */ + pi->primitives.gradients.rho[0] -= + wi_dx * dx[0] * (pi->primitives.rho - pj->primitives.rho) / r; + pi->primitives.gradients.rho[1] -= + wi_dx * dx[1] * (pi->primitives.rho - pj->primitives.rho) / r; + pi->primitives.gradients.rho[2] -= + wi_dx * dx[2] * (pi->primitives.rho - pj->primitives.rho) / r; + + pi->primitives.gradients.v[0][0] -= + wi_dx * dx[0] * (pi->primitives.v[0] - pj->primitives.v[0]) / r; + pi->primitives.gradients.v[0][1] -= + wi_dx * dx[1] * (pi->primitives.v[0] - pj->primitives.v[0]) / r; + pi->primitives.gradients.v[0][2] -= + wi_dx * dx[2] * (pi->primitives.v[0] - pj->primitives.v[0]) / r; + + pi->primitives.gradients.v[1][0] -= + wi_dx * dx[0] * (pi->primitives.v[1] - pj->primitives.v[1]) / r; + pi->primitives.gradients.v[1][1] -= + wi_dx * dx[1] * (pi->primitives.v[1] - pj->primitives.v[1]) / r; + pi->primitives.gradients.v[1][2] -= + wi_dx * dx[2] * (pi->primitives.v[1] - pj->primitives.v[1]) / r; + + pi->primitives.gradients.v[2][0] -= + wi_dx * dx[0] * (pi->primitives.v[2] - pj->primitives.v[2]) / r; + pi->primitives.gradients.v[2][1] -= + wi_dx * dx[1] * (pi->primitives.v[2] - pj->primitives.v[2]) / r; + pi->primitives.gradients.v[2][2] -= + wi_dx * dx[2] * (pi->primitives.v[2] - pj->primitives.v[2]) / r; + + pi->primitives.gradients.P[0] -= + wi_dx * dx[0] * (pi->primitives.P - pj->primitives.P) / r; + pi->primitives.gradients.P[1] -= + wi_dx * dx[1] * (pi->primitives.P - pj->primitives.P) / r; + pi->primitives.gradients.P[2] -= + wi_dx * dx[2] * (pi->primitives.P - pj->primitives.P) / r; + + /* slope limiter */ + pi->primitives.limiter.rho[0] = + fmin(pj->primitives.rho, pi->primitives.limiter.rho[0]); + pi->primitives.limiter.rho[1] = + fmax(pj->primitives.rho, pi->primitives.limiter.rho[1]); + + pi->primitives.limiter.v[0][0] = + fmin(pj->primitives.v[0], pi->primitives.limiter.v[0][0]); + pi->primitives.limiter.v[0][1] = + fmax(pj->primitives.v[0], pi->primitives.limiter.v[0][1]); + pi->primitives.limiter.v[1][0] = + fmin(pj->primitives.v[1], pi->primitives.limiter.v[1][0]); + pi->primitives.limiter.v[1][1] = + fmax(pj->primitives.v[1], pi->primitives.limiter.v[1][1]); + pi->primitives.limiter.v[2][0] = + fmin(pj->primitives.v[2], pi->primitives.limiter.v[2][0]); + pi->primitives.limiter.v[2][1] = + fmax(pj->primitives.v[2], pi->primitives.limiter.v[2][1]); + + pi->primitives.limiter.P[0] = + fmin(pj->primitives.P, pi->primitives.limiter.P[0]); + pi->primitives.limiter.P[1] = + fmax(pj->primitives.P, pi->primitives.limiter.P[1]); + + pi->primitives.limiter.maxr = fmax(r, pi->primitives.limiter.maxr); +#endif +} + +__attribute__((always_inline)) INLINE static void runner_iact_hydro_loop2( + float r2, float *dx, float hi, float hj, struct part *pi, struct part *pj) { + +#ifndef SPH_GRADIENTS + + float r = sqrtf(r2); + float xi, xj; + float hi_inv, hj_inv; + float wi, wj, wi_dx, wj_dx; + int k, l; + float Bi[3][3]; + float Bj[3][3]; + GFLOAT Wi[5], Wj[5]; + + /* Initialize local variables */ + for (k = 0; k < 3; k++) { + for (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. */ + hi_inv = 1.0 / hi; + xi = r * hi_inv; + kernel_deval(xi, &wi, &wi_dx); + + /* 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]); + + /* basic slope limiter: collect the maximal and the minimal value for the + * primitive variables among the ngbs */ + pi->primitives.limiter.rho[0] = + fmin(pj->primitives.rho, pi->primitives.limiter.rho[0]); + pi->primitives.limiter.rho[1] = + fmax(pj->primitives.rho, pi->primitives.limiter.rho[1]); + + pi->primitives.limiter.v[0][0] = + fmin(pj->primitives.v[0], pi->primitives.limiter.v[0][0]); + pi->primitives.limiter.v[0][1] = + fmax(pj->primitives.v[0], pi->primitives.limiter.v[0][1]); + pi->primitives.limiter.v[1][0] = + fmin(pj->primitives.v[1], pi->primitives.limiter.v[1][0]); + pi->primitives.limiter.v[1][1] = + fmax(pj->primitives.v[1], pi->primitives.limiter.v[1][1]); + pi->primitives.limiter.v[2][0] = + fmin(pj->primitives.v[2], pi->primitives.limiter.v[2][0]); + pi->primitives.limiter.v[2][1] = + fmax(pj->primitives.v[2], pi->primitives.limiter.v[2][1]); + + pi->primitives.limiter.P[0] = + fmin(pj->primitives.P, pi->primitives.limiter.P[0]); + pi->primitives.limiter.P[1] = + fmax(pj->primitives.P, pi->primitives.limiter.P[1]); + + pi->primitives.limiter.maxr = fmax(r, pi->primitives.limiter.maxr); + + /* Compute kernel of pj. */ + hj_inv = 1.0 / hj; + xj = r * hj_inv; + kernel_deval(xj, &wj, &wj_dx); + + /* 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]); + + /* basic slope limiter: collect the maximal and the minimal value for the + * primitive variables among the ngbs */ + pj->primitives.limiter.rho[0] = + fmin(pi->primitives.rho, pj->primitives.limiter.rho[0]); + pj->primitives.limiter.rho[1] = + fmax(pi->primitives.rho, pj->primitives.limiter.rho[1]); + + pj->primitives.limiter.v[0][0] = + fmin(pi->primitives.v[0], pj->primitives.limiter.v[0][0]); + pj->primitives.limiter.v[0][1] = + fmax(pi->primitives.v[0], pj->primitives.limiter.v[0][1]); + pj->primitives.limiter.v[1][0] = + fmin(pi->primitives.v[1], pj->primitives.limiter.v[1][0]); + pj->primitives.limiter.v[1][1] = + fmax(pi->primitives.v[1], pj->primitives.limiter.v[1][1]); + pj->primitives.limiter.v[2][0] = + fmin(pi->primitives.v[2], pj->primitives.limiter.v[2][0]); + pj->primitives.limiter.v[2][1] = + fmax(pi->primitives.v[2], pj->primitives.limiter.v[2][1]); + + pj->primitives.limiter.P[0] = + fmin(pi->primitives.P, pj->primitives.limiter.P[0]); + pj->primitives.limiter.P[1] = + fmax(pi->primitives.P, pj->primitives.limiter.P[1]); + + pj->primitives.limiter.maxr = fmax(r, pj->primitives.limiter.maxr); + +#endif +} + +__attribute__((always_inline)) + INLINE static void runner_iact_nonsym_hydro_loop2(float r2, float *dx, + float hi, float hj, + struct part *pi, + struct part *pj) { + +#ifndef SPH_GRADIENTS + + float r = sqrtf(r2); + float xi; + float hi_inv; + float wi, wi_dx; + int k, l; + float Bi[3][3]; + GFLOAT Wi[5], Wj[5]; + + /* Initialize local variables */ + for (k = 0; k < 3; k++) { + for (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. */ + hi_inv = 1.0 / hi; + xi = r * hi_inv; + kernel_deval(xi, &wi, &wi_dx); + + /* 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]); + + /* slope limiter */ + pi->primitives.limiter.rho[0] = + fmin(pj->primitives.rho, pi->primitives.limiter.rho[0]); + pi->primitives.limiter.rho[1] = + fmax(pj->primitives.rho, pi->primitives.limiter.rho[1]); + + pi->primitives.limiter.v[0][0] = + fmin(pj->primitives.v[0], pi->primitives.limiter.v[0][0]); + pi->primitives.limiter.v[0][1] = + fmax(pj->primitives.v[0], pi->primitives.limiter.v[0][1]); + pi->primitives.limiter.v[1][0] = + fmin(pj->primitives.v[1], pi->primitives.limiter.v[1][0]); + pi->primitives.limiter.v[1][1] = + fmax(pj->primitives.v[1], pi->primitives.limiter.v[1][1]); + pi->primitives.limiter.v[2][0] = + fmin(pj->primitives.v[2], pi->primitives.limiter.v[2][0]); + pi->primitives.limiter.v[2][1] = + fmax(pj->primitives.v[2], pi->primitives.limiter.v[2][1]); + + pi->primitives.limiter.P[0] = + fmin(pj->primitives.P, pi->primitives.limiter.P[0]); + pi->primitives.limiter.P[1] = + fmax(pj->primitives.P, pi->primitives.limiter.P[1]); + + pi->primitives.limiter.maxr = fmax(r, pi->primitives.limiter.maxr); + +#endif +} + +__attribute__((always_inline)) INLINE static void runner_iact_fluxes_common( + float r2, float *dx, float hi, float hj, struct part *pi, struct part *pj, + int mode) { + + float r = sqrtf(r2); + float xi, xj; + float hi_inv, hi_inv2; + float hj_inv, hj_inv2; + float wi, wj, wi_dx, wj_dx; + int k, l; + float A[3]; + float Anorm; + float Bi[3][3]; + float Bj[3][3]; + float Vi, Vj; + float xij_i[3], xfac, xijdotdx; + float vmax, dvdotdx; + float vi[3], vj[3], vij[3]; + GFLOAT Wi[5], Wj[5]; //, Whalf[5]; +#ifdef USE_GRADIENTS + GFLOAT dWi[5], dWj[5]; + float xij_j[3]; +#endif + // GFLOAT rhoe; + // GFLOAT flux[5][3]; + float dti, dtj, mindt; + float n_unit[3]; + + /* Initialize local variables */ + for (k = 0; k < 3; k++) { + for (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]; + } + Vi = pi->geometry.volume; + Vj = pj->geometry.volume; + 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; + dti = pi->ti_end - pi->ti_begin; // MATTHIEU + dtj = pj->ti_end - pj->ti_begin; + + // if(dti > 1.e-7 || dtj > 1.e-7){ + // message("Timestep too large: %g %g!", dti, dtj); + // } + + /* calculate the maximal signal velocity */ + vmax = sqrtf(const_hydro_gamma * Wi[4] / Wi[0]) + + sqrtf(const_hydro_gamma * Wj[4] / Wj[0]); + dvdotdx = (Wi[1] - Wj[1]) * dx[0] + (Wi[2] - Wj[2]) * dx[1] + + (Wi[3] - Wj[3]) * dx[2]; + if (dvdotdx > 0.) { + vmax -= dvdotdx / r; + } + pi->timestepvars.vmax = fmaxf(pi->timestepvars.vmax, vmax); + if (mode == 1) { + pj->timestepvars.vmax = fmaxf(pj->timestepvars.vmax, vmax); + } + + /* The flux will be exchanged using the smallest time step of the two + * particles */ + mindt = fminf(dti, dtj); + + /* Compute kernel of pi. */ + hi_inv = 1.0 / hi; + hi_inv2 = hi_inv * hi_inv; + xi = r * hi_inv; + kernel_deval(xi, &wi, &wi_dx); + + /* Compute kernel of pj. */ + hj_inv = 1.0 / hj; + hj_inv2 = hj_inv * hj_inv; + xj = r * hj_inv; + kernel_deval(xj, &wj, &wj_dx); + + /* Compute area */ + /* eqn. (7) */ + Anorm = 0.0f; + for (k = 0; k < 3; k++) { + /* we add a minus sign since dx is pi->x - pj->x */ + A[k] = -Vi * (Bi[k][0] * dx[0] + Bi[k][1] * dx[1] + Bi[k][2] * dx[2]) * wi * + hi_inv * hi_inv2 - + Vj * (Bj[k][0] * dx[0] + Bj[k][1] * dx[1] + Bj[k][2] * dx[2]) * wj * + hj_inv * hj_inv2; + Anorm += A[k] * A[k]; + } + + if (!Anorm) { + /* if the interface has no area, nothing happens and we return */ + /* continuing results in dividing by zero and NaN's... */ + return; + } + + /* compute the normal vector of the interface */ + Anorm = sqrtf(Anorm); + for (k = 0; k < 3; k++) n_unit[k] = A[k] / Anorm; + +#ifdef PRINT_ID + if (pi->id == PRINT_ID || pj->id == PRINT_ID) { + printf("pi: %g %g %g\npj: %g %g %g\nA = %g %g %g\n", pi->x[0], pi->x[1], + pi->x[2], pj->x[0], pj->x[1], pj->x[2], A[0], A[1], A[2]); + } +#endif + + /* Compute interface position (relative to pi, since we don't need the actual + * position) */ + /* eqn. (8) */ + xfac = hi / (hi + hj); + for (k = 0; k < 3; k++) xij_i[k] = -xfac * dx[k]; + + /* Compute interface velocity */ + /* eqn. (9) */ + xijdotdx = xij_i[0] * dx[0] + xij_i[1] * dx[1] + xij_i[2] * dx[2]; + for (k = 0; k < 3; k++) vij[k] = vi[k] + (vi[k] - vj[k]) * xijdotdx / r2; + + /* complete calculation of position of interface */ + /* NOTE: dx is not necessarily just pi->x - pj->x but can also contain + correction terms for periodicity. If we do the interpolation, + we have to use xij w.r.t. the actual particle. + => we need a separate xij for pi and pj... */ + /* tldr: we do not need the code below, but we do need the same code as above + but then + with i and j swapped */ + // for ( k = 0 ; k < 3 ; k++ ) + // xij[k] += pi->x[k]; + + /* 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]; + +#ifdef USE_GRADIENTS + /* perform gradient reconstruction in space and time */ + /* space */ + /* Compute interface position (relative to pj, since we don't need the actual + * position) */ + /* eqn. (8) */ + xfac = hj / (hi + hj); + for (k = 0; k < 3; k++) xij_j[k] = xfac * dx[k]; + + 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]; + + 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]; + +#ifdef PER_FACE_LIMITER + + float xij_i_norm; + GFLOAT phi_i, phi_j; + GFLOAT delta1, delta2; + GFLOAT phiminus, phiplus; + GFLOAT phimin, phimax; + GFLOAT phibar; + /* free parameters, values from Hopkins */ + GFLOAT psi1 = 0.5, psi2 = 0.25; + GFLOAT phi_mid0, phi_mid; + + for (k = 0; k < 10; k++) { + if (k < 5) { + phi_i = Wi[k]; + phi_j = Wj[k]; + phi_mid0 = Wi[k] + dWi[k]; + xij_i_norm = sqrtf(xij_i[0] * xij_i[0] + xij_i[1] * xij_i[1] + + xij_i[2] * xij_i[2]); + } else { + phi_i = Wj[k - 5]; + phi_j = Wi[k - 5]; + phi_mid0 = Wj[k - 5] + dWj[k - 5]; + xij_i_norm = sqrtf(xij_j[0] * xij_j[0] + xij_j[1] * xij_j[1] + + xij_j[2] * xij_j[2]); + } + + delta1 = psi1 * fabs(phi_i - phi_j); + delta2 = psi2 * fabs(phi_i - phi_j); + + phimin = fmin(phi_i, phi_j); + phimax = fmax(phi_i, phi_j); + + phibar = phi_i + xij_i_norm / r * (phi_j - phi_i); + + /* if sign(phimax+delta1) == sign(phimax) */ + if ((phimax + delta1) * phimax > 0.0f) { + phiplus = phimax + delta1; + } else { + phiplus = phimax / (1.0f + delta1 / fabs(phimax)); + } + + /* if sign(phimin-delta1) == sign(phimin) */ + if ((phimin - delta1) * phimin > 0.0f) { + phiminus = phimin - delta1; + } else { + phiminus = phimin / (1.0f + delta1 / fabs(phimin)); + } + + if (phi_i == phi_j) { + phi_mid = phi_i; + } else { + if (phi_i < phi_j) { + phi_mid = fmax(phiminus, fmin(phibar + delta2, phi_mid0)); + } else { + phi_mid = fmin(phiplus, fmax(phibar - delta2, phi_mid0)); + } + } + + if (k < 5) { + dWi[k] = phi_mid - phi_i; + } else { + dWj[k - 5] = phi_mid - phi_i; + } + } + +#endif + + // printf("dWL: %g %g %g %g %g\n", dWi[0], dWi[1], dWi[2], dWi[3], dWi[4]); + // printf("dWR: %g %g %g %g %g\n", dWj[0], dWj[1], dWj[2], dWj[3], dWj[4]); + + /* time */ + dWi[0] -= 0.5 * mindt * (Wi[1] * pi->primitives.gradients.rho[0] + + Wi[2] * pi->primitives.gradients.rho[1] + + Wi[3] * pi->primitives.gradients.rho[2] + + Wi[0] * (pi->primitives.gradients.v[0][0] + + pi->primitives.gradients.v[1][1] + + pi->primitives.gradients.v[2][2])); + dWi[1] -= 0.5 * mindt * (Wi[1] * pi->primitives.gradients.v[0][0] + + Wi[2] * pi->primitives.gradients.v[0][1] + + Wi[3] * pi->primitives.gradients.v[0][2] + + pi->primitives.gradients.P[0] / Wi[0]); + dWi[2] -= 0.5 * mindt * (Wi[1] * pi->primitives.gradients.v[1][0] + + Wi[2] * pi->primitives.gradients.v[1][1] + + Wi[3] * pi->primitives.gradients.v[1][2] + + pi->primitives.gradients.P[1] / Wi[0]); + dWi[3] -= 0.5 * mindt * (Wi[1] * pi->primitives.gradients.v[2][0] + + Wi[2] * pi->primitives.gradients.v[2][1] + + Wi[3] * pi->primitives.gradients.v[2][2] + + pi->primitives.gradients.P[2] / Wi[0]); + dWi[4] -= 0.5 * mindt * + (Wi[1] * pi->primitives.gradients.P[0] + + Wi[2] * pi->primitives.gradients.P[1] + + Wi[3] * pi->primitives.gradients.P[2] + + const_hydro_gamma * Wi[4] * (pi->primitives.gradients.v[0][0] + + pi->primitives.gradients.v[1][1] + + pi->primitives.gradients.v[2][2])); + + dWj[0] -= 0.5 * mindt * (Wj[1] * pj->primitives.gradients.rho[0] + + Wj[2] * pj->primitives.gradients.rho[1] + + Wj[3] * pj->primitives.gradients.rho[2] + + Wj[0] * (pj->primitives.gradients.v[0][0] + + pj->primitives.gradients.v[1][1] + + pj->primitives.gradients.v[2][2])); + dWj[1] -= 0.5 * mindt * (Wj[1] * pj->primitives.gradients.v[0][0] + + Wj[2] * pj->primitives.gradients.v[0][1] + + Wj[3] * pj->primitives.gradients.v[0][2] + + pj->primitives.gradients.P[0] / Wj[0]); + dWj[2] -= 0.5 * mindt * (Wj[1] * pj->primitives.gradients.v[1][0] + + Wj[2] * pj->primitives.gradients.v[1][1] + + Wj[3] * pj->primitives.gradients.v[1][2] + + pj->primitives.gradients.P[1] / Wj[0]); + dWj[3] -= 0.5 * mindt * (Wj[1] * pj->primitives.gradients.v[2][0] + + Wj[2] * pj->primitives.gradients.v[2][1] + + Wj[3] * pj->primitives.gradients.v[2][2] + + pj->primitives.gradients.P[2] / Wj[0]); + dWj[4] -= 0.5 * mindt * + (Wj[1] * pj->primitives.gradients.P[0] + + Wj[2] * pj->primitives.gradients.P[1] + + Wj[3] * pj->primitives.gradients.P[2] + + const_hydro_gamma * Wj[4] * (pj->primitives.gradients.v[0][0] + + pj->primitives.gradients.v[1][1] + + pj->primitives.gradients.v[2][2])); + + // printf("WL: %g %g %g %g %g\n", Wi[0], Wi[1], Wi[2], Wi[3], Wi[4]); + // printf("WR: %g %g %g %g %g\n", Wj[0], Wj[1], Wj[2], Wj[3], Wj[4]); + + // printf("dWL: %g %g %g %g %g\n", dWi[0], dWi[1], dWi[2], dWi[3], dWi[4]); + // printf("dWR: %g %g %g %g %g\n", dWj[0], dWj[1], dWj[2], dWj[3], dWj[4]); + + 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]; +#endif + + /* apply slope limiter interface by interface */ + /* ... to be done ... */ + + /* we don't need to rotate, we can use the unit vector in the Riemann problem + * itself (see GIZMO) */ + + if (Wi[0] < 0.0f || Wj[0] < 0.0f || Wi[4] < 0.0f || Wj[4] < 0.0f) { + printf("mindt: %g\n", mindt); + printf("WL: %g %g %g %g %g\n", pi->primitives.rho, pi->primitives.v[0], + pi->primitives.v[1], pi->primitives.v[2], pi->primitives.P); + printf("dWL: %g %g %g %g %g\n", dWi[0], dWi[1], dWi[2], dWi[3], dWi[4]); + printf("gradWL[0]: %g %g %g\n", pi->primitives.gradients.rho[0], + pi->primitives.gradients.rho[1], pi->primitives.gradients.rho[2]); + printf("gradWL[1]: %g %g %g\n", pi->primitives.gradients.v[0][0], + pi->primitives.gradients.v[0][1], pi->primitives.gradients.v[0][2]); + printf("gradWL[2]: %g %g %g\n", pi->primitives.gradients.v[1][0], + pi->primitives.gradients.v[1][1], pi->primitives.gradients.v[1][2]); + printf("gradWL[3]: %g %g %g\n", pi->primitives.gradients.v[2][0], + pi->primitives.gradients.v[2][1], pi->primitives.gradients.v[2][2]); + printf("gradWL[4]: %g %g %g\n", pi->primitives.gradients.P[0], + pi->primitives.gradients.P[1], pi->primitives.gradients.P[2]); + printf("WL': %g %g %g %g %g\n", Wi[0], Wi[1], Wi[2], Wi[3], Wi[4]); + printf("WR: %g %g %g %g %g\n", pj->primitives.rho, pj->primitives.v[0], + pj->primitives.v[1], pj->primitives.v[2], pj->primitives.P); + printf("dWR: %g %g %g %g %g\n", dWj[0], dWj[1], dWj[2], dWj[3], dWj[4]); + printf("gradWR[0]: %g %g %g\n", pj->primitives.gradients.rho[0], + pj->primitives.gradients.rho[1], pj->primitives.gradients.rho[2]); + printf("gradWR[1]: %g %g %g\n", pj->primitives.gradients.v[0][0], + pj->primitives.gradients.v[0][1], pj->primitives.gradients.v[0][2]); + printf("gradWR[2]: %g %g %g\n", pj->primitives.gradients.v[1][0], + pj->primitives.gradients.v[1][1], pj->primitives.gradients.v[1][2]); + printf("gradWR[3]: %g %g %g\n", pj->primitives.gradients.v[2][0], + pj->primitives.gradients.v[2][1], pj->primitives.gradients.v[2][2]); + printf("gradWR[4]: %g %g %g\n", pj->primitives.gradients.P[0], + pj->primitives.gradients.P[1], pj->primitives.gradients.P[2]); + printf("WR': %g %g %g %g %g\n", Wj[0], Wj[1], Wj[2], Wj[3], Wj[4]); + error("Negative density or pressure!\n"); + } + + GFLOAT totflux[5]; + riemann_solve_for_flux(Wi, Wj, n_unit, vij, totflux); + + /* Update conserved variables */ + /* eqn. (16) */ + pi->conserved.mass -= mindt * Anorm * totflux[0]; + pi->conserved.momentum[0] -= mindt * Anorm * totflux[1]; + pi->conserved.momentum[1] -= mindt * Anorm * totflux[2]; + pi->conserved.momentum[2] -= mindt * Anorm * totflux[3]; + pi->conserved.energy -= mindt * Anorm * totflux[4]; + +#ifdef THERMAL_ENERGY + float ekin = 0.5 * (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.energy += mindt * Anorm * totflux[1] * pi->primitives.v[0]; + pi->conserved.energy += mindt * Anorm * totflux[2] * pi->primitives.v[1]; + pi->conserved.energy += mindt * Anorm * totflux[3] * pi->primitives.v[2]; + pi->conserved.energy -= mindt * Anorm * totflux[0] * ekin; +#endif + + /* the non symmetric version is never called when using mindt, whether this + * piece of code + * should always be executed or only in the symmetric case is currently + * unclear */ + if (mode == 1) { + pj->conserved.mass += mindt * Anorm * totflux[0]; + pj->conserved.momentum[0] += mindt * Anorm * totflux[1]; + pj->conserved.momentum[1] += mindt * Anorm * totflux[2]; + pj->conserved.momentum[2] += mindt * Anorm * totflux[3]; + pj->conserved.energy += mindt * Anorm * totflux[4]; + +#ifdef THERMAL_ENERGY + ekin = 0.5 * (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.energy -= mindt * Anorm * totflux[1] * pj->primitives.v[0]; + pj->conserved.energy -= mindt * Anorm * totflux[2] * pj->primitives.v[1]; + pj->conserved.energy -= mindt * Anorm * totflux[3] * pj->primitives.v[2]; + pj->conserved.energy += mindt * Anorm * totflux[0] * ekin; +#endif + } +} + +/* this corresponds to task_subtype_fluxes */ +__attribute__((always_inline)) INLINE static void runner_iact_hydro_loop3( + float r2, float *dx, float hi, float hj, struct part *pi, struct part *pj) { + + runner_iact_fluxes_common(r2, dx, hi, hj, pi, pj, 1); +} + +/* this corresponds to task_subtype_fluxes */ +__attribute__((always_inline)) + INLINE static void runner_iact_nonsym_hydro_loop3(float r2, float *dx, + float hi, float hj, + struct part *pi, + struct part *pj) { + + runner_iact_fluxes_common(r2, dx, hi, hj, pi, pj, 0); +} diff --git a/src/hydro/Gizmo/hydro_io.h b/src/hydro/Gizmo/hydro_io.h new file mode 100644 index 0000000000000000000000000000000000000000..3c51653d994bd9f01864bcc24c6886eba25d1d05 --- /dev/null +++ b/src/hydro/Gizmo/hydro_io.h @@ -0,0 +1,120 @@ +/******************************************************************************* + * This file is part of SWIFT. + * Coypright (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/>. + * + ******************************************************************************/ + +/** + * @brief Reads the different particles to the HDF5 file + * + * @param h_grp The HDF5 group in which to read the arrays. + * @param N The number of particles on that MPI rank. + * @param N_total The total number of particles (only used in MPI mode) + * @param offset The offset of the particles for this MPI rank (only used in MPI + *mode) + * @param parts The particle array + * + */ +__attribute__((always_inline)) INLINE static void hydro_read_particles( + hid_t h_grp, int N, long long N_total, long long offset, + struct part* parts) { + + /* Read arrays */ + readArray(h_grp, "Coordinates", DOUBLE, N, 3, parts, N_total, offset, x, + COMPULSORY); + readArray(h_grp, "Velocities", FLOAT, N, 3, parts, N_total, offset, v, + COMPULSORY); + readArray(h_grp, "Masses", FLOAT, N, 1, parts, N_total, offset, + conserved.mass, COMPULSORY); + readArray(h_grp, "SmoothingLength", FLOAT, N, 1, parts, N_total, offset, h, + COMPULSORY); + readArray(h_grp, "InternalEnergy", FLOAT, N, 1, parts, N_total, offset, + primitives.P, COMPULSORY); + readArray(h_grp, "ParticleIDs", ULONGLONG, N, 1, parts, N_total, offset, id, + COMPULSORY); + readArray(h_grp, "Acceleration", FLOAT, N, 3, parts, N_total, offset, a_hydro, + OPTIONAL); + readArray(h_grp, "Density", FLOAT, N, 1, parts, N_total, offset, + primitives.rho, OPTIONAL); +} + +/** + * @brief Writes the different particles to the HDF5 file + * + * @param h_grp The HDF5 group in which to write the arrays. + * @param fileName The name of the file (unsued in MPI mode). + * @param xmfFile The XMF file to write to (unused in MPI mode). + * @param N The number of particles on that MPI rank. + * @param N_total The total number of particles (only used in MPI mode) + * @param mpi_rank The MPI rank of this node (only used in MPI mode) + * @param offset The offset of the particles for this MPI rank (only used in MPI + *mode) + * @param parts The particle array + * @param us The unit system to use + * + */ +__attribute__((always_inline)) INLINE static void hydro_write_particles( + hid_t h_grp, char* fileName, FILE* xmfFile, int N, long long N_total, + int mpi_rank, long long offset, struct part* parts, struct UnitSystem* us) { + + /* Write arrays */ + writeArray(h_grp, fileName, xmfFile, "Coordinates", DOUBLE, N, 3, parts, + N_total, mpi_rank, offset, x, us, UNIT_CONV_LENGTH); + writeArray(h_grp, fileName, xmfFile, "Velocities", FLOAT, N, 3, parts, + N_total, mpi_rank, offset, v, us, UNIT_CONV_SPEED); + writeArray(h_grp, fileName, xmfFile, "Masses", FLOAT, N, 1, parts, N_total, + mpi_rank, offset, conserved.mass, us, UNIT_CONV_MASS); + writeArray(h_grp, fileName, xmfFile, "SmoothingLength", FLOAT, N, 1, parts, + N_total, mpi_rank, offset, h, us, UNIT_CONV_LENGTH); + writeArray(h_grp, fileName, xmfFile, "InternalEnergy", FLOAT, N, 1, parts, + N_total, mpi_rank, offset, primitives.P, us, + UNIT_CONV_ENTROPY_PER_UNIT_MASS); + writeArray(h_grp, fileName, xmfFile, "ParticleIDs", ULONGLONG, N, 1, parts, + N_total, mpi_rank, offset, id, us, UNIT_CONV_NO_UNITS); + writeArray(h_grp, fileName, xmfFile, "Acceleration", FLOAT, N, 3, parts, + N_total, mpi_rank, offset, a_hydro, us, UNIT_CONV_ACCELERATION); + writeArray(h_grp, fileName, xmfFile, "Density", FLOAT, N, 1, parts, N_total, + mpi_rank, offset, primitives.rho, us, UNIT_CONV_DENSITY); +} + +/** + * @brief Writes the current model of SPH to the file + * @param h_grpsph The HDF5 group in which to write + */ +void writeSPHflavour(hid_t h_grpsph) { + + /* Kernel function description */ + writeAttribute_s(h_grpsph, "Kernel", kernel_name); + writeAttribute_f(h_grpsph, "Kernel eta", const_eta_kernel); + writeAttribute_f(h_grpsph, "Weighted N_ngb", kernel_nwneigh); + writeAttribute_f(h_grpsph, "Delta N_ngb", const_delta_nwneigh); + writeAttribute_f(h_grpsph, "Hydro gamma", const_hydro_gamma); + + /* Viscosity and thermal conduction */ + writeAttribute_s(h_grpsph, "Thermal Conductivity Model", + "(No treatment) Legacy Gadget-2 as in Springel (2005)"); + writeAttribute_s(h_grpsph, "Viscosity Model", + "Legacy Gadget-2 as in Springel (2005)"); + writeAttribute_f(h_grpsph, "Viscosity alpha", const_viscosity_alpha); + writeAttribute_f(h_grpsph, "Viscosity beta", 3.f); + + /* Time integration properties */ + writeAttribute_f(h_grpsph, "CFL parameter", const_cfl); + writeAttribute_f(h_grpsph, "Maximal ln(Delta h) change over dt", + const_ln_max_h_change); + writeAttribute_f(h_grpsph, "Maximal Delta h change over dt", + exp(const_ln_max_h_change)); +} diff --git a/src/hydro/Gizmo/hydro_part.h b/src/hydro/Gizmo/hydro_part.h new file mode 100644 index 0000000000000000000000000000000000000000..9e5f32f758248d1d1616f4556c81fc8e0b52e83b --- /dev/null +++ b/src/hydro/Gizmo/hydro_part.h @@ -0,0 +1,162 @@ +/******************************************************************************* + * 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/>. + * + ******************************************************************************/ + +/* Some standard headers. */ +#include <stdlib.h> + +#define GFLOAT float + +/* Extra particle data not needed during the computation. */ +struct xpart { + + /* Old position, at last tree rebuild. */ + double x_old[3]; + + /* Velocity at the last full step. */ + float v_full[3]; + + /* Entropy at the half-step. */ + float u_hdt; + + /* Old density. */ + float omega; + +} __attribute__((aligned(xpart_align))); + +/* Data of a single particle. */ +struct part { + + /* Particle position. */ + double x[3]; + + /* Particle velocity. */ + float v[3]; + + /* Particle acceleration. */ + float a_hydro[3]; + + float mass; // MATTHIEU + float h_dt; + float rho; + float rho_dh; + + /* Particle cutoff radius. */ + float h; + + /* Particle time of beginning of time-step. */ + int ti_begin; + + /* Particle time of end of time-step. */ + int ti_end; + + /* The primitive hydrodynamical variables */ + struct { + + /* fluid velocity */ + GFLOAT v[3]; + + /* density */ + GFLOAT rho; + + /* pressure */ + GFLOAT P; + + struct { + + GFLOAT rho[3]; + + GFLOAT v[3][3]; + + GFLOAT P[3]; + + } gradients; + + struct { + + /* extreme values among the neighbours */ + GFLOAT rho[2]; + + GFLOAT v[3][2]; + + GFLOAT P[2]; + + /* maximal distance to all neighbouring faces */ + float maxr; + + } limiter; + + } primitives; + + /* The conserved hydrodynamical variables */ + struct { + + /* fluid momentum */ + GFLOAT momentum[3]; + + /* fluid mass */ + GFLOAT mass; + + /* fluid energy */ + GFLOAT energy; + + } conserved; + + /* Geometrical quantities used for hydro */ + struct { + + /* volume of the particle */ + float volume; + + /* gradient matrix */ + float matrix_E[3][3]; + + } geometry; + + struct { + + float vmax; + + } timestepvars; + + /* Quantities used during the density loop */ + struct { + + /* Particle velocity divergence. */ + float div_v; + + /* Derivative of particle number density. */ + float wcount_dh; + + /* Particle velocity curl. */ + float curl_v[3]; + + /* Particle number density. */ + float wcount; + + } density; + + /* Particle ID. */ + unsigned long long id; + + /* Associated gravitas. */ + struct gpart *gpart; + +} __attribute__((aligned(part_align))); diff --git a/src/riemann.h b/src/riemann.h new file mode 100644 index 0000000000000000000000000000000000000000..ad37490d7249bafe776b58a609064cbd0bc23abe --- /dev/null +++ b/src/riemann.h @@ -0,0 +1,44 @@ +/******************************************************************************* + * This file is part of SWIFT. + * Coypright (c) 2015 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_RIEMANN_H +#define SWIFT_RIEMANN_H + +/* gives us const_hydro_gamma and tells us which floating point type to use */ +#include "const.h" +#include "math.h" +#include "stdio.h" +#include "float.h" +#include "stdlib.h" +#include "error.h" + +#define HLLC_SOLVER + +#ifdef EXACT_SOLVER +#include "riemann/riemann_exact.h" +#endif + +#ifdef TRRS_SOLVER +#include "riemann/riemann_trrs.h" +#endif + +#ifdef HLLC_SOLVER +#include "riemann/riemann_hllc.h" +#endif + +#endif /* SWIFT_RIEMANN_H */ diff --git a/src/riemann/riemann_exact.h b/src/riemann/riemann_exact.h new file mode 100644 index 0000000000000000000000000000000000000000..861dad9729794efb302638792fef6e3df43c700a --- /dev/null +++ b/src/riemann/riemann_exact.h @@ -0,0 +1,710 @@ +/******************************************************************************* + * This file is part of SWIFT. + * Coypright (c) 2015 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/>. + * + ******************************************************************************/ + +/****************************************************************************** + * The Riemann solver in this file was written by Bert Vandenbroucke as part of + * the moving mesh code Shadowfax and adapted for use with SWIFT. It consists + * of an exact Riemann solver as described in + * Toro, Eleuterio F., Riemann Solvers and Numerical Methods for Fluid + * Dynamics, Springer (2009, 3rd edition) + * + ******************************************************************************/ + +#ifndef SWIFT_RIEMANN_EXACT_H +#define SWIFT_RIEMANN_EXACT_H + +/* frequently used combinations of const_hydro_gamma */ +#define const_riemann_gp1d2g \ + (0.5f * (const_hydro_gamma + 1.0f) / const_hydro_gamma) +#define const_riemann_gm1d2g \ + (0.5f * (const_hydro_gamma - 1.0f) / const_hydro_gamma) +#define const_riemann_gm1dgp1 \ + ((const_hydro_gamma - 1.0f) / (const_hydro_gamma + 1.0f)) +#define const_riemann_tdgp1 (2.0f / (const_hydro_gamma + 1.0f)) +#define const_riemann_tdgm1 (2.0f / (const_hydro_gamma - 1.0f)) +#define const_riemann_gm1d2 (0.5f * (const_hydro_gamma - 1.0f)) +#define const_riemann_tgdgm1 \ + (2.0f * const_hydro_gamma / (const_hydro_gamma - 1.0f)) +#define const_riemann_ginv (1.0f / const_hydro_gamma) + +/** + * @brief Functions (4.6) and (4.7) in Toro. + * + * @param p The current guess for the pressure + * @param W The left or right state vector + * @param a The left or right sound speed + */ +__attribute__((always_inline)) INLINE static GFLOAT riemann_fb(GFLOAT p, + GFLOAT* W, + GFLOAT a) { + + GFLOAT fval = 0.; + GFLOAT A, B; + if (p > W[4]) { + A = const_riemann_tdgp1 / W[0]; + B = const_riemann_gm1dgp1 * W[4]; + fval = (p - W[4]) * sqrtf(A / (p + B)); + } else { + fval = + const_riemann_tdgm1 * a * (powf(p / W[4], const_riemann_gm1d2g) - 1.0f); + } + return fval; +} + +/** + * @brief Function (4.5) in Toro + * + * @param p The current guess for the pressure + * @param WL The left state vector + * @param WR The right state vector + * @param vL The left velocity along the interface normal + * @param vR The right velocity along the interface normal + * @param aL The left sound speed + * @param aR The right sound speed + */ +__attribute__((always_inline)) + INLINE static GFLOAT riemann_f(GFLOAT p, GFLOAT* WL, GFLOAT* WR, GFLOAT vL, + GFLOAT vR, GFLOAT aL, GFLOAT aR) { + + return riemann_fb(p, WL, aL) + riemann_fb(p, WR, aR) + (vR - vL); +} + +/** + * @brief Function (4.37) in Toro + * + * @param p The current guess for the pressure + * @param W The left or right state vector + * @param a The left or right sound speed + */ +__attribute__((always_inline)) INLINE static GFLOAT riemann_fprimeb(GFLOAT p, + GFLOAT* W, + GFLOAT a) { + + GFLOAT fval = 0.; + GFLOAT A, B; + if (p > W[4]) { + A = const_riemann_tdgp1 / W[0]; + B = const_riemann_gm1dgp1 * W[4]; + fval = (1.0f - 0.5f * (p - W[4]) / (B + p)) * sqrtf(A / (p + B)); + } else { + fval = 1.0f / (W[0] * a) * powf(p / W[4], -const_riemann_gp1d2g); + } + return fval; +} + +/** + * @brief The derivative of riemann_f w.r.t. p + * + * @param p The current guess for the pressure + * @param WL The left state vector + * @param WR The right state vector + * @param aL The left sound speed + * @param aR The right sound speed + */ +__attribute__((always_inline)) INLINE static GFLOAT riemann_fprime( + GFLOAT p, GFLOAT* WL, GFLOAT* WR, GFLOAT aL, GFLOAT aR) { + + return riemann_fprimeb(p, WL, aL) + riemann_fprimeb(p, WR, aR); +} + +/** + * @brief Bottom function of (4.48) in Toro + * + * @param p The current guess for the pressure + * @param W The left or right state vector + */ +__attribute__((always_inline)) INLINE static GFLOAT riemann_gb(GFLOAT p, + GFLOAT* W) { + + GFLOAT A, B; + A = const_riemann_tdgp1 / W[0]; + B = const_riemann_gm1dgp1 * W[4]; + return sqrtf(A / (p + B)); +} + +/** + * @brief Get a good first guess for the pressure in the iterative scheme + * + * This function is based on (4.47) and (4.48) in Toro and on the + * FORTRAN code provided in Toro p.156-157 + * + * @param WL The left state vector + * @param WR The right state vector + * @param vL The left velocity along the interface normal + * @param vR The right velocity along the interface normal + * @param aL The left sound speed + * @param aR The right sound speed + */ +__attribute__((always_inline)) INLINE static GFLOAT riemann_guess_p( + GFLOAT* WL, GFLOAT* WR, GFLOAT vL, GFLOAT vR, GFLOAT aL, GFLOAT aR) { + + GFLOAT pguess, pmin, pmax, qmax; + GFLOAT ppv; + + pmin = fminf(WL[4], WR[4]); + pmax = fmaxf(WL[4], WR[4]); + qmax = pmax / pmin; + ppv = + 0.5f * (WL[4] + WR[4]) - 0.125f * (vR - vL) * (WL[0] + WR[0]) * (aL + aR); + ppv = fmaxf(1.e-8f, ppv); + if (qmax <= 2.0f && pmin <= ppv && ppv <= pmax) { + pguess = ppv; + } else { + if (ppv < pmin) { + /* two rarefactions */ + pguess = powf((aL + aR - const_riemann_gm1d2 * (vR - vL)) / + (aL / powf(WL[4], const_riemann_gm1d2g) + + aR / powf(WR[4], const_riemann_gm1d2g)), + const_riemann_tgdgm1); + } else { + /* two shocks */ + pguess = (riemann_gb(ppv, WL) * WL[4] + riemann_gb(ppv, WR) * WR[4] - vR + + vL) / + (riemann_gb(ppv, WL) + riemann_gb(ppv, WR)); + } + } + /* Toro: "Not that approximate solutions may predict, incorrectly, a negative + value for pressure (...). + Thus in order to avoid negative guess values we introduce the small + positive constant _tolerance" */ + pguess = fmaxf(1.e-8f, pguess); + return pguess; +} + +/** + * @brief Find the zeropoint of riemann_f(p) using Brent's method + * + * @param lower_limit Lower limit for the method (riemann_f(lower_limit) < 0) + * @param upper_limit Upper limit for the method (riemann_f(upper_limit) > 0) + * @param error_tol Tolerance used to decide if the solution is converged + * @param WL Left state vector + * @param WR Right state vector + * @param vL The left velocity along the interface normal + * @param vR The right velocity along the interface normal + * @param aL The left sound speed + * @param aR The right sound speed + */ +__attribute__((always_inline)) INLINE static GFLOAT riemann_solve_brent( + GFLOAT lower_limit, GFLOAT upper_limit, GFLOAT lowf, GFLOAT upf, + GFLOAT error_tol, GFLOAT* WL, GFLOAT* WR, GFLOAT vL, GFLOAT vR, GFLOAT aL, + GFLOAT aR) { + + GFLOAT a, b, c, d, s; + GFLOAT fa, fb, fc, fs; + GFLOAT tmp, tmp2; + int mflag; + int i; + + a = lower_limit; + b = upper_limit; + c = 0.0f; + d = FLT_MAX; + + fa = lowf; + fb = upf; + + fc = 0.0f; + s = 0.0f; + fs = 0.0f; + + /* if f(a) f(b) >= 0 then error-exit */ + if (fa * fb >= 0.0f) { + error( + "Brent's method called with equal sign function values!\n" + "f(%g) = %g, f(%g) = %g\n", + a, fa, b, fb); + /* return NaN */ + return 0.0f / 0.0f; + } + + /* if |f(a)| < |f(b)| then swap (a,b) */ + if (fabs(fa) < fabs(fb)) { + tmp = a; + a = b; + b = tmp; + tmp = fa; + fa = fb; + fb = tmp; + } + + c = a; + fc = fa; + mflag = 1; + i = 0; + + while (!(fb == 0.0f) && (fabs(a - b) > error_tol * 0.5f * (a + b))) { + if ((fa != fc) && (fb != fc)) /* Inverse quadratic interpolation */ + s = a * fb * fc / (fa - fb) / (fa - fc) + + b * fa * fc / (fb - fa) / (fb - fc) + + c * fa * fb / (fc - fa) / (fc - fb); + else + /* Secant Rule */ + s = b - fb * (b - a) / (fb - fa); + + tmp2 = 0.25f * (3.0f * a + b); + if (!(((s > tmp2) && (s < b)) || ((s < tmp2) && (s > b))) || + (mflag && (fabs(s - b) >= (0.5f * fabs(b - c)))) || + (!mflag && (fabs(s - b) >= (0.5f * fabs(c - d)))) || + (mflag && (fabs(b - c) < error_tol)) || + (!mflag && (fabs(c - d) < error_tol))) { + s = 0.5f * (a + b); + mflag = 1; + } else { + mflag = 0; + } + fs = riemann_f(s, WL, WR, vL, vR, aL, aR); + d = c; + c = b; + fc = fb; + if (fa * fs < 0.) { + b = s; + fb = fs; + } else { + a = s; + fa = fs; + } + + /* if |f(a)| < |f(b)| then swap (a,b) */ + if (fabs(fa) < fabs(fb)) { + tmp = a; + a = b; + b = tmp; + tmp = fa; + fa = fb; + fb = tmp; + } + i++; + } + return b; +} + +/** + * @brief Vacuum Riemann solver, based on section 4.6 in Toro + * + * @param WL The left state vector + * @param WR The right state vector + * @param vL The left velocity along the interface normal + * @param vR The right velocity along the interface normal + * @param aL The left sound speed + * @param aR The right sound speed + * @param Whalf Empty state vector to store the solution in + * @param n_unit Normal vector of the interface + */ +__attribute__((always_inline)) INLINE static void riemann_solve_vacuum( + GFLOAT* WL, GFLOAT* WR, GFLOAT vL, GFLOAT vR, GFLOAT aL, GFLOAT aR, + GFLOAT* Whalf, float* n_unit) { + + GFLOAT SL, SR; + GFLOAT vhalf; + + if (!WR[0] && !WL[0]) { + /* if both states are vacuum, the solution is also vacuum */ + Whalf[0] = 0.0f; + Whalf[1] = 0.0f; + Whalf[2] = 0.0f; + Whalf[3] = 0.0f; + Whalf[4] = 0.0f; + return; + } + if (!WR[0]) { + Whalf[1] = WL[1]; + Whalf[2] = WL[2]; + Whalf[3] = WL[3]; + /* vacuum right state */ + if (vL < aL) { + SL = vL + const_riemann_tdgm1 * aL; + if (SL > 0.0f) { + Whalf[0] = + WL[0] * powf(const_riemann_tdgp1 + const_riemann_gm1dgp1 / aL * vL, + const_riemann_tdgm1); + vhalf = const_riemann_tdgp1 * (aL + const_riemann_gm1d2 * vL) - vL; + Whalf[4] = + WL[4] * powf(const_riemann_tdgp1 + const_riemann_gm1dgp1 / aL * vL, + const_riemann_tgdgm1); + } else { + Whalf[0] = 0.0f; + Whalf[1] = 0.0f; + Whalf[2] = 0.0f; + Whalf[3] = 0.0f; + Whalf[4] = 0.0f; + return; + } + } else { + Whalf[0] = WL[0]; + vhalf = 0.0f; + Whalf[4] = WL[4]; + } + } else { + if (!WL[0]) { + Whalf[1] = WR[1]; + Whalf[2] = WR[2]; + Whalf[3] = WR[3]; + /* vacuum left state */ + if (-vR < aR) { + SR = vR - const_riemann_tdgm1 * aR; + if (SR >= 0.0f) { + Whalf[0] = 0.0f; + Whalf[1] = 0.0f; + Whalf[2] = 0.0f; + Whalf[3] = 0.0f; + Whalf[4] = 0.0f; + return; + } else { + Whalf[0] = WR[0] * + powf(const_riemann_tdgp1 - const_riemann_gm1dgp1 / aR * vR, + const_riemann_tdgm1); + vhalf = const_riemann_tdgp1 * (-aR + const_riemann_gm1d2 * vR) - vR; + Whalf[4] = WR[4] * + powf(const_riemann_tdgp1 - const_riemann_gm1dgp1 / aR * vR, + const_riemann_tgdgm1); + } + } else { + Whalf[0] = WR[0]; + vhalf = 0.0f; + Whalf[4] = WR[4]; + } + } else { + /* vacuum generation */ + SR = vR - const_riemann_tdgm1 * aR; + SL = vL + const_riemann_tdgm1 * aL; + if (SR > 0.0f && SL < 0.0f) { + Whalf[0] = 0.0f; + Whalf[1] = 0.0f; + Whalf[2] = 0.0f; + Whalf[3] = 0.0f; + Whalf[4] = 0.0f; + return; + } else { + if (SL >= 0.0f) { + Whalf[1] = WL[1]; + Whalf[2] = WL[2]; + Whalf[3] = WL[3]; + if (aL > vL) { + Whalf[0] = WL[0] * powf(const_riemann_tdgp1 + + const_riemann_gm1dgp1 / aL * vL, + const_riemann_tdgm1); + vhalf = const_riemann_tdgp1 * (aL + const_riemann_gm1d2 * vL) - vL; + Whalf[4] = WL[4] * powf(const_riemann_tdgp1 + + const_riemann_gm1dgp1 / aL * vL, + const_riemann_tgdgm1); + } else { + Whalf[0] = WL[0]; + vhalf = 0.0f; + Whalf[4] = WL[4]; + } + } else { + Whalf[1] = WR[1]; + Whalf[2] = WR[2]; + Whalf[3] = WR[3]; + if (-vR < aR) { + Whalf[0] = WR[0] * powf(const_riemann_tdgp1 - + const_riemann_gm1dgp1 / aR * vR, + const_riemann_tdgm1); + vhalf = const_riemann_tdgp1 * (-aR + const_riemann_gm1d2 * vR) - vR; + Whalf[4] = WR[4] * powf(const_riemann_tdgp1 - + const_riemann_gm1dgp1 / aR * vR, + const_riemann_tgdgm1); + } else { + Whalf[0] = WR[0]; + vhalf = 0.0f; + Whalf[4] = WR[4]; + } + } + } + } + } + + /* Add the velocity solution along the interface normal to the velocities */ + Whalf[1] += vhalf * n_unit[0]; + Whalf[2] += vhalf * n_unit[1]; + Whalf[3] += vhalf * n_unit[2]; +} + +/* Solve the Riemann problem between the states WL and WR and store the result + * in Whalf + * The Riemann problem is solved in the x-direction; the velocities in the y- + * and z-direction + * are simply advected. + */ +/** + * @brief Solve the Riemann problem between the given left and right state and + * along the given interface normal + * + * Based on chapter 4 in Toro + * + * @param WL The left state vector + * @param WR The right state vector + * @param Whalf Empty state vector in which the result will be stored + * @param n_unit Normal vector of the interface + */ +__attribute__((always_inline)) INLINE static void riemann_solver_solve( + GFLOAT* WL, GFLOAT* WR, GFLOAT* Whalf, float* n_unit) { + + /* velocity of the left and right state in a frame aligned with n_unit */ + GFLOAT vL, vR, vhalf; + /* sound speeds */ + GFLOAT aL, aR; + /* variables used for finding pstar */ + GFLOAT p, pguess, fp, fpguess; + /* variables used for sampling the solution */ + GFLOAT u; + GFLOAT pdpR, SR; + GFLOAT SHR, STR; + GFLOAT pdpL, SL; + GFLOAT SHL, STL; + int errorFlag = 0; + + /* sanity checks */ + if (WL[0] != WL[0] || WL[4] != WL[4]) { + printf("NaN WL!\n"); + errorFlag = 1; + } + if (WR[0] != WR[0] || WR[4] != WR[4]) { + printf("NaN WR!\n"); + errorFlag = 1; + } + if (WL[0] < 0.0f || WL[4] < 0.0f) { + printf("Negative WL!\n"); + errorFlag = 1; + } + if (WR[0] < 0.0f || WR[4] < 0.0f) { + printf("Negative WR!\n"); + errorFlag = 1; + } + if (errorFlag) { + printf("WL: %g %g %g %g %g\n", WL[0], WL[1], WL[2], WL[3], WL[4]); + printf("WR: %g %g %g %g %g\n", WR[0], WR[1], WR[2], WR[3], WR[4]); + error("Riemman solver input error!\n"); + } + + /* calculate velocities in interface frame */ + vL = WL[1] * n_unit[0] + WL[2] * n_unit[1] + WL[3] * n_unit[2]; + vR = WR[1] * n_unit[0] + WR[2] * n_unit[1] + WR[3] * n_unit[2]; + + /* calculate sound speeds */ + aL = sqrtf(const_hydro_gamma * WL[4] / WL[0]); + aR = sqrtf(const_hydro_gamma * WR[4] / WR[0]); + + if (!WL[0] || !WR[0]) { + /* vacuum: we need a vacuum riemann solver */ + riemann_solve_vacuum(WL, WR, vL, vR, aL, aR, Whalf, n_unit); + return; + } + + /* check vacuum generation condition */ + if (2.0f * aL / (const_hydro_gamma - 1.0f) + + 2.0f * aR / (const_hydro_gamma - 1.0f) < + fabs(vL - vR)) { + /* vacuum generation: need a vacuum riemann solver */ + riemann_solve_vacuum(WL, WR, vL, vR, aL, aR, Whalf, n_unit); + return; + } else { + /* values are ok: let's find pstar (riemann_f(pstar) = 0)! */ + /* We normally use a Newton-Raphson iteration to find the zeropoint + of riemann_f(p), but if pstar is close to 0, we risk negative p values. + Since riemann_f(p) is undefined for negative pressures, we don't + want this to happen. + We therefore use Brent's method if riemann_f(0) is larger than some + value. -5 makes the iteration fail safe while almost never invoking + the expensive Brent solver. */ + p = 0.; + /* obtain a first guess for p */ + pguess = riemann_guess_p(WL, WR, vL, vR, aL, aR); + fp = riemann_f(p, WL, WR, vL, vR, aL, aR); + fpguess = riemann_f(pguess, WL, WR, vL, vR, aL, aR); + /* ok, pstar is close to 0, better use Brent's method... */ + /* we use Newton-Raphson until we find a suitable interval */ + if (fp * fpguess >= 0.0f) { + /* Newton-Raphson until convergence or until suitable interval is found + to use Brent's method */ + unsigned int counter = 0; + while (fabs(p - pguess) > 1.e-6f * 0.5f * (p + pguess) && + fpguess < 0.0f) { + p = pguess; + pguess = pguess - fpguess / riemann_fprime(pguess, WL, WR, aL, aR); + fpguess = riemann_f(pguess, WL, WR, vL, vR, aL, aR); + counter++; + if (counter > 1000) { + error("Stuck in Newton-Raphson!\n"); + } + } + } + /* As soon as there is a suitable interval: use Brent's method */ + if (1.e6 * fabs(p - pguess) > 0.5f * (p + pguess) && fpguess > 0.0f) { + p = 0.0f; + fp = riemann_f(p, WL, WR, vL, vR, aL, aR); + /* use Brent's method to find the zeropoint */ + p = riemann_solve_brent(p, pguess, fp, fpguess, 1.e-6, WL, WR, vL, vR, aL, + aR); + } else { + p = pguess; + } + + /* calculate the velocity in the intermediate state */ + u = 0.5f * (vL + vR) + + 0.5f * (riemann_fb(p, WR, aR) - riemann_fb(p, WL, aL)); + + /* sample the solution */ + /* This corresponds to the flow chart in Fig. 4.14 in Toro */ + if (u < 0.0f) { + /* advect velocity components */ + Whalf[1] = WR[1]; + Whalf[2] = WR[2]; + Whalf[3] = WR[3]; + pdpR = p / WR[4]; + if (p > WR[4]) { + /* shockwave */ + SR = + vR + aR * sqrtf(const_riemann_gp1d2g * pdpR + const_riemann_gm1d2g); + if (SR > 0.0f) { + Whalf[0] = WR[0] * (pdpR + const_riemann_gm1dgp1) / + (const_riemann_gm1dgp1 * pdpR + 1.0f); + vhalf = u - vR; + Whalf[4] = p; + } else { + Whalf[0] = WR[0]; + vhalf = 0.0f; + Whalf[4] = WR[4]; + } + } else { + /* rarefaction wave */ + SHR = vR + aR; + if (SHR > 0.0f) { + STR = u + aR * powf(pdpR, const_riemann_gm1d2g); + if (STR <= 0.0f) { + Whalf[0] = WR[0] * powf(const_riemann_tdgp1 - + const_riemann_gm1dgp1 / aR * vR, + const_riemann_tdgm1); + vhalf = const_riemann_tdgp1 * (-aR + const_riemann_gm1d2 * vR) - vR; + Whalf[4] = WR[4] * powf(const_riemann_tdgp1 - + const_riemann_gm1dgp1 / aR * vR, + const_riemann_tgdgm1); + } else { + Whalf[0] = WR[0] * powf(pdpR, const_riemann_ginv); + vhalf = u - vR; + Whalf[4] = p; + } + } else { + Whalf[0] = WR[0]; + vhalf = 0.0f; + Whalf[4] = WR[4]; + } + } + } else { + Whalf[1] = WL[1]; + Whalf[2] = WL[2]; + Whalf[3] = WL[3]; + pdpL = p / WL[4]; + if (p > WL[4]) { + /* shockwave */ + SL = + vL - aL * sqrtf(const_riemann_gp1d2g * pdpL + const_riemann_gm1d2g); + if (SL < 0.0f) { + Whalf[0] = WL[0] * (pdpL + const_riemann_gm1dgp1) / + (const_riemann_gm1dgp1 * pdpL + 1.0f); + vhalf = u - vL; + Whalf[4] = p; + } else { + Whalf[0] = WL[0]; + vhalf = 0.0f; + Whalf[4] = WL[4]; + } + } else { + /* rarefaction wave */ + SHL = vL - aL; + if (SHL < 0.0f) { + STL = u - aL * powf(pdpL, const_riemann_gm1d2g); + if (STL > 0.0f) { + Whalf[0] = WL[0] * powf(const_riemann_tdgp1 + + const_riemann_gm1dgp1 / aL * vL, + const_riemann_tdgm1); + vhalf = const_riemann_tdgp1 * (aL + const_riemann_gm1d2 * vL) - vL; + Whalf[4] = WL[4] * powf(const_riemann_tdgp1 + + const_riemann_gm1dgp1 / aL * vL, + const_riemann_tgdgm1); + } else { + Whalf[0] = WL[0] * powf(pdpL, const_riemann_ginv); + vhalf = u - vL; + Whalf[4] = p; + } + } else { + Whalf[0] = WL[0]; + vhalf = 0.0f; + Whalf[4] = WL[4]; + } + } + } + } + + /* add the velocity solution along the interface normal to the velocities */ + Whalf[1] += vhalf * n_unit[0]; + Whalf[2] += vhalf * n_unit[1]; + Whalf[3] += vhalf * n_unit[2]; +} + +__attribute__((always_inline)) INLINE static void riemann_solve_for_flux( + GFLOAT* Wi, GFLOAT* Wj, float* n_unit, float* vij, GFLOAT* totflux) { + + GFLOAT Whalf[5]; + GFLOAT flux[5][3]; + float vtot[3]; + float rhoe; + + riemann_solver_solve(Wi, Wj, Whalf, n_unit); + + flux[0][0] = Whalf[0] * Whalf[1]; + flux[0][1] = Whalf[0] * Whalf[2]; + flux[0][2] = Whalf[0] * Whalf[3]; + + vtot[0] = Whalf[1] + vij[0]; + vtot[1] = Whalf[2] + vij[1]; + vtot[2] = Whalf[3] + vij[2]; + flux[1][0] = Whalf[0] * vtot[0] * Whalf[1] + Whalf[4]; + flux[1][1] = Whalf[0] * vtot[0] * Whalf[2]; + flux[1][2] = Whalf[0] * vtot[0] * Whalf[3]; + flux[2][0] = Whalf[0] * vtot[1] * Whalf[1]; + flux[2][1] = Whalf[0] * vtot[1] * Whalf[2] + Whalf[4]; + flux[2][2] = Whalf[0] * vtot[1] * Whalf[3]; + flux[3][0] = Whalf[0] * vtot[2] * Whalf[1]; + flux[3][1] = Whalf[0] * vtot[2] * Whalf[2]; + flux[3][2] = Whalf[0] * vtot[2] * Whalf[3] + Whalf[4]; + + /* eqn. (15) */ + /* F_P = \rho e ( \vec{v} - \vec{v_{ij}} ) + P \vec{v} */ + /* \rho e = P / (\gamma-1) + 1/2 \rho \vec{v}^2 */ + rhoe = Whalf[4] / (const_hydro_gamma - 1.0f) + + 0.5f * Whalf[0] * + (vtot[0] * vtot[0] + vtot[1] * vtot[1] + vtot[2] * vtot[2]); + flux[4][0] = rhoe * Whalf[1] + Whalf[4] * vtot[0]; + flux[4][1] = rhoe * Whalf[2] + Whalf[4] * vtot[1]; + flux[4][2] = rhoe * Whalf[3] + Whalf[4] * vtot[2]; + + totflux[0] = + flux[0][0] * n_unit[0] + flux[0][1] * n_unit[1] + flux[0][2] * n_unit[2]; + totflux[1] = + flux[1][0] * n_unit[0] + flux[1][1] * n_unit[1] + flux[1][2] * n_unit[2]; + totflux[2] = + flux[2][0] * n_unit[0] + flux[2][1] * n_unit[1] + flux[2][2] * n_unit[2]; + totflux[3] = + flux[3][0] * n_unit[0] + flux[3][1] * n_unit[1] + flux[3][2] * n_unit[2]; + totflux[4] = + flux[4][0] * n_unit[0] + flux[4][1] * n_unit[1] + flux[4][2] * n_unit[2]; +} + +#endif /* SWIFT_RIEMANN_EXACT_H */ diff --git a/src/riemann/riemann_hllc.h b/src/riemann/riemann_hllc.h new file mode 100644 index 0000000000000000000000000000000000000000..3fcc8b534ce65d4d364c400dc43e1992f39264b9 --- /dev/null +++ b/src/riemann/riemann_hllc.h @@ -0,0 +1,154 @@ +/******************************************************************************* + * This file is part of SWIFT. + * Coypright (c) 2015 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_RIEMANN_HLLC_H +#define SWIFT_RIEMANN_HLLC_H + +__attribute__((always_inline)) INLINE static void riemann_solve_for_flux( + GFLOAT *WL, GFLOAT *WR, float *n, float *vij, GFLOAT *totflux) { + + GFLOAT uL, uR, aL, aR; + GFLOAT rhobar, abar, pPVRS, pstar, qL, qR, SL, SR, Sstar; + GFLOAT v2, eL, eR; + GFLOAT UstarL[5], UstarR[5]; + + /* Handle pure vacuum */ + if (!WL[0] && !WR[0]) { + totflux[0] = 0.; + totflux[1] = 0.; + totflux[2] = 0.; + totflux[3] = 0.; + totflux[4] = 0.; + return; + } + + /* STEP 0: obtain velocity in interface frame */ + uL = WL[1] * n[0] + WL[2] * n[1] + WL[3] * n[2]; + uR = WR[1] * n[0] + WR[2] * n[1] + WR[3] * n[2]; + aL = sqrtf(const_hydro_gamma * WL[4] / WL[0]); + aR = sqrtf(const_hydro_gamma * WR[4] / WR[0]); + + /* Handle vacuum: vacuum does not require iteration and is always exact */ + if (!WL[0] || !WR[0]) { + error("Vacuum not yet supported"); + } + if (2. * aL / (const_hydro_gamma - 1.) + 2. * aR / (const_hydro_gamma - 1.) < + fabs(uL - uR)) { + error("Vacuum not yet supported"); + } + + /* STEP 1: pressure estimate */ + rhobar = 0.5 * (WL[0] + WR[0]); + abar = 0.5 * (aL + aR); + pPVRS = 0.5 * (WL[4] + WR[4]) - 0.5 * (uR - uL) * rhobar * abar; + pstar = fmaxf(0., pPVRS); + + /* STEP 2: wave speed estimates + all these speeds are along the interface normal, since uL and uR are */ + qL = 1.; + if (pstar > WL[4]) { + qL = sqrtf(1. + 0.5 * (const_hydro_gamma + 1.) / const_hydro_gamma * + (pstar / WL[4] - 1.)); + } + qR = 1.; + if (pstar > WR[4]) { + qR = sqrtf(1. + 0.5 * (const_hydro_gamma + 1.) / const_hydro_gamma * + (pstar / WR[4] - 1.)); + } + SL = uL - aL * qL; + SR = uR + aR * qR; + Sstar = (WR[4] - WL[4] + WL[0] * uL * (SL - uL) - WR[0] * uR * (SR - uR)) / + (WL[0] * (SL - uL) - WR[0] * (SR - uR)); + + /* STEP 3: HLLC flux in a frame moving with the interface velocity */ + if (Sstar >= 0.) { + /* flux FL */ + totflux[0] = WL[0] * uL; + /* these are the actual correct fluxes in the boosted lab frame + (not rotated to interface frame) */ + totflux[1] = WL[0] * WL[1] * uL + WL[4] * n[0]; + totflux[2] = WL[0] * WL[2] * uL + WL[4] * n[1]; + totflux[3] = WL[0] * WL[2] * uL + WL[4] * n[2]; + v2 = WL[1] * WL[1] + WL[2] * WL[2] + WL[3] * WL[3]; + eL = WL[4] / (const_hydro_gamma - 1.) / WL[0] + 0.5 * v2; + totflux[4] = WL[0] * eL * uL + WL[4] * uL; + if (SL < 0.) { + /* add flux FstarL */ + UstarL[0] = 1.; + /* we need UstarL in the lab frame: + subtract the velocity in the interface frame from the lab frame + velocity and then add Sstar in interface frame */ + UstarL[1] = WL[1] + (Sstar - uL) * n[0]; + UstarL[2] = WL[2] + (Sstar - uL) * n[1]; + UstarL[3] = WL[3] + (Sstar - uL) * n[2]; + UstarL[4] = eL + (Sstar - uL) * (Sstar + WL[4] / (WL[0] * (SL - uL))); + UstarL[0] *= WL[0] * (SL - uL) / (SL - Sstar); + UstarL[1] *= WL[0] * (SL - uL) / (SL - Sstar); + UstarL[2] *= WL[0] * (SL - uL) / (SL - Sstar); + UstarL[3] *= WL[0] * (SL - uL) / (SL - Sstar); + UstarL[4] *= WL[0] * (SL - uL) / (SL - Sstar); + totflux[0] += SL * (UstarL[0] - WL[0]); + totflux[1] += SL * (UstarL[1] - WL[0] * WL[1]); + totflux[2] += SL * (UstarL[2] - WL[0] * WL[2]); + totflux[3] += SL * (UstarL[3] - WL[0] * WL[3]); + totflux[4] += SL * (UstarL[4] - WL[0] * eL); + } + } else { + /* flux FR */ + totflux[0] = WR[0] * uR; + totflux[1] = WR[0] * WR[1] * uR + WR[4] * n[0]; + totflux[2] = WR[0] * WR[2] * uR + WR[4] * n[1]; + totflux[3] = WR[0] * WR[3] * uR + WR[4] * n[2]; + v2 = WR[1] * WR[1] + WR[2] * WR[2] + WR[3] * WR[3]; + eR = WR[4] / (const_hydro_gamma - 1.) / WR[0] + 0.5 * v2; + totflux[4] = WR[0] * eR * uR + WR[4] * uR; + if (SR > 0.) { + /* add flux FstarR */ + UstarR[0] = 1.; + UstarR[1] = WR[1] + (Sstar - uR) * n[0]; + UstarR[2] = WR[2] + (Sstar - uR) * n[1]; + UstarR[3] = WR[3] + (Sstar - uR) * n[2]; + UstarR[4] = eR + (Sstar - uR) * (Sstar + WR[4] / (WR[0] * (SR - uR))); + UstarR[0] *= WR[0] * (SR - uR) / (SR - Sstar); + UstarR[1] *= WR[0] * (SR - uR) / (SR - Sstar); + UstarR[2] *= WR[0] * (SR - uR) / (SR - Sstar); + UstarR[3] *= WR[0] * (SR - uR) / (SR - Sstar); + UstarR[4] *= WR[0] * (SR - uR) / (SR - Sstar); + totflux[0] += SR * (UstarR[0] - WR[0]); + totflux[1] += SR * (UstarR[1] - WR[0] * WR[1]); + totflux[2] += SR * (UstarR[2] - WR[0] * WR[2]); + totflux[3] += SR * (UstarR[3] - WR[0] * WR[3]); + totflux[4] += SR * (UstarR[4] - WR[0] * eR); + } + } + + /* deboost to lab frame + we add the flux contribution due to the movement of the interface + the density flux is unchanged + we add the extra velocity flux due to the absolute motion of the fluid + similarly, we need to add the energy fluxes due to the absolute motion */ + v2 = vij[0] * vij[0] + vij[1] * vij[1] + vij[2] * vij[2]; + totflux[1] += vij[0] * totflux[0]; + totflux[2] += vij[1] * totflux[0]; + totflux[3] += vij[2] * totflux[0]; + totflux[4] += vij[0] * totflux[1] + vij[1] * totflux[2] + + vij[2] * totflux[3] + 0.5 * v2 * totflux[0]; +} + +#endif /* SWIFT_RIEMANN_HLLC_H */ diff --git a/src/riemann/riemann_trrs.h b/src/riemann/riemann_trrs.h new file mode 100644 index 0000000000000000000000000000000000000000..56f7feadae6ea89cec742e298a269e787d58e7b3 --- /dev/null +++ b/src/riemann/riemann_trrs.h @@ -0,0 +1,144 @@ +/******************************************************************************* + * This file is part of SWIFT. + * Coypright (c) 2015 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_RIEMANN_TRRS_H +#define SWIFT_RIEMANN_TRRS_H + +/* frequently used combinations of const_hydro_gamma */ +#define const_riemann_gp1d2g \ + (0.5f * (const_hydro_gamma + 1.0f) / const_hydro_gamma) +#define const_riemann_gm1d2g \ + (0.5f * (const_hydro_gamma - 1.0f) / const_hydro_gamma) +#define const_riemann_gm1dgp1 \ + ((const_hydro_gamma - 1.0f) / (const_hydro_gamma + 1.0f)) +#define const_riemann_tdgp1 (2.0f / (const_hydro_gamma + 1.0f)) +#define const_riemann_tdgm1 (2.0f / (const_hydro_gamma - 1.0f)) +#define const_riemann_gm1d2 (0.5f * (const_hydro_gamma - 1.0f)) +#define const_riemann_tgdgm1 \ + (2.0f * const_hydro_gamma / (const_hydro_gamma - 1.0f)) +#define const_riemann_ginv (1.0f / const_hydro_gamma) + +/** + * @brief Solve the Riemann problem using the Two Rarefaction Riemann Solver + * + * By assuming 2 rarefaction waves, we can analytically solve for the pressure + * and velocity in the intermediate region, eliminating the iterative procedure. + * + * According to Toro: "The two-rarefaction approximation is generally quite + * robust; (...) The TRRS is in fact exact when both non-linear waves are + * actually rarefaction waves." + * + * @param WL The left state vector + * @param WR The right state vector + * @param Whalf Empty state vector in which the result will be stored + * @param n_unit Normal vector of the interface + */ +__attribute__((always_inline)) INLINE static void riemann_solver_solve( + GFLOAT* WL, GFLOAT* WR, GFLOAT* Whalf, float* n_unit) { + GFLOAT aL, aR; + GFLOAT PLR; + GFLOAT vL, vR; + GFLOAT ustar, pstar; + GFLOAT vhalf; + GFLOAT pdpR, SHR, STR; + GFLOAT pdpL, SHL, STL; + + /* calculate the velocities along the interface normal */ + vL = WL[1] * n_unit[0] + WL[2] * n_unit[1] + WL[3] * n_unit[2]; + vR = WR[1] * n_unit[0] + WR[2] * n_unit[1] + WR[3] * n_unit[2]; + + /* calculate the sound speeds */ + aL = sqrtf(const_hydro_gamma * WL[4] / WL[0]); + aR = sqrtf(const_hydro_gamma * WR[4] / WR[0]); + + /* calculate the velocity and pressure in the intermediate state */ + PLR = pow(WL[4] / WR[4], const_riemann_gm1d2g); + ustar = (PLR * vL / aL + vR / aR + const_riemann_tdgm1 * (PLR - 1.0f)) / + (PLR / aL + 1.0f / aR); + pstar = 0.5f * (WL[4] * pow(1.0f + const_riemann_gm1d2 / aL * (vL - ustar), + const_riemann_tgdgm1) + + WR[4] * pow(1.0f + const_riemann_gm1d2 / aR * (ustar - vR), + const_riemann_tgdgm1)); + + /* sample the solution */ + if (ustar < 0.0f) { + /* right state */ + Whalf[1] = WR[1]; + Whalf[2] = WR[2]; + Whalf[3] = WR[3]; + pdpR = pstar / WR[4]; + /* always a rarefaction wave, that's the approximation */ + SHR = vR + aR; + if (SHR > 0.0f) { + STR = ustar + aR * pow(pdpR, const_riemann_gm1d2g); + if (STR <= 0.0f) { + Whalf[0] = + WR[0] * pow(const_riemann_tdgp1 - const_riemann_gm1dgp1 / aR * vR, + const_riemann_tdgm1); + vhalf = const_riemann_tdgp1 * (-aR + const_riemann_gm1d2 * vR) - vR; + Whalf[4] = + WR[4] * pow(const_riemann_tdgp1 - const_riemann_gm1dgp1 / aR * vR, + const_riemann_tgdgm1); + } else { + Whalf[0] = WR[0] * pow(pdpR, const_riemann_ginv); + vhalf = ustar - vR; + Whalf[4] = pstar; + } + } else { + Whalf[0] = WR[0]; + vhalf = 0.0f; + Whalf[4] = WR[4]; + } + } else { + /* left state */ + Whalf[1] = WL[1]; + Whalf[2] = WL[2]; + Whalf[3] = WL[3]; + pdpL = pstar / WL[4]; + /* rarefaction wave */ + SHL = vL - aL; + if (SHL < 0.0f) { + STL = ustar - aL * pow(pdpL, const_riemann_gm1d2g); + if (STL > 0.0f) { + Whalf[0] = + WL[0] * pow(const_riemann_tdgp1 + const_riemann_gm1dgp1 / aL * vL, + const_riemann_tdgm1); + vhalf = const_riemann_tdgp1 * (aL + const_riemann_gm1d2 * vL) - vL; + Whalf[4] = + WL[4] * pow(const_riemann_tdgp1 + const_riemann_gm1dgp1 / aL * vL, + const_riemann_tgdgm1); + } else { + Whalf[0] = WL[0] * pow(pdpL, const_riemann_ginv); + vhalf = ustar - vL; + Whalf[4] = pstar; + } + } else { + Whalf[0] = WL[0]; + vhalf = 0.0f; + Whalf[4] = WL[4]; + } + } + + /* add the velocity solution along the interface normal to the velocities */ + Whalf[1] += vhalf * n_unit[0]; + Whalf[2] += vhalf * n_unit[1]; + Whalf[3] += vhalf * n_unit[2]; +} + +#endif /* SWIFT_RIEMANN_TRRS_H */