diff --git a/.gitignore b/.gitignore index aa3676fe292246d0ab53022dfd2a4a3ce305174e..db06575cf9f291d1fb9fa253fb5146c065523dd9 100644 --- a/.gitignore +++ b/.gitignore @@ -36,6 +36,7 @@ examples/*/*/*.xmf examples/*/*/*.hdf5 examples/*/*/*.txt examples/*/*/used_parameters.yml +examples/*/*.png tests/testPair tests/brute_force_standard.dat @@ -72,7 +73,11 @@ tests/testPair.sh tests/testPairPerturbed.sh tests/testParser.sh tests/testReading.sh - +tests/testAdiabaticIndex +tests/testRiemannExact +tests/testRiemannTRRS +tests/testRiemannHLLC +tests/testMatrixInversion theory/latex/swift.pdf theory/kernel/kernels.pdf diff --git a/examples/Gradients/gradientsCartesian.yml b/examples/Gradients/gradientsCartesian.yml new file mode 100644 index 0000000000000000000000000000000000000000..917a4803004c2ce89984beb857cb1691d9a1ec1b --- /dev/null +++ b/examples/Gradients/gradientsCartesian.yml @@ -0,0 +1,36 @@ +# Define the system of units to use internally. +InternalUnitSystem: + UnitMass_in_cgs: 1 # Grams + UnitLength_in_cgs: 1 # Centimeters + UnitVelocity_in_cgs: 1 # Centimeters per second + UnitCurrent_in_cgs: 1 # Amperes + UnitTemp_in_cgs: 1 # Kelvin + +# Parameters governing the time integration +TimeIntegration: + time_begin: 0. # The starting time of the simulation (in internal units). + time_end: 1e-6 # The end time of the simulation (in internal units). + dt_min: 1e-6 # The minimal time-step size of the simulation (in internal units). + dt_max: 1e-6 # The maximal time-step size of the simulation (in internal units). + +# Parameters governing the snapshots +Snapshots: + basename: gradients_cartesian # Common part of the name of output files + time_first: 0. # Time of the first output (in internal units) + delta_time: 5e-7 # Time difference between consecutive outputs (in internal units) + +# Parameters governing the conserved quantities statistics +Statistics: + delta_time: 1e-6 # Time between statistics output + +# Parameters for the hydrodynamics scheme +SPH: + resolution_eta: 1.2348 # Target smoothing length in units of the mean inter-particle separation (1.2348 == 48Ngbs with the cubic spline kernel). + delta_neighbours: 0.1 # The tolerance for the targetted number of neighbours. + max_smoothing_length: 0.01 # Maximal smoothing length allowed (in internal units). + CFL_condition: 0.1 # Courant-Friedrich-Levy condition for time integration. + +# Parameters related to the initial conditions +InitialConditions: + file_name: ./Gradients_cartesian.hdf5 # The file to read + diff --git a/examples/Gradients/gradientsRandom.yml b/examples/Gradients/gradientsRandom.yml new file mode 100644 index 0000000000000000000000000000000000000000..209f30060f031f7d50a15ffbf8ad0e7fe5b013b8 --- /dev/null +++ b/examples/Gradients/gradientsRandom.yml @@ -0,0 +1,36 @@ +# Define the system of units to use internally. +InternalUnitSystem: + UnitMass_in_cgs: 1 # Grams + UnitLength_in_cgs: 1 # Centimeters + UnitVelocity_in_cgs: 1 # Centimeters per second + UnitCurrent_in_cgs: 1 # Amperes + UnitTemp_in_cgs: 1 # Kelvin + +# Parameters governing the time integration +TimeIntegration: + time_begin: 0. # The starting time of the simulation (in internal units). + time_end: 1e-6 # The end time of the simulation (in internal units). + dt_min: 1e-6 # The minimal time-step size of the simulation (in internal units). + dt_max: 1e-6 # The maximal time-step size of the simulation (in internal units). + +# Parameters governing the snapshots +Snapshots: + basename: gradients_random # Common part of the name of output files + time_first: 0. # Time of the first output (in internal units) + delta_time: 5e-7 # Time difference between consecutive outputs (in internal units) + +# Parameters governing the conserved quantities statistics +Statistics: + delta_time: 1e-6 # Time between statistics output + +# Parameters for the hydrodynamics scheme +SPH: + resolution_eta: 1.2348 # Target smoothing length in units of the mean inter-particle separation (1.2348 == 48Ngbs with the cubic spline kernel). + delta_neighbours: 0.1 # The tolerance for the targetted number of neighbours. + max_smoothing_length: 0.01 # Maximal smoothing length allowed (in internal units). + CFL_condition: 0.1 # Courant-Friedrich-Levy condition for time integration. + +# Parameters related to the initial conditions +InitialConditions: + file_name: ./Gradients_random.hdf5 # The file to read + diff --git a/examples/Gradients/gradientsStretched.yml b/examples/Gradients/gradientsStretched.yml new file mode 100644 index 0000000000000000000000000000000000000000..592a70762988fca764c3ec7dcbc9bfcc9a8f2751 --- /dev/null +++ b/examples/Gradients/gradientsStretched.yml @@ -0,0 +1,36 @@ +# Define the system of units to use internally. +InternalUnitSystem: + UnitMass_in_cgs: 1 # Grams + UnitLength_in_cgs: 1 # Centimeters + UnitVelocity_in_cgs: 1 # Centimeters per second + UnitCurrent_in_cgs: 1 # Amperes + UnitTemp_in_cgs: 1 # Kelvin + +# Parameters governing the time integration +TimeIntegration: + time_begin: 0. # The starting time of the simulation (in internal units). + time_end: 1e-6 # The end time of the simulation (in internal units). + dt_min: 1e-6 # The minimal time-step size of the simulation (in internal units). + dt_max: 1e-6 # The maximal time-step size of the simulation (in internal units). + +# Parameters governing the snapshots +Snapshots: + basename: gradients_stretched # Common part of the name of output files + time_first: 0. # Time of the first output (in internal units) + delta_time: 5e-7 # Time difference between consecutive outputs (in internal units) + +# Parameters governing the conserved quantities statistics +Statistics: + delta_time: 1e-6 # Time between statistics output + +# Parameters for the hydrodynamics scheme +SPH: + resolution_eta: 1.2348 # Target smoothing length in units of the mean inter-particle separation (1.2348 == 48Ngbs with the cubic spline kernel). + delta_neighbours: 0.1 # The tolerance for the targetted number of neighbours. + max_smoothing_length: 0.01 # Maximal smoothing length allowed (in internal units). + CFL_condition: 0.1 # Courant-Friedrich-Levy condition for time integration. + +# Parameters related to the initial conditions +InitialConditions: + file_name: ./Gradients_stretched.hdf5 # The file to read + diff --git a/examples/Gradients/makeICs.py b/examples/Gradients/makeICs.py new file mode 100644 index 0000000000000000000000000000000000000000..38d035d2ad2dd3dd6daacfd6f58d824e9daf6742 --- /dev/null +++ b/examples/Gradients/makeICs.py @@ -0,0 +1,177 @@ +################################################################################ +# This file is part of SWIFT. +# Copyright (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/>. +# +################################################################################ + +import h5py +import random +import numpy as np +import sys + +# Generates a swift IC file with some density gradients, to check the gradient +# reconstruction + +# Parameters +periodic= 1 # 1 For periodic box +gamma = 5./3. # Gas adiabatic index +gridtype = "cartesian" +if len(sys.argv) > 1: + gridtype = sys.argv[1] + +# stretched cartesian box ###################################################### +if gridtype == "stretched": + fileName = "Gradients_stretched.hdf5" + factor = 8 + boxSize = [ 1.0 , 1.0/factor , 1.0/factor ] + L = 20 + nx1 = factor*L/2 + ny1 = L + nz1 = L + numfac = 2. + nx2 = int(nx1/numfac) + ny2 = int(ny1/numfac) + nz2 = int(nz1/numfac) + npart = nx1*ny1*nz1 + nx2*ny2*nz2 + vol = boxSize[0] * boxSize[1] * boxSize[2] + partVol1 = 0.5*vol/(nx1*ny1*nz1) + partVol2 = 0.5*vol/(nx2*ny2*nz2) + + coords = np.zeros((npart,3)) + h = np.zeros((npart,1)) + ids = np.zeros((npart,1), dtype='L') + idx = 0 + dcell = 0.5/nx1 + for i in range(nx1): + for j in range(ny1): + for k in range(nz1): + coords[idx,0] = (i+0.5)*dcell + coords[idx,1] = (j+0.5)*dcell + coords[idx,2] = (k+0.5)*dcell + h[idx] = 0.56/nx1 + ids[idx] = idx + idx += 1 + dcell = 0.5/nx2 + for i in range(nx2): + for j in range(ny2): + for k in range(nz2): + coords[idx,0] = 0.5+(i+0.5)*dcell + coords[idx,1] = (j+0.5)*dcell + coords[idx,2] = (k+0.5)*dcell + h[idx] = 0.56/nx2 + ids[idx] = idx + idx += 1 + +# cartesian box ################################################################ +if gridtype == "cartesian": + fileName = "Gradients_cartesian.hdf5" + boxSize = [ 1.0 , 1.0 , 1.0 ] + nx = 20 + npart = nx**3 + partVol = 1./npart + coords = np.zeros((npart,3)) + h = np.zeros((npart,1)) + ids = np.zeros((npart,1), dtype='L') + idx = 0 + dcell = 1./nx + for i in range(nx): + for j in range(nx): + for k in range(nx): + coords[idx,0] = (i+0.5)*dcell + coords[idx,1] = (j+0.5)*dcell + coords[idx,2] = (k+0.5)*dcell + h[idx] = 1.12/nx + ids[idx] = idx + idx += 1 + +# random box ################################################################### +if gridtype == "random": + fileName = "Gradients_random.hdf5" + boxSize = [ 1.0 , 1.0 , 1.0 ] + glass = h5py.File("../Glass/glass_50000.hdf5", "r") + coords = np.array(glass["/PartType0/Coordinates"]) + npart = len(coords) + partVol = 1./npart + h = np.zeros((npart,1)) + ids = np.zeros((npart,1), dtype='L') + for i in range(npart): + h[i] = 0.019 + ids[i] = i + +v = np.zeros((npart,3)) +m = np.zeros((npart,1)) +rho = np.zeros((npart,1)) +u = np.zeros((npart,1)) + +for i in range(npart): + rhox = coords[i,0] + if coords[i,0] < 0.75: + rhox = 0.75 + if coords[i,0] < 0.25: + rhox = 1.-coords[i,0] + rhoy = 1.+boxSize[1]-coords[i,1] + if coords[i,1] < 0.75*boxSize[1]: + rhoy = 1. + 0.25*boxSize[1] + if coords[i,1] < 0.25*boxSize[1]: + rhoy = 1.+coords[i,1] + rhoz = 1. + rho[i] = rhox + rhoy + rhoz + P = 1. + u[i] = P / ((gamma-1.)*rho[i]) + if gridtype == "stretched": + if coords[i,0] < 0.5: + m[i] = rho[i] * partVol1 + else: + m[i] = rho[i] * partVol2 + else: + m[i] = rho[i] * partVol + +#File +file = h5py.File(fileName, 'w') + +# Header +grp = file.create_group("/Header") +grp.attrs["BoxSize"] = boxSize +grp.attrs["NumPart_Total"] = [npart, 0, 0, 0, 0, 0] +grp.attrs["NumPart_Total_HighWord"] = [0, 0, 0, 0, 0, 0] +grp.attrs["NumPart_ThisFile"] = [npart, 0, 0, 0, 0, 0] +grp.attrs["Time"] = 0.0 +grp.attrs["NumFilesPerSnapshot"] = 1 +grp.attrs["MassTable"] = [0.0, 0.0, 0.0, 0.0, 0.0, 0.0] +grp.attrs["Flag_Entropy_ICs"] = [0, 0, 0, 0, 0, 0] + +#Runtime parameters +grp = file.create_group("/RuntimePars") +grp.attrs["PeriodicBoundariesOn"] = periodic + +#Particle group +grp = file.create_group("/PartType0") +ds = grp.create_dataset('Coordinates', (npart, 3), 'd') +ds[()] = coords +ds = grp.create_dataset('Velocities', (npart, 3), 'f') +ds[()] = v +ds = grp.create_dataset('Masses', (npart,1), 'f') +ds[()] = m +ds = grp.create_dataset('Density', (npart,1), 'd') +ds[()] = rho +ds = grp.create_dataset('SmoothingLength', (npart,1), 'f') +ds[()] = h +ds = grp.create_dataset('InternalEnergy', (npart,1), 'd') +ds[()] = u +ds = grp.create_dataset('ParticleIDs', (npart,1), 'L') +ds[()] = ids[:] + +file.close() diff --git a/examples/Gradients/plot.py b/examples/Gradients/plot.py new file mode 100644 index 0000000000000000000000000000000000000000..d6750ffc581437ebbf402ec44bcb1d14cb82a698 --- /dev/null +++ b/examples/Gradients/plot.py @@ -0,0 +1,50 @@ +################################################################################ +# This file is part of SWIFT. +# Copyright (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/>. +# +################################################################################ + +import scipy as sp +import pylab as pl +import numpy as np +import h5py +import sys + +# this file plots the gradients of the density in the x and y direction for +# the given input file and saves the result as gradiens_NAME.png + +inputfile = sys.argv[1] +outputfile = "gradients_{0}.png".format(sys.argv[2]) + +f = h5py.File(inputfile, "r") +rho = np.array(f["/PartType0/Density"]) +gradrho = np.array(f["/PartType0/GradDensity"]) +coords = np.array(f["/PartType0/Coordinates"]) + +fig, ax = pl.subplots(1,2, sharey=True) + +ax[0].plot(coords[:,0], rho, "r.", label="density") +ax[0].plot(coords[:,0], gradrho[:,0], "b.", label="grad density x") +ax[0].set_xlabel("x") +ax[0].legend(loc="best") + +ax[1].plot(coords[:,1], rho, "r.", label="density") +ax[1].plot(coords[:,1], gradrho[:,1], "b.", label="grad density y") +ax[1].set_xlabel("y") +ax[1].legend(loc="best") + +pl.tight_layout() +pl.savefig(outputfile) diff --git a/examples/Gradients/run.sh b/examples/Gradients/run.sh new file mode 100755 index 0000000000000000000000000000000000000000..cc1adc676427b257445f64a011ed8ebee87285ab --- /dev/null +++ b/examples/Gradients/run.sh @@ -0,0 +1,13 @@ +#! /bin/bash + +python makeICs.py stretched +../swift -s -t 2 gradientsStretched.yml +python plot.py gradients_stretched_001.hdf5 stretched + +python makeICs.py cartesian +../swift -s -t 2 gradientsCartesian.yml +python plot.py gradients_cartesian_001.hdf5 cartesian + +python makeICs.py random +../swift -s -t 2 gradientsRandom.yml +python plot.py gradients_random_001.hdf5 random diff --git a/src/adiabatic_index.h b/src/adiabatic_index.h index 78d1cc9d2deaf60c5d933b74a089c77446b44414..da0ce943e966c8061bd8732c0335f63766a8621c 100644 --- a/src/adiabatic_index.h +++ b/src/adiabatic_index.h @@ -1,6 +1,7 @@ /******************************************************************************* * This file is part of SWIFT. * Copyright (c) 2016 Matthieu Schaller (matthieu.schaller@durham.ac.uk). + * 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 @@ -42,18 +43,42 @@ #define hydro_gamma 1.66666666666666667f #define hydro_gamma_minus_one 0.66666666666666667f #define hydro_one_over_gamma_minus_one 1.5f +#define hydro_gamma_plus_one_over_two_gamma 0.8f +#define hydro_gamma_minus_one_over_two_gamma 0.2f +#define hydro_gamma_minus_one_over_gamma_plus_one 0.25f +#define hydro_two_over_gamma_plus_one 0.75f +#define hydro_two_over_gamma_minus_one 3.0f +#define hydro_gamma_minus_one_over_two 0.33333333333333333f +#define hydro_two_gamma_over_gamma_minus_one 5.0f +#define hydro_one_over_gamma 0.6f #elif defined(HYDRO_GAMMA_4_3) #define hydro_gamma 1.33333333333333333f #define hydro_gamma_minus_one 0.33333333333333333f #define hydro_one_over_gamma_minus_one 3.f +#define hydro_gamma_plus_one_over_two_gamma 0.875f +#define hydro_gamma_minus_one_over_two_gamma 0.125f +#define hydro_gamma_minus_one_over_gamma_plus_one 0.142857143f +#define hydro_two_over_gamma_plus_one 0.857142857f +#define hydro_two_over_gamma_minus_one 6.0f +#define hydro_gamma_minus_one_over_two 0.166666666666666666f +#define hydro_two_gamma_over_gamma_minus_one 8.0f +#define hydro_one_over_gamma 0.75f #elif defined(HYDRO_GAMMA_2_1) #define hydro_gamma 2.f #define hydro_gamma_minus_one 1.f #define hydro_one_over_gamma_minus_one 1.f +#define hydro_gamma_plus_one_over_two_gamma 0.75f +#define hydro_gamma_minus_one_over_two_gamma 0.25f +#define hydro_gamma_minus_one_over_gamma_plus_one 0.33333333333333333f +#define hydro_two_over_gamma_plus_one 0.66666666666666666f +#define hydro_two_over_gamma_minus_one 2.0f +#define hydro_gamma_minus_one_over_two 0.5f +#define hydro_two_gamma_over_gamma_minus_one 4.0f +#define hydro_one_over_gamma 0.5f #else @@ -149,4 +174,201 @@ __attribute__((always_inline)) INLINE static float pow_minus_gamma_minus_one( #endif } +/** + * @brief Returns one over the argument to the power given by the adiabatic + * index + * + * Computes \f$x^{-\gamma}\f$. + * + * @param x Argument + * @return One over the argument to the power given by the adiabatic index + */ +__attribute__((always_inline)) INLINE static float pow_minus_gamma(float x) { + +#if defined(HYDRO_GAMMA_5_3) + + const float cbrt_inv = 1.f / cbrtf(x); /* x^(-1/3) */ + const float cbrt_inv2 = cbrt_inv * cbrt_inv; /* x^(-2/3) */ + return cbrt_inv * cbrt_inv2 * cbrt_inv2; /* x^(-5/3) */ + +#elif defined(HYDRO_GAMMA_4_3) + + const float cbrt_inv = 1.f / cbrtf(x); /* x^(-1/3) */ + const float cbrt_inv2 = cbrt_inv * cbrt_inv; /* x^(-2/3) */ + return cbrt_inv2 * cbrt_inv2; /* x^(-4/3) */ + +#elif defined(HYDRO_GAMMA_2_1) + + const float inv = 1.f / x; + return inv * inv; + +#else + + error("The adiabatic index is not defined !"); + return 0.f; + +#endif +} + +/** + * @brief Return the argument to the power given by two divided by the adiabatic + * index minus one + * + * Computes \f$x^{\frac{2}{\gamma - 1}}\f$. + * + * @param x Argument + * @return Argument to the power two divided by the adiabatic index minus one + */ +__attribute__((always_inline)) INLINE static float pow_two_over_gamma_minus_one( + float x) { + +#if defined(HYDRO_GAMMA_5_3) + + return x * x * x; /* x^3 */ + +#elif defined(HYDRO_GAMMA_4_3) + + return x * x * x * x * x * x; /* x^6 */ + +#elif defined(HYDRO_GAMMA_2_1) + + return x * x; /* x^2 */ + +#else + + error("The adiabatic index is not defined !"); + return 0.f; + +#endif +} + +/** + * @brief Return the argument to the power given by two times the adiabatic + * index divided by the adiabatic index minus one + * + * Computes \f$x^{\frac{2\gamma}{\gamma - 1}}\f$. + * + * @param x Argument + * @return Argument to the power two times the adiabatic index divided by the + * adiabatic index minus one + */ +__attribute__((always_inline)) INLINE static float +pow_two_gamma_over_gamma_minus_one(float x) { + +#if defined(HYDRO_GAMMA_5_3) + + return x * x * x * x * x; /* x^5 */ + +#elif defined(HYDRO_GAMMA_4_3) + + return x * x * x * x * x * x * x * x; /* x^8 */ + +#elif defined(HYDRO_GAMMA_2_1) + + return x * x * x * x; /* x^4 */ + +#else + + error("The adiabatic index is not defined !"); + return 0.f; + +#endif +} + +/** + * @brief Return the argument to the power given by the adiabatic index minus + * one divided by two times the adiabatic index + * + * Computes \f$x^{\frac{\gamma - 1}{2\gamma}}\f$. + * + * @param x Argument + * @return Argument to the power the adiabatic index minus one divided by two + * times the adiabatic index + */ +__attribute__((always_inline)) INLINE static float +pow_gamma_minus_one_over_two_gamma(float x) { + +#if defined(HYDRO_GAMMA_5_3) + + return powf(x, 0.2f); /* x^0.2 */ + +#elif defined(HYDRO_GAMMA_4_3) + + return powf(x, 0.125f); /* x^0.125 */ + +#elif defined(HYDRO_GAMMA_2_1) + + return powf(x, 0.25f); /* x^0.25 */ + +#else + + error("The adiabatic index is not defined !"); + return 0.f; + +#endif +} + +/** + * @brief Return the inverse argument to the power given by the adiabatic index + * plus one divided by two times the adiabatic index + * + * Computes \f$x^{-\frac{\gamma + 1}{2\gamma}}\f$. + * + * @param x Argument + * @return Inverse argument to the power the adiabatic index plus one divided by + * two times the adiabatic index + */ +__attribute__((always_inline)) INLINE static float +pow_minus_gamma_plus_one_over_two_gamma(float x) { + +#if defined(HYDRO_GAMMA_5_3) + + return powf(x, -0.8f); /* x^-0.8 */ + +#elif defined(HYDRO_GAMMA_4_3) + + return powf(x, -0.875f); /* x^-0.875 */ + +#elif defined(HYDRO_GAMMA_2_1) + + return powf(x, -0.75f); /* x^-0.75 */ + +#else + + error("The adiabatic index is not defined !"); + return 0.f; + +#endif +} + +/** + * @brief Return the argument to the power one over the adiabatic index + * + * Computes \f$x^{\frac{1}{\gamma}}\f$. + * + * @param x Argument + * @return Argument to the power one over the adiabatic index + */ +__attribute__((always_inline)) INLINE static float pow_one_over_gamma(float x) { + +#if defined(HYDRO_GAMMA_5_3) + + return powf(x, 0.6f); /* x^(3/5) */ + +#elif defined(HYDRO_GAMMA_4_3) + + return powf(x, 0.75f); /* x^(3/4) */ + +#elif defined(HYDRO_GAMMA_2_1) + + return sqrtf(x); /* x^(1/2) */ + +#else + + error("The adiabatic index is not defined !"); + return 0.f; + +#endif +} + #endif /* SWIFT_ADIABATIC_INDEX_H */ diff --git a/src/cell.c b/src/cell.c index 7df55ce04ca739da2de6e6061048ad1fe3998a1e..63c7c37fa017c26d0032ebe7e95fd8edac3e5fe7 100644 --- a/src/cell.c +++ b/src/cell.c @@ -704,6 +704,9 @@ void cell_clean_links(struct cell *c, void *data) { c->density = NULL; c->nr_density = 0; + c->gradient = NULL; + c->nr_gradient = 0; + c->force = NULL; c->nr_force = 0; } diff --git a/src/cell.h b/src/cell.h index ef9881c664225488e47c6281e35c5388c1f1bc4c..43f542254ecb692b5c4d86beddd892a4e242cdc9 100644 --- a/src/cell.h +++ b/src/cell.h @@ -118,17 +118,17 @@ struct cell { int sortsize, gsortsize; /* The tasks computing this cell's density. */ - struct link *density, *force, *grav; - int nr_density, nr_force, nr_grav; + struct link *density, *gradient, *force, *grav; + int nr_density, nr_gradient, nr_force, nr_grav; /* The hierarchical tasks. */ - struct task *ghost, *init, *kick; + struct task *extra_ghost, *ghost, *init, *kick; /* Task receiving data. */ - struct task *recv_xv, *recv_rho, *recv_ti; + struct task *recv_xv, *recv_rho, *recv_gradient, *recv_ti; /* Task send data. */ - struct link *send_xv, *send_rho, *send_ti; + struct link *send_xv, *send_rho, *send_gradient, *send_ti; /* Tasks for gravity tree. */ struct task *grav_up, *grav_down; diff --git a/src/common_io.c b/src/common_io.c index b7495b1089ab0b46993f492deff6b955f7dc1ccf..37e2837fbaeee87916ddea9264439c824149479c 100644 --- a/src/common_io.c +++ b/src/common_io.c @@ -42,6 +42,7 @@ /* Local includes. */ #include "const.h" #include "error.h" +#include "hydro.h" #include "kernel_hydro.h" #include "part.h" #include "units.h" @@ -614,7 +615,7 @@ void duplicate_hydro_gparts(struct part* const parts, gparts[i + Ndm].v_full[1] = parts[i].v[1]; gparts[i + Ndm].v_full[2] = parts[i].v[2]; - gparts[i + Ndm].mass = parts[i].mass; + gparts[i + Ndm].mass = hydro_get_mass(&parts[i]); /* Link the particles */ gparts[i + Ndm].id_or_neg_offset = -i; diff --git a/src/const.h b/src/const.h index cbaa0054fe3bc9f829c59b19b71197264fd0c5af..64d07b3f3b883dd9f574ee12f4bd98bdb53675a1 100644 --- a/src/const.h +++ b/src/const.h @@ -65,6 +65,22 @@ //#define MINIMAL_SPH #define GADGET2_SPH //#define DEFAULT_SPH +//#define GIZMO_SPH + +/* Riemann solver to use (GIZMO_SPH only) */ +#define RIEMANN_SOLVER_EXACT +//#define RIEMANN_SOLVER_TRRS +//#define RIEMANN_SOLVER_HLLC + +/* Type of gradients to use (GIZMO_SPH only) */ +/* If no option is chosen, no gradients are used (first order scheme) */ +//#define GRADIENTS_SPH +#define GRADIENTS_GIZMO + +/* Types of slope limiter to use (GIZMO_SPH only) */ +/* Different slope limiters can be combined */ +#define SLOPE_LIMITER_PER_FACE +#define SLOPE_LIMITER_CELL_WIDE /* Self gravity stuff. */ #define const_gravity_multipole_order 2 diff --git a/src/debug.c b/src/debug.c index ea4934363fd0a87584b94a41f6ae1b63e578cfbe..15354b7d419544a8456543b79c38235eb3b68b2c 100644 --- a/src/debug.c +++ b/src/debug.c @@ -46,6 +46,8 @@ #include "./hydro/Gadget2/hydro_debug.h" #elif defined(DEFAULT_SPH) #include "./hydro/Default/hydro_debug.h" +#elif defined(GIZMO_SPH) +#include "./hydro/Gizmo/hydro_debug.h" #else #error "Invalid choice of SPH variant" #endif diff --git a/src/dimension.h b/src/dimension.h index 6395d4d04e50d40b733e7a74dafb7d0ab277d204..0fae2c5602b87622ff67f6f5feb325efc6422472 100644 --- a/src/dimension.h +++ b/src/dimension.h @@ -33,6 +33,8 @@ #include "inline.h" #include "vector.h" +#include <math.h> + /* First define some constants */ #if defined(HYDRO_DIMENSION_3D) @@ -114,6 +116,92 @@ __attribute__((always_inline)) INLINE static float pow_dimension_plus_one( #endif } +/** + * @brief Inverts the given dimension by dimension matrix (in place) + * + * @param A A 3x3 matrix of which we want to invert the top left dxd part + */ +__attribute__((always_inline)) INLINE static void +invert_dimension_by_dimension_matrix(float A[3][3]) { + +#if defined(HYDRO_DIMENSION_3D) + + float detA, Ainv[3][3]; + + detA = A[0][0] * A[1][1] * A[2][2] + A[0][1] * A[1][2] * A[2][0] + + A[0][2] * A[1][0] * A[2][1] - A[0][2] * A[1][1] * A[2][0] - + A[0][1] * A[1][0] * A[2][2] - A[0][0] * A[1][2] * A[2][1]; + + if (detA && !isnan(detA)) { + Ainv[0][0] = (A[1][1] * A[2][2] - A[1][2] * A[2][1]) / detA; + Ainv[0][1] = (A[0][2] * A[2][1] - A[0][1] * A[2][2]) / detA; + Ainv[0][2] = (A[0][1] * A[1][2] - A[0][2] * A[1][1]) / detA; + Ainv[1][0] = (A[1][2] * A[2][0] - A[1][0] * A[2][2]) / detA; + Ainv[1][1] = (A[0][0] * A[2][2] - A[0][2] * A[2][0]) / detA; + Ainv[1][2] = (A[0][2] * A[1][0] - A[0][0] * A[1][2]) / detA; + Ainv[2][0] = (A[1][0] * A[2][1] - A[1][1] * A[2][0]) / detA; + Ainv[2][1] = (A[0][1] * A[2][0] - A[0][0] * A[2][1]) / detA; + Ainv[2][2] = (A[0][0] * A[1][1] - A[0][1] * A[1][0]) / detA; + } else { + Ainv[0][0] = 0.0f; + Ainv[0][1] = 0.0f; + Ainv[0][2] = 0.0f; + Ainv[1][0] = 0.0f; + Ainv[1][1] = 0.0f; + Ainv[1][2] = 0.0f; + Ainv[2][0] = 0.0f; + Ainv[2][1] = 0.0f; + Ainv[2][2] = 0.0f; + } + + A[0][0] = Ainv[0][0]; + A[0][1] = Ainv[0][1]; + A[0][2] = Ainv[0][2]; + A[1][0] = Ainv[1][0]; + A[1][1] = Ainv[1][1]; + A[1][2] = Ainv[1][2]; + A[2][0] = Ainv[2][0]; + A[2][1] = Ainv[2][1]; + A[2][2] = Ainv[2][2]; + +#elif defined(HYDRO_DIMENSION_2D) + + float detA, Ainv[2][2]; + + detA = A[0][0] * A[1][1] - A[0][1] * A[1][0]; + + if (detA && !isnan(detA)) { + Ainv[0][0] = A[1][1] / detA; + Ainv[0][1] = -A[0][1] / detA; + Ainv[1][0] = -A[1][0] / detA; + Ainv[1][1] = A[0][0] / detA; + } else { + Ainv[0][0] = 0.0f; + Ainv[0][1] = 0.0f; + Ainv[1][0] = 0.0f; + Ainv[1][1] = 0.0f; + } + + A[0][0] = Ainv[0][0]; + A[0][1] = Ainv[0][1]; + A[1][0] = Ainv[1][0]; + A[1][1] = Ainv[1][1]; + +#elif defined(HYDRO_DIMENSION_1D) + + if (A[0][0] && !isnan(A[0][0])) { + A[0][0] = 1.0f / A[0][0]; + } else { + A[0][0] = 0.0f; + } + +#else + + error("The dimension is not defined !"); + +#endif +} + /* ------------------------------------------------------------------------- */ #ifdef WITH_VECTORIZATION diff --git a/src/drift.h b/src/drift.h index 880595dc59e3e5174ee5e888e595a9204ad383e2..bd1b35926740d49a67291ede4676f3387cd66748 100644 --- a/src/drift.h +++ b/src/drift.h @@ -65,8 +65,6 @@ __attribute__((always_inline)) INLINE static void drift_gpart( __attribute__((always_inline)) INLINE static void drift_part( struct part *restrict p, struct xpart *restrict xp, float dt, double timeBase, int ti_old, int ti_current) { - /* Useful quantity */ - const float h_inv = 1.0f / p->h; /* Drift... */ p->x[0] += xp->v_full[0] * dt; @@ -78,22 +76,8 @@ __attribute__((always_inline)) INLINE static void drift_part( p->v[1] += p->a_hydro[1] * dt; p->v[2] += p->a_hydro[2] * dt; - /* Predict smoothing length */ - const float w1 = p->force.h_dt * h_inv * dt; - if (fabsf(w1) < 0.2f) - p->h *= approx_expf(w1); /* 4th order expansion of exp(w) */ - else - p->h *= expf(w1); - - /* Predict density */ - const float w2 = -hydro_dimension * w1; - if (fabsf(w2) < 0.2f) - p->rho *= approx_expf(w2); /* 4th order expansion of exp(w) */ - else - p->rho *= expf(w2); - /* Predict the values of the extra fields */ - hydro_predict_extra(p, xp, ti_old, ti_current, timeBase); + hydro_predict_extra(p, xp, dt, ti_old, ti_current, timeBase); /* Compute offset since last cell construction */ xp->x_diff[0] -= xp->v_full[0] * dt; diff --git a/src/engine.c b/src/engine.c index dcd9283537d72ba3b4b0cf5130a70209f950b97e..7c62114730673902fa120d6be5d867b8c2a932d4 100644 --- a/src/engine.c +++ b/src/engine.c @@ -218,6 +218,12 @@ void engine_make_hydro_hierarchical_tasks(struct engine *e, struct cell *c, /* Generate the ghost task. */ c->ghost = scheduler_addtask(s, task_type_ghost, task_subtype_none, 0, 0, c, NULL, 0); + +#ifdef EXTRA_HYDRO_LOOP + /* Generate the extra ghost task. */ + c->extra_ghost = scheduler_addtask(s, task_type_extra_ghost, + task_subtype_none, 0, 0, c, NULL, 0); +#endif } } @@ -675,11 +681,12 @@ void engine_addtasks_grav(struct engine *e, struct cell *c, struct task *up, * @param cj Dummy cell containing the nodeID of the receiving node. * @param t_xv The send_xv #task, if it has already been created. * @param t_rho The send_rho #task, if it has already been created. + * @param t_gradient The send_gradient #task, if already created. * @param t_ti The send_ti #task, if required and has already been created. */ void engine_addtasks_send(struct engine *e, struct cell *ci, struct cell *cj, struct task *t_xv, struct task *t_rho, - struct task *t_ti) { + struct task *t_gradient, struct task *t_ti) { #ifdef WITH_MPI struct link *l = NULL; @@ -698,21 +705,42 @@ void engine_addtasks_send(struct engine *e, struct cell *ci, struct cell *cj, /* Create the tasks and their dependencies? */ if (t_xv == NULL) { t_xv = scheduler_addtask(s, task_type_send, task_subtype_none, - 3 * ci->tag, 0, ci, cj, 0); + 4 * ci->tag, 0, ci, cj, 0); t_rho = scheduler_addtask(s, task_type_send, task_subtype_none, - 3 * ci->tag + 1, 0, ci, cj, 0); + 4 * ci->tag + 1, 0, ci, cj, 0); if (!(e->policy & engine_policy_fixdt)) t_ti = scheduler_addtask(s, task_type_send, task_subtype_tend, - 3 * ci->tag + 2, 0, ci, cj, 0); + 4 * ci->tag + 2, 0, ci, cj, 0); +#ifdef EXTRA_HYDRO_LOOP + t_gradient = scheduler_addtask(s, task_type_send, task_subtype_none, + 4 * ci->tag + 3, 0, ci, cj, 0); +#endif + +#ifdef EXTRA_HYDRO_LOOP + + scheduler_addunlock(s, t_gradient, ci->super->kick); + + scheduler_addunlock(s, ci->super->extra_ghost, t_gradient); + + /* The send_rho task should unlock the super-cell's extra_ghost task. */ + scheduler_addunlock(s, t_rho, ci->super->extra_ghost); /* The send_rho task depends on the cell's ghost task. */ scheduler_addunlock(s, ci->super->ghost, t_rho); + /* The send_xv task should unlock the super-cell's ghost task. */ + scheduler_addunlock(s, t_xv, ci->super->ghost); + +#else /* The send_rho task should unlock the super-cell's kick task. */ scheduler_addunlock(s, t_rho, ci->super->kick); + /* The send_rho task depends on the cell's ghost task. */ + scheduler_addunlock(s, ci->super->ghost, t_rho); + /* The send_xv task should unlock the super-cell's ghost task. */ scheduler_addunlock(s, t_xv, ci->super->ghost); +#endif /* The super-cell's kick task should unlock the send_ti task. */ if (t_ti != NULL) scheduler_addunlock(s, ci->super->kick, t_ti); @@ -721,6 +749,9 @@ void engine_addtasks_send(struct engine *e, struct cell *ci, struct cell *cj, /* Add them to the local cell. */ engine_addlink(e, &ci->send_xv, t_xv); engine_addlink(e, &ci->send_rho, t_rho); +#ifdef EXTRA_HYDRO_LOOP + engine_addlink(e, &ci->send_gradient, t_gradient); +#endif if (t_ti != NULL) engine_addlink(e, &ci->send_ti, t_ti); } @@ -728,7 +759,8 @@ void engine_addtasks_send(struct engine *e, struct cell *ci, struct cell *cj, if (ci->split) for (int k = 0; k < 8; k++) if (ci->progeny[k] != NULL) - engine_addtasks_send(e, ci->progeny[k], cj, t_xv, t_rho, t_ti); + engine_addtasks_send(e, ci->progeny[k], cj, t_xv, t_rho, t_gradient, + t_ti); #else error("SWIFT was not compiled with MPI support."); @@ -742,11 +774,13 @@ void engine_addtasks_send(struct engine *e, struct cell *ci, struct cell *cj, * @param c The foreign #cell. * @param t_xv The recv_xv #task, if it has already been created. * @param t_rho The recv_rho #task, if it has already been created. + * @param t_gradient The recv_gradient #task, if it has already been created. * @param t_ti The recv_ti #task, if required and has already been created. */ void engine_addtasks_recv(struct engine *e, struct cell *c, struct task *t_xv, - struct task *t_rho, struct task *t_ti) { + struct task *t_rho, struct task *t_gradient, + struct task *t_ti) { #ifdef WITH_MPI struct scheduler *s = &e->sched; @@ -757,19 +791,39 @@ void engine_addtasks_recv(struct engine *e, struct cell *c, struct task *t_xv, if (t_xv == NULL && c->density != NULL) { /* Create the tasks. */ - t_xv = scheduler_addtask(s, task_type_recv, task_subtype_none, 3 * c->tag, + t_xv = scheduler_addtask(s, task_type_recv, task_subtype_none, 4 * c->tag, 0, c, NULL, 0); t_rho = scheduler_addtask(s, task_type_recv, task_subtype_none, - 3 * c->tag + 1, 0, c, NULL, 0); + 4 * c->tag + 1, 0, c, NULL, 0); if (!(e->policy & engine_policy_fixdt)) t_ti = scheduler_addtask(s, task_type_recv, task_subtype_tend, - 3 * c->tag + 2, 0, c, NULL, 0); + 4 * c->tag + 2, 0, c, NULL, 0); +#ifdef EXTRA_HYDRO_LOOP + t_gradient = scheduler_addtask(s, task_type_recv, task_subtype_none, + 4 * c->tag + 3, 0, c, NULL, 0); +#endif } c->recv_xv = t_xv; c->recv_rho = t_rho; + c->recv_gradient = t_gradient; c->recv_ti = t_ti; - /* Add dependencies. */ +/* Add dependencies. */ +#ifdef EXTRA_HYDRO_LOOP + for (struct link *l = c->density; l != NULL; l = l->next) { + scheduler_addunlock(s, t_xv, l->t); + scheduler_addunlock(s, l->t, t_rho); + } + for (struct link *l = c->gradient; l != NULL; l = l->next) { + scheduler_addunlock(s, t_rho, l->t); + scheduler_addunlock(s, l->t, t_gradient); + } + for (struct link *l = c->force; l != NULL; l = l->next) { + scheduler_addunlock(s, t_gradient, l->t); + if (t_ti != NULL) scheduler_addunlock(s, l->t, t_ti); + } + if (c->sorts != NULL) scheduler_addunlock(s, t_xv, c->sorts); +#else for (struct link *l = c->density; l != NULL; l = l->next) { scheduler_addunlock(s, t_xv, l->t); scheduler_addunlock(s, l->t, t_rho); @@ -779,12 +833,13 @@ void engine_addtasks_recv(struct engine *e, struct cell *c, struct task *t_xv, if (t_ti != NULL) scheduler_addunlock(s, l->t, t_ti); } if (c->sorts != NULL) scheduler_addunlock(s, t_xv, c->sorts); +#endif /* Recurse? */ if (c->split) for (int k = 0; k < 8; k++) if (c->progeny[k] != NULL) - engine_addtasks_recv(e, c->progeny[k], t_xv, t_rho, t_ti); + engine_addtasks_recv(e, c->progeny[k], t_xv, t_rho, t_gradient, t_ti); #else error("SWIFT was not compiled with MPI support."); @@ -1470,19 +1525,46 @@ void engine_link_gravity_tasks(struct engine *e) { } } +#ifdef EXTRA_HYDRO_LOOP + /** * @brief Creates the dependency network for the hydro tasks of a given cell. * * @param sched The #scheduler. * @param density The density task to link. + * @param gradient The gradient task to link. * @param force The force task to link. * @param c The cell. */ static inline void engine_make_hydro_loops_dependencies(struct scheduler *sched, struct task *density, + struct task *gradient, struct task *force, struct cell *c) { + /* init --> density loop --> ghost --> gradient loop --> extra_ghost */ + /* extra_ghost --> force loop --> kick */ + scheduler_addunlock(sched, c->super->init, density); + scheduler_addunlock(sched, density, c->super->ghost); + scheduler_addunlock(sched, c->super->ghost, gradient); + scheduler_addunlock(sched, gradient, c->super->extra_ghost); + scheduler_addunlock(sched, c->super->extra_ghost, force); + scheduler_addunlock(sched, force, c->super->kick); +} + +#else +/** + * @brief Creates the dependency network for the hydro tasks of a given cell. + * + * @param sched The #scheduler. + * @param density The density task to link. + * @param force The force task to link. + * @param c The cell. + */ +static inline void engine_make_hydro_loops_dependencies(struct scheduler *sched, + struct task *density, + struct task *force, + struct cell *c) { /* init --> density loop --> ghost --> force loop --> kick */ scheduler_addunlock(sched, c->super->init, density); scheduler_addunlock(sched, density, c->super->ghost); @@ -1490,6 +1572,7 @@ static inline void engine_make_hydro_loops_dependencies(struct scheduler *sched, scheduler_addunlock(sched, force, c->super->kick); } +#endif /** * @brief Duplicates the first hydro loop and construct all the * dependencies for the hydro part @@ -1517,6 +1600,24 @@ void engine_make_extra_hydroloop_tasks(struct engine *e) { /* Self-interaction? */ if (t->type == task_type_self && t->subtype == task_subtype_density) { +#ifdef EXTRA_HYDRO_LOOP + /* Start by constructing the task for the second and third hydro loop */ + struct task *t2 = scheduler_addtask( + sched, task_type_self, task_subtype_gradient, 0, 0, t->ci, NULL, 0); + struct task *t3 = scheduler_addtask( + sched, task_type_self, task_subtype_force, 0, 0, t->ci, NULL, 0); + + /* Add the link between the new loops and the cell */ + engine_addlink(e, &t->ci->gradient, t2); + atomic_inc(&t->ci->nr_gradient); + engine_addlink(e, &t->ci->force, t3); + atomic_inc(&t->ci->nr_force); + + /* Now, build all the dependencies for the hydro */ + engine_make_hydro_loops_dependencies(sched, t, t2, t3, t->ci); + +#else + /* Start by constructing the task for the second hydro loop */ struct task *t2 = scheduler_addtask( sched, task_type_self, task_subtype_force, 0, 0, t->ci, NULL, 0); @@ -1527,11 +1628,40 @@ void engine_make_extra_hydroloop_tasks(struct engine *e) { /* Now, build all the dependencies for the hydro */ engine_make_hydro_loops_dependencies(sched, t, t2, t->ci); +#endif } /* Otherwise, pair interaction? */ else if (t->type == task_type_pair && t->subtype == task_subtype_density) { +#ifdef EXTRA_HYDRO_LOOP + /* Start by constructing the task for the second and third hydro loop */ + struct task *t2 = scheduler_addtask( + sched, task_type_pair, task_subtype_gradient, 0, 0, t->ci, t->cj, 0); + struct task *t3 = scheduler_addtask( + sched, task_type_pair, task_subtype_force, 0, 0, t->ci, t->cj, 0); + + /* Add the link between the new loop and both cells */ + engine_addlink(e, &t->ci->gradient, t2); + atomic_inc(&t->ci->nr_gradient); + engine_addlink(e, &t->cj->gradient, t2); + atomic_inc(&t->cj->nr_gradient); + engine_addlink(e, &t->ci->force, t3); + atomic_inc(&t->ci->nr_force); + engine_addlink(e, &t->cj->force, t3); + atomic_inc(&t->cj->nr_force); + + /* Now, build all the dependencies for the hydro for the cells */ + /* that are local and are not descendant of the same super-cells */ + if (t->ci->nodeID == nodeID) { + engine_make_hydro_loops_dependencies(sched, t, t2, t3, t->ci); + } + if (t->cj->nodeID == nodeID && t->ci->super != t->cj->super) { + engine_make_hydro_loops_dependencies(sched, t, t2, t3, t->cj); + } + +#else + /* Start by constructing the task for the second hydro loop */ struct task *t2 = scheduler_addtask( sched, task_type_pair, task_subtype_force, 0, 0, t->ci, t->cj, 0); @@ -1550,12 +1680,38 @@ void engine_make_extra_hydroloop_tasks(struct engine *e) { if (t->cj->nodeID == nodeID && t->ci->super != t->cj->super) { engine_make_hydro_loops_dependencies(sched, t, t2, t->cj); } + +#endif + } /* Otherwise, sub-self interaction? */ else if (t->type == task_type_sub_self && t->subtype == task_subtype_density) { +#ifdef EXTRA_HYDRO_LOOP + + /* Start by constructing the task for the second and third hydro loop */ + struct task *t2 = + scheduler_addtask(sched, task_type_sub_self, task_subtype_gradient, + t->flags, 0, t->ci, t->cj, 0); + struct task *t3 = + scheduler_addtask(sched, task_type_sub_self, task_subtype_force, + t->flags, 0, t->ci, t->cj, 0); + + /* Add the link between the new loop and the cell */ + engine_addlink(e, &t->ci->gradient, t2); + atomic_inc(&t->ci->nr_gradient); + engine_addlink(e, &t->ci->force, t3); + atomic_inc(&t->ci->nr_force); + + /* Now, build all the dependencies for the hydro for the cells */ + /* that are local and are not descendant of the same super-cells */ + if (t->ci->nodeID == nodeID) { + engine_make_hydro_loops_dependencies(sched, t, t2, t3, t->ci); + } + +#else /* Start by constructing the task for the second hydro loop */ struct task *t2 = scheduler_addtask(sched, task_type_sub_self, task_subtype_force, @@ -1570,12 +1726,43 @@ void engine_make_extra_hydroloop_tasks(struct engine *e) { if (t->ci->nodeID == nodeID) { engine_make_hydro_loops_dependencies(sched, t, t2, t->ci); } +#endif } /* Otherwise, sub-pair interaction? */ else if (t->type == task_type_sub_pair && t->subtype == task_subtype_density) { +#ifdef EXTRA_HYDRO_LOOP + + /* Start by constructing the task for the second and third hydro loop */ + struct task *t2 = + scheduler_addtask(sched, task_type_sub_pair, task_subtype_gradient, + t->flags, 0, t->ci, t->cj, 0); + struct task *t3 = + scheduler_addtask(sched, task_type_sub_pair, task_subtype_force, + t->flags, 0, t->ci, t->cj, 0); + + /* Add the link between the new loop and both cells */ + engine_addlink(e, &t->ci->gradient, t2); + atomic_inc(&t->ci->nr_gradient); + engine_addlink(e, &t->cj->gradient, t2); + atomic_inc(&t->cj->nr_gradient); + engine_addlink(e, &t->ci->force, t3); + atomic_inc(&t->ci->nr_force); + engine_addlink(e, &t->cj->force, t3); + atomic_inc(&t->cj->nr_force); + + /* Now, build all the dependencies for the hydro for the cells */ + /* that are local and are not descendant of the same super-cells */ + if (t->ci->nodeID == nodeID) { + engine_make_hydro_loops_dependencies(sched, t, t2, t3, t->ci); + } + if (t->cj->nodeID == nodeID && t->ci->super != t->cj->super) { + engine_make_hydro_loops_dependencies(sched, t, t2, t3, t->cj); + } + +#else /* Start by constructing the task for the second hydro loop */ struct task *t2 = scheduler_addtask(sched, task_type_sub_pair, task_subtype_force, @@ -1595,8 +1782,8 @@ void engine_make_extra_hydroloop_tasks(struct engine *e) { if (t->cj->nodeID == nodeID && t->ci->super != t->cj->super) { engine_make_hydro_loops_dependencies(sched, t, t2, t->cj); } +#endif } - /* External gravity tasks should depend on init and unlock the kick */ else if (t->type == task_type_grav_external) { scheduler_addunlock(sched, t->ci->init, t); @@ -1672,7 +1859,11 @@ void engine_maketasks(struct engine *e) { is the number of cells (s->tot_cells) times the number of neighbours (27) times the number of interaction types (2, density and force). */ if (e->links != NULL) free(e->links); +#ifdef EXTRA_HYDRO_LOOP + e->size_links = s->tot_cells * 27 * 3; +#else e->size_links = s->tot_cells * 27 * 2; +#endif if ((e->links = malloc(sizeof(struct link) * e->size_links)) == NULL) error("Failed to allocate cell-task links."); e->nr_links = 0; @@ -1718,13 +1909,13 @@ void engine_maketasks(struct engine *e) { /* Loop through the proxy's incoming cells and add the recv tasks. */ for (int k = 0; k < p->nr_cells_in; k++) - engine_addtasks_recv(e, p->cells_in[k], NULL, NULL, NULL); + engine_addtasks_recv(e, p->cells_in[k], NULL, NULL, NULL, NULL); /* Loop through the proxy's outgoing cells and add the send tasks. */ for (int k = 0; k < p->nr_cells_out; k++) engine_addtasks_send(e, p->cells_out[k], p->cells_in[0], NULL, NULL, - NULL); + NULL, NULL); } } #endif @@ -2535,6 +2726,11 @@ void engine_step(struct engine *e) { submask |= 1 << task_subtype_density; submask |= 1 << task_subtype_force; + +#ifdef EXTRA_HYDRO_LOOP + mask |= 1 << task_type_extra_ghost; + submask |= 1 << task_subtype_gradient; +#endif } /* Add the tasks corresponding to self-gravity to the masks */ diff --git a/src/hydro.h b/src/hydro.h index b2ae9d57c399ecea818e9f3dc7db238e01487a9a..4a2b0bd029d494e2091b9081d22b7949cec5648c 100644 --- a/src/hydro.h +++ b/src/hydro.h @@ -38,6 +38,10 @@ #include "./hydro/Default/hydro.h" #include "./hydro/Default/hydro_iact.h" #define SPH_IMPLEMENTATION "Default version of SPH" +#elif defined(GIZMO_SPH) +#include "./hydro/Gizmo/hydro.h" +#include "./hydro/Gizmo/hydro_iact.h" +#define SPH_IMPLEMENTATION "GIZMO (Hopkins 2015)" #else #error "Invalid choice of SPH variant" #endif diff --git a/src/hydro/Default/hydro.h b/src/hydro/Default/hydro.h index 021599cd2daf61ff35e5f29e3f13b2ad61c8947a..f61bff55821809fe1f5da27c95d75afbecbc04cc 100644 --- a/src/hydro/Default/hydro.h +++ b/src/hydro/Default/hydro.h @@ -73,6 +73,28 @@ __attribute__((always_inline)) INLINE static float hydro_get_soundspeed( return p->force.soundspeed; } +/** + * @brief Returns the density of a particle + * + * @param p The particle of interest + */ +__attribute__((always_inline)) INLINE static float hydro_get_density( + const struct part *restrict p) { + + return p->rho; +} + +/** + * @brief Returns the mass of a particle + * + * @param p The particle of interest + */ +__attribute__((always_inline)) INLINE static float hydro_get_mass( + const struct part *restrict p) { + + return p->mass; +} + /** * @brief Modifies the thermal state of a particle to the imposed internal * energy @@ -288,16 +310,31 @@ __attribute__((always_inline)) INLINE static void hydro_reset_acceleration( * * @param p The particle * @param xp The extended data of the particle + * @param dt The drift time-step. * @param t0 The time at the start of the drift * @param t1 The time at the end of the drift * @param timeBase The minimal time-step size */ __attribute__((always_inline)) INLINE static void hydro_predict_extra( - struct part *restrict p, struct xpart *restrict xp, int t0, int t1, - double timeBase) { + struct part *restrict p, struct xpart *restrict xp, float dt, int t0, + int t1, double timeBase) { float u, w; - const float dt = (t1 - t0) * timeBase; + const float h_inv = 1.f / p->h; + + /* Predict smoothing length */ + const float w1 = p->force.h_dt * h_inv * dt; + if (fabsf(w1) < 0.2f) + p->h *= approx_expf(w1); /* 4th order expansion of exp(w) */ + else + p->h *= expf(w1); + + /* Predict density */ + const float w2 = -hydro_dimension * w1; + if (fabsf(w2) < 0.2f) + p->rho *= approx_expf(w2); /* 4th order expansion of exp(w) */ + else + p->rho *= expf(w2); /* Predict internal energy */ w = p->force.u_dt / p->u * dt; diff --git a/src/hydro/Default/hydro_part.h b/src/hydro/Default/hydro_part.h index a2f4453dc69ed06ca4f315b6be29844c177d0435..f42c3dc886ae1ab8f472ffdf5ff508f6735d1bb1 100644 --- a/src/hydro/Default/hydro_part.h +++ b/src/hydro/Default/hydro_part.h @@ -28,6 +28,8 @@ struct xpart { /* Velocity at the last full step. */ float v_full[3]; + float u_full; + /* Old density. */ float omega; diff --git a/src/hydro/Gadget2/hydro.h b/src/hydro/Gadget2/hydro.h index e9d626cb8c147c0cf4fa8d27f8bab31d2471beae..09a8f50d5b2e9abd43c3b9bd43a12fad8a347258 100644 --- a/src/hydro/Gadget2/hydro.h +++ b/src/hydro/Gadget2/hydro.h @@ -20,6 +20,7 @@ #define SWIFT_GADGET2_HYDRO_H #include "adiabatic_index.h" +#include "approx_math.h" #include "dimension.h" #include "equation_of_state.h" #include "hydro_properties.h" @@ -77,6 +78,28 @@ __attribute__((always_inline)) INLINE static float hydro_get_soundspeed( return p->force.soundspeed; } +/** + * @brief Returns the density of a particle + * + * @param p The particle of interest + */ +__attribute__((always_inline)) INLINE static float hydro_get_density( + const struct part *restrict p) { + + return p->rho; +} + +/** + * @brief Returns the mass of a particle + * + * @param p The particle of interest + */ +__attribute__((always_inline)) INLINE static float hydro_get_mass( + const struct part *restrict p) { + + return p->mass; +} + /** * @brief Modifies the thermal state of a particle to the imposed internal * energy @@ -285,13 +308,30 @@ __attribute__((always_inline)) INLINE static void hydro_reset_acceleration( * * @param p The particle * @param xp The extended data of the particle + * @param dt The drift time-step. * @param t0 The time at the start of the drift * @param t1 The time at the end of the drift * @param timeBase The minimal time-step size */ __attribute__((always_inline)) INLINE static void hydro_predict_extra( - struct part *restrict p, const struct xpart *restrict xp, int t0, int t1, - double timeBase) { + struct part *restrict p, const struct xpart *restrict xp, float dt, int t0, + int t1, double timeBase) { + + const float h_inv = 1.f / p->h; + + /* Predict smoothing length */ + const float w1 = p->force.h_dt * h_inv * dt; + if (fabsf(w1) < 0.2f) + p->h *= approx_expf(w1); /* 4th order expansion of exp(w) */ + else + p->h *= expf(w1); + + /* Predict density */ + const float w2 = -hydro_dimension * w1; + if (fabsf(w2) < 0.2f) + p->rho *= approx_expf(w2); /* 4th order expansion of exp(w) */ + else + p->rho *= expf(w2); /* Drift the pressure */ const float dt_entr = (t1 - (p->ti_begin + p->ti_end) / 2) * timeBase; diff --git a/src/hydro/Gizmo/hydro.h b/src/hydro/Gizmo/hydro.h index f69dc3f1798f014e895c4a63760805b1739cec94..e24a44529dc1907c9ceadeedfbfc9e49c308bcda 100644 --- a/src/hydro/Gizmo/hydro.h +++ b/src/hydro/Gizmo/hydro.h @@ -17,17 +17,25 @@ * ******************************************************************************/ +#include <float.h> +#include "adiabatic_index.h" +#include "approx_math.h" +#include "hydro_gradients.h" + /** * @brief Computes the hydro time-step of a given particle * - * @param p Pointer to the particle data - * @param xp Pointer to the extended particle data - * + * @param p Pointer to the particle data. + * @param xp Pointer to the extended particle data. + * @param hydro_properties Pointer to the hydro parameters. */ __attribute__((always_inline)) INLINE static float hydro_compute_timestep( - struct part* p, struct xpart* xp) { + const struct part* restrict p, const struct xpart* restrict xp, + const struct hydro_props* restrict hydro_properties) { - return const_cfl * p->h / fabs(p->timestepvars.vmax); + const float CFL_condition = hydro_properties->CFL_condition; + + return CFL_condition * p->h / fabsf(p->timestepvars.vmax); } /** @@ -36,39 +44,37 @@ __attribute__((always_inline)) INLINE static float hydro_compute_timestep( * This function is called only once just after the ICs have been * read in to do some conversions. * + * In this case, we copy the particle velocities into the corresponding + * primitive variable field. We do this because the particle velocities in GIZMO + * can be independent of the actual fluid velocity. The latter is stored as a + * primitive variable and integrated using the linear momentum, a conserved + * variable. + * * @param p The particle to act upon * @param xp The extended particle data to act upon */ __attribute__((always_inline)) INLINE static void hydro_first_init_part( - struct part* p, struct xpart* xp) {} + struct part* p, struct xpart* xp) { + + xp->v_full[0] = p->v[0]; + xp->v_full[1] = p->v[1]; + xp->v_full[2] = p->v[2]; + + p->primitives.v[0] = p->v[0]; + p->primitives.v[1] = p->v[1]; + p->primitives.v[2] = p->v[2]; +} /** * @brief Prepares a particle for the volume calculation. * + * Simply makes sure all necessary variables are initialized to zero. + * * @param p The particle to act upon */ __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; @@ -81,540 +87,417 @@ __attribute__((always_inline)) INLINE static void hydro_init_part( p->geometry.matrix_E[2][0] = 0.0f; p->geometry.matrix_E[2][1] = 0.0f; p->geometry.matrix_E[2][2] = 0.0f; - -#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. + * @brief Finishes the volume calculation. * * Multiplies the density and number of neighbours by the appropiate constants - * and add the self-contribution term. + * and adds the self-contribution term. Calculates the volume and uses it to + * update the primitive variables (based on the conserved variables). The latter + * should only be done for active particles. This is okay, since this method is + * only called for active particles. * - * @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. + * Multiplies the components of the matrix E with the appropriate constants and + * inverts it. Initializes the variables used during the gradient loop. This + * cannot be done in hydro_prepare_force, since that method is called for all + * particles, and not just the active ones. If we would initialize the + * variables there, gradients for passive particles would be zero, while we + * actually use the old gradients in the flux calculation between active and + * passive particles. * - * 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 + * @param p The particle to act upon. + * @param The current physical time. */ -__attribute__((always_inline)) INLINE static void hydro_prepare_gradient( - struct part* p, struct xpart* xp) { +__attribute__((always_inline)) INLINE static void hydro_end_density( + struct part* restrict p, float time) { /* 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; + /* Final operation on the density. */ + p->density.wcount += kernel_root; + p->density.wcount *= kernel_norm; -#ifndef THERMAL_ENERGY - GFLOAT momentum2; -#endif + p->density.wcount_dh *= ih * kernel_gamma * kernel_norm; -#if defined(SPH_GRADIENTS) && defined(SLOPE_LIMITER) - GFLOAT gradrho[3], gradv[3][3], gradP[3]; - GFLOAT gradtrue, gradmax, gradmin, alpha; -#endif + const float ihdim = pow_dimension(ih); /* 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; - } + const float volume = 1.f / (ihdim * (p->geometry.volume + kernel_root)); + p->geometry.volume = volume; - 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; - } + /* we multiply with the smoothing kernel normalization */ + p->geometry.matrix_E[0][0] = ihdim * p->geometry.matrix_E[0][0]; + p->geometry.matrix_E[0][1] = ihdim * p->geometry.matrix_E[0][1]; + p->geometry.matrix_E[0][2] = ihdim * p->geometry.matrix_E[0][2]; + p->geometry.matrix_E[1][0] = ihdim * p->geometry.matrix_E[1][0]; + p->geometry.matrix_E[1][1] = ihdim * p->geometry.matrix_E[1][1]; + p->geometry.matrix_E[1][2] = ihdim * p->geometry.matrix_E[1][2]; + p->geometry.matrix_E[2][0] = ihdim * p->geometry.matrix_E[2][0]; + p->geometry.matrix_E[2][1] = ihdim * p->geometry.matrix_E[2][1]; + p->geometry.matrix_E[2][2] = ihdim * p->geometry.matrix_E[2][2]; - 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; - } + invert_dimension_by_dimension_matrix(p->geometry.matrix_E); - 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 + hydro_gradients_init(p); /* compute primitive variables */ /* eqns (3)-(5) */ - m = p->conserved.mass; - if (m) { + const float m = p->conserved.mass; + if (m > 0.f) { + float momentum[3]; 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 + const float energy = p->conserved.energy; + p->primitives.P = hydro_gamma_minus_one * energy / volume; } } /** - * @brief Finishes the gradient calculation. + * @brief Prepare a particle for the gradient calculation. * - * @param p The particle to act upon + * The name of this method is confusing, as this method is really called after + * the density loop and before the gradient loop. + * + * We use it to set the physical timestep for the particle and to copy the + * actual velocities, which we need to boost our interfaces during the flux + * calculation. We also initialize the variables used for the time step + * calculation. + * + * @param p The particle to act upon. + * @param xp The extended particle data to act upon. + * @param ti_current Current integer time. + * @param timeBase Conversion factor between integer time and physical time. */ -__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; - } +__attribute__((always_inline)) INLINE static void hydro_prepare_force( + struct part* restrict p, struct xpart* restrict xp, int ti_current, + double timeBase) { - 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; - } + /* Set the physical time step */ + p->force.dt = (p->ti_end - p->ti_begin) * timeBase; - 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 + /* Initialize time step criterion variables */ + p->timestepvars.vmax = 0.0f; -#endif // SPH_GRADIENTS + /* Set the actual velocity of the particle */ + p->force.v_full[0] = xp->v_full[0]; + p->force.v_full[1] = xp->v_full[1]; + p->force.v_full[2] = xp->v_full[2]; } /** - * @brief Prepare a particle for the fluxes calculation. + * @brief Finishes the gradient calculation. * - * @param p The particle to act upon - * @param xp The extended particle data to act upon + * Just a wrapper around hydro_gradients_finalize, which can be an empty method, + * in which case no gradients are used. + * + * This method also initializes the force loop variables. + * + * @param p The particle to act upon. */ -__attribute__((always_inline)) INLINE static void hydro_prepare_fluxes( - struct part* p, struct xpart* xp) { +__attribute__((always_inline)) INLINE static void hydro_end_gradient( + struct part* p) { - /* initialize variables used for timestep calculation */ - p->timestepvars.vmax = 0.0f; + hydro_gradients_finalize(p); + + p->gravity.mflux[0] = 0.0f; + p->gravity.mflux[1] = 0.0f; + p->gravity.mflux[2] = 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 + * This is actually not necessary for GIZMO, since we just set the accelerations + * after the flux calculation. * - * @param p The particle to act upon + * @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 */ + /* Reset the acceleration. */ + p->a_hydro[0] = 0.0f; + p->a_hydro[1] = 0.0f; + p->a_hydro[2] = 0.0f; + + /* Reset the time derivatives. */ + p->force.h_dt = 0.0f; } /** - * @brief Finishes the fluxes calculation. + * @brief Converts the hydrodynamic variables from the initial condition file to + * conserved variables that can be used during the integration * - * Multiplies the forces and accelerationsby the appropiate constants + * Requires the volume to be known. * - * @param p The particle to act upon + * The initial condition file contains a mixture of primitive and conserved + * variables. Mass is a conserved variable, and we just copy the particle + * mass into the corresponding conserved quantity. We need the volume to + * also derive a density, which is then used to convert the internal energy + * to a pressure. However, we do not actually use these variables anymore. + * We do need to initialize the linear momentum, based on the mass and the + * velocity of the particle. + * + * @param p The particle to act upon. */ -__attribute__((always_inline)) INLINE static void hydro_end_fluxes( +__attribute__((always_inline)) INLINE static void hydro_convert_quantities( struct part* p) { - /* do nothing */ + const float volume = p->geometry.volume; + const float m = p->conserved.mass; + p->primitives.rho = m / volume; + + p->conserved.momentum[0] = m * p->primitives.v[0]; + p->conserved.momentum[1] = m * p->primitives.v[1]; + p->conserved.momentum[2] = m * p->primitives.v[2]; + + p->primitives.P = + hydro_gamma_minus_one * p->conserved.energy * p->primitives.rho; + + p->conserved.energy *= m; } /** - * @brief Converts hydro quantity of a particle + * @brief Extra operations to be done during the drift * - * Requires the volume to be known + * @param p Particle to act upon. + * @param xp The extended particle data to act upon. + * @param dt The drift time-step. + * @param t0 Integer start time of the drift interval. + * @param t1 Integer end time of the drift interval. + * @param timeBase Conversion factor between integer and physical time. + */ +__attribute__((always_inline)) INLINE static void hydro_predict_extra( + struct part* p, struct xpart* xp, float dt, int t0, int t1, + double timeBase) { + + const float h_inv = 1.0f / p->h; + + /* Predict smoothing length */ + const float w1 = p->force.h_dt * h_inv * dt; + if (fabsf(w1) < 0.2f) + p->h *= approx_expf(w1); /* 4th order expansion of exp(w) */ + else + p->h *= expf(w1); + + const float w2 = -hydro_dimension * w1; + if (fabsf(w2) < 0.2f) { + p->primitives.rho *= approx_expf(w2); + } else { + p->primitives.rho *= expf(w2); + } + + p->primitives.v[0] += (p->a_hydro[0] + p->gravity.old_a[0]) * dt; + p->primitives.v[1] += (p->a_hydro[1] + p->gravity.old_a[1]) * dt; + p->primitives.v[2] += (p->a_hydro[2] + p->gravity.old_a[2]) * dt; + const float u = p->conserved.energy + p->du_dt * dt; + p->primitives.P = + hydro_gamma_minus_one * u * p->primitives.rho / p->conserved.mass; +} + +/** + * @brief Set the particle acceleration after the flux loop * - * @param p The particle to act upon + * We use the new conserved variables to calculate the new velocity of the + * particle, and use that to derive the change of the velocity over the particle + * time step. + * + * If the particle time step is zero, we set the accelerations to zero. This + * should only happen at the start of the simulation. + * + * @param p Particle to act upon. */ -__attribute__((always_inline)) INLINE static void hydro_convert_quantities( +__attribute__((always_inline)) INLINE static void hydro_end_force( struct part* p) { - float volume; - GFLOAT m; - GFLOAT momentum[3]; -#ifndef THERMAL_ENERGY - GFLOAT momentum2; -#endif - volume = p->geometry.volume; + /* Add normalization to h_dt. */ + p->force.h_dt *= p->h * hydro_dimension_inv; - /* 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 + /* Set the hydro acceleration, based on the new momentum and mass */ + /* NOTE: the momentum and mass are only correct for active particles, since + only active particles have received flux contributions from all their + neighbours. Since this method is only called for active particles, + this is indeed the case. */ + if (p->force.dt) { + float mnew; + float vnew[3]; + + mnew = p->conserved.mass + p->conserved.flux.mass; + vnew[0] = (p->conserved.momentum[0] + p->conserved.flux.momentum[0]) / mnew; + vnew[1] = (p->conserved.momentum[1] + p->conserved.flux.momentum[1]) / mnew; + vnew[2] = (p->conserved.momentum[2] + p->conserved.flux.momentum[2]) / mnew; + + p->a_hydro[0] = (vnew[0] - p->force.v_full[0]) / p->force.dt; + p->a_hydro[1] = (vnew[1] - p->force.v_full[1]) / p->force.dt; + p->a_hydro[2] = (vnew[2] - p->force.v_full[2]) / p->force.dt; + + p->du_dt = p->conserved.flux.energy / p->force.dt; + } else { + p->a_hydro[0] = 0.0f; + p->a_hydro[1] = 0.0f; + p->a_hydro[2] = 0.0f; + + p->du_dt = 0.0f; + } } -// 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) {} +/** + * @brief Extra operations done during the kick + * + * Not used for GIZMO. + * + * @param p Particle to act upon. + * @param xp Extended particle data to act upon. + * @param dt Physical time step. + * @param half_dt Half the physical time step. + */ __attribute__((always_inline)) INLINE static void hydro_kick_extra( - struct part* p, struct xpart* xp, float dt, float half_dt) {} + struct part* p, struct xpart* xp, float dt, float half_dt) { + + float oldm, oldp[3], anew[3]; + + /* Retrieve the current value of the gravitational acceleration from the + gpart. We are only allowed to do this because this is the kick. We still + need to check whether gpart exists though.*/ + if (p->gpart) { + anew[0] = p->gpart->a_grav[0]; + anew[1] = p->gpart->a_grav[1]; + anew[2] = p->gpart->a_grav[2]; + + /* Copy the old mass and momentum before updating the conserved variables */ + oldm = p->conserved.mass; + oldp[0] = p->conserved.momentum[0]; + oldp[1] = p->conserved.momentum[1]; + oldp[2] = p->conserved.momentum[2]; + } + + /* Update conserved variables. */ + p->conserved.mass += p->conserved.flux.mass; + p->conserved.momentum[0] += p->conserved.flux.momentum[0]; + p->conserved.momentum[1] += p->conserved.flux.momentum[1]; + p->conserved.momentum[2] += p->conserved.flux.momentum[2]; + p->conserved.energy += p->conserved.flux.energy; + + /* Add gravity. We only do this if we have gravity activated. */ + if (p->gpart) { + p->conserved.momentum[0] += + half_dt * (oldm * p->gravity.old_a[0] + p->conserved.mass * anew[0]); + p->conserved.momentum[1] += + half_dt * (oldm * p->gravity.old_a[1] + p->conserved.mass * anew[1]); + p->conserved.momentum[2] += + half_dt * (oldm * p->gravity.old_a[2] + p->conserved.mass * anew[2]); + + float paold, panew; + paold = oldp[0] * p->gravity.old_a[0] + oldp[1] * p->gravity.old_a[1] + + oldp[2] * p->gravity.old_a[2]; + panew = p->conserved.momentum[0] * anew[0] + + p->conserved.momentum[1] * anew[1] + + p->conserved.momentum[2] * anew[2]; + p->conserved.energy += half_dt * (paold + panew); + + float fluxaold, fluxanew; + fluxaold = p->gravity.old_a[0] * p->gravity.old_mflux[0] + + p->gravity.old_a[1] * p->gravity.old_mflux[1] + + p->gravity.old_a[2] * p->gravity.old_mflux[2]; + fluxanew = anew[0] * p->gravity.mflux[0] + anew[1] * p->gravity.mflux[1] + + anew[2] * p->gravity.mflux[2]; + p->conserved.energy += half_dt * (fluxaold + fluxanew); + + /* Store gravitational acceleration and mass flux for next step */ + p->gravity.old_a[0] = anew[0]; + p->gravity.old_a[1] = anew[1]; + p->gravity.old_a[2] = anew[2]; + p->gravity.old_mflux[0] = p->gravity.mflux[0]; + p->gravity.old_mflux[1] = p->gravity.mflux[1]; + p->gravity.old_mflux[2] = p->gravity.mflux[2]; + } + + /* reset fluxes */ + /* we can only do this here, since we need to keep the fluxes for inactive + particles */ + p->conserved.flux.mass = 0.0f; + p->conserved.flux.momentum[0] = 0.0f; + p->conserved.flux.momentum[1] = 0.0f; + p->conserved.flux.momentum[2] = 0.0f; + p->conserved.flux.energy = 0.0f; +} + +/** + * @brief Returns the internal energy of a particle + * + * @param p The particle of interest. + * @param dt Time since the last kick. + */ __attribute__((always_inline)) INLINE static float hydro_get_internal_energy( - struct part* p) { - return 0.f; + const struct part* restrict p, float dt) { + + return p->primitives.P / hydro_gamma_minus_one / p->primitives.rho; +} + +/** + * @brief Returns the entropy of a particle + * + * @param p The particle of interest. + * @param dt Time since the last kick. + */ +__attribute__((always_inline)) INLINE static float hydro_get_entropy( + const struct part* restrict p, float dt) { + + return p->primitives.P / pow_gamma(p->primitives.rho); +} + +/** + * @brief Returns the sound speed of a particle + * + * @param p The particle of interest. + * @param dt Time since the last kick. + */ +__attribute__((always_inline)) INLINE static float hydro_get_soundspeed( + const struct part* restrict p, float dt) { + + return sqrtf(hydro_gamma * p->primitives.P / p->primitives.rho); +} + +/** + * @brief Returns the pressure of a particle + * + * @param p The particle of interest + * @param dt Time since the last kick + */ +__attribute__((always_inline)) INLINE static float hydro_get_pressure( + const struct part* restrict p, float dt) { + + return p->primitives.P; +} + +/** + * @brief Returns the mass of a particle + * + * @param p The particle of interest + */ +__attribute__((always_inline)) INLINE static float hydro_get_mass( + const struct part* restrict p) { + + return p->conserved.mass; +} + +/** + * @brief Returns the density of a particle + * + * @param p The particle of interest + */ +__attribute__((always_inline)) INLINE static float hydro_get_density( + const struct part* restrict p) { + + return p->primitives.rho; } diff --git a/src/hydro/Gizmo/hydro_debug.h b/src/hydro/Gizmo/hydro_debug.h index 365d85a2f651cf98b0713e8d82f11ae70fa9beaa..f4c071023a627b177fd06373856f25611fc9485d 100644 --- a/src/hydro/Gizmo/hydro_debug.h +++ b/src/hydro/Gizmo/hydro_debug.h @@ -18,10 +18,65 @@ ******************************************************************************/ __attribute__((always_inline)) INLINE static void hydro_debug_particle( - struct part* p, struct xpart* xp) { + const struct part* p, const struct xpart* xp) { printf( "x=[%.16e,%.16e,%.16e], " - "v=[%.3e,%.3e,%.3e], a=[%.3e,%.3e,%.3e], volume=%.3e\n", + "v=[%.3e,%.3e,%.3e], " + "a=[%.3e,%.3e,%.3e], " + "h=%.3e, " + "ti_begin=%d, " + "ti_end=%d, " + "primitives={" + "v=[%.3e,%.3e,%.3e], " + "rho=%.3e, " + "P=%.3e, " + "gradients={" + "rho=[%.3e,%.3e,%.3e], " + "v=[[%.3e,%.3e,%.3e],[%.3e,%.3e,%.3e],[%.3e,%.3e,%.3e]], " + "P=[%.3e,%.3e,%.3e]}, " + "limiter={" + "rho=[%.3e,%.3e], " + "v=[[%.3e,%.3e],[%.3e,%.3e],[%.3e,%.3e]], " + "P=[%.3e,%.3e], " + "maxr=%.3e}}, " + "conserved={" + "momentum=[%.3e,%.3e,%.3e], " + "mass=%.3e, " + "energy=%.3e}, " + "geometry={" + "volume=%.3e, " + "matrix_E=[[%.3e,%.3e,%.3e],[%.3e,%.3e,%.3e],[%.3e,%.3e,%.3e]]}, " + "timestepvars={" + "vmax=%.3e}, " + "density={" + "div_v=%.3e, " + "wcount_dh=%.3e, " + "curl_v=[%.3e,%.3e,%.3e], " + "wcount=%.3e}\n", p->x[0], p->x[1], p->x[2], p->v[0], p->v[1], p->v[2], p->a_hydro[0], - p->a_hydro[1], p->a_hydro[2], p->geometry.volume); + p->a_hydro[1], p->a_hydro[2], p->h, p->ti_begin, p->ti_end, + p->primitives.v[0], p->primitives.v[1], p->primitives.v[2], + p->primitives.rho, p->primitives.P, p->primitives.gradients.rho[0], + p->primitives.gradients.rho[1], p->primitives.gradients.rho[2], + p->primitives.gradients.v[0][0], p->primitives.gradients.v[0][1], + p->primitives.gradients.v[0][2], p->primitives.gradients.v[1][0], + p->primitives.gradients.v[1][1], p->primitives.gradients.v[1][2], + p->primitives.gradients.v[2][0], p->primitives.gradients.v[2][1], + p->primitives.gradients.v[2][2], p->primitives.gradients.P[0], + p->primitives.gradients.P[1], p->primitives.gradients.P[2], + p->primitives.limiter.rho[0], p->primitives.limiter.rho[1], + p->primitives.limiter.v[0][0], p->primitives.limiter.v[0][1], + p->primitives.limiter.v[1][0], p->primitives.limiter.v[1][1], + p->primitives.limiter.v[2][0], p->primitives.limiter.v[2][1], + p->primitives.limiter.P[0], p->primitives.limiter.P[1], + p->primitives.limiter.maxr, p->conserved.momentum[0], + p->conserved.momentum[1], p->conserved.momentum[2], p->conserved.mass, + p->conserved.energy, p->geometry.volume, p->geometry.matrix_E[0][0], + p->geometry.matrix_E[0][1], p->geometry.matrix_E[0][2], + p->geometry.matrix_E[1][0], p->geometry.matrix_E[1][1], + p->geometry.matrix_E[1][2], p->geometry.matrix_E[2][0], + p->geometry.matrix_E[2][1], p->geometry.matrix_E[2][2], + p->timestepvars.vmax, p->density.div_v, p->density.wcount_dh, + p->density.curl_v[0], p->density.curl_v[1], p->density.curl_v[2], + p->density.wcount); } diff --git a/src/hydro/Gizmo/hydro_gradients.h b/src/hydro/Gizmo/hydro_gradients.h new file mode 100644 index 0000000000000000000000000000000000000000..90448efc7adb8ccecaaa98c7388f89eaa8d16bcd --- /dev/null +++ b/src/hydro/Gizmo/hydro_gradients.h @@ -0,0 +1,208 @@ +/******************************************************************************* + * This file is part of SWIFT. + * Copyright (c) 2016 Bert Vandenbroucke (bert.vandenbroucke@gmail.com) + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published + * by the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this program. If not, see <http://www.gnu.org/licenses/>. + * + ******************************************************************************/ + +#ifndef SWIFT_HYDRO_GRADIENTS_H +#define SWIFT_HYDRO_GRADIENTS_H + +#include "hydro_slope_limiters.h" + +#if defined(GRADIENTS_SPH) + +#define HYDRO_GRADIENT_IMPLEMENTATION "SPH gradients (Price 2012)" +#include "hydro_gradients_sph.h" + +#elif defined(GRADIENTS_GIZMO) + +#define HYDRO_GRADIENT_IMPLEMENTATION "GIZMO gradients (Hopkins 2015)" +#include "hydro_gradients_gizmo.h" + +#else + +/* No gradients. Perfectly acceptable, but we have to provide empty functions */ +#define HYDRO_GRADIENT_IMPLEMENTATION "No gradients (first order scheme)" + +/** + * @brief Initialize gradient variables + * + * @param p Particle. + */ +__attribute__((always_inline)) INLINE static void hydro_gradients_init( + struct part* p) {} + +/** + * @brief Gradient calculations done during the neighbour loop + * + * @param r2 Squared distance between the two particles. + * @param dx Distance vector (pi->x - pj->x). + * @param hi Smoothing length of particle i. + * @param hj Smoothing length of particle j. + * @param pi Particle i. + * @param pj Particle j. + */ +__attribute__((always_inline)) INLINE static void hydro_gradients_collect( + float r2, float* dx, float hi, float hj, struct part* pi, struct part* pj) { +} + +/** + * @brief Gradient calculations done during the neighbour loop: non-symmetric + * version + * + * @param r2 Squared distance between the two particles. + * @param dx Distance vector (pi->x - pj->x). + * @param hi Smoothing length of particle i. + * @param hj Smoothing length of particle j. + * @param pi Particle i. + * @param pj Particle j. + */ +__attribute__((always_inline)) INLINE static void +hydro_gradients_nonsym_collect(float r2, float* dx, float hi, float hj, + struct part* pi, struct part* pj) {} + +/** + * @brief Finalize the gradient variables after all data have been collected + * + * @param p Particle. + */ +__attribute__((always_inline)) INLINE static void hydro_gradients_finalize( + struct part* p) {} + +#endif + +/** + * @brief Gradients reconstruction. Is the same for all gradient types (although + * gradients_none does nothing, since all gradients are zero -- are they?). + */ +__attribute__((always_inline)) INLINE static void hydro_gradients_predict( + struct part* pi, struct part* pj, float hi, float hj, float* dx, float r, + float* xij_i, float* Wi, float* Wj, float mindt) { + + float dWi[5], dWj[5]; + float xij_j[3]; + int k; + float xfac; + + /* 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]; + + hydro_slope_limit_face(Wi, Wj, dWi, dWj, xij_i, xij_j, r); + + /* 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] + + 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] + + hydro_gamma * Wj[4] * (pj->primitives.gradients.v[0][0] + + pj->primitives.gradients.v[1][1] + + pj->primitives.gradients.v[2][2])); + + 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 // SWIFT_HYDRO_GRADIENTS_H diff --git a/src/hydro/Gizmo/hydro_gradients_gizmo.h b/src/hydro/Gizmo/hydro_gradients_gizmo.h new file mode 100644 index 0000000000000000000000000000000000000000..aa6e4406b94e7a5cafcd0ca556162476003477de --- /dev/null +++ b/src/hydro/Gizmo/hydro_gradients_gizmo.h @@ -0,0 +1,341 @@ +/******************************************************************************* + * This file is part of SWIFT. + * Copyright (c) 2016 Bert Vandenbroucke (bert.vandenbroucke@gmail.com) + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published + * by the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this program. If not, see <http://www.gnu.org/licenses/>. + * + ******************************************************************************/ + +/** + * @brief Initialize gradient variables + * + * @param p Particle. + */ +__attribute__((always_inline)) INLINE static void hydro_gradients_init( + struct part *p) { + + p->primitives.gradients.rho[0] = 0.0f; + p->primitives.gradients.rho[1] = 0.0f; + p->primitives.gradients.rho[2] = 0.0f; + + p->primitives.gradients.v[0][0] = 0.0f; + p->primitives.gradients.v[0][1] = 0.0f; + p->primitives.gradients.v[0][2] = 0.0f; + + p->primitives.gradients.v[1][0] = 0.0f; + p->primitives.gradients.v[1][1] = 0.0f; + p->primitives.gradients.v[1][2] = 0.0f; + + p->primitives.gradients.v[2][0] = 0.0f; + p->primitives.gradients.v[2][1] = 0.0f; + p->primitives.gradients.v[2][2] = 0.0f; + + p->primitives.gradients.P[0] = 0.0f; + p->primitives.gradients.P[1] = 0.0f; + p->primitives.gradients.P[2] = 0.0f; + + hydro_slope_limit_cell_init(p); +} + +/** + * @brief Gradient calculations done during the neighbour loop + * + * @param r2 Squared distance between the two particles. + * @param dx Distance vector (pi->x - pj->x). + * @param hi Smoothing length of particle i. + * @param hj Smoothing length of particle j. + * @param pi Particle i. + * @param pj Particle j. + */ +__attribute__((always_inline)) INLINE static void hydro_gradients_collect( + float r2, float *dx, float hi, float hj, struct part *pi, struct part *pj) { + + 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]; + float 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]); + + hydro_slope_limit_cell_collect(pi, pj, r); + + /* 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]); + + hydro_slope_limit_cell_collect(pj, pi, r); +} + +/** + * @brief Gradient calculations done during the neighbour loop + * + * @param r2 Squared distance between the two particles. + * @param dx Distance vector (pi->x - pj->x). + * @param hi Smoothing length of particle i. + * @param hj Smoothing length of particle j. + * @param pi Particle i. + * @param pj Particle j. + */ +__attribute__((always_inline)) INLINE static void +hydro_gradients_nonsym_collect(float r2, float *dx, float hi, float hj, + struct part *pi, struct part *pj) { + + float r = sqrtf(r2); + float xi; + float hi_inv; + float wi, wi_dx; + int k, l; + float Bi[3][3]; + float 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]); + + hydro_slope_limit_cell_collect(pi, pj, r); +} + +/** + * @brief Finalize the gradient variables after all data have been collected + * + * @param p Particle. + */ +__attribute__((always_inline)) INLINE static void hydro_gradients_finalize( + struct part *p) { + + float h, ih; + + /* add kernel normalization to gradients */ + h = p->h; + ih = 1.0f / h; + const float ihdim = pow_dimension(ih); + + p->primitives.gradients.rho[0] *= ihdim; + p->primitives.gradients.rho[1] *= ihdim; + p->primitives.gradients.rho[2] *= ihdim; + + p->primitives.gradients.v[0][0] *= ihdim; + p->primitives.gradients.v[0][1] *= ihdim; + p->primitives.gradients.v[0][2] *= ihdim; + p->primitives.gradients.v[1][0] *= ihdim; + p->primitives.gradients.v[1][1] *= ihdim; + p->primitives.gradients.v[1][2] *= ihdim; + p->primitives.gradients.v[2][0] *= ihdim; + p->primitives.gradients.v[2][1] *= ihdim; + p->primitives.gradients.v[2][2] *= ihdim; + + p->primitives.gradients.P[0] *= ihdim; + p->primitives.gradients.P[1] *= ihdim; + p->primitives.gradients.P[2] *= ihdim; + + hydro_slope_limit_cell(p); +} diff --git a/src/hydro/Gizmo/hydro_gradients_sph.h b/src/hydro/Gizmo/hydro_gradients_sph.h new file mode 100644 index 0000000000000000000000000000000000000000..f635faecea549f7da280ade9b944021a5e4aeb4c --- /dev/null +++ b/src/hydro/Gizmo/hydro_gradients_sph.h @@ -0,0 +1,248 @@ +/******************************************************************************* + * This file is part of SWIFT. + * Copyright (c) 2016 Bert Vandenbroucke (bert.vandenbroucke@gmail.com) + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published + * by the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this program. If not, see <http://www.gnu.org/licenses/>. + * + ******************************************************************************/ + +/** + * @brief Initialize gradient variables + * + * @param p Particle. + */ +__attribute__((always_inline)) INLINE static void hydro_gradients_init( + struct part *p) { + + p->primitives.gradients.rho[0] = 0.0f; + p->primitives.gradients.rho[1] = 0.0f; + p->primitives.gradients.rho[2] = 0.0f; + + p->primitives.gradients.v[0][0] = 0.0f; + p->primitives.gradients.v[0][1] = 0.0f; + p->primitives.gradients.v[0][2] = 0.0f; + + p->primitives.gradients.v[1][0] = 0.0f; + p->primitives.gradients.v[1][1] = 0.0f; + p->primitives.gradients.v[1][2] = 0.0f; + p->primitives.gradients.v[2][0] = 0.0f; + p->primitives.gradients.v[2][1] = 0.0f; + p->primitives.gradients.v[2][2] = 0.0f; + + p->primitives.gradients.P[0] = 0.0f; + p->primitives.gradients.P[1] = 0.0f; + p->primitives.gradients.P[2] = 0.0f; + + hydro_slope_limit_cell_init(p); +} + +/** + * @brief Gradient calculations done during the neighbour loop + * + * @param r2 Squared distance between the two particles. + * @param dx Distance vector (pi->x - pj->x). + * @param hi Smoothing length of particle i. + * @param hj Smoothing length of particle j. + * @param pi Particle i. + * @param pj Particle j. + */ +__attribute__((always_inline)) INLINE static void hydro_gradients_collect( + float r2, float *dx, float hi, float hj, struct part *pi, struct part *pj) { + + float wi, wi_dx, xi, hi_inv; + float wj, wj_dx, xj, hj_inv; + float r = sqrtf(r2); + + hi_inv = 1.0f / hi; + xi = r * hi_inv; + kernel_deval(xi, &wi, &wi_dx); + + /* very basic gradient estimate */ + pi->primitives.gradients.rho[0] -= + wi_dx * dx[0] * (pi->primitives.rho - pj->primitives.rho) / r; + 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; + + hydro_slope_limit_cell_collect(pi, pj, r); + + hj_inv = 1.0f / hj; + xj = r * hj_inv; + kernel_deval(xj, &wj, &wj_dx); + + /* signs are the same as before, since we swap i and j twice */ + pj->primitives.gradients.rho[0] -= + wj_dx * dx[0] * (pi->primitives.rho - pj->primitives.rho) / r; + 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; + + hydro_slope_limit_cell_collect(pj, pi, r); +} + +/** + * @brief Gradient calculations done during the neighbour loop: non-symmetric + * version + * + * @param r2 Squared distance between the two particles. + * @param dx Distance vector (pi->x - pj->x). + * @param hi Smoothing length of particle i. + * @param hj Smoothing length of particle j. + * @param pi Particle i. + * @param pj Particle j. + */ +__attribute__((always_inline)) INLINE static void +hydro_gradients_nonsym_collect(float r2, float *dx, float hi, float hj, + struct part *pi, struct part *pj) { + + float wi, wi_dx, xi, hi_inv; + float r = sqrtf(r2); + + hi_inv = 1.0f / hi; + xi = r * hi_inv; + kernel_deval(xi, &wi, &wi_dx); + + /* very basic gradient estimate */ + pi->primitives.gradients.rho[0] -= + wi_dx * dx[0] * (pi->primitives.rho - pj->primitives.rho) / r; + 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; + + hydro_slope_limit_cell_collect(pi, pj, r); +} + +/** + * @brief Finalize the gradient variables after all data have been collected + * + * @param p Particle. + */ +__attribute__((always_inline)) INLINE static void hydro_gradients_finalize( + struct part *p) { + + const float h = p->h; + const float ih = 1.0f / h; + const float ihdimp1 = pow_dimension_plus_one(ih); + + float volume = p->geometry.volume; + + /* finalize gradients by multiplying with volume */ + p->primitives.gradients.rho[0] *= ihdimp1 * volume; + p->primitives.gradients.rho[1] *= ihdimp1 * volume; + p->primitives.gradients.rho[2] *= ihdimp1 * volume; + + p->primitives.gradients.v[0][0] *= ihdimp1 * volume; + p->primitives.gradients.v[0][1] *= ihdimp1 * volume; + p->primitives.gradients.v[0][2] *= ihdimp1 * volume; + + p->primitives.gradients.v[1][0] *= ihdimp1 * volume; + p->primitives.gradients.v[1][1] *= ihdimp1 * volume; + p->primitives.gradients.v[1][2] *= ihdimp1 * volume; + + p->primitives.gradients.v[2][0] *= ihdimp1 * volume; + p->primitives.gradients.v[2][1] *= ihdimp1 * volume; + p->primitives.gradients.v[2][2] *= ihdimp1 * volume; + + p->primitives.gradients.P[0] *= ihdimp1 * volume; + p->primitives.gradients.P[1] *= ihdimp1 * volume; + p->primitives.gradients.P[2] *= ihdimp1 * volume; + + hydro_slope_limit_cell(p); +} diff --git a/src/hydro/Gizmo/hydro_iact.h b/src/hydro/Gizmo/hydro_iact.h index 30a8d6cbebc851b44a5ee2339950aec9e15057c0..79973364617bb04855115bff9bfbf3808f46d04f 100644 --- a/src/hydro/Gizmo/hydro_iact.h +++ b/src/hydro/Gizmo/hydro_iact.h @@ -19,14 +19,28 @@ * ******************************************************************************/ +#include "adiabatic_index.h" +#include "hydro_gradients.h" #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( +/** + * @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 Squared distance between particle i and particle j. + * @param dx Distance vector between the particles (dx = pi->x - pj->x). + * @param hi Smoothing length of particle i. + * @param hj Smoothing length of particle j. + * @param pi Particle i. + * @param pj Particle j. + */ +__attribute__((always_inline)) INLINE static void runner_iact_density( float r2, float *dx, float hi, float hj, struct part *pi, struct part *pj) { float r = sqrtf(r2); @@ -48,71 +62,6 @@ __attribute__((always_inline)) INLINE static void runner_iact_hydro_loop1( 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; @@ -125,78 +74,28 @@ __attribute__((always_inline)) INLINE static void runner_iact_hydro_loop1( 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) { +/** + * @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 Squared distance between particle i and particle j. + * @param dx Distance vector between the particles (dx = pi->x - pj->x). + * @param hi Smoothing length of particle i. + * @param hj Smoothing length of particle j. + * @param pi Particle i. + * @param pj Particle j. + */ +__attribute__((always_inline)) INLINE static void runner_iact_nonsym_density( + float r2, float *dx, float hi, float hj, struct part *pi, struct part *pj) { float r; float xi; @@ -218,397 +117,80 @@ runner_iact_nonsym_hydro_loop1(float r2, float *dx, float hi, float hj, 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( +/** + * @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 Squared distance between particle i and particle j. + * @param dx Distance vector between the particles (dx = pi->x - pj->x). + * @param hi Smoothing length of particle i. + * @param hj Smoothing length of particle j. + * @param pi Particle i. + * @param pj Particle j. + */ +__attribute__((always_inline)) INLINE static void runner_iact_gradient( 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 + hydro_gradients_collect(r2, dx, hi, hj, pi, pj); } -__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); +/** + * @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 Squared distance between particle i and particle j. + * @param dx Distance vector between the particles (dx = pi->x - pj->x). + * @param hi Smoothing length of particle i. + * @param hj Smoothing length of particle j. + * @param pi Particle i. + * @param pj Particle j. + */ +__attribute__((always_inline)) INLINE static void runner_iact_nonsym_gradient( + float r2, float *dx, float hi, float hj, struct part *pi, struct part *pj) { -#endif + 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 and particle j is + * active), 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 Squared distance between particle i and particle j. + * @param dx Distance vector between the particles (dx = pi->x - pj->x). + * @param hi Smoothing length of particle i. + * @param hj Smoothing length of particle j. + * @param pi Particle i. + * @param pj Particle j. + */ __attribute__((always_inline)) INLINE static void 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 hi_inv, hi_inv_dim; + float hj_inv, hj_inv_dim; float wi, wj, wi_dx, wj_dx; int k, l; float A[3]; @@ -619,13 +201,7 @@ __attribute__((always_inline)) INLINE static void runner_iact_fluxes_common( 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 Wi[5], Wj[5]; float dti, dtj, mindt; float n_unit[3]; @@ -635,8 +211,8 @@ __attribute__((always_inline)) INLINE static void runner_iact_fluxes_common( 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[k] = pi->force.v_full[k]; /* particle velocities */ + vj[k] = pj->force.v_full[k]; } Vi = pi->geometry.volume; Vj = pj->geometry.volume; @@ -650,16 +226,17 @@ __attribute__((always_inline)) INLINE static void runner_iact_fluxes_common( 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); - // } + dti = pi->force.dt; + dtj = pj->force.dt; /* calculate the maximal signal velocity */ - vmax = sqrtf(const_hydro_gamma * Wi[4] / Wi[0]) + - sqrtf(const_hydro_gamma * Wj[4] / Wj[0]); + if (Wi[0] && Wj[0]) { + vmax = + sqrtf(hydro_gamma * Wi[4] / Wi[0]) + sqrtf(hydro_gamma * Wj[4] / Wj[0]); + } else { + vmax = 0.0f; + } dvdotdx = (Wi[1] - Wj[1]) * dx[0] + (Wi[2] - Wj[2]) * dx[1] + (Wi[3] - Wj[3]) * dx[2]; if (dvdotdx > 0.) { @@ -673,28 +250,44 @@ __attribute__((always_inline)) INLINE static void runner_iact_fluxes_common( /* The flux will be exchanged using the smallest time step of the two * particles */ mindt = fminf(dti, dtj); + dti = mindt; + dtj = mindt; /* Compute kernel of pi. */ hi_inv = 1.0 / hi; - hi_inv2 = hi_inv * hi_inv; + hi_inv_dim = pow_dimension(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; + hj_inv_dim = pow_dimension(hj_inv); 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 */ + 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]; + float ri = 1.0f / r; + float hidp1 = pow_dimension_plus_one(hi_inv); + float hjdp1 = pow_dimension_plus_one(hj_inv); + float wi_dr = hidp1 * wi_dx; + float wj_dr = hjdp1 * wj_dx; + dvdr *= ri; + pi->force.h_dt -= pj->conserved.mass * dvdr / pj->primitives.rho * wi_dr; + if (mode == 1) { + pj->force.h_dt -= pi->conserved.mass * dvdr / pi->primitives.rho * wj_dr; + } + /* 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 - + hi_inv_dim - Vj * (Bj[k][0] * dx[0] + Bj[k][1] * dx[1] + Bj[k][2] * dx[2]) * wj * - hj_inv * hj_inv2; + hj_inv_dim; Anorm += A[k] * A[k]; } @@ -708,13 +301,6 @@ __attribute__((always_inline)) INLINE static void runner_iact_fluxes_common( 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) */ @@ -746,192 +332,7 @@ __attribute__((always_inline)) INLINE static void runner_iact_fluxes_common( 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 ... */ + hydro_gradients_predict(pi, pj, hi, hj, dx, r, xij_i, Wi, Wj, mindt); /* we don't need to rotate, we can use the unit vector in the Riemann problem * itself (see GIZMO) */ @@ -940,7 +341,9 @@ __attribute__((always_inline)) INLINE static void runner_iact_fluxes_common( 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); +#ifdef USE_GRADIENTS printf("dWL: %g %g %g %g %g\n", dWi[0], dWi[1], dWi[2], dWi[3], dWi[4]); +#endif 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], @@ -954,7 +357,9 @@ __attribute__((always_inline)) INLINE static void runner_iact_fluxes_common( 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); +#ifdef USE_GRADIENTS printf("dWR: %g %g %g %g %g\n", dWj[0], dWj[1], dWj[2], dWj[3], dWj[4]); +#endif 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], @@ -969,61 +374,133 @@ __attribute__((always_inline)) INLINE static void runner_iact_fluxes_common( error("Negative density or pressure!\n"); } - GFLOAT totflux[5]; + float totflux[5]; riemann_solve_for_flux(Wi, Wj, n_unit, vij, totflux); + /* Store mass flux */ + float mflux = dti * Anorm * totflux[0]; + pi->gravity.mflux[0] += mflux * dx[0]; + pi->gravity.mflux[1] += mflux * dx[1]; + pi->gravity.mflux[2] += mflux * dx[2]; + /* 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 + pi->conserved.flux.mass -= dti * Anorm * totflux[0]; + pi->conserved.flux.momentum[0] -= dti * Anorm * totflux[1]; + pi->conserved.flux.momentum[1] -= dti * Anorm * totflux[2]; + pi->conserved.flux.momentum[2] -= dti * Anorm * totflux[3]; + pi->conserved.flux.energy -= dti * Anorm * totflux[4]; + + float ekin = 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 += dti * Anorm * totflux[1] * pi->primitives.v[0]; + pi->conserved.flux.energy += dti * Anorm * totflux[2] * pi->primitives.v[1]; + pi->conserved.flux.energy += dti * Anorm * totflux[3] * pi->primitives.v[2]; + pi->conserved.flux.energy -= dti * Anorm * totflux[0] * ekin; + + /* here is how it works: + Mode will only be 1 if both particles are ACTIVE and they are in the same + cell. In this case, this method IS the flux calculation for particle j, and + we HAVE TO UPDATE it. + Mode 0 can mean several things: it can mean that particle j is INACTIVE, in + which case we NEED TO UPDATE it, since otherwise the flux is lost from the + system and the conserved variable is not conserved. + It can also mean that particle j sits in another cell and is ACTIVE. In + this case, the flux exchange for particle j is done TWICE and we SHOULD NOT + UPDATE particle j. + ==> we update particle j if (MODE IS 1) OR (j IS INACTIVE) + */ + if (mode == 1 || pj->ti_end > pi->ti_end) { + /* Store mass flux */ + mflux = dtj * Anorm * totflux[0]; + pj->gravity.mflux[0] -= mflux * dx[0]; + pj->gravity.mflux[1] -= mflux * dx[1]; + pj->gravity.mflux[2] -= mflux * dx[2]; + + pj->conserved.flux.mass += dtj * Anorm * totflux[0]; + pj->conserved.flux.momentum[0] += dtj * Anorm * totflux[1]; + pj->conserved.flux.momentum[1] += dtj * Anorm * totflux[2]; + pj->conserved.flux.momentum[2] += dtj * Anorm * totflux[3]; + pj->conserved.flux.energy += dtj * Anorm * totflux[4]; + + ekin = 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 -= dtj * Anorm * totflux[1] * pj->primitives.v[0]; + pj->conserved.flux.energy -= dtj * Anorm * totflux[2] * pj->primitives.v[1]; + pj->conserved.flux.energy -= dtj * Anorm * totflux[3] * pj->primitives.v[2]; + pj->conserved.flux.energy += dtj * Anorm * totflux[0] * ekin; } } -/* this corresponds to task_subtype_fluxes */ -__attribute__((always_inline)) INLINE static void runner_iact_hydro_loop3( +/** + * @brief Flux calculation between particle i and particle j + * + * This method calls runner_iact_fluxes_common with mode 1. + * + * @param r2 Squared distance between particle i and particle j. + * @param dx Distance vector between the particles (dx = pi->x - pj->x). + * @param hi Smoothing length of particle i. + * @param hj Smoothing length of particle j. + * @param pi Particle i. + * @param pj Particle j. + */ +__attribute__((always_inline)) INLINE static void runner_iact_force( 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) { +/** + * @brief Flux calculation between particle i and particle j: non-symmetric + * version + * + * This method calls runner_iact_fluxes_common with mode 0. + * + * @param r2 Squared distance between particle i and particle j. + * @param dx Distance vector between the particles (dx = pi->x - pj->x). + * @param hi Smoothing length of particle i. + * @param hj Smoothing length of particle j. + * @param pi Particle i. + * @param pj Particle j. + */ +__attribute__((always_inline)) INLINE static void runner_iact_nonsym_force( + 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); } + +//// EMPTY VECTORIZED VERSIONS (gradients methods are missing...) + +__attribute__((always_inline)) INLINE static void runner_iact_vec_density( + float *R2, float *Dx, float *Hi, float *Hj, struct part **pi, + struct part **pj) { + error( + "Vectorised versions of the Gizmo interaction functions do not exist " + "yet!"); +} + +__attribute__((always_inline)) INLINE static void +runner_iact_nonsym_vec_density(float *R2, float *Dx, float *Hi, float *Hj, + struct part **pi, struct part **pj) { + error( + "Vectorised versions of the Gizmo interaction functions do not exist " + "yet!"); +} + +__attribute__((always_inline)) INLINE static void runner_iact_vec_force( + float *R2, float *Dx, float *Hi, float *Hj, struct part **pi, + struct part **pj) { + error( + "Vectorised versions of the Gizmo interaction functions do not exist " + "yet!"); +} + +__attribute__((always_inline)) INLINE static void runner_iact_nonsym_vec_force( + float *R2, float *Dx, float *Hi, float *Hj, struct part **pi, + struct part **pj) { + error( + "Vectorised versions of the Gizmo interaction functions do not exist " + "yet!"); +} diff --git a/src/hydro/Gizmo/hydro_io.h b/src/hydro/Gizmo/hydro_io.h index 3c51653d994bd9f01864bcc24c6886eba25d1d05..e5f221ae4345dc519a50d332131ecf296f318338 100644 --- a/src/hydro/Gizmo/hydro_io.h +++ b/src/hydro/Gizmo/hydro_io.h @@ -1,6 +1,6 @@ /******************************************************************************* * This file is part of SWIFT. - * Coypright (c) 2016 Matthieu Schaller (matthieu.schaller@durham.ac.uk) + * Coypright (c) 2016 Bert Vandenbroucke (bert.vandenbroucke@gmail.com) * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU Lesser General Public License as published @@ -17,77 +17,124 @@ * ******************************************************************************/ +#include "adiabatic_index.h" +#include "hydro_gradients.h" +#include "hydro_slope_limiters.h" +#include "io_properties.h" +#include "riemann.h" + /** - * @brief Reads the different particles to the HDF5 file + * @brief Specifies which particle fields to read from a dataset * - * @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 + * @param parts The particle array. + * @param list The list of i/o properties to read. + * @param num_fields The number of i/o fields to read. + */ +void hydro_read_particles(struct part* parts, struct io_props* list, + int* num_fields) { + + *num_fields = 8; + + /* List what we want to read */ + list[0] = io_make_input_field("Coordinates", DOUBLE, 3, COMPULSORY, + UNIT_CONV_LENGTH, parts, x); + list[1] = io_make_input_field("Velocities", FLOAT, 3, COMPULSORY, + UNIT_CONV_SPEED, parts, v); + list[2] = io_make_input_field("Masses", FLOAT, 1, COMPULSORY, UNIT_CONV_MASS, + parts, conserved.mass); + list[3] = io_make_input_field("SmoothingLength", FLOAT, 1, COMPULSORY, + UNIT_CONV_LENGTH, parts, h); + list[4] = io_make_input_field("InternalEnergy", FLOAT, 1, COMPULSORY, + UNIT_CONV_ENERGY_PER_UNIT_MASS, parts, + conserved.energy); + list[5] = io_make_input_field("ParticleIDs", ULONGLONG, 1, COMPULSORY, + UNIT_CONV_NO_UNITS, parts, id); + list[6] = io_make_input_field("Accelerations", FLOAT, 3, OPTIONAL, + UNIT_CONV_ACCELERATION, parts, a_hydro); + list[7] = io_make_input_field("Density", FLOAT, 1, OPTIONAL, + UNIT_CONV_DENSITY, parts, primitives.rho); +} + +/** + * @brief Get the internal energy of a particle * + * @param e #engine. + * @param p Particle. + * @return Internal energy of the particle */ -__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); +float convert_u(struct engine* e, struct part* p) { + return p->primitives.P / hydro_gamma_minus_one / p->primitives.rho; } /** - * @brief Writes the different particles to the HDF5 file + * @brief Get the entropic function of a particle * - * @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 + * @param e #engine. + * @param p Particle. + * @return Entropic function of the particle + */ +float convert_A(struct engine* e, struct part* p) { + return p->primitives.P / pow_gamma(p->primitives.rho); +} + +/** + * @brief Get the total energy of a particle * + * @param e #engine. + * @param p Particle. + * @return Total energy of the particle */ -__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); +float convert_Etot(struct engine* e, struct part* p) { + float momentum2; + + momentum2 = p->conserved.momentum[0] * p->conserved.momentum[0] + + p->conserved.momentum[1] * p->conserved.momentum[1] + + p->conserved.momentum[2] * p->conserved.momentum[2]; + + return p->conserved.energy + 0.5f * momentum2 / p->conserved.mass; +} + +/** + * @brief Specifies which particle fields to write to a dataset + * + * @param parts The particle array. + * @param list The list of i/o properties to write. + * @param num_fields The number of i/o fields to write. + */ +void hydro_write_particles(struct part* parts, struct io_props* list, + int* num_fields) { + + *num_fields = 13; + + /* List what we want to write */ + list[0] = io_make_output_field("Coordinates", DOUBLE, 3, UNIT_CONV_LENGTH, + parts, x); + list[1] = io_make_output_field("Velocities", FLOAT, 3, UNIT_CONV_SPEED, parts, + primitives.v); + list[2] = io_make_output_field("Masses", FLOAT, 1, UNIT_CONV_MASS, parts, + conserved.mass); + list[3] = io_make_output_field("SmoothingLength", FLOAT, 1, UNIT_CONV_LENGTH, + parts, h); + list[4] = io_make_output_field_convert_part("InternalEnergy", FLOAT, 1, + UNIT_CONV_ENERGY_PER_UNIT_MASS, + parts, primitives.P, convert_u); + list[5] = io_make_output_field("ParticleIDs", ULONGLONG, 1, + UNIT_CONV_NO_UNITS, parts, id); + list[6] = io_make_output_field("Acceleration", FLOAT, 3, + UNIT_CONV_ACCELERATION, parts, a_hydro); + list[7] = io_make_output_field("Density", FLOAT, 1, UNIT_CONV_DENSITY, parts, + primitives.rho); + list[8] = io_make_output_field("Volume", FLOAT, 1, UNIT_CONV_VOLUME, parts, + geometry.volume); + list[9] = io_make_output_field("GradDensity", FLOAT, 3, UNIT_CONV_DENSITY, + parts, primitives.gradients.rho); + list[10] = io_make_output_field_convert_part( + "Entropy", FLOAT, 1, UNIT_CONV_ENTROPY, parts, primitives.P, convert_A); + list[11] = io_make_output_field("Pressure", FLOAT, 1, UNIT_CONV_PRESSURE, + parts, primitives.P); + list[12] = + io_make_output_field_convert_part("TotEnergy", FLOAT, 1, UNIT_CONV_ENERGY, + parts, conserved.energy, convert_Etot); } /** @@ -95,26 +142,24 @@ __attribute__((always_inline)) INLINE static void hydro_write_particles( * @param h_grpsph The HDF5 group in which to write */ void writeSPHflavour(hid_t h_grpsph) { + /* Gradient information */ + writeAttribute_s(h_grpsph, "Gradient reconstruction model", + HYDRO_GRADIENT_IMPLEMENTATION); + + /* Slope limiter information */ + writeAttribute_s(h_grpsph, "Cell wide slope limiter model", + HYDRO_SLOPE_LIMITER_CELL_IMPLEMENTATION); + writeAttribute_s(h_grpsph, "Piecewise slope limiter model", + HYDRO_SLOPE_LIMITER_FACE_IMPLEMENTATION); - /* 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)); + /* Riemann solver information */ + writeAttribute_s(h_grpsph, "Riemann solver type", + RIEMANN_SOLVER_IMPLEMENTATION); } + +/** + * @brief Are we writing entropy in the internal energy field ? + * + * @return 1 if entropy is in 'internal energy', 0 otherwise. + */ +int writeEntropyFlag() { return 0; } diff --git a/src/hydro/Gizmo/hydro_part.h b/src/hydro/Gizmo/hydro_part.h index 9e5f32f758248d1d1616f4556c81fc8e0b52e83b..d425294671d4bc172f45c928c2290f8cfa8e093c 100644 --- a/src/hydro/Gizmo/hydro_part.h +++ b/src/hydro/Gizmo/hydro_part.h @@ -1,8 +1,6 @@ /******************************************************************************* * This file is part of SWIFT. - * Coypright (c) 2012 Pedro Gonnet (pedro.gonnet@durham.ac.uk) - * Matthieu Schaller (matthieu.schaller@durham.ac.uk) - * Bert Vandenbroucke (bert.vandenbroucke@ugent.be) + * Coypright (c) 2014 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 @@ -19,26 +17,15 @@ * ******************************************************************************/ -/* 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]; + /* Offset between current position and position at last tree rebuild. */ + float x_diff[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. */ @@ -47,18 +34,13 @@ struct part { /* Particle position. */ double x[3]; - /* Particle velocity. */ + /* Particle predicted velocity. */ float v[3]; /* Particle acceleration. */ float a_hydro[3]; - float mass; // MATTHIEU - float h_dt; - float rho; - float rho_dh; - - /* Particle cutoff radius. */ + /* Particle smoothing length. */ float h; /* Particle time of beginning of time-step. */ @@ -67,76 +49,103 @@ struct part { /* Particle time of end of time-step. */ int ti_end; - /* The primitive hydrodynamical variables */ + /* Old internal energy flux */ + float du_dt; + + /* The primitive hydrodynamical variables. */ struct { - /* fluid velocity */ - GFLOAT v[3]; + /* Fluid velocity. */ + float v[3]; - /* density */ - GFLOAT rho; + /* Density. */ + float rho; - /* pressure */ - GFLOAT P; + /* Pressure. */ + float P; + /* Gradients of the primitive variables. */ struct { - GFLOAT rho[3]; + /* Density gradients. */ + float rho[3]; - GFLOAT v[3][3]; + /* Fluid velocity gradients. */ + float v[3][3]; - GFLOAT P[3]; + /* Pressure gradients. */ + float P[3]; } gradients; + /* Quantities needed by the slope limiter. */ struct { - /* extreme values among the neighbours */ - GFLOAT rho[2]; + /* Extreme values of the density among the neighbours. */ + float rho[2]; - GFLOAT v[3][2]; + /* Extreme values of the fluid velocity among the neighbours. */ + float v[3][2]; - GFLOAT P[2]; + /* Extreme values of the pressure among the neighbours. */ + float P[2]; - /* maximal distance to all neighbouring faces */ + /* Maximal distance to all neighbouring faces. */ float maxr; } limiter; } primitives; - /* The conserved hydrodynamical variables */ + /* The conserved hydrodynamical variables. */ struct { - /* fluid momentum */ - GFLOAT momentum[3]; + /* Fluid momentum. */ + float momentum[3]; + + /* Fluid mass */ + float mass; + + /* Fluid thermal energy (not per unit mass!). */ + float energy; + + /* Fluxes. */ + struct { + + /* Mass flux. */ + float mass; + + /* Momentum flux. */ + float momentum[3]; - /* fluid mass */ - GFLOAT mass; + /* Energy flux. */ + float energy; - /* fluid energy */ - GFLOAT energy; + } flux; } conserved; - /* Geometrical quantities used for hydro */ + /* Geometrical quantities used for hydro. */ struct { - /* volume of the particle */ + /* Volume of the particle. */ float volume; - /* gradient matrix */ + /* Geometrical shear matrix used to calculate second order accurate + gradients */ float matrix_E[3][3]; } geometry; + /* Variables used for timestep calculation (currently not used). */ struct { + /* Maximum fluid velocity among all neighbours. */ float vmax; } timestepvars; - /* Quantities used during the density loop */ + /* Quantities used during the volume (=density) loop. */ struct { /* Particle velocity divergence. */ @@ -153,8 +162,36 @@ struct part { } density; + /* Quantities used during the force loop. */ + struct { + + /* Needed to drift the primitive variables. */ + float h_dt; + + /* Physical time step of the particle. */ + float dt; + + /* Actual velocity of the particle. */ + float v_full[3]; + + } force; + + /* Specific stuff for the gravity-hydro coupling. */ + struct { + + /* Previous value of the gravitational acceleration. */ + float old_a[3]; + + /* Previous value of the mass flux vector. */ + float old_mflux[3]; + + /* Current value of the mass flux vector. */ + float mflux[3]; + + } gravity; + /* Particle ID. */ - unsigned long long id; + long long id; /* Associated gravitas. */ struct gpart *gpart; diff --git a/src/hydro/Gizmo/hydro_slope_limiters.h b/src/hydro/Gizmo/hydro_slope_limiters.h new file mode 100644 index 0000000000000000000000000000000000000000..cd66f05ac9eb9d51744723d93f899b0c8c668e2e --- /dev/null +++ b/src/hydro/Gizmo/hydro_slope_limiters.h @@ -0,0 +1,94 @@ +/******************************************************************************* + * This file is part of SWIFT. + * Copyright (c) 2016 Bert Vandenbroucke (bert.vandenbroucke@gmail.com) + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published + * by the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this program. If not, see <http://www.gnu.org/licenses/>. + * + ******************************************************************************/ + +#ifndef SWIFT_HYDRO_SLOPE_LIMITERS_H +#define SWIFT_HYDRO_SLOPE_LIMITERS_H + +#include "dimension.h" +#include "kernel_hydro.h" + +#ifdef SLOPE_LIMITER_PER_FACE + +#define HYDRO_SLOPE_LIMITER_FACE_IMPLEMENTATION \ + "GIZMO piecewise slope limiter (Hopkins 2015)" +#include "hydro_slope_limiters_face.h" + +#else + +#define HYDRO_SLOPE_LIMITER_FACE_IMPLEMENTATION "No piecewise slope limiter" + +/** + * @brief Slope limit the slopes at the interface between two particles + * + * @param Wi Hydrodynamic variables of particle i. + * @param Wj Hydrodynamic variables of particle j. + * @param dWi Difference between the hydrodynamic variables of particle i at the + * position of particle i and at the interface position. + * @param dWj Difference between the hydrodynamic variables of particle j at the + * position of particle j and at the interface position. + * @param xij_i Relative position vector of the interface w.r.t. particle i. + * @param xij_j Relative position vector of the interface w.r.t. partilce j. + * @param r Distance between particle i and particle j. + */ +__attribute__((always_inline)) INLINE static void hydro_slope_limit_face( + float *Wi, float *Wj, float *dWi, float *dWj, float *xij_i, float *xij_j, + float r) {} + +#endif + +#ifdef SLOPE_LIMITER_CELL_WIDE + +#define HYDRO_SLOPE_LIMITER_CELL_IMPLEMENTATION \ + "Cell wide slope limiter (Springel 2010)" +#include "hydro_slope_limiters_cell.h" + +#else + +#define HYDRO_SLOPE_LIMITER_CELL_IMPLEMENTATION "No cell wide slope limiter" + +/** + * @brief Initialize variables for the cell wide slope limiter + * + * @param p Particle. + */ +__attribute__((always_inline)) INLINE static void hydro_slope_limit_cell_init( + struct part *p) {} + +/** + * @brief Collect information for the cell wide slope limiter during the + * neighbour loop + * + * @param pi Particle i. + * @param pj Particle j. + * @param r Distance between particle i and particle j. + */ +__attribute__((always_inline)) INLINE static void +hydro_slope_limit_cell_collect(struct part *pi, struct part *pj, float r) {} + +/** + * @brief Slope limit cell gradients + * + * @param p Particle. + */ +__attribute__((always_inline)) INLINE static void hydro_slope_limit_cell( + struct part *p) {} + +#endif + +#endif // SWIFT_HYDRO_SLOPE_LIMITERS_H diff --git a/src/hydro/Gizmo/hydro_slope_limiters_cell.h b/src/hydro/Gizmo/hydro_slope_limiters_cell.h new file mode 100644 index 0000000000000000000000000000000000000000..aa99b43721f669f47a7888a5da0b1933ca1ebd62 --- /dev/null +++ b/src/hydro/Gizmo/hydro_slope_limiters_cell.h @@ -0,0 +1,173 @@ +/******************************************************************************* + * This file is part of SWIFT. + * Copyright (c) 2016 Bert Vandenbroucke (bert.vandenbroucke@gmail.com) + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published + * by the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this program. If not, see <http://www.gnu.org/licenses/>. + * + ******************************************************************************/ + +#include <float.h> + +/** + * @brief Initialize variables for the cell wide slope limiter + * + * @param p Particle. + */ +__attribute__((always_inline)) INLINE static void hydro_slope_limit_cell_init( + struct part* p) { + + p->primitives.limiter.rho[0] = FLT_MAX; + p->primitives.limiter.rho[1] = -FLT_MAX; + p->primitives.limiter.v[0][0] = FLT_MAX; + p->primitives.limiter.v[0][1] = -FLT_MAX; + p->primitives.limiter.v[1][0] = FLT_MAX; + p->primitives.limiter.v[1][1] = -FLT_MAX; + p->primitives.limiter.v[2][0] = FLT_MAX; + p->primitives.limiter.v[2][1] = -FLT_MAX; + p->primitives.limiter.P[0] = FLT_MAX; + p->primitives.limiter.P[1] = -FLT_MAX; + + p->primitives.limiter.maxr = -FLT_MAX; +} + +/** + * @brief Collect information for the cell wide slope limiter during the + * neighbour loop + * + * @param pi Particle i. + * @param pj Particle j. + * @param r Distance between particle i and particle j. + */ +__attribute__((always_inline)) INLINE static void +hydro_slope_limit_cell_collect(struct part* pi, struct part* pj, float r) { + + /* basic slope limiter: collect the maximal and the minimal value for the + * primitive variables among the ngbs */ + pi->primitives.limiter.rho[0] = + 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); +} + +/** + * @brief Slope limit cell gradients + * + * @param p Particle. + */ +__attribute__((always_inline)) INLINE static void hydro_slope_limit_cell( + struct part* p) { + + float gradrho[3], gradv[3][3], gradP[3]; + float gradtrue, gradmax, gradmin, alpha; + + gradrho[0] = p->primitives.gradients.rho[0]; + gradrho[1] = p->primitives.gradients.rho[1]; + gradrho[2] = p->primitives.gradients.rho[2]; + + gradv[0][0] = p->primitives.gradients.v[0][0]; + gradv[0][1] = p->primitives.gradients.v[0][1]; + gradv[0][2] = p->primitives.gradients.v[0][2]; + + gradv[1][0] = p->primitives.gradients.v[1][0]; + gradv[1][1] = p->primitives.gradients.v[1][1]; + gradv[1][2] = p->primitives.gradients.v[1][2]; + + gradv[2][0] = p->primitives.gradients.v[2][0]; + gradv[2][1] = p->primitives.gradients.v[2][1]; + gradv[2][2] = p->primitives.gradients.v[2][2]; + + gradP[0] = p->primitives.gradients.P[0]; + gradP[1] = p->primitives.gradients.P[1]; + gradP[2] = p->primitives.gradients.P[2]; + + gradtrue = sqrtf(gradrho[0] * gradrho[0] + gradrho[1] * gradrho[1] + + gradrho[2] * gradrho[2]); + if (gradtrue) { + gradtrue *= p->primitives.limiter.maxr; + 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; + } +} diff --git a/src/hydro/Gizmo/hydro_slope_limiters_face.h b/src/hydro/Gizmo/hydro_slope_limiters_face.h new file mode 100644 index 0000000000000000000000000000000000000000..7ae5dd2eb073d9aae8ab6f2efffdf8df15b4bb4a --- /dev/null +++ b/src/hydro/Gizmo/hydro_slope_limiters_face.h @@ -0,0 +1,121 @@ +/******************************************************************************* + * This file is part of SWIFT. + * Copyright (c) 2016 Bert Vandenbroucke (bert.vandenbroucke@gmail.com) + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published + * by the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this program. If not, see <http://www.gnu.org/licenses/>. + * + ******************************************************************************/ + +/** + * @brief Slope limit a single quantity at the interface + * + * @param phi_i Value of the quantity at the particle position. + * @param phi_j Value of the quantity at the neighbouring particle position. + * @param phi_mid0 Extrapolated value of the quantity at the interface position. + * @param xij_norm Distance between the particle position and the interface + * position. + * @param r Distance between the particle and its neighbour. + * @return The slope limited difference between the quantity at the particle + * position and the quantity at the interface position. + */ +__attribute__((always_inline)) INLINE static float +hydro_slope_limit_face_quantity(float phi_i, float phi_j, float phi_mid0, + float xij_norm, float r) { + + float delta1, delta2, phimin, phimax, phibar, phiplus, phiminus, phi_mid; + const float psi1 = 0.5f; + const float psi2 = 0.25f; + + if (phi_i == phi_j) { + return 0.0f; + } + + 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_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 = fmax(phiminus, fmin(phibar + delta2, phi_mid0)); + } else { + phi_mid = fmin(phiplus, fmax(phibar - delta2, phi_mid0)); + } + + return phi_mid - phi_i; +} + +/** + * @brief Slope limit the slopes at the interface between two particles + * + * @param Wi Hydrodynamic variables of particle i. + * @param Wj Hydrodynamic variables of particle j. + * @param dWi Difference between the hydrodynamic variables of particle i at the + * position of particle i and at the interface position. + * @param dWj Difference between the hydrodynamic variables of particle j at the + * position of particle j and at the interface position. + * @param xij_i Relative position vector of the interface w.r.t. particle i. + * @param xij_j Relative position vector of the interface w.r.t. partilce j. + * @param r Distance between particle i and particle j. + */ +__attribute__((always_inline)) INLINE static void hydro_slope_limit_face( + float *Wi, float *Wj, float *dWi, float *dWj, float *xij_i, float *xij_j, + float r) { + + float xij_i_norm, xij_j_norm; + + xij_i_norm = + sqrtf(xij_i[0] * xij_i[0] + xij_i[1] * xij_i[1] + xij_i[2] * xij_i[2]); + + xij_j_norm = + sqrtf(xij_j[0] * xij_j[0] + xij_j[1] * xij_j[1] + xij_j[2] * xij_j[2]); + + dWi[0] = hydro_slope_limit_face_quantity(Wi[0], Wj[0], Wi[0] + dWi[0], + xij_i_norm, r); + dWi[1] = hydro_slope_limit_face_quantity(Wi[1], Wj[1], Wi[1] + dWi[1], + xij_i_norm, r); + dWi[2] = hydro_slope_limit_face_quantity(Wi[2], Wj[2], Wi[2] + dWi[2], + xij_i_norm, r); + dWi[3] = hydro_slope_limit_face_quantity(Wi[3], Wj[3], Wi[3] + dWi[3], + xij_i_norm, r); + dWi[4] = hydro_slope_limit_face_quantity(Wi[4], Wj[4], Wi[4] + dWi[4], + xij_i_norm, r); + + dWj[0] = hydro_slope_limit_face_quantity(Wj[0], Wi[0], Wj[0] + dWj[0], + xij_j_norm, r); + dWj[1] = hydro_slope_limit_face_quantity(Wj[1], Wi[1], Wj[1] + dWj[1], + xij_j_norm, r); + dWj[2] = hydro_slope_limit_face_quantity(Wj[2], Wi[2], Wj[2] + dWj[2], + xij_j_norm, r); + dWj[3] = hydro_slope_limit_face_quantity(Wj[3], Wi[3], Wj[3] + dWj[3], + xij_j_norm, r); + dWj[4] = hydro_slope_limit_face_quantity(Wj[4], Wi[4], Wj[4] + dWj[4], + xij_j_norm, r); +} diff --git a/src/hydro/Minimal/hydro.h b/src/hydro/Minimal/hydro.h index a5d73aad02372aa22b840c2cb0d3100cd439e75d..0bbc77f4a2384c79f7d3329c20b92990598d5c63 100644 --- a/src/hydro/Minimal/hydro.h +++ b/src/hydro/Minimal/hydro.h @@ -35,6 +35,7 @@ */ #include "adiabatic_index.h" +#include "approx_math.h" #include "dimension.h" #include "equation_of_state.h" #include "hydro_properties.h" @@ -102,6 +103,28 @@ __attribute__((always_inline)) INLINE static float hydro_get_soundspeed( return gas_soundspeed_from_internal_energy(p->rho, u); } +/** + * @brief Returns the density of a particle + * + * @param p The particle of interest + */ +__attribute__((always_inline)) INLINE static float hydro_get_density( + const struct part *restrict p) { + + return p->rho; +} + +/** + * @brief Returns the mass of a particle + * + * @param p The particle of interest + */ +__attribute__((always_inline)) INLINE static float hydro_get_mass( + const struct part *restrict p) { + + return p->mass; +} + /** * @brief Modifies the thermal state of a particle to the imposed internal * energy @@ -286,15 +309,32 @@ __attribute__((always_inline)) INLINE static void hydro_reset_acceleration( * Additional hydrodynamic quantites are drifted forward in time here. These * include thermal quantities (thermal energy or total energy or entropy, ...). * - * @param p The particle - * @param xp The extended data of the particle - * @param t0 The time at the start of the drift (on the timeline) - * @param t1 The time at the end of the drift (on the timeline) - * @param timeBase The minimal time-step size + * @param p The particle. + * @param xp The extended data of the particle. + * @param dt The drift time-step. + * @param t0 The time at the start of the drift (on the timeline). + * @param t1 The time at the end of the drift (on the timeline). + * @param timeBase The minimal time-step size. */ __attribute__((always_inline)) INLINE static void hydro_predict_extra( - struct part *restrict p, const struct xpart *restrict xp, int t0, int t1, - double timeBase) { + struct part *restrict p, const struct xpart *restrict xp, float dt, int t0, + int t1, double timeBase) { + + const float h_inv = 1.f / p->h; + + /* Predict smoothing length */ + const float w1 = p->force.h_dt * h_inv * dt; + if (fabsf(w1) < 0.2f) + p->h *= approx_expf(w1); /* 4th order expansion of exp(w) */ + else + p->h *= expf(w1); + + /* Predict density */ + const float w2 = -hydro_dimension * w1; + if (fabsf(w2) < 0.2f) + p->rho *= approx_expf(w2); /* 4th order expansion of exp(w) */ + else + p->rho *= expf(w2); /* Drift the pressure */ const float dt_entr = (t1 - (p->ti_begin + p->ti_end) / 2) * timeBase; diff --git a/src/hydro_io.h b/src/hydro_io.h index 30d663f647c9b763e9b19177e9ba8ef374855768..f0a619b90b774574c434007b1c01a0e55e75e464 100644 --- a/src/hydro_io.h +++ b/src/hydro_io.h @@ -28,6 +28,8 @@ #include "./hydro/Gadget2/hydro_io.h" #elif defined(DEFAULT_SPH) #include "./hydro/Default/hydro_io.h" +#elif defined(GIZMO_SPH) +#include "./hydro/Gizmo/hydro_io.h" #else #error "Invalid choice of SPH variant" #endif diff --git a/src/part.h b/src/part.h index efca7b6b5bef49f20df1e2c45b30f65ecbbf4960..ea895e6e0295d6a8b63309c7bd6855daa2cf7d64 100644 --- a/src/part.h +++ b/src/part.h @@ -45,6 +45,9 @@ #include "./hydro/Gadget2/hydro_part.h" #elif defined(DEFAULT_SPH) #include "./hydro/Default/hydro_part.h" +#elif defined(GIZMO_SPH) +#include "./hydro/Gizmo/hydro_part.h" +#define EXTRA_HYDRO_LOOP #else #error "Invalid choice of SPH variant" #endif diff --git a/src/riemann.h b/src/riemann.h index d647b021167317d14f4cd7316d09c247794f3d23..0191058e3ba856d7dcec42ba6185def3ee71d090 100644 --- a/src/riemann.h +++ b/src/riemann.h @@ -27,18 +27,27 @@ #include "stdio.h" #include "stdlib.h" -#define HLLC_SOLVER +#if defined(RIEMANN_SOLVER_EXACT) -#ifdef EXACT_SOLVER +#define RIEMANN_SOLVER_IMPLEMENTATION "Exact Riemann solver (Toro 2009)" #include "riemann/riemann_exact.h" -#endif -#ifdef TRRS_SOLVER +#elif defined(RIEMANN_SOLVER_TRRS) + +#define RIEMANN_SOLVER_IMPLEMENTATION \ + "Two Rarefaction Riemann Solver (Toro 2009)" #include "riemann/riemann_trrs.h" -#endif -#ifdef HLLC_SOLVER +#elif defined(RIEMANN_SOLVER_HLLC) + +#define RIEMANN_SOLVER_IMPLEMENTATION \ + "Harten-Lax-van Leer-Contact Riemann solver (Toro 2009)" #include "riemann/riemann_hllc.h" + +#else + +#error "Error: no Riemann solver selected!" + #endif #endif /* SWIFT_RIEMANN_H */ diff --git a/src/riemann/riemann_exact.h b/src/riemann/riemann_exact.h index a2f3c30fb1daf5d53bf35abe4ca7e73eafba6018..9763d9f0d12da32d9142c24481105b9f139be588 100644 --- a/src/riemann/riemann_exact.h +++ b/src/riemann/riemann_exact.h @@ -29,19 +29,9 @@ #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) +#include <float.h> +#include "adiabatic_index.h" +#include "riemann_vacuum.h" /** * @brief Functions (4.6) and (4.7) in Toro. @@ -50,19 +40,18 @@ * @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) { +__attribute__((always_inline)) INLINE static float riemann_fb(float p, float* W, + float a) { - GFLOAT fval = 0.; - GFLOAT A, B; + float fval = 0.; + float A, B; if (p > W[4]) { - A = const_riemann_tdgp1 / W[0]; - B = const_riemann_gm1dgp1 * W[4]; + A = hydro_two_over_gamma_plus_one / W[0]; + B = hydro_gamma_minus_one_over_gamma_plus_one * 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); + fval = hydro_two_over_gamma_minus_one * a * + (pow_gamma_minus_one_over_two_gamma(p / W[4]) - 1.0f); } return fval; } @@ -78,9 +67,8 @@ __attribute__((always_inline)) INLINE static GFLOAT riemann_fb(GFLOAT p, * @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) { +__attribute__((always_inline)) INLINE static float riemann_f( + float p, float* WL, float* WR, float vL, float vR, float aL, float aR) { return riemann_fb(p, WL, aL) + riemann_fb(p, WR, aR) + (vR - vL); } @@ -92,18 +80,18 @@ __attribute__((always_inline)) INLINE static GFLOAT riemann_f( * @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) { +__attribute__((always_inline)) INLINE static float riemann_fprimeb(float p, + float* W, + float a) { - GFLOAT fval = 0.; - GFLOAT A, B; + float fval = 0.; + float A, B; if (p > W[4]) { - A = const_riemann_tdgp1 / W[0]; - B = const_riemann_gm1dgp1 * W[4]; + A = hydro_two_over_gamma_plus_one / W[0]; + B = hydro_gamma_minus_one_over_gamma_plus_one * 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); + fval = 1.0f / W[0] / a * pow_minus_gamma_plus_one_over_two_gamma(p / W[4]); } return fval; } @@ -117,8 +105,8 @@ __attribute__((always_inline)) INLINE static GFLOAT riemann_fprimeb(GFLOAT p, * @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) { +__attribute__((always_inline)) INLINE static float riemann_fprime( + float p, float* WL, float* WR, float aL, float aR) { return riemann_fprimeb(p, WL, aL) + riemann_fprimeb(p, WR, aR); } @@ -129,12 +117,12 @@ __attribute__((always_inline)) INLINE static GFLOAT riemann_fprime( * @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) { +__attribute__((always_inline)) INLINE static float riemann_gb(float p, + float* W) { - GFLOAT A, B; - A = const_riemann_tdgp1 / W[0]; - B = const_riemann_gm1dgp1 * W[4]; + float A, B; + A = hydro_two_over_gamma_plus_one / W[0]; + B = hydro_gamma_minus_one_over_gamma_plus_one * W[4]; return sqrtf(A / (p + B)); } @@ -151,11 +139,11 @@ __attribute__((always_inline)) INLINE static GFLOAT riemann_gb(GFLOAT p, * @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) { +__attribute__((always_inline)) INLINE static float riemann_guess_p( + float* WL, float* WR, float vL, float vR, float aL, float aR) { - GFLOAT pguess, pmin, pmax, qmax; - GFLOAT ppv; + float pguess, pmin, pmax, qmax; + float ppv; pmin = fminf(WL[4], WR[4]); pmax = fmaxf(WL[4], WR[4]); @@ -168,10 +156,10 @@ __attribute__((always_inline)) INLINE static GFLOAT riemann_guess_p( } 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); + pguess = pow_two_gamma_over_gamma_minus_one( + (aL + aR - hydro_gamma_minus_one_over_two * (vR - vL)) / + (aL / pow_gamma_minus_one_over_two_gamma(WL[4]) + + aR / pow_gamma_minus_one_over_two_gamma(WR[4]))); } else { /* two shocks */ pguess = (riemann_gb(ppv, WL) * WL[4] + riemann_gb(ppv, WR) * WR[4] - vR + @@ -202,14 +190,14 @@ __attribute__((always_inline)) INLINE static GFLOAT riemann_guess_p( * @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; +__attribute__((always_inline)) INLINE static float riemann_solve_brent( + float lower_limit, float upper_limit, float lowf, float upf, + float error_tol, float* WL, float* WR, float vL, float vR, float aL, + float aR) { + + float a, b, c, d, s; + float fa, fb, fc, fs; + float tmp, tmp2; int mflag; int i; @@ -296,148 +284,6 @@ __attribute__((always_inline)) INLINE static GFLOAT riemann_solve_brent( 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- @@ -456,20 +302,20 @@ __attribute__((always_inline)) INLINE static void riemann_solve_vacuum( * @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) { + float* WL, float* WR, float* Whalf, float* n_unit) { /* velocity of the left and right state in a frame aligned with n_unit */ - GFLOAT vL, vR, vhalf; + float vL, vR, vhalf; /* sound speeds */ - GFLOAT aL, aR; + float aL, aR; /* variables used for finding pstar */ - GFLOAT p, pguess, fp, fpguess; + float p, pguess, fp, fpguess; /* variables used for sampling the solution */ - GFLOAT u; - GFLOAT pdpR, SR; - GFLOAT SHR, STR; - GFLOAT pdpL, SL; - GFLOAT SHL, STL; + float u; + float pdpR, SR; + float SHR, STR; + float pdpL, SL; + float SHL, STL; int errorFlag = 0; /* sanity checks */ @@ -500,156 +346,155 @@ __attribute__((always_inline)) INLINE static void riemann_solver_solve( 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]); + aL = sqrtf(hydro_gamma * WL[4] / WL[0]); + aR = sqrtf(hydro_gamma * WR[4] / WR[0]); - if (!WL[0] || !WR[0]) { - /* vacuum: we need a vacuum riemann solver */ + /* check vacuum (generation) condition */ + if (riemann_is_vacuum(WL, WR, vL, vR, aL, aR)) { 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 { + /* 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); + /* 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(hydro_gamma_plus_one_over_two_gamma * pdpR + + hydro_gamma_minus_one_over_two_gamma); + if (SR > 0.0f) { + Whalf[0] = WR[0] * (pdpR + hydro_gamma_minus_one_over_gamma_plus_one) / + (hydro_gamma_minus_one_over_gamma_plus_one * 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 * pow_gamma_minus_one_over_two_gamma(pdpR); + if (STR <= 0.0f) { + Whalf[0] = + WR[0] * pow_two_over_gamma_minus_one( + hydro_two_over_gamma_plus_one - + hydro_gamma_minus_one_over_gamma_plus_one / aR * vR); + vhalf = hydro_two_over_gamma_plus_one * + (-aR + hydro_gamma_minus_one_over_two * vR) - + vR; + Whalf[4] = + WR[4] * pow_two_gamma_over_gamma_minus_one( + hydro_two_over_gamma_plus_one - + hydro_gamma_minus_one_over_gamma_plus_one / aR * vR); + } else { + Whalf[0] = WR[0] * pow_one_over_gamma(pdpR); 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]; - } + 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(hydro_gamma_plus_one_over_two_gamma * pdpL + + hydro_gamma_minus_one_over_two_gamma); + if (SL < 0.0f) { + Whalf[0] = WL[0] * (pdpL + hydro_gamma_minus_one_over_gamma_plus_one) / + (hydro_gamma_minus_one_over_gamma_plus_one * pdpL + 1.0f); + vhalf = u - vL; + Whalf[4] = p; + } else { + Whalf[0] = WL[0]; + vhalf = 0.0f; + Whalf[4] = WL[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); + /* rarefaction wave */ + SHL = vL - aL; + if (SHL < 0.0f) { + STL = u - aL * pow_gamma_minus_one_over_two_gamma(pdpL); + if (STL > 0.0f) { + Whalf[0] = + WL[0] * pow_two_over_gamma_minus_one( + hydro_two_over_gamma_plus_one + + hydro_gamma_minus_one_over_gamma_plus_one / aL * vL); + vhalf = hydro_two_over_gamma_plus_one * + (aL + hydro_gamma_minus_one_over_two * vL) - + vL; + Whalf[4] = + WL[4] * pow_two_gamma_over_gamma_minus_one( + hydro_two_over_gamma_plus_one + + hydro_gamma_minus_one_over_gamma_plus_one / aL * vL); + } else { + Whalf[0] = WL[0] * pow_one_over_gamma(pdpL); 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]; - } + Whalf[0] = WL[0]; + vhalf = 0.0f; + Whalf[4] = WL[4]; } } } @@ -661,10 +506,10 @@ __attribute__((always_inline)) INLINE static void riemann_solver_solve( } __attribute__((always_inline)) INLINE static void riemann_solve_for_flux( - GFLOAT* Wi, GFLOAT* Wj, float* n_unit, float* vij, GFLOAT* totflux) { + float* Wi, float* Wj, float* n_unit, float* vij, float* totflux) { - GFLOAT Whalf[5]; - GFLOAT flux[5][3]; + float Whalf[5]; + float flux[5][3]; float vtot[3]; float rhoe; @@ -690,7 +535,7 @@ __attribute__((always_inline)) INLINE static void riemann_solve_for_flux( /* 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) + + rhoe = Whalf[4] / hydro_gamma_minus_one + 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]; diff --git a/src/riemann/riemann_hllc.h b/src/riemann/riemann_hllc.h index 6c583f6410f53ed64d630082926d816129768fab..fdc22ce05b8d63bdba66e530d1a5a968801a9f10 100644 --- a/src/riemann/riemann_hllc.h +++ b/src/riemann/riemann_hllc.h @@ -20,13 +20,16 @@ #ifndef SWIFT_RIEMANN_HLLC_H #define SWIFT_RIEMANN_HLLC_H +#include "adiabatic_index.h" +#include "riemann_vacuum.h" + __attribute__((always_inline)) INLINE static void riemann_solve_for_flux( - GFLOAT *WL, GFLOAT *WR, float *n, float *vij, GFLOAT *totflux) { + float *WL, float *WR, float *n, float *vij, float *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]; + float uL, uR, aL, aR; + float rhobar, abar, pPVRS, pstar, qL, qR, SL, SR, Sstar; + float v2, eL, eR; + float UstarL[5], UstarR[5]; /* Handle pure vacuum */ if (!WL[0] && !WR[0]) { @@ -41,16 +44,13 @@ __attribute__((always_inline)) INLINE static void riemann_solve_for_flux( /* 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]); + aL = sqrtf(hydro_gamma * WL[4] / WL[0]); + aR = sqrtf(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"); + if (riemann_is_vacuum(WL, WR, uL, uR, aL, aR)) { + riemann_solve_vacuum_flux(WL, WR, uL, uR, aL, aR, n, vij, totflux); + return; } /* STEP 1: pressure estimate */ @@ -64,14 +64,12 @@ __attribute__((always_inline)) INLINE static void riemann_solve_for_flux( qL = 1.; if (pstar > WL[4]) { qL = sqrtf(1. + - 0.5 * (const_hydro_gamma + 1.) / const_hydro_gamma * - (pstar / WL[4] - 1.)); + 0.5 * (hydro_gamma + 1.) / 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.)); + 0.5 * (hydro_gamma + 1.) / hydro_gamma * (pstar / WR[4] - 1.)); } SL = uL - aL * qL; SR = uR + aR * qR; @@ -86,9 +84,9 @@ __attribute__((always_inline)) INLINE static void riemann_solve_for_flux( (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]; + totflux[3] = WL[0] * WL[3] * 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; + eL = WL[4] / hydro_gamma_minus_one / WL[0] + 0.5 * v2; totflux[4] = WL[0] * eL * uL + WL[4] * uL; if (SL < 0.) { /* add flux FstarL */ @@ -118,7 +116,7 @@ __attribute__((always_inline)) INLINE static void riemann_solve_for_flux( 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; + eR = WR[4] / hydro_gamma_minus_one / WR[0] + 0.5 * v2; totflux[4] = WR[0] * eR * uR + WR[4] * uR; if (SR > 0.) { /* add flux FstarR */ diff --git a/src/riemann/riemann_trrs.h b/src/riemann/riemann_trrs.h index efdbfb59877c09a59d535a4785ad74620c0f3651..b13a76b4c57af548497780e974e5c9ee3a721fac 100644 --- a/src/riemann/riemann_trrs.h +++ b/src/riemann/riemann_trrs.h @@ -20,19 +20,8 @@ #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) +#include "adiabatic_index.h" +#include "riemann_vacuum.h" /** * @brief Solve the Riemann problem using the Two Rarefaction Riemann Solver @@ -50,31 +39,39 @@ * @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; + float* WL, float* WR, float* Whalf, float* n_unit) { + float aL, aR; + float PLR; + float vL, vR; + float ustar, pstar; + float vhalf; + float pdpR, SHR, STR; + float 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]); + aL = sqrtf(hydro_gamma * WL[4] / WL[0]); + aR = sqrtf(hydro_gamma * WR[4] / WR[0]); + + if (riemann_is_vacuum(WL, WR, vL, vR, aL, aR)) { + riemann_solve_vacuum(WL, WR, vL, vR, aL, aR, Whalf, n_unit); + return; + } /* 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 = pow_gamma_minus_one_over_two_gamma(WL[4] / WR[4]); + ustar = (PLR * vL / aL + vR / aR + + hydro_two_over_gamma_minus_one * (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)); + pstar = + 0.5f * + (WL[4] * pow_two_gamma_over_gamma_minus_one( + 1.0f + hydro_gamma_minus_one_over_two / aL * (vL - ustar)) + + WR[4] * pow_two_gamma_over_gamma_minus_one( + 1.0f + hydro_gamma_minus_one_over_two / aR * (ustar - vR))); /* sample the solution */ if (ustar < 0.0f) { @@ -86,17 +83,21 @@ __attribute__((always_inline)) INLINE static void riemann_solver_solve( /* always a rarefaction wave, that's the approximation */ SHR = vR + aR; if (SHR > 0.0f) { - STR = ustar + aR * pow(pdpR, const_riemann_gm1d2g); + STR = ustar + aR * pow_gamma_minus_one_over_two_gamma(pdpR); 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; + WR[0] * pow_two_over_gamma_minus_one( + hydro_two_over_gamma_plus_one - + hydro_gamma_minus_one_over_gamma_plus_one / aR * vR); + vhalf = hydro_two_over_gamma_plus_one * + (-aR + hydro_gamma_minus_one_over_two * vR) - + vR; Whalf[4] = - WR[4] * pow(const_riemann_tdgp1 - const_riemann_gm1dgp1 / aR * vR, - const_riemann_tgdgm1); + WR[4] * pow_two_gamma_over_gamma_minus_one( + hydro_two_over_gamma_plus_one - + hydro_gamma_minus_one_over_gamma_plus_one / aR * vR); } else { - Whalf[0] = WR[0] * pow(pdpR, const_riemann_ginv); + Whalf[0] = WR[0] * pow_one_over_gamma(pdpR); vhalf = ustar - vR; Whalf[4] = pstar; } @@ -114,17 +115,21 @@ __attribute__((always_inline)) INLINE static void riemann_solver_solve( /* rarefaction wave */ SHL = vL - aL; if (SHL < 0.0f) { - STL = ustar - aL * pow(pdpL, const_riemann_gm1d2g); + STL = ustar - aL * pow_gamma_minus_one_over_two_gamma(pdpL); 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; + WL[0] * pow_two_over_gamma_minus_one( + hydro_two_over_gamma_plus_one + + hydro_gamma_minus_one_over_gamma_plus_one / aL * vL); + vhalf = hydro_two_over_gamma_plus_one * + (aL + hydro_gamma_minus_one_over_two * vL) - + vL; Whalf[4] = - WL[4] * pow(const_riemann_tdgp1 + const_riemann_gm1dgp1 / aL * vL, - const_riemann_tgdgm1); + WL[4] * pow_two_gamma_over_gamma_minus_one( + hydro_two_over_gamma_plus_one + + hydro_gamma_minus_one_over_gamma_plus_one / aL * vL); } else { - Whalf[0] = WL[0] * pow(pdpL, const_riemann_ginv); + Whalf[0] = WL[0] * pow_one_over_gamma(pdpL); vhalf = ustar - vL; Whalf[4] = pstar; } @@ -141,4 +146,53 @@ __attribute__((always_inline)) INLINE static void riemann_solver_solve( Whalf[3] += vhalf * n_unit[2]; } +__attribute__((always_inline)) INLINE static void riemann_solve_for_flux( + float* Wi, float* Wj, float* n_unit, float* vij, float* totflux) { + + float Whalf[5]; + float 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] / hydro_gamma_minus_one + + 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_TRRS_H */ diff --git a/src/riemann/riemann_vacuum.h b/src/riemann/riemann_vacuum.h new file mode 100644 index 0000000000000000000000000000000000000000..743abb910193380793ccdf3d7eddbcedc4968691 --- /dev/null +++ b/src/riemann/riemann_vacuum.h @@ -0,0 +1,254 @@ +/******************************************************************************* + * This file is part of SWIFT. + * Coypright (c) 2016 Bert Vandenbroucke (bert.vandenbroucke@gmail.com) + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published + * by the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this program. If not, see <http://www.gnu.org/licenses/>. + * + ******************************************************************************/ + +#ifndef SWIFT_RIEMANN_VACUUM_H +#define SWIFT_RIEMANN_VACUUM_H + +/** + * @brief Check if the given input states are vacuum or will generate vacuum + */ +__attribute__((always_inline)) INLINE static int riemann_is_vacuum( + float* WL, float* WR, float vL, float vR, float aL, float aR) { + + /* vacuum */ + if (!WL[0] || !WR[0]) { + return 1; + } + /* vacuum generation */ + if (2.0f * aL / hydro_gamma_minus_one + 2.0f * aR / hydro_gamma_minus_one <= + vR - vL) { + return 1; + } + + /* no vacuum */ + return 0; +} + +/** + * @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( + float* WL, float* WR, float vL, float vR, float aL, float aR, float* Whalf, + float* n_unit) { + + float SL, SR; + float 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 + hydro_two_over_gamma_minus_one * aL; + if (SL > 0.0f) { + Whalf[0] = + WL[0] * pow_two_over_gamma_minus_one( + hydro_two_over_gamma_plus_one + + hydro_gamma_minus_one_over_gamma_plus_one / aL * vL); + vhalf = hydro_two_over_gamma_plus_one * + (aL + hydro_gamma_minus_one_over_two * vL) - + vL; + Whalf[4] = + WL[4] * pow_two_gamma_over_gamma_minus_one( + hydro_two_over_gamma_plus_one + + hydro_gamma_minus_one_over_gamma_plus_one / aL * vL); + } 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 (-aR < vR) { + SR = vR - hydro_two_over_gamma_minus_one * 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] * pow_two_over_gamma_minus_one( + hydro_two_over_gamma_plus_one - + hydro_gamma_minus_one_over_gamma_plus_one / aR * vR); + vhalf = hydro_two_over_gamma_plus_one * + (-aR + hydro_gamma_minus_one_over_two * vR) - + vR; + Whalf[4] = + WR[4] * pow_two_gamma_over_gamma_minus_one( + hydro_two_over_gamma_plus_one - + hydro_gamma_minus_one_over_gamma_plus_one / aR * vR); + } + } else { + Whalf[0] = WR[0]; + vhalf = 0.0f; + Whalf[4] = WR[4]; + } + } else { + /* vacuum generation */ + SR = vR - hydro_two_over_gamma_minus_one * aR; + SL = vL + hydro_two_over_gamma_minus_one * 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] * + pow_two_over_gamma_minus_one( + hydro_two_over_gamma_plus_one + + hydro_gamma_minus_one_over_gamma_plus_one / aL * vL); + vhalf = hydro_two_over_gamma_plus_one * + (aL + hydro_gamma_minus_one_over_two * vL) - + vL; + Whalf[4] = WL[4] * + pow_two_gamma_over_gamma_minus_one( + hydro_two_over_gamma_plus_one + + hydro_gamma_minus_one_over_gamma_plus_one / aL * vL); + } 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 (-aR < vR) { + Whalf[0] = WR[0] * + pow_two_over_gamma_minus_one( + hydro_two_over_gamma_plus_one - + hydro_gamma_minus_one_over_gamma_plus_one / aR * vR); + vhalf = hydro_two_over_gamma_plus_one * + (-aR + hydro_gamma_minus_one_over_two * vR) - + vR; + Whalf[4] = WR[4] * + pow_two_gamma_over_gamma_minus_one( + hydro_two_over_gamma_plus_one - + hydro_gamma_minus_one_over_gamma_plus_one / aR * vR); + } 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]; +} + +/** + * @brief Solve the vacuum Riemann problem and return the fluxes + */ +__attribute__((always_inline)) INLINE static void riemann_solve_vacuum_flux( + float* WL, float* WR, float vL, float vR, float aL, float aR, float* n_unit, + float* vij, float* totflux) { + + float Whalf[5]; + float flux[5][3]; + float vtot[3]; + float rhoe; + + riemann_solve_vacuum(WL, WR, vL, vR, aL, aR, 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] / hydro_gamma_minus_one + + 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_VACUUM_H */ diff --git a/src/runner.c b/src/runner.c index 9833524cf3ee711b3b37f2b6339d46aa9fda4612..f7c061c145a982e544439732bc5ad92febfc6afd 100644 --- a/src/runner.c +++ b/src/runner.c @@ -82,6 +82,13 @@ const char runner_flip[27] = {1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, #define FUNCTION density #include "runner_doiact.h" +/* Import the gradient loop functions (if required). */ +#ifdef EXTRA_HYDRO_LOOP +#undef FUNCTION +#define FUNCTION gradient +#include "runner_doiact.h" +#endif + /* Import the force loop functions. */ #undef FUNCTION #define FUNCTION force @@ -422,7 +429,49 @@ void runner_do_init(struct runner *r, struct cell *c, int timer) { } /** - * @brief Intermediate task between density and force + * @brief Intermediate task after the gradient loop that does final operations + * on the gradient quantities and optionally slope limits the gradients + * + * @param r The runner thread. + * @param c The cell. + */ +void runner_do_extra_ghost(struct runner *r, struct cell *c) { + +#ifdef EXTRA_HYDRO_LOOP + + struct part *restrict parts = c->parts; + const int count = c->count; + const int ti_current = r->e->ti_current; + + /* Recurse? */ + if (c->split) { + for (int k = 0; k < 8; k++) + if (c->progeny[k] != NULL) runner_do_extra_ghost(r, c->progeny[k]); + return; + } else { + + /* Loop over the parts in this cell. */ + for (int i = 0; i < count; i++) { + + /* Get a direct pointer on the part. */ + struct part *restrict p = &parts[i]; + + if (p->ti_end <= ti_current) { + + /* Get ready for a force calculation */ + hydro_end_gradient(p); + } + } + } + +#else + error("SWIFT was not compiled with the extra hydro loop activated."); +#endif +} + +/** + * @brief Intermediate task after the density to check that the smoothing + * lengths are correct. * * @param r The runner thread. * @param c The cell. @@ -653,7 +702,8 @@ static void runner_do_drift(struct cell *c, struct engine *e) { const float v[3] = {xp->v_full[0] + p->a_hydro[0] * half_dt, xp->v_full[1] + p->a_hydro[1] * half_dt, xp->v_full[2] + p->a_hydro[2] * half_dt}; - const float m = p->mass; + + const float m = hydro_get_mass(p); /* Collect mass */ mass += m; @@ -1087,8 +1137,11 @@ void *runner_main(void *data) { /* Different types of tasks... */ switch (t->type) { case task_type_self: - if (t->subtype == task_subtype_density) - runner_doself1_density(r, ci); + if (t->subtype == task_subtype_density) runner_doself1_density(r, ci); +#ifdef EXTRA_HYDRO_LOOP + else if (t->subtype == task_subtype_gradient) + runner_doself1_gradient(r, ci); +#endif else if (t->subtype == task_subtype_force) runner_doself2_force(r, ci); else if (t->subtype == task_subtype_grav) @@ -1099,6 +1152,10 @@ void *runner_main(void *data) { case task_type_pair: if (t->subtype == task_subtype_density) runner_dopair1_density(r, ci, cj); +#ifdef EXTRA_HYDRO_LOOP + else if (t->subtype == task_subtype_gradient) + runner_dopair1_gradient(r, ci, cj); +#endif else if (t->subtype == task_subtype_force) runner_dopair2_force(r, ci, cj); else if (t->subtype == task_subtype_grav) @@ -1112,6 +1169,10 @@ void *runner_main(void *data) { case task_type_sub_self: if (t->subtype == task_subtype_density) runner_dosub_self1_density(r, ci, 1); +#ifdef EXTRA_HYDRO_LOOP + else if (t->subtype == task_subtype_gradient) + runner_dosub_self1_gradient(r, ci, 1); +#endif else if (t->subtype == task_subtype_force) runner_dosub_self2_force(r, ci, 1); else if (t->subtype == task_subtype_grav) @@ -1122,6 +1183,10 @@ void *runner_main(void *data) { case task_type_sub_pair: if (t->subtype == task_subtype_density) runner_dosub_pair1_density(r, ci, cj, t->flags, 1); +#ifdef EXTRA_HYDRO_LOOP + else if (t->subtype == task_subtype_gradient) + runner_dosub_pair1_gradient(r, ci, cj, t->flags, 1); +#endif else if (t->subtype == task_subtype_force) runner_dosub_pair2_force(r, ci, cj, t->flags, 1); else if (t->subtype == task_subtype_grav) @@ -1135,6 +1200,11 @@ void *runner_main(void *data) { case task_type_ghost: runner_do_ghost(r, ci); break; +#ifdef EXTRA_HYDRO_LOOP + case task_type_extra_ghost: + runner_do_extra_ghost(r, ci); + break; +#endif case task_type_kick: runner_do_kick(r, ci, 1); break; diff --git a/src/space.c b/src/space.c index b772482a88df84d2558d63cf59d50d4361d6ed9a..5f76055f5e2ee8926aace22b24c771196c4f557d 100644 --- a/src/space.c +++ b/src/space.c @@ -350,14 +350,17 @@ void space_regrid(struct space *s, double cell_max, int verbose) { s->cells[k].sorts = NULL; s->cells[k].nr_tasks = 0; s->cells[k].nr_density = 0; + s->cells[k].nr_gradient = 0; s->cells[k].nr_force = 0; s->cells[k].density = NULL; + s->cells[k].gradient = NULL; s->cells[k].force = NULL; s->cells[k].dx_max = 0.0f; s->cells[k].sorted = 0; s->cells[k].count = 0; s->cells[k].gcount = 0; s->cells[k].init = NULL; + s->cells[k].extra_ghost = NULL; s->cells[k].ghost = NULL; s->cells[k].kick = NULL; s->cells[k].super = &s->cells[k]; diff --git a/src/task.c b/src/task.c index 9e48f8abeb9659ea2674f48620b58da977a6775a..f80068d465802f75f952c1a6c02c76bc7aa0512c 100644 --- a/src/task.c +++ b/src/task.c @@ -48,13 +48,13 @@ /* Task type names. */ const char *taskID_names[task_type_count] = { - "none", "sort", "self", "pair", "sub_self", - "sub_pair", "init", "ghost", "kick", "kick_fixdt", - "send", "recv", "grav_gather_m", "grav_fft", "grav_mm", - "grav_up", "grav_external"}; + "none", "sort", "self", "pair", "sub_self", + "sub_pair", "init", "ghost", "extra_ghost", "kick", + "kick_fixdt", "send", "recv", "grav_gather_m", "grav_fft", + "grav_mm", "grav_up", "grav_external"}; -const char *subtaskID_names[task_type_count] = {"none", "density", "force", - "grav", "tend"}; +const char *subtaskID_names[task_subtype_count] = { + "none", "density", "gradient", "force", "grav", "tend"}; /** * @brief Computes the overlap between the parts array of two given cells. @@ -110,6 +110,7 @@ __attribute__((always_inline)) INLINE static enum task_actions task_acts_on( case task_type_sort: case task_type_ghost: + case task_type_extra_ghost: return task_action_part; break; @@ -120,6 +121,7 @@ __attribute__((always_inline)) INLINE static enum task_actions task_acts_on( switch (t->subtype) { case task_subtype_density: + case task_subtype_gradient: case task_subtype_force: return task_action_part; break; diff --git a/src/task.h b/src/task.h index db74c296bb7988d12e474368ed9abffd97ede49e..d174bad4fac62332b3d2c43997be4ddbf794ea34 100644 --- a/src/task.h +++ b/src/task.h @@ -41,6 +41,7 @@ enum task_types { task_type_sub_pair, task_type_init, task_type_ghost, + task_type_extra_ghost, task_type_kick, task_type_kick_fixdt, task_type_send, @@ -59,6 +60,7 @@ extern const char *taskID_names[]; enum task_subtypes { task_subtype_none = 0, task_subtype_density, + task_subtype_gradient, task_subtype_force, task_subtype_grav, task_subtype_tend, diff --git a/src/timers.c b/src/timers.c index b621d27c90902f06c3760cbef6a88237a2b3b95b..c2f3b35d75ea340082acf1a5ec334bb3543bab12 100644 --- a/src/timers.c +++ b/src/timers.c @@ -37,11 +37,11 @@ ticks timers[timer_count]; * To reset all timers, use the mask #timers_mask_all. */ -void timers_reset(unsigned int mask) { +void timers_reset(unsigned long long mask) { int k; /* Loop over the timers and set the masked ones to zero. */ for (k = 0; k < timer_count; k++) - if (mask & (1 << k)) timers[k] = 0; + if (mask & (1ull << k)) timers[k] = 0; } diff --git a/src/timers.h b/src/timers.h index aa8455397daf1e88b709a8332e3ae63694991e94..0bf1f3f413d123c84cc30edff73ca9dfce4ea159 100644 --- a/src/timers.h +++ b/src/timers.h @@ -36,17 +36,21 @@ enum { timer_kick, timer_dosort, timer_doself_density, + timer_doself_gradient, timer_doself_force, timer_doself_grav_pp, timer_dopair_density, + timer_dopair_gradient, timer_dopair_force, timer_dopair_grav_pm, timer_dopair_grav_pp, timer_dograv_external, timer_dosub_self_density, + timer_dosub_self_gradient, timer_dosub_self_force, timer_dosub_self_grav, timer_dosub_pair_density, + timer_dosub_pair_gradient, timer_dosub_pair_force, timer_dosub_pair_grav, timer_dopair_subset, @@ -64,7 +68,7 @@ enum { extern ticks timers[timer_count]; /* Mask for all timers. */ -#define timers_mask_all ((1 << timer_count) - 1) +#define timers_mask_all ((1ull << timer_count) - 1) /* Define the timer macros. */ #ifdef TIMER @@ -74,7 +78,7 @@ extern ticks timers[timer_count]; #define TIMER_TOC(t) timers_toc(t, tic) #define TIMER_TIC2 ticks tic2 = getticks(); #define TIMER_TOC2(t) timers_toc(t, tic2) -INLINE static ticks timers_toc(int t, ticks tic) { +INLINE static ticks timers_toc(unsigned int t, ticks tic) { ticks d = (getticks() - tic); atomic_add(&timers[t], d); return d; @@ -87,6 +91,6 @@ INLINE static ticks timers_toc(int t, ticks tic) { #endif /* Function prototypes. */ -void timers_reset(unsigned int mask); +void timers_reset(unsigned long long mask); #endif /* SWIFT_TIMERS_H */ diff --git a/src/tools.c b/src/tools.c index 148af4f612fd05d3724787c2908c0f229d3867c5..060bf1439f30dc6237938c060bc4ddc8d9be822b 100644 --- a/src/tools.c +++ b/src/tools.c @@ -442,43 +442,6 @@ void pairs_single_grav(double *dim, long long int pid, aabs[2]); } -/** - * @brief Test the density function by dumping it for two random parts. - * - * @param N number of intervals in [0,1]. - */ -void density_dump(int N) { - - int k; - float r2[4] = {0.0f, 0.0f, 0.0f, 0.0f}, hi[4], hj[4]; - struct part /**pi[4], *pj[4],*/ Pi[4], Pj[4]; - - /* Init the interaction parameters. */ - for (k = 0; k < 4; k++) { - Pi[k].mass = 1.0f; - Pi[k].rho = 0.0f; - Pi[k].density.wcount = 0.0f; - Pi[k].id = k; - Pj[k].mass = 1.0f; - Pj[k].rho = 0.0f; - Pj[k].density.wcount = 0.0f; - Pj[k].id = k + 4; - hi[k] = 1.0; - hj[k] = 1.0; - } - - for (k = 0; k <= N; k++) { - r2[3] = r2[2]; - r2[2] = r2[1]; - r2[1] = r2[0]; - r2[0] = ((float)k) / N; - Pi[0].density.wcount = 0; - Pj[0].density.wcount = 0; - runner_iact_density(r2[0], NULL, hi[0], hj[0], &Pi[0], &Pj[0]); - printf(" %e %e %e", r2[0], Pi[0].density.wcount, Pj[0].density.wcount); - } -} - /** * @brief Compute the force on a single particle brute-force. */ @@ -520,7 +483,7 @@ void engine_single_density(double *dim, long long int pid, /* Dump the result. */ hydro_end_density(&p, 0); message("part %lli (h=%e) has wcount=%e, rho=%e.", p.id, p.h, - p.density.wcount, p.rho); + p.density.wcount, hydro_get_density(&p)); fflush(stdout); } diff --git a/src/units.c b/src/units.c index 5c262ae03639262dfa126b101402b8fbfe41259a..f598b5ddf0b1a4b165648d5378915cd6f10f0bba 100644 --- a/src/units.c +++ b/src/units.c @@ -316,6 +316,10 @@ void units_get_base_unit_exponants_array(float baseUnitsExp[5], case UNIT_CONV_TEMPERATURE: baseUnitsExp[UNIT_TEMPERATURE] = 1.f; + break; + + case UNIT_CONV_VOLUME: + baseUnitsExp[UNIT_LENGTH] = -3.f; } } diff --git a/src/units.h b/src/units.h index c67f6ebbab324e3c90ae86eb1ea11dcf013c5dc7..d189933993fdb195120d5b961c60211fef51b1d1 100644 --- a/src/units.h +++ b/src/units.h @@ -89,7 +89,8 @@ enum UnitConversionFactor { UNIT_CONV_MAGNETIC_FLUX, UNIT_CONV_MAGNETIC_FIELD, UNIT_CONV_MAGNETIC_INDUCTANCE, - UNIT_CONV_TEMPERATURE + UNIT_CONV_TEMPERATURE, + UNIT_CONV_VOLUME }; void units_init_cgs(struct UnitSystem*); diff --git a/tests/Makefile.am b/tests/Makefile.am index 952787823d08772b79b4d69d0c8b3728d79e4bfd..5648c9a3ca0c3f944982b31060cfe9a0e9c3e45d 100644 --- a/tests/Makefile.am +++ b/tests/Makefile.am @@ -24,13 +24,16 @@ AM_LDFLAGS = ../src/.libs/libswiftsim.a $(HDF5_LDFLAGS) $(HDF5_LIBS) $(FFTW_LIBS TESTS = testGreetings testMaths testReading.sh testSingle testKernel testSymmetry \ testPair.sh testPairPerturbed.sh test27cells.sh test27cellsPerturbed.sh \ testParser.sh testSPHStep test125cells.sh testKernelGrav testFFT \ - testThreadpool + testAdiabaticIndex testRiemannExact testRiemannTRRS testRiemannHLLC \ + testMatrixInversion testThreadpool # List of test programs to compile check_PROGRAMS = testGreetings testReading testSingle testTimeIntegration \ testSPHStep testPair test27cells test125cells testParser \ testKernel testKernelGrav testFFT testInteractions testMaths \ - testSymmetry testThreadpool + testSymmetry testThreadpool \ + testAdiabaticIndex testRiemannExact testRiemannTRRS \ + testRiemannHLLC testMatrixInversion # Sources for the individual programs testGreetings_SOURCES = testGreetings.c @@ -63,6 +66,16 @@ testFFT_SOURCES = testFFT.c testInteractions_SOURCES = testInteractions.c +testAdiabaticIndex_SOURCES = testAdiabaticIndex.c + +testRiemannExact_SOURCES = testRiemannExact.c + +testRiemannTRRS_SOURCES = testRiemannTRRS.c + +testRiemannHLLC_SOURCES = testRiemannHLLC.c + +testMatrixInversion_SOURCES = testMatrixInversion.c + testThreadpool_SOURCES = testThreadpool.c # Files necessary for distribution diff --git a/tests/test125cells.c b/tests/test125cells.c index b34ae02eadae494ca45c58f05e8999b0d5d34cf2..f3d02a68b4ae1e89ebd88ddd988b9be96c8c36ac 100644 --- a/tests/test125cells.c +++ b/tests/test125cells.c @@ -99,6 +99,8 @@ void set_energy_state(struct part *part, enum pressure_field press, float size, part->u = pressure / (hydro_gamma_minus_one * density); #elif defined(MINIMAL_SPH) part->u = pressure / (hydro_gamma_minus_one * density); +#elif defined(GIZMO_SPH) + part->primitives.P = pressure; #else error("Need to define pressure here !"); #endif @@ -193,6 +195,23 @@ void reset_particles(struct cell *c, enum velocity_field vel, set_velocity(p, vel, size); set_energy_state(p, press, size, density); + +#if defined(GIZMO_SPH) + p->geometry.volume = p->conserved.mass / density; + p->primitives.rho = density; + p->primitives.v[0] = p->v[0]; + p->primitives.v[1] = p->v[1]; + p->primitives.v[2] = p->v[2]; + p->conserved.momentum[0] = p->conserved.mass * p->v[0]; + p->conserved.momentum[1] = p->conserved.mass * p->v[1]; + p->conserved.momentum[2] = p->conserved.mass * p->v[2]; + p->conserved.energy = + p->primitives.P / hydro_gamma_minus_one * p->geometry.volume + + 0.5f * (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; +#endif } } @@ -238,7 +257,12 @@ struct cell *make_cell(size_t n, const double offset[3], double size, double h, part->x[1] = offset[1] + size * (y + 0.5) / (float)n; part->x[2] = offset[2] + size * (z + 0.5) / (float)n; part->h = size * h / (float)n; + +#ifdef GIZMO_SPH + part->conserved.mass = density * volume / count; +#else part->mass = density * volume / count; +#endif set_velocity(part, vel, size); set_energy_state(part, press, size, density); @@ -248,6 +272,24 @@ struct cell *make_cell(size_t n, const double offset[3], double size, double h, part->ti_end = 1; hydro_first_init_part(part, xpart); + +#if defined(GIZMO_SPH) + part->geometry.volume = part->conserved.mass / density; + part->primitives.rho = density; + part->primitives.v[0] = part->v[0]; + part->primitives.v[1] = part->v[1]; + part->primitives.v[2] = part->v[2]; + part->conserved.momentum[0] = part->conserved.mass * part->v[0]; + part->conserved.momentum[1] = part->conserved.mass * part->v[1]; + part->conserved.momentum[2] = part->conserved.mass * part->v[2]; + part->conserved.energy = + part->primitives.P / hydro_gamma_minus_one * part->geometry.volume + + 0.5f * (part->conserved.momentum[0] * part->conserved.momentum[0] + + part->conserved.momentum[1] * part->conserved.momentum[1] + + part->conserved.momentum[2] * part->conserved.momentum[2]) / + part->conserved.mass; +#endif + ++part; ++xpart; } @@ -313,7 +355,7 @@ void dump_particle_fields(char *fileName, struct cell *main_cell, main_cell->parts[pid].x[1], main_cell->parts[pid].x[2], main_cell->parts[pid].v[0], main_cell->parts[pid].v[1], main_cell->parts[pid].v[2], main_cell->parts[pid].h, - main_cell->parts[pid].rho, + hydro_get_density(&main_cell->parts[pid]), #ifdef MINIMAL_SPH 0.f, #else diff --git a/tests/test27cells.c b/tests/test27cells.c index 3df058011092661502f32886632e63cf8f61c7a1..739d31623168b0933dd9aaa7d6ed44e34a9ace07 100644 --- a/tests/test27cells.c +++ b/tests/test27cells.c @@ -104,7 +104,11 @@ struct cell *make_cell(size_t n, double *offset, double size, double h, } part->h = size * h / (float)n; part->id = ++(*partId); +#ifdef GIZMO_SPH + part->conserved.mass = density * volume / count; +#else part->mass = density * volume / count; +#endif part->ti_begin = 0; part->ti_end = 1; ++part; @@ -184,7 +188,7 @@ void dump_particle_fields(char *fileName, struct cell *main_cell, main_cell->parts[pid].id, main_cell->parts[pid].x[0], main_cell->parts[pid].x[1], main_cell->parts[pid].x[2], main_cell->parts[pid].v[0], main_cell->parts[pid].v[1], - main_cell->parts[pid].v[2], main_cell->parts[pid].rho, + main_cell->parts[pid].v[2], hydro_get_density(&main_cell->parts[pid]), #if defined(GIZMO_SPH) 0.f, #else @@ -226,7 +230,7 @@ void dump_particle_fields(char *fileName, struct cell *main_cell, "%13e %13e %13e\n", cj->parts[pjd].id, cj->parts[pjd].x[0], cj->parts[pjd].x[1], cj->parts[pjd].x[2], cj->parts[pjd].v[0], cj->parts[pjd].v[1], - cj->parts[pjd].v[2], cj->parts[pjd].rho, + cj->parts[pjd].v[2], hydro_get_density(&cj->parts[pjd]), #if defined(GIZMO_SPH) 0.f, #else diff --git a/tests/testAdiabaticIndex.c b/tests/testAdiabaticIndex.c new file mode 100644 index 0000000000000000000000000000000000000000..e0c8c4f54bd2d6e5ddadb25bc44b96f1ca19aad2 --- /dev/null +++ b/tests/testAdiabaticIndex.c @@ -0,0 +1,116 @@ +/******************************************************************************* + * This file is part of SWIFT. + * Copyright (C) 2016 Bert Vandenbroucke (bert.vandenbroucke@gmail.com). + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published + * by the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this program. If not, see <http://www.gnu.org/licenses/>. + * + ******************************************************************************/ + +#include "adiabatic_index.h" +#include "error.h" + +/** + * @brief Check that a and b are consistent (up to some absolute error) + * + * @param a First value + * @param b Second value + * @param s String used to identify this check in messages + */ +void check_value(float a, float b, const char* s) { + if (fabsf(a - b) > 1.e-5f) { + error("Values are inconsistent: %g %g (%s)!", a, b, s); + } else { + message("Values are consistent: %g %g (%s).", a, b, s); + } +} + +/** + * @brief Check that the pre-defined adiabatic index constants contain correct + * values + */ +void check_constants() { + float val; + + val = 0.5 * (hydro_gamma + 1.0f) / hydro_gamma; + check_value(val, hydro_gamma_plus_one_over_two_gamma, "(gamma+1)/(2 gamma)"); + + val = 0.5 * (hydro_gamma - 1.0f) / hydro_gamma; + check_value(val, hydro_gamma_minus_one_over_two_gamma, "(gamma-1)/(2 gamma)"); + + val = (hydro_gamma - 1.0f) / (hydro_gamma + 1.0f); + check_value(val, hydro_gamma_minus_one_over_gamma_plus_one, + "(gamma-1)/(gamma+1)"); + + val = 2.0f / (hydro_gamma + 1.0f); + check_value(val, hydro_two_over_gamma_plus_one, "2/(gamma+1)"); + + val = 2.0f / (hydro_gamma - 1.0f); + check_value(val, hydro_two_over_gamma_minus_one, "2/(gamma-1)"); + + val = 0.5f * (hydro_gamma - 1.0f); + check_value(val, hydro_gamma_minus_one_over_two, "(gamma-1)/2"); + + val = 2.0f * hydro_gamma / (hydro_gamma - 1.0f); + check_value(val, hydro_two_gamma_over_gamma_minus_one, "(2 gamma)/(gamma-1)"); + + val = 1.0f / hydro_gamma; + check_value(val, hydro_one_over_gamma, "1/gamma"); +} + +/** + * @brief Check that the adiabatic index power functions return the correct + * values + */ +void check_functions() { + float val_a, val_b; + const float x = 0.4; + + val_a = pow(x, -hydro_gamma); + val_b = pow_minus_gamma(x); + check_value(val_a, val_b, "x^(-gamma)"); + + val_a = pow(x, 2.0f / (hydro_gamma - 1.0f)); + val_b = pow_two_over_gamma_minus_one(x); + check_value(val_a, val_b, "x^(2/(gamma-1))"); + + val_a = pow(x, 2.0f * hydro_gamma / (hydro_gamma - 1.0f)); + val_b = pow_two_gamma_over_gamma_minus_one(x); + check_value(val_a, val_b, "x^((2 gamma)/(gamma-1))"); + + val_a = pow(x, 0.5f * (hydro_gamma - 1.0f) / hydro_gamma); + val_b = pow_gamma_minus_one_over_two_gamma(x); + check_value(val_a, val_b, "x^((gamma-1)/(2 gamma))"); + + val_a = pow(x, -0.5f * (hydro_gamma + 1.0f) / hydro_gamma); + val_b = pow_minus_gamma_plus_one_over_two_gamma(x); + check_value(val_a, val_b, "x^(-(gamma+1)/(2 gamma))"); + + val_a = pow(x, 1.0f / hydro_gamma); + val_b = pow_one_over_gamma(x); + check_value(val_a, val_b, "x^(1/gamma)"); +} + +/** + * @brief Check adiabatic index constants and power functions + */ +int main() { + + /* check the values of the adiabatic index constants */ + check_constants(); + + /* check the adiabatic index power functions */ + check_functions(); + + return 0; +} diff --git a/tests/testMatrixInversion.c b/tests/testMatrixInversion.c new file mode 100644 index 0000000000000000000000000000000000000000..9a45cd52d6f5d3ec96cc6d3f34fd683971f4cf19 --- /dev/null +++ b/tests/testMatrixInversion.c @@ -0,0 +1,125 @@ +/******************************************************************************* + * This file is part of SWIFT. + * Copyright (C) 2016 Bert Vandenbroucke (bert.vandenbroucke@gmail.com). + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published + * by the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this program. If not, see <http://www.gnu.org/licenses/>. + * + ******************************************************************************/ + +#include <stdlib.h> +#include <string.h> +#include "const.h" +#include "dimension.h" +#include "error.h" +#include "tools.h" + +void setup_matrix(float A[3][3]) { + A[0][0] = random_uniform(-1.0, 1.0); + A[0][1] = random_uniform(-1.0, 1.0); + A[0][2] = random_uniform(-1.0, 1.0); + A[1][0] = random_uniform(-1.0, 1.0); + A[1][1] = random_uniform(-1.0, 1.0); + A[1][2] = random_uniform(-1.0, 1.0); + A[2][0] = random_uniform(-1.0, 1.0); + A[2][1] = random_uniform(-1.0, 1.0); + A[2][2] = random_uniform(-1.0, 1.0); +} + +int is_unit_matrix(float A[3][3]) { + int check = 1; + + check &= (fabsf(A[0][0] - 1.0f) < 1.e-6f); + +#if defined(HYDRO_DIMENSION_2D) && defined(HYDRO_DIMENSION_3D) + check &= (fabsf(A[0][1]) < 1.e-6f); + check &= (fabsf(A[1][0]) < 1.e-6f); + check &= (fabsf(A[1][1] - 1.0f) < 1.e-6f); +#if defined(HYDRO_DIMENSION_3D) + check &= (fabsf(A[0][2]) < 1.e-6f); + check &= (fabsf(A[1][2]) < 1.e-6f); + check &= (fabsf(A[2][0]) < 1.e-6f); + check &= (fabsf(A[2][1]) < 1.e-6f); + check &= (fabsf(A[2][2] - 1.0f) < 1.e-6f); +#endif // 3D +#endif // 2D and 3D + + return check; +} + +void print_matrix(float A[3][3], const char* s) { + message("Matrix %s:", s); +#if defined(HYDRO_DIMENSION_1D) + message("[%.3e]", A[0][0]); +#elif defined(HYDRO_DIMENSION_2D) + message("[%.3e, %.3e]", A[0][0], A[0][1]); + message("[%.3e, %.3e]", A[1][0], A[1][1]); +#elif defined(HYDRO_DIMENSION_3D) + message("[%.8e, %.8e, %.8e]", A[0][0], A[0][1], A[0][2]); + message("[%.8e, %.8e, %.8e]", A[1][0], A[1][1], A[1][2]); + message("[%.8e, %.8e, %.8e]", A[2][0], A[2][1], A[2][2]); +#endif +} + +void multiply_matrices(float A[3][3], float B[3][3], float C[3][3]) { +#if defined(HYDRO_DIMENSION_1D) + C[0][0] = A[0][0] * B[0][0]; +#elif defined(HYDRO_DIMENSION_2D) + for (int i = 0; i < 2; ++i) { + for (int j = 0; j < 2; ++j) { + C[i][j] = 0.0f; + for (int k = 0; k < 2; ++k) { + C[i][j] += A[i][k] * B[k][j]; + } + } + } +#elif defined(HYDRO_DIMENSION_3D) + for (int i = 0; i < 3; ++i) { + for (int j = 0; j < 3; ++j) { + C[i][j] = 0.0f; + for (int k = 0; k < 3; ++k) { + C[i][j] += A[i][k] * B[k][j]; + } + } + } +#endif +} + +int main() { + + float A[3][3], B[3][3], C[3][3]; + setup_matrix(A); + + memcpy(B, A, 9 * sizeof(float)); + + for (int i = 0; i < 3; ++i) { + for (int j = 0; j < 3; ++j) { + if (A[i][j] != B[i][j]) { + error("Matrices not equal after copy!"); + } + } + } + + invert_dimension_by_dimension_matrix(A); + + multiply_matrices(A, B, C); + + if (!is_unit_matrix(C)) { + print_matrix(A, "A"); + print_matrix(B, "B"); + print_matrix(C, "C"); + error("Inverted matrix is wrong!"); + } + + return 0; +} diff --git a/tests/testPair.c b/tests/testPair.c index a1173e41f12ba4fbca0d3baaab0a49d12cbf587b..a77409eeeb763c3ca0fd002783784c4796600e6e 100644 --- a/tests/testPair.c +++ b/tests/testPair.c @@ -63,7 +63,11 @@ struct cell *make_cell(size_t n, double *offset, double size, double h, part->v[2] = random_uniform(-0.05, 0.05); part->h = size * h / (float)n; part->id = ++(*partId); +#ifdef GIZMO_SPH + part->conserved.mass = density * volume / count; +#else part->mass = density * volume / count; +#endif part->ti_begin = 0; part->ti_end = 1; ++part; @@ -131,7 +135,7 @@ void dump_particle_fields(char *fileName, struct cell *ci, struct cell *cj) { "%13e %13e %13e\n", ci->parts[pid].id, ci->parts[pid].x[0], ci->parts[pid].x[1], ci->parts[pid].x[2], ci->parts[pid].v[0], ci->parts[pid].v[1], - ci->parts[pid].v[2], ci->parts[pid].rho, + ci->parts[pid].v[2], hydro_get_density(&ci->parts[pid]), #if defined(GIZMO_SPH) 0.f, #else @@ -155,7 +159,7 @@ void dump_particle_fields(char *fileName, struct cell *ci, struct cell *cj) { "%13e %13e %13e\n", cj->parts[pjd].id, cj->parts[pjd].x[0], cj->parts[pjd].x[1], cj->parts[pjd].x[2], cj->parts[pjd].v[0], cj->parts[pjd].v[1], - cj->parts[pjd].v[2], cj->parts[pjd].rho, + cj->parts[pjd].v[2], hydro_get_density(&cj->parts[pjd]), #if defined(GIZMO_SPH) 0.f, #else diff --git a/tests/testReading.c b/tests/testReading.c index 1824ad8992c12bd2a2e8f9b721d89b1fab708501..2ef32a5ef11c7e24a379ce5131df9cbea153fa7c 100644 --- a/tests/testReading.c +++ b/tests/testReading.c @@ -62,7 +62,7 @@ int main() { assert(index < Ngas); /* Check masses */ - float mass = parts[n].mass; + float mass = hydro_get_mass(&parts[n]); float correct_mass = boxSize * boxSize * boxSize * rho / Ngas; assert(mass == correct_mass); diff --git a/tests/testRiemannExact.c b/tests/testRiemannExact.c new file mode 100644 index 0000000000000000000000000000000000000000..1943820339ba2ac06d194a17d2d450157ded1a31 --- /dev/null +++ b/tests/testRiemannExact.c @@ -0,0 +1,338 @@ +/******************************************************************************* + * This file is part of SWIFT. + * Copyright (C) 2016 Bert Vandenbroucke (bert.vandenbroucke@gmail.com). + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published + * by the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this program. If not, see <http://www.gnu.org/licenses/>. + * + ******************************************************************************/ + +#include <string.h> +#include "error.h" +#include "riemann/riemann_exact.h" +#include "tools.h" + +int opposite(float a, float b) { + if ((a - b)) { + return fabs((a + b) / (a - b)) < 1.e-4; + } else { + return a == 0.0f; + } +} + +int equal(float a, float b) { + if ((a + b)) { + return fabs((a - b) / (a + b)) < 1.e-4; + } else { + return a == 0.0f; + } +} + +/** + * @brief Check that a and b are consistent (up to some error) + * + * @param a First value + * @param b Second value + * @param s String used to identify this check in messages + */ +void check_value(float a, float b, const char* s) { + if (fabsf(a - b) / fabsf(a + b) > 1.e-5f && fabsf(a - b) > 1.e-5f) { + error("Values are inconsistent: %g %g (%s)!", a, b, s); + } else { + message("Values are consistent: %g %g (%s).", a, b, s); + } +} + +struct riemann_statevector { + /*! @brief Density */ + float rho; + + /*! @brief Fluid velocity */ + float v; + + /*! @brief Pressure */ + float P; +}; + +/** + * @brief Check that the solution to the Riemann problem with given left and + * right state is consistent with the given expected solution + * + * @param WL Left state + * @param WR Right state + * @param Whalf Expected solution + * @param s String used to identify this check in messages + */ +void check_riemann_solution(struct riemann_statevector* WL, + struct riemann_statevector* WR, + struct riemann_statevector* Whalf, const char* s) { + float WLarr[5], WRarr[5], Whalfarr[5], n_unit[3]; + + n_unit[0] = 1.0f; + n_unit[1] = 0.0f; + n_unit[2] = 0.0f; + + WLarr[0] = WL->rho; + WLarr[1] = WL->v; + WLarr[2] = 0.0f; + WLarr[3] = 0.0f; + WLarr[4] = WL->P; + + WRarr[0] = WR->rho; + WRarr[1] = WR->v; + WRarr[2] = 0.0f; + WRarr[3] = 0.0f; + WRarr[4] = WR->P; + + riemann_solver_solve(WLarr, WRarr, Whalfarr, n_unit); + + message("Checking %s...", s); + check_value(Whalfarr[0], Whalf->rho, "rho"); + check_value(Whalfarr[1], Whalf->v, "v"); + check_value(Whalfarr[4], Whalf->P, "P"); +} + +/** + * @brief Check the exact Riemann solver on the Toro test problems + */ +void check_riemann_exact() { + struct riemann_statevector WL, WR, Whalf; + + /* Test 1 */ + WL.rho = 1.0f; + WL.v = 0.0f; + WL.P = 1.0f; + WR.rho = 0.125f; + WR.v = 0.0f; + WR.P = 0.1f; +#if defined(HYDRO_GAMMA_5_3) + Whalf.rho = 0.47969f; + Whalf.v = 0.841194f; + Whalf.P = 0.293945f; +#elif defined(HYDRO_GAMMA_4_3) + Whalf.rho = 0.411437f; + Whalf.v = 0.953205f; + Whalf.P = 0.306011f; +#elif defined(HYDRO_GAMMA_2_1) + Whalf.rho = 0.534767f; + Whalf.v = 0.760062f; + Whalf.P = 0.285975f; +#else +#error "Unsupported adiabatic index!" +#endif + check_riemann_solution(&WL, &WR, &Whalf, "Test 1"); + + /* Test 2 */ + WL.rho = 1.0f; + WL.v = -2.0f; + WL.P = 0.4f; + WR.rho = 1.0f; + WR.v = 2.0f; + WR.P = 0.4f; +#if defined(HYDRO_GAMMA_5_3) + Whalf.rho = 0.00617903f; + Whalf.v = 0.0f; + Whalf.P = 8.32249e-5f; +#elif defined(HYDRO_GAMMA_4_3) + Whalf.rho = 0.0257933f; + Whalf.v = 0.0f; + Whalf.P = 0.00304838f; +#elif defined(HYDRO_GAMMA_2_1) + Whalf.rho = 0.0f; + Whalf.v = 0.0f; + Whalf.P = 0.0f; +#else +#error "Unsupported adiabatic index!" +#endif + check_riemann_solution(&WL, &WR, &Whalf, "Test 2"); + + /* Test 3 */ + WL.rho = 1.0f; + WL.v = 0.0f; + WL.P = 1000.0f; + WR.rho = 1.0f; + WR.v = 0.0f; + WR.P = 0.01f; +#if defined(HYDRO_GAMMA_5_3) + Whalf.rho = 0.615719f; + Whalf.v = 18.2812f; + Whalf.P = 445.626f; +#elif defined(HYDRO_GAMMA_4_3) + Whalf.rho = 0.563517f; + Whalf.v = 19.9735f; + Whalf.P = 465.453f; +#elif defined(HYDRO_GAMMA_2_1) + Whalf.rho = 0.656768f; + Whalf.v = 16.9572f; + Whalf.P = 431.345f; +#else +#error "Unsupported adiabatic index!" +#endif + check_riemann_solution(&WL, &WR, &Whalf, "Test 3"); + + /* Test 4 */ + WL.rho = 1.0f; + WL.v = 0.0f; + WL.P = 0.01f; + WR.rho = 1.0f; + WR.v = 0.0f; + WR.P = 100.0f; +#if defined(HYDRO_GAMMA_5_3) + Whalf.rho = 0.61577f; + Whalf.v = -5.78022f; + Whalf.P = 44.5687f; +#elif defined(HYDRO_GAMMA_4_3) + Whalf.rho = 0.563567f; + Whalf.v = -6.31525f; + Whalf.P = 46.5508f; +#elif defined(HYDRO_GAMMA_2_1) + Whalf.rho = 0.656819f; + Whalf.v = -5.36146f; + Whalf.P = 43.1412f; +#else +#error "Unsupported adiabatic index!" +#endif + check_riemann_solution(&WL, &WR, &Whalf, "Test 4"); + + /* Test 5 */ + WL.rho = 5.99924f; + WL.v = 19.5975f; + WL.P = 460.894f; + WR.rho = 5.99242f; + WR.v = -6.19633f; + WR.P = 46.0950f; +#if defined(HYDRO_GAMMA_5_3) + Whalf.rho = 12.743f; + Whalf.v = 8.56045f; + Whalf.P = 1841.82f; +#elif defined(HYDRO_GAMMA_4_3) + Whalf.rho = 5.99924f; + Whalf.v = 19.5975f; + Whalf.P = 460.894f; +#elif defined(HYDRO_GAMMA_2_1) + Whalf.rho = 11.5089f; + Whalf.v = 8.42099f; + Whalf.P = 2026.27f; +#else +#error "Unsupported adiabatic index!" +#endif + check_riemann_solution(&WL, &WR, &Whalf, "Test 5"); +} + +/** + * @brief Check the symmetry of the TRRS Riemann solver + */ +void check_riemann_symmetry() { + float WL[5], WR[5], Whalf1[5], Whalf2[5], n_unit1[3], n_unit2[3], n_norm, + vij[3], totflux1[5], totflux2[5]; + + WL[0] = random_uniform(0.1f, 1.0f); + WL[1] = random_uniform(-10.0f, 10.0f); + WL[2] = random_uniform(-10.0f, 10.0f); + WL[3] = random_uniform(-10.0f, 10.0f); + WL[4] = random_uniform(0.1f, 1.0f); + WR[0] = random_uniform(0.1f, 1.0f); + WR[1] = random_uniform(-10.0f, 10.0f); + WR[2] = random_uniform(-10.0f, 10.0f); + WR[3] = random_uniform(-10.0f, 10.0f); + WR[4] = random_uniform(0.1f, 1.0f); + + n_unit1[0] = random_uniform(-1.0f, 1.0f); + n_unit1[1] = random_uniform(-1.0f, 1.0f); + n_unit1[2] = random_uniform(-1.0f, 1.0f); + + n_norm = sqrtf(n_unit1[0] * n_unit1[0] + n_unit1[1] * n_unit1[1] + + n_unit1[2] * n_unit1[2]); + n_unit1[0] /= n_norm; + n_unit1[1] /= n_norm; + n_unit1[2] /= n_norm; + + n_unit2[0] = -n_unit1[0]; + n_unit2[1] = -n_unit1[1]; + n_unit2[2] = -n_unit1[2]; + + riemann_solver_solve(WL, WR, Whalf1, n_unit1); + riemann_solver_solve(WR, WL, Whalf2, n_unit2); + + if (!equal(Whalf1[0], Whalf2[0]) || !equal(Whalf1[1], Whalf2[1]) || + !equal(Whalf1[2], Whalf2[2]) || !equal(Whalf1[3], Whalf2[3]) || + !equal(Whalf1[4], Whalf2[4])) { + message( + "Solver asymmetric: [%.3e,%.3e,%.3e,%.3e,%.3e] == " + "[%.3e,%.3e,%.3e,%.3e,%.3e]\n", + Whalf1[0], Whalf1[1], Whalf1[2], Whalf1[3], Whalf1[4], Whalf2[0], + Whalf2[1], Whalf2[2], Whalf2[3], Whalf2[4]); + message("Asymmetry in solution!\n"); + /* This asymmetry is to be expected, since we do an iteration. Are the + results at least consistent? */ + check_value(Whalf1[0], Whalf2[0], "Rho solution"); + check_value(Whalf1[1], Whalf2[1], "V[0] solution"); + check_value(Whalf1[2], Whalf2[2], "V[1] solution"); + check_value(Whalf1[3], Whalf2[3], "V[2] solution"); + check_value(Whalf1[4], Whalf2[4], "Pressure solution"); + } else { + message( + "Solver symmetric: [%.3e,%.3e,%.3e,%.3e,%.3e] == " + "[%.3e,%.3e,%.3e,%.3e,%.3e]\n", + Whalf1[0], Whalf1[1], Whalf1[2], Whalf1[3], Whalf1[4], Whalf2[0], + Whalf2[1], Whalf2[2], Whalf2[3], Whalf2[4]); + } + + vij[0] = random_uniform(-10.0f, 10.0f); + vij[1] = random_uniform(-10.0f, 10.0f); + vij[2] = random_uniform(-10.0f, 10.0f); + + riemann_solve_for_flux(WL, WR, n_unit1, vij, totflux1); + riemann_solve_for_flux(WR, WL, n_unit2, vij, totflux2); + + if (!opposite(totflux1[0], totflux2[0]) || + !opposite(totflux1[1], totflux2[1]) || + !opposite(totflux1[2], totflux2[2]) || + !opposite(totflux1[3], totflux2[3]) || + !opposite(totflux1[4], totflux2[4])) { + message( + "Flux solver asymmetric: [%.3e,%.3e,%.3e,%.3e,%.3e] == " + "[%.3e,%.3e,%.3e,%.3e,%.3e]\n", + totflux1[0], totflux1[1], totflux1[2], totflux1[3], totflux1[4], + totflux2[0], totflux2[1], totflux2[2], totflux2[3], totflux2[4]); + message("Asymmetry in flux solution!"); + /* This asymmetry is to be expected, since we do an iteration. Are the + results at least consistent? */ + check_value(totflux1[0], totflux2[0], "Mass flux"); + check_value(totflux1[1], totflux2[1], "Momentum[0] flux"); + check_value(totflux1[2], totflux2[2], "Momentum[1] flux"); + check_value(totflux1[3], totflux2[3], "Momentum[2] flux"); + check_value(totflux1[4], totflux2[4], "Energy flux"); + } else { + message( + "Flux solver symmetric: [%.3e,%.3e,%.3e,%.3e,%.3e] == " + "[%.3e,%.3e,%.3e,%.3e,%.3e]\n", + totflux1[0], totflux1[1], totflux1[2], totflux1[3], totflux1[4], + totflux2[0], totflux2[1], totflux2[2], totflux2[3], totflux2[4]); + } +} + +/** + * @brief Check the exact Riemann solver + */ +int main() { + + /* check the exact Riemann solver */ + check_riemann_exact(); + + /* symmetry test */ + int i; + for (i = 0; i < 100; ++i) check_riemann_symmetry(); + + return 0; +} diff --git a/tests/testRiemannHLLC.c b/tests/testRiemannHLLC.c new file mode 100644 index 0000000000000000000000000000000000000000..4cf883b68efbcfd795d0b7894adb9e7265b14d14 --- /dev/null +++ b/tests/testRiemannHLLC.c @@ -0,0 +1,96 @@ +/******************************************************************************* + * This file is part of SWIFT. + * Copyright (C) 2016 Bert Vandenbroucke (bert.vandenbroucke@gmail.com). + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published + * by the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this program. If not, see <http://www.gnu.org/licenses/>. + * + ******************************************************************************/ + +#include <string.h> +#include "error.h" +#include "riemann/riemann_hllc.h" +#include "tools.h" + +int consistent_with_zero(float val) { return fabs(val) < 1.e-4; } + +/** + * @brief Check the symmetry of the TRRS Riemann solver + */ +void check_riemann_symmetry() { + float WL[5], WR[5], n_unit1[3], n_unit2[3], n_norm, vij[3], totflux1[5], + totflux2[5]; + + WL[0] = random_uniform(0.1f, 1.0f); + WL[1] = random_uniform(-10.0f, 10.0f); + WL[2] = random_uniform(-10.0f, 10.0f); + WL[3] = random_uniform(-10.0f, 10.0f); + WL[4] = random_uniform(0.1f, 1.0f); + WR[0] = random_uniform(0.1f, 1.0f); + WR[1] = random_uniform(-10.0f, 10.0f); + WR[2] = random_uniform(-10.0f, 10.0f); + WR[3] = random_uniform(-10.0f, 10.0f); + WR[4] = random_uniform(0.1f, 1.0f); + + n_unit1[0] = random_uniform(-1.0f, 1.0f); + n_unit1[1] = random_uniform(-1.0f, 1.0f); + n_unit1[2] = random_uniform(-1.0f, 1.0f); + + n_norm = sqrtf(n_unit1[0] * n_unit1[0] + n_unit1[1] * n_unit1[1] + + n_unit1[2] * n_unit1[2]); + n_unit1[0] /= n_norm; + n_unit1[1] /= n_norm; + n_unit1[2] /= n_norm; + + n_unit2[0] = -n_unit1[0]; + n_unit2[1] = -n_unit1[1]; + n_unit2[2] = -n_unit1[2]; + + vij[0] = random_uniform(-10.0f, 10.0f); + vij[1] = random_uniform(-10.0f, 10.0f); + vij[2] = random_uniform(-10.0f, 10.0f); + + riemann_solve_for_flux(WL, WR, n_unit1, vij, totflux1); + riemann_solve_for_flux(WR, WL, n_unit2, vij, totflux2); + + if (!consistent_with_zero(totflux1[0] + totflux2[0]) || + !consistent_with_zero(totflux1[1] + totflux2[1]) || + !consistent_with_zero(totflux1[2] + totflux2[2]) || + !consistent_with_zero(totflux1[3] + totflux2[3]) || + !consistent_with_zero(totflux1[4] + totflux2[4])) { + message( + "Flux solver asymmetric: [%.3e,%.3e,%.3e,%.3e,%.3e] == " + "[%.3e,%.3e,%.3e,%.3e,%.3e]\n", + totflux1[0], totflux1[1], totflux1[2], totflux1[3], totflux1[4], + totflux2[0], totflux2[1], totflux2[2], totflux2[3], totflux2[4]); + error("Asymmetry in flux solution!"); + } else { + message( + "Flux solver symmetric: [%.3e,%.3e,%.3e,%.3e,%.3e] == " + "[%.3e,%.3e,%.3e,%.3e,%.3e]\n", + totflux1[0], totflux1[1], totflux1[2], totflux1[3], totflux1[4], + totflux2[0], totflux2[1], totflux2[2], totflux2[3], totflux2[4]); + } +} + +/** + * @brief Check the HLLC Riemann solver + */ +int main() { + + int i; + /* symmetry test */ + for (i = 0; i < 100; i++) check_riemann_symmetry(); + + return 0; +} diff --git a/tests/testRiemannTRRS.c b/tests/testRiemannTRRS.c new file mode 100644 index 0000000000000000000000000000000000000000..18ecbdce9173f43674a63b21231322cb01620d29 --- /dev/null +++ b/tests/testRiemannTRRS.c @@ -0,0 +1,324 @@ +/******************************************************************************* + * This file is part of SWIFT. + * Copyright (C) 2016 Bert Vandenbroucke (bert.vandenbroucke@gmail.com). + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published + * by the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this program. If not, see <http://www.gnu.org/licenses/>. + * + ******************************************************************************/ + +#include <string.h> +#include "error.h" +#include "riemann/riemann_trrs.h" +#include "tools.h" + +int opposite(float a, float b) { + if ((a - b)) { + return fabs((a + b) / (a - b)) < 1.e-4; + } else { + return a == 0.0f; + } +} + +int equal(float a, float b) { + if ((a + b)) { + return fabs((a - b) / (a + b)) < 1.e-4; + } else { + return a == 0.0f; + } +} + +/** + * @brief Check that a and b are consistent (up to some error) + * + * @param a First value + * @param b Second value + * @param s String used to identify this check in messages + */ +void check_value(float a, float b, const char* s) { + if (fabsf(a - b) / fabsf(a + b) > 1.e-5f && fabsf(a - b) > 1.e-5f) { + error("Values are inconsistent: %g %g (%s)!", a, b, s); + } else { + message("Values are consistent: %g %g (%s).", a, b, s); + } +} + +struct riemann_statevector { + /*! @brief Density */ + float rho; + + /*! @brief Fluid velocity */ + float v; + + /*! @brief Pressure */ + float P; +}; + +/** + * @brief Check that the solution to the Riemann problem with given left and + * right state is consistent with the given expected solution + * + * @param WL Left state + * @param WR Right state + * @param Whalf Expected solution + * @param s String used to identify this check in messages + */ +void check_riemann_solution(struct riemann_statevector* WL, + struct riemann_statevector* WR, + struct riemann_statevector* Whalf, const char* s) { + float WLarr[5], WRarr[5], Whalfarr[5], n_unit[3]; + + n_unit[0] = 1.0f; + n_unit[1] = 0.0f; + n_unit[2] = 0.0f; + + WLarr[0] = WL->rho; + WLarr[1] = WL->v; + WLarr[2] = 0.0f; + WLarr[3] = 0.0f; + WLarr[4] = WL->P; + + WRarr[0] = WR->rho; + WRarr[1] = WR->v; + WRarr[2] = 0.0f; + WRarr[3] = 0.0f; + WRarr[4] = WR->P; + + riemann_solver_solve(WLarr, WRarr, Whalfarr, n_unit); + + message("Checking %s...", s); + check_value(Whalfarr[0], Whalf->rho, "rho"); + check_value(Whalfarr[1], Whalf->v, "v"); + check_value(Whalfarr[4], Whalf->P, "P"); +} + +/** + * @brief Check the TRRS Riemann solver on the Toro test problems + */ +void check_riemann_trrs() { + struct riemann_statevector WL, WR, Whalf; + + /* Test 1 */ + WL.rho = 1.0f; + WL.v = 0.0f; + WL.P = 1.0f; + WR.rho = 0.125f; + WR.v = 0.0f; + WR.P = 0.1f; +#if defined(HYDRO_GAMMA_5_3) + Whalf.rho = 0.481167f; + Whalf.v = 0.838085f; + Whalf.P = 0.295456f; +#elif defined(HYDRO_GAMMA_4_3) + Whalf.rho = 0.41586f; + Whalf.v = 0.942546f; + Whalf.P = 0.310406f; +#elif defined(HYDRO_GAMMA_2_1) + Whalf.rho = 0.53478f; + Whalf.v = 0.760037f; + Whalf.P = 0.285989f; +#else +#error "Unsupported adiabatic index!" +#endif + check_riemann_solution(&WL, &WR, &Whalf, "Test 1"); + + /* Test 2 */ + WL.rho = 1.0f; + WL.v = -2.0f; + WL.P = 0.4f; + WR.rho = 1.0f; + WR.v = 2.0f; + WR.P = 0.4f; +#if defined(HYDRO_GAMMA_5_3) + Whalf.rho = 0.00617903f; + Whalf.v = 0.0f; + Whalf.P = 8.32249e-5f; +#elif defined(HYDRO_GAMMA_4_3) + Whalf.rho = 0.0257933f; + Whalf.v = 0.0f; + Whalf.P = 0.00304838f; +#elif defined(HYDRO_GAMMA_2_1) + Whalf.rho = 0.013932f; + Whalf.v = 0.0f; + Whalf.P = 7.76405e-5f; +#else +#error "Unsupported adiabatic index!" +#endif + check_riemann_solution(&WL, &WR, &Whalf, "Test 2"); + + /* Test 3 */ + WL.rho = 1.0f; + WL.v = 0.0f; + WL.P = 1000.0f; + WR.rho = 1.0f; + WR.v = 0.0f; + WR.P = 0.01f; +#if defined(HYDRO_GAMMA_5_3) + Whalf.rho = 0.919498f; + Whalf.v = 3.37884f; + Whalf.P = 869.464f; +#elif defined(HYDRO_GAMMA_4_3) + Whalf.rho = 0.941258f; + Whalf.v = 2.19945f; + Whalf.P = 922.454f; +#elif defined(HYDRO_GAMMA_2_1) + Whalf.rho = 0.902032f; + Whalf.v = 4.49417f; + Whalf.P = 813.662f; +#else +#error "Unsupported adiabatic index!" +#endif + check_riemann_solution(&WL, &WR, &Whalf, "Test 3"); + + /* Test 4 */ + WL.rho = 1.0f; + WL.v = 0.0f; + WL.P = 0.01f; + WR.rho = 1.0f; + WR.v = 0.0f; + WR.P = 100.0f; +#if defined(HYDRO_GAMMA_5_3) + Whalf.rho = 0.857525f; + Whalf.v = -1.93434f; + Whalf.P = 77.4007f; +#elif defined(HYDRO_GAMMA_4_3) + Whalf.rho = 0.880649f; + Whalf.v = -1.45215f; + Whalf.P = 84.4119f; +#elif defined(HYDRO_GAMMA_2_1) + Whalf.rho = 0.843058f; + Whalf.v = -2.31417f; + Whalf.P = 71.0747f; +#else +#error "Unsupported adiabatic index!" +#endif + check_riemann_solution(&WL, &WR, &Whalf, "Test 4"); + + /* Test 5 */ + WL.rho = 5.99924f; + WL.v = 19.5975f; + WL.P = 460.894f; + WR.rho = 5.99242f; + WR.v = -6.19633f; + WR.P = 46.0950f; +#if defined(HYDRO_GAMMA_5_3) + Whalf.rho = 5.99924f; + Whalf.v = 19.5975f; + Whalf.P = 460.894f; +#elif defined(HYDRO_GAMMA_4_3) + Whalf.rho = 5.99924f; + Whalf.v = 19.5975f; + Whalf.P = 460.894f; +#elif defined(HYDRO_GAMMA_2_1) + Whalf.rho = 5.99924f; + Whalf.v = 19.5975f; + Whalf.P = 460.894f; +#else +#error "Unsupported adiabatic index!" +#endif + check_riemann_solution(&WL, &WR, &Whalf, "Test 5"); +} + +/** + * @brief Check the symmetry of the TRRS Riemann solver + */ +void check_riemann_symmetry() { + float WL[5], WR[5], Whalf1[5], Whalf2[5], n_unit1[3], n_unit2[3], n_norm, + vij[3], totflux1[5], totflux2[5]; + + WL[0] = random_uniform(0.1f, 1.0f); + WL[1] = random_uniform(-10.0f, 10.0f); + WL[2] = random_uniform(-10.0f, 10.0f); + WL[3] = random_uniform(-10.0f, 10.0f); + WL[4] = random_uniform(0.1f, 1.0f); + WR[0] = random_uniform(0.1f, 1.0f); + WR[1] = random_uniform(-10.0f, 10.0f); + WR[2] = random_uniform(-10.0f, 10.0f); + WR[3] = random_uniform(-10.0f, 10.0f); + WR[4] = random_uniform(0.1f, 1.0f); + + n_unit1[0] = random_uniform(-1.0f, 1.0f); + n_unit1[1] = random_uniform(-1.0f, 1.0f); + n_unit1[2] = random_uniform(-1.0f, 1.0f); + + n_norm = sqrtf(n_unit1[0] * n_unit1[0] + n_unit1[1] * n_unit1[1] + + n_unit1[2] * n_unit1[2]); + n_unit1[0] /= n_norm; + n_unit1[1] /= n_norm; + n_unit1[2] /= n_norm; + + n_unit2[0] = -n_unit1[0]; + n_unit2[1] = -n_unit1[1]; + n_unit2[2] = -n_unit1[2]; + + riemann_solver_solve(WL, WR, Whalf1, n_unit1); + riemann_solver_solve(WR, WL, Whalf2, n_unit2); + + if (!equal(Whalf1[0], Whalf2[0]) || !equal(Whalf1[1], Whalf2[1]) || + !equal(Whalf1[2], Whalf2[2]) || !equal(Whalf1[3], Whalf2[3]) || + !equal(Whalf1[4], Whalf2[4])) { + message( + "Solver asymmetric: [%.3e,%.3e,%.3e,%.3e,%.3e] == " + "[%.3e,%.3e,%.3e,%.3e,%.3e]\n", + Whalf1[0], Whalf1[1], Whalf1[2], Whalf1[3], Whalf1[4], Whalf2[0], + Whalf2[1], Whalf2[2], Whalf2[3], Whalf2[4]); + error("Asymmetry in solution!"); + } else { + message( + "Solver symmetric: [%.3e,%.3e,%.3e,%.3e,%.3e] == " + "[%.3e,%.3e,%.3e,%.3e,%.3e]\n", + Whalf1[0], Whalf1[1], Whalf1[2], Whalf1[3], Whalf1[4], Whalf2[0], + Whalf2[1], Whalf2[2], Whalf2[3], Whalf2[4]); + } + + vij[0] = random_uniform(-10.0f, 10.0f); + vij[1] = random_uniform(-10.0f, 10.0f); + vij[2] = random_uniform(-10.0f, 10.0f); + + riemann_solve_for_flux(WL, WR, n_unit1, vij, totflux1); + riemann_solve_for_flux(WR, WL, n_unit2, vij, totflux2); + + if (!opposite(totflux1[0], totflux2[0]) || + !opposite(totflux1[1], totflux2[1]) || + !opposite(totflux1[2], totflux2[2]) || + !opposite(totflux1[3], totflux2[3]) || + !opposite(totflux1[4], totflux2[4])) { + message( + "Solver asymmetric: [%.3e,%.3e,%.3e,%.3e,%.3e] == " + "[%.3e,%.3e,%.3e,%.3e,%.3e]\n", + totflux1[0], totflux1[1], totflux1[2], totflux1[3], totflux1[4], + totflux2[0], totflux2[1], totflux2[2], totflux2[3], totflux2[4]); + error("Asymmetry in solution!"); + } else { + message( + "Solver symmetric: [%.3e,%.3e,%.3e,%.3e,%.3e] == " + "[%.3e,%.3e,%.3e,%.3e,%.3e]\n", + totflux1[0], totflux1[1], totflux1[2], totflux1[3], totflux1[4], + totflux2[0], totflux2[1], totflux2[2], totflux2[3], totflux2[4]); + } +} + +/** + * @brief Check the TRRS Riemann solver + */ +int main() { + + /* check the TRRS Riemann solver */ + check_riemann_trrs(); + + /* symmetry test */ + int i; + for (i = 0; i < 100; i++) check_riemann_symmetry(); + + return 0; +} diff --git a/tests/testSymmetry.c b/tests/testSymmetry.c index eb3fab6becca08e9ef87e7c60cc8c04bd2a0290c..6469d314fb8b1438cc2c9737669c1a13a97bd803 100644 --- a/tests/testSymmetry.c +++ b/tests/testSymmetry.c @@ -46,6 +46,55 @@ int main(int argc, char *argv[]) { pi.id = 1; pj.id = 2; +#if defined(GIZMO_SPH) + /* Give the primitive variables sensible values, since the Riemann solver does + not like negative densities and pressures */ + pi.primitives.rho = random_uniform(0.1f, 1.0f); + pi.primitives.v[0] = random_uniform(-10.0f, 10.0f); + pi.primitives.v[1] = random_uniform(-10.0f, 10.0f); + pi.primitives.v[2] = random_uniform(-10.0f, 10.0f); + pi.primitives.P = random_uniform(0.1f, 1.0f); + pj.primitives.rho = random_uniform(0.1f, 1.0f); + pj.primitives.v[0] = random_uniform(-10.0f, 10.0f); + pj.primitives.v[1] = random_uniform(-10.0f, 10.0f); + pj.primitives.v[2] = random_uniform(-10.0f, 10.0f); + pj.primitives.P = random_uniform(0.1f, 1.0f); + /* make gradients zero */ + pi.primitives.gradients.rho[0] = 0.0f; + pi.primitives.gradients.rho[1] = 0.0f; + pi.primitives.gradients.rho[2] = 0.0f; + pi.primitives.gradients.v[0][0] = 0.0f; + pi.primitives.gradients.v[0][1] = 0.0f; + pi.primitives.gradients.v[0][2] = 0.0f; + pi.primitives.gradients.v[1][0] = 0.0f; + pi.primitives.gradients.v[1][1] = 0.0f; + pi.primitives.gradients.v[1][2] = 0.0f; + pi.primitives.gradients.v[2][0] = 0.0f; + pi.primitives.gradients.v[2][1] = 0.0f; + pi.primitives.gradients.v[2][2] = 0.0f; + pi.primitives.gradients.P[0] = 0.0f; + pi.primitives.gradients.P[1] = 0.0f; + pi.primitives.gradients.P[2] = 0.0f; + pj.primitives.gradients.rho[0] = 0.0f; + pj.primitives.gradients.rho[1] = 0.0f; + pj.primitives.gradients.rho[2] = 0.0f; + pj.primitives.gradients.v[0][0] = 0.0f; + pj.primitives.gradients.v[0][1] = 0.0f; + pj.primitives.gradients.v[0][2] = 0.0f; + pj.primitives.gradients.v[1][0] = 0.0f; + pj.primitives.gradients.v[1][1] = 0.0f; + pj.primitives.gradients.v[1][2] = 0.0f; + pj.primitives.gradients.v[2][0] = 0.0f; + pj.primitives.gradients.v[2][1] = 0.0f; + pj.primitives.gradients.v[2][2] = 0.0f; + pj.primitives.gradients.P[0] = 0.0f; + pj.primitives.gradients.P[1] = 0.0f; + pj.primitives.gradients.P[2] = 0.0f; + /* set time step to reasonable value */ + pi.force.dt = 0.001; + pj.force.dt = 0.001; +#endif + /* Make an xpart companion */ struct xpart xpi, xpj; bzero(&xpi, sizeof(struct xpart)); @@ -100,12 +149,54 @@ int main(int argc, char *argv[]) { dx[2] = -dx[2]; runner_iact_nonsym_force(r2, dx, pj2.h, pi2.h, &pj2, &pi2); - /* Check that the particles are the same */ +/* Check that the particles are the same */ +#if defined(GIZMO_SPH) + i_ok = 0; + j_ok = 0; + for (size_t i = 0; i < sizeof(struct part) / sizeof(float); ++i) { + float a = *(((float *)&pi) + i); + float b = *(((float *)&pi2) + i); + float c = *(((float *)&pj) + i); + float d = *(((float *)&pj2) + i); + + int a_is_b; + if ((a + b)) { + a_is_b = (fabs((a - b) / (a + b)) > 1.e-4); + } else { + a_is_b = !(a == 0.0f); + } + int c_is_d; + if ((c + d)) { + c_is_d = (fabs((c - d) / (c + d)) > 1.e-4); + } else { + c_is_d = !(c == 0.0f); + } + + if (a_is_b) { + message("%.8e, %.8e, %lu", a, b, i); + } + if (c_is_d) { + message("%.8e, %.8e, %lu", c, d, i); + } + + i_ok |= a_is_b; + j_ok |= c_is_d; + } +#else i_ok = memcmp(&pi, &pi2, sizeof(struct part)); j_ok = memcmp(&pj, &pj2, sizeof(struct part)); +#endif - if (i_ok) error("Particles 'pi' do not match after force"); - if (j_ok) error("Particles 'pj' do not match after force"); + if (i_ok) { + printParticle_single(&pi, &xpi); + printParticle_single(&pi2, &xpi); + error("Particles 'pi' do not match after force"); + } + if (j_ok) { + printParticle_single(&pj, &xpj); + printParticle_single(&pj2, &xpj); + error("Particles 'pj' do not match after force"); + } return 0; } diff --git a/tests/testThreadpool.c b/tests/testThreadpool.c index 90ec58e10b16d816b52b785c87e6604ad11f61d8..aa65d533a29afbe4e7e8384fb887281822a31e58 100644 --- a/tests/testThreadpool.c +++ b/tests/testThreadpool.c @@ -77,4 +77,9 @@ int main(int argc, char *argv[]) { fflush(stdout); threadpool_map(&tp, map_function_first, data, N, sizeof(int), 2, NULL); } + + /* Be clean */ + threadpool_clean(&tp); + + return 0; }