diff --git a/src/Makefile.am b/src/Makefile.am index eec459727ba4951777a6b1d9c214bdd13986a1e3..043c084df6ef9a966450f0dd172bb44e79355263 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -137,7 +137,11 @@ nobase_noinst_HEADERS = align.h approx_math.h atomic.h barrier.h cycle.h error.h hydro/Gizmo/hydro_io.h hydro/Gizmo/hydro_debug.h \ hydro/Gizmo/hydro.h hydro/Gizmo/hydro_iact.h \ hydro/Gizmo/hydro_part.h \ - hydro/Gizmo/MFV/hydro.h hydro/Gizmo/MFV/hydro_iact.h \ + hydro/Gizmo/hydro_gradients.h \ + hydro/Gizmo/hydro_getters.h \ + hydro/Gizmo/hydro_setters.h \ + hydro/Gizmo/hydro_flux.h \ + hydro/Gizmo/MFV/hydro.h \ hydro/Gizmo/MFV/hydro_io.h hydro/Gizmo/MFV/hydro_debug.h \ hydro/Gizmo/MFV/hydro_part.h \ hydro/Gizmo/MFV/hydro_gradients_gizmo.h \ @@ -149,7 +153,10 @@ nobase_noinst_HEADERS = align.h approx_math.h atomic.h barrier.h cycle.h error.h hydro/Gizmo/MFV/hydro_unphysical.h \ hydro/Gizmo/MFV/hydro_velocities.h \ hydro/Gizmo/MFV/hydro_parameters.h \ - hydro/Gizmo/MFM/hydro.h hydro/Gizmo/MFM/hydro_iact.h \ + hydro/Gizmo/MFV/hydro_getters.h \ + hydro/Gizmo/MFV/hydro_setters.h \ + hydro/Gizmo/MFV/hydro_flux.h \ + hydro/Gizmo/MFM/hydro.h \ hydro/Gizmo/MFM/hydro_io.h hydro/Gizmo/MFM/hydro_debug.h \ hydro/Gizmo/MFM/hydro_part.h \ hydro/Gizmo/MFM/hydro_gradients_gizmo.h \ @@ -160,6 +167,9 @@ nobase_noinst_HEADERS = align.h approx_math.h atomic.h barrier.h cycle.h error.h hydro/Gizmo/MFM/hydro_slope_limiters.h \ hydro/Gizmo/MFM/hydro_unphysical.h \ hydro/Gizmo/MFM/hydro_parameters.h \ + hydro/Gizmo/MFM/hydro_getters.h \ + hydro/Gizmo/MFM/hydro_setters.h \ + hydro/Gizmo/MFM/hydro_flux.h \ hydro/Shadowswift/hydro_debug.h \ hydro/Shadowswift/hydro_gradients.h hydro/Shadowswift/hydro.h \ hydro/Shadowswift/hydro_iact.h \ diff --git a/src/hydro/Gizmo/MFM/hydro_flux.h b/src/hydro/Gizmo/MFM/hydro_flux.h new file mode 100644 index 0000000000000000000000000000000000000000..9cdc2dbeecd5dbc9303d852bb5c39d1de0999605 --- /dev/null +++ b/src/hydro/Gizmo/MFM/hydro_flux.h @@ -0,0 +1,47 @@ +/******************************************************************************* + * This file is part of SWIFT. + * Coypright (c) 2019 Bert Vandenbroucke (bert.vandenbroucke@gmail.com) + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published + * by the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this program. If not, see <http://www.gnu.org/licenses/>. + * + ******************************************************************************/ +#ifndef SWIFT_GIZMO_MFM_HYDRO_FLUX_H +#define SWIFT_GIZMO_MFM_HYDRO_FLUX_H + +#include "riemann.h" + +/** + * @brief Compute the flux for the Riemann problem with the given left and right + * state, and interface normal, surface area and velocity. + * + * @param WL Left state variables. + * @param WR Right state variables. + * @param n_unit Unit vector of the interface. + * @param vLR Velocity of the interface. + * @param Anorm Surface area of the interface. + * @param fluxes Array to store the result in (of size 5 or more). + */ +__attribute__((always_inline)) INLINE static void hydro_compute_flux( + const float *WL, const float *WR, const float *n_unit, const float *vLR, + const float Anorm, float *fluxes) { + + riemann_solve_for_middle_state_flux(WL, WR, n_unit, vLR, fluxes); + + fluxes[1] *= Anorm; + fluxes[2] *= Anorm; + fluxes[3] *= Anorm; + fluxes[4] *= Anorm; +} + +#endif /* SWIFT_GIZMO_MFM_HYDRO_FLUX_H */ diff --git a/src/hydro/Gizmo/MFM/hydro_getters.h b/src/hydro/Gizmo/MFM/hydro_getters.h new file mode 100644 index 0000000000000000000000000000000000000000..bbf87d048f8c40e55956a35f084b44208e129357 --- /dev/null +++ b/src/hydro/Gizmo/MFM/hydro_getters.h @@ -0,0 +1,46 @@ +/******************************************************************************* + * This file is part of SWIFT. + * Coypright (c) 2019 Bert Vandenbroucke (bert.vandenbroucke@gmail.com) + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published + * by the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this program. If not, see <http://www.gnu.org/licenses/>. + * + ******************************************************************************/ +#ifndef SWIFT_GIZMO_MFM_HYDRO_GETTERS_H +#define SWIFT_GIZMO_MFM_HYDRO_GETTERS_H + +/** + * @brief Get a 5-element state vector W containing the primitive hydrodynamic + * variables. + * + * @param p Particle. + * @param W Pointer to the array in which the result needs to be stored (of size + * 5 or more). + */ +__attribute__((always_inline)) INLINE static void +hydro_part_get_primitive_variables(const struct part *restrict p, float *W) { + + W[0] = p->rho; + W[1] = p->v[0]; + W[2] = p->v[1]; + W[3] = p->v[2]; + W[4] = p->P; +} + +/** + * @brief Check if the gradient matrix for this particle is well behaved. + */ +#define hydro_part_geometry_well_behaved(p) \ + (p->geometry.wcorr > const_gizmo_min_wcorr) + +#endif /* SWIFT_GIZMO_MFM_HYDRO_GETTERS_H */ diff --git a/src/hydro/Gizmo/MFM/hydro_iact.h b/src/hydro/Gizmo/MFM/hydro_iact.h deleted file mode 100644 index e8b8efaeb71553cfdb776ee0510de9c25ef70bb7..0000000000000000000000000000000000000000 --- a/src/hydro/Gizmo/MFM/hydro_iact.h +++ /dev/null @@ -1,491 +0,0 @@ -/******************************************************************************* - * This file is part of SWIFT. - * Coypright (c) 2012 Pedro Gonnet (pedro.gonnet@durham.ac.uk) - * Matthieu Schaller (matthieu.schaller@durham.ac.uk) - * Bert Vandenbroucke (bert.vandenbroucke@ugent.be) - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU Lesser General Public License as published - * by the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public License - * along with this program. If not, see <http://www.gnu.org/licenses/>. - * - ******************************************************************************/ -#ifndef SWIFT_GIZMO_MFM_HYDRO_IACT_H -#define SWIFT_GIZMO_MFM_HYDRO_IACT_H - -#include "adiabatic_index.h" -#include "hydro_gradients.h" -#include "riemann.h" - -#include "./hydro_parameters.h" - -#define GIZMO_VOLUME_CORRECTION - -/** - * @brief Calculate the volume interaction between particle i and particle j - * - * The volume is in essence the same as the weighted number of neighbours in a - * classical SPH density calculation. - * - * We also calculate the components of the matrix E, which is used for second - * order accurate gradient calculations and for the calculation of the interface - * surface areas. - * - * @param r2 Comoving squared distance between particle i and particle j. - * @param dx Comoving distance vector between the particles (dx = pi->x - - * pj->x). - * @param hi Comoving smoothing-length of particle i. - * @param hj Comoving smoothing-length of particle j. - * @param pi Particle i. - * @param pj Particle j. - * @param a Current scale factor. - * @param H Current Hubble parameter. - */ -__attribute__((always_inline)) INLINE static void runner_iact_density( - float r2, const float *dx, float hi, float hj, struct part *restrict pi, - struct part *restrict pj, float a, float H) { - - float wi, wj, wi_dx, wj_dx; - - /* Get r and h inverse. */ - const float r = sqrtf(r2); - - /* Compute density of pi. */ - const float hi_inv = 1.0f / hi; - const float xi = r * hi_inv; - kernel_deval(xi, &wi, &wi_dx); - - pi->density.wcount += wi; - pi->density.wcount_dh -= (hydro_dimension * wi + xi * wi_dx); - - /* these are eqns. (1) and (2) in the summary */ - pi->geometry.volume += wi; - for (int k = 0; k < 3; k++) - for (int l = 0; l < 3; l++) - pi->geometry.matrix_E[k][l] += dx[k] * dx[l] * wi; - - pi->geometry.centroid[0] -= dx[0] * wi; - pi->geometry.centroid[1] -= dx[1] * wi; - pi->geometry.centroid[2] -= dx[2] * wi; - - /* Compute density of pj. */ - const float hj_inv = 1.0f / hj; - const float xj = r * hj_inv; - kernel_deval(xj, &wj, &wj_dx); - - pj->density.wcount += wj; - pj->density.wcount_dh -= (hydro_dimension * wj + xj * wj_dx); - - /* these are eqns. (1) and (2) in the summary */ - pj->geometry.volume += wj; - for (int k = 0; k < 3; k++) - for (int l = 0; l < 3; l++) - pj->geometry.matrix_E[k][l] += dx[k] * dx[l] * wj; - - pj->geometry.centroid[0] += dx[0] * wj; - pj->geometry.centroid[1] += dx[1] * wj; - pj->geometry.centroid[2] += dx[2] * wj; -} - -/** - * @brief Calculate the volume interaction between particle i and particle j: - * non-symmetric version - * - * The volume is in essence the same as the weighted number of neighbours in a - * classical SPH density calculation. - * - * We also calculate the components of the matrix E, which is used for second - * order accurate gradient calculations and for the calculation of the interface - * surface areas. - * - * @param r2 Comoving squared distance between particle i and particle j. - * @param dx Comoving distance vector between the particles (dx = pi->x - - * pj->x). - * @param hi Comoving smoothing-length of particle i. - * @param hj Comoving smoothing-length of particle j. - * @param pi Particle i. - * @param pj Particle j. - * @param a Current scale factor. - * @param H Current Hubble parameter. - */ -__attribute__((always_inline)) INLINE static void runner_iact_nonsym_density( - float r2, const float *dx, float hi, float hj, struct part *restrict pi, - const struct part *restrict pj, float a, float H) { - - float wi, wi_dx; - - /* Get r and h inverse. */ - const float r = sqrtf(r2); - - const float hi_inv = 1.0f / hi; - const float xi = r * hi_inv; - kernel_deval(xi, &wi, &wi_dx); - - pi->density.wcount += wi; - pi->density.wcount_dh -= (hydro_dimension * wi + xi * wi_dx); - - /* these are eqns. (1) and (2) in the summary */ - pi->geometry.volume += wi; - for (int k = 0; k < 3; k++) - for (int l = 0; l < 3; l++) - pi->geometry.matrix_E[k][l] += dx[k] * dx[l] * wi; - - pi->geometry.centroid[0] -= dx[0] * wi; - pi->geometry.centroid[1] -= dx[1] * wi; - pi->geometry.centroid[2] -= dx[2] * wi; -} - -/** - * @brief Calculate the gradient interaction between particle i and particle j - * - * This method wraps around hydro_gradients_collect, which can be an empty - * method, in which case no gradients are used. - * - * @param r2 Comoving squared distance between particle i and particle j. - * @param dx Comoving distance vector between the particles (dx = pi->x - - * pj->x). - * @param hi Comoving smoothing-length of particle i. - * @param hj Comoving smoothing-length of particle j. - * @param pi Particle i. - * @param pj Particle j. - * @param a Current scale factor. - * @param H Current Hubble parameter. - */ -__attribute__((always_inline)) INLINE static void runner_iact_gradient( - float r2, const float *dx, float hi, float hj, struct part *restrict pi, - struct part *restrict pj, float a, float H) { - - hydro_gradients_collect(r2, dx, hi, hj, pi, pj); -} - -/** - * @brief Calculate the gradient interaction between particle i and particle j: - * non-symmetric version - * - * This method wraps around hydro_gradients_nonsym_collect, which can be an - * empty method, in which case no gradients are used. - * - * @param r2 Comoving squared distance between particle i and particle j. - * @param dx Comoving distance vector between the particles (dx = pi->x - - * pj->x). - * @param hi Comoving smoothing-length of particle i. - * @param hj Comoving smoothing-length of particle j. - * @param pi Particle i. - * @param pj Particle j. - * @param a Current scale factor. - * @param H Current Hubble parameter. - */ -__attribute__((always_inline)) INLINE static void runner_iact_nonsym_gradient( - float r2, const float *dx, float hi, float hj, struct part *restrict pi, - struct part *restrict pj, float a, float H) { - - hydro_gradients_nonsym_collect(r2, dx, hi, hj, pi, pj); -} - -/** - * @brief Common part of the flux calculation between particle i and j - * - * Since the only difference between the symmetric and non-symmetric version - * of the flux calculation is in the update of the conserved variables at the - * very end (which is not done for particle j if mode is 0), both - * runner_iact_force and runner_iact_nonsym_force call this method, with an - * appropriate mode. - * - * This method calculates the surface area of the interface between particle i - * and particle j, as well as the interface position and velocity. These are - * then used to reconstruct and predict the primitive variables, which are then - * fed to a Riemann solver that calculates a flux. This flux is used to update - * the conserved variables of particle i or both particles. - * - * This method also calculates the maximal velocity used to calculate the time - * step. - * - * @param r2 Comoving squared distance between particle i and particle j. - * @param dx Comoving distance vector between the particles (dx = pi->x - - * pj->x). - * @param hi Comoving smoothing-length of particle i. - * @param hj Comoving smoothing-length of particle j. - * @param pi Particle i. - * @param pj Particle j. - * @param a Current scale factor. - * @param H Current Hubble parameter. - */ -__attribute__((always_inline)) INLINE static void runner_iact_fluxes_common( - float r2, const float *dx, float hi, float hj, struct part *restrict pi, - struct part *restrict pj, int mode, float a, float H) { - - const float r_inv = 1.0f / sqrtf(r2); - const float r = r2 * r_inv; - - /* Initialize local variables */ - float Bi[3][3]; - float Bj[3][3]; - float vi[3], vj[3]; - for (int k = 0; k < 3; k++) { - for (int l = 0; l < 3; l++) { - Bi[k][l] = pi->geometry.matrix_E[k][l]; - Bj[k][l] = pj->geometry.matrix_E[k][l]; - } - vi[k] = pi->v[k]; /* particle velocities */ - vj[k] = pj->v[k]; - } - const float Vi = pi->geometry.volume; - const float Vj = pj->geometry.volume; - float Wi[5], Wj[5]; - Wi[0] = pi->rho; - Wi[1] = pi->v[0]; - Wi[2] = pi->v[1]; - Wi[3] = pi->v[2]; - Wi[4] = pi->P; - Wj[0] = pj->rho; - Wj[1] = pj->v[0]; - Wj[2] = pj->v[1]; - Wj[3] = pj->v[2]; - Wj[4] = pj->P; - - /* calculate the maximal signal velocity */ - float vmax; - if (Wi[0] > 0.0f && Wj[0] > 0.0f) { - const float ci = gas_soundspeed_from_pressure(Wi[0], Wi[4]); - const float cj = gas_soundspeed_from_pressure(Wj[0], Wj[4]); - vmax = ci + cj; - } else - vmax = 0.0f; - - /* Velocity on the axis linking the particles */ - float dvdr = (Wi[1] - Wj[1]) * dx[0] + (Wi[2] - Wj[2]) * dx[1] + - (Wi[3] - Wj[3]) * dx[2]; - - /* We only care about this velocity for particles moving towards each other - */ - const float dvdotdx = min(dvdr, 0.0f); - - /* Get the signal velocity */ - vmax -= const_viscosity_beta * dvdotdx * r_inv; - - /* Store the signal velocity */ - pi->timestepvars.vmax = max(pi->timestepvars.vmax, vmax); - if (mode == 1) pj->timestepvars.vmax = max(pj->timestepvars.vmax, vmax); - - /* Compute kernel of pi. */ - float wi, wi_dx; - const float hi_inv = 1.0f / hi; - const float hi_inv_dim = pow_dimension(hi_inv); - const float xi = r * hi_inv; - kernel_deval(xi, &wi, &wi_dx); - - /* Compute kernel of pj. */ - float wj, wj_dx; - const float hj_inv = 1.0f / hj; - const float hj_inv_dim = pow_dimension(hj_inv); - const float xj = r * hj_inv; - kernel_deval(xj, &wj, &wj_dx); - - /* Compute h_dt. We are going to use an SPH-like estimate of div_v for that */ - const float hidp1 = pow_dimension_plus_one(hi_inv); - const float hjdp1 = pow_dimension_plus_one(hj_inv); - const float wi_dr = hidp1 * wi_dx; - const float wj_dr = hjdp1 * wj_dx; - dvdr *= r_inv; - if (pj->rho > 0.0f) - pi->force.h_dt -= pj->conserved.mass * dvdr / pj->rho * wi_dr; - if (mode == 1 && pi->rho > 0.0f) - pj->force.h_dt -= pi->conserved.mass * dvdr / pi->rho * wj_dr; - - /* Compute (square of) area */ - /* eqn. (7) */ - float Anorm2 = 0.0f; - float A[3]; - if (pi->geometry.wcorr > const_gizmo_min_wcorr && - pj->geometry.wcorr > const_gizmo_min_wcorr) { - /* in principle, we use Vi and Vj as weights for the left and right - contributions to the generalized surface vector. - However, if Vi and Vj are very different (because they have very - different - smoothing lengths), then the expressions below are more stable. */ - float Xi = Vi; - float Xj = Vj; -#ifdef GIZMO_VOLUME_CORRECTION - if (fabsf(Vi - Vj) / min(Vi, Vj) > 1.5f * hydro_dimension) { - Xi = (Vi * hj + Vj * hi) / (hi + hj); - Xj = Xi; - } -#endif - for (int k = 0; k < 3; k++) { - /* we add a minus sign since dx is pi->x - pj->x */ - A[k] = -Xi * (Bi[k][0] * dx[0] + Bi[k][1] * dx[1] + Bi[k][2] * dx[2]) * - wi * hi_inv_dim - - Xj * (Bj[k][0] * dx[0] + Bj[k][1] * dx[1] + Bj[k][2] * dx[2]) * - wj * hj_inv_dim; - Anorm2 += A[k] * A[k]; - } - } else { - /* ill condition gradient matrix: revert to SPH face area */ - const float Anorm = - -(hidp1 * Vi * Vi * wi_dx + hjdp1 * Vj * Vj * wj_dx) * r_inv; - A[0] = -Anorm * dx[0]; - A[1] = -Anorm * dx[1]; - A[2] = -Anorm * dx[2]; - Anorm2 = Anorm * Anorm * r2; - } - - /* if the interface has no area, nothing happens and we return */ - /* continuing results in dividing by zero and NaN's... */ - if (Anorm2 == 0.0f) return; - - /* Compute the area */ - const float Anorm_inv = 1.0f / sqrtf(Anorm2); - const float Anorm = Anorm2 * Anorm_inv; - -#ifdef SWIFT_DEBUG_CHECKS - /* For stability reasons, we do require A and dx to have opposite - directions (basically meaning that the surface normal for the surface - always points from particle i to particle j, as it would in a real - moving-mesh code). If not, our scheme is no longer upwind and hence can - become unstable. */ - const float dA_dot_dx = A[0] * dx[0] + A[1] * dx[1] + A[2] * dx[2]; - /* In GIZMO, Phil Hopkins reverts to an SPH integration scheme if this - happens. We curently just ignore this case and display a message. */ - const float rdim = pow_dimension(r); - if (dA_dot_dx > 1.e-6f * rdim) { - message("Ill conditioned gradient matrix (%g %g %g %g %g)!", dA_dot_dx, - Anorm, Vi, Vj, r); - } -#endif - - /* compute the normal vector of the interface */ - const float n_unit[3] = {A[0] * Anorm_inv, A[1] * Anorm_inv, - A[2] * Anorm_inv}; - - /* Compute interface position (relative to pi, since we don't need the actual - * position) eqn. (8) */ - const float xfac = -hi / (hi + hj); - const float xij_i[3] = {xfac * dx[0], xfac * dx[1], xfac * dx[2]}; - - /* Compute interface velocity */ - /* eqn. (9) */ - const float vij[3] = {vi[0] + (vi[0] - vj[0]) * xfac, - vi[1] + (vi[1] - vj[1]) * xfac, - vi[2] + (vi[2] - vj[2]) * xfac}; - - /* 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]; - - hydro_gradients_predict(pi, pj, hi, hj, dx, r, xij_i, Wi, Wj); - - /* Boost the primitive variables to the frame of reference of the interface */ - /* Note that velocities are indices 1-3 in W */ - Wi[1] -= vij[0]; - Wi[2] -= vij[1]; - Wi[3] -= vij[2]; - Wj[1] -= vij[0]; - Wj[2] -= vij[1]; - Wj[3] -= vij[2]; - - /* we don't need to rotate, we can use the unit vector in the Riemann problem - * itself (see GIZMO) */ - - float totflux[5]; - riemann_solve_for_middle_state_flux(Wi, Wj, n_unit, vij, totflux); - - /* Multiply with the interface surface area */ - totflux[1] *= Anorm; - totflux[2] *= Anorm; - totflux[3] *= Anorm; - totflux[4] *= Anorm; - - /* Update conserved variables */ - /* We shamelessly exploit the fact that the mass flux is zero and omit all - terms involving it */ - /* eqn. (16) */ - pi->flux.momentum[0] -= totflux[1]; - pi->flux.momentum[1] -= totflux[2]; - pi->flux.momentum[2] -= totflux[3]; - pi->flux.energy -= totflux[4]; - -#ifndef GIZMO_TOTAL_ENERGY - pi->flux.energy += totflux[1] * pi->v[0]; - pi->flux.energy += totflux[2] * pi->v[1]; - pi->flux.energy += totflux[3] * pi->v[2]; -#endif - - /* Note that this used to be much more complicated in early implementations of - * the GIZMO scheme, as we wanted manifest conservation of conserved variables - * and had to do symmetric flux exchanges. Now we don't care about manifest - * conservation anymore and just assume the current fluxes are representative - * for the flux over the entire time step. */ - if (mode == 1) { - pj->flux.momentum[0] += totflux[1]; - pj->flux.momentum[1] += totflux[2]; - pj->flux.momentum[2] += totflux[3]; - pj->flux.energy += totflux[4]; - -#ifndef GIZMO_TOTAL_ENERGY - pj->flux.energy -= totflux[1] * pj->v[0]; - pj->flux.energy -= totflux[2] * pj->v[1]; - pj->flux.energy -= totflux[3] * pj->v[2]; -#endif - } -} - -/** - * @brief Flux calculation between particle i and particle j - * - * This method calls runner_iact_fluxes_common with mode 1. - * - * @param r2 Comoving squared distance between particle i and particle j. - * @param dx Comoving distance vector between the particles (dx = pi->x - - * pj->x). - * @param hi Comoving smoothing-length of particle i. - * @param hj Comoving smoothing-length of particle j. - * @param pi Particle i. - * @param pj Particle j. - * @param a Current scale factor. - * @param H Current Hubble parameter. - */ -__attribute__((always_inline)) INLINE static void runner_iact_force( - float r2, const float *dx, float hi, float hj, struct part *restrict pi, - struct part *restrict pj, float a, float H) { - - runner_iact_fluxes_common(r2, dx, hi, hj, pi, pj, 1, a, H); -} - -/** - * @brief Flux calculation between particle i and particle j: non-symmetric - * version - * - * This method calls runner_iact_fluxes_common with mode 0. - * - * @param r2 Comoving squared distance between particle i and particle j. - * @param dx Comoving distance vector between the particles (dx = pi->x - - * pj->x). - * @param hi Comoving smoothing-length of particle i. - * @param hj Comoving smoothing-length of particle j. - * @param pi Particle i. - * @param pj Particle j. - * @param a Current scale factor. - * @param H Current Hubble parameter. - */ -__attribute__((always_inline)) INLINE static void runner_iact_nonsym_force( - float r2, const float *dx, float hi, float hj, struct part *restrict pi, - struct part *restrict pj, float a, float H) { - - runner_iact_fluxes_common(r2, dx, hi, hj, pi, pj, 0, a, H); -} - -#endif /* SWIFT_GIZMO_MFM_HYDRO_IACT_H */ diff --git a/src/hydro/Gizmo/MFM/hydro_setters.h b/src/hydro/Gizmo/MFM/hydro_setters.h new file mode 100644 index 0000000000000000000000000000000000000000..68767745d248c8e4eab6f9c2f9dc63a0c3092b85 --- /dev/null +++ b/src/hydro/Gizmo/MFM/hydro_setters.h @@ -0,0 +1,71 @@ +/******************************************************************************* + * This file is part of SWIFT. + * Coypright (c) 2019 Bert Vandenbroucke (bert.vandenbroucke@gmail.com) + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published + * by the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this program. If not, see <http://www.gnu.org/licenses/>. + * + ******************************************************************************/ +#ifndef SWIFT_GIZMO_MFM_HYDRO_SETTERS_H +#define SWIFT_GIZMO_MFM_HYDRO_SETTERS_H + +#include "const.h" + +/** + * @brief Update the fluxes for the particle with the given contributions, + * assuming the particle is to the left of the interparticle interface. + * + * @param p Particle. + * @param fluxes Fluxes accross the interface. + * @param dx Distance between the particles that share the interface. + */ +__attribute__((always_inline)) INLINE static void hydro_part_update_fluxes_left( + struct part *restrict p, const float *fluxes, const float *dx) { + + p->flux.momentum[0] -= fluxes[1]; + p->flux.momentum[1] -= fluxes[2]; + p->flux.momentum[2] -= fluxes[3]; + p->flux.energy -= fluxes[4]; + +#ifndef GIZMO_TOTAL_ENERGY + p->flux.energy += fluxes[1] * p->v[0]; + p->flux.energy += fluxes[2] * p->v[1]; + p->flux.energy += fluxes[3] * p->v[2]; +#endif +} + +/** + * @brief Update the fluxes for the particle with the given contributions, + * assuming the particle is to the right of the interparticle interface. + * + * @param p Particle. + * @param fluxes Fluxes accross the interface. + * @param dx Distance between the particles that share the interface. + */ +__attribute__((always_inline)) INLINE static void +hydro_part_update_fluxes_right(struct part *restrict p, const float *fluxes, + const float *dx) { + + p->flux.momentum[0] += fluxes[1]; + p->flux.momentum[1] += fluxes[2]; + p->flux.momentum[2] += fluxes[3]; + p->flux.energy += fluxes[4]; + +#ifndef GIZMO_TOTAL_ENERGY + p->flux.energy -= fluxes[1] * p->v[0]; + p->flux.energy -= fluxes[2] * p->v[1]; + p->flux.energy -= fluxes[3] * p->v[2]; +#endif +} + +#endif /* SWIFT_GIZMO_MFM_HYDRO_SETTERS_H */ diff --git a/src/hydro/Gizmo/MFV/hydro_flux.h b/src/hydro/Gizmo/MFV/hydro_flux.h new file mode 100644 index 0000000000000000000000000000000000000000..bc66e6088f09357ff2398c3b15f744029b86111a --- /dev/null +++ b/src/hydro/Gizmo/MFV/hydro_flux.h @@ -0,0 +1,48 @@ +/******************************************************************************* + * This file is part of SWIFT. + * Coypright (c) 2019 Bert Vandenbroucke (bert.vandenbroucke@gmail.com) + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published + * by the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this program. If not, see <http://www.gnu.org/licenses/>. + * + ******************************************************************************/ +#ifndef SWIFT_GIZMO_MFV_HYDRO_FLUX_H +#define SWIFT_GIZMO_MFV_HYDRO_FLUX_H + +#include "riemann.h" + +/** + * @brief Compute the flux for the Riemann problem with the given left and right + * state, and interface normal, surface area and velocity. + * + * @param WL Left state variables. + * @param WR Right state variables. + * @param n_unit Unit vector of the interface. + * @param vLR Velocity of the interface. + * @param Anorm Surface area of the interface. + * @param fluxes Array to store the result in (of size 5 or more). + */ +__attribute__((always_inline)) INLINE static void hydro_compute_flux( + const float *WL, const float *WR, const float *n_unit, const float *vLR, + const float Anorm, float *fluxes) { + + riemann_solve_for_flux(WL, WR, n_unit, vLR, fluxes); + + fluxes[0] *= Anorm; + fluxes[1] *= Anorm; + fluxes[2] *= Anorm; + fluxes[3] *= Anorm; + fluxes[4] *= Anorm; +} + +#endif /* SWIFT_GIZMO_MFV_HYDRO_FLUX_H */ diff --git a/src/hydro/Gizmo/MFV/hydro_getters.h b/src/hydro/Gizmo/MFV/hydro_getters.h new file mode 100644 index 0000000000000000000000000000000000000000..e793380d7ff88624db6634eeb878749ff1371e73 --- /dev/null +++ b/src/hydro/Gizmo/MFV/hydro_getters.h @@ -0,0 +1,46 @@ +/******************************************************************************* + * This file is part of SWIFT. + * Coypright (c) 2019 Bert Vandenbroucke (bert.vandenbroucke@gmail.com) + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published + * by the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this program. If not, see <http://www.gnu.org/licenses/>. + * + ******************************************************************************/ +#ifndef SWIFT_GIZMO_MFV_HYDRO_GETTERS_H +#define SWIFT_GIZMO_MFV_HYDRO_GETTERS_H + +/** + * @brief Get a 5-element state vector W containing the primitive hydrodynamic + * variables. + * + * @param p Particle. + * @param W Pointer to the array in which the result needs to be stored (of size + * 5 or more). + */ +__attribute__((always_inline)) INLINE static void +hydro_part_get_primitive_variables(const struct part *restrict p, float *W) { + + W[0] = p->primitives.rho; + W[1] = p->primitives.v[0]; + W[2] = p->primitives.v[1]; + W[3] = p->primitives.v[2]; + W[4] = p->primitives.P; +} + +/** + * @brief Check if the gradient matrix for this particle is well behaved. + */ +#define hydro_part_geometry_well_behaved(p) \ + (p->density.wcorr > const_gizmo_min_wcorr) + +#endif /* SWIFT_GIZMO_MFV_HYDRO_GETTERS_H */ diff --git a/src/hydro/Gizmo/MFV/hydro_iact.h b/src/hydro/Gizmo/MFV/hydro_iact.h deleted file mode 100644 index 1b8aac4ff89e4945a314ff72c44bff8dbfe1502c..0000000000000000000000000000000000000000 --- a/src/hydro/Gizmo/MFV/hydro_iact.h +++ /dev/null @@ -1,506 +0,0 @@ -/******************************************************************************* - * This file is part of SWIFT. - * Coypright (c) 2012 Pedro Gonnet (pedro.gonnet@durham.ac.uk) - * Matthieu Schaller (matthieu.schaller@durham.ac.uk) - * Bert Vandenbroucke (bert.vandenbroucke@ugent.be) - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU Lesser General Public License as published - * by the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public License - * along with this program. If not, see <http://www.gnu.org/licenses/>. - * - ******************************************************************************/ -#ifndef SWIFT_GIZMO_MFV_HYDRO_IACT_H -#define SWIFT_GIZMO_MFV_HYDRO_IACT_H - -#include "adiabatic_index.h" -#include "hydro_gradients.h" -#include "riemann.h" - -#include "./hydro_parameters.h" - -#define GIZMO_VOLUME_CORRECTION - -/** - * @brief Calculate the volume interaction between particle i and particle j - * - * The volume is in essence the same as the weighted number of neighbours in a - * classical SPH density calculation. - * - * We also calculate the components of the matrix E, which is used for second - * order accurate gradient calculations and for the calculation of the interface - * surface areas. - * - * @param r2 Comoving squared distance between particle i and particle j. - * @param dx Comoving distance vector between the particles (dx = pi->x - - * pj->x). - * @param hi Comoving smoothing-length of particle i. - * @param hj Comoving smoothing-length of particle j. - * @param pi Particle i. - * @param pj Particle j. - * @param a Current scale factor. - * @param H Current Hubble parameter. - */ -__attribute__((always_inline)) INLINE static void runner_iact_density( - float r2, const float *dx, float hi, float hj, struct part *restrict pi, - struct part *restrict pj, float a, float H) { - - float wi, wj, wi_dx, wj_dx; - - /* Get r and h inverse. */ - const float r = sqrtf(r2); - - /* Compute density of pi. */ - const float hi_inv = 1.f / hi; - const float xi = r * hi_inv; - kernel_deval(xi, &wi, &wi_dx); - - pi->density.wcount += wi; - pi->density.wcount_dh -= (hydro_dimension * wi + xi * wi_dx); - - /* these are eqns. (1) and (2) in the summary */ - pi->geometry.volume += wi; - for (int k = 0; k < 3; k++) - for (int l = 0; l < 3; l++) - pi->geometry.matrix_E[k][l] += dx[k] * dx[l] * wi; - - pi->geometry.centroid[0] -= dx[0] * wi; - pi->geometry.centroid[1] -= dx[1] * wi; - pi->geometry.centroid[2] -= dx[2] * wi; - - /* Compute density of pj. */ - const float hj_inv = 1.f / hj; - const float xj = r * hj_inv; - kernel_deval(xj, &wj, &wj_dx); - - pj->density.wcount += wj; - pj->density.wcount_dh -= (hydro_dimension * wj + xj * wj_dx); - - /* these are eqns. (1) and (2) in the summary */ - pj->geometry.volume += wj; - for (int k = 0; k < 3; k++) - for (int l = 0; l < 3; l++) - pj->geometry.matrix_E[k][l] += dx[k] * dx[l] * wj; - - pj->geometry.centroid[0] += dx[0] * wj; - pj->geometry.centroid[1] += dx[1] * wj; - pj->geometry.centroid[2] += dx[2] * wj; -} - -/** - * @brief Calculate the volume interaction between particle i and particle j: - * non-symmetric version - * - * The volume is in essence the same as the weighted number of neighbours in a - * classical SPH density calculation. - * - * We also calculate the components of the matrix E, which is used for second - * order accurate gradient calculations and for the calculation of the interface - * surface areas. - * - * @param r2 Comoving squared distance between particle i and particle j. - * @param dx Comoving distance vector between the particles (dx = pi->x - - * pj->x). - * @param hi Comoving smoothing-length of particle i. - * @param hj Comoving smoothing-length of particle j. - * @param pi Particle i. - * @param pj Particle j. - * @param a Current scale factor. - * @param H Current Hubble parameter. - */ -__attribute__((always_inline)) INLINE static void runner_iact_nonsym_density( - float r2, const float *dx, float hi, float hj, struct part *restrict pi, - const struct part *restrict pj, float a, float H) { - - float wi, wi_dx; - - /* Get r and h inverse. */ - const float r = sqrtf(r2); - - const float hi_inv = 1.f / hi; - const float xi = r * hi_inv; - kernel_deval(xi, &wi, &wi_dx); - - pi->density.wcount += wi; - pi->density.wcount_dh -= (hydro_dimension * wi + xi * wi_dx); - - /* these are eqns. (1) and (2) in the summary */ - pi->geometry.volume += wi; - for (int k = 0; k < 3; k++) - for (int l = 0; l < 3; l++) - pi->geometry.matrix_E[k][l] += dx[k] * dx[l] * wi; - - pi->geometry.centroid[0] -= dx[0] * wi; - pi->geometry.centroid[1] -= dx[1] * wi; - pi->geometry.centroid[2] -= dx[2] * wi; -} - -/** - * @brief Calculate the gradient interaction between particle i and particle j - * - * This method wraps around hydro_gradients_collect, which can be an empty - * method, in which case no gradients are used. - * - * @param r2 Comoving squared distance between particle i and particle j. - * @param dx Comoving distance vector between the particles (dx = pi->x - - * pj->x). - * @param hi Comoving smoothing-length of particle i. - * @param hj Comoving smoothing-length of particle j. - * @param pi Particle i. - * @param pj Particle j. - * @param a Current scale factor. - * @param H Current Hubble parameter. - */ -__attribute__((always_inline)) INLINE static void runner_iact_gradient( - float r2, const float *dx, float hi, float hj, struct part *restrict pi, - struct part *restrict pj, float a, float H) { - - hydro_gradients_collect(r2, dx, hi, hj, pi, pj); -} - -/** - * @brief Calculate the gradient interaction between particle i and particle j: - * non-symmetric version - * - * This method wraps around hydro_gradients_nonsym_collect, which can be an - * empty method, in which case no gradients are used. - * - * @param r2 Comoving squared distance between particle i and particle j. - * @param dx Comoving distance vector between the particles (dx = pi->x - - * pj->x). - * @param hi Comoving smoothing-length of particle i. - * @param hj Comoving smoothing-length of particle j. - * @param pi Particle i. - * @param pj Particle j. - * @param a Current scale factor. - * @param H Current Hubble parameter. - */ -__attribute__((always_inline)) INLINE static void runner_iact_nonsym_gradient( - float r2, const float *dx, float hi, float hj, struct part *restrict pi, - struct part *restrict pj, float a, float H) { - - hydro_gradients_nonsym_collect(r2, dx, hi, hj, pi, pj); -} - -/** - * @brief Common part of the flux calculation between particle i and j - * - * Since the only difference between the symmetric and non-symmetric version - * of the flux calculation is in the update of the conserved variables at the - * very end (which is not done for particle j if mode is 0), both - * runner_iact_force and runner_iact_nonsym_force call this method, with an - * appropriate mode. - * - * This method calculates the surface area of the interface between particle i - * and particle j, as well as the interface position and velocity. These are - * then used to reconstruct and predict the primitive variables, which are then - * fed to a Riemann solver that calculates a flux. This flux is used to update - * the conserved variables of particle i or both particles. - * - * This method also calculates the maximal velocity used to calculate the time - * step. - * - * @param r2 Comoving squared distance between particle i and particle j. - * @param dx Comoving distance vector between the particles (dx = pi->x - - * pj->x). - * @param hi Comoving smoothing-length of particle i. - * @param hj Comoving smoothing-length of particle j. - * @param pi Particle i. - * @param pj Particle j. - * @param a Current scale factor. - * @param H Current Hubble parameter. - */ -__attribute__((always_inline)) INLINE static void runner_iact_fluxes_common( - float r2, const float *dx, float hi, float hj, struct part *restrict pi, - struct part *restrict pj, int mode, float a, float H) { - - const float r_inv = 1.f / sqrtf(r2); - const float r = r2 * r_inv; - - /* Initialize local variables */ - float Bi[3][3]; - float Bj[3][3]; - float vi[3], vj[3]; - for (int k = 0; k < 3; k++) { - for (int l = 0; l < 3; l++) { - Bi[k][l] = pi->geometry.matrix_E[k][l]; - Bj[k][l] = pj->geometry.matrix_E[k][l]; - } - vi[k] = pi->v[k]; /* particle velocities */ - vj[k] = pj->v[k]; - } - const float Vi = pi->geometry.volume; - const float Vj = pj->geometry.volume; - float Wi[5], Wj[5]; - Wi[0] = pi->primitives.rho; - Wi[1] = pi->primitives.v[0]; - Wi[2] = pi->primitives.v[1]; - Wi[3] = pi->primitives.v[2]; - Wi[4] = pi->primitives.P; - Wj[0] = pj->primitives.rho; - Wj[1] = pj->primitives.v[0]; - Wj[2] = pj->primitives.v[1]; - Wj[3] = pj->primitives.v[2]; - Wj[4] = pj->primitives.P; - - /* calculate the maximal signal velocity */ - float vmax; - if (Wi[0] > 0.0f && Wj[0] > 0.0f) { - const float ci = gas_soundspeed_from_pressure(Wi[0], Wi[4]); - const float cj = gas_soundspeed_from_pressure(Wj[0], Wj[4]); - vmax = ci + cj; - } else - vmax = 0.0f; - - float dvdr = (pi->v[0] - pj->v[0]) * dx[0] + (pi->v[1] - pj->v[1]) * dx[1] + - (pi->v[2] - pj->v[2]) * dx[2]; - - /* Velocity on the axis linking the particles */ - float dvdotdx = (Wi[1] - Wj[1]) * dx[0] + (Wi[2] - Wj[2]) * dx[1] + - (Wi[3] - Wj[3]) * dx[2]; - dvdotdx = min(dvdotdx, dvdr); - - /* We only care about this velocity for particles moving towards each others - */ - dvdotdx = min(dvdotdx, 0.f); - - /* Get the signal velocity */ - vmax -= const_viscosity_beta * dvdotdx * r_inv; - - /* Store the signal velocity */ - pi->timestepvars.vmax = max(pi->timestepvars.vmax, vmax); - if (mode == 1) pj->timestepvars.vmax = max(pj->timestepvars.vmax, vmax); - - /* Compute kernel of pi. */ - float wi, wi_dx; - const float hi_inv = 1.f / hi; - const float hi_inv_dim = pow_dimension(hi_inv); - const float xi = r * hi_inv; - kernel_deval(xi, &wi, &wi_dx); - - /* Compute kernel of pj. */ - float wj, wj_dx; - const float hj_inv = 1.f / hj; - const float hj_inv_dim = pow_dimension(hj_inv); - const float xj = r * hj_inv; - kernel_deval(xj, &wj, &wj_dx); - - /* Compute h_dt. We are going to use an SPH-like estimate of div_v for that */ - const float hidp1 = pow_dimension_plus_one(hi_inv); - const float hjdp1 = pow_dimension_plus_one(hj_inv); - const float wi_dr = hidp1 * wi_dx; - const float wj_dr = hjdp1 * wj_dx; - dvdr *= r_inv; - if (pj->primitives.rho > 0.) - pi->force.h_dt -= pj->conserved.mass * dvdr / pj->primitives.rho * wi_dr; - if (mode == 1 && pi->primitives.rho > 0.) - pj->force.h_dt -= pi->conserved.mass * dvdr / pi->primitives.rho * wj_dr; - - /* Compute (square of) area */ - /* eqn. (7) */ - float Anorm2 = 0.0f; - float A[3]; - if (pi->density.wcorr > const_gizmo_min_wcorr && - pj->density.wcorr > const_gizmo_min_wcorr) { - /* in principle, we use Vi and Vj as weights for the left and right - contributions to the generalized surface vector. - However, if Vi and Vj are very different (because they have very - different - smoothing lengths), then the expressions below are more stable. */ - float Xi = Vi; - float Xj = Vj; -#ifdef GIZMO_VOLUME_CORRECTION - if (fabsf(Vi - Vj) / min(Vi, Vj) > 1.5f * hydro_dimension) { - Xi = (Vi * hj + Vj * hi) / (hi + hj); - Xj = Xi; - } -#endif - for (int k = 0; k < 3; k++) { - /* we add a minus sign since dx is pi->x - pj->x */ - A[k] = -Xi * (Bi[k][0] * dx[0] + Bi[k][1] * dx[1] + Bi[k][2] * dx[2]) * - wi * hi_inv_dim - - Xj * (Bj[k][0] * dx[0] + Bj[k][1] * dx[1] + Bj[k][2] * dx[2]) * - wj * hj_inv_dim; - Anorm2 += A[k] * A[k]; - } - } else { - /* ill condition gradient matrix: revert to SPH face area */ - const float Anorm = - -(hidp1 * Vi * Vi * wi_dx + hjdp1 * Vj * Vj * wj_dx) * r_inv; - A[0] = -Anorm * dx[0]; - A[1] = -Anorm * dx[1]; - A[2] = -Anorm * dx[2]; - Anorm2 = Anorm * Anorm * r2; - } - - /* if the interface has no area, nothing happens and we return */ - /* continuing results in dividing by zero and NaN's... */ - if (Anorm2 == 0.f) return; - - /* Compute the area */ - const float Anorm_inv = 1. / sqrtf(Anorm2); - const float Anorm = Anorm2 * Anorm_inv; - -#ifdef SWIFT_DEBUG_CHECKS - /* For stability reasons, we do require A and dx to have opposite - directions (basically meaning that the surface normal for the surface - always points from particle i to particle j, as it would in a real - moving-mesh code). If not, our scheme is no longer upwind and hence can - become unstable. */ - const float dA_dot_dx = A[0] * dx[0] + A[1] * dx[1] + A[2] * dx[2]; - /* In GIZMO, Phil Hopkins reverts to an SPH integration scheme if this - happens. We curently just ignore this case and display a message. */ - const float rdim = pow_dimension(r); - if (dA_dot_dx > 1.e-6f * rdim) { - message("Ill conditioned gradient matrix (%g %g %g %g %g)!", dA_dot_dx, - Anorm, Vi, Vj, r); - } -#endif - - /* compute the normal vector of the interface */ - const float n_unit[3] = {A[0] * Anorm_inv, A[1] * Anorm_inv, - A[2] * Anorm_inv}; - - /* Compute interface position (relative to pi, since we don't need the actual - * position) eqn. (8) */ - const float xfac = -hi / (hi + hj); - const float xij_i[3] = {xfac * dx[0], xfac * dx[1], xfac * dx[2]}; - - /* Compute interface velocity */ - /* eqn. (9) */ - const float vij[3] = {vi[0] + xfac * (vi[0] - vj[0]), - vi[1] + xfac * (vi[1] - vj[1]), - vi[2] + xfac * (vi[2] - vj[2])}; - - hydro_gradients_predict(pi, pj, hi, hj, dx, r, xij_i, Wi, Wj); - - /* Boost the primitive variables to the frame of reference of the interface */ - /* Note that velocities are indices 1-3 in W */ - Wi[1] -= vij[0]; - Wi[2] -= vij[1]; - Wi[3] -= vij[2]; - Wj[1] -= vij[0]; - Wj[2] -= vij[1]; - Wj[3] -= vij[2]; - - /* we don't need to rotate, we can use the unit vector in the Riemann problem - * itself (see GIZMO) */ - - float totflux[5]; - riemann_solve_for_flux(Wi, Wj, n_unit, vij, totflux); - - /* Multiply with the interface surface area */ - totflux[0] *= Anorm; - totflux[1] *= Anorm; - totflux[2] *= Anorm; - totflux[3] *= Anorm; - totflux[4] *= Anorm; - - /* Store mass flux */ - const float mflux_i = totflux[0]; - pi->gravity.mflux[0] += mflux_i * dx[0]; - pi->gravity.mflux[1] += mflux_i * dx[1]; - pi->gravity.mflux[2] += mflux_i * dx[2]; - - /* Update conserved variables */ - /* eqn. (16) */ - pi->conserved.flux.mass -= totflux[0]; - pi->conserved.flux.momentum[0] -= totflux[1]; - pi->conserved.flux.momentum[1] -= totflux[2]; - pi->conserved.flux.momentum[2] -= totflux[3]; - pi->conserved.flux.energy -= totflux[4]; - -#ifndef GIZMO_TOTAL_ENERGY - const float ekin_i = 0.5f * (pi->primitives.v[0] * pi->primitives.v[0] + - pi->primitives.v[1] * pi->primitives.v[1] + - pi->primitives.v[2] * pi->primitives.v[2]); - pi->conserved.flux.energy += totflux[1] * pi->primitives.v[0]; - pi->conserved.flux.energy += totflux[2] * pi->primitives.v[1]; - pi->conserved.flux.energy += totflux[3] * pi->primitives.v[2]; - pi->conserved.flux.energy -= totflux[0] * ekin_i; -#endif - - /* Note that this used to be much more complicated in early implementations of - * the GIZMO scheme, as we wanted manifest conservation of conserved variables - * and had to do symmetric flux exchanges. Now we don't care about manifest - * conservation anymore and just assume the current fluxes are representative - * for the flux over the entire time step. */ - if (mode == 1) { - /* Store mass flux */ - const float mflux_j = totflux[0]; - pj->gravity.mflux[0] += mflux_j * dx[0]; - pj->gravity.mflux[1] += mflux_j * dx[1]; - pj->gravity.mflux[2] += mflux_j * dx[2]; - - pj->conserved.flux.mass += totflux[0]; - pj->conserved.flux.momentum[0] += totflux[1]; - pj->conserved.flux.momentum[1] += totflux[2]; - pj->conserved.flux.momentum[2] += totflux[3]; - pj->conserved.flux.energy += totflux[4]; - -#ifndef GIZMO_TOTAL_ENERGY - const float ekin_j = 0.5f * (pj->primitives.v[0] * pj->primitives.v[0] + - pj->primitives.v[1] * pj->primitives.v[1] + - pj->primitives.v[2] * pj->primitives.v[2]); - pj->conserved.flux.energy -= totflux[1] * pj->primitives.v[0]; - pj->conserved.flux.energy -= totflux[2] * pj->primitives.v[1]; - pj->conserved.flux.energy -= totflux[3] * pj->primitives.v[2]; - pj->conserved.flux.energy += totflux[0] * ekin_j; -#endif - } -} - -/** - * @brief Flux calculation between particle i and particle j - * - * This method calls runner_iact_fluxes_common with mode 1. - * - * @param r2 Comoving squared distance between particle i and particle j. - * @param dx Comoving distance vector between the particles (dx = pi->x - - * pj->x). - * @param hi Comoving smoothing-length of particle i. - * @param hj Comoving smoothing-length of particle j. - * @param pi Particle i. - * @param pj Particle j. - * @param a Current scale factor. - * @param H Current Hubble parameter. - */ -__attribute__((always_inline)) INLINE static void runner_iact_force( - float r2, const float *dx, float hi, float hj, struct part *restrict pi, - struct part *restrict pj, float a, float H) { - - runner_iact_fluxes_common(r2, dx, hi, hj, pi, pj, 1, a, H); -} - -/** - * @brief Flux calculation between particle i and particle j: non-symmetric - * version - * - * This method calls runner_iact_fluxes_common with mode 0. - * - * @param r2 Comoving squared distance between particle i and particle j. - * @param dx Comoving distance vector between the particles (dx = pi->x - - * pj->x). - * @param hi Comoving smoothing-length of particle i. - * @param hj Comoving smoothing-length of particle j. - * @param pi Particle i. - * @param pj Particle j. - * @param a Current scale factor. - * @param H Current Hubble parameter. - */ -__attribute__((always_inline)) INLINE static void runner_iact_nonsym_force( - float r2, const float *dx, float hi, float hj, struct part *restrict pi, - struct part *restrict pj, float a, float H) { - - runner_iact_fluxes_common(r2, dx, hi, hj, pi, pj, 0, a, H); -} - -#endif /* SWIFT_GIZMO_MFV_HYDRO_IACT_H */ diff --git a/src/hydro/Gizmo/MFV/hydro_setters.h b/src/hydro/Gizmo/MFV/hydro_setters.h new file mode 100644 index 0000000000000000000000000000000000000000..d3ae4177612cf47b9ca9b21c1aec74361176a515 --- /dev/null +++ b/src/hydro/Gizmo/MFV/hydro_setters.h @@ -0,0 +1,89 @@ +/******************************************************************************* + * This file is part of SWIFT. + * Coypright (c) 2019 Bert Vandenbroucke (bert.vandenbroucke@gmail.com) + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published + * by the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this program. If not, see <http://www.gnu.org/licenses/>. + * + ******************************************************************************/ +#ifndef SWIFT_GIZMO_MFV_HYDRO_SETTERS_H +#define SWIFT_GIZMO_MFV_HYDRO_SETTERS_H + +#include "const.h" + +/** + * @brief Update the fluxes for the particle with the given contributions, + * assuming the particle is to the left of the interparticle interface. + * + * @param p Particle. + * @param fluxes Fluxes accross the interface. + * @param dx Distance between the particles that share the interface. + */ +__attribute__((always_inline)) INLINE static void hydro_part_update_fluxes_left( + struct part *restrict p, const float *fluxes, const float *dx) { + + p->gravity.mflux[0] += fluxes[0] * dx[0]; + p->gravity.mflux[1] += fluxes[0] * dx[1]; + p->gravity.mflux[2] += fluxes[0] * dx[2]; + + p->conserved.flux.mass -= fluxes[0]; + p->conserved.flux.momentum[0] -= fluxes[1]; + p->conserved.flux.momentum[1] -= fluxes[2]; + p->conserved.flux.momentum[2] -= fluxes[3]; + p->conserved.flux.energy -= fluxes[4]; + +#ifndef GIZMO_TOTAL_ENERGY + const float ekin = 0.5f * (p->primitives.v[0] * p->primitives.v[0] + + p->primitives.v[1] * p->primitives.v[1] + + p->primitives.v[2] * p->primitives.v[2]); + p->conserved.flux.energy += fluxes[1] * p->primitives.v[0]; + p->conserved.flux.energy += fluxes[2] * p->primitives.v[1]; + p->conserved.flux.energy += fluxes[3] * p->primitives.v[2]; + p->conserved.flux.energy -= fluxes[0] * ekin; +#endif +} + +/** + * @brief Update the fluxes for the particle with the given contributions, + * assuming the particle is to the right of the interparticle interface. + * + * @param p Particle. + * @param fluxes Fluxes accross the interface. + * @param dx Distance between the particles that share the interface. + */ +__attribute__((always_inline)) INLINE static void +hydro_part_update_fluxes_right(struct part *restrict p, const float *fluxes, + const float *dx) { + + p->gravity.mflux[0] += fluxes[0] * dx[0]; + p->gravity.mflux[1] += fluxes[0] * dx[1]; + p->gravity.mflux[2] += fluxes[0] * dx[2]; + + p->conserved.flux.mass += fluxes[0]; + p->conserved.flux.momentum[0] += fluxes[1]; + p->conserved.flux.momentum[1] += fluxes[2]; + p->conserved.flux.momentum[2] += fluxes[3]; + p->conserved.flux.energy += fluxes[4]; + +#ifndef GIZMO_TOTAL_ENERGY + const float ekin = 0.5f * (p->primitives.v[0] * p->primitives.v[0] + + p->primitives.v[1] * p->primitives.v[1] + + p->primitives.v[2] * p->primitives.v[2]); + p->conserved.flux.energy -= fluxes[1] * p->primitives.v[0]; + p->conserved.flux.energy -= fluxes[2] * p->primitives.v[1]; + p->conserved.flux.energy -= fluxes[3] * p->primitives.v[2]; + p->conserved.flux.energy += fluxes[0] * ekin; +#endif +} + +#endif /* SWIFT_GIZMO_MFV_HYDRO_SETTERS_H */ diff --git a/src/hydro/Gizmo/hydro_flux.h b/src/hydro/Gizmo/hydro_flux.h new file mode 100644 index 0000000000000000000000000000000000000000..0fba48fe6aafa6073d8af90ac57a4a6cc44508a7 --- /dev/null +++ b/src/hydro/Gizmo/hydro_flux.h @@ -0,0 +1,28 @@ +/******************************************************************************* + * This file is part of SWIFT. + * Coypright (c) 2019 Bert Vandenbroucke (bert.vandenbroucke@gmail.com) + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published + * by the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this program. If not, see <http://www.gnu.org/licenses/>. + * + ******************************************************************************/ +#ifndef SWIFT_GIZMO_HYDRO_FLUX_H +#define SWIFT_GIZMO_HYDRO_FLUX_H + +#if defined(GIZMO_MFV_SPH) +#include "MFV/hydro_flux.h" +#elif defined(GIZMO_MFM_SPH) +#include "MFM/hydro_flux.h" +#endif + +#endif /* SWIFT_GIZMO_HYDRO_FLUX_H */ diff --git a/src/hydro/Gizmo/hydro_getters.h b/src/hydro/Gizmo/hydro_getters.h new file mode 100644 index 0000000000000000000000000000000000000000..59217744441c00680b20ed9ab13f35ba7a22c5cb --- /dev/null +++ b/src/hydro/Gizmo/hydro_getters.h @@ -0,0 +1,28 @@ +/******************************************************************************* + * This file is part of SWIFT. + * Coypright (c) 2019 Bert Vandenbroucke (bert.vandenbroucke@gmail.com) + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published + * by the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this program. If not, see <http://www.gnu.org/licenses/>. + * + ******************************************************************************/ +#ifndef SWIFT_GIZMO_HYDRO_GETTERS_H +#define SWIFT_GIZMO_HYDRO_GETTERS_H + +#if defined(GIZMO_MFV_SPH) +#include "MFV/hydro_getters.h" +#elif defined(GIZMO_MFM_SPH) +#include "MFM/hydro_getters.h" +#endif + +#endif /* SWIFT_GIZMO_HYDRO_GETTERS_H */ diff --git a/src/hydro/Gizmo/hydro_gradients.h b/src/hydro/Gizmo/hydro_gradients.h new file mode 100644 index 0000000000000000000000000000000000000000..da0b096bdda889cc1959fb310402707549edf43b --- /dev/null +++ b/src/hydro/Gizmo/hydro_gradients.h @@ -0,0 +1,28 @@ +/******************************************************************************* + * This file is part of SWIFT. + * Coypright (c) 2019 Bert Vandenbroucke (bert.vandenbroucke@gmail.com) + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published + * by the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this program. If not, see <http://www.gnu.org/licenses/>. + * + ******************************************************************************/ +#ifndef SWIFT_GIZMO_HYDRO_GRADIENTS_H +#define SWIFT_GIZMO_HYDRO_GRADIENTS_H + +#if defined(GIZMO_MFV_SPH) +#include "MFV/hydro_gradients.h" +#elif defined(GIZMO_MFM_SPH) +#include "MFM/hydro_gradients.h" +#endif + +#endif /* SWIFT_GIZMO_HYDRO_GRADIENTS_H */ diff --git a/src/hydro/Gizmo/hydro_iact.h b/src/hydro/Gizmo/hydro_iact.h index 61f307037baf15a03732e4e9106bd794fb6ce049..243a3d37c343ec6ae4157ab25815b08e6d0c6ddc 100644 --- a/src/hydro/Gizmo/hydro_iact.h +++ b/src/hydro/Gizmo/hydro_iact.h @@ -19,10 +19,446 @@ #ifndef SWIFT_GIZMO_HYDRO_IACT_H #define SWIFT_GIZMO_HYDRO_IACT_H -#if defined(GIZMO_MFV_SPH) -#include "MFV/hydro_iact.h" -#elif defined(GIZMO_MFM_SPH) -#include "MFM/hydro_iact.h" +#include "hydro_flux.h" +#include "hydro_getters.h" +#include "hydro_gradients.h" +#include "hydro_setters.h" + +#define GIZMO_VOLUME_CORRECTION + +/** + * @brief Calculate the volume interaction between particle i and particle j + * + * The volume is in essence the same as the weighted number of neighbours in a + * classical SPH density calculation. + * + * We also calculate the components of the matrix E, which is used for second + * order accurate gradient calculations and for the calculation of the interface + * surface areas. + * + * @param r2 Comoving squared distance between particle i and particle j. + * @param dx Comoving distance vector between the particles (dx = pi->x - + * pj->x). + * @param hi Comoving smoothing-length of particle i. + * @param hj Comoving smoothing-length of particle j. + * @param pi Particle i. + * @param pj Particle j. + * @param a Current scale factor. + * @param H Current Hubble parameter. + */ +__attribute__((always_inline)) INLINE static void runner_iact_density( + float r2, const float *dx, float hi, float hj, struct part *restrict pi, + struct part *restrict pj, float a, float H) { + + float wi, wj, wi_dx, wj_dx; + + /* Get r and h inverse. */ + const float r = sqrtf(r2); + + /* Compute density of pi. */ + const float hi_inv = 1.0f / hi; + const float xi = r * hi_inv; + kernel_deval(xi, &wi, &wi_dx); + + pi->density.wcount += wi; + pi->density.wcount_dh -= (hydro_dimension * wi + xi * wi_dx); + + /* these are eqns. (1) and (2) in the summary */ + pi->geometry.volume += wi; + for (int k = 0; k < 3; k++) + for (int l = 0; l < 3; l++) + pi->geometry.matrix_E[k][l] += dx[k] * dx[l] * wi; + + pi->geometry.centroid[0] -= dx[0] * wi; + pi->geometry.centroid[1] -= dx[1] * wi; + pi->geometry.centroid[2] -= dx[2] * wi; + + /* Compute density of pj. */ + const float hj_inv = 1.0f / hj; + const float xj = r * hj_inv; + kernel_deval(xj, &wj, &wj_dx); + + pj->density.wcount += wj; + pj->density.wcount_dh -= (hydro_dimension * wj + xj * wj_dx); + + /* these are eqns. (1) and (2) in the summary */ + pj->geometry.volume += wj; + for (int k = 0; k < 3; k++) + for (int l = 0; l < 3; l++) + pj->geometry.matrix_E[k][l] += dx[k] * dx[l] * wj; + + pj->geometry.centroid[0] += dx[0] * wj; + pj->geometry.centroid[1] += dx[1] * wj; + pj->geometry.centroid[2] += dx[2] * wj; +} + +/** + * @brief Calculate the volume interaction between particle i and particle j: + * non-symmetric version + * + * The volume is in essence the same as the weighted number of neighbours in a + * classical SPH density calculation. + * + * We also calculate the components of the matrix E, which is used for second + * order accurate gradient calculations and for the calculation of the interface + * surface areas. + * + * @param r2 Comoving squared distance between particle i and particle j. + * @param dx Comoving distance vector between the particles (dx = pi->x - + * pj->x). + * @param hi Comoving smoothing-length of particle i. + * @param hj Comoving smoothing-length of particle j. + * @param pi Particle i. + * @param pj Particle j. + * @param a Current scale factor. + * @param H Current Hubble parameter. + */ +__attribute__((always_inline)) INLINE static void runner_iact_nonsym_density( + float r2, const float *dx, float hi, float hj, struct part *restrict pi, + const struct part *restrict pj, float a, float H) { + + float wi, wi_dx; + + /* Get r and h inverse. */ + const float r = sqrtf(r2); + + const float hi_inv = 1.0f / hi; + const float xi = r * hi_inv; + kernel_deval(xi, &wi, &wi_dx); + + pi->density.wcount += wi; + pi->density.wcount_dh -= (hydro_dimension * wi + xi * wi_dx); + + /* these are eqns. (1) and (2) in the summary */ + pi->geometry.volume += wi; + for (int k = 0; k < 3; k++) + for (int l = 0; l < 3; l++) + pi->geometry.matrix_E[k][l] += dx[k] * dx[l] * wi; + + pi->geometry.centroid[0] -= dx[0] * wi; + pi->geometry.centroid[1] -= dx[1] * wi; + pi->geometry.centroid[2] -= dx[2] * wi; +} + +/** + * @brief Calculate the gradient interaction between particle i and particle j + * + * This method wraps around hydro_gradients_collect, which can be an empty + * method, in which case no gradients are used. + * + * @param r2 Comoving squared distance between particle i and particle j. + * @param dx Comoving distance vector between the particles (dx = pi->x - + * pj->x). + * @param hi Comoving smoothing-length of particle i. + * @param hj Comoving smoothing-length of particle j. + * @param pi Particle i. + * @param pj Particle j. + * @param a Current scale factor. + * @param H Current Hubble parameter. + */ +__attribute__((always_inline)) INLINE static void runner_iact_gradient( + float r2, const float *dx, float hi, float hj, struct part *restrict pi, + struct part *restrict pj, float a, float H) { + + hydro_gradients_collect(r2, dx, hi, hj, pi, pj); +} + +/** + * @brief Calculate the gradient interaction between particle i and particle j: + * non-symmetric version + * + * This method wraps around hydro_gradients_nonsym_collect, which can be an + * empty method, in which case no gradients are used. + * + * @param r2 Comoving squared distance between particle i and particle j. + * @param dx Comoving distance vector between the particles (dx = pi->x - + * pj->x). + * @param hi Comoving smoothing-length of particle i. + * @param hj Comoving smoothing-length of particle j. + * @param pi Particle i. + * @param pj Particle j. + * @param a Current scale factor. + * @param H Current Hubble parameter. + */ +__attribute__((always_inline)) INLINE static void runner_iact_nonsym_gradient( + float r2, const float *dx, float hi, float hj, struct part *restrict pi, + struct part *restrict pj, float a, float H) { + + hydro_gradients_nonsym_collect(r2, dx, hi, hj, pi, pj); +} + +/** + * @brief Common part of the flux calculation between particle i and j + * + * Since the only difference between the symmetric and non-symmetric version + * of the flux calculation is in the update of the conserved variables at the + * very end (which is not done for particle j if mode is 0), both + * runner_iact_force and runner_iact_nonsym_force call this method, with an + * appropriate mode. + * + * This method calculates the surface area of the interface between particle i + * and particle j, as well as the interface position and velocity. These are + * then used to reconstruct and predict the primitive variables, which are then + * fed to a Riemann solver that calculates a flux. This flux is used to update + * the conserved variables of particle i or both particles. + * + * This method also calculates the maximal velocity used to calculate the time + * step. + * + * @param r2 Comoving squared distance between particle i and particle j. + * @param dx Comoving distance vector between the particles (dx = pi->x - + * pj->x). + * @param hi Comoving smoothing-length of particle i. + * @param hj Comoving smoothing-length of particle j. + * @param pi Particle i. + * @param pj Particle j. + * @param a Current scale factor. + * @param H Current Hubble parameter. + */ +__attribute__((always_inline)) INLINE static void runner_iact_fluxes_common( + float r2, const float *dx, float hi, float hj, struct part *restrict pi, + struct part *restrict pj, int mode, float a, float H) { + + const float r_inv = 1.0f / sqrtf(r2); + const float r = r2 * r_inv; + + /* Initialize local variables */ + float Bi[3][3]; + float Bj[3][3]; + float vi[3], vj[3]; + for (int k = 0; k < 3; k++) { + for (int l = 0; l < 3; l++) { + Bi[k][l] = pi->geometry.matrix_E[k][l]; + Bj[k][l] = pj->geometry.matrix_E[k][l]; + } + vi[k] = pi->v[k]; /* particle velocities */ + vj[k] = pj->v[k]; + } + const float Vi = pi->geometry.volume; + const float Vj = pj->geometry.volume; + float Wi[5], Wj[5]; + hydro_part_get_primitive_variables(pi, Wi); + hydro_part_get_primitive_variables(pj, Wj); + + /* calculate the maximal signal velocity */ + float vmax; + if (Wi[0] > 0.0f && Wj[0] > 0.0f) { + const float ci = gas_soundspeed_from_pressure(Wi[0], Wi[4]); + const float cj = gas_soundspeed_from_pressure(Wj[0], Wj[4]); + vmax = ci + cj; + } else { + vmax = 0.0f; + } + + float dvdr = (pi->v[0] - pj->v[0]) * dx[0] + (pi->v[1] - pj->v[1]) * dx[1] + + (pi->v[2] - pj->v[2]) * dx[2]; + + /* Velocity on the axis linking the particles */ + /* This velocity will be the same as dvdr for MFM, so hopefully this gets + optimised out. */ + float dvdotdx = (Wi[1] - Wj[1]) * dx[0] + (Wi[2] - Wj[2]) * dx[1] + + (Wi[3] - Wj[3]) * dx[2]; + + /* We only care about this velocity for particles moving towards each others + */ + dvdotdx = min3(dvdr, dvdotdx, 0.f); + + /* Get the signal velocity */ + vmax -= const_viscosity_beta * dvdotdx * r_inv; + + /* Store the signal velocity */ + pi->timestepvars.vmax = max(pi->timestepvars.vmax, vmax); + if (mode == 1) { + pj->timestepvars.vmax = max(pj->timestepvars.vmax, vmax); + } + + /* Compute kernel of pi. */ + float wi, wi_dx; + const float hi_inv = 1.0f / hi; + const float hi_inv_dim = pow_dimension(hi_inv); + const float xi = r * hi_inv; + kernel_deval(xi, &wi, &wi_dx); + + /* Compute kernel of pj. */ + float wj, wj_dx; + const float hj_inv = 1.0f / hj; + const float hj_inv_dim = pow_dimension(hj_inv); + const float xj = r * hj_inv; + kernel_deval(xj, &wj, &wj_dx); + + /* Compute h_dt. We are going to use an SPH-like estimate of div_v for that */ + const float hidp1 = pow_dimension_plus_one(hi_inv); + const float hjdp1 = pow_dimension_plus_one(hj_inv); + const float wi_dr = hidp1 * wi_dx; + const float wj_dr = hjdp1 * wj_dx; + dvdr *= r_inv; + if (Wj[0] > 0.0f) { + pi->force.h_dt -= pj->conserved.mass * dvdr / Wj[0] * wi_dr; + } + if (mode == 1 && Wi[0] > 0.0f) { + pj->force.h_dt -= pi->conserved.mass * dvdr / Wi[0] * wj_dr; + } + + /* Compute (square of) area */ + /* eqn. (7) */ + float Anorm2 = 0.0f; + float A[3]; + if (hydro_part_geometry_well_behaved(pi) && + hydro_part_geometry_well_behaved(pj)) { + /* in principle, we use Vi and Vj as weights for the left and right + contributions to the generalized surface vector. + However, if Vi and Vj are very different (because they have very + different + smoothing lengths), then the expressions below are more stable. */ + float Xi = Vi; + float Xj = Vj; +#ifdef GIZMO_VOLUME_CORRECTION + if (fabsf(Vi - Vj) / min(Vi, Vj) > 1.5f * hydro_dimension) { + Xi = (Vi * hj + Vj * hi) / (hi + hj); + Xj = Xi; + } +#endif + for (int k = 0; k < 3; k++) { + /* we add a minus sign since dx is pi->x - pj->x */ + A[k] = -Xi * (Bi[k][0] * dx[0] + Bi[k][1] * dx[1] + Bi[k][2] * dx[2]) * + wi * hi_inv_dim - + Xj * (Bj[k][0] * dx[0] + Bj[k][1] * dx[1] + Bj[k][2] * dx[2]) * + wj * hj_inv_dim; + Anorm2 += A[k] * A[k]; + } + } else { + /* ill condition gradient matrix: revert to SPH face area */ + const float Anorm = + -(hidp1 * Vi * Vi * wi_dx + hjdp1 * Vj * Vj * wj_dx) * r_inv; + A[0] = -Anorm * dx[0]; + A[1] = -Anorm * dx[1]; + A[2] = -Anorm * dx[2]; + Anorm2 = Anorm * Anorm * r2; + } + + /* if the interface has no area, nothing happens and we return */ + /* continuing results in dividing by zero and NaN's... */ + if (Anorm2 == 0.0f) { + return; + } + + /* Compute the area */ + const float Anorm_inv = 1.0f / sqrtf(Anorm2); + const float Anorm = Anorm2 * Anorm_inv; + +#ifdef SWIFT_DEBUG_CHECKS + /* For stability reasons, we do require A and dx to have opposite + directions (basically meaning that the surface normal for the surface + always points from particle i to particle j, as it would in a real + moving-mesh code). If not, our scheme is no longer upwind and hence can + become unstable. */ + const float dA_dot_dx = A[0] * dx[0] + A[1] * dx[1] + A[2] * dx[2]; + /* In GIZMO, Phil Hopkins reverts to an SPH integration scheme if this + happens. We curently just ignore this case and display a message. */ + const float rdim = pow_dimension(r); + if (dA_dot_dx > 1.e-6f * rdim) { + message("Ill conditioned gradient matrix (%g %g %g %g %g)!", dA_dot_dx, + Anorm, Vi, Vj, r); + } #endif + /* compute the normal vector of the interface */ + const float n_unit[3] = {A[0] * Anorm_inv, A[1] * Anorm_inv, + A[2] * Anorm_inv}; + + /* Compute interface position (relative to pi, since we don't need the actual + * position) eqn. (8) */ + const float xfac = -hi / (hi + hj); + const float xij_i[3] = {xfac * dx[0], xfac * dx[1], xfac * dx[2]}; + + /* Compute interface velocity */ + /* eqn. (9) */ + const float vij[3] = {vi[0] + (vi[0] - vj[0]) * xfac, + vi[1] + (vi[1] - vj[1]) * xfac, + vi[2] + (vi[2] - vj[2]) * xfac}; + + /* 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]; + + hydro_gradients_predict(pi, pj, hi, hj, dx, r, xij_i, Wi, Wj); + + /* Boost the primitive variables to the frame of reference of the interface */ + /* Note that velocities are indices 1-3 in W */ + Wi[1] -= vij[0]; + Wi[2] -= vij[1]; + Wi[3] -= vij[2]; + Wj[1] -= vij[0]; + Wj[2] -= vij[1]; + Wj[3] -= vij[2]; + + /* we don't need to rotate, we can use the unit vector in the Riemann problem + * itself (see GIZMO) */ + + float totflux[5]; + hydro_compute_flux(Wi, Wj, n_unit, vij, Anorm, totflux); + + hydro_part_update_fluxes_left(pi, totflux, dx); + + /* Note that this used to be much more complicated in early implementations of + * the GIZMO scheme, as we wanted manifest conservation of conserved variables + * and had to do symmetric flux exchanges. Now we don't care about manifest + * conservation anymore and just assume the current fluxes are representative + * for the flux over the entire time step. */ + if (mode == 1) { + hydro_part_update_fluxes_right(pj, totflux, dx); + } +} + +/** + * @brief Flux calculation between particle i and particle j + * + * This method calls runner_iact_fluxes_common with mode 1. + * + * @param r2 Comoving squared distance between particle i and particle j. + * @param dx Comoving distance vector between the particles (dx = pi->x - + * pj->x). + * @param hi Comoving smoothing-length of particle i. + * @param hj Comoving smoothing-length of particle j. + * @param pi Particle i. + * @param pj Particle j. + * @param a Current scale factor. + * @param H Current Hubble parameter. + */ +__attribute__((always_inline)) INLINE static void runner_iact_force( + float r2, const float *dx, float hi, float hj, struct part *restrict pi, + struct part *restrict pj, float a, float H) { + + runner_iact_fluxes_common(r2, dx, hi, hj, pi, pj, 1, a, H); +} + +/** + * @brief Flux calculation between particle i and particle j: non-symmetric + * version + * + * This method calls runner_iact_fluxes_common with mode 0. + * + * @param r2 Comoving squared distance between particle i and particle j. + * @param dx Comoving distance vector between the particles (dx = pi->x - + * pj->x). + * @param hi Comoving smoothing-length of particle i. + * @param hj Comoving smoothing-length of particle j. + * @param pi Particle i. + * @param pj Particle j. + * @param a Current scale factor. + * @param H Current Hubble parameter. + */ +__attribute__((always_inline)) INLINE static void runner_iact_nonsym_force( + float r2, const float *dx, float hi, float hj, struct part *restrict pi, + struct part *restrict pj, float a, float H) { + + runner_iact_fluxes_common(r2, dx, hi, hj, pi, pj, 0, a, H); +} + #endif /* SWIFT_GIZMO_HYDRO_IACT_H */ diff --git a/src/hydro/Gizmo/hydro_setters.h b/src/hydro/Gizmo/hydro_setters.h new file mode 100644 index 0000000000000000000000000000000000000000..351796979f84417647719dd2076b9f32fc1f551b --- /dev/null +++ b/src/hydro/Gizmo/hydro_setters.h @@ -0,0 +1,28 @@ +/******************************************************************************* + * This file is part of SWIFT. + * Coypright (c) 2019 Bert Vandenbroucke (bert.vandenbroucke@gmail.com) + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published + * by the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this program. If not, see <http://www.gnu.org/licenses/>. + * + ******************************************************************************/ +#ifndef SWIFT_GIZMO_HYDRO_SETTERS_H +#define SWIFT_GIZMO_HYDRO_SETTERS_H + +#if defined(GIZMO_MFV_SPH) +#include "MFV/hydro_setters.h" +#elif defined(GIZMO_MFM_SPH) +#include "MFM/hydro_setters.h" +#endif + +#endif /* SWIFT_GIZMO_HYDRO_SETTERS_H */