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/configure.ac b/configure.ac index a798372c2f219a8da71f2b79321c140aba23e790..82382447fde7c411f61dbd62f7db388a6a8d9cf9 100644 --- a/configure.ac +++ b/configure.ac @@ -16,7 +16,7 @@ # along with this program. If not, see <http://www.gnu.org/licenses/>. # Init the project. -AC_INIT([SWIFT],[0.3.0]) +AC_INIT([SWIFT],[0.4.0]) AC_CONFIG_SRCDIR([src/space.c]) AC_CONFIG_AUX_DIR([.]) AM_INIT_AUTOMAKE @@ -466,7 +466,7 @@ if test "$enable_warn" != "no"; then # We will do this by hand instead and only default to the macro for unknown compilers case "$ax_cv_c_compiler_vendor" in gnu | clang) - CFLAGS="$CFLAGS -Wall" + CFLAGS="$CFLAGS -Wall -Wextra -Wno-unused-parameter" ;; intel) CFLAGS="$CFLAGS -w2 -Wunused-variable" diff --git a/examples/Disk-Patch/GravityOnly/makeIC.py b/examples/Disk-Patch/GravityOnly/makeIC.py index 135d1d4e34e0ec4c32d75a2c49d6e55f46db4e1c..702a50ff53b73d004ff36be8049823515675cccf 100644 --- a/examples/Disk-Patch/GravityOnly/makeIC.py +++ b/examples/Disk-Patch/GravityOnly/makeIC.py @@ -110,7 +110,7 @@ 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] - +grp.attrs["Dimension"] = 3 #Runtime parameters grp = file.create_group("/RuntimePars") diff --git a/examples/Disk-Patch/HydroStatic/makeIC.py b/examples/Disk-Patch/HydroStatic/makeIC.py index 7404f76aeaa485037b19052d84636c1656847a2b..40b1d1f1ff9e08dae0c4b0b1539ca773c93009b4 100644 --- a/examples/Disk-Patch/HydroStatic/makeIC.py +++ b/examples/Disk-Patch/HydroStatic/makeIC.py @@ -175,6 +175,7 @@ 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"] = [entropy_flag] +grp.attrs["Dimension"] = 3 #Runtime parameters grp = file.create_group("/RuntimePars") 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/examples/main.c b/examples/main.c index 561f20ae3fefa723c0fb2c0677f12b9eae724306..7dcfee85478235e48351f7b8f9cf973cf5f0fda4 100644 --- a/examples/main.c +++ b/examples/main.c @@ -273,18 +273,6 @@ int main(int argc, char *argv[]) { message("sizeof(struct cell) is %4zi bytes.", sizeof(struct cell)); } -/* Temporary abort to handle absence of vectorized functions */ -#ifdef WITH_VECTORIZATION - -#ifdef MINIMAL_SPH - error( - "Vectorized version of Minimal SPH routines not implemented yet. " - "Reconfigure with --disable-vec and recompile or use DEFAULT_SPH."); -#endif - -#endif - /* End temporary fix */ - /* How vocal are we ? */ const int talking = (verbose == 1 && myrank == 0) || (verbose == 2); @@ -487,6 +475,8 @@ int main(int argc, char *argv[]) { #endif if (myrank == 0) message("Time integration ready to start. End of dry-run."); + engine_clean(&e); + free(params); return 0; } @@ -553,7 +543,7 @@ int main(int argc, char *argv[]) { if (!e.sched.tasks[l].skip && !e.sched.tasks[l].implicit) { fprintf( file_thread, " %03i %i %i %i %i %lli %lli %i %i %i %i %i\n", - myrank, e.sched.tasks[l].last_rid, e.sched.tasks[l].type, + myrank, e.sched.tasks[l].rid, e.sched.tasks[l].type, e.sched.tasks[l].subtype, (e.sched.tasks[l].cj == NULL), e.sched.tasks[l].tic, e.sched.tasks[l].toc, (e.sched.tasks[l].ci != NULL) ? e.sched.tasks[l].ci->count @@ -589,7 +579,7 @@ int main(int argc, char *argv[]) { if (!e.sched.tasks[l].skip && !e.sched.tasks[l].implicit) fprintf( file_thread, " %i %i %i %i %lli %lli %i %i %i %i\n", - e.sched.tasks[l].last_rid, e.sched.tasks[l].type, + e.sched.tasks[l].rid, e.sched.tasks[l].type, e.sched.tasks[l].subtype, (e.sched.tasks[l].cj == NULL), e.sched.tasks[l].tic, e.sched.tasks[l].toc, (e.sched.tasks[l].ci == NULL) ? 0 : e.sched.tasks[l].ci->count, diff --git a/examples/plot_tasks.py b/examples/plot_tasks.py index 6e71f476a106937f43bd4bd5973af01f65218afe..fb8b2ce57a47b4d397284bba9960b098c1e3ce62 100755 --- a/examples/plot_tasks.py +++ b/examples/plot_tasks.py @@ -56,9 +56,8 @@ pl.rcParams.update(PLOT_PARAMS) # Tasks and subtypes. Indexed as in tasks.h. TASKTYPES = ["none", "sort", "self", "pair", "sub_self", "sub_pair", "init", "ghost", - "drift", "kick", "kick_fixdt", "send", "recv", "grav_gather_m", "grav_fft", - "grav_mm", "grav_up", "grav_external", "part_sort", "gpart_sort", - "split_cell", "rewait", "count"] + "kick", "kick_fixdt", "send", "recv", "grav_gather_m", "grav_fft", + "grav_mm", "grav_up", "grav_external", "count"] TASKCOLOURS = {"none": "black", "sort": "lightblue", @@ -68,7 +67,6 @@ TASKCOLOURS = {"none": "black", "sub_pair": "navy", "init": "indigo", "ghost": "cyan", - "drift": "maroon", "kick": "green", "kick_fixdt": "green", "send": "yellow", @@ -78,20 +76,17 @@ TASKCOLOURS = {"none": "black", "grav_mm": "mediumturquoise", "grav_up": "mediumvioletred", "grav_external": "darkred", - "part_sort": "steelblue", - "gpart_sort": "teal" , - "split_cell": "seagreen", - "rewait": "olive", "count": "powerblue"} -SUBTYPES = ["none", "density", "force", "grav", "tend", "count"] +SUBTYPES = ["none", "density", "gradient", "force", "grav", "tend", "count"] SUBCOLOURS = {"none": "black", "density": "red", + "gradient": "powerblue", "force": "blue", "grav": "indigo", - "tend": "grey" - "count": "purple"} + "tend": "grey", + "count": "black"} # Show docs if help is requested. if len( sys.argv ) == 2 and ( sys.argv[1][0:2] == "-h" or sys.argv[1][0:3] == "--h" ): diff --git a/examples/plot_tasks_MPI.py b/examples/plot_tasks_MPI.py index 7550899da2d4a34a5f73b192cbd7c348426786b7..398324cdc773d1dc4b7f26c58866c9df6469cc0b 100755 --- a/examples/plot_tasks_MPI.py +++ b/examples/plot_tasks_MPI.py @@ -62,9 +62,8 @@ pl.rcParams.update(PLOT_PARAMS) # Tasks and subtypes. Indexed as in tasks.h. TASKTYPES = ["none", "sort", "self", "pair", "sub_self", "sub_pair", "init", "ghost", - "drift", "kick", "kick_fixdt", "send", "recv", "grav_gather_m", "grav_fft", - "grav_mm", "grav_up", "grav_external", "part_sort", "gpart_sort", - "split_cell", "rewait", "count"] + "kick", "kick_fixdt", "send", "recv", "grav_gather_m", "grav_fft", + "grav_mm", "grav_up", "grav_external", "count"] TASKCOLOURS = {"none": "black", "sort": "lightblue", @@ -74,7 +73,6 @@ TASKCOLOURS = {"none": "black", "sub_pair": "navy", "init": "indigo", "ghost": "cyan", - "drift": "maroon", "kick": "green", "kick_fixdt": "green", "send": "yellow", @@ -84,20 +82,17 @@ TASKCOLOURS = {"none": "black", "grav_mm": "mediumturquoise", "grav_up": "mediumvioletred", "grav_external": "darkred", - "part_sort": "steelblue", - "gpart_sort": "teal" , - "split_cell": "seagreen", - "rewait": "olive", "count": "powerblue"} -SUBTYPES = ["none", "density", "force", "grav", "tend", "count"] +SUBTYPES = ["none", "density", "gradient", "force", "grav", "tend", "count"] SUBCOLOURS = {"none": "black", "density": "red", + "gradient": "powerblue", "force": "blue", "grav": "indigo", - "tend": "grey" - "count": "purple"} + "tend": "grey", + "count": "black"} # Show docs if help is requested. if len( sys.argv ) == 2 and ( sys.argv[1][0:2] == "-h" or sys.argv[1][0:3] == "--h" ): diff --git a/src/adiabatic_index.h b/src/adiabatic_index.h index 78d1cc9d2deaf60c5d933b74a089c77446b44414..a0c9ce09e3e004af07e8b208ef9f1af5f46c9e81 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 @@ -34,6 +35,7 @@ /* Local headers. */ #include "const.h" #include "debug.h" +#include "error.h" #include "inline.h" /* First define some constants */ @@ -42,18 +44,56 @@ #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.f +#define hydro_gamma_minus_one_over_two 0.33333333333333333f +#define hydro_two_gamma_over_gamma_minus_one 5.f +#define hydro_one_over_gamma 0.6f + +#elif defined(HYDRO_GAMMA_7_5) + +#define hydro_gamma 1.4f +#define hydro_gamma_minus_one 0.4f +#define hydro_one_over_gamma_minus_one 2.5f +#define hydro_gamma_plus_one_over_two_gamma 0.857142857f +#define hydro_gamma_minus_one_over_two_gamma 0.142857143f +#define hydro_gamma_minus_one_over_gamma_plus_one 0.166666667f +#define hydro_two_over_gamma_plus_one 0.833333333 +#define hydro_two_over_gamma_minus_one 5.f +#define hydro_gamma_minus_one_over_two 0.2f +#define hydro_two_gamma_over_gamma_minus_one 7.f +#define hydro_one_over_gamma 0.714285714f #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.f +#define hydro_gamma_minus_one_over_two 0.166666666666666666f +#define hydro_two_gamma_over_gamma_minus_one 8.f +#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.f +#define hydro_gamma_minus_one_over_two 0.5f +#define hydro_two_gamma_over_gamma_minus_one 4.f +#define hydro_one_over_gamma 0.5f #else @@ -73,6 +113,10 @@ __attribute__((always_inline)) INLINE static float pow_gamma(float x) { const float cbrt = cbrtf(x); /* x^(1/3) */ return cbrt * cbrt * x; /* x^(5/3) */ +#elif defined(HYDRO_GAMMA_7_5) + + return powf(x, 1.4f); /* x^(7/5) */ + #elif defined(HYDRO_GAMMA_4_3) return cbrtf(x) * x; /* x^(4/3) */ @@ -103,6 +147,10 @@ __attribute__((always_inline)) INLINE static float pow_gamma_minus_one( const float cbrt = cbrtf(x); /* x^(1/3) */ return cbrt * cbrt; /* x^(2/3) */ +#elif defined(HYDRO_GAMMA_7_5) + + return powf(x, 0.4f); /* x^(2/5) */ + #elif defined(HYDRO_GAMMA_4_3) return cbrtf(x); /* x^(1/3) */ @@ -133,6 +181,10 @@ __attribute__((always_inline)) INLINE static float pow_minus_gamma_minus_one( const float cbrt_inv = 1.f / cbrtf(x); /* x^(-1/3) */ return cbrt_inv * cbrt_inv; /* x^(-2/3) */ +#elif defined(HYDRO_GAMMA_7_5) + + return powf(x, -0.4f); /* x^(-2/5) */ + #elif defined(HYDRO_GAMMA_4_3) return 1.f / cbrtf(x); /* x^(-1/3) */ @@ -149,4 +201,235 @@ __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_7_5) + + return powf(x, -1.4f); /* x^(-7/5) */ + +#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_7_5) + + const float x2 = x * x; + const float x3 = x2 * x; + return x2 * x3; + +#elif defined(HYDRO_GAMMA_4_3) + + const float x3 = x * x * x; /* x^3 */ + return x3 * x3; /* 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) + + const float x2 = x * x; + const float x3 = x2 * x; + return x2 * x3; + +#elif defined(HYDRO_GAMMA_7_5) + + const float x2 = x * x; + const float x4 = x2 * x2; + return x4 * x2 * x; + +#elif defined(HYDRO_GAMMA_4_3) + + const float x2 = x * x; + const float x4 = x2 * x2; + return x4 * x4; /* x^8 */ + +#elif defined(HYDRO_GAMMA_2_1) + + const float x2 = x * x; + return x2 * x2; /* 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_7_5) + + return powf(x, hydro_gamma_minus_one_over_two_gamma); + +#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_7_5) + + return powf(x, -hydro_gamma_plus_one_over_two_gamma); + +#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_7_5) + + return powf(x, hydro_one_over_gamma); + +#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 9cf64b89005c497d70feccb6bc4067bdbfb8ee02..094645ba50e35cd06e3a3f0c333741cb34d4858d 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 605d0c85444c1ac3b4147ef2fb23df52b2694ff5..19e347225d59d6bdb86091efaa4a06bbf981422a 100644 --- a/src/cell.h +++ b/src/cell.h @@ -134,18 +134,20 @@ 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; #ifdef WITH_MPI - /* Task receiving data. */ - struct task *recv_xv, *recv_rho, *recv_ti; + +/* Task receiving data. */ + 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; + #endif /* Tasks for gravity tree. */ @@ -215,6 +217,8 @@ int cell_unpack_ti_ends(struct cell *c, int *ti_ends); int cell_getsize(struct cell *c); int cell_link_parts(struct cell *c, struct part *parts); int cell_link_gparts(struct cell *c, struct gpart *gparts); +void cell_init_parts(struct cell *c, void *data); +void cell_init_gparts(struct cell *c, void *data); void cell_convert_hydro(struct cell *c, void *data); void cell_clean_links(struct cell *c, void *data); int cell_are_neighbours(const struct cell *restrict ci, diff --git a/src/common_io.c b/src/common_io.c index 3c001d9da106a46ef5033c8cdec9346d68c54ecd..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" @@ -515,13 +516,13 @@ void writeXMFgroupheader(FILE* xmfFile, char* hdfFileName, size_t N, fprintf(xmfFile, "\n<Grid Name=\"%s\" GridType=\"Uniform\">\n", particle_type_names[ptype]); fprintf(xmfFile, - "<Topology TopologyType=\"Polyvertex\" Dimensions=\"%zi\"/>\n", N); + "<Topology TopologyType=\"Polyvertex\" Dimensions=\"%zu\"/>\n", N); fprintf(xmfFile, "<Geometry GeometryType=\"XYZ\">\n"); fprintf(xmfFile, - "<DataItem Dimensions=\"%zi 3\" NumberType=\"Double\" " + "<DataItem Dimensions=\"%zu 3\" NumberType=\"Double\" " "Precision=\"8\" " "Format=\"HDF\">%s:/PartType%d/Coordinates</DataItem>\n", - N, hdfFileName, ptype); + N, hdfFileName, (int)ptype); fprintf(xmfFile, "</Geometry>\n <!-- Done geometry for %s, start of particle fields " "list -->\n", @@ -555,12 +556,12 @@ void writeXMFline(FILE* xmfFile, const char* fileName, name, dim == 1 ? "Scalar" : "Vector"); if (dim == 1) fprintf(xmfFile, - "<DataItem Dimensions=\"%zi\" NumberType=\"Double\" " + "<DataItem Dimensions=\"%zu\" NumberType=\"Double\" " "Precision=\"%d\" Format=\"HDF\">%s:%s/%s</DataItem>\n", N, type == FLOAT ? 4 : 8, fileName, partTypeGroupName, name); else fprintf(xmfFile, - "<DataItem Dimensions=\"%zi %d\" NumberType=\"Double\" " + "<DataItem Dimensions=\"%zu %d\" NumberType=\"Double\" " "Precision=\"%d\" Format=\"HDF\">%s:%s/%s</DataItem>\n", N, dim, type == FLOAT ? 4 : 8, fileName, partTypeGroupName, name); fprintf(xmfFile, "</Attribute>\n"); @@ -582,7 +583,7 @@ void prepare_dm_gparts(struct gpart* const gparts, size_t Ndm) { for (size_t i = 0; i < Ndm; ++i) { /* 0 or negative ids are not allowed */ if (gparts[i].id_or_neg_offset <= 0) - error("0 or negative ID for DM particle %zd: ID=%lld", i, + error("0 or negative ID for DM particle %zu: ID=%lld", i, gparts[i].id_or_neg_offset); } } @@ -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; @@ -650,7 +651,7 @@ void collect_dm_gparts(const struct gpart* const gparts, size_t Ntot, /* Check that everything is fine */ if (count != Ndm) - error("Collected the wrong number of dm particles (%zd vs. %zd expected)", + error("Collected the wrong number of dm particles (%zu vs. %zu expected)", count, Ndm); } diff --git a/src/const.h b/src/const.h index cbaa0054fe3bc9f829c59b19b71197264fd0c5af..5f7bf0d26431887c8e37d96b20b0eba460de55a6 100644 --- a/src/const.h +++ b/src/const.h @@ -46,6 +46,7 @@ /* Hydrodynamical adiabatic index. */ #define HYDRO_GAMMA_5_3 +//#define HYDRO_GAMMA_7_5 //#define HYDRO_GAMMA_4_3 //#define HYDRO_GAMMA_2_1 @@ -65,6 +66,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 4601f9bacc2d51d988ee0212b4ccf778bcf15f5c..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 @@ -71,7 +73,7 @@ void printParticle(const struct part *parts, struct xpart *xparts, /* Look for the particle. */ for (size_t i = 0; i < N; i++) if (parts[i].id == id) { - printf("## Particle[%zd]:\n id=%lld ", i, parts[i].id); + printf("## Particle[%zu]:\n id=%lld ", i, parts[i].id); hydro_debug_particle(&parts[i], &xparts[i]); found = 1; break; @@ -100,13 +102,13 @@ void printgParticle(const struct gpart *gparts, const struct part *parts, /* Look for the particle. */ for (size_t i = 0; i < N; i++) if (gparts[i].id_or_neg_offset == id) { - printf("## gParticle[%zd] (DM) :\n id=%lld", i, id); + printf("## gParticle[%zu] (DM) :\n id=%lld", i, id); gravity_debug_particle(&gparts[i]); found = 1; break; } else if (gparts[i].id_or_neg_offset < 0 && parts[-gparts[i].id_or_neg_offset].id == id) { - printf("## gParticle[%zd] (hydro) :\n id=%lld", i, id); + printf("## gParticle[%zu] (hydro) :\n id=%lld", i, id); gravity_debug_particle(&gparts[i]); found = 1; break; @@ -159,7 +161,7 @@ int checkSpacehmax(struct space *s) { /* Now all particles. */ float part_h_max = 0.0f; - for (int k = 0; k < s->nr_parts; k++) { + for (size_t k = 0; k < s->nr_parts; k++) { if (s->parts[k].h > part_h_max) { part_h_max = s->parts[k].h; } @@ -178,7 +180,7 @@ int checkSpacehmax(struct space *s) { } } - for (int k = 0; k < s->nr_parts; k++) { + for (size_t k = 0; k < s->nr_parts; k++) { if (s->parts[k].h > cell_h_max) { message("part %lld is inconsistent (%f > %f)", s->parts[k].id, s->parts[k].h, cell_h_max); 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 2d4b8460c0a1373cfa67832c4437472c64394d7f..0b09e2766e52e7ac2c354f038aab8d13c0a52553 100644 --- a/src/engine.c +++ b/src/engine.c @@ -219,6 +219,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 } } @@ -297,7 +303,7 @@ void engine_redistribute(struct engine *e) { parts[k].x[2] * iwidth[2]); #ifdef SWIFT_DEBUG_CHECKS if (cid < 0 || cid >= s->nr_cells) - error("Bad cell id %i for part %zi at [%.3e,%.3e,%.3e].", cid, k, + error("Bad cell id %i for part %zu at [%.3e,%.3e,%.3e].", cid, k, parts[k].x[0], parts[k].x[1], parts[k].x[2]); #endif @@ -353,7 +359,7 @@ void engine_redistribute(struct engine *e) { gparts[k].x[2] * iwidth[2]); #ifdef SWIFT_DEBUG_CHECKS if (cid < 0 || cid >= s->nr_cells) - error("Bad cell id %i for part %zi at [%.3e,%.3e,%.3e].", cid, k, + error("Bad cell id %i for part %zu at [%.3e,%.3e,%.3e].", cid, k, gparts[k].x[0], gparts[k].x[1], gparts[k].x[2]); #endif @@ -588,7 +594,7 @@ void engine_redistribute(struct engine *e) { int my_cells = 0; for (int k = 0; k < nr_cells; k++) if (cells[k].nodeID == nodeID) my_cells += 1; - message("node %i now has %zi parts and %zi gparts in %i cells.", nodeID, + message("node %i now has %zu parts and %zu gparts in %i cells.", nodeID, nr_parts, nr_gparts, my_cells); } @@ -676,11 +682,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; @@ -699,21 +706,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); @@ -722,6 +750,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); } @@ -729,7 +760,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."); @@ -743,11 +775,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; @@ -758,19 +792,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); @@ -780,12 +834,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."); @@ -879,7 +934,7 @@ void engine_exchange_cells(struct engine *e) { /* Count the number of particles we need to import and re-allocate the buffer if needed. */ - int count_parts_in = 0, count_gparts_in = 0; + size_t count_parts_in = 0, count_gparts_in = 0; for (int k = 0; k < nr_proxies; k++) for (int j = 0; j < e->proxies[k].nr_cells_in; j++) { count_parts_in += e->proxies[k].cells_in[j]->count; @@ -969,7 +1024,7 @@ void engine_exchange_strays(struct engine *e, size_t offset_parts, if (pid < 0) { error( "Do not have a proxy for the requested nodeID %i for part with " - "id=%llu, x=[%e,%e,%e].", + "id=%lld, x=[%e,%e,%e].", node_id, s->parts[offset_parts + k].id, s->parts[offset_parts + k].x[0], s->parts[offset_parts + k].x[1], s->parts[offset_parts + k].x[2]); @@ -1033,7 +1088,7 @@ void engine_exchange_strays(struct engine *e, size_t offset_parts, count_gparts_in += e->proxies[k].nr_gparts_in; } if (e->verbose) { - message("sent out %zi/%zi parts/gparts, got %i/%i back.", *Npart, *Ngpart, + message("sent out %zu/%zu parts/gparts, got %i/%i back.", *Npart, *Ngpart, count_parts_in, count_gparts_in); } if (offset_parts + count_parts_in > s->size_parts) { @@ -1127,13 +1182,13 @@ void engine_exchange_strays(struct engine *e, size_t offset_parts, reqs_in[pid + 1] == MPI_REQUEST_NULL && reqs_in[pid + 2] == MPI_REQUEST_NULL) { /* Copy the particle data to the part/xpart/gpart arrays. */ - struct proxy *p = &e->proxies[pid / 3]; - memcpy(&s->parts[offset_parts + count_parts], p->parts_in, - sizeof(struct part) * p->nr_parts_in); - memcpy(&s->xparts[offset_parts + count_parts], p->xparts_in, - sizeof(struct xpart) * p->nr_parts_in); - memcpy(&s->gparts[offset_gparts + count_gparts], p->gparts_in, - sizeof(struct gpart) * p->nr_gparts_in); + struct proxy *prox = &e->proxies[pid / 3]; + memcpy(&s->parts[offset_parts + count_parts], prox->parts_in, + sizeof(struct part) * prox->nr_parts_in); + memcpy(&s->xparts[offset_parts + count_parts], prox->xparts_in, + sizeof(struct xpart) * prox->nr_parts_in); + memcpy(&s->gparts[offset_gparts + count_gparts], prox->gparts_in, + sizeof(struct gpart) * prox->nr_gparts_in); /* for (int k = offset; k < offset + count; k++) message( "received particle %lli, x=[%.3e %.3e %.3e], h=%.3e, from node %i.", @@ -1141,8 +1196,8 @@ void engine_exchange_strays(struct engine *e, size_t offset_parts, s->parts[k].x[2], s->parts[k].h, p->nodeID); */ /* Re-link the gparts. */ - for (int k = 0; k < p->nr_gparts_in; k++) { - struct gpart *gp = &s->gparts[offset_gparts + count_gparts + k]; + for (int kk = 0; kk < prox->nr_gparts_in; kk++) { + struct gpart *gp = &s->gparts[offset_gparts + count_gparts + kk]; if (gp->id_or_neg_offset <= 0) { struct part *p = &s->parts[offset_gparts + count_parts - gp->id_or_neg_offset]; @@ -1152,8 +1207,8 @@ void engine_exchange_strays(struct engine *e, size_t offset_parts, } /* Advance the counters. */ - count_parts += p->nr_parts_in; - count_gparts += p->nr_gparts_in; + count_parts += prox->nr_parts_in; + count_gparts += prox->nr_gparts_in; } } @@ -1471,19 +1526,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); @@ -1491,6 +1573,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 @@ -1518,6 +1601,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); @@ -1528,11 +1629,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); @@ -1551,12 +1681,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, @@ -1571,12 +1727,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, @@ -1596,8 +1783,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); @@ -1673,7 +1860,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; @@ -1719,13 +1910,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 @@ -2026,8 +2217,8 @@ void engine_print_task_counts(struct engine *e) { printf(" %s=%i", taskID_names[k], counts[k]); printf(" skipped=%i ]\n", counts[task_type_count]); fflush(stdout); - message("nr_parts = %zi.", e->s->nr_parts); - message("nr_gparts = %zi.", e->s->nr_gparts); + message("nr_parts = %zu.", e->s->nr_parts); + message("nr_gparts = %zu.", e->s->nr_gparts); } /** @@ -2508,11 +2699,11 @@ void engine_step(struct engine *e) { if (e->nodeID == 0) { /* Print some information to the screen */ - printf(" %6d %14e %14e %10zd %10zd %21.3f\n", e->step, e->time, + printf(" %6d %14e %14e %10zu %10zu %21.3f\n", e->step, e->time, e->timeStep, e->updates, e->g_updates, e->wallclock_time); fflush(stdout); - fprintf(e->file_timesteps, " %6d %14e %14e %10zd %10zd %21.3f\n", e->step, + fprintf(e->file_timesteps, " %6d %14e %14e %10zu %10zu %21.3f\n", e->step, e->time, e->timeStep, e->updates, e->g_updates, e->wallclock_time); fflush(e->file_timesteps); } @@ -2554,6 +2745,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 */ @@ -2727,7 +2923,7 @@ void engine_split(struct engine *e, struct partition *initial_partition) { /* Re-allocate the local parts. */ if (e->verbose) - message("Re-allocating parts array from %zi to %zi.", s->size_parts, + message("Re-allocating parts array from %zu to %zu.", s->size_parts, (size_t)(s->nr_parts * 1.2)); s->size_parts = s->nr_parts * 1.2; struct part *parts_new = NULL; @@ -2749,7 +2945,7 @@ void engine_split(struct engine *e, struct partition *initial_partition) { /* Re-allocate the local gparts. */ if (e->verbose) - message("Re-allocating gparts array from %zi to %zi.", s->size_gparts, + message("Re-allocating gparts array from %zu to %zu.", s->size_gparts, (size_t)(s->nr_gparts * 1.2)); s->size_gparts = s->nr_gparts * 1.2; struct gpart *gparts_new = NULL; diff --git a/src/gravity/Default/gravity.h b/src/gravity/Default/gravity.h index da6b9aa01d7d382b1d6aa85f732f1fae1169ac34..d4249c46a3150a357aaecfb02f9251901d97a157 100644 --- a/src/gravity/Default/gravity.h +++ b/src/gravity/Default/gravity.h @@ -71,7 +71,7 @@ gravity_compute_timestep_self(const struct phys_const* const phys_const, const float ac = (ac2 > 0.f) ? sqrtf(ac2) : FLT_MIN; - const float dt = sqrt(2.f * const_gravity_eta * gp->epsilon / ac); + const float dt = sqrtf(2.f * const_gravity_eta * gp->epsilon / ac); return dt; } @@ -115,10 +115,10 @@ __attribute__((always_inline)) INLINE static void gravity_init_gpart( * Multiplies the forces and accelerations by the appropiate constants * * @param gp The particle to act upon - * @param const_G Newton's constant + * @param const_G Newton's constant in internal units */ __attribute__((always_inline)) INLINE static void gravity_end_force( - struct gpart* gp, double const_G) { + struct gpart* gp, float const_G) { /* Let's get physical... */ gp->a_grav[0] *= const_G; 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/kernel_gravity.h b/src/kernel_gravity.h index b38feb5758debf87add2007ee3684d869f393f7e..a1e382a21d04b7354aaf215069e999627e56ee07 100644 --- a/src/kernel_gravity.h +++ b/src/kernel_gravity.h @@ -50,7 +50,7 @@ static const float -10.66666667f, 38.4f, -48.f, - 21.3333333, + 21.3333333f, 0.f, 0.f, -0.066666667f, /* 0.5 < u < 1 */ diff --git a/src/kernel_long_gravity.h b/src/kernel_long_gravity.h index d247c7a461d4bd116f30ab106143f6c75e1b941e..6952681999f833bce7755a72aaee742a7fa0ed22 100644 --- a/src/kernel_long_gravity.h +++ b/src/kernel_long_gravity.h @@ -41,7 +41,7 @@ __attribute__((always_inline)) INLINE static void kernel_long_grav_eval( const float arg2 = u * one_over_sqrt_pi; const float arg3 = -arg1 * arg1; - const float term1 = erfc(arg1); + const float term1 = erfcf(arg1); const float term2 = arg2 * expf(arg3); *W = term1 + term2; diff --git a/src/kick.h b/src/kick.h index b57e13d4ebf27d3a366d571e7fd4cd819653f726..e3fa3bf78c7da514abacf697a9d94212020e5a7b 100644 --- a/src/kick.h +++ b/src/kick.h @@ -39,8 +39,8 @@ __attribute__((always_inline)) INLINE static void kick_gpart( /* Compute the time step for this kick */ const int ti_start = (gp->ti_begin + gp->ti_end) / 2; const int ti_end = gp->ti_end + new_dti / 2; - const double dt = (ti_end - ti_start) * timeBase; - const double half_dt = (ti_end - gp->ti_end) * timeBase; + const float dt = (ti_end - ti_start) * timeBase; + const float half_dt = (ti_end - gp->ti_end) * timeBase; /* Move particle forward in time */ gp->ti_begin = gp->ti_end; @@ -70,8 +70,8 @@ __attribute__((always_inline)) INLINE static void kick_part( /* Compute the time step for this kick */ const int ti_start = (p->ti_begin + p->ti_end) / 2; const int ti_end = p->ti_end + new_dti / 2; - const double dt = (ti_end - ti_start) * timeBase; - const double half_dt = (ti_end - p->ti_end) * timeBase; + const float dt = (ti_end - ti_start) * timeBase; + const float half_dt = (ti_end - p->ti_end) * timeBase; /* Move particle forward in time */ p->ti_begin = p->ti_end; diff --git a/src/parallel_io.c b/src/parallel_io.c index d543aac7e700dc008c439ffca7e45108c6c1904e..5d10cf03137937a4b89db68218bb723d3a282c59 100644 --- a/src/parallel_io.c +++ b/src/parallel_io.c @@ -528,27 +528,18 @@ void read_ic_parallel(char* fileName, const struct UnitSystem* internal_units, int num_fields = 0; struct io_props list[100]; - size_t N = 0; + size_t Nparticles = 0; /* Read particle fields into the particle structure */ switch (ptype) { case GAS: - /* if (!dry_run) */ - /* hydro_read_particles(h_grp, N[ptype], N_total[ptype], - * offset[ptype], */ - /* *parts); */ - /* break; */ - N = *Ngas; + Nparticles = *Ngas; hydro_read_particles(*parts, list, &num_fields); break; case DM: - /* if (!dry_run) */ - /* darkmatter_read_particles(h_grp, N[ptype], N_total[ptype], */ - /* offset[ptype], *gparts); */ - /* break; */ - N = Ndm; + Nparticles = Ndm; darkmatter_read_particles(*gparts, list, &num_fields); break; @@ -559,7 +550,7 @@ void read_ic_parallel(char* fileName, const struct UnitSystem* internal_units, /* Read everything */ if (!dry_run) for (int i = 0; i < num_fields; ++i) - readArray(h_grp, list[i], N, N_total[ptype], offset[ptype], + readArray(h_grp, list[i], Nparticles, N_total[ptype], offset[ptype], internal_units, ic_units); /* Close particle group */ @@ -793,13 +784,13 @@ void write_output_parallel(struct engine* e, const char* baseName, int num_fields = 0; struct io_props list[100]; - size_t N = 0; + size_t Nparticles = 0; /* Write particle fields from the particle structure */ switch (ptype) { case GAS: - N = Ngas; + Nparticles = Ngas; hydro_write_particles(parts, list, &num_fields); break; @@ -816,7 +807,7 @@ void write_output_parallel(struct engine* e, const char* baseName, collect_dm_gparts(gparts, Ntot, dmparts, Ndm); /* Write DM particles */ - N = Ndm; + Nparticles = Ndm; darkmatter_write_particles(dmparts, list, &num_fields); /* Free temporary array */ @@ -829,9 +820,9 @@ void write_output_parallel(struct engine* e, const char* baseName, /* Write everything */ for (int i = 0; i < num_fields; ++i) - writeArray(e, h_grp, fileName, xmfFile, partTypeGroupName, list[i], N, - N_total[ptype], mpi_rank, offset[ptype], internal_units, - snapshot_units); + writeArray(e, h_grp, fileName, xmfFile, partTypeGroupName, list[i], + Nparticles, N_total[ptype], mpi_rank, offset[ptype], + internal_units, snapshot_units); /* Free temporary array */ free(dmparts); 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/potentials.h b/src/potentials.h index f0de5b4dc784be2e613c634bf687300d57f40ecd..74f0fd28566f355962c83e5d743aeae9afe09c59 100644 --- a/src/potentials.h +++ b/src/potentials.h @@ -78,13 +78,15 @@ struct external_potential { * * See Creasey, Theuns & Bower, 2013, MNRAS, Volume 429, Issue 3, p.1922-1948 * - * @param phys_cont The physical constants in internal units. - * @param gp Pointer to the g-particle data. + * @param potential The properties of the potential. + * @param phys_const The physical constants in internal units. + * @param g Pointer to the g-particle data. */ __attribute__((always_inline)) INLINE static float -external_gravity_disk_patch_timestep(const struct external_potential* potential, - const struct phys_const* const phys_const, - const struct gpart* const g) { +external_gravity_disk_patch_timestep( + const struct external_potential* restrict potential, + const struct phys_const* restrict phys_const, + const struct gpart* restrict g) { /* initilize time step to disk dynamical time */ const float dt_dyn = potential->disk_patch_potential.dynamical_time; @@ -136,13 +138,15 @@ external_gravity_disk_patch_timestep(const struct external_potential* potential, * * See Creasey, Theuns & Bower, 2013, MNRAS, Volume 429, Issue 3, p.1922-1948 * - * @param phys_cont The physical constants in internal units. + * @param time The current time in internal units. + * @param potential The properties of the potential. + * @param phys_const The physical constants in internal units. * @param g Pointer to the g-particle data. */ __attribute__((always_inline)) INLINE static void external_gravity_disk_patch_potential( - const double time, const struct external_potential* potential, - const struct phys_const* const phys_const, struct gpart* g) { + double time, const struct external_potential* restrict potential, + const struct phys_const* restrict phys_const, struct gpart* restrict g) { const float G_newton = phys_const->const_newton_G; const float dz = g->x[2] - potential->disk_patch_potential.z_disk; @@ -178,8 +182,9 @@ external_gravity_disk_patch_potential( */ __attribute__((always_inline)) INLINE static float external_gravity_isothermalpotential_timestep( - const struct external_potential* potential, - const struct phys_const* const phys_const, const struct gpart* const g) { + const struct external_potential* restrict potential, + const struct phys_const* restrict phys_const, + const struct gpart* restrict g) { const float dx = g->x[0] - potential->isothermal_potential.x; const float dy = g->x[1] - potential->isothermal_potential.y; @@ -247,9 +252,10 @@ external_gravity_isothermalpotential(const struct external_potential* potential, * @param g Pointer to the g-particle data. */ __attribute__((always_inline)) INLINE static float -external_gravity_pointmass_timestep(const struct external_potential* potential, - const struct phys_const* const phys_const, - const struct gpart* const g) { +external_gravity_pointmass_timestep( + const struct external_potential* restrict potential, + const struct phys_const* restrict phys_const, + const struct gpart* restrict g) { const float G_newton = phys_const->const_newton_G; const float dx = g->x[0] - potential->point_mass.x; @@ -284,8 +290,8 @@ external_gravity_pointmass_timestep(const struct external_potential* potential, * @param g Pointer to the g-particle data. */ __attribute__((always_inline)) INLINE static void external_gravity_pointmass( - const struct external_potential* potential, - const struct phys_const* const phys_const, struct gpart* g) { + const struct external_potential* restrict potential, + const struct phys_const* restrict phys_const, struct gpart* restrict g) { const float dx = g->x[0] - potential->point_mass.x; const float dy = g->x[1] - potential->point_mass.y; 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 8434b3445bf3cebf6d7f5d1110c54a9ccdefb5a1..57a6b9de7017ccb953eaaf05d9880cc440bdd974 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. @@ -613,7 +662,7 @@ static void runner_do_drift(struct cell *c, struct engine *e) { if (!c->split) { /* Loop over all the g-particles in the cell */ - const int nr_gparts = c->gcount; + const size_t nr_gparts = c->gcount; for (size_t k = 0; k < nr_gparts; k++) { /* Get a handle on the gpart. */ @@ -657,7 +706,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; @@ -1089,13 +1139,15 @@ void *runner_main(void *data) { struct cell *ci = t->ci; struct cell *cj = t->cj; t->rid = r->cpuid; - t->last_rid = r->cpuid; /* 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) @@ -1106,6 +1158,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) @@ -1119,6 +1175,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) @@ -1129,6 +1189,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) @@ -1142,12 +1206,18 @@ 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; case task_type_kick_fixdt: runner_do_kick_fixdt(r, ci, 1); break; +#ifdef WITH_MPI case task_type_send: if (t->subtype == task_subtype_tend) { free(t->buff); @@ -1161,6 +1231,7 @@ void *runner_main(void *data) { runner_do_recv_cell(r, ci, 1); } break; +#endif case task_type_grav_mm: runner_do_grav_mm(r, t->ci, 1); break; diff --git a/src/runner_doiact.h b/src/runner_doiact.h index db439671ff5fee56c086444ddaa8268571c80a15..376400926432a9e9b6b9c736260dc3e119c2c64d 100644 --- a/src/runner_doiact.h +++ b/src/runner_doiact.h @@ -1739,7 +1739,7 @@ void DOSUB_PAIR1(struct runner *r, struct cell *ci, struct cell *cj, int sid, if (ci->ti_end_min > ti_current && cj->ti_end_min > ti_current) return; /* Get the cell dimensions. */ - const float h = fmin(ci->width[0], fmin(ci->width[1], ci->width[2])); + const float h = fminf(ci->width[0], fminf(ci->width[1], ci->width[2])); /* Get the type of pair if not specified explicitly. */ // if ( sid < 0 ) @@ -2023,7 +2023,7 @@ void DOSUB_PAIR2(struct runner *r, struct cell *ci, struct cell *cj, int sid, if (ci->ti_end_min > ti_current && cj->ti_end_min > ti_current) return; /* Get the cell dimensions. */ - const float h = fmin(ci->width[0], fmin(ci->width[1], ci->width[2])); + const float h = fminf(ci->width[0], fminf(ci->width[1], ci->width[2])); /* Get the type of pair if not specified explicitly. */ // if ( sid < 0 ) @@ -2336,7 +2336,7 @@ void DOSUB_SUBSET(struct runner *r, struct cell *ci, struct part *parts, else { /* Get the cell dimensions. */ - const float h = fmin(ci->width[0], fmin(ci->width[1], ci->width[2])); + const float h = fminf(ci->width[0], fminf(ci->width[1], ci->width[2])); /* Recurse? */ if (ci->split && cj->split && @@ -2862,16 +2862,17 @@ void DOSUB_SUBSET(struct runner *r, struct cell *ci, struct part *parts, } /* Get the sorting index. */ - int sid = 0; + int new_sid = 0; for (int k = 0; k < 3; k++) - sid = - 3 * sid + ((cj->loc[k] - ci->loc[k] + shift[k] < 0) - ? 0 - : (cj->loc[k] - ci->loc[k] + shift[k] > 0) ? 2 : 1); - sid = sortlistID[sid]; + new_sid = 3 * new_sid + + ((cj->loc[k] - ci->loc[k] + shift[k] < 0) + ? 0 + : (cj->loc[k] - ci->loc[k] + shift[k] > 0) ? 2 : 1); + new_sid = sortlistID[new_sid]; /* Do any of the cells need to be sorted first? */ - if (!(cj->sorted & (1 << sid))) runner_do_sort(r, cj, (1 << sid), 1); + if (!(cj->sorted & (1 << new_sid))) + runner_do_sort(r, cj, (1 << new_sid), 1); /* Compute the interactions. */ DOPAIR_SUBSET(r, ci, parts, ind, count, cj); diff --git a/src/scheduler.c b/src/scheduler.c index adc63e55092ff9bc69e6a2f98d6dfd5c399857f4..ef4d19107fb48684ca299f286436a155a6fe0151 100644 --- a/src/scheduler.c +++ b/src/scheduler.c @@ -111,14 +111,14 @@ void scheduler_addunlock(struct scheduler *s, struct task *ta, static void scheduler_splittask(struct task *t, struct scheduler *s) { /* Static constants. */ - const static int pts[7][8] = { + static const int pts[7][8] = { {-1, 12, 10, 9, 4, 3, 1, 0}, {-1, -1, 11, 10, 5, 4, 2, 1}, {-1, -1, -1, 12, 7, 6, 4, 3}, {-1, -1, -1, -1, 8, 7, 5, 4}, {-1, -1, -1, -1, -1, 12, 10, 9}, {-1, -1, -1, -1, -1, -1, 11, 10}, {-1, -1, -1, -1, -1, -1, -1, 12}}; - const static float sid_scale[13] = {0.1897, 0.4025, 0.1897, 0.4025, 0.5788, - 0.4025, 0.1897, 0.4025, 0.1897, 0.4025, - 0.5788, 0.4025, 0.5788}; + static const float sid_scale[13] = { + 0.1897f, 0.4025f, 0.1897f, 0.4025f, 0.5788f, 0.4025f, 0.1897f, + 0.4025f, 0.1897f, 0.4025f, 0.5788f, 0.4025f, 0.5788f}; /* Iterate on this task until we're done with it. */ int redo = 1; @@ -704,7 +704,6 @@ struct task *scheduler_addtask(struct scheduler *s, enum task_types type, t->toc = 0; t->nr_unlock_tasks = 0; t->rid = -1; - t->last_rid = -1; /* Add an index for it. */ // lock_lock( &s->lock ); diff --git a/src/serial_io.c b/src/serial_io.c index d0618ea93e07168274dff02f31ae95c89503859b..a9213819d4816a08614b82264ab463cecc060419 100644 --- a/src/serial_io.c +++ b/src/serial_io.c @@ -179,7 +179,8 @@ void readArray(hid_t grp, const struct io_props props, size_t N, void prepareArray(struct engine* e, hid_t grp, char* fileName, FILE* xmfFile, char* partTypeGroupName, const struct io_props props, - long long N_total, const struct UnitSystem* internal_units, + unsigned long long N_total, + const struct UnitSystem* internal_units, const struct UnitSystem* snapshot_units) { /* Create data space */ @@ -220,7 +221,7 @@ void prepareArray(struct engine* e, hid_t grp, char* fileName, FILE* xmfFile, /* Set chunk size */ h_err = H5Pset_chunk(h_prop, rank, chunk_shape); if (h_err < 0) { - error("Error while setting chunk size (%lld, %lld) for field '%s'.", + error("Error while setting chunk size (%llu, %llu) for field '%s'.", chunk_shape[0], chunk_shape[1], props.name); } @@ -590,26 +591,18 @@ void read_ic_serial(char* fileName, const struct UnitSystem* internal_units, int num_fields = 0; struct io_props list[100]; - size_t N = 0; + size_t Nparticles = 0; /* Read particle fields into the particle structure */ switch (ptype) { case GAS: - /* if (!dry_run) */ - /* hydro_read_particles(h_grp, N[ptype], N_total[ptype], */ - /* offset[ptype], *parts); */ - /* break; */ - N = *Ngas; + Nparticles = *Ngas; hydro_read_particles(*parts, list, &num_fields); break; case DM: - /* if (!dry_run) */ - /* darkmatter_read_particles(h_grp, N[ptype], N_total[ptype], */ - /* offset[ptype], *gparts); */ - /* break; */ - N = Ndm; + Nparticles = Ndm; darkmatter_read_particles(*gparts, list, &num_fields); break; @@ -621,7 +614,7 @@ void read_ic_serial(char* fileName, const struct UnitSystem* internal_units, /* Read everything */ if (!dry_run) for (int i = 0; i < num_fields; ++i) - readArray(h_grp, list[i], N, N_total[ptype], offset[ptype], + readArray(h_grp, list[i], Nparticles, N_total[ptype], offset[ptype], internal_units, ic_units); /* Close particle group */ @@ -886,13 +879,13 @@ void write_output_serial(struct engine* e, const char* baseName, int num_fields = 0; struct io_props list[100]; - size_t N = 0; + size_t Nparticles = 0; /* Write particle fields from the particle structure */ switch (ptype) { case GAS: - N = Ngas; + Nparticles = Ngas; hydro_write_particles(parts, list, &num_fields); break; @@ -907,7 +900,7 @@ void write_output_serial(struct engine* e, const char* baseName, collect_dm_gparts(gparts, Ntot, dmparts, Ndm); /* Write DM particles */ - N = Ndm; + Nparticles = Ndm; darkmatter_write_particles(dmparts, list, &num_fields); break; @@ -918,9 +911,9 @@ void write_output_serial(struct engine* e, const char* baseName, /* Write everything */ for (int i = 0; i < num_fields; ++i) - writeArray(e, h_grp, fileName, xmfFile, partTypeGroupName, list[i], N, - N_total[ptype], mpi_rank, offset[ptype], internal_units, - snapshot_units); + writeArray(e, h_grp, fileName, xmfFile, partTypeGroupName, list[i], + Nparticles, N_total[ptype], mpi_rank, offset[ptype], + internal_units, snapshot_units); /* Free temporary array */ free(dmparts); diff --git a/src/single_io.c b/src/single_io.c index 2d95c2b32fc4b9b2e0e696deb75c9eab1acd9158..df741ac22335fc05ec1ac334636a897e6def3e96 100644 --- a/src/single_io.c +++ b/src/single_io.c @@ -257,7 +257,7 @@ void writeArray(struct engine* e, hid_t grp, char* fileName, FILE* xmfFile, /* Set chunk size */ h_err = H5Pset_chunk(h_prop, rank, chunk_shape); if (h_err < 0) { - error("Error while setting chunk size (%lld, %lld) for field '%s'.", + error("Error while setting chunk size (%llu, %llu) for field '%s'.", chunk_shape[0], chunk_shape[1], props.name); } @@ -471,18 +471,18 @@ void read_ic_single(char* fileName, const struct UnitSystem* internal_units, int num_fields = 0; struct io_props list[100]; - size_t N = 0; + size_t Nparticles = 0; /* Read particle fields into the structure */ switch (ptype) { case GAS: - N = *Ngas; + Nparticles = *Ngas; hydro_read_particles(*parts, list, &num_fields); break; case DM: - N = Ndm; + Nparticles = Ndm; darkmatter_read_particles(*gparts, list, &num_fields); break; @@ -493,7 +493,7 @@ void read_ic_single(char* fileName, const struct UnitSystem* internal_units, /* Read everything */ if (!dry_run) for (int i = 0; i < num_fields; ++i) - readArray(h_grp, list[i], N, internal_units, ic_units); + readArray(h_grp, list[i], Nparticles, internal_units, ic_units); /* Close particle group */ H5Gclose(h_grp); diff --git a/src/space.c b/src/space.c index def8adad3d023efe5daf552328d523d3cfc37429..2f4442c4729f69d8010278f7cf772b40d100d1f1 100644 --- a/src/space.c +++ b/src/space.c @@ -352,14 +352,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]; @@ -426,7 +429,7 @@ void space_rebuild(struct space *s, double cell_max, int verbose) { int *gind; if ((gind = (int *)malloc(sizeof(int) * gind_size)) == NULL) error("Failed to allocate temporary g-particle indices."); - for (int k = 0; k < nr_gparts; k++) { + for (size_t k = 0; k < nr_gparts; k++) { struct gpart *restrict gp = &s->gparts[k]; for (int j = 0; j < 3; j++) if (gp->x[j] < 0.0) @@ -484,7 +487,7 @@ void space_rebuild(struct space *s, double cell_max, int verbose) { #endif /* Move non-local gparts to the end of the list. */ - for (int k = 0; k < nr_gparts;) { + for (size_t k = 0; k < nr_gparts;) { if (cells[gind[k]].nodeID != local_nodeID) { cells[gind[k]].gcount -= 1; nr_gparts -= 1; @@ -593,7 +596,7 @@ void space_rebuild(struct space *s, double cell_max, int verbose) { } /* Assign each particle to its cell. */ - for (int k = nr_gparts; k < s->nr_gparts; k++) { + for (size_t k = nr_gparts; k < s->nr_gparts; k++) { const struct gpart *const p = &s->gparts[k]; gind[k] = cell_getid(cdim, p->x[0] * ih[0], p->x[1] * ih[1], p->x[2] * ih[2]); @@ -711,7 +714,7 @@ void space_parts_sort(struct space *s, int *ind, size_t N, int min, int max, if ((sort_struct.stack = malloc(sizeof(struct qstack) * sort_struct.stack_size)) == NULL) error("Failed to allocate sorting stack."); - for (int i = 0; i < sort_struct.stack_size; i++) + for (unsigned int i = 0; i < sort_struct.stack_size; i++) sort_struct.stack[i].ready = 0; /* Add the first interval. */ @@ -896,7 +899,7 @@ void space_gparts_sort(struct space *s, int *ind, size_t N, int min, int max, if ((sort_struct.stack = malloc(sizeof(struct qstack) * sort_struct.stack_size)) == NULL) error("Failed to allocate sorting stack."); - for (int i = 0; i < sort_struct.stack_size; i++) + for (unsigned int i = 0; i < sort_struct.stack_size; i++) sort_struct.stack[i].ready = 0; /* Add the first interval. */ @@ -1580,13 +1583,13 @@ void space_init(struct space *s, const struct swift_params *params, /* Check that all the part positions are reasonable, wrap if periodic. */ if (periodic) { - for (int k = 0; k < Npart; k++) + for (size_t k = 0; k < Npart; k++) for (int j = 0; j < 3; j++) { while (parts[k].x[j] < 0) parts[k].x[j] += dim[j]; while (parts[k].x[j] >= dim[j]) parts[k].x[j] -= dim[j]; } } else { - for (int k = 0; k < Npart; k++) + for (size_t k = 0; k < Npart; k++) for (int j = 0; j < 3; j++) if (parts[k].x[j] < 0 || parts[k].x[j] >= dim[j]) error("Not all particles are within the specified domain."); @@ -1594,13 +1597,13 @@ void space_init(struct space *s, const struct swift_params *params, /* Same for the gparts */ if (periodic) { - for (int k = 0; k < Ngpart; k++) + for (size_t k = 0; k < Ngpart; k++) for (int j = 0; j < 3; j++) { while (gparts[k].x[j] < 0) gparts[k].x[j] += dim[j]; while (gparts[k].x[j] >= dim[j]) gparts[k].x[j] -= dim[j]; } } else { - for (int k = 0; k < Ngpart; k++) + for (size_t k = 0; k < Ngpart; k++) for (int j = 0; j < 3; j++) if (gparts[k].x[j] < 0 || gparts[k].x[j] >= dim[j]) error("Not all g-particles are within the specified domain."); diff --git a/src/task.c b/src/task.c index 9e48f8abeb9659ea2674f48620b58da977a6775a..2cecce9f066727c9059b08764df647bd8f0f3901 100644 --- a/src/task.c +++ b/src/task.c @@ -46,18 +46,20 @@ #include "inline.h" #include "lock.h" -/* 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. + * + * @param ci The first #cell. + * @param cj The second #cell. */ __attribute__((always_inline)) INLINE static size_t task_cell_overlap_part( const struct cell *ci, const struct cell *cj) { @@ -77,6 +79,9 @@ __attribute__((always_inline)) INLINE static size_t task_cell_overlap_part( /** * @brief Computes the overlap between the gparts array of two given cells. + * + * @param ci The first #cell. + * @param cj The second #cell. */ __attribute__((always_inline)) INLINE static size_t task_cell_overlap_gpart( const struct cell *ci, const struct cell *cj) { @@ -110,6 +115,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 +126,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..c0c9e47ee4ca221f9f960256e9208c749ae523ea 100644 --- a/src/task.h +++ b/src/task.h @@ -23,15 +23,15 @@ #ifndef SWIFT_TASK_H #define SWIFT_TASK_H +#include "../config.h" + /* Includes. */ #include "cell.h" #include "cycle.h" -/* Some constants. */ -#define task_maxwait 3 -#define task_maxunlock 15 - -/* The different task types. */ +/** + * @brief The different task types. + */ enum task_types { task_type_none = 0, task_type_sort, @@ -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, @@ -53,19 +54,22 @@ enum task_types { task_type_count }; -extern const char *taskID_names[]; - -/* The different task sub-types. */ +/** + * @brief The different task sub-types (for pairs, selfs and sub-tasks). + */ enum task_subtypes { task_subtype_none = 0, task_subtype_density, + task_subtype_gradient, task_subtype_force, task_subtype_grav, task_subtype_tend, task_subtype_count }; -/* The kind of action the task perform */ +/** + * @brief The type of particles/objects this task acts upon in a given cell. + */ enum task_actions { task_action_none, task_action_part, @@ -75,29 +79,72 @@ enum task_actions { task_action_count }; +/** + * @brief Names of the task types. + */ +extern const char *taskID_names[]; + +/** + * @brief Names of the task sub-types. + */ extern const char *subtaskID_names[]; -/* Data of a task. */ +/** + * @brief A task to be run by the #scheduler. + */ struct task { + /*! Type of the task */ enum task_types type; + + /*! Sub-type of the task (for the tasks that have one */ enum task_subtypes subtype; - char skip, tight, implicit; - int flags, wait, rank, weight; + /*! Flags used to carry additional information (e.g. sort directions) */ + int flags; + + /*! Number of unsatisfied dependencies */ + int wait; + + /*! Rank of a task in the order */ + int rank; + + /*! Weight of the task */ + int weight; + + /*! Pointers to the cells this task acts upon */ struct cell *ci, *cj; - void *buff; + /*! ID of the queue or runner owning this task */ + int rid; + + /*! Number of tasks unlocked by this one */ + int nr_unlock_tasks; + + /*! List of tasks unlocked by this one */ + struct task **unlock_tasks; #ifdef WITH_MPI + + /*! Buffer for this task's communications */ + void *buff; + + /*! MPI request corresponding to this task */ MPI_Request req; + #endif - int rid, last_rid; + /*! Start and end time of this task */ ticks tic, toc; - int nr_unlock_tasks; - struct task **unlock_tasks; + /*! Should the scheduler skip this task ? */ + char skip; + + /*! Does this task require the particles to be tightly in the cell ? */ + char tight; + + /*! Is this task implicit (i.e. does not do anything) ? */ + char implicit; }; /* Function prototypes. */ 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 b64e17849081994e1969d5f8de0636768dcb729a..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. */ @@ -499,7 +462,7 @@ void engine_single_density(double *dim, long long int pid, hydro_init_part(&p); /* Loop over all particle pairs (force). */ - for (int k = 0; k < N; k++) { + for (k = 0; k < N; k++) { if (parts[k].id == p.id) continue; for (int i = 0; i < 3; i++) { dx[i] = p.x[i] - parts[k].x[i]; @@ -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..9adaa7dc621edafe0c1f097b8c5202a2f017e41d 100644 --- a/src/units.h +++ b/src/units.h @@ -29,25 +29,26 @@ * @brief The unit system used internally. * * This structure contains the conversion factors to the 7 cgs base units to the - *internal units. - * It is used everytime a conversion is performed or an i/o function is called. - * + * internal units. It is used everytime a conversion is performed or an i/o + * function is called. **/ struct UnitSystem { - double UnitMass_in_cgs; /*< Conversion factor from grams to internal mass - units */ - double UnitLength_in_cgs; /*< Conversion factor from centimeters to internal - length units. */ + /*! Conversion factor from grams to internal mass units */ + double UnitMass_in_cgs; + + /*! Conversion factor from centimeters to internal length unit */ + double UnitLength_in_cgs; - double UnitTime_in_cgs; /*< Conversion factor from seconds to internal time - units. */ + /*! Conversion factor from seconds to internal time units */ + double UnitTime_in_cgs; - double UnitCurrent_in_cgs; /*< Conversion factor from Ampere to internal - current units. */ + /*! Conversion factor from Ampere to internal current units */ + double UnitCurrent_in_cgs; - double UnitTemperature_in_cgs; /*< Conversion factor from Kelvins to internal - temperature units. */ + /*! Conversion factor from Kelvins to internal temperature units. */ + double UnitTemperature_in_cgs; + }; /** @@ -89,7 +90,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/src/version.c b/src/version.c index 68a051fa08c53c68319c1e785c0c6503afe18f4d..8bd94e5651dbc597fcd80bc585a47c6633ee3993 100644 --- a/src/version.c +++ b/src/version.c @@ -218,7 +218,7 @@ const char *hdf5_version(void) { #ifdef HAVE_HDF5 unsigned int majnum, minnum, relnum; H5get_libversion(&majnum, &minnum, &relnum); - sprintf(version, "%i.%i.%i", majnum, minnum, relnum); + sprintf(version, "%u.%u.%u", majnum, minnum, relnum); #else sprintf(version, "Unknown version"); #endif 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 dc15c5aa2f4e00862633807bec9603d77fa4bf30..c7e01693b45f76fa21ffd397289fc06ad36af03d 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 @@ -127,7 +129,7 @@ void get_solution(const struct cell *main_cell, struct solution_part *solution, float density, enum velocity_field vel, enum pressure_field press, float size) { - for (size_t i = 0; i < main_cell->count; ++i) { + for (int i = 0; i < main_cell->count; ++i) { solution[i].id = main_cell->parts[i].id; @@ -187,12 +189,29 @@ void get_solution(const struct cell *main_cell, struct solution_part *solution, void reset_particles(struct cell *c, enum velocity_field vel, enum pressure_field press, float size, float density) { - for (size_t i = 0; i < c->count; ++i) { + for (int i = 0; i < c->count; ++i) { struct part *p = &c->parts[i]; 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; } @@ -304,7 +346,7 @@ void dump_particle_fields(char *fileName, struct cell *main_cell, fprintf(file, "# Main cell --------------------------------------------\n"); /* Write main cell */ - for (size_t pid = 0; pid < main_cell->count; pid++) { + for (int pid = 0; pid < main_cell->count; pid++) { fprintf(file, "%6llu %8.5f %8.5f %8.5f %8.5f %8.5f %8.5f %8.5f %8.5f %8.5f %8.5f " "%8.5f " @@ -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 @@ -343,7 +385,7 @@ void dump_particle_fields(char *fileName, struct cell *main_cell, fprintf(file, "# Solution ---------------------------------------------\n"); - for (size_t pid = 0; pid < main_cell->count; pid++) { + for (int pid = 0; pid < main_cell->count; pid++) { fprintf(file, "%6llu %8.5f %8.5f %8.5f %8.5f %8.5f %8.5f %8.5f %8.5f %8.5f " "%8.5f %8.5f " diff --git a/tests/test27cells.c b/tests/test27cells.c index 6d935c0a4a57b3fbbdbd9b378a4b8cb97234aa63..1a1ab88748d922b3e7fbb30a73a10809dca10863 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; @@ -146,7 +150,7 @@ void clean_up(struct cell *ci) { * @brief Initializes all particles field to be ready for a density calculation */ void zero_particle_fields(struct cell *c) { - for (size_t pid = 0; pid < c->count; pid++) { + for (int pid = 0; pid < c->count; pid++) { hydro_init_part(&c->parts[pid]); } } @@ -155,7 +159,7 @@ void zero_particle_fields(struct cell *c) { * @brief Ends the loop by adding the appropriate coefficients */ void end_calculation(struct cell *c) { - for (size_t pid = 0; pid < c->count; pid++) { + for (int pid = 0; pid < c->count; pid++) { hydro_end_density(&c->parts[pid], 1); } } @@ -177,14 +181,15 @@ void dump_particle_fields(char *fileName, struct cell *main_cell, fprintf(file, "# Main cell --------------------------------------------\n"); /* Write main cell */ - for (size_t pid = 0; pid < main_cell->count; pid++) { + for (int pid = 0; pid < main_cell->count; pid++) { fprintf(file, "%6llu %10f %10f %10f %10f %10f %10f %13e %13e %13e %13e %13e " "%13e %13e %13e\n", 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 @@ -219,14 +224,14 @@ void dump_particle_fields(char *fileName, struct cell *main_cell, "# Offset: [%2d %2d %2d] -----------------------------------\n", i - 1, j - 1, k - 1); - for (size_t pjd = 0; pjd < cj->count; pjd++) { + for (int pjd = 0; pjd < cj->count; pjd++) { fprintf( file, "%6llu %10f %10f %10f %10f %10f %10f %13e %13e %13e %13e %13e " "%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 f7b20faa3dc2aeb39e829ae634666e164c47b60a..efa1e628c2d57bf7922be8affdd5436ebca2f9cf 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; @@ -105,7 +109,7 @@ void clean_up(struct cell *ci) { * @brief Initializes all particles field to be ready for a density calculation */ void zero_particle_fields(struct cell *c) { - for (size_t pid = 0; pid < c->count; pid++) { + for (int pid = 0; pid < c->count; pid++) { hydro_init_part(&c->parts[pid]); } } @@ -125,13 +129,13 @@ void dump_particle_fields(char *fileName, struct cell *ci, struct cell *cj) { fprintf(file, "# ci --------------------------------------------\n"); - for (size_t pid = 0; pid < ci->count; pid++) { + for (int pid = 0; pid < ci->count; pid++) { fprintf(file, "%6llu %10f %10f %10f %10f %10f %10f %13e %13e %13e %13e %13e " "%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 @@ -149,13 +153,13 @@ void dump_particle_fields(char *fileName, struct cell *ci, struct cell *cj) { fprintf(file, "# cj --------------------------------------------\n"); - for (size_t pjd = 0; pjd < cj->count; pjd++) { + for (int pjd = 0; pjd < cj->count; pjd++) { fprintf(file, "%6llu %10f %10f %10f %10f %10f %10f %13e %13e %13e %13e %13e " "%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 5a9707d2705ed021996859f324310c4a4926730c..2ef32a5ef11c7e24a379ce5131df9cbea153fa7c 100644 --- a/tests/testReading.c +++ b/tests/testReading.c @@ -28,7 +28,7 @@ int main() { size_t Ngas = 0, Ngpart = 0; int periodic = -1; int flag_entropy_ICs = -1; - int i, j, k, n; + int i, j, k; double dim[3]; struct part *parts = NULL; struct gpart *gparts = NULL; @@ -55,14 +55,14 @@ int main() { assert(periodic == 1); /* Check particles */ - for (n = 0; n < Ngas; ++n) { + for (size_t n = 0; n < Ngas; ++n) { /* Check that indices are in a reasonable range */ unsigned long long index = parts[n].id; 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; }