diff --git a/.gitignore b/.gitignore index 27ff2cf7ff880de2007e27978fcc1cfa22d2bd75..d2f69ad4e8759839082a38d4558a5ab7bac0e18d 100644 --- a/.gitignore +++ b/.gitignore @@ -165,6 +165,8 @@ m4/lt~obsolete.m4 /stamp-h1 /test-driver +src/equation_of_state/planetary/*.txt + # Intel compiler optimization reports *.optrpt @@ -316,3 +318,6 @@ sympy-plots-for-*.tex/ #ctags *tags + +# vim +*.swp diff --git a/configure.ac b/configure.ac index 56f88116c845def33300b87630524f06fec666bb..6ec1ece5ed2fef20ceab484eff4e09fce808e635 100644 --- a/configure.ac +++ b/configure.ac @@ -576,7 +576,7 @@ if test "x$with_profiler" != "xno"; then proflibs="-lprofiler" fi AC_CHECK_LIB([profiler],[ProfilerFlush], - [have_profiler="yes" + [have_profiler="yes" AC_DEFINE([WITH_PROFILER],1,[Link against the gperftools profiling library.])], [have_profiler="no"], $proflibs) @@ -973,7 +973,7 @@ esac # Hydro scheme. AC_ARG_WITH([hydro], [AS_HELP_STRING([--with-hydro=<scheme>], - [Hydro dynamics to use @<:@gadget2, minimal, pressure-entropy, pressure-energy, default, gizmo-mfv, gizmo-mfm, shadowfax, minimal-multi-mat, debug default: gadget2@:>@] + [Hydro dynamics to use @<:@gadget2, minimal, pressure-entropy, pressure-energy, default, gizmo-mfv, gizmo-mfm, shadowfax, planetary, debug default: gadget2@:>@] )], [with_hydro="$withval"], [with_hydro="gadget2"] @@ -1012,10 +1012,11 @@ case "$with_hydro" in shadowfax) AC_DEFINE([SHADOWFAX_SPH], [1], [Shadowfax SPH]) ;; - minimal-multi-mat) - AC_DEFINE([MINIMAL_MULTI_MAT_SPH], [1], [Minimal Multiple Material SPH]) + planetary) + AC_DEFINE([PLANETARY_SPH], [1], [Planetary SPH]) ;; + *) AC_MSG_ERROR([Unknown hydrodynamics scheme: $with_hydro]) ;; diff --git a/examples/ConstantCosmoVolume/constant_volume.yml b/examples/ConstantCosmoVolume/constant_volume.yml new file mode 100644 index 0000000000000000000000000000000000000000..ad31fd1972565b0d7683711a20db78e854c3dc5f --- /dev/null +++ b/examples/ConstantCosmoVolume/constant_volume.yml @@ -0,0 +1,53 @@ +# Define the system of units to use internally. +InternalUnitSystem: + UnitMass_in_cgs: 1.98848e43 # 10^10 M_sun in grams + UnitLength_in_cgs: 3.08567758e24 # Mpc in centimeters + UnitVelocity_in_cgs: 1e5 # km/s in centimeters per second + UnitCurrent_in_cgs: 1 # Amperes + UnitTemp_in_cgs: 1 # Kelvin + +Cosmology: + Omega_m: 1. + Omega_lambda: 0. + Omega_b: 1. + h: 1. + a_begin: 0.00990099 + a_end: 1.0 + +# Parameters governing the time integration +TimeIntegration: + dt_min: 1e-7 # The minimal time-step size of the simulation (in internal units). + dt_max: 5e-3 # The maximal time-step size of the simulation (in internal units). + +# Parameters governing the snapshots +Snapshots: + basename: box # Common part of the name of output files + time_first: 0. # Time of the first output (in internal units) + delta_time: 1.04 # Time difference between consecutive outputs (in internal units) + scale_factor_first: 0.00991 + compression: 4 + +# Parameters governing the conserved quantities statistics +Statistics: + delta_time: 2. # 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 + CFL_condition: 0.1 # Courant-Friedrich-Levy condition for time integration. + +# Parameters related to the initial conditions +InitialConditions: + file_name: ./constantBox.hdf5 # The file to read + +Scheduler: + max_top_level_cells: 8 + cell_split_size: 50 + +Gravity: + mesh_side_length: 32 + eta: 0.025 + theta: 0.3 + r_cut_max: 5. + comoving_softening: 0.05 + max_physical_softening: 0.05 diff --git a/examples/ConstantCosmoVolume/makeIC.py b/examples/ConstantCosmoVolume/makeIC.py new file mode 100644 index 0000000000000000000000000000000000000000..970f197400129d2ca3f3a7b6ff2cfdd5a7f53f3f --- /dev/null +++ b/examples/ConstantCosmoVolume/makeIC.py @@ -0,0 +1,150 @@ +################################################################################ +# This file is part of SWIFT. +# Copyright (c) 2018 Matthieu Schaller (matthieu.schaller@durham.ac.uk) +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU Lesser General Public License as published +# by the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU Lesser General Public License +# along with this program. If not, see <http://www.gnu.org/licenses/>. +# +################################################################################ + +import h5py +from numpy import * + +# Parameters +T_i = 100. # Initial temperature of the gas (in K) +z_i = 100. # Initial redshift +gamma = 5./3. # Gas adiabatic index +numPart_1D = 32 +#glassFile = "glassCube_32.hdf5" +fileName = "constantBox.hdf5" + + +# Some units +Mpc_in_m = 3.08567758e22 +Msol_in_kg = 1.98848e30 +Gyr_in_s = 3.08567758e19 +mH_in_kg = 1.6737236e-27 + +# Some constants +kB_in_SI = 1.38064852e-23 +G_in_SI = 6.67408e-11 + +# Some useful variables in h-full units +H_0 = 1. / Mpc_in_m * 10**5 # h s^-1 +rho_0 = 3. * H_0**2 / (8* math.pi * G_in_SI) # h^2 kg m^-3 +lambda_i = 64. / H_0 * 10**5 # h^-1 m (= 64 h^-1 Mpc) +x_min = -0.5 * lambda_i +x_max = 0.5 * lambda_i + +# SI system of units +unit_l_in_si = Mpc_in_m +unit_m_in_si = Msol_in_kg * 1.e10 +unit_t_in_si = Gyr_in_s +unit_v_in_si = unit_l_in_si / unit_t_in_si +unit_u_in_si = unit_v_in_si**2 + +#--------------------------------------------------- + +# Read the glass file +#glass = h5py.File(glassFile, "r" ) + +# Read particle positions and h from the glass +#pos = glass["/PartType0/Coordinates"][:,:] +#h = glass["/PartType0/SmoothingLength"][:] * 0.3 +#glass.close() + +# Total number of particles +#numPart = size(h) +#if numPart != numPart_1D**3: +# print "Non-matching glass file" +numPart = numPart_1D**3 + +# Set box size and interparticle distance +boxSize = x_max - x_min +delta_x = boxSize / numPart_1D + +# Get the particle mass +a_i = 1. / (1. + z_i) +m_i = boxSize**3 * rho_0 / numPart + +# Build the arrays +#pos *= boxSize +#h *= boxSize +coords = zeros((numPart, 3)) +v = zeros((numPart, 3)) +ids = linspace(1, numPart, numPart) +m = zeros(numPart) +h = zeros(numPart) +u = zeros(numPart) + +# Set the particles on the left +for i in range(numPart_1D): + for j in range(numPart_1D): + for k in range(numPart_1D): + index = i * numPart_1D**2 + j * numPart_1D + k + coords[index,0] = (i + 0.5) * delta_x + coords[index,1] = (j + 0.5) * delta_x + coords[index,2] = (k + 0.5) * delta_x + u[index] = kB_in_SI * T_i / (gamma - 1.) / mH_in_kg + h[index] = 1.2348 * delta_x + m[index] = m_i + v[index,0] = 0. + v[index,1] = 0. + v[index,2] = 0. + +# Unit conversion +coords /= unit_l_in_si +v /= unit_v_in_si +m /= unit_m_in_si +h /= unit_l_in_si +u /= unit_u_in_si + +boxSize /= unit_l_in_si + +#File +file = h5py.File(fileName, 'w') + +# Header +grp = file.create_group("/Header") +grp.attrs["BoxSize"] = [boxSize, boxSize, boxSize] +grp.attrs["NumPart_Total"] = [numPart, 0, 0, 0, 0, 0] +grp.attrs["NumPart_Total_HighWord"] = [0, 0, 0, 0, 0, 0] +grp.attrs["NumPart_ThisFile"] = [numPart, 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 +grp.attrs["Dimension"] = 3 + +#Runtime parameters +grp = file.create_group("/RuntimePars") +grp.attrs["PeriodicBoundariesOn"] = 1 + +#Units +grp = file.create_group("/Units") +grp.attrs["Unit length in cgs (U_L)"] = 100. * unit_l_in_si +grp.attrs["Unit mass in cgs (U_M)"] = 1000. * unit_m_in_si +grp.attrs["Unit time in cgs (U_t)"] = 1. * unit_t_in_si +grp.attrs["Unit current in cgs (U_I)"] = 1. +grp.attrs["Unit temperature in cgs (U_T)"] = 1. + +#Particle group +grp = file.create_group("/PartType0") +grp.create_dataset('Coordinates', data=coords, dtype='d', compression="gzip", shuffle=True) +grp.create_dataset('Velocities', data=v, dtype='f',compression="gzip", shuffle=True) +grp.create_dataset('Masses', data=m, dtype='f', compression="gzip", shuffle=True) +grp.create_dataset('SmoothingLength', data=h, dtype='f', compression="gzip", shuffle=True) +grp.create_dataset('InternalEnergy', data=u, dtype='f', compression="gzip", shuffle=True) +grp.create_dataset('ParticleIDs', data=ids, dtype='L', compression="gzip", shuffle=True) + +file.close() diff --git a/examples/ConstantCosmoVolume/plotSolution.py b/examples/ConstantCosmoVolume/plotSolution.py new file mode 100644 index 0000000000000000000000000000000000000000..6f772b85d76890dcdcd8f9eb4fdb53305dd26732 --- /dev/null +++ b/examples/ConstantCosmoVolume/plotSolution.py @@ -0,0 +1,224 @@ +################################################################################ +# This file is part of SWIFT. +# Copyright (c) 2018 Matthieu Schaller (matthieu.schaller@durham.ac.uk) +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU Lesser General Public License as published +# by the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU Lesser General Public License +# along with this program. If not, see <http://www.gnu.org/licenses/>. +# +################################################################################ + +# Computes the analytical solution of the Zeldovich pancake and compares with +# the simulation result + +# Parameters +T_i = 100. # Initial temperature of the gas (in K) +z_c = 1. # Redshift of caustic formation (non-linear collapse) +z_i = 100. # Initial redshift +gas_gamma = 5./3. # Gas adiabatic index + +# Physical constants needed for internal energy to temperature conversion +k_in_J_K = 1.38064852e-23 +mH_in_kg = 1.6737236e-27 + +import matplotlib +matplotlib.use("Agg") +from pylab import * +import h5py +import os.path + +# Plot parameters +params = {'axes.labelsize': 10, +'axes.titlesize': 10, +'font.size': 12, +'legend.fontsize': 12, +'xtick.labelsize': 10, +'ytick.labelsize': 10, +'text.usetex': True, + 'figure.figsize' : (9.90,6.45), +'figure.subplot.left' : 0.08, +'figure.subplot.right' : 0.99, +'figure.subplot.bottom' : 0.06, +'figure.subplot.top' : 0.99, +'figure.subplot.wspace' : 0.2, +'figure.subplot.hspace' : 0.12, +'lines.markersize' : 6, +'lines.linewidth' : 3., +'text.latex.unicode': True +} +rcParams.update(params) +rc('font',**{'family':'sans-serif','sans-serif':['Times']}) + +# Read the simulation data +sim = h5py.File("box_0000.hdf5", "r") +boxSize = sim["/Header"].attrs["BoxSize"][0] +time = sim["/Header"].attrs["Time"][0] +redshift = sim["/Header"].attrs["Redshift"][0] +a = sim["/Header"].attrs["Scale-factor"][0] +scheme = sim["/HydroScheme"].attrs["Scheme"] +kernel = sim["/HydroScheme"].attrs["Kernel function"] +neighbours = sim["/HydroScheme"].attrs["Kernel target N_ngb"] +eta = sim["/HydroScheme"].attrs["Kernel eta"] +git = sim["Code"].attrs["Git Revision"] +H_0 = sim["/Cosmology"].attrs["H0 [internal units]"][0] +unit_length_in_cgs = sim["/Units"].attrs["Unit length in cgs (U_L)"] +unit_mass_in_cgs = sim["/Units"].attrs["Unit mass in cgs (U_M)"] +unit_time_in_cgs = sim["/Units"].attrs["Unit time in cgs (U_t)"] +sim.close() + +# Mean quantities over time +z = np.zeros(120) +a = np.zeros(120) +S_mean = np.zeros(120) +S_std = np.zeros(120) +u_mean = np.zeros(120) +u_std = np.zeros(120) +P_mean = np.zeros(120) +P_std = np.zeros(120) +rho_mean = np.zeros(120) +rho_std = np.zeros(120) + +vx_mean = np.zeros(120) +vy_mean = np.zeros(120) +vz_mean = np.zeros(120) +vx_std = np.zeros(120) +vy_std = np.zeros(120) +vz_std = np.zeros(120) + +for i in range(120): + sim = h5py.File("box_%04d.hdf5"%i, "r") + + z[i] = sim["/Cosmology"].attrs["Redshift"][0] + a[i] = sim["/Cosmology"].attrs["Scale-factor"][0] + + S = sim["/PartType0/Entropy"][:] + S_mean[i] = np.mean(S) + S_std[i] = np.std(S) + + u = sim["/PartType0/InternalEnergy"][:] + u_mean[i] = np.mean(u) + u_std[i] = np.std(u) + + P = sim["/PartType0/Pressure"][:] + P_mean[i] = np.mean(P) + P_std[i] = np.std(P) + + rho = sim["/PartType0/Density"][:] + rho_mean[i] = np.mean(rho) + rho_std[i] = np.std(rho) + + v = sim["/PartType0/Velocities"][:,:] + vx_mean[i] = np.mean(v[:,0]) + vy_mean[i] = np.mean(v[:,1]) + vz_mean[i] = np.mean(v[:,2]) + vx_std[i] = np.std(v[:,0]) + vy_std[i] = np.std(v[:,1]) + vz_std[i] = np.std(v[:,2]) + +# Move to physical quantities +rho_mean_phys = rho_mean / a**3 +u_mean_phys = u_mean / a**(3*(gas_gamma - 1.)) +S_mean_phys = S_mean + +# Solution in physical coordinates +#T_solution = np.ones(T) / a + +figure() + +# Density evolution -------------------------------- +subplot(231)#, yscale="log") +semilogx(a, rho_mean, '-', color='r', lw=1) +xlabel("${\\rm Scale-factor}$", labelpad=0.) +ylabel("${\\rm Comoving~density}$", labelpad=0.) + +# Thermal energy evolution -------------------------------- +subplot(232)#, yscale="log") +semilogx(a, u_mean, '-', color='r', lw=1) +xlabel("${\\rm Scale-factor}$", labelpad=0.) +ylabel("${\\rm Comoving~internal~energy}$", labelpad=0.) + +# Entropy evolution -------------------------------- +subplot(233)#, yscale="log") +semilogx(a, S_mean, '-', color='r', lw=1) +xlabel("${\\rm Scale-factor}$", labelpad=0.) +ylabel("${\\rm Comoving~entropy}$", labelpad=0.) + +# Peculiar velocity evolution --------------------- +subplot(234) +semilogx(a, vx_mean, '-', color='r', lw=1) +semilogx(a, vy_mean, '-', color='g', lw=1) +semilogx(a, vz_mean, '-', color='b', lw=1) +xlabel("${\\rm Scale-factor}$", labelpad=0.) +ylabel("${\\rm Peculiar~velocity~mean}$", labelpad=0.) + +# Peculiar velocity evolution --------------------- +subplot(235) +semilogx(a, vx_std, '--', color='r', lw=1) +semilogx(a, vy_std, '--', color='g', lw=1) +semilogx(a, vz_std, '--', color='b', lw=1) +xlabel("${\\rm Scale-factor}$", labelpad=0.) +ylabel("${\\rm Peculiar~velocity~std-dev}$", labelpad=0.) + + +# Information ------------------------------------- +subplot(236, frameon=False) + +plot([-0.49, 0.1], [0.62, 0.62], 'k-', lw=1) +text(-0.49, 0.5, "$\\textsc{Swift}$ %s"%git, fontsize=10) +text(-0.49, 0.4, scheme, fontsize=10) +text(-0.49, 0.3, kernel, fontsize=10) +text(-0.49, 0.2, "$%.2f$ neighbours ($\\eta=%.3f$)"%(neighbours, eta), fontsize=10) +xlim(-0.5, 0.5) +ylim(0, 1) +xticks([]) +yticks([]) + +savefig("ConstantBox_comoving.png", dpi=200) + + + +figure() + +# Density evolution -------------------------------- +subplot(231)#, yscale="log") +loglog(a, rho_mean_phys, '-', color='r', lw=1) +xlabel("${\\rm Scale-factor}$") +ylabel("${\\rm Physical~density}$") + +# Thermal energy evolution -------------------------------- +subplot(232)#, yscale="log") +loglog(a, u_mean_phys, '-', color='r', lw=1) +xlabel("${\\rm Scale-factor}$") +ylabel("${\\rm Physical~internal~energy}$") + +# Entropy evolution -------------------------------- +subplot(233)#, yscale="log") +semilogx(a, S_mean_phys, '-', color='r', lw=1) +xlabel("${\\rm Scale-factor}$") +ylabel("${\\rm Physical~entropy}$") + +# Information ------------------------------------- +subplot(236, frameon=False) + +plot([-0.49, 0.1], [0.62, 0.62], 'k-', lw=1) +text(-0.49, 0.5, "$\\textsc{Swift}$ %s"%git, fontsize=10) +text(-0.49, 0.4, scheme, fontsize=10) +text(-0.49, 0.3, kernel, fontsize=10) +text(-0.49, 0.2, "$%.2f$ neighbours ($\\eta=%.3f$)"%(neighbours, eta), fontsize=10) +xlim(-0.5, 0.5) +ylim(0, 1) +xticks([]) +yticks([]) + +savefig("ConstantBox_physical.png", dpi=200) + + diff --git a/examples/ConstantCosmoVolume/run.sh b/examples/ConstantCosmoVolume/run.sh new file mode 100755 index 0000000000000000000000000000000000000000..521659b26d6e4d3c07a8322ba92fa3d52f0ba2cf --- /dev/null +++ b/examples/ConstantCosmoVolume/run.sh @@ -0,0 +1,14 @@ +#!/bin/bash + +# Generate the initial conditions if they are not present. +if [ ! -e constantBox.hdf5 ] +then + echo "Generating initial conditions for the uniform cosmo box example..." + python makeIC.py +fi + +# Run SWIFT +../swift -s -c -G -t 8 constant_volume.yml 2>&1 | tee output.log + +# Plot the result +python plotSolution.py $i diff --git a/examples/MoonFormingImpact/README.md b/examples/MoonFormingImpact/README.md deleted file mode 100644 index 97a84f67c6aeeff4176a1385381f1cfe9e340c91..0000000000000000000000000000000000000000 --- a/examples/MoonFormingImpact/README.md +++ /dev/null @@ -1,34 +0,0 @@ -Canonical Moon-Forming Giant Impact -=================================== - -NOTE: This doesn't really work because the EOS are different to Canup (2004) so -the impactor just glances then flies away! - -A version of the canonical moon-forming giant impact of Theia onto the early -Earth (Canup 2004; Barr 2016). Both bodies are here made of a (Tillotson) iron -core and granite mantle. Only ~10,000 particles are used for a quick and crude -simulation. - -Setup ------ - -In `swiftsim/`: - -`$ ./configure --with-hydro=minimal-multi-mat --with-equation-of-state=planetary` -`$ make` - -In `swiftsim/examples/MoonFormingImpact/`: - -`$ ./get_init_cond.sh` - -Run ---- - -`$ ./run.sh` - -Output ------- - -`$ python plot.py` -`$ mplayer anim.mpg` - diff --git a/examples/MoonFormingImpact/get_init_cond.sh b/examples/MoonFormingImpact/get_init_cond.sh deleted file mode 100755 index 7d63943c2c5dc3bd4ab88e63a2abba62cc3f04a5..0000000000000000000000000000000000000000 --- a/examples/MoonFormingImpact/get_init_cond.sh +++ /dev/null @@ -1,2 +0,0 @@ -#!/bin/bash -wget http://virgodb.cosma.dur.ac.uk/swift-webstorage/ICs/moon_forming_impact.hdf5 diff --git a/examples/MoonFormingImpact/moon_forming_impact.yml b/examples/MoonFormingImpact/moon_forming_impact.yml deleted file mode 100644 index 323adf7f3ac73f41b45b50eaa76a95033dca35d7..0000000000000000000000000000000000000000 --- a/examples/MoonFormingImpact/moon_forming_impact.yml +++ /dev/null @@ -1,48 +0,0 @@ -# Define the system of units to use internally. -InternalUnitSystem: - UnitMass_in_cgs: 5.9724e27 # Grams - UnitLength_in_cgs: 6.371e8 # Centimeters - UnitVelocity_in_cgs: 6.371e8 # 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: 100000 # The end time of the simulation (in internal units). - dt_min: 0.001 # The minimal time-step size of the simulation (in internal units). - dt_max: 100 # The maximal time-step size of the simulation (in internal units). - -# Parameters governing the snapshots -Snapshots: - # Common part of the name of output files - basename: snapshots/moon_forming_impact - time_first: 0 # Time of the first output (in internal units) - delta_time: 100 # Time difference between consecutive outputs (in internal units) - label_delta: 100 # Integer increment between snapshot output labels - -# Parameters governing the conserved quantities statistics -Statistics: - delta_time: 500 # 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. - CFL_condition: 0.2 # Courant-Friedrich-Levy condition for time integration. - -# Parameters for the self-gravity scheme -Gravity: - eta: 0.025 # Constant dimensionless multiplier for time integration. - theta: 0.7 # Opening angle (Multipole acceptance criterion) - comoving_softening: 0.005 # Comoving softening length (in internal units). - max_physical_softening: 0.005 # Physical softening length (in internal units). - -# Parameters related to the initial conditions -InitialConditions: - # The initial conditions file to read - file_name: moon_forming_impact.hdf5 - -# Parameters related to the equation of state -EoS: - planetary_use_Til: 1 # Whether to prepare the Tillotson EOS diff --git a/examples/MoonFormingImpact/plot.py b/examples/MoonFormingImpact/plot.py deleted file mode 100644 index aa0d64a5d0d06709d51b1db231c507e22861f36c..0000000000000000000000000000000000000000 --- a/examples/MoonFormingImpact/plot.py +++ /dev/null @@ -1,285 +0,0 @@ -""" -############################################################################### -# This file is part of SWIFT. -# Copyright (c) 2018 Jacob Kegerreis (jacob.kegerreis@durham.ac.uk) -# -# This program is free software: you can redistribute it and/or modify -# it under the terms of the GNU Lesser General Public License as published -# by the Free Software Foundation, either version 3 of the License, or -# (at your option) any later version. -# -# This program is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU General Public License for more details. -# -# You should have received a copy of the GNU Lesser General Public License -# along with this program. If not, see <http://www.gnu.org/licenses/>. -# -############################################################################### - -Plotting script for the Canonical Moon-Forming Giant Impact example. - -Save a figure for each snapshot in `./plots/` then make them into a simple -animation with ffmpeg in `./`. - -Usage: - `$ python plot.py time_end delta_time` - - Sys args: - + `time_end` | (opt) int | The time of the last snapshot to plot. - Default = 100000 - + `delta_time` | (opt) int | The time between successive snapshots. - Default = 100 -""" - -from __future__ import division -import numpy as np -import matplotlib -import matplotlib.pyplot as plt -import h5py -import sys -import subprocess - -# Particle array fields -dtype_picle = [ - ('m', float), ('x', float), ('y', float), ('z', float), ('v_x', float), - ('v_y', float), ('v_z', float), ('ID', int), ('rho', float), ('u', float), - ('phi', float), ('P', float), ('h', float), ('mat_ID', int), ('r', float) - ] - -s_to_hour = 1 / 60**2 - -# Snapshot info -file_snap = "./snapshots/moon_forming_impact_" -file_plot = "./plots/moon_forming_impact_" -# Number of particles in the target body -num_target = 9496 - -# Material types (copied from src/equation_of_state/planetary/equation_of_state.h) -type_factor = 100 -Di_type = { - 'Til' : 1, - 'HM80' : 2, - 'ANEOS' : 3, - 'SESAME' : 4, -} -Di_material = { - # Tillotson - 'Til_iron' : Di_type['Til']*type_factor, - 'Til_granite' : Di_type['Til']*type_factor + 1, - 'Til_water' : Di_type['Til']*type_factor + 2, - # Hubbard & MacFarlane (1980) Uranus/Neptune - 'HM80_HHe' : Di_type['HM80']*type_factor, # Hydrogen-helium atmosphere - 'HM80_ice' : Di_type['HM80']*type_factor + 1, # H20-CH4-NH3 ice mix - 'HM80_rock' : Di_type['HM80']*type_factor + 2, # SiO2-MgO-FeS-FeO rock mix - # ANEOS - 'ANEOS_iron' : Di_type['ANEOS']*type_factor, - 'MANEOS_forsterite' : Di_type['ANEOS']*type_factor + 1, - # SESAME - 'SESAME_iron' : Di_type['SESAME']*type_factor, -} - -# Material offset for impactor particles -ID_imp = 10000 -# Material colours -Di_mat_colour = { - # Target - Di_material['Til_iron'] : 'orange', - Di_material['Til_granite'] : '#FFF0E0', - # Impactor - Di_material['Til_iron'] + ID_imp : 'dodgerblue', - Di_material['Til_granite'] + ID_imp : '#A080D0', - } - - -def load_snapshot(filename): - """ Load the hdf5 snapshot file and return the structured particle array. - """ - # Add extension if needed - if (filename[-5:] != ".hdf5"): - filename += ".hdf5" - - # Load the hdf5 file - with h5py.File(filename, 'r') as f: - header = f['Header'].attrs - A2_pos = f['PartType0/Coordinates'].value - A2_vel = f['PartType0/Velocities'].value - - # Structured array of all particle data - A2_picle = np.empty(header['NumPart_Total'][0], - dtype=dtype_picle) - - A2_picle['x'] = A2_pos[:, 0] - A2_picle['y'] = A2_pos[:, 1] - A2_picle['z'] = A2_pos[:, 2] - A2_picle['v_x'] = A2_vel[:, 0] - A2_picle['v_y'] = A2_vel[:, 1] - A2_picle['v_z'] = A2_vel[:, 2] - A2_picle['m'] = f['PartType0/Masses'].value - A2_picle['ID'] = f['PartType0/ParticleIDs'].value - A2_picle['rho'] = f['PartType0/Density'].value - A2_picle['u'] = f['PartType0/InternalEnergy'].value - A2_picle['phi'] = f['PartType0/Potential'].value - A2_picle['P'] = f['PartType0/Pressure'].value - A2_picle['h'] = f['PartType0/SmoothingLength'].value - A2_picle['mat_ID'] = f['PartType0/MaterialID'].value - - return A2_picle - - -def process_particles(A2_picle, num_target): - """ Modify things like particle units, material IDs, and coordinate origins. - """ - # Offset material IDs for impactor particles - A2_picle['mat_ID'][A2_picle['ID'] >= num_target] += ID_imp - - # Shift coordinates to the centre of the target's core's mass and momentum - sel_tar = np.where(A2_picle['mat_ID'] == Di_material['Til_iron'])[0] - - # Centre of mass - m_tot = np.sum(A2_picle[sel_tar]['m']) - x_com = np.sum(A2_picle[sel_tar]['m'] * A2_picle[sel_tar]['x']) / m_tot - y_com = np.sum(A2_picle[sel_tar]['m'] * A2_picle[sel_tar]['y']) / m_tot - z_com = np.sum(A2_picle[sel_tar]['m'] * A2_picle[sel_tar]['z']) / m_tot - - # Change origin to the centre-of-mass - A2_picle['x'] -= x_com - A2_picle['y'] -= y_com - A2_picle['z'] -= z_com - A2_picle['r'] = np.sqrt( - A2_picle['x']**2 + A2_picle['y']**2 + A2_picle['z']**2 - ) - - # Centre of momentum - v_x_com = np.sum(A2_picle[sel_tar]['m'] * A2_picle[sel_tar]['v_x']) / m_tot - v_y_com = np.sum(A2_picle[sel_tar]['m'] * A2_picle[sel_tar]['v_y']) / m_tot - v_z_com = np.sum(A2_picle[sel_tar]['m'] * A2_picle[sel_tar]['v_z']) / m_tot - - # Change to the centre-of-momentum frame of reference - A2_picle['v_x'] -= v_x_com - A2_picle['v_y'] -= v_y_com - A2_picle['v_z'] -= v_z_com - - return A2_picle - - -def plot_snapshot(A2_picle, filename, time, ax_lim=100, dz=0.1): - """ Plot the snapshot particles and save the figure. - """ - # Add extension if needed - if (filename[-5:] != ".png"): - filename += ".png" - - fig = plt.figure(figsize=(9, 9)) - ax = fig.add_subplot(111, aspect='equal') - - # Plot slices in z below zero - for z in np.arange(-ax_lim, 0, dz): - sel_z = np.where((z < A2_picle['z']) & (A2_picle['z'] < z+dz))[0] - A2_picle_z = A2_picle[sel_z] - - # Plot each material - for mat_ID, colour in Di_mat_colour.iteritems(): - sel_col = np.where(A2_picle_z['mat_ID'] == mat_ID)[0] - - ax.scatter( - A2_picle_z[sel_col]['x'], A2_picle_z[sel_col]['y'], - c=colour, edgecolors='none', marker='.', s=50, alpha=0.7 - ) - - # Axes etc. - ax.set_axis_bgcolor('k') - - ax.set_xlabel("x Position ($R_\oplus$)") - ax.set_ylabel("y Position ($R_\oplus$)") - - ax.set_xlim(-ax_lim, ax_lim) - ax.set_ylim(-ax_lim, ax_lim) - - plt.text( - -0.92*ax_lim, 0.85*ax_lim, "%.1f h" % (time*s_to_hour), fontsize=20, - color='w' - ) - - # Font sizes - for item in ( - [ax.title, ax.xaxis.label, ax.yaxis.label] + ax.get_xticklabels() + - ax.get_yticklabels() - ): - item.set_fontsize(20) - - plt.tight_layout() - - plt.savefig(filename) - plt.close() - - -if __name__ == '__main__': - # Sys args - try: - time_end = int(sys.argv[1]) - - try: - delta_time = int(sys.argv[2]) - except IndexError: - delta_time = 100 - except IndexError: - time_end = 100000 - delta_time = 100 - - # Load and plot each snapshot - for i_snap in range(int(time_end/delta_time) + 1): - snap_time = i_snap * delta_time - print "\rPlotting snapshot %06d (%d of %d)" % ( - snap_time, i_snap+1, int(time_end/delta_time) - ), - sys.stdout.flush() - - # Load particle data - filename = "%s%06d" % (file_snap, snap_time) - A2_picle = load_snapshot(filename) - - # Process particle data - A2_picle = process_particles(A2_picle, num_target) - - # Plot particles - filename = "%s%06d" % (file_plot, snap_time) - plot_snapshot(A2_picle, filename, snap_time) - - # Animation - command = ( - "ffmpeg -framerate 12 -i plots/moon_forming_impact_%*.png -r 25 " - "anim.mpg -y" - ) - print "\n%s\n" % command - subprocess.check_output(command, shell=True) - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/examples/MoonFormingImpact/run.sh b/examples/MoonFormingImpact/run.sh deleted file mode 100755 index 165dae3a24a9c30960959fbb37aa6e1da2eb851f..0000000000000000000000000000000000000000 --- a/examples/MoonFormingImpact/run.sh +++ /dev/null @@ -1,2 +0,0 @@ -#!/bin/bash -../swift -G -s -t 8 moon_forming_impact.yml diff --git a/examples/SineWavePotential_1D/makeIC.py b/examples/SineWavePotential_1D/makeIC.py index 321af0714219dfa0c7cbb3d80845881dcbb8416d..afbf1bc0fa47a27677cb9c5645d439432bd9fd9a 100644 --- a/examples/SineWavePotential_1D/makeIC.py +++ b/examples/SineWavePotential_1D/makeIC.py @@ -31,12 +31,12 @@ cs2 = 2.*uconst/3. A = 10. fileName = "sineWavePotential.hdf5" -numPart = 100 +numPart = 1000 boxSize = 1. coords = np.zeros((numPart, 3)) v = np.zeros((numPart, 3)) -m = np.zeros(numPart) + 1. +m = np.zeros(numPart) + 1000. / numPart h = np.zeros(numPart) + 2./numPart u = np.zeros(numPart) + uconst ids = np.arange(numPart, dtype = 'L') diff --git a/examples/SineWavePotential_1D/plotSolution.py b/examples/SineWavePotential_1D/plotSolution.py index 65e981e4648fe0fe5d1da6cf3e753fb8a34f0fb4..3bb889aaabd3cdac0274afb09647d0e3aebb02cc 100644 --- a/examples/SineWavePotential_1D/plotSolution.py +++ b/examples/SineWavePotential_1D/plotSolution.py @@ -23,8 +23,13 @@ import numpy as np import h5py import sys +import matplotlib +matplotlib.use("Agg") import pylab as pl +pl.rcParams["figure.figsize"] = (12, 10) +pl.rcParams["text.usetex"] = True + # these should be the same as in makeIC.py uconst = 20.2615290634 cs2 = 2.*uconst/3. @@ -39,15 +44,20 @@ fileName = sys.argv[1] file = h5py.File(fileName, 'r') coords = np.array(file["/PartType0/Coordinates"]) rho = np.array(file["/PartType0/Density"]) +P = np.array(file["/PartType0/Pressure"]) u = np.array(file["/PartType0/InternalEnergy"]) -agrav = np.array(file["/PartType0/GravAcceleration"]) m = np.array(file["/PartType0/Masses"]) +vs = np.array(file["/PartType0/Velocities"]) ids = np.array(file["/PartType0/ParticleIDs"]) x = np.linspace(0., 1., 1000) rho_x = 1000.*np.exp(-0.5*A/np.pi/cs2*np.cos(2.*np.pi*x)) -P = cs2*rho +a = A * np.sin(2. * np.pi * x) + +apart = A * np.sin(2. * np.pi * coords[:,0]) +tkin = -0.5 * np.dot(apart, coords[:,0]) +print tkin, 0.5 * np.dot(m, vs[:,0]**2) ids_reverse = np.argsort(ids) @@ -65,13 +75,38 @@ for i in range(len(P)): corr = 1. idxp1 = ids_reverse[ip1] idxm1 = ids_reverse[im1] - gradP[i] = (P[idxp1]-P[idxm1])/(coords[idxp1,0]-coords[idxm1,0]) + gradP[i] = (P[idxp1] - P[idxm1])/(coords[idxp1,0] - coords[idxm1,0]) + +fig, ax = pl.subplots(2, 2, sharex = True) + +ax[0][0].plot(coords[:,0], rho, ".", label = "gizmo-mfm") +ax[0][0].plot(x, rho_x, "-", label = "stable solution") +ax[0][0].set_ylabel("$\\rho{}$ (code units)") +ax[0][0].legend(loc = "best") + +ax[0][1].plot(x, a, "-", label = "$\\nabla{}\\Phi{}$ external") +ax[0][1].plot(coords[:,0], gradP/rho, ".", + label = "$\\nabla{}P/\\rho{}$ gizmo-mfm") +ax[0][1].set_ylabel("force (code units)") +ax[0][1].legend(loc = "best") + +ax[1][0].axhline(y = uconst, label = "isothermal $u$", color = "k", + linestyle = "--") +ax[1][0].plot(coords[:,0], u, ".", label = "gizmo-mfm") +ax[1][0].set_ylabel("$u$ (code units)") +ax[1][0].set_xlabel("$x$ (code units)") +ax[1][0].legend(loc = "best") + +#ax[1][1].plot(coords[:,0], m, "y.") +#ax[1][1].set_ylabel("$m_i$ (code units)") +#ax[1][1].set_xlabel("$x$ (code units)") -fig, ax = pl.subplots(2, 2) +ax[1][1].axhline(y = 0., label = "target", color = "k", + linestyle = "--") +ax[1][1].plot(coords[:,0], vs[:,0], ".", label = "gizmo-mfm") +ax[1][1].set_ylabel("$v_x$ (code units)") +ax[1][1].set_xlabel("$x$ (code units)") +ax[1][1].legend(loc = "best") -ax[0][0].plot(coords[:,0], rho, "r.", markersize = 0.5) -ax[0][0].plot(x, rho_x, "g-") -ax[0][1].plot(coords[:,0], gradP/rho, "b.") -ax[1][0].plot(coords[:,0], agrav[:,0], "g.", markersize = 0.5) -ax[1][1].plot(coords[:,0], m, "y.") +pl.tight_layout() pl.savefig("{fileName}.png".format(fileName = fileName[:-5])) diff --git a/examples/SineWavePotential_1D/sineWavePotential.yml b/examples/SineWavePotential_1D/sineWavePotential.yml index 9662841032a12d48870f12de8c1bcfcd579a6b42..e6285785099f10902ea60b21334a0ad26c0593de 100644 --- a/examples/SineWavePotential_1D/sineWavePotential.yml +++ b/examples/SineWavePotential_1D/sineWavePotential.yml @@ -10,7 +10,7 @@ InternalUnitSystem: TimeIntegration: time_begin: 0. # The starting time of the simulation (in internal units). time_end: 10. # 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_min: 1e-8 # The minimal time-step size of the simulation (in internal units). dt_max: 1e-2 # The maximal time-step size of the simulation (in internal units). # Parameters governing the conserved quantities statistics @@ -36,3 +36,6 @@ InitialConditions: SineWavePotential: amplitude: 10. timestep_limit: 1. + +EoS: + isothermal_internal_energy: 20.2615290634 diff --git a/examples/UranusImpact/README.md b/examples/UranusImpact/README.md deleted file mode 100644 index 178a3937ecbe527df8e8e82a0d8fd8bcbf9dbef7..0000000000000000000000000000000000000000 --- a/examples/UranusImpact/README.md +++ /dev/null @@ -1,40 +0,0 @@ -Uranus Giant Impact -=================== - -A simple version of the low angular momentum impact onto the early Uranus shown -in Kegerreis et al. (2018), Fig. 2; with only ~10,000 particles for a quick and -crude simulation. - -The collision of a 2 Earth mass impactor onto a proto-Uranus that can explain -the spin of the present-day planet, with an angular momentum of 2e36 kg m^2 s^-1 -and velocity at infinity of 5 km s^-1 for a relatively head-on impact. - -Both bodies have a rocky core and icy mantle, with a hydrogen-helium atmosphere -on the target as well. Although with this low number of particles it cannot be -modelled in any detail. - -Setup ------ - -In `swiftsim/`: - -`$ ./configure --with-hydro=minimal-multi-mat --with-equation-of-state=planetary` - -`$ make` - -In `swiftsim/examples/UranusImpact/`: - -`$ ./get_init_cond.sh` - -Run ---- - -`$ ./run.sh` - -Analysis --------- - -`$ python plot.py` - -`$ mplayer anim.mpg` - diff --git a/examples/UranusImpact/get_init_cond.sh b/examples/UranusImpact/get_init_cond.sh deleted file mode 100755 index e12e009adfbd727cb2452ac21c477b3ecd77b9c9..0000000000000000000000000000000000000000 --- a/examples/UranusImpact/get_init_cond.sh +++ /dev/null @@ -1,2 +0,0 @@ -#!/bin/bash -wget http://virgodb.cosma.dur.ac.uk/swift-webstorage/ICs/uranus_impact.hdf5 diff --git a/examples/UranusImpact/plot.py b/examples/UranusImpact/plot.py deleted file mode 100644 index 3db3bf21bb15862ec524a069c38e47564b48df1d..0000000000000000000000000000000000000000 --- a/examples/UranusImpact/plot.py +++ /dev/null @@ -1,291 +0,0 @@ -""" -############################################################################### -# This file is part of SWIFT. -# Copyright (c) 2018 Jacob Kegerreis (jacob.kegerreis@durham.ac.uk) -# -# This program is free software: you can redistribute it and/or modify -# it under the terms of the GNU Lesser General Public License as published -# by the Free Software Foundation, either version 3 of the License, or -# (at your option) any later version. -# -# This program is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU General Public License for more details. -# -# You should have received a copy of the GNU Lesser General Public License -# along with this program. If not, see <http://www.gnu.org/licenses/>. -# -############################################################################### - -Plotting script for the Uranus Giant Impact example. - -Save a figure for each snapshot in `./plots/` then make them into a simple -animation with ffmpeg in `./`. - -The snapshot plots show all particles with z < 0, coloured by their material. - -Usage: - `$ python plot.py time_end delta_time` - - Sys args: - + `time_end` | (opt) int | The time of the last snapshot to plot. - Default = 100000 - + `delta_time` | (opt) int | The time between successive snapshots. - Default = 500 -""" - -from __future__ import division -import numpy as np -import matplotlib -import matplotlib.pyplot as plt -import h5py -import sys -import subprocess - -# Particle array fields -dtype_picle = [ - ('m', float), ('x', float), ('y', float), ('z', float), ('v_x', float), - ('v_y', float), ('v_z', float), ('ID', int), ('rho', float), ('u', float), - ('phi', float), ('P', float), ('h', float), ('mat_ID', int), ('r', float) - ] - -s_to_hour = 1 / 60**2 -R_Ea = 6.371e6 - -# Default sys args -time_end_default = 100000 -delta_time_default = 500 - -# Snapshot info -file_snap = "./snapshots/uranus_impact_" -file_plot = "./plots/uranus_impact_" - -# Number of particles in the target body -num_target = 8992 - -# Material types (copied from src/equation_of_state/planetary/equation_of_state.h) -type_factor = 100 -Di_type = { - 'Til' : 1, - 'HM80' : 2, - 'ANEOS' : 3, - 'SESAME' : 4, -} -Di_material = { - # Tillotson - 'Til_iron' : Di_type['Til']*type_factor, - 'Til_granite' : Di_type['Til']*type_factor + 1, - 'Til_water' : Di_type['Til']*type_factor + 2, - # Hubbard & MacFarlane (1980) Uranus/Neptune - 'HM80_HHe' : Di_type['HM80']*type_factor, # Hydrogen-helium atmosphere - 'HM80_ice' : Di_type['HM80']*type_factor + 1, # H20-CH4-NH3 ice mix - 'HM80_rock' : Di_type['HM80']*type_factor + 2, # SiO2-MgO-FeS-FeO rock mix - # ANEOS - 'ANEOS_iron' : Di_type['ANEOS']*type_factor, - 'MANEOS_forsterite' : Di_type['ANEOS']*type_factor + 1, - # SESAME - 'SESAME_iron' : Di_type['SESAME']*type_factor, -} - -# Material offset for impactor particles -ID_imp = 10000 -# Material colours -Di_mat_colour = { - # Target - Di_material['HM80_HHe'] : '#33DDFF', - Di_material['HM80_ice'] : 'lightsteelblue', - Di_material['HM80_rock'] : 'slategrey', - # Impactor - Di_material['HM80_ice'] + ID_imp : '#A080D0', - Di_material['HM80_rock'] + ID_imp : '#706050', - } - - -def load_snapshot(filename): - """ Load the hdf5 snapshot file and return the structured particle array. - """ - # Add extension if needed - if (filename[-5:] != ".hdf5"): - filename += ".hdf5" - - # Load the hdf5 file - with h5py.File(filename, 'r') as f: - header = f['Header'].attrs - A2_pos = f['PartType0/Coordinates'].value - A2_vel = f['PartType0/Velocities'].value - - # Structured array of all particle data - A2_picle = np.empty(header['NumPart_Total'][0], - dtype=dtype_picle) - - A2_picle['x'] = A2_pos[:, 0] - A2_picle['y'] = A2_pos[:, 1] - A2_picle['z'] = A2_pos[:, 2] - A2_picle['v_x'] = A2_vel[:, 0] - A2_picle['v_y'] = A2_vel[:, 1] - A2_picle['v_z'] = A2_vel[:, 2] - A2_picle['m'] = f['PartType0/Masses'].value - A2_picle['ID'] = f['PartType0/ParticleIDs'].value - A2_picle['rho'] = f['PartType0/Density'].value - A2_picle['u'] = f['PartType0/InternalEnergy'].value - A2_picle['phi'] = f['PartType0/Potential'].value - A2_picle['P'] = f['PartType0/Pressure'].value - A2_picle['h'] = f['PartType0/SmoothingLength'].value - A2_picle['mat_ID'] = f['PartType0/MaterialID'].value - - return A2_picle - - -def process_particles(A2_picle, num_target): - """ Modify things like particle units, material IDs, and coordinate origins. - """ - # Offset material IDs for impactor particles - A2_picle['mat_ID'][A2_picle['ID'] >= num_target] += ID_imp - - # Shift coordinates to the centre of the target's core's mass and momentum - sel_tar = np.where(A2_picle['mat_ID'] == Di_material['HM80_rock'])[0] - - # Centre of mass - m_tot = np.sum(A2_picle[sel_tar]['m']) - x_com = np.sum(A2_picle[sel_tar]['m'] * A2_picle[sel_tar]['x']) / m_tot - y_com = np.sum(A2_picle[sel_tar]['m'] * A2_picle[sel_tar]['y']) / m_tot - z_com = np.sum(A2_picle[sel_tar]['m'] * A2_picle[sel_tar]['z']) / m_tot - - # Change origin to the centre-of-mass - A2_picle['x'] -= x_com - A2_picle['y'] -= y_com - A2_picle['z'] -= z_com - A2_picle['r'] = np.sqrt( - A2_picle['x']**2 + A2_picle['y']**2 + A2_picle['z']**2 - ) - - # Centre of momentum - v_x_com = np.sum(A2_picle[sel_tar]['m'] * A2_picle[sel_tar]['v_x']) / m_tot - v_y_com = np.sum(A2_picle[sel_tar]['m'] * A2_picle[sel_tar]['v_y']) / m_tot - v_z_com = np.sum(A2_picle[sel_tar]['m'] * A2_picle[sel_tar]['v_z']) / m_tot - - # Change to the centre-of-momentum frame of reference - A2_picle['v_x'] -= v_x_com - A2_picle['v_y'] -= v_y_com - A2_picle['v_z'] -= v_z_com - - return A2_picle - - -def plot_snapshot(A2_picle, filename, time, ax_lim=13, dz=0.1): - """ Plot the snapshot particles and save the figure. - """ - # Add extension if needed - if (filename[-5:] != ".png"): - filename += ".png" - - fig = plt.figure(figsize=(9, 9)) - ax = fig.add_subplot(111, aspect='equal') - - # Plot slices in z below zero - for z in np.arange(-ax_lim, 0, dz): - sel_z = np.where((z < A2_picle['z']) & (A2_picle['z'] < z+dz))[0] - A2_picle_z = A2_picle[sel_z] - - # Plot each material - for mat_ID, colour in Di_mat_colour.iteritems(): - sel_col = np.where(A2_picle_z['mat_ID'] == mat_ID)[0] - - ax.scatter( - A2_picle_z[sel_col]['x'], A2_picle_z[sel_col]['y'], - c=colour, edgecolors='none', marker='.', s=50, alpha=0.7 - ) - - # Axes etc. - ax.set_axis_bgcolor('k') - - ax.set_xlabel("x Position ($R_\oplus$)") - ax.set_ylabel("y Position ($R_\oplus$)") - - ax.set_xlim(-ax_lim, ax_lim) - ax.set_ylim(-ax_lim, ax_lim) - - plt.text( - -0.92*ax_lim, 0.85*ax_lim, "%.1f h" % (time*s_to_hour), fontsize=20, - color='w' - ) - - # Font sizes - for item in ( - [ax.title, ax.xaxis.label, ax.yaxis.label] + ax.get_xticklabels() + - ax.get_yticklabels() - ): - item.set_fontsize(20) - - plt.tight_layout() - - plt.savefig(filename) - plt.close() - - -if __name__ == '__main__': - # Sys args - try: - time_end = int(sys.argv[1]) - try: - delta_time = int(sys.argv[2]) - except IndexError: - delta_time = delta_time_default - except IndexError: - time_end = time_end_default - delta_time = delta_time_default - - # Load and plot each snapshot - for i_snap in range(int(time_end/delta_time) + 1): - snap_time = i_snap * delta_time - print "\rPlotting snapshot %06d (%d of %d)" % ( - snap_time, i_snap+1, int(time_end/delta_time) - ), - sys.stdout.flush() - - # Load particle data - filename = "%s%06d" % (file_snap, snap_time) - A2_picle = load_snapshot(filename) - - # Process particle data - A2_picle = process_particles(A2_picle, num_target) - - # Plot particles - filename = "%s%06d" % (file_plot, snap_time) - plot_snapshot(A2_picle, filename, snap_time) - - # Animation - command = ( - "ffmpeg -framerate 10 -i plots/uranus_impact_%*.png -r 25 anim.mpg -y" - ) - print "\n$ %s\n" % command - subprocess.call(command, shell=True) - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/examples/UranusImpact/run.sh b/examples/UranusImpact/run.sh deleted file mode 100755 index c6773b7e40fff3fa312dfcb5ba4ada9d9e4b1b8d..0000000000000000000000000000000000000000 --- a/examples/UranusImpact/run.sh +++ /dev/null @@ -1,2 +0,0 @@ -#!/bin/bash -../swift -G -s -t 8 uranus_impact.yml diff --git a/examples/UranusImpact/uranus_impact.yml b/examples/UranusImpact/uranus_impact.yml deleted file mode 100644 index fabddca00f80fcdd79ff6114ff0544cd251046f4..0000000000000000000000000000000000000000 --- a/examples/UranusImpact/uranus_impact.yml +++ /dev/null @@ -1,51 +0,0 @@ -# Define the system of units to use internally. -InternalUnitSystem: - UnitMass_in_cgs: 5.9724e27 # Grams - UnitLength_in_cgs: 6.371e8 # Centimeters - UnitVelocity_in_cgs: 6.371e8 # 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: 100000 # The end time of the simulation (in internal units). - dt_min: 0.001 # The minimal time-step size of the simulation (in internal units). - dt_max: 100 # The maximal time-step size of the simulation (in internal units). - -# Parameters governing the snapshots -Snapshots: - # Common part of the name of output files - basename: snapshots/uranus_impact - time_first: 0 # Time of the first output (in internal units) - delta_time: 500 # Time difference between consecutive outputs (in internal units) - label_delta: 500 # Integer increment between snapshot output labels - -# Parameters governing the conserved quantities statistics -Statistics: - delta_time: 1000 # 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. - CFL_condition: 0.2 # Courant-Friedrich-Levy condition for time integration. - -# Parameters for the self-gravity scheme -Gravity: - eta: 0.025 # Constant dimensionless multiplier for time integration. - theta: 0.7 # Opening angle (Multipole acceptance criterion) - comoving_softening: 0.01 # Comoving softening length (in internal units). - max_physical_softening: 0.01 # Physical softening length (in internal units). - -# Parameters related to the initial conditions -InitialConditions: - file_name: uranus_impact.hdf5 # The initial conditions file to read - -# Parameters related to the equation of state -EoS: - planetary_use_HM80: 1 # Whether to prepare the Hubbard & MacFarlane (1980) EOS - # Table file paths - planetary_HM80_HHe_table_file: /gpfs/data/dc-kege1/gihr_data/P_rho_u_HHe.txt - planetary_HM80_ice_table_file: /gpfs/data/dc-kege1/gihr_data/P_rho_u_ice.txt - planetary_HM80_rock_table_file: /gpfs/data/dc-kege1/gihr_data/P_rho_u_roc.txt diff --git a/examples/ZeldovichPancake_3D/makeIC.py b/examples/ZeldovichPancake_3D/makeIC.py index 15fb8bdef95f6e830e78f4d1b2c419051a6f00af..79ed7e71e924941102049b8457fe070ebd08f5c2 100644 --- a/examples/ZeldovichPancake_3D/makeIC.py +++ b/examples/ZeldovichPancake_3D/makeIC.py @@ -28,29 +28,34 @@ z_c = 1. # Redshift of caustic formation (non-linear collapse) z_i = 100. # Initial redshift gamma = 5./3. # Gas adiabatic index numPart_1D = 32 # Number of particles along each dimension +fileName = "zeldovichPancake.hdf5" # Some units -Mpc_in_m = 3.085678e22 -Msol_in_kg = 1.989e30 -Gyr_in_s = 3.085678e19 +Mpc_in_m = 3.08567758e22 +Msol_in_kg = 1.98848e30 +Gyr_in_s = 3.08567758e19 mH_in_kg = 1.6737236e-27 -k_in_J_K = 1.38064852e-23 -# Parameters -rho_0 = 1.8788e-26 # h^2 kg m^-3 -H_0 = 1. / Mpc_in_m * 10**5 # s^-1 +# Some constants +kB_in_SI = 1.38064852e-23 +G_in_SI = 6.67408e-11 + +# Some useful variables in h-full units +H_0 = 1. / Mpc_in_m * 10**5 # h s^-1 +rho_0 = 3. * H_0**2 / (8* math.pi * G_in_SI) # h^2 kg m^-3 lambda_i = 64. / H_0 * 10**5 # h^-1 m (= 64 h^-1 Mpc) x_min = -0.5 * lambda_i x_max = 0.5 * lambda_i -fileName = "zeldovichPancake.hdf5" +# SI system of units unit_l_in_si = Mpc_in_m unit_m_in_si = Msol_in_kg * 1.e10 unit_t_in_si = Gyr_in_s unit_v_in_si = unit_l_in_si / unit_t_in_si unit_u_in_si = unit_v_in_si**2 +# Total number of particles numPart = numPart_1D**3 #--------------------------------------------------- @@ -87,7 +92,7 @@ for i in range(numPart_1D): coords[index,1] = (j + 0.5) * delta_x coords[index,2] = (k + 0.5) * delta_x T = T_i * (1. / (1. - zfac * cos(k_i * q)))**(2. / 3.) - u[index] = k_in_J_K * T / (gamma - 1.) / mH_in_kg + u[index] = kB_in_SI * T / (gamma - 1.) / mH_in_kg h[index] = 1.2348 * delta_x m[index] = m_i v[index,0] = -H_0 * (1. + z_c) / sqrt(1. + z_i) * sin(k_i * q) / k_i @@ -141,7 +146,7 @@ grp.create_dataset('ParticleIDs', data=ids, dtype='L') file.close() -import pylab as pl +#import pylab as pl -pl.plot(coords[:,0], v[:,0], "k.") -pl.show() +#pl.plot(coords[:,0], v[:,0], "k.") +#pl.show() diff --git a/examples/ZeldovichPancake_3D/plotSolution.py b/examples/ZeldovichPancake_3D/plotSolution.py index 163e61eb9d3738c39912c8c42c0b6c6bb9990cac..2a175e346e041a142c6921052ccf13978afa8a38 100644 --- a/examples/ZeldovichPancake_3D/plotSolution.py +++ b/examples/ZeldovichPancake_3D/plotSolution.py @@ -138,8 +138,8 @@ if np.size(x_g) > 1: plot(x_g, v_g, 's', color='g', alpha=0.8, lw=1.2, ms=4) plot(x, v, '.', color='r', ms=4.0) plot(x_s, v_s, '--', color='k', alpha=0.8, lw=1.2) -xlabel("${\\rm{Comoving Position}}~x$", labelpad=0) -ylabel("${\\rm{Peculiar Velocity}}~v_x$", labelpad=0) +xlabel("${\\rm{Comoving~position}}~x$", labelpad=0) +ylabel("${\\rm{Peculiar~velocity}}~v_x$", labelpad=0) # Density profile -------------------------------- @@ -148,7 +148,7 @@ if np.size(x_g) > 1: plot(x_g, rho_g/rho_0, 's', color='g', alpha=0.8, lw=1.2, ms=4) plot(x, rho/rho_0, '.', color='r', ms=4.0) plot(x_s, rho_s/rho_0, '--', color='k', alpha=0.8, lw=1.2) -xlabel("${\\rm{Comoving Position}}~x$", labelpad=0) +xlabel("${\\rm{Comoving~position}}~x$", labelpad=0) ylabel("${\\rm{Density}}~\\rho / \\rho_0$", labelpad=0) # Potential profile -------------------------------- @@ -156,7 +156,7 @@ subplot(233) if np.size(x_g) > 1: plot(x_g, phi_g, 's', color='g', alpha=0.8, lw=1.2, ms=4) plot(x, phi, '.', color='r', ms=4.0) -xlabel("${\\rm{Comoving Position}}~x$", labelpad=0) +xlabel("${\\rm{Comoving~position}}~x$", labelpad=0) ylabel("${\\rm{Potential}}~\\phi$", labelpad=0) # Temperature profile ------------------------- @@ -172,7 +172,7 @@ if np.size(x_g) > 1: plot(x_g, T_g, 's', color='g', alpha=0.8, lw=1.2, ms=4) plot(x, T, '.', color='r', ms=4.0) plot(x_s, T_s, '--', color='k', alpha=0.8, lw=1.2) -xlabel("${\\rm{Comoving Position}}~x$", labelpad=0) +xlabel("${\\rm{Comoving~position}}~x$", labelpad=0) ylabel("${\\rm{Temperature}}~T$", labelpad=0) # Information ------------------------------------- diff --git a/examples/ZeldovichPancake_3D/run.sh b/examples/ZeldovichPancake_3D/run.sh index 9b6b8166ac0d084898b96e2de6b0fc1ef378aecd..b3f802f978377a9615f7cdd1cdd14e85ae3baad2 100755 --- a/examples/ZeldovichPancake_3D/run.sh +++ b/examples/ZeldovichPancake_3D/run.sh @@ -8,7 +8,7 @@ then fi # Run SWIFT -../swift -a -s -c -G -t 8 zeldovichPancake.yml 2>&1 | tee output.log +../swift -s -c -G -t 8 zeldovichPancake.yml 2>&1 | tee output.log # Plot the result for i in {0..119} diff --git a/examples/ZeldovichPancake_3D/zeldovichPancake.yml b/examples/ZeldovichPancake_3D/zeldovichPancake.yml index 481432d5875470aa464f69d5aa47fb76328cde7d..5cfa01ff954a959e06076035ae22240bb3c5a120 100644 --- a/examples/ZeldovichPancake_3D/zeldovichPancake.yml +++ b/examples/ZeldovichPancake_3D/zeldovichPancake.yml @@ -17,7 +17,7 @@ Cosmology: # Parameters governing the time integration TimeIntegration: dt_min: 1e-7 # The minimal time-step size of the simulation (in internal units). - dt_max: 1e-3 # The maximal time-step size of the simulation (in internal units). + dt_max: 4e-3 # The maximal time-step size of the simulation (in internal units). # Parameters governing the snapshots Snapshots: @@ -42,10 +42,9 @@ InitialConditions: Scheduler: max_top_level_cells: 8 cell_split_size: 50 - tasks_per_cell: 125 Gravity: - mesh_side_length: 16 + mesh_side_length: 32 eta: 0.025 theta: 0.3 r_cut_max: 5. diff --git a/examples/parameter_example.yml b/examples/parameter_example.yml index ddb71c594122a3e8d6ddbd7c5b73e0474b404a75..5fb48eb17d1c210d2a320917e1fd5d1ad67ddd94 100644 --- a/examples/parameter_example.yml +++ b/examples/parameter_example.yml @@ -75,6 +75,7 @@ Snapshots: time_first: 0. # (Optional) Time of the first output if non-cosmological time-integration (in internal units) delta_time: 0.01 # Time difference between consecutive outputs (in internal units) compression: 0 # (Optional) Set the level of compression of the HDF5 datasets [0-9]. 0 does no compression. + label_first: 0 # (Optional) An additional offset for the snapshot output label label_delta: 1 # (Optional) Set the integer increment between snapshot output labels UnitMass_in_cgs: 1 # (Optional) Unit system for the outputs (Grams) UnitLength_in_cgs: 1 # (Optional) Unit system for the outputs (Centimeters) @@ -142,9 +143,13 @@ EoS: planetary_use_ANEOS: 0 # (Optional) Whether to prepare the ANEOS EOS planetary_use_SESAME: 0 # (Optional) Whether to prepare the SESAME EOS # (Optional) Table file paths - planetary_HM80_HHe_table_file: HM80_HHe.txt - planetary_HM80_ice_table_file: HM80_ice.txt - planetary_HM80_rock_table_file: HM80_rock.txt + planetary_HM80_HHe_table_file: ./equation_of_state/planetary_HM80_HHe.txt + planetary_HM80_ice_table_file: ./equation_of_state/planetary_HM80_ice.txt + planetary_HM80_rock_table_file: ./equation_of_state/planetary_HM80_rock.txt + planetary_SESAME_iron_table_file: ./equation_of_state/planetary_SESAME_iron_2140.txt + planetary_SESAME_basalt_table_file: ./equation_of_state/planetary_SESAME_basalt_7530.txt + planetary_SESAME_water_table_file: ./equation_of_state/planetary_SESAME_water_7154.txt + planetary_SS08_water_table_file: ./equation_of_state/planetary_SS08_water.txt # Parameters related to external potentials -------------------------------------------- diff --git a/src/Makefile.am b/src/Makefile.am index fbc1d9fdc025dca2a498208ddce98e716fa2fd03..0f61fb108d8d8acbd420c994266f4803a3f69d3e 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -106,7 +106,6 @@ nobase_noinst_HEADERS = align.h approx_math.h atomic.h barrier.h cycle.h error.h hydro/GizmoMFM/hydro_slope_limiters_face.h \ hydro/GizmoMFM/hydro_slope_limiters.h \ hydro/GizmoMFM/hydro_unphysical.h \ - hydro/GizmoMFM/hydro_velocities.h \ hydro/Shadowswift/hydro_debug.h \ hydro/Shadowswift/hydro_gradients.h hydro/Shadowswift/hydro.h \ hydro/Shadowswift/hydro_iact.h \ diff --git a/src/cell.c b/src/cell.c index 8ca6771a43929b924003630f80b56cbf6d185fa8..1ceb0556a5bfada87d2a5b160dd6c353724dc315 100644 --- a/src/cell.c +++ b/src/cell.c @@ -62,6 +62,7 @@ #include "space.h" #include "space_getsid.h" #include "timers.h" +#include "tools.h" /* Global variables. */ int cell_next_tag = 0; @@ -2587,6 +2588,36 @@ void cell_drift_part(struct cell *c, const struct engine *e, int force) { } #endif +#ifdef PLANETARY_SPH + /* Remove particles that cross the non-periodic box edge */ + if (!(e->s->periodic)) { + for (int i = 0; i < 3; i++) { + if ((p->x[i] - xp->v_full[i] * dt_drift > e->s->dim[i]) || + (p->x[i] - xp->v_full[i] * dt_drift < 0.f) || + ((p->mass != 0.f) && ((p->x[i] < 0.01f * e->s->dim[i]) || + (p->x[i] > 0.99f * e->s->dim[i])))) { + /* (TEMPORARY) Crudely stop the particle manually */ + message( + "Particle %lld hit a box edge. \n" + " pos=%.4e %.4e %.4e vel=%.2e %.2e %.2e", + p->id, p->x[0], p->x[1], p->x[2], p->v[0], p->v[1], p->v[2]); + for (int j = 0; j < 3; j++) { + p->v[j] = 0.f; + p->gpart->v_full[j] = 0.f; + xp->v_full[j] = 0.f; + } + p->h = hydro_h_max; + p->time_bin = time_bin_inhibited; + p->gpart->time_bin = time_bin_inhibited; + hydro_part_has_no_neighbours(p, xp, e->cosmology); + p->mass = 0.f; + p->gpart->mass = 0.f; + break; + } + } + } +#endif + /* Limit h to within the allowed range */ p->h = min(p->h, hydro_h_max); @@ -2689,6 +2720,26 @@ void cell_drift_gpart(struct cell *c, const struct engine *e, int force) { /* Drift... */ drift_gpart(gp, dt_drift, ti_old_gpart, ti_current); +#ifdef PLANETARY_SPH + /* Remove particles that cross the non-periodic box edge */ + if (!(e->s->periodic)) { + for (int i = 0; i < 3; i++) { + if ((gp->x[i] - gp->v_full[i] * dt_drift > e->s->dim[i]) || + (gp->x[i] - gp->v_full[i] * dt_drift < 0.f) || + ((gp->mass != 0.f) && ((gp->x[i] < 0.01f * e->s->dim[i]) || + (gp->x[i] > 0.99f * e->s->dim[i])))) { + /* (TEMPORARY) Crudely stop the particle manually */ + for (int j = 0; j < 3; j++) { + gp->v_full[j] = 0.f; + } + gp->time_bin = time_bin_inhibited; + gp->mass = 0.f; + break; + } + } + } +#endif + /* Init gravity force fields. */ if (gpart_is_active(gp, e)) { gravity_init_gpart(gp); diff --git a/src/cosmology.c b/src/cosmology.c index 0c81cb00aaae8d0c8d0974e02c41ad99c9e83840..e9d35125f65777ffb7f143896029c5720c14cc54 100644 --- a/src/cosmology.c +++ b/src/cosmology.c @@ -265,6 +265,29 @@ double hydro_kick_integrand(double a, void *param) { return (1. / H) * pow(a_inv, 3. * hydro_gamma_minus_one) * a_inv; } +/** + * @brief Computes \f$a dt\f$ for the current cosmology. + * + * @param a The scale-factor of interest. + * @param param The current #cosmology. + */ +double hydro_kick_corr_integrand(double a, void *param) { + + const struct cosmology *c = (const struct cosmology *)param; + const double Omega_r = c->Omega_r; + const double Omega_m = c->Omega_m; + const double Omega_k = c->Omega_k; + const double Omega_l = c->Omega_lambda; + const double w_0 = c->w_0; + const double w_a = c->w_a; + const double H0 = c->H0; + + const double E_z = E(Omega_r, Omega_m, Omega_k, Omega_l, w_0, w_a, a); + const double H = H0 * E_z; + + return 1. / H; +} + /** * @brief Computes \f$ dt \f$ for the current cosmology. * @@ -306,6 +329,8 @@ void cosmology_init_tables(struct cosmology *c) { (double *)malloc(cosmology_table_length * sizeof(double)); c->hydro_kick_fac_interp_table = (double *)malloc(cosmology_table_length * sizeof(double)); + c->hydro_kick_corr_interp_table = + (double *)malloc(cosmology_table_length * sizeof(double)); c->time_interp_table = (double *)malloc(cosmology_table_length * sizeof(double)); c->scale_factor_interp_table = @@ -354,6 +379,16 @@ void cosmology_init_tables(struct cosmology *c) { c->hydro_kick_fac_interp_table[i] = result; } + /* Integrate the kick correction factor \int_{a_begin}^{a_table[i]} a dt */ + F.function = &hydro_kick_corr_integrand; + for (int i = 0; i < cosmology_table_length; i++) { + gsl_integration_qag(&F, a_begin, a_table[i], 0, 1.0e-10, GSL_workspace_size, + GSL_INTEG_GAUSS61, space, &result, &abserr); + + /* Store result */ + c->hydro_kick_corr_interp_table[i] = result; + } + /* Integrate the time \int_{a_begin}^{a_table[i]} dt */ F.function = &time_integrand; for (int i = 0; i < cosmology_table_length; i++) { @@ -374,31 +409,43 @@ void cosmology_init_tables(struct cosmology *c) { GSL_INTEG_GAUSS61, space, &result, &abserr); c->universe_age_at_present_day = result; - /* Inverse t(a) */ - const double time_init = c->time_interp_table_offset; - const double delta_t = - (c->universe_age_at_present_day - time_init) / cosmology_table_length; + /* Update the times */ + c->time_begin = cosmology_get_time_since_big_bang(c, c->a_begin); + c->time_end = cosmology_get_time_since_big_bang(c, c->a_end); - int i_prev = 0; - for (int i = 0; i < cosmology_table_length; i++) { - /* Current time */ - double time_interp = delta_t * i; + /* + * Inverse t(a) + */ + + const double delta_t = (c->time_end - c->time_begin) / cosmology_table_length; + + /* index in the time_interp_table */ + int i_a = 0; + + for (int i_time = 0; i_time < cosmology_table_length; i_time++) { + /* Current time + * time_interp_table = \int_a_begin^a => no need of time_begin */ + double time_interp = delta_t * (i_time + 1); /* Find next time in time_interp_table */ - while (i_prev < cosmology_table_length && - c->time_interp_table[i_prev] <= time_interp) { - i_prev++; + while (i_a < cosmology_table_length && + c->time_interp_table[i_a] <= time_interp) { + i_a++; } /* Find linear interpolation scaling */ - double scale = time_interp - c->time_interp_table[i_prev - 1]; - scale /= c->time_interp_table[i_prev] - c->time_interp_table[i_prev - 1]; - scale += i_prev; + double scale = 0; + if (i_a != cosmology_table_length) { + scale = time_interp - c->time_interp_table[i_a - 1]; + scale /= c->time_interp_table[i_a] - c->time_interp_table[i_a - 1]; + } + + scale += i_a; /* Compute interpolated scale factor */ double log_a = c->log_a_begin + scale * (c->log_a_end - c->log_a_begin) / cosmology_table_length; - c->scale_factor_interp_table[i] = exp(log_a) - c->a_begin; + c->scale_factor_interp_table[i_time] = exp(log_a) - c->a_begin; } /* Free the workspace and temp array */ @@ -586,7 +633,8 @@ double cosmology_get_grav_kick_factor(const struct cosmology *c, /** * @brief Computes the cosmology factor that enters the hydro kick operator. * - * Computes \f$ \int_{a_start}^{a_end} dt/a \f$ using the interpolation table. + * Computes \f$ \int_{a_start}^{a_end} dt/a^{3(gamma - 1)} \f$ using the + * interpolation table. * * @param c The current #cosmology. * @param ti_start the (integer) time of the start of the drift. @@ -603,9 +651,38 @@ double cosmology_get_hydro_kick_factor(const struct cosmology *c, const double a_start = c->log_a_begin + ti_start * c->time_base; const double a_end = c->log_a_begin + ti_end * c->time_base; - const double int_start = interp_table(c->drift_fac_interp_table, a_start, + const double int_start = interp_table(c->hydro_kick_fac_interp_table, a_start, c->log_a_begin, c->log_a_end); - const double int_end = interp_table(c->drift_fac_interp_table, a_end, + const double int_end = interp_table(c->hydro_kick_fac_interp_table, a_end, + c->log_a_begin, c->log_a_end); + + return int_end - int_start; +} + +/** + * @brief Computes the cosmology factor that enters the hydro kick correction + * operator for the meshless schemes (GIZMO-MFV). + * + * Computes \f$ \int_{a_start}^{a_end} a dt \f$ using the interpolation table. + * + * @param c The current #cosmology. + * @param ti_start the (integer) time of the start of the drift. + * @param ti_end the (integer) time of the end of the drift. + */ +double cosmology_get_corr_kick_factor(const struct cosmology *c, + integertime_t ti_start, + integertime_t ti_end) { + +#ifdef SWIFT_DEBUG_CHECKS + if (ti_end < ti_start) error("ti_end must be >= ti_start"); +#endif + + const double a_start = c->log_a_begin + ti_start * c->time_base; + const double a_end = c->log_a_begin + ti_end * c->time_base; + + const double int_start = interp_table(c->hydro_kick_corr_interp_table, + a_start, c->log_a_begin, c->log_a_end); + const double int_end = interp_table(c->hydro_kick_corr_interp_table, a_end, c->log_a_begin, c->log_a_end); return int_end - int_start; @@ -632,9 +709,9 @@ double cosmology_get_therm_kick_factor(const struct cosmology *c, const double a_start = c->log_a_begin + ti_start * c->time_base; const double a_end = c->log_a_begin + ti_end * c->time_base; - const double int_start = interp_table(c->hydro_kick_fac_interp_table, a_start, + const double int_start = interp_table(c->drift_fac_interp_table, a_start, c->log_a_begin, c->log_a_end); - const double int_end = interp_table(c->hydro_kick_fac_interp_table, a_end, + const double int_end = interp_table(c->drift_fac_interp_table, a_end, c->log_a_begin, c->log_a_end); return int_end - int_start; @@ -672,9 +749,6 @@ double cosmology_get_delta_time(const struct cosmology *c, /** * @brief Compute scale factor from time since big bang (in internal units). * - * WARNING: This method has a low accuracy at high redshift. - * The relative error is around 1e-3 (testCosmology.c is measuring it). - * * @param c The current #cosmology. * @param t time since the big bang * @return The scale factor. @@ -707,6 +781,7 @@ void cosmology_clean(struct cosmology *c) { free(c->drift_fac_interp_table); free(c->grav_kick_fac_interp_table); free(c->hydro_kick_fac_interp_table); + free(c->hydro_kick_corr_interp_table); free(c->time_interp_table); free(c->scale_factor_interp_table); } diff --git a/src/cosmology.h b/src/cosmology.h index 7136b65667195953971060b76ddfd447a5fdf500..4556b039bd0e306dab37a05bc200c3aa2ab8a602 100644 --- a/src/cosmology.h +++ b/src/cosmology.h @@ -153,6 +153,9 @@ struct cosmology { /*! Kick factor (hydro) interpolation table */ double *hydro_kick_fac_interp_table; + /*! Kick factor (hydro correction) interpolation table (GIZMO-MFV only) */ + double *hydro_kick_corr_interp_table; + /*! Time interpolation table */ double *time_interp_table; @@ -180,6 +183,9 @@ double cosmology_get_hydro_kick_factor(const struct cosmology *cosmo, double cosmology_get_therm_kick_factor(const struct cosmology *cosmo, integertime_t ti_start, integertime_t ti_end); +double cosmology_get_corr_kick_factor(const struct cosmology *cosmo, + integertime_t ti_start, + integertime_t ti_end); double cosmology_get_delta_time(const struct cosmology *c, integertime_t ti_start, integertime_t ti_end); diff --git a/src/debug.c b/src/debug.c index da8ef0e118b57a6aa94577898b03bcf7c56b006a..5c2523da7b97e44febe52405e954eef1c5f865d2 100644 --- a/src/debug.c +++ b/src/debug.c @@ -56,8 +56,8 @@ #include "./hydro/GizmoMFM/hydro_debug.h" #elif defined(SHADOWFAX_SPH) #include "./hydro/Shadowswift/hydro_debug.h" -#elif defined(MINIMAL_MULTI_MAT_SPH) -#include "./hydro/MinimalMultiMat/hydro_debug.h" +#elif defined(PLANETARY_SPH) +#include "./hydro/Planetary/hydro_debug.h" #else #error "Invalid choice of SPH variant" #endif diff --git a/src/engine.c b/src/engine.c index 93c033d0c398e7a0e9865ab1feb5e0ef5c34d290..78705411d455ab032d184410cad3f957b7b0cfec 100644 --- a/src/engine.c +++ b/src/engine.c @@ -62,6 +62,7 @@ #include "cosmology.h" #include "cycle.h" #include "debug.h" +#include "equation_of_state.h" #include "error.h" #include "gravity.h" #include "gravity_cache.h" @@ -2745,6 +2746,9 @@ void engine_link_gravity_tasks(struct engine *e) { /* Get a pointer to the task. */ struct task *t = &sched->tasks[k]; + if(t->type == task_type_none) + continue; + /* Get the cells we act on */ struct cell *ci = t->ci; struct cell *cj = t->cj; @@ -5770,6 +5774,10 @@ void engine_init(struct engine *e, struct space *s, struct swift_params *params, parser_get_param_string(params, "Snapshots:basename", e->snapshot_base_name); e->snapshot_compression = parser_get_opt_param_int(params, "Snapshots:compression", 0); + e->snapshot_label_first = + parser_get_opt_param_int(params, "Snapshots:label_first", 0); + if (e->snapshot_label_first < 0) + error("Snapshots:label_first must be zero or positive"); e->snapshot_label_delta = parser_get_opt_param_int(params, "Snapshots:label_delta", 1); e->snapshot_units = (struct unit_system *)malloc(sizeof(struct unit_system)); @@ -6980,6 +6988,10 @@ void engine_struct_restore(struct engine *e, FILE *stream) { e->output_list_stf = output_list_stf; } +#ifdef EOS_PLANETARY + eos_init(&eos, e->physical_constants, e->snapshot_units, e->parameter_file); +#endif + /* Want to force a rebuild before using this engine. Wait to repartition.*/ e->forcerebuild = 1; e->forcerepart = 0; diff --git a/src/engine.h b/src/engine.h index aeb57c65ac36ff5ddbf4b74185adeb94f3d460da..cfd656712bdea84484101cf7e83795f795200f5f 100644 --- a/src/engine.h +++ b/src/engine.h @@ -223,6 +223,7 @@ struct engine { char snapshot_base_name[PARSER_MAX_LINE_SIZE]; int snapshot_compression; + int snapshot_label_first; int snapshot_label_delta; struct unit_system *snapshot_units; int snapshot_output_count; diff --git a/src/equation_of_state/planetary/aneos.h b/src/equation_of_state/planetary/aneos.h deleted file mode 100644 index 904288b2fdf3ba825cdc7d114ebb61cd42de198d..0000000000000000000000000000000000000000 --- a/src/equation_of_state/planetary/aneos.h +++ /dev/null @@ -1,144 +0,0 @@ -/******************************************************************************* - * This file is part of SWIFT. - * Copyright (c) 2016 Matthieu Schaller (matthieu.schaller@durham.ac.uk). - * 2018 Jacob Kegerreis (jacob.kegerreis@durham.ac.uk). - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU Lesser General Public License as published - * by the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public License - * along with this program. If not, see <http://www.gnu.org/licenses/>. - * - ******************************************************************************/ -#ifndef SWIFT_ANEOS_EQUATION_OF_STATE_H -#define SWIFT_ANEOS_EQUATION_OF_STATE_H - -/** - * @file equation_of_state/planetary/aneos.h - * - * Contains the (M)ANEOS EOS functions for - * equation_of_state/planetary/equation_of_state.h - * - * Adapted from the implementation in Gadget 2 of Cuk & Stewart (2012) - * - */ - -/* Some standard headers. */ -#include <math.h> - -/* Local headers. */ -#include "adiabatic_index.h" -#include "common_io.h" -#include "equation_of_state.h" -#include "inline.h" -#include "physical_constants.h" -#include "units.h" - -// ANEOS parameters -struct ANEOS_params { - enum eos_planetary_material_id mat_id; -}; - -// Parameter values for each material (cgs units) -INLINE static void set_ANEOS_iron(struct ANEOS_params *mat, - enum eos_planetary_material_id mat_id) { - mat->mat_id = mat_id; -} -INLINE static void set_MANEOS_forsterite( - struct ANEOS_params *mat, enum eos_planetary_material_id mat_id) { - mat->mat_id = mat_id; -} - -// Convert from cgs to internal units -INLINE static void convert_units_ANEOS(struct ANEOS_params *mat, - const struct unit_system *us) {} - -// gas_internal_energy_from_entropy -INLINE static float ANEOS_internal_energy_from_entropy( - float density, float entropy, const struct ANEOS_params *mat) { - - error("This EOS function is not yet implemented!"); - - return 0; -} - -// gas_pressure_from_entropy -INLINE static float ANEOS_pressure_from_entropy( - float density, float entropy, const struct ANEOS_params *mat) { - - error("This EOS function is not yet implemented!"); - - return 0; -} - -// gas_entropy_from_pressure -INLINE static float ANEOS_entropy_from_pressure( - float density, float pressure, const struct ANEOS_params *mat) { - - error("This EOS function is not yet implemented!"); - - return 0; -} - -// gas_soundspeed_from_entropy -INLINE static float ANEOS_soundspeed_from_entropy( - float density, float entropy, const struct ANEOS_params *mat) { - - error("This EOS function is not yet implemented!"); - - return 0; -} - -// gas_entropy_from_internal_energy -INLINE static float ANEOS_entropy_from_internal_energy( - float density, float u, const struct ANEOS_params *mat) { - - error("This EOS function is not yet implemented!"); - - return 0; -} - -// gas_pressure_from_internal_energy -INLINE static float ANEOS_pressure_from_internal_energy( - float density, float u, const struct ANEOS_params *mat) { - - error("This EOS function is not yet implemented!"); - - return 0; -} - -// gas_internal_energy_from_pressure -INLINE static float ANEOS_internal_energy_from_pressure( - float density, float P, const struct ANEOS_params *mat) { - - error("This EOS function is not yet implemented!"); - - return 0; -} - -// gas_soundspeed_from_internal_energy -INLINE static float ANEOS_soundspeed_from_internal_energy( - float density, float u, const struct ANEOS_params *mat) { - - error("This EOS function is not yet implemented!"); - - return 0; -} - -// gas_soundspeed_from_pressure -INLINE static float ANEOS_soundspeed_from_pressure( - float density, float P, const struct ANEOS_params *mat) { - - error("This EOS function is not yet implemented!"); - - return 0; -} - -#endif /* SWIFT_ANEOS_EQUATION_OF_STATE_H */ diff --git a/src/equation_of_state/planetary/equation_of_state.h b/src/equation_of_state/planetary/equation_of_state.h index 61e23dc0b4eb82e9ae5c0869f7a10dfff97fc45e..644167bb4795a2a3d0fefe130cba93c64f29941b 100644 --- a/src/equation_of_state/planetary/equation_of_state.h +++ b/src/equation_of_state/planetary/equation_of_state.h @@ -39,6 +39,7 @@ #include "common_io.h" #include "inline.h" #include "physical_constants.h" +#include "restart.h" #include "units.h" extern struct eos_parameters eos; @@ -50,10 +51,15 @@ extern struct eos_parameters eos; * @brief Master type for the planetary equation of state. */ enum eos_planetary_type_id { + + /*! Tillotson */ eos_planetary_type_Til = 1, + + /*! Hubbard & MacFarlane (1980) Uranus/Neptune */ eos_planetary_type_HM80 = 2, - eos_planetary_type_ANEOS = 3, - eos_planetary_type_SESAME = 4, + + /*! SESAME */ + eos_planetary_type_SESAME = 3, }; /** @@ -89,25 +95,26 @@ enum eos_planetary_material_id { eos_planetary_id_HM80_rock = eos_planetary_type_HM80 * eos_planetary_type_factor + 2, - /* ANEOS */ - - /*! ANEOS iron */ - eos_planetary_id_ANEOS_iron = - eos_planetary_type_ANEOS * eos_planetary_type_factor, - - /*! MANEOS forsterite */ - eos_planetary_id_MANEOS_forsterite = - eos_planetary_type_ANEOS * eos_planetary_type_factor + 1, - /* SESAME */ - /*! SESAME iron */ + /*! SESAME iron 2140 */ eos_planetary_id_SESAME_iron = eos_planetary_type_SESAME * eos_planetary_type_factor, + + /*! SESAME basalt 7530 */ + eos_planetary_id_SESAME_basalt = + eos_planetary_type_SESAME * eos_planetary_type_factor + 1, + + /*! SESAME water 7154 */ + eos_planetary_id_SESAME_water = + eos_planetary_type_SESAME * eos_planetary_type_factor + 2, + + /*! Senft & Stewart (2008) SESAME-like water */ + eos_planetary_id_SS08_water = + eos_planetary_type_SESAME * eos_planetary_type_factor + 3, }; /* Individual EOS function headers. */ -#include "aneos.h" #include "hm80.h" #include "sesame.h" #include "tillotson.h" @@ -118,8 +125,7 @@ enum eos_planetary_material_id { struct eos_parameters { struct Til_params Til_iron, Til_granite, Til_water; struct HM80_params HM80_HHe, HM80_ice, HM80_rock; - struct ANEOS_params ANEOS_iron, MANEOS_forsterite; - struct SESAME_params SESAME_iron; + struct SESAME_params SESAME_iron, SESAME_basalt, SESAME_water, SS08_water; }; /** @@ -190,35 +196,29 @@ gas_internal_energy_from_entropy(float density, float entropy, }; break; - /* ANEOS EoS */ - case eos_planetary_type_ANEOS: + /* SESAME EoS */ + case eos_planetary_type_SESAME:; /* Select the material */ switch (mat_id) { - case eos_planetary_id_ANEOS_iron: - return ANEOS_internal_energy_from_entropy(density, entropy, - &eos.ANEOS_iron); + case eos_planetary_id_SESAME_iron: + return SESAME_internal_energy_from_entropy(density, entropy, + &eos.SESAME_iron); break; - case eos_planetary_id_MANEOS_forsterite: - return ANEOS_internal_energy_from_entropy(density, entropy, - &eos.MANEOS_forsterite); + case eos_planetary_id_SESAME_basalt: + return SESAME_internal_energy_from_entropy(density, entropy, + &eos.SESAME_basalt); break; - default: - error("Unknown material ID! mat_id = %d", mat_id); - return 0.f; - }; - break; - - /* SESAME EoS */ - case eos_planetary_type_SESAME:; + case eos_planetary_id_SESAME_water: + return SESAME_internal_energy_from_entropy(density, entropy, + &eos.SESAME_water); + break; - /* Select the material */ - switch (mat_id) { - case eos_planetary_id_SESAME_iron: + case eos_planetary_id_SS08_water: return SESAME_internal_energy_from_entropy(density, entropy, - &eos.SESAME_iron); + &eos.SS08_water); break; default: @@ -294,34 +294,29 @@ __attribute__((always_inline)) INLINE static float gas_pressure_from_entropy( }; break; - /* ANEOS EoS */ - case eos_planetary_type_ANEOS: + /* SESAME EoS */ + case eos_planetary_type_SESAME:; /* Select the material */ switch (mat_id) { - case eos_planetary_id_ANEOS_iron: - return ANEOS_pressure_from_entropy(density, entropy, &eos.ANEOS_iron); + case eos_planetary_id_SESAME_iron: + return SESAME_pressure_from_entropy(density, entropy, + &eos.SESAME_iron); break; - case eos_planetary_id_MANEOS_forsterite: - return ANEOS_pressure_from_entropy(density, entropy, - &eos.MANEOS_forsterite); + case eos_planetary_id_SESAME_basalt: + return SESAME_pressure_from_entropy(density, entropy, + &eos.SESAME_basalt); break; - default: - error("Unknown material ID! mat_id = %d", mat_id); - return 0.f; - }; - break; - - /* SESAME EoS */ - case eos_planetary_type_SESAME:; + case eos_planetary_id_SESAME_water: + return SESAME_pressure_from_entropy(density, entropy, + &eos.SESAME_water); - /* Select the material */ - switch (mat_id) { - case eos_planetary_id_SESAME_iron: + case eos_planetary_id_SS08_water: return SESAME_pressure_from_entropy(density, entropy, - &eos.SESAME_iron); + &eos.SS08_water); + break; break; default: @@ -398,33 +393,25 @@ __attribute__((always_inline)) INLINE static float gas_entropy_from_pressure( }; break; - /* ANEOS EoS */ - case eos_planetary_type_ANEOS: + /* SESAME EoS */ + case eos_planetary_type_SESAME:; /* Select the material */ switch (mat_id) { - case eos_planetary_id_ANEOS_iron: - return ANEOS_entropy_from_pressure(density, P, &eos.ANEOS_iron); + case eos_planetary_id_SESAME_iron: + return SESAME_entropy_from_pressure(density, P, &eos.SESAME_iron); break; - case eos_planetary_id_MANEOS_forsterite: - return ANEOS_entropy_from_pressure(density, P, - &eos.MANEOS_forsterite); + case eos_planetary_id_SESAME_basalt: + return SESAME_entropy_from_pressure(density, P, &eos.SESAME_basalt); break; - default: - error("Unknown material ID! mat_id = %d", mat_id); - return 0.f; - }; - break; - - /* SESAME EoS */ - case eos_planetary_type_SESAME:; + case eos_planetary_id_SESAME_water: + return SESAME_entropy_from_pressure(density, P, &eos.SESAME_water); + break; - /* Select the material */ - switch (mat_id) { - case eos_planetary_id_SESAME_iron: - return SESAME_entropy_from_pressure(density, P, &eos.SESAME_iron); + case eos_planetary_id_SS08_water: + return SESAME_entropy_from_pressure(density, P, &eos.SS08_water); break; default: @@ -501,35 +488,29 @@ __attribute__((always_inline)) INLINE static float gas_soundspeed_from_entropy( }; break; - /* ANEOS EoS */ - case eos_planetary_type_ANEOS: + /* SESAME EoS */ + case eos_planetary_type_SESAME:; /* Select the material */ switch (mat_id) { - case eos_planetary_id_ANEOS_iron: - return ANEOS_soundspeed_from_entropy(density, entropy, - &eos.ANEOS_iron); + case eos_planetary_id_SESAME_iron: + return SESAME_soundspeed_from_entropy(density, entropy, + &eos.SESAME_iron); break; - case eos_planetary_id_MANEOS_forsterite: - return ANEOS_soundspeed_from_entropy(density, entropy, - &eos.MANEOS_forsterite); + case eos_planetary_id_SESAME_basalt: + return SESAME_soundspeed_from_entropy(density, entropy, + &eos.SESAME_basalt); break; - default: - error("Unknown material ID! mat_id = %d", mat_id); - return 0.f; - }; - break; - - /* SESAME EoS */ - case eos_planetary_type_SESAME:; + case eos_planetary_id_SESAME_water: + return SESAME_soundspeed_from_entropy(density, entropy, + &eos.SESAME_water); + break; - /* Select the material */ - switch (mat_id) { - case eos_planetary_id_SESAME_iron: + case eos_planetary_id_SS08_water: return SESAME_soundspeed_from_entropy(density, entropy, - &eos.SESAME_iron); + &eos.SS08_water); break; default: @@ -605,35 +586,29 @@ gas_entropy_from_internal_energy(float density, float u, }; break; - /* ANEOS EoS */ - case eos_planetary_type_ANEOS: + /* SESAME EoS */ + case eos_planetary_type_SESAME:; /* Select the material */ switch (mat_id) { - case eos_planetary_id_ANEOS_iron: - return ANEOS_entropy_from_internal_energy(density, u, - &eos.ANEOS_iron); + case eos_planetary_id_SESAME_iron: + return SESAME_entropy_from_internal_energy(density, u, + &eos.SESAME_iron); break; - case eos_planetary_id_MANEOS_forsterite: - return ANEOS_entropy_from_internal_energy(density, u, - &eos.MANEOS_forsterite); + case eos_planetary_id_SESAME_basalt: + return SESAME_entropy_from_internal_energy(density, u, + &eos.SESAME_basalt); break; - default: - error("Unknown material ID! mat_id = %d", mat_id); - return 0.f; - }; - break; - - /* SESAME EoS */ - case eos_planetary_type_SESAME:; + case eos_planetary_id_SESAME_water: + return SESAME_entropy_from_internal_energy(density, u, + &eos.SESAME_water); + break; - /* Select the material */ - switch (mat_id) { - case eos_planetary_id_SESAME_iron: + case eos_planetary_id_SS08_water: return SESAME_entropy_from_internal_energy(density, u, - &eos.SESAME_iron); + &eos.SS08_water); break; default: @@ -711,35 +686,29 @@ gas_pressure_from_internal_energy(float density, float u, }; break; - /* ANEOS EoS */ - case eos_planetary_type_ANEOS: + /* SESAME EoS */ + case eos_planetary_type_SESAME:; /* Select the material */ switch (mat_id) { - case eos_planetary_id_ANEOS_iron: - return ANEOS_pressure_from_internal_energy(density, u, - &eos.ANEOS_iron); + case eos_planetary_id_SESAME_iron: + return SESAME_pressure_from_internal_energy(density, u, + &eos.SESAME_iron); break; - case eos_planetary_id_MANEOS_forsterite: - return ANEOS_pressure_from_internal_energy(density, u, - &eos.MANEOS_forsterite); + case eos_planetary_id_SESAME_basalt: + return SESAME_pressure_from_internal_energy(density, u, + &eos.SESAME_basalt); break; - default: - error("Unknown material ID! mat_id = %d", mat_id); - return 0.f; - }; - break; - - /* SESAME EoS */ - case eos_planetary_type_SESAME:; + case eos_planetary_id_SESAME_water: + return SESAME_pressure_from_internal_energy(density, u, + &eos.SESAME_water); + break; - /* Select the material */ - switch (mat_id) { - case eos_planetary_id_SESAME_iron: + case eos_planetary_id_SS08_water: return SESAME_pressure_from_internal_energy(density, u, - &eos.SESAME_iron); + &eos.SS08_water); break; default: @@ -820,35 +789,29 @@ gas_internal_energy_from_pressure(float density, float P, }; break; - /* ANEOS EoS */ - case eos_planetary_type_ANEOS: + /* SESAME EoS */ + case eos_planetary_type_SESAME:; /* Select the material */ switch (mat_id) { - case eos_planetary_id_ANEOS_iron: - return ANEOS_internal_energy_from_pressure(density, P, - &eos.ANEOS_iron); + case eos_planetary_id_SESAME_iron: + return SESAME_internal_energy_from_pressure(density, P, + &eos.SESAME_iron); break; - case eos_planetary_id_MANEOS_forsterite: - return ANEOS_internal_energy_from_pressure(density, P, - &eos.MANEOS_forsterite); + case eos_planetary_id_SESAME_basalt: + return SESAME_internal_energy_from_pressure(density, P, + &eos.SESAME_basalt); break; - default: - error("Unknown material ID! mat_id = %d", mat_id); - return 0.f; - }; - break; - - /* SESAME EoS */ - case eos_planetary_type_SESAME:; + case eos_planetary_id_SESAME_water: + return SESAME_internal_energy_from_pressure(density, P, + &eos.SESAME_water); + break; - /* Select the material */ - switch (mat_id) { - case eos_planetary_id_SESAME_iron: + case eos_planetary_id_SS08_water: return SESAME_internal_energy_from_pressure(density, P, - &eos.SESAME_iron); + &eos.SS08_water); break; default: @@ -930,35 +893,29 @@ gas_soundspeed_from_internal_energy(float density, float u, }; break; - /* ANEOS EoS */ - case eos_planetary_type_ANEOS: + /* SESAME EoS */ + case eos_planetary_type_SESAME:; /* Select the material */ switch (mat_id) { - case eos_planetary_id_ANEOS_iron: - return ANEOS_soundspeed_from_internal_energy(density, u, - &eos.ANEOS_iron); + case eos_planetary_id_SESAME_iron: + return SESAME_soundspeed_from_internal_energy(density, u, + &eos.SESAME_iron); break; - case eos_planetary_id_MANEOS_forsterite: - return ANEOS_soundspeed_from_internal_energy(density, u, - &eos.MANEOS_forsterite); + case eos_planetary_id_SESAME_basalt: + return SESAME_soundspeed_from_internal_energy(density, u, + &eos.SESAME_basalt); break; - default: - error("Unknown material ID! mat_id = %d", mat_id); - return 0.f; - }; - break; - - /* SESAME EoS */ - case eos_planetary_type_SESAME:; + case eos_planetary_id_SESAME_water: + return SESAME_soundspeed_from_internal_energy(density, u, + &eos.SESAME_water); + break; - /* Select the material */ - switch (mat_id) { - case eos_planetary_id_SESAME_iron: + case eos_planetary_id_SS08_water: return SESAME_soundspeed_from_internal_energy(density, u, - &eos.SESAME_iron); + &eos.SS08_water); break; default: @@ -1034,33 +991,26 @@ __attribute__((always_inline)) INLINE static float gas_soundspeed_from_pressure( }; break; - /* ANEOS EoS */ - case eos_planetary_type_ANEOS: + /* SESAME EoS */ + case eos_planetary_type_SESAME:; /* Select the material */ switch (mat_id) { - case eos_planetary_id_ANEOS_iron: - return ANEOS_soundspeed_from_pressure(density, P, &eos.ANEOS_iron); + case eos_planetary_id_SESAME_iron: + return SESAME_soundspeed_from_pressure(density, P, &eos.SESAME_iron); break; - case eos_planetary_id_MANEOS_forsterite: - return ANEOS_soundspeed_from_pressure(density, P, - &eos.MANEOS_forsterite); + case eos_planetary_id_SESAME_basalt: + return SESAME_soundspeed_from_pressure(density, P, + &eos.SESAME_basalt); break; - default: - error("Unknown material ID! mat_id = %d", mat_id); - return 0.f; - }; - break; - - /* SESAME EoS */ - case eos_planetary_type_SESAME:; + case eos_planetary_id_SESAME_water: + return SESAME_soundspeed_from_pressure(density, P, &eos.SESAME_water); + break; - /* Select the material */ - switch (mat_id) { - case eos_planetary_id_SESAME_iron: - return SESAME_soundspeed_from_pressure(density, P, &eos.SESAME_iron); + case eos_planetary_id_SS08_water: + return SESAME_soundspeed_from_pressure(density, P, &eos.SS08_water); break; default: @@ -1089,6 +1039,10 @@ __attribute__((always_inline)) INLINE static void eos_init( char HM80_HHe_table_file[PARSER_MAX_LINE_SIZE]; char HM80_ice_table_file[PARSER_MAX_LINE_SIZE]; char HM80_rock_table_file[PARSER_MAX_LINE_SIZE]; + char SESAME_iron_table_file[PARSER_MAX_LINE_SIZE]; + char SESAME_basalt_table_file[PARSER_MAX_LINE_SIZE]; + char SESAME_water_table_file[PARSER_MAX_LINE_SIZE]; + char SS08_water_table_file[PARSER_MAX_LINE_SIZE]; // Set the parameters and material IDs, load tables, etc. for each material // and convert to internal units @@ -1116,30 +1070,49 @@ __attribute__((always_inline)) INLINE static void eos_init( parser_get_param_string(params, "EoS:planetary_HM80_rock_table_file", HM80_rock_table_file); - load_HM80_table(&e->HM80_HHe, HM80_HHe_table_file); - load_HM80_table(&e->HM80_ice, HM80_ice_table_file); - load_HM80_table(&e->HM80_rock, HM80_rock_table_file); + load_table_HM80(&e->HM80_HHe, HM80_HHe_table_file); + load_table_HM80(&e->HM80_ice, HM80_ice_table_file); + load_table_HM80(&e->HM80_rock, HM80_rock_table_file); + + prepare_table_HM80(&e->HM80_HHe); + prepare_table_HM80(&e->HM80_ice); + prepare_table_HM80(&e->HM80_rock); convert_units_HM80(&e->HM80_HHe, us); convert_units_HM80(&e->HM80_ice, us); convert_units_HM80(&e->HM80_rock, us); } - // ANEOS - if (parser_get_opt_param_int(params, "EoS:planetary_use_ANEOS", 0)) { - set_ANEOS_iron(&e->ANEOS_iron, eos_planetary_id_ANEOS_iron); - set_MANEOS_forsterite(&e->MANEOS_forsterite, - eos_planetary_id_MANEOS_forsterite); - - convert_units_ANEOS(&e->ANEOS_iron, us); - convert_units_ANEOS(&e->MANEOS_forsterite, us); - } - // SESAME if (parser_get_opt_param_int(params, "EoS:planetary_use_SESAME", 0)) { set_SESAME_iron(&e->SESAME_iron, eos_planetary_id_SESAME_iron); + set_SESAME_basalt(&e->SESAME_basalt, eos_planetary_id_SESAME_basalt); + set_SESAME_water(&e->SESAME_water, eos_planetary_id_SESAME_water); + set_SS08_water(&e->SESAME_water, eos_planetary_id_SS08_water); + + parser_get_param_string(params, "EoS:planetary_SESAME_iron_table_file", + SESAME_iron_table_file); + parser_get_param_string(params, "EoS:planetary_SESAME_basalt_table_file", + SESAME_basalt_table_file); + parser_get_param_string(params, "EoS:planetary_SESAME_water_table_file", + SESAME_water_table_file); + parser_get_param_string(params, "EoS:planetary_SS08_water_table_file", + SS08_water_table_file); + + load_table_SESAME(&e->SESAME_iron, SESAME_iron_table_file); + load_table_SESAME(&e->SESAME_basalt, SESAME_basalt_table_file); + load_table_SESAME(&e->SESAME_water, SESAME_water_table_file); + load_table_SESAME(&e->SS08_water, SS08_water_table_file); + + prepare_table_SESAME(&e->SESAME_iron); + prepare_table_SESAME(&e->SESAME_basalt); + prepare_table_SESAME(&e->SESAME_water); + prepare_table_SESAME(&e->SS08_water); convert_units_SESAME(&e->SESAME_iron, us); + convert_units_SESAME(&e->SESAME_basalt, us); + convert_units_SESAME(&e->SESAME_water, us); + convert_units_SESAME(&e->SS08_water, us); } } diff --git a/src/equation_of_state/planetary/get_eos_tables.sh b/src/equation_of_state/planetary/get_eos_tables.sh new file mode 100755 index 0000000000000000000000000000000000000000..c0a751252bb060341a01ac70320a16251069a84e --- /dev/null +++ b/src/equation_of_state/planetary/get_eos_tables.sh @@ -0,0 +1,10 @@ +#!/bin/bash + +# Download the tables of the publicly available planetary equations of state +wget http://virgodb.cosma.dur.ac.uk/swift-webstorage/EoS/planetary_HM80_HHe.txt +wget http://virgodb.cosma.dur.ac.uk/swift-webstorage/EoS/planetary_HM80_ice.txt +wget http://virgodb.cosma.dur.ac.uk/swift-webstorage/EoS/planetary_HM80_rock.txt + +mv planetary_HM80_HHe.txt ../../../examples/ +mv planetary_HM80_ice.txt ../../../examples/ +mv planetary_HM80_rock.txt ../../../examples/ diff --git a/src/equation_of_state/planetary/hm80.h b/src/equation_of_state/planetary/hm80.h index 0131bab6c447e5a8898e29e13dc3f8f6e1c897c6..5e80c240018756cb57cc8974df4974a6cc53724a 100644 --- a/src/equation_of_state/planetary/hm80.h +++ b/src/equation_of_state/planetary/hm80.h @@ -41,75 +41,80 @@ // Hubbard & MacFarlane (1980) parameters struct HM80_params { - float *table_P_rho_u; + float *table_log_P_rho_u; int num_rho, num_u; float log_rho_min, log_rho_max, log_rho_step, inv_log_rho_step, log_u_min, - log_u_max, log_u_step, inv_log_u_step, bulk_mod; + log_u_max, log_u_step, inv_log_u_step, bulk_mod, P_min_for_c_min; enum eos_planetary_material_id mat_id; }; -// Parameter values for each material (cgs units) +// Parameter values for each material (SI units) INLINE static void set_HM80_HHe(struct HM80_params *mat, enum eos_planetary_material_id mat_id) { mat->mat_id = mat_id; - mat->num_rho = 100; - mat->num_u = 100; - mat->log_rho_min = -9.2103404f; - mat->log_rho_max = 1.6094379f; - mat->log_rho_step = 0.1092907f; - mat->log_u_min = 9.2103404f; - mat->log_u_max = 22.3327037f; - mat->log_u_step = 0.1325491f; - mat->bulk_mod = 0; - - mat->inv_log_rho_step = 1.f / mat->log_rho_step; - mat->inv_log_u_step = 1.f / mat->log_u_step; + mat->bulk_mod = 0.f; + mat->P_min_for_c_min = 1e3f; } INLINE static void set_HM80_ice(struct HM80_params *mat, enum eos_planetary_material_id mat_id) { mat->mat_id = mat_id; - mat->num_rho = 200; - mat->num_u = 200; - mat->log_rho_min = -6.9077553f; - mat->log_rho_max = 2.7080502f; - mat->log_rho_step = 0.0483206f; - mat->log_u_min = 6.9077553f; - mat->log_u_max = 22.3327037f; - mat->log_u_step = 0.0775123f; - mat->bulk_mod = 2.0e10f; - - mat->inv_log_rho_step = 1.f / mat->log_rho_step; - mat->inv_log_u_step = 1.f / mat->log_u_step; + mat->bulk_mod = 2.0e9f; + mat->P_min_for_c_min = 0.f; } INLINE static void set_HM80_rock(struct HM80_params *mat, enum eos_planetary_material_id mat_id) { mat->mat_id = mat_id; - mat->num_rho = 100; - mat->num_u = 100; - mat->log_rho_min = -6.9077553f; - mat->log_rho_max = 2.9957323f; - mat->log_rho_step = 0.1000352f; - mat->log_u_min = 9.2103404f; - mat->log_u_max = 20.7232658f; - mat->log_u_step = 0.1162922f; - mat->bulk_mod = 3.49e11f; - - mat->inv_log_rho_step = 1.f / mat->log_rho_step; - mat->inv_log_u_step = 1.f / mat->log_u_step; + mat->bulk_mod = 3.49e10f; + mat->P_min_for_c_min = 0.f; } // Read the table from file -INLINE static void load_HM80_table(struct HM80_params *mat, char *table_file) { - // Allocate table memory - mat->table_P_rho_u = - (float *)malloc(mat->num_rho * mat->num_u * sizeof(float *)); +INLINE static void load_table_HM80(struct HM80_params *mat, char *table_file) { + + /* File contents: + header (four lines) + log_rho_min log_rho_max num_rho log_u_min log_u_max num_u (SI) + P_0_0 P_0_1 ... P_0_num_u # Array of pressures (Pa) + P_1_0 ... ... P_1_num_u + ... ... ... ... + P_num_rho_0 ... P_num_rho_num_u + T_0_0 T_0_1 ... T_0_num_u # Array of temperatures (K) + T_1_0 ... ... T_1_num_u + ... ... ... ... + T_num_rho_0 ... T_num_rho_num_u + */ // Load table contents from file FILE *f = fopen(table_file, "r"); int c; - for (int i = 0; i < mat->num_rho; i++) { - for (int j = 0; j < mat->num_u; j++) { - c = fscanf(f, "%f", &mat->table_P_rho_u[i * mat->num_rho + j]); + + // Ignore header lines + char buffer[100]; + for (int i = 0; i < 4; i++) { + if (fgets(buffer, 100, f) == NULL) + error("Something incorrect happening with the file header."); + } + + // Table properties + c = fscanf(f, "%f %f %d %f %f %d", &mat->log_rho_min, &mat->log_rho_max, + &mat->num_rho, &mat->log_u_min, &mat->log_u_max, &mat->num_u); + if (c != 6) { + error("Failed to read EOS table %s", table_file); + } + mat->log_rho_step = + (mat->log_rho_max - mat->log_rho_min) / (mat->num_rho - 1); + mat->log_u_step = (mat->log_u_max - mat->log_u_min) / (mat->num_u - 1); + mat->inv_log_rho_step = 1.f / mat->log_rho_step; + mat->inv_log_u_step = 1.f / mat->log_u_step; + + // Allocate table memory + mat->table_log_P_rho_u = + (float *)malloc(mat->num_rho * mat->num_u * sizeof(float)); + + // Pressures (not log yet) + for (int i_rho = 0; i_rho < mat->num_rho; i_rho++) { + for (int i_u = 0; i_u < mat->num_u; i_u++) { + c = fscanf(f, "%f", &mat->table_log_P_rho_u[i_rho * mat->num_u + i_u]); if (c != 1) { error("Failed to read EOS table"); } @@ -118,33 +123,49 @@ INLINE static void load_HM80_table(struct HM80_params *mat, char *table_file) { fclose(f); } -// Convert from cgs to internal units +// Misc. modifications +INLINE static void prepare_table_HM80(struct HM80_params *mat) { + + // Convert pressures to log(pressure) + for (int i_rho = 0; i_rho < mat->num_rho; i_rho++) { + for (int i_u = 0; i_u < mat->num_u; i_u++) { + mat->table_log_P_rho_u[i_rho * mat->num_u + i_u] = + logf(mat->table_log_P_rho_u[i_rho * mat->num_u + i_u]); + } + } +} + +// Convert to internal units INLINE static void convert_units_HM80(struct HM80_params *mat, const struct unit_system *us) { - const float Mbar_to_Ba = 1e12f; // Convert Megabar to Barye - const float J_kg_to_erg_g = 1e4f; // Convert J/kg to erg/g + struct unit_system si; + units_init_si(&si); - // Table densities in cgs - mat->log_rho_min -= logf(units_cgs_conversion_factor(us, UNIT_CONV_DENSITY)); - mat->log_rho_max -= logf(units_cgs_conversion_factor(us, UNIT_CONV_DENSITY)); + // All table values in SI + mat->log_rho_min += logf(units_cgs_conversion_factor(&si, UNIT_CONV_DENSITY) / + units_cgs_conversion_factor(us, UNIT_CONV_DENSITY)); + mat->log_rho_max += logf(units_cgs_conversion_factor(&si, UNIT_CONV_DENSITY) / + units_cgs_conversion_factor(us, UNIT_CONV_DENSITY)); - // Table energies in SI mat->log_u_min += - logf(J_kg_to_erg_g / + logf(units_cgs_conversion_factor(&si, UNIT_CONV_ENERGY_PER_UNIT_MASS) / units_cgs_conversion_factor(us, UNIT_CONV_ENERGY_PER_UNIT_MASS)); mat->log_u_max += - logf(J_kg_to_erg_g / + logf(units_cgs_conversion_factor(&si, UNIT_CONV_ENERGY_PER_UNIT_MASS) / units_cgs_conversion_factor(us, UNIT_CONV_ENERGY_PER_UNIT_MASS)); - // Table Pressures in Mbar - for (int i = 0; i < mat->num_rho; i++) { - for (int j = 0; j < mat->num_u; j++) { - mat->table_P_rho_u[i * mat->num_rho + j] *= - Mbar_to_Ba / units_cgs_conversion_factor(us, UNIT_CONV_PRESSURE); + for (int i_rho = 0; i_rho < mat->num_rho; i_rho++) { + for (int i_u = 0; i_u < mat->num_u; i_u++) { + mat->table_log_P_rho_u[i_rho * mat->num_u + i_u] += + logf(units_cgs_conversion_factor(&si, UNIT_CONV_PRESSURE) / + units_cgs_conversion_factor(us, UNIT_CONV_PRESSURE)); } } - mat->bulk_mod /= units_cgs_conversion_factor(us, UNIT_CONV_PRESSURE); + mat->bulk_mod *= units_cgs_conversion_factor(&si, UNIT_CONV_PRESSURE) / + units_cgs_conversion_factor(us, UNIT_CONV_PRESSURE); + mat->P_min_for_c_min *= units_cgs_conversion_factor(&si, UNIT_CONV_PRESSURE) / + units_cgs_conversion_factor(us, UNIT_CONV_PRESSURE); } // gas_internal_energy_from_entropy @@ -153,7 +174,7 @@ INLINE static float HM80_internal_energy_from_entropy( error("This EOS function is not yet implemented!"); - return 0; + return 0.f; } // gas_pressure_from_entropy @@ -162,7 +183,7 @@ INLINE static float HM80_pressure_from_entropy(float density, float entropy, error("This EOS function is not yet implemented!"); - return 0; + return 0.f; } // gas_entropy_from_pressure @@ -171,7 +192,7 @@ INLINE static float HM80_entropy_from_pressure(float density, float pressure, error("This EOS function is not yet implemented!"); - return 0; + return 0.f; } // gas_soundspeed_from_entropy @@ -180,75 +201,62 @@ INLINE static float HM80_soundspeed_from_entropy( error("This EOS function is not yet implemented!"); - return 0; + return 0.f; } // gas_entropy_from_internal_energy INLINE static float HM80_entropy_from_internal_energy( float density, float u, const struct HM80_params *mat) { - return 0; + return 0.f; } // gas_pressure_from_internal_energy INLINE static float HM80_pressure_from_internal_energy( float density, float u, const struct HM80_params *mat) { - float P; + float log_P, log_P_1, log_P_2, log_P_3, log_P_4; if (u <= 0.f) { return 0.f; } - int rho_idx, u_idx; + int idx_rho, idx_u; float intp_rho, intp_u; const float log_rho = logf(density); const float log_u = logf(u); - // 2D interpolation (linear in log(rho), log(u)) to find P(rho, u) - rho_idx = floorf((log_rho - mat->log_rho_min) * mat->inv_log_rho_step); - u_idx = floorf((log_u - mat->log_u_min) * mat->inv_log_u_step); + // 2D interpolation (bilinear with log(rho), log(u)) to find P(rho, u) + idx_rho = floor((log_rho - mat->log_rho_min) * mat->inv_log_rho_step); + idx_u = floor((log_u - mat->log_u_min) * mat->inv_log_u_step); - intp_rho = (log_rho - mat->log_rho_min - rho_idx * mat->log_rho_step) * - mat->inv_log_rho_step; - intp_u = - (log_u - mat->log_u_min - u_idx * mat->log_u_step) * mat->inv_log_u_step; - - // Return zero pressure if below the table minimum/a - // Extrapolate the pressure for low densities - if (rho_idx < 0) { // Too-low rho - P = expf(logf((1 - intp_u) * mat->table_P_rho_u[u_idx] + - intp_u * mat->table_P_rho_u[u_idx + 1]) + - log_rho - mat->log_rho_min); - if (u_idx < 0) { // and too-low u - P = 0.f; - } - } else if (u_idx < 0) { // Too-low u - P = 0.f; + // If outside the table then extrapolate from the edge and edge-but-one values + if (idx_rho <= -1) { + idx_rho = 0; + } else if (idx_rho >= mat->num_rho - 1) { + idx_rho = mat->num_rho - 2; } - // Return an edge value if above the table maximum/a - else if (rho_idx >= mat->num_rho - 1) { // Too-high rho - if (u_idx >= mat->num_u - 1) { // and too-high u - P = mat->table_P_rho_u[(mat->num_rho - 1) * mat->num_u + mat->num_u - 1]; - } else { - P = mat->table_P_rho_u[(mat->num_rho - 1) * mat->num_u + u_idx]; - } - } else if (u_idx >= mat->num_u - 1) { // Too-high u - P = mat->table_P_rho_u[rho_idx * mat->num_u + mat->num_u - 1]; - } - // Normal interpolation within the table - else { - P = (1.f - intp_rho) * - ((1.f - intp_u) * mat->table_P_rho_u[rho_idx * mat->num_u + u_idx] + - intp_u * mat->table_P_rho_u[rho_idx * mat->num_u + u_idx + 1]) + - intp_rho * - ((1 - intp_u) * - mat->table_P_rho_u[(rho_idx + 1) * mat->num_u + u_idx] + - intp_u * - mat->table_P_rho_u[(rho_idx + 1) * mat->num_u + u_idx + 1]); + if (idx_u <= -1) { + idx_u = 0; + } else if (idx_u >= mat->num_u - 1) { + idx_u = mat->num_u - 2; } - return P; + intp_rho = (log_rho - mat->log_rho_min - idx_rho * mat->log_rho_step) * + mat->inv_log_rho_step; + intp_u = + (log_u - mat->log_u_min - idx_u * mat->log_u_step) * mat->inv_log_u_step; + + // Table values + log_P_1 = mat->table_log_P_rho_u[idx_rho * mat->num_u + idx_u]; + log_P_2 = mat->table_log_P_rho_u[idx_rho * mat->num_u + idx_u + 1]; + log_P_3 = mat->table_log_P_rho_u[(idx_rho + 1) * mat->num_u + idx_u]; + log_P_4 = mat->table_log_P_rho_u[(idx_rho + 1) * mat->num_u + idx_u + 1]; + + log_P = (1.f - intp_rho) * ((1.f - intp_u) * log_P_1 + intp_u * log_P_2) + + intp_rho * ((1.f - intp_u) * log_P_3 + intp_u * log_P_4); + + return expf(log_P); } // gas_internal_energy_from_pressure @@ -257,7 +265,7 @@ INLINE static float HM80_internal_energy_from_pressure( error("This EOS function is not yet implemented!"); - return 0; + return 0.f; } // gas_soundspeed_from_internal_energy @@ -274,6 +282,10 @@ INLINE static float HM80_soundspeed_from_internal_energy( else { P = HM80_pressure_from_internal_energy(density, u, mat); c = sqrtf(hydro_gamma * P / density); + + if (c <= 0) { + c = sqrtf(hydro_gamma * mat->P_min_for_c_min / density); + } } return c; @@ -283,18 +295,9 @@ INLINE static float HM80_soundspeed_from_internal_energy( INLINE static float HM80_soundspeed_from_pressure( float density, float P, const struct HM80_params *mat) { - float c; - - // Bulk modulus - if (mat->bulk_mod != 0) { - c = sqrtf(mat->bulk_mod / density); - } - // Ideal gas - else { - c = sqrtf(hydro_gamma * P / density); - } + error("This EOS function is not yet implemented!"); - return c; + return 0.f; } #endif /* SWIFT_HUBBARD_MACFARLANE_EQUATION_OF_STATE_H */ diff --git a/src/equation_of_state/planetary/sesame.h b/src/equation_of_state/planetary/sesame.h index 76574c2ad00282a82649705cd8a2b5a1b428d867..d958c9b9d09ffe37eefd77ad0384d85bf8c055dd 100644 --- a/src/equation_of_state/planetary/sesame.h +++ b/src/equation_of_state/planetary/sesame.h @@ -40,21 +40,229 @@ #include "inline.h" #include "physical_constants.h" #include "units.h" +#include "utilities.h" // SESAME parameters struct SESAME_params { + float *table_log_rho; + float *table_log_u_rho_T; + float *table_P_rho_T; + float *table_c_rho_T; + float *table_s_rho_T; + int num_rho, num_T; + float P_tiny, c_tiny; enum eos_planetary_material_id mat_id; }; // Parameter values for each material (cgs units) INLINE static void set_SESAME_iron(struct SESAME_params *mat, enum eos_planetary_material_id mat_id) { + // SESAME 2140 mat->mat_id = mat_id; } +INLINE static void set_SESAME_basalt(struct SESAME_params *mat, + enum eos_planetary_material_id mat_id) { + // SESAME 7530 + mat->mat_id = mat_id; +} +INLINE static void set_SESAME_water(struct SESAME_params *mat, + enum eos_planetary_material_id mat_id) { + // SESAME 7154 + mat->mat_id = mat_id; +} +INLINE static void set_SS08_water(struct SESAME_params *mat, + enum eos_planetary_material_id mat_id) { + // Senft & Stewart (2008) + mat->mat_id = mat_id; +} + +// Read the tables from file +INLINE static void load_table_SESAME(struct SESAME_params *mat, + char *table_file) { + + // Load table contents from file + FILE *f = fopen(table_file, "r"); + int c; + + // Ignore header lines + char buffer[100]; + for (int i = 0; i < 5; i++) { + if (fgets(buffer, 100, f) == NULL) + error("Something incorrect happening with the file header."); + } + float ignore; + + // Table properties + c = fscanf(f, "%d %d", &mat->num_rho, &mat->num_T); + if (c != 2) { + error("Failed to read EOS table %s", table_file); + } + + // Ignore the first elements of rho = 0, T = 0 + mat->num_rho--; + mat->num_T--; + + // Allocate table memory + mat->table_log_rho = (float *)malloc(mat->num_rho * sizeof(float)); + mat->table_log_u_rho_T = + (float *)malloc(mat->num_rho * mat->num_T * sizeof(float)); + mat->table_P_rho_T = + (float *)malloc(mat->num_rho * mat->num_T * sizeof(float)); + mat->table_c_rho_T = + (float *)malloc(mat->num_rho * mat->num_T * sizeof(float)); + mat->table_s_rho_T = + (float *)malloc(mat->num_rho * mat->num_T * sizeof(float)); + + // Densities (not log yet) + for (int i_rho = -1; i_rho < mat->num_rho; i_rho++) { + // Ignore the first elements of rho = 0, T = 0 + if (i_rho == -1) { + c = fscanf(f, "%f", &ignore); + if (c != 1) { + error("Failed to read EOS table %s", table_file); + } + } else { + c = fscanf(f, "%f", &mat->table_log_rho[i_rho]); + if (c != 1) { + error("Failed to read EOS table %s", table_file); + } + } + } + + // Temperatures (ignored) + for (int i_T = -1; i_T < mat->num_T; i_T++) { + c = fscanf(f, "%f", &ignore); + if (c != 1) { + error("Failed to read EOS table %s", table_file); + } + } + + // Sp. int. energies (not log yet), pressures, sound speeds, and entropies + for (int i_T = -1; i_T < mat->num_T; i_T++) { + for (int i_rho = -1; i_rho < mat->num_rho; i_rho++) { + // Ignore the first elements of rho = 0, T = 0 + if ((i_T == -1) || (i_rho == -1)) { + c = fscanf(f, "%f %f %f %f", &ignore, &ignore, &ignore, &ignore); + if (c != 4) { + error("Failed to read EOS table %s", table_file); + } + } else { + c = fscanf(f, "%f %f %f %f", + &mat->table_log_u_rho_T[i_rho * mat->num_T + i_T], + &mat->table_P_rho_T[i_rho * mat->num_T + i_T], + &mat->table_c_rho_T[i_rho * mat->num_T + i_T], + &mat->table_s_rho_T[i_rho * mat->num_T + i_T]); + if (c != 4) { + error("Failed to read EOS table %s", table_file); + } + } + } + } + + fclose(f); +} -// Convert from cgs to internal units +// Misc. modifications +INLINE static void prepare_table_SESAME(struct SESAME_params *mat) { + + // Convert densities to log(density) + for (int i_rho = 0; i_rho < mat->num_rho; i_rho++) { + mat->table_log_rho[i_rho] = logf(mat->table_log_rho[i_rho]); + } + + // Convert sp. int. energies to log(sp. int. energy) + for (int i_rho = 0; i_rho < mat->num_rho; i_rho++) { + for (int i_T = 0; i_T < mat->num_T; i_T++) { + // If not positive then set very small for the log + if (mat->table_log_u_rho_T[i_rho * mat->num_T + i_T] <= 0) { + mat->table_log_u_rho_T[i_rho * mat->num_T + i_T] = 1.f; + } + + mat->table_log_u_rho_T[i_rho * mat->num_T + i_T] = + logf(mat->table_log_u_rho_T[i_rho * mat->num_T + i_T]); + } + } + + // Tiny pressure and soundspeed, initialise in the middle + mat->P_tiny = + mat->table_P_rho_T[mat->num_rho / 2 * mat->num_T + mat->num_T / 2]; + mat->c_tiny = + mat->table_c_rho_T[mat->num_rho / 2 * mat->num_T + mat->num_T / 2]; + + // Enforce that the 1D arrays of u (at each rho) are monotonic + // This is necessary because, for some high-density u slices at very low T, + // u decreases (very slightly) with T, which makes the interpolation fail + for (int i_rho = 0; i_rho < mat->num_rho; i_rho++) { + for (int i_T = mat->num_T - 1; i_T > 0; i_T--) { + + // If the one-lower-T u is greater than this u + if (mat->table_log_u_rho_T[i_rho * mat->num_T + i_T] < + mat->table_log_u_rho_T[i_rho * mat->num_T + i_T - 1]) { + + // Replace it and all elements below it with that value + for (int j_u = 0; j_u < i_T; j_u++) { + mat->table_log_u_rho_T[i_rho * mat->num_T + j_u] = + mat->table_log_u_rho_T[i_rho * mat->num_T + i_T]; + } + break; + } + + // Smallest positive pressure and sound speed + if ((mat->table_P_rho_T[i_rho * mat->num_T + i_T] < mat->P_tiny) && + (mat->table_P_rho_T[i_rho * mat->num_T + i_T] > 0)) { + mat->P_tiny = mat->table_P_rho_T[i_rho * mat->num_T + i_T]; + } + if ((mat->table_c_rho_T[i_rho * mat->num_T + i_T] < mat->c_tiny) && + (mat->table_c_rho_T[i_rho * mat->num_T + i_T] > 0)) { + mat->c_tiny = mat->table_c_rho_T[i_rho * mat->num_T + i_T]; + } + } + } + + // Tiny pressure to allow interpolation near non-positive values + mat->P_tiny *= 1e-3f; + mat->c_tiny *= 1e-3f; +} + +// Convert to internal units INLINE static void convert_units_SESAME(struct SESAME_params *mat, - const struct unit_system *us) {} + const struct unit_system *us) { + + struct unit_system si; + units_init_si(&si); + + // All table values in SI + // Densities (log) + for (int i_rho = 0; i_rho < mat->num_rho; i_rho++) { + mat->table_log_rho[i_rho] += + logf(units_cgs_conversion_factor(&si, UNIT_CONV_DENSITY) / + units_cgs_conversion_factor(us, UNIT_CONV_DENSITY)); + } + + // Sp. Int. Energies (log), pressures, and sound speeds + for (int i_rho = 0; i_rho < mat->num_rho; i_rho++) { + for (int i_T = 0; i_T < mat->num_T; i_T++) { + mat->table_log_u_rho_T[i_rho * mat->num_T + i_T] += logf( + units_cgs_conversion_factor(&si, UNIT_CONV_ENERGY_PER_UNIT_MASS) / + units_cgs_conversion_factor(us, UNIT_CONV_ENERGY_PER_UNIT_MASS)); + mat->table_P_rho_T[i_rho * mat->num_T + i_T] *= + units_cgs_conversion_factor(&si, UNIT_CONV_PRESSURE) / + units_cgs_conversion_factor(us, UNIT_CONV_PRESSURE); + mat->table_c_rho_T[i_rho * mat->num_T + i_T] *= + units_cgs_conversion_factor(&si, UNIT_CONV_SPEED) / + units_cgs_conversion_factor(us, UNIT_CONV_SPEED); + mat->table_s_rho_T[i_rho * mat->num_T + i_T] *= + units_cgs_conversion_factor(&si, UNIT_CONV_ENERGY_PER_UNIT_MASS) / + units_cgs_conversion_factor(us, UNIT_CONV_ENTROPY); + } + } + + // Tiny pressure and sound speed + mat->P_tiny *= units_cgs_conversion_factor(&si, UNIT_CONV_PRESSURE) / + units_cgs_conversion_factor(us, UNIT_CONV_PRESSURE); + mat->c_tiny *= units_cgs_conversion_factor(&si, UNIT_CONV_SPEED) / + units_cgs_conversion_factor(us, UNIT_CONV_SPEED); +} // gas_internal_energy_from_entropy INLINE static float SESAME_internal_energy_from_entropy( @@ -62,7 +270,7 @@ INLINE static float SESAME_internal_energy_from_entropy( error("This EOS function is not yet implemented!"); - return 0; + return 0.f; } // gas_pressure_from_entropy @@ -71,7 +279,7 @@ INLINE static float SESAME_pressure_from_entropy( error("This EOS function is not yet implemented!"); - return 0; + return 0.f; } // gas_entropy_from_pressure @@ -80,7 +288,7 @@ INLINE static float SESAME_entropy_from_pressure( error("This EOS function is not yet implemented!"); - return 0; + return 0.f; } // gas_soundspeed_from_entropy @@ -89,25 +297,109 @@ INLINE static float SESAME_soundspeed_from_entropy( error("This EOS function is not yet implemented!"); - return 0; + return 0.f; } // gas_entropy_from_internal_energy INLINE static float SESAME_entropy_from_internal_energy( float density, float u, const struct SESAME_params *mat) { - error("This EOS function is not yet implemented!"); - - return 0; + return 0.f; } // gas_pressure_from_internal_energy INLINE static float SESAME_pressure_from_internal_energy( float density, float u, const struct SESAME_params *mat) { - error("This EOS function is not yet implemented!"); - - return 0; + float P, P_1, P_2, P_3, P_4; + + if (u <= 0.f) { + return 0.f; + } + + int idx_rho, idx_u_1, idx_u_2; + float intp_rho, intp_u_1, intp_u_2; + const float log_rho = logf(density); + const float log_u = logf(u); + + // 2D interpolation (bilinear with log(rho), log(u)) to find P(rho, u) + // Density index + idx_rho = + find_value_in_monot_incr_array(log_rho, mat->table_log_rho, mat->num_rho); + + // Sp. int. energy at this and the next density (in relevant slice of u array) + idx_u_1 = find_value_in_monot_incr_array( + log_u, mat->table_log_u_rho_T + idx_rho * mat->num_T, mat->num_T); + idx_u_2 = find_value_in_monot_incr_array( + log_u, mat->table_log_u_rho_T + (idx_rho + 1) * mat->num_T, mat->num_T); + + // If outside the table then extrapolate from the edge and edge-but-one values + if (idx_rho <= -1) { + idx_rho = 0; + } else if (idx_rho >= mat->num_rho) { + idx_rho = mat->num_rho - 2; + } + if (idx_u_1 <= -1) { + idx_u_1 = 0; + } else if (idx_u_1 >= mat->num_T) { + idx_u_1 = mat->num_T - 2; + } + if (idx_u_2 <= -1) { + idx_u_2 = 0; + } else if (idx_u_2 >= mat->num_T) { + idx_u_2 = mat->num_T - 2; + } + + intp_rho = (log_rho - mat->table_log_rho[idx_rho]) / + (mat->table_log_rho[idx_rho + 1] - mat->table_log_rho[idx_rho]); + intp_u_1 = (log_u - mat->table_log_u_rho_T[idx_rho * mat->num_T + idx_u_1]) / + (mat->table_log_u_rho_T[idx_rho * mat->num_T + (idx_u_1 + 1)] - + mat->table_log_u_rho_T[idx_rho * mat->num_T + idx_u_1]); + intp_u_2 = + (log_u - mat->table_log_u_rho_T[(idx_rho + 1) * mat->num_T + idx_u_2]) / + (mat->table_log_u_rho_T[(idx_rho + 1) * mat->num_T + (idx_u_2 + 1)] - + mat->table_log_u_rho_T[(idx_rho + 1) * mat->num_T + idx_u_2]); + + // Table values + P_1 = mat->table_P_rho_T[idx_rho * mat->num_T + idx_u_1]; + P_2 = mat->table_P_rho_T[idx_rho * mat->num_T + idx_u_1 + 1]; + P_3 = mat->table_P_rho_T[(idx_rho + 1) * mat->num_T + idx_u_2]; + P_4 = mat->table_P_rho_T[(idx_rho + 1) * mat->num_T + idx_u_2 + 1]; + + // If more than two table values are non-positive then return zero + int num_non_pos = 0; + if (P_1 <= 0.f) num_non_pos++; + if (P_2 <= 0.f) num_non_pos++; + if (P_3 <= 0.f) num_non_pos++; + if (P_4 <= 0.f) num_non_pos++; + if (num_non_pos > 2) { + return 0.f; + } + // If just one or two are non-positive then replace them with a tiny value + else if (num_non_pos > 0) { + // Unless already trying to extrapolate in which case return zero + if ((intp_rho < 0.f) || (intp_u_1 < 0.f) || (intp_u_2 < 0.f)) { + return 0.f; + } + if (P_1 <= 0.f) P_1 = mat->P_tiny; + if (P_2 <= 0.f) P_2 = mat->P_tiny; + if (P_3 <= 0.f) P_3 = mat->P_tiny; + if (P_4 <= 0.f) P_4 = mat->P_tiny; + } + + // Interpolate with the log values + P_1 = logf(P_1); + P_2 = logf(P_2); + P_3 = logf(P_3); + P_4 = logf(P_4); + + P = (1.f - intp_rho) * ((1.f - intp_u_1) * P_1 + intp_u_1 * P_2) + + intp_rho * ((1.f - intp_u_2) * P_3 + intp_u_2 * P_4); + + // Convert back from log + P = expf(P); + + return P; } // gas_internal_energy_from_pressure @@ -116,16 +408,102 @@ INLINE static float SESAME_internal_energy_from_pressure( error("This EOS function is not yet implemented!"); - return 0; + return 0.f; } // gas_soundspeed_from_internal_energy INLINE static float SESAME_soundspeed_from_internal_energy( float density, float u, const struct SESAME_params *mat) { - error("This EOS function is not yet implemented!"); - - return 0; + float c, c_1, c_2, c_3, c_4; + + if (u <= 0.f) { + return 0.f; + } + + int idx_rho, idx_u_1, idx_u_2; + float intp_rho, intp_u_1, intp_u_2; + const float log_rho = logf(density); + const float log_u = logf(u); + + // 2D interpolation (bilinear with log(rho), log(u)) to find c(rho, u) + // Density index + idx_rho = + find_value_in_monot_incr_array(log_rho, mat->table_log_rho, mat->num_rho); + + // Sp. int. energy at this and the next density (in relevant slice of u array) + idx_u_1 = find_value_in_monot_incr_array( + log_u, mat->table_log_u_rho_T + idx_rho * mat->num_T, mat->num_T); + idx_u_2 = find_value_in_monot_incr_array( + log_u, mat->table_log_u_rho_T + (idx_rho + 1) * mat->num_T, mat->num_T); + + // If outside the table then extrapolate from the edge and edge-but-one values + if (idx_rho <= -1) { + idx_rho = 0; + } else if (idx_rho >= mat->num_rho) { + idx_rho = mat->num_rho - 2; + } + if (idx_u_1 <= -1) { + idx_u_1 = 0; + } else if (idx_u_1 >= mat->num_T) { + idx_u_1 = mat->num_T - 2; + } + if (idx_u_2 <= -1) { + idx_u_2 = 0; + } else if (idx_u_2 >= mat->num_T) { + idx_u_2 = mat->num_T - 2; + } + + intp_rho = (log_rho - mat->table_log_rho[idx_rho]) / + (mat->table_log_rho[idx_rho + 1] - mat->table_log_rho[idx_rho]); + intp_u_1 = (log_u - mat->table_log_u_rho_T[idx_rho * mat->num_T + idx_u_1]) / + (mat->table_log_u_rho_T[idx_rho * mat->num_T + (idx_u_1 + 1)] - + mat->table_log_u_rho_T[idx_rho * mat->num_T + idx_u_1]); + intp_u_2 = + (log_u - mat->table_log_u_rho_T[(idx_rho + 1) * mat->num_T + idx_u_2]) / + (mat->table_log_u_rho_T[(idx_rho + 1) * mat->num_T + (idx_u_2 + 1)] - + mat->table_log_u_rho_T[(idx_rho + 1) * mat->num_T + idx_u_2]); + + // Table values + c_1 = mat->table_c_rho_T[idx_rho * mat->num_T + idx_u_1]; + c_2 = mat->table_c_rho_T[idx_rho * mat->num_T + idx_u_1 + 1]; + c_3 = mat->table_c_rho_T[(idx_rho + 1) * mat->num_T + idx_u_2]; + c_4 = mat->table_c_rho_T[(idx_rho + 1) * mat->num_T + idx_u_2 + 1]; + + // If more than two table values are non-positive then return zero + int num_non_pos = 0; + if (c_1 <= 0.f) num_non_pos++; + if (c_2 <= 0.f) num_non_pos++; + if (c_3 <= 0.f) num_non_pos++; + if (c_4 <= 0.f) num_non_pos++; + if (num_non_pos > 2) { + return mat->c_tiny; + } + // If just one or two are non-positive then replace them with a tiny value + else if (num_non_pos > 0) { + // Unless already trying to extrapolate in which case return zero + if ((intp_rho < 0.f) || (intp_u_1 < 0.f) || (intp_u_2 < 0.f)) { + return mat->c_tiny; + } + if (c_1 <= 0.f) c_1 = mat->c_tiny; + if (c_2 <= 0.f) c_2 = mat->c_tiny; + if (c_3 <= 0.f) c_3 = mat->c_tiny; + if (c_4 <= 0.f) c_4 = mat->c_tiny; + } + + // Interpolate with the log values + c_1 = logf(c_1); + c_2 = logf(c_2); + c_3 = logf(c_3); + c_4 = logf(c_4); + + c = (1.f - intp_rho) * ((1.f - intp_u_1) * c_1 + intp_u_1 * c_2) + + intp_rho * ((1.f - intp_u_2) * c_3 + intp_u_2 * c_4); + + // Convert back from log + c = expf(c); + + return c; } // gas_soundspeed_from_pressure @@ -134,7 +512,7 @@ INLINE static float SESAME_soundspeed_from_pressure( error("This EOS function is not yet implemented!"); - return 0; + return 0.f; } #endif /* SWIFT_SESAME_EQUATION_OF_STATE_H */ diff --git a/src/equation_of_state/planetary/tillotson.h b/src/equation_of_state/planetary/tillotson.h index d5b6d5c35d5edf9e114fe7f010c4f5b1e2327a83..1a4210699380b3b0398506dde7fce6ca8055e4dc 100644 --- a/src/equation_of_state/planetary/tillotson.h +++ b/src/equation_of_state/planetary/tillotson.h @@ -41,22 +41,22 @@ // Tillotson parameters struct Til_params { - float rho_0, a, b, A, B, E_0, E_iv, E_cv, alpha, beta, eta_min, P_min; + float rho_0, a, b, A, B, u_0, u_iv, u_cv, alpha, beta, eta_min, P_min; enum eos_planetary_material_id mat_id; }; -// Parameter values for each material (cgs units) +// Parameter values for each material (SI units) INLINE static void set_Til_iron(struct Til_params *mat, enum eos_planetary_material_id mat_id) { mat->mat_id = mat_id; - mat->rho_0 = 7.800f; + mat->rho_0 = 7800.0f; mat->a = 0.5f; mat->b = 1.5f; - mat->A = 1.28e12f; - mat->B = 1.05e12f; - mat->E_0 = 9.5e10f; - mat->E_iv = 2.4e10f; - mat->E_cv = 8.67e10f; + mat->A = 1.28e11f; + mat->B = 1.05e11f; + mat->u_0 = 9.5e9f; + mat->u_iv = 2.4e9f; + mat->u_cv = 8.67e9f; mat->alpha = 5.0f; mat->beta = 5.0f; mat->eta_min = 0.0f; @@ -65,14 +65,14 @@ INLINE static void set_Til_iron(struct Til_params *mat, INLINE static void set_Til_granite(struct Til_params *mat, enum eos_planetary_material_id mat_id) { mat->mat_id = mat_id; - mat->rho_0 = 2.680f; + mat->rho_0 = 2680.0f; mat->a = 0.5f; mat->b = 1.3f; - mat->A = 1.8e11f; - mat->B = 1.8e11f; - mat->E_0 = 1.6e11f; - mat->E_iv = 3.5e10f; - mat->E_cv = 1.8e11f; + mat->A = 1.8e10f; + mat->B = 1.8e10f; + mat->u_0 = 1.6e10f; + mat->u_iv = 3.5e9f; + mat->u_cv = 1.8e10f; mat->alpha = 5.0f; mat->beta = 5.0f; mat->eta_min = 0.0f; @@ -81,30 +81,43 @@ INLINE static void set_Til_granite(struct Til_params *mat, INLINE static void set_Til_water(struct Til_params *mat, enum eos_planetary_material_id mat_id) { mat->mat_id = mat_id; - mat->rho_0 = 0.998f; + mat->rho_0 = 998.0f; mat->a = 0.7f; mat->b = 0.15f; - mat->A = 2.18e10f; - mat->B = 1.325e11f; - mat->E_0 = 7.0e10f; - mat->E_iv = 4.19e9f; - mat->E_cv = 2.69e10f; + mat->A = 2.18e9f; + mat->B = 1.325e10f; + mat->u_0 = 7.0e9f; + mat->u_iv = 4.19e8f; + mat->u_cv = 2.69e9f; mat->alpha = 10.0f; mat->beta = 5.0f; - mat->eta_min = 0.915f; + mat->eta_min = 0.9f; mat->P_min = 0.0f; } -// Convert from cgs to internal units +// Convert to internal units INLINE static void convert_units_Til(struct Til_params *mat, const struct unit_system *us) { + struct unit_system si; + units_init_si(&si); + + // SI to cgs + mat->rho_0 *= units_cgs_conversion_factor(&si, UNIT_CONV_DENSITY); + mat->A *= units_cgs_conversion_factor(&si, UNIT_CONV_PRESSURE); + mat->B *= units_cgs_conversion_factor(&si, UNIT_CONV_PRESSURE); + mat->u_0 *= units_cgs_conversion_factor(&si, UNIT_CONV_ENERGY_PER_UNIT_MASS); + mat->u_iv *= units_cgs_conversion_factor(&si, UNIT_CONV_ENERGY_PER_UNIT_MASS); + mat->u_cv *= units_cgs_conversion_factor(&si, UNIT_CONV_ENERGY_PER_UNIT_MASS); + mat->P_min *= units_cgs_conversion_factor(&si, UNIT_CONV_PRESSURE); + + // cgs to internal mat->rho_0 /= units_cgs_conversion_factor(us, UNIT_CONV_DENSITY); mat->A /= units_cgs_conversion_factor(us, UNIT_CONV_PRESSURE); mat->B /= units_cgs_conversion_factor(us, UNIT_CONV_PRESSURE); - mat->E_0 /= units_cgs_conversion_factor(us, UNIT_CONV_ENERGY_PER_UNIT_MASS); - mat->E_iv /= units_cgs_conversion_factor(us, UNIT_CONV_ENERGY_PER_UNIT_MASS); - mat->E_cv /= units_cgs_conversion_factor(us, UNIT_CONV_ENERGY_PER_UNIT_MASS); + mat->u_0 /= units_cgs_conversion_factor(us, UNIT_CONV_ENERGY_PER_UNIT_MASS); + mat->u_iv /= units_cgs_conversion_factor(us, UNIT_CONV_ENERGY_PER_UNIT_MASS); + mat->u_cv /= units_cgs_conversion_factor(us, UNIT_CONV_ENERGY_PER_UNIT_MASS); mat->P_min /= units_cgs_conversion_factor(us, UNIT_CONV_PRESSURE); } @@ -114,7 +127,7 @@ INLINE static float Til_internal_energy_from_entropy( error("This EOS function is not yet implemented!"); - return 0; + return 0.f; } // gas_pressure_from_entropy @@ -123,7 +136,7 @@ INLINE static float Til_pressure_from_entropy(float density, float entropy, error("This EOS function is not yet implemented!"); - return 0; + return 0.f; } // gas_entropy_from_pressure @@ -132,7 +145,7 @@ INLINE static float Til_entropy_from_pressure(float density, float pressure, error("This EOS function is not yet implemented!"); - return 0; + return 0.f; } // gas_soundspeed_from_entropy @@ -141,14 +154,14 @@ INLINE static float Til_soundspeed_from_entropy(float density, float entropy, error("This EOS function is not yet implemented!"); - return 0; + return 0.f; } // gas_entropy_from_internal_energy INLINE static float Til_entropy_from_internal_energy( float density, float u, const struct Til_params *mat) { - return 0; + return 0.f; } // gas_pressure_from_internal_energy @@ -156,35 +169,37 @@ INLINE static float Til_pressure_from_internal_energy( float density, float u, const struct Til_params *mat) { const float eta = density / mat->rho_0; + const float eta_sq = eta * eta; const float mu = eta - 1.f; const float nu = 1.f / eta - 1.f; + const float w = u / (mat->u_0 * eta_sq) + 1.f; + const float w_inv = 1.f / w; float P_c, P_e, P; // Condensed or cold if (eta < mat->eta_min) { P_c = 0.f; } else { - P_c = (mat->a + mat->b / (u / (mat->E_0 * eta * eta) + 1.f)) * density * u + - mat->A * mu + mat->B * mu * mu; + P_c = (mat->a + mat->b * w_inv) * density * u + mat->A * mu + + mat->B * mu * mu; } // Expanded and hot P_e = mat->a * density * u + - (mat->b * density * u / (u / (mat->E_0 * eta * eta) + 1.f) + - mat->A * mu * expf(-mat->beta * nu)) * + (mat->b * density * u * w_inv + mat->A * mu * expf(-mat->beta * nu)) * expf(-mat->alpha * nu * nu); // Condensed or cold state - if ((1.f < eta) || (u < mat->E_iv)) { + if ((1.f < eta) || (u < mat->u_iv)) { P = P_c; } // Expanded and hot state - else if ((eta < 1.f) && (mat->E_cv < u)) { + else if ((eta < 1.f) && (mat->u_cv < u)) { P = P_e; } // Hybrid state else { - P = ((u - mat->E_iv) * P_e + (mat->E_cv - u) * P_c) / - (mat->E_cv - mat->E_iv); + P = ((u - mat->u_iv) * P_e + (mat->u_cv - u) * P_c) / + (mat->u_cv - mat->u_iv); } // Minimum pressure @@ -201,81 +216,78 @@ INLINE static float Til_internal_energy_from_pressure( error("This EOS function is not yet implemented!"); - return 0; + return 0.f; } // gas_soundspeed_from_internal_energy INLINE static float Til_soundspeed_from_internal_energy( float density, float u, const struct Til_params *mat) { - // const float eta = density / mat->rho_0; - // const float mu = eta - 1.f; - // const float nu = 1.f/eta - 1.f; - // float P_c, P_e, P, c_c, c_e, c; - // - // // Condensed or cold - // if (eta < mat->eta_min) { - // P_c = 0.f; - // } - // else { - // P_c = (mat->a + mat->b / (u / (mat->E_0 * eta*eta) + 1.f)) * density - // * u - // + mat->A * mu + mat->B * mu*mu; - // } - // c_c = mat->a*u + mat->b*u / ((u / (mat->E_0*eta*eta)+1.f) * - // (u / (mat->E_0*eta*eta)+1.f)) * - // (3.f*(u / (mat->E_0*eta*eta)+1.f) - 2.f) + - // (mat->A + 2.f*mat->B*mu) / mat->rho_0 + P_c / (rho*rho) * - // (mat->a*rho + mat->b*rho / ((u / (mat->E_0*eta*eta)+1.f) * - // (u / (mat->E_0*eta*eta)+1.f))); - // - // c_c = max(c_c, mat->A / mat->rho_0); - // - // // Expanded and hot - // P_e = mat->a*density*u + ( - // mat->b * density * u / (u / (mat->E_0 * eta*eta) + 1.f) - // + mat->A*mu * expf(-mat->beta * nu) - // ) * expf(-mat->alpha * nu*nu); - // - // c_e = (mat->a + mat->b / (u / (mat->E_0*eta*eta)+1.f) * - // expf(-mat->beta*((1.f - eta)/eta)*((1.f - eta)/eta)) - // + 1.f)*P_e/rho + mat->A/mat->rho_0 - // *expf(-(mat->alpha*((1.f - eta)/eta)+mat->beta * - // ((1.f - eta)/eta)*((1.f - eta)/eta)))*(1.f+mu/(eta*eta) - // *(mat->alpha+2.f*mat->beta*((1.f - eta)/eta)-eta)) + - // mat->b*rho*u/((u / (mat->E_0*eta*eta)+1.f)* - // (u / (mat->E_0*eta*eta)+1.f)*eta*eta)* - // expf(-mat->beta*((1.f - eta)/eta)*((1.f - eta)/eta))* - // (2.f*mat->beta*((1.f - eta)/eta)*(u / (mat->E_0*eta*eta)+1.f) / - // mat->rho_0 + 1.f/(mat->E_0*rho)*(2.f*u-P_e/rho)); - // - // // Condensed or cold state - // if ((1.f < eta) || (u < mat->E_iv)) { - // c = c_c; - // } - // // Expanded and hot state - // else if ((eta < 1.f) && (mat->E_cv < u)) { - // c = c_e; - // } - // // Hybrid state - // else { - // c = ((u - mat->E_iv)*c_e + (mat->E_cv - u)*c_c) / - // (mat->E_cv - mat->E_iv); - // - // c = max(c_c, mat->A / mat->rho0); - // } - float c = sqrtf(mat->A / mat->rho_0); - - return c; + const float rho_0_inv = 1.f / mat->rho_0; + const float eta = density * rho_0_inv; + const float rho_inv = 1.f / density; + const float eta_sq = eta * eta; + const float mu = eta - 1.f; + const float nu = 1.f / eta - 1.f; + const float w = u / (mat->u_0 * eta_sq) + 1.f; + const float w_inv = 1.f / w; + const float w_inv_sq = w_inv * w_inv; + const float exp_beta = expf(-mat->beta * nu); + const float exp_alpha = expf(-mat->alpha * nu * nu); + float P_c, P_e, c_sq_c, c_sq_e, c_sq; + + // Condensed or cold + if (eta < mat->eta_min) { + P_c = 0.f; + } else { + P_c = (mat->a + mat->b * w_inv) * density * u + mat->A * mu + + mat->B * mu * mu; + } + c_sq_c = P_c * rho_inv * (1.f - mat->a - mat->b * w_inv) + + mat->b * (w - 1.f) * w_inv_sq * (2 * u + P_c * rho_inv) + + rho_inv * (mat->A + mat->B * (eta_sq - 1.f)); + + c_sq_c = fmax(c_sq_c, mat->A * rho_0_inv); + + // Expanded and hot + P_e = mat->a * density * u + + (mat->b * density * u * w_inv + mat->A * mu * exp_beta) * exp_alpha; + + c_sq_e = P_e * rho_inv * (1.f - mat->a) + + (mat->b * density * u / (w * w * eta_sq) * + (rho_inv / mat->u_0 * (2 * u - P_e * rho_inv * eta_sq) + + 2.f * mat->alpha * nu * rho_0_inv) + + mat->A * rho_0_inv * + (1 + mu / eta_sq * (mat->beta + 2.f * mat->alpha * nu - eta)) * + exp_beta) * + exp_alpha; + + // Condensed or cold state + if ((1.f < eta) || (u < mat->u_iv)) { + c_sq = c_sq_c; + } + // Expanded and hot state + else if ((eta < 1.f) && (mat->u_cv < u)) { + c_sq = c_sq_e; + } + // Hybrid state + else { + c_sq = ((u - mat->u_iv) * c_sq_e + (mat->u_cv - u) * c_sq_c) / + (mat->u_cv - mat->u_iv); + + c_sq = fmax(c_sq_c, mat->A * rho_0_inv); + } + + return sqrtf(c_sq); } // gas_soundspeed_from_pressure INLINE static float Til_soundspeed_from_pressure(float density, float P, const struct Til_params *mat) { - float c = sqrtf(mat->A / mat->rho_0); + error("This EOS function is not yet implemented!"); - return c; + return 0.f; } #endif /* SWIFT_TILLOTSON_EQUATION_OF_STATE_H */ diff --git a/src/hydro.h b/src/hydro.h index 950f63526a1590fa0fdcf2bfb5e650a2dfe14431..b3716996cc4da68f9445adccd12315b32d81a34c 100644 --- a/src/hydro.h +++ b/src/hydro.h @@ -62,9 +62,9 @@ #include "./hydro/Shadowswift/hydro_iact.h" #define SPH_IMPLEMENTATION \ "Shadowfax moving mesh (Vandenbroucke and De Rijcke 2016)" -#elif defined(MINIMAL_MULTI_MAT_SPH) -#include "./hydro/MinimalMultiMat/hydro.h" -#include "./hydro/MinimalMultiMat/hydro_iact.h" +#elif defined(PLANETARY_SPH) +#include "./hydro/Planetary/hydro.h" +#include "./hydro/Planetary/hydro_iact.h" #define SPH_IMPLEMENTATION "Minimal version of SPH with multiple materials" #else #error "Invalid choice of SPH variant" diff --git a/src/hydro/Default/hydro.h b/src/hydro/Default/hydro.h index 2c3a9c46f0500fb20aa3cfa2e5feb682b3dcec63..237a34283e1b89b06a4de1d6f1890f9a7e1af509 100644 --- a/src/hydro/Default/hydro.h +++ b/src/hydro/Default/hydro.h @@ -506,6 +506,7 @@ __attribute__((always_inline)) INLINE static void hydro_end_force( */ __attribute__((always_inline)) INLINE static void hydro_kick_extra( struct part *restrict p, struct xpart *restrict xp, float dt_therm, + float dt_grav, float dt_hydro, float dt_kick_corr, const struct cosmology *cosmo, const struct hydro_props *hydro_props) {} /** diff --git a/src/hydro/Gadget2/hydro.h b/src/hydro/Gadget2/hydro.h index 26e3bf97dd1924abbe7380d1eaadce75213344df..4511b2d655b0e7b3293633a466c76757a0237874 100644 --- a/src/hydro/Gadget2/hydro.h +++ b/src/hydro/Gadget2/hydro.h @@ -530,6 +530,7 @@ __attribute__((always_inline)) INLINE static void hydro_end_force( */ __attribute__((always_inline)) INLINE static void hydro_kick_extra( struct part *restrict p, struct xpart *restrict xp, float dt_therm, + float dt_grav, float dt_hydro, float dt_kick_corr, const struct cosmology *cosmo, const struct hydro_props *hydro_props) { /* Do not decrease the entropy by more than a factor of 2 */ diff --git a/src/hydro/GizmoMFM/hydro.h b/src/hydro/GizmoMFM/hydro.h index 1ab142740b641bdc9a0dff5a02b19479bae8257e..41c870da0cc4630896324b5fdab4b6ca2d4362bc 100644 --- a/src/hydro/GizmoMFM/hydro.h +++ b/src/hydro/GizmoMFM/hydro.h @@ -28,14 +28,11 @@ #include "hydro_properties.h" #include "hydro_space.h" #include "hydro_unphysical.h" -#include "hydro_velocities.h" #include "minmax.h" #include "riemann.h" #include <float.h> -//#define GIZMO_LLOYD_ITERATION - /** * @brief Computes the hydro time-step of a given particle * @@ -51,28 +48,23 @@ __attribute__((always_inline)) INLINE static float hydro_compute_timestep( const float CFL_condition = hydro_properties->CFL_condition; -#ifdef GIZMO_LLOYD_ITERATION - return CFL_condition; -#endif - - /* v_full is the actual velocity of the particle, primitives.v is its + /* v_full is the actual velocity of the particle, v is its hydrodynamical velocity. The time step depends on the relative difference of the two. */ float vrel[3]; - vrel[0] = p->primitives.v[0] - xp->v_full[0]; - vrel[1] = p->primitives.v[1] - xp->v_full[1]; - vrel[2] = p->primitives.v[2] - xp->v_full[2]; + vrel[0] = p->v[0] - xp->v_full[0]; + vrel[1] = p->v[1] - xp->v_full[1]; + vrel[2] = p->v[2] - xp->v_full[2]; float vmax = sqrtf(vrel[0] * vrel[0] + vrel[1] * vrel[1] + vrel[2] * vrel[2]) + - sqrtf(hydro_gamma * p->primitives.P / p->primitives.rho); + sqrtf(hydro_gamma * p->P / p->rho); vmax = max(vmax, p->timestepvars.vmax); - // MATTHIEU: Bert is this correct? Do we need more cosmology terms here? - const float psize = - cosmo->a * powf(p->geometry.volume / hydro_dimension_unit_sphere, - hydro_dimension_inv); + const float psize = cosmo->a * cosmo->a * + powf(p->geometry.volume / hydro_dimension_unit_sphere, + hydro_dimension_inv); float dt = FLT_MAX; - if (vmax > 0.) { + if (vmax > 0.0f) { dt = psize / vmax; } return CFL_condition * dt; @@ -92,7 +84,7 @@ __attribute__((always_inline)) INLINE static void hydro_timestep_extra( struct part* p, float dt) { #ifdef SWIFT_DEBUG_CHECKS - if (dt == 0.) { + if (dt == 0.0f) { error("Zero time step assigned to particle!"); } @@ -122,14 +114,10 @@ __attribute__((always_inline)) INLINE static void hydro_first_init_part( const float mass = p->conserved.mass; - p->primitives.v[0] = p->v[0]; - p->primitives.v[1] = p->v[1]; - p->primitives.v[2] = p->v[2]; - /* we can already initialize the momentum */ - p->conserved.momentum[0] = mass * p->primitives.v[0]; - p->conserved.momentum[1] = mass * p->primitives.v[1]; - p->conserved.momentum[2] = mass * p->primitives.v[2]; + p->conserved.momentum[0] = mass * p->v[0]; + p->conserved.momentum[1] = mass * p->v[1]; + p->conserved.momentum[2] = mass * p->v[2]; /* and the thermal energy */ /* remember that we store the total thermal energy, not the specific thermal @@ -137,39 +125,22 @@ __attribute__((always_inline)) INLINE static void hydro_first_init_part( #if defined(EOS_ISOTHERMAL_GAS) /* this overwrites the internal energy from the initial condition file * Note that we call the EoS function just to get the constant u here. */ - p->conserved.energy = mass * gas_internal_energy_from_entropy(0.f, 0.f); + p->conserved.energy = mass * gas_internal_energy_from_entropy(0.0f, 0.0f); #else p->conserved.energy *= mass; #endif #ifdef GIZMO_TOTAL_ENERGY /* add the total kinetic energy */ - p->conserved.energy += 0.5f * (p->conserved.momentum[0] * p->primitives.v[0] + - p->conserved.momentum[1] * p->primitives.v[1] + - p->conserved.momentum[2] * p->primitives.v[2]); -#endif - -#ifdef GIZMO_LLOYD_ITERATION - /* overwrite all variables to make sure they have safe values */ - p->primitives.rho = 1.; - p->primitives.v[0] = 0.; - p->primitives.v[1] = 0.; - p->primitives.v[2] = 0.; - p->primitives.P = 1.; - - p->conserved.mass = 1.; - p->conserved.momentum[0] = 0.; - p->conserved.momentum[1] = 0.; - p->conserved.momentum[2] = 0.; - p->conserved.energy = 1.; - - p->v[0] = 0.; - p->v[1] = 0.; - p->v[2] = 0.; + p->conserved.energy += 0.5f * (p->conserved.momentum[0] * p->v[0] + + p->conserved.momentum[1] * p->v[1] + + p->conserved.momentum[2] * p->v[2]); #endif /* initialize the particle velocity based on the primitive fluid velocity */ - hydro_velocities_init(p, xp); + xp->v_full[0] = p->v[0]; + xp->v_full[1] = p->v[1]; + xp->v_full[2] = p->v[2]; /* ignore accelerations present in the initial condition */ p->a_hydro[0] = 0.0f; @@ -180,7 +151,7 @@ __attribute__((always_inline)) INLINE static void hydro_first_init_part( time the density loop is repeated, and the whole point of storing wcorr is to have a way of remembering that we need more neighbours for this particle */ - p->density.wcorr = 1.0f; + p->geometry.wcorr = 1.0f; } /** @@ -250,7 +221,8 @@ __attribute__((always_inline)) INLINE static void hydro_end_density( /* Final operation on the geometry. */ /* we multiply with the smoothing kernel normalization ih3 and calculate the * volume */ - const float volume = 1.f / (ihdim * (p->geometry.volume + kernel_root)); + const float volume_inv = ihdim * (p->geometry.volume + kernel_root); + const float volume = 1.0f / volume_inv; p->geometry.volume = volume; /* we multiply with the smoothing kernel normalization */ @@ -268,9 +240,10 @@ __attribute__((always_inline)) INLINE static void hydro_end_density( p->geometry.centroid[1] *= kernel_norm; p->geometry.centroid[2] *= kernel_norm; - p->geometry.centroid[0] /= p->density.wcount; - p->geometry.centroid[1] /= p->density.wcount; - p->geometry.centroid[2] /= p->density.wcount; + const float wcount_inv = 1.0f / p->density.wcount; + p->geometry.centroid[0] *= wcount_inv; + p->geometry.centroid[1] *= wcount_inv; + p->geometry.centroid[2] *= wcount_inv; /* Check the condition number to see if we have a stable geometry. */ float condition_number_E = 0.0f; @@ -296,7 +269,7 @@ __attribute__((always_inline)) INLINE static void hydro_end_density( hydro_dimension_inv * sqrtf(condition_number_E * condition_number_Einv); if (condition_number > const_gizmo_max_condition_number && - p->density.wcorr > const_gizmo_min_wcorr) { + p->geometry.wcorr > const_gizmo_min_wcorr) { #ifdef GIZMO_PATHOLOGICAL_ERROR error("Condition number larger than %g (%g)!", const_gizmo_max_condition_number, condition_number); @@ -306,21 +279,19 @@ __attribute__((always_inline)) INLINE static void hydro_end_density( condition_number, const_gizmo_max_condition_number, p->id); #endif /* add a correction to the number of neighbours for this particle */ - p->density.wcorr *= const_gizmo_w_correction_factor; + p->geometry.wcorr *= const_gizmo_w_correction_factor; } - hydro_gradients_init(p); - /* compute primitive variables */ /* eqns (3)-(5) */ const float m = p->conserved.mass; #ifdef SWIFT_DEBUG_CHECKS - if (m < 0.) { + if (m < 0.0f) { error("Mass is negative!"); } - if (volume == 0.) { + if (volume == 0.0f) { error("Volume is 0!"); } #endif @@ -330,55 +301,45 @@ __attribute__((always_inline)) INLINE static void hydro_end_density( momentum[0] = p->conserved.momentum[0]; momentum[1] = p->conserved.momentum[1]; momentum[2] = p->conserved.momentum[2]; - p->primitives.rho = m / volume; - if (m == 0.) { - p->primitives.v[0] = 0.; - p->primitives.v[1] = 0.; - p->primitives.v[2] = 0.; + p->rho = m * volume_inv; + if (m == 0.0f) { + p->v[0] = 0.0f; + p->v[1] = 0.0f; + p->v[2] = 0.0f; } else { - p->primitives.v[0] = momentum[0] / m; - p->primitives.v[1] = momentum[1] / m; - p->primitives.v[2] = momentum[2] / m; + const float m_inv = 1.0f / m; + p->v[0] = momentum[0] * m_inv; + p->v[1] = momentum[1] * m_inv; + p->v[2] = momentum[2] * m_inv; } #ifdef EOS_ISOTHERMAL_GAS /* although the pressure is not formally used anywhere if an isothermal eos has been selected, we still make sure it is set to the correct value */ - p->primitives.P = gas_pressure_from_internal_energy(p->primitives.rho, 0.); + p->P = gas_pressure_from_internal_energy(p->rho, 0.0f); #else float energy = p->conserved.energy; #ifdef GIZMO_TOTAL_ENERGY /* subtract the kinetic energy; we want the thermal energy */ - energy -= 0.5f * (momentum[0] * p->primitives.v[0] + - momentum[1] * p->primitives.v[1] + - momentum[2] * p->primitives.v[2]); + energy -= 0.5f * (momentum[0] * p->v[0] + momentum[1] * p->v[1] + + momentum[2] * p->v[2]); #endif /* energy contains the total thermal energy, we want the specific energy. this is why we divide by the volume, and not by the density */ - p->primitives.P = hydro_gamma_minus_one * energy / volume; + p->P = hydro_gamma_minus_one * energy * volume_inv; #endif /* sanity checks */ - gizmo_check_physical_quantities("density", "pressure", p->primitives.rho, - p->primitives.v[0], p->primitives.v[1], - p->primitives.v[2], p->primitives.P); - -#ifdef GIZMO_LLOYD_ITERATION - /* overwrite primitive variables to make sure they still have safe values */ - p->primitives.rho = 1.; - p->primitives.v[0] = 0.; - p->primitives.v[1] = 0.; - p->primitives.v[2] = 0.; - p->primitives.P = 1.; -#endif + gizmo_check_physical_quantities("density", "pressure", p->rho, p->v[0], + p->v[1], p->v[2], p->P); /* Add a correction factor to wcount (to force a neighbour number increase if the geometry matrix is close to singular) */ - p->density.wcount *= p->density.wcorr; - p->density.wcount_dh *= p->density.wcorr; + p->density.wcount *= p->geometry.wcorr; + p->density.wcount_dh *= p->geometry.wcorr; } /** @@ -399,7 +360,7 @@ __attribute__((always_inline)) INLINE static void hydro_part_has_no_neighbours( /* Re-set problematic values */ p->density.wcount = kernel_root * h_inv_dim; - p->density.wcount_dh = 0.f; + p->density.wcount_dh = 0.0f; p->geometry.volume = 1.0f; p->geometry.matrix_E[0][0] = 1.0f; p->geometry.matrix_E[0][1] = 0.0f; @@ -437,12 +398,11 @@ __attribute__((always_inline)) INLINE static void hydro_prepare_gradient( const struct cosmology* cosmo) { /* Initialize time step criterion variables */ - p->timestepvars.vmax = 0.; + p->timestepvars.vmax = 0.0f; - // MATTHIEU: Bert is this correct? Do we need cosmology terms here? + hydro_gradients_init(p); - /* Set the actual velocity of the particle */ - hydro_velocities_prepare_force(p, xp); + // MATTHIEU: Bert is this correct? Do we need cosmology terms here? } /** @@ -494,15 +454,10 @@ __attribute__((always_inline)) INLINE static void hydro_prepare_force( const struct cosmology* cosmo) { /* Initialise values that are used in the force loop */ - p->gravity.mflux[0] = 0.0f; - p->gravity.mflux[1] = 0.0f; - p->gravity.mflux[2] = 0.0f; - - 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; + p->flux.momentum[0] = 0.0f; + p->flux.momentum[1] = 0.0f; + p->flux.momentum[2] = 0.0f; + p->flux.energy = 0.0f; } /** @@ -546,7 +501,10 @@ __attribute__((always_inline)) INLINE static void hydro_reset_predicted_values( * @param p The particle to act upon. */ __attribute__((always_inline)) INLINE static void hydro_convert_quantities( - struct part* p, struct xpart* xp, const struct cosmology* cosmo) {} + struct part* p, struct xpart* xp, const struct cosmology* cosmo) { + + p->conserved.energy /= cosmo->a_factor_internal_energy; +} /** * @brief Extra operations to be done during the drift @@ -559,10 +517,6 @@ __attribute__((always_inline)) INLINE static void hydro_convert_quantities( __attribute__((always_inline)) INLINE static void hydro_predict_extra( struct part* p, struct xpart* xp, float dt_drift, float dt_therm) { -#ifdef GIZMO_LLOYD_ITERATION - return; -#endif - const float h_inv = 1.0f / p->h; /* Predict smoothing length */ @@ -575,39 +529,39 @@ __attribute__((always_inline)) INLINE static void hydro_predict_extra( /* Limit the smoothing length correction (and make sure it is always positive). */ - if (h_corr < 2.0f && h_corr > 0.) { + if (h_corr < 2.0f && h_corr > 0.0f) { p->h *= h_corr; } /* drift the primitive variables based on the old fluxes */ - if (p->geometry.volume > 0.) { - p->primitives.rho += p->conserved.flux.mass * dt_drift / p->geometry.volume; - } + if (p->conserved.mass > 0.0f) { + const float m_inv = 1.0f / p->conserved.mass; - if (p->conserved.mass > 0.) { - p->primitives.v[0] += - p->conserved.flux.momentum[0] * dt_drift / p->conserved.mass; - p->primitives.v[1] += - p->conserved.flux.momentum[1] * dt_drift / p->conserved.mass; - p->primitives.v[2] += - p->conserved.flux.momentum[2] * dt_drift / p->conserved.mass; + p->v[0] += p->flux.momentum[0] * dt_drift * m_inv; + p->v[1] += p->flux.momentum[1] * dt_drift * m_inv; + p->v[2] += p->flux.momentum[2] * dt_drift * m_inv; #if !defined(EOS_ISOTHERMAL_GAS) - const float u = p->conserved.energy + p->conserved.flux.energy * dt_therm; - p->primitives.P = - hydro_gamma_minus_one * u * p->primitives.rho / p->conserved.mass; +#ifdef GIZMO_TOTAL_ENERGY + const float Etot = p->conserved.energy + p->flux.energy * dt_drift; + const float v2 = + (p->v[0] * p->v[0] + p->v[1] * p->v[1] + p->v[2] * p->v[2]); + const float u = (Etot * m_inv - 0.5f * v2); +#else + const float u = (p->conserved.energy + p->flux.energy * dt_drift) * m_inv; +#endif + p->P = hydro_gamma_minus_one * u * p->rho; #endif } #ifdef SWIFT_DEBUG_CHECKS - if (p->h <= 0.) { + if (p->h <= 0.0f) { error("Zero or negative smoothing length (%g)!", p->h); } #endif - gizmo_check_physical_quantities("density", "pressure", p->primitives.rho, - p->primitives.v[0], p->primitives.v[1], - p->primitives.v[2], p->primitives.P); + gizmo_check_physical_quantities("density", "pressure", p->rho, p->v[0], + p->v[1], p->v[2], p->P); } /** @@ -629,36 +583,48 @@ __attribute__((always_inline)) INLINE static void hydro_end_force( /* set the variables that are used to drift the primitive variables */ // MATTHIEU: Bert is this correct? Do we need cosmology terms here? - hydro_velocities_end_force(p); + + /* Add normalization to h_dt. */ + p->force.h_dt *= p->h * hydro_dimension_inv; } /** * @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. + * @param dt_therm Thermal energy time-step @f$\frac{dt}{a^2}@f$. + * @param dt_grav Gravity time-step @f$\frac{dt}{a}@f$. + * @param dt_hydro Hydro acceleration time-step + * @f$\frac{dt}{a^{3(\gamma{}-1)}}@f$. + * @param dt_kick_corr Gravity correction time-step @f$adt@f$. + * @param cosmo Cosmology. + * @param hydro_props Additional hydro properties. */ __attribute__((always_inline)) INLINE static void hydro_kick_extra( - struct part* p, struct xpart* xp, float dt, const struct cosmology* cosmo, + struct part* p, struct xpart* xp, float dt_therm, float dt_grav, + float dt_hydro, float dt_kick_corr, const struct cosmology* cosmo, const struct hydro_props* hydro_props) { float a_grav[3]; - /* Update conserved variables. */ - p->conserved.mass += p->conserved.flux.mass * dt; - p->conserved.momentum[0] += p->conserved.flux.momentum[0] * dt; - p->conserved.momentum[1] += p->conserved.flux.momentum[1] * dt; - p->conserved.momentum[2] += p->conserved.flux.momentum[2] * dt; + /* Update conserved variables (note: the mass does not change). */ + p->conserved.momentum[0] += p->flux.momentum[0] * dt_therm; + p->conserved.momentum[1] += p->flux.momentum[1] * dt_therm; + p->conserved.momentum[2] += p->flux.momentum[2] * dt_therm; #if defined(EOS_ISOTHERMAL_GAS) /* We use the EoS equation in a sneaky way here just to get the constant u */ p->conserved.energy = - p->conserved.mass * gas_internal_energy_from_entropy(0.f, 0.f); + p->conserved.mass * gas_internal_energy_from_entropy(0.0f, 0.0f); #else - p->conserved.energy += p->conserved.flux.energy * dt; + p->conserved.energy += p->flux.energy * dt_therm; +#endif + +#ifndef HYDRO_GAMMA_5_3 + const float Pcorr = (dt_hydro - dt_therm) * p->geometry.volume; + p->conserved.momentum[0] -= Pcorr * p->gradients.P[0]; + p->conserved.momentum[1] -= Pcorr * p->gradients.P[1]; + p->conserved.momentum[2] -= Pcorr * p->gradients.P[2]; #endif /* Apply the minimal energy limit */ @@ -666,7 +632,7 @@ __attribute__((always_inline)) INLINE static void hydro_kick_extra( hydro_props->minimal_internal_energy * cosmo->a_factor_internal_energy; if (p->conserved.energy < min_energy * p->conserved.mass) { p->conserved.energy = min_energy * p->conserved.mass; - p->conserved.flux.energy = 0.f; + p->flux.energy = 0.0f; } gizmo_check_physical_quantities( @@ -676,17 +642,11 @@ __attribute__((always_inline)) INLINE static void hydro_kick_extra( #ifdef SWIFT_DEBUG_CHECKS /* Note that this check will only have effect if no GIZMO_UNPHYSICAL option was selected. */ - if (p->conserved.mass < 0.) { - error( - "Negative mass after conserved variables update (mass: %g, dmass: %g)!", - p->conserved.mass, p->conserved.flux.mass); - } - - if (p->conserved.energy < 0.) { + if (p->conserved.energy < 0.0f) { error( "Negative energy after conserved variables update (energy: %g, " "denergy: %g)!", - p->conserved.energy, p->conserved.flux.energy); + p->conserved.energy, p->flux.energy); } #endif @@ -699,44 +659,40 @@ __attribute__((always_inline)) INLINE static void hydro_kick_extra( a_grav[1] = p->gpart->a_grav[1]; a_grav[2] = p->gpart->a_grav[2]; - /* Make sure the gpart knows the mass has changed. */ - p->gpart->mass = p->conserved.mass; - /* Kick the momentum for half a time step */ /* Note that this also affects the particle movement, as the velocity for the particles is set after this. */ - p->conserved.momentum[0] += dt * p->conserved.mass * a_grav[0]; - p->conserved.momentum[1] += dt * p->conserved.mass * a_grav[1]; - p->conserved.momentum[2] += dt * p->conserved.mass * a_grav[2]; - - p->conserved.energy += dt * (p->gravity.mflux[0] * a_grav[0] + - p->gravity.mflux[1] * a_grav[1] + - p->gravity.mflux[2] * a_grav[2]); + p->conserved.momentum[0] += dt_grav * p->conserved.mass * a_grav[0]; + p->conserved.momentum[1] += dt_grav * p->conserved.mass * a_grav[1]; + p->conserved.momentum[2] += dt_grav * p->conserved.mass * a_grav[2]; } - hydro_velocities_set(p, xp); + /* Set the velocities: */ + /* We first set the particle velocity */ + if (p->conserved.mass > 0.0f && p->rho > 0.0f) { -#ifdef GIZMO_LLOYD_ITERATION - /* reset conserved variables to safe values */ - p->conserved.mass = 1.; - p->conserved.momentum[0] = 0.; - p->conserved.momentum[1] = 0.; - p->conserved.momentum[2] = 0.; - p->conserved.energy = 1.; - - /* set the particle velocities to the Lloyd velocities */ - /* note that centroid is the relative position of the centroid w.r.t. the - particle position (position - centroid) */ - xp->v_full[0] = -p->geometry.centroid[0] / p->force.dt; - xp->v_full[1] = -p->geometry.centroid[1] / p->force.dt; - xp->v_full[2] = -p->geometry.centroid[2] / p->force.dt; - p->v[0] = xp->v_full[0]; - p->v[1] = xp->v_full[1]; - p->v[2] = xp->v_full[2]; -#endif + const float inverse_mass = 1.0f / p->conserved.mass; + + /* Normal case: set particle velocity to fluid velocity. */ + xp->v_full[0] = p->conserved.momentum[0] * inverse_mass; + xp->v_full[1] = p->conserved.momentum[1] * inverse_mass; + xp->v_full[2] = p->conserved.momentum[2] * inverse_mass; + + } else { + /* Vacuum particles have no fluid velocity. */ + xp->v_full[0] = 0.0f; + xp->v_full[1] = 0.0f; + xp->v_full[2] = 0.0f; + } + + if (p->gpart) { + p->gpart->v_full[0] = xp->v_full[0]; + p->gpart->v_full[1] = xp->v_full[1]; + p->gpart->v_full[2] = xp->v_full[2]; + } /* reset wcorr */ - p->density.wcorr = 1.0f; + p->geometry.wcorr = 1.0f; } /** @@ -747,11 +703,11 @@ __attribute__((always_inline)) INLINE static void hydro_kick_extra( __attribute__((always_inline)) INLINE static float hydro_get_comoving_internal_energy(const struct part* restrict p) { - if (p->primitives.rho > 0.) - return gas_internal_energy_from_pressure(p->primitives.rho, - p->primitives.P); - else - return 0.; + if (p->rho > 0.0f) { + return gas_internal_energy_from_pressure(p->rho, p->P); + } else { + return 0.0f; + } } /** @@ -776,10 +732,10 @@ hydro_get_physical_internal_energy(const struct part* restrict p, __attribute__((always_inline)) INLINE static float hydro_get_comoving_entropy( const struct part* restrict p) { - if (p->primitives.rho > 0.) { - return gas_entropy_from_pressure(p->primitives.rho, p->primitives.P); + if (p->rho > 0.0f) { + return gas_entropy_from_pressure(p->rho, p->P); } else { - return 0.; + return 0.0f; } } @@ -805,10 +761,11 @@ __attribute__((always_inline)) INLINE static float hydro_get_physical_entropy( __attribute__((always_inline)) INLINE static float hydro_get_comoving_soundspeed(const struct part* restrict p) { - if (p->primitives.rho > 0.) - return gas_soundspeed_from_pressure(p->primitives.rho, p->primitives.P); - else - return 0.; + if (p->rho > 0.0f) { + return gas_soundspeed_from_pressure(p->rho, p->P); + } else { + return 0.0f; + } } /** @@ -832,7 +789,7 @@ hydro_get_physical_soundspeed(const struct part* restrict p, __attribute__((always_inline)) INLINE static float hydro_get_comoving_pressure( const struct part* restrict p) { - return p->primitives.P; + return p->P; } /** @@ -844,7 +801,7 @@ __attribute__((always_inline)) INLINE static float hydro_get_comoving_pressure( __attribute__((always_inline)) INLINE static float hydro_get_physical_pressure( const struct part* restrict p, const struct cosmology* cosmo) { - return cosmo->a_factor_pressure * p->primitives.P; + return cosmo->a_factor_pressure * p->P; } /** @@ -883,20 +840,17 @@ __attribute__((always_inline)) INLINE static void hydro_get_drifted_velocities( const struct part* restrict p, const struct xpart* xp, float dt_kick_hydro, float dt_kick_grav, float v[3]) { - if (p->conserved.mass > 0.) { - v[0] = p->primitives.v[0] + - p->conserved.flux.momentum[0] * dt_kick_hydro / p->conserved.mass; - v[1] = p->primitives.v[1] + - p->conserved.flux.momentum[1] * dt_kick_hydro / p->conserved.mass; - v[2] = p->primitives.v[2] + - p->conserved.flux.momentum[2] * dt_kick_hydro / p->conserved.mass; + if (p->conserved.mass > 0.0f) { + const float inverse_mass = 1.0f / p->conserved.mass; + v[0] = p->v[0] + p->flux.momentum[0] * dt_kick_hydro * inverse_mass; + v[1] = p->v[1] + p->flux.momentum[1] * dt_kick_hydro * inverse_mass; + v[2] = p->v[2] + p->flux.momentum[2] * dt_kick_hydro * inverse_mass; } else { - v[0] = p->primitives.v[0]; - v[1] = p->primitives.v[1]; - v[2] = p->primitives.v[2]; + v[0] = p->v[0]; + v[1] = p->v[1]; + v[2] = p->v[2]; } - // MATTHIEU: Bert is this correct? v[0] += xp->a_grav[0] * dt_kick_grav; v[1] += xp->a_grav[1] * dt_kick_grav; v[2] += xp->a_grav[2] * dt_kick_grav; @@ -910,7 +864,7 @@ __attribute__((always_inline)) INLINE static void hydro_get_drifted_velocities( __attribute__((always_inline)) INLINE static float hydro_get_comoving_density( const struct part* restrict p) { - return p->primitives.rho; + return p->rho; } /** @@ -922,7 +876,7 @@ __attribute__((always_inline)) INLINE static float hydro_get_comoving_density( __attribute__((always_inline)) INLINE static float hydro_get_physical_density( const struct part* restrict p, const struct cosmology* cosmo) { - return cosmo->a3_inv * p->primitives.rho; + return cosmo->a3_inv * p->rho; } /** @@ -943,12 +897,12 @@ __attribute__((always_inline)) INLINE static void hydro_set_internal_energy( p->conserved.energy = u * p->conserved.mass; #ifdef GIZMO_TOTAL_ENERGY /* add the kinetic energy */ - p->conserved.energy += 0.5f * p->conserved.mass * - (p->conserved.momentum[0] * p->primitives.v[0] + - p->conserved.momentum[1] * p->primitives.v[1] + - p->conserved.momentum[2] * p->primitives.v[2]); + p->conserved.energy += + 0.5f * p->conserved.mass * + (p->conserved.momentum[0] * p->v[0] + p->conserved.momentum[1] * p->v[1] + + p->conserved.momentum[2] * p->v[2]); #endif - p->primitives.P = hydro_gamma_minus_one * p->primitives.rho * u; + p->P = hydro_gamma_minus_one * p->rho * u; } /** @@ -963,16 +917,16 @@ __attribute__((always_inline)) INLINE static void hydro_set_internal_energy( __attribute__((always_inline)) INLINE static void hydro_set_entropy( struct part* restrict p, float S) { - p->conserved.energy = S * pow_gamma_minus_one(p->primitives.rho) * + p->conserved.energy = S * pow_gamma_minus_one(p->rho) * hydro_one_over_gamma_minus_one * p->conserved.mass; #ifdef GIZMO_TOTAL_ENERGY /* add the kinetic energy */ - p->conserved.energy += 0.5f * p->conserved.mass * - (p->conserved.momentum[0] * p->primitives.v[0] + - p->conserved.momentum[1] * p->primitives.v[1] + - p->conserved.momentum[2] * p->primitives.v[2]); + p->conserved.energy += + 0.5f * p->conserved.mass * + (p->conserved.momentum[0] * p->v[0] + p->conserved.momentum[1] * p->v[1] + + p->conserved.momentum[2] * p->v[2]); #endif - p->primitives.P = S * pow_gamma(p->primitives.rho); + p->P = S * pow_gamma(p->rho); } /** @@ -992,12 +946,12 @@ hydro_set_init_internal_energy(struct part* p, float u_init) { p->conserved.energy = u_init * p->conserved.mass; #ifdef GIZMO_TOTAL_ENERGY /* add the kinetic energy */ - p->conserved.energy += 0.5f * p->conserved.mass * - (p->conserved.momentum[0] * p->primitives.v[0] + - p->conserved.momentum[1] * p->primitives.v[1] + - p->conserved.momentum[2] * p->primitives.v[2]); + p->conserved.energy += + 0.5f * p->conserved.mass * + (p->conserved.momentum[0] * p->v[0] + p->conserved.momentum[1] * p->v[1] + + p->conserved.momentum[2] * p->v[2]); #endif - p->primitives.P = hydro_gamma_minus_one * p->primitives.rho * u_init; + p->P = hydro_gamma_minus_one * p->rho * u_init; } #endif /* SWIFT_GIZMO_MFM_HYDRO_H */ diff --git a/src/hydro/GizmoMFM/hydro_debug.h b/src/hydro/GizmoMFM/hydro_debug.h index 6603bc216b986b40513383120587d3caec1adc87..e8b0914bd3cf6a99210399c6fc654e526319009f 100644 --- a/src/hydro/GizmoMFM/hydro_debug.h +++ b/src/hydro/GizmoMFM/hydro_debug.h @@ -27,8 +27,6 @@ __attribute__((always_inline)) INLINE static void hydro_debug_particle( "a=[%.3e,%.3e,%.3e], " "h=%.3e, " "time_bin=%d, " - "primitives={" - "v=[%.3e,%.3e,%.3e], " "rho=%.3e, " "P=%.3e, " "gradients={" @@ -39,7 +37,7 @@ __attribute__((always_inline)) INLINE static void hydro_debug_particle( "rho=[%.3e,%.3e], " "v=[[%.3e,%.3e],[%.3e,%.3e],[%.3e,%.3e]], " "P=[%.3e,%.3e], " - "maxr=%.3e}}, " + "maxr=%.3e}, " "conserved={" "momentum=[%.3e,%.3e,%.3e], " "mass=%.3e, " @@ -53,24 +51,18 @@ __attribute__((always_inline)) INLINE static void hydro_debug_particle( "wcount_dh=%.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->h, p->time_bin, 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->a_hydro[1], p->a_hydro[2], p->h, p->time_bin, p->rho, p->P, + p->gradients.rho[0], p->gradients.rho[1], p->gradients.rho[2], + p->gradients.v[0][0], p->gradients.v[0][1], p->gradients.v[0][2], + p->gradients.v[1][0], p->gradients.v[1][1], p->gradients.v[1][2], + p->gradients.v[2][0], p->gradients.v[2][1], p->gradients.v[2][2], + p->gradients.P[0], p->gradients.P[1], p->gradients.P[2], + p->limiter.rho[0], p->limiter.rho[1], p->limiter.v[0][0], + p->limiter.v[0][1], p->limiter.v[1][0], p->limiter.v[1][1], + p->limiter.v[2][0], p->limiter.v[2][1], p->limiter.P[0], p->limiter.P[1], + p->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], diff --git a/src/hydro/GizmoMFM/hydro_gradients.h b/src/hydro/GizmoMFM/hydro_gradients.h index 964a2adcfe09b95c2a221af540e5e3ff0830dd67..6f751d970287ca7ba137c1138ca6f3bf00e6c4cb 100644 --- a/src/hydro/GizmoMFM/hydro_gradients.h +++ b/src/hydro/GizmoMFM/hydro_gradients.h @@ -98,42 +98,31 @@ __attribute__((always_inline)) INLINE static void hydro_gradients_predict( /* perform gradient reconstruction in space and time */ /* Compute interface position (relative to pj, since we don't need the actual * position) eqn. (8) */ - const float xfac = hj / (hi + hj); - const float xij_j[3] = {xfac * dx[0], xfac * dx[1], xfac * dx[2]}; + const float xij_j[3] = {xij_i[0] + dx[0], xij_i[1] + dx[1], xij_i[2] + dx[2]}; float dWi[5]; - 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]; + dWi[0] = pi->gradients.rho[0] * xij_i[0] + pi->gradients.rho[1] * xij_i[1] + + pi->gradients.rho[2] * xij_i[2]; + dWi[1] = pi->gradients.v[0][0] * xij_i[0] + pi->gradients.v[0][1] * xij_i[1] + + pi->gradients.v[0][2] * xij_i[2]; + dWi[2] = pi->gradients.v[1][0] * xij_i[0] + pi->gradients.v[1][1] * xij_i[1] + + pi->gradients.v[1][2] * xij_i[2]; + dWi[3] = pi->gradients.v[2][0] * xij_i[0] + pi->gradients.v[2][1] * xij_i[1] + + pi->gradients.v[2][2] * xij_i[2]; + dWi[4] = pi->gradients.P[0] * xij_i[0] + pi->gradients.P[1] * xij_i[1] + + pi->gradients.P[2] * xij_i[2]; float dWj[5]; - 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]; + dWj[0] = pj->gradients.rho[0] * xij_j[0] + pj->gradients.rho[1] * xij_j[1] + + pj->gradients.rho[2] * xij_j[2]; + dWj[1] = pj->gradients.v[0][0] * xij_j[0] + pj->gradients.v[0][1] * xij_j[1] + + pj->gradients.v[0][2] * xij_j[2]; + dWj[2] = pj->gradients.v[1][0] * xij_j[0] + pj->gradients.v[1][1] * xij_j[1] + + pj->gradients.v[1][2] * xij_j[2]; + dWj[3] = pj->gradients.v[2][0] * xij_j[0] + pj->gradients.v[2][1] * xij_j[1] + + pj->gradients.v[2][2] * xij_j[2]; + dWj[4] = pj->gradients.P[0] * xij_j[0] + pj->gradients.P[1] * xij_j[1] + + pj->gradients.P[2] * xij_j[2]; /* Apply the slope limiter at this interface */ hydro_slope_limit_face(Wi, Wj, dWi, dWj, xij_i, xij_j, r); diff --git a/src/hydro/GizmoMFM/hydro_gradients_gizmo.h b/src/hydro/GizmoMFM/hydro_gradients_gizmo.h index 1c3b68bb28375259628e09f16730710fbbd80149..90c8096a85b3418c8ee4c5382d6f087c14f8907e 100644 --- a/src/hydro/GizmoMFM/hydro_gradients_gizmo.h +++ b/src/hydro/GizmoMFM/hydro_gradients_gizmo.h @@ -28,25 +28,25 @@ __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->gradients.rho[0] = 0.0f; + p->gradients.rho[1] = 0.0f; + p->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->gradients.v[0][0] = 0.0f; + p->gradients.v[0][1] = 0.0f; + p->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->gradients.v[1][0] = 0.0f; + p->gradients.v[1][1] = 0.0f; + p->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->gradients.v[2][0] = 0.0f; + p->gradients.v[2][1] = 0.0f; + p->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->gradients.P[0] = 0.0f; + p->gradients.P[1] = 0.0f; + p->gradients.P[2] = 0.0f; hydro_slope_limit_cell_init(p); } @@ -65,7 +65,7 @@ __attribute__((always_inline)) INLINE static void hydro_gradients_collect( float r2, const float *dx, float hi, float hj, struct part *restrict pi, struct part *restrict pj) { - const float r_inv = 1.f / sqrtf(r2); + const float r_inv = 1.0f / sqrtf(r2); const float r = r2 * r_inv; float wi, wj, wi_dx, wj_dx; @@ -80,211 +80,100 @@ __attribute__((always_inline)) INLINE static void hydro_gradients_collect( 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; + Wi[0] = pi->rho; + Wi[1] = pi->v[0]; + Wi[2] = pi->v[1]; + Wi[3] = pi->v[2]; + Wi[4] = pi->P; + Wj[0] = pj->rho; + Wj[1] = pj->v[0]; + Wj[2] = pj->v[1]; + Wj[3] = pj->v[2]; + Wj[4] = pj->P; /* Compute kernel of pi. */ - const float hi_inv = 1.f / hi; + const float hi_inv = 1.0f / hi; const float xi = r * hi_inv; kernel_deval(xi, &wi, &wi_dx); - if (pi->density.wcorr > const_gizmo_min_wcorr) { - /* 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]); + const float dW[5] = {Wi[0] - Wj[0], Wi[1] - Wj[1], Wi[2] - Wj[2], + Wi[3] - Wj[3], Wi[4] - Wj[4]}; + float wiBidx[3]; + if (pi->geometry.wcorr > const_gizmo_min_wcorr) { + wiBidx[0] = wi * (Bi[0][0] * dx[0] + Bi[0][1] * dx[1] + Bi[0][2] * dx[2]); + wiBidx[1] = wi * (Bi[1][0] * dx[0] + Bi[1][1] * dx[1] + Bi[1][2] * dx[2]); + wiBidx[2] = wi * (Bi[2][0] * dx[0] + Bi[2][1] * dx[1] + Bi[2][2] * dx[2]); } else { - /* The gradient matrix was not well-behaved, switch to SPH gradients */ - - pi->primitives.gradients.rho[0] -= - wi_dx * dx[0] * (pi->primitives.rho - pj->primitives.rho) * r_inv; - pi->primitives.gradients.rho[1] -= - wi_dx * dx[1] * (pi->primitives.rho - pj->primitives.rho) * r_inv; - pi->primitives.gradients.rho[2] -= - wi_dx * dx[2] * (pi->primitives.rho - pj->primitives.rho) * r_inv; - - pi->primitives.gradients.v[0][0] -= - wi_dx * dx[0] * (pi->primitives.v[0] - pj->primitives.v[0]) * r_inv; - pi->primitives.gradients.v[0][1] -= - wi_dx * dx[1] * (pi->primitives.v[0] - pj->primitives.v[0]) * r_inv; - pi->primitives.gradients.v[0][2] -= - wi_dx * dx[2] * (pi->primitives.v[0] - pj->primitives.v[0]) * r_inv; - - pi->primitives.gradients.v[1][0] -= - wi_dx * dx[0] * (pi->primitives.v[1] - pj->primitives.v[1]) * r_inv; - pi->primitives.gradients.v[1][1] -= - wi_dx * dx[1] * (pi->primitives.v[1] - pj->primitives.v[1]) * r_inv; - pi->primitives.gradients.v[1][2] -= - wi_dx * dx[2] * (pi->primitives.v[1] - pj->primitives.v[1]) * r_inv; - - pi->primitives.gradients.v[2][0] -= - wi_dx * dx[0] * (pi->primitives.v[2] - pj->primitives.v[2]) * r_inv; - pi->primitives.gradients.v[2][1] -= - wi_dx * dx[1] * (pi->primitives.v[2] - pj->primitives.v[2]) * r_inv; - pi->primitives.gradients.v[2][2] -= - wi_dx * dx[2] * (pi->primitives.v[2] - pj->primitives.v[2]) * r_inv; - - pi->primitives.gradients.P[0] -= - wi_dx * dx[0] * (pi->primitives.P - pj->primitives.P) * r_inv; - pi->primitives.gradients.P[1] -= - wi_dx * dx[1] * (pi->primitives.P - pj->primitives.P) * r_inv; - pi->primitives.gradients.P[2] -= - wi_dx * dx[2] * (pi->primitives.P - pj->primitives.P) * r_inv; + const float norm = -wi_dx * r_inv; + wiBidx[0] = norm * dx[0]; + wiBidx[1] = norm * dx[1]; + wiBidx[2] = norm * dx[2]; } + /* Compute gradients for pi */ + /* there is a sign difference w.r.t. eqn. (6) because of the inverse + * definition of dx */ + pi->gradients.rho[0] += dW[0] * wiBidx[0]; + pi->gradients.rho[1] += dW[0] * wiBidx[1]; + pi->gradients.rho[2] += dW[0] * wiBidx[2]; + + pi->gradients.v[0][0] += dW[1] * wiBidx[0]; + pi->gradients.v[0][1] += dW[1] * wiBidx[1]; + pi->gradients.v[0][2] += dW[1] * wiBidx[2]; + pi->gradients.v[1][0] += dW[2] * wiBidx[0]; + pi->gradients.v[1][1] += dW[2] * wiBidx[1]; + pi->gradients.v[1][2] += dW[2] * wiBidx[2]; + pi->gradients.v[2][0] += dW[3] * wiBidx[0]; + pi->gradients.v[2][1] += dW[3] * wiBidx[1]; + pi->gradients.v[2][2] += dW[3] * wiBidx[2]; + + pi->gradients.P[0] += dW[4] * wiBidx[0]; + pi->gradients.P[1] += dW[4] * wiBidx[1]; + pi->gradients.P[2] += dW[4] * wiBidx[2]; + hydro_slope_limit_cell_collect(pi, pj, r); /* Compute kernel of pj. */ - const float hj_inv = 1.f / hj; + const float hj_inv = 1.0f / hj; const float xj = r * hj_inv; kernel_deval(xj, &wj, &wj_dx); - if (pj->density.wcorr > const_gizmo_min_wcorr) { - /* 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]); + float wjBjdx[3]; + if (pj->geometry.wcorr > const_gizmo_min_wcorr) { + + wjBjdx[0] = wj * (Bj[0][0] * dx[0] + Bj[0][1] * dx[1] + Bj[0][2] * dx[2]); + wjBjdx[1] = wj * (Bj[1][0] * dx[0] + Bj[1][1] * dx[1] + Bj[1][2] * dx[2]); + wjBjdx[2] = wj * (Bj[2][0] * dx[0] + Bj[2][1] * dx[1] + Bj[2][2] * dx[2]); } else { - /* SPH gradients */ - - pj->primitives.gradients.rho[0] -= - wj_dx * dx[0] * (pi->primitives.rho - pj->primitives.rho) * r_inv; - pj->primitives.gradients.rho[1] -= - wj_dx * dx[1] * (pi->primitives.rho - pj->primitives.rho) * r_inv; - pj->primitives.gradients.rho[2] -= - wj_dx * dx[2] * (pi->primitives.rho - pj->primitives.rho) * r_inv; - - pj->primitives.gradients.v[0][0] -= - wj_dx * dx[0] * (pi->primitives.v[0] - pj->primitives.v[0]) * r_inv; - pj->primitives.gradients.v[0][1] -= - wj_dx * dx[1] * (pi->primitives.v[0] - pj->primitives.v[0]) * r_inv; - pj->primitives.gradients.v[0][2] -= - wj_dx * dx[2] * (pi->primitives.v[0] - pj->primitives.v[0]) * r_inv; - - pj->primitives.gradients.v[1][0] -= - wj_dx * dx[0] * (pi->primitives.v[1] - pj->primitives.v[1]) * r_inv; - pj->primitives.gradients.v[1][1] -= - wj_dx * dx[1] * (pi->primitives.v[1] - pj->primitives.v[1]) * r_inv; - pj->primitives.gradients.v[1][2] -= - wj_dx * dx[2] * (pi->primitives.v[1] - pj->primitives.v[1]) * r_inv; - pj->primitives.gradients.v[2][0] -= - wj_dx * dx[0] * (pi->primitives.v[2] - pj->primitives.v[2]) * r_inv; - pj->primitives.gradients.v[2][1] -= - wj_dx * dx[1] * (pi->primitives.v[2] - pj->primitives.v[2]) * r_inv; - pj->primitives.gradients.v[2][2] -= - wj_dx * dx[2] * (pi->primitives.v[2] - pj->primitives.v[2]) * r_inv; - - pj->primitives.gradients.P[0] -= - wj_dx * dx[0] * (pi->primitives.P - pj->primitives.P) * r_inv; - pj->primitives.gradients.P[1] -= - wj_dx * dx[1] * (pi->primitives.P - pj->primitives.P) * r_inv; - pj->primitives.gradients.P[2] -= - wj_dx * dx[2] * (pi->primitives.P - pj->primitives.P) * r_inv; + const float norm = -wj_dx * r_inv; + wjBjdx[0] = norm * dx[0]; + wjBjdx[1] = norm * dx[1]; + wjBjdx[2] = norm * dx[2]; } + /* 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->gradients.rho[0] += dW[0] * wjBjdx[0]; + pj->gradients.rho[1] += dW[0] * wjBjdx[1]; + pj->gradients.rho[2] += dW[0] * wjBjdx[2]; + + pj->gradients.v[0][0] += dW[1] * wjBjdx[0]; + pj->gradients.v[0][1] += dW[1] * wjBjdx[1]; + pj->gradients.v[0][2] += dW[1] * wjBjdx[2]; + pj->gradients.v[1][0] += dW[2] * wjBjdx[0]; + pj->gradients.v[1][1] += dW[2] * wjBjdx[1]; + pj->gradients.v[1][2] += dW[2] * wjBjdx[2]; + pj->gradients.v[2][0] += dW[3] * wjBjdx[0]; + pj->gradients.v[2][1] += dW[3] * wjBjdx[1]; + pj->gradients.v[2][2] += dW[3] * wjBjdx[2]; + + pj->gradients.P[0] += dW[4] * wjBjdx[0]; + pj->gradients.P[1] += dW[4] * wjBjdx[1]; + pj->gradients.P[2] += dW[4] * wjBjdx[2]; + hydro_slope_limit_cell_collect(pj, pi, r); } @@ -303,7 +192,7 @@ hydro_gradients_nonsym_collect(float r2, const float *dx, float hi, float hj, struct part *restrict pi, struct part *restrict pj) { - const float r_inv = 1.f / sqrtf(r2); + const float r_inv = 1.0f / sqrtf(r2); const float r = r2 * r_inv; float Bi[3][3]; @@ -315,113 +204,59 @@ hydro_gradients_nonsym_collect(float r2, const float *dx, float hi, float hj, 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; + Wi[0] = pi->rho; + Wi[1] = pi->v[0]; + Wi[2] = pi->v[1]; + Wi[3] = pi->v[2]; + Wi[4] = pi->P; + Wj[0] = pj->rho; + Wj[1] = pj->v[0]; + Wj[2] = pj->v[1]; + Wj[3] = pj->v[2]; + Wj[4] = pj->P; /* Compute kernel of pi. */ float wi, wi_dx; - const float hi_inv = 1.f / hi; + const float hi_inv = 1.0f / hi; const float xi = r * hi_inv; kernel_deval(xi, &wi, &wi_dx); - if (pi->density.wcorr > const_gizmo_min_wcorr) { - /* 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]); + const float dW[5] = {Wi[0] - Wj[0], Wi[1] - Wj[1], Wi[2] - Wj[2], + Wi[3] - Wj[3], Wi[4] - Wj[4]}; + float wiBidx[3]; + if (pi->geometry.wcorr > const_gizmo_min_wcorr) { + wiBidx[0] = wi * (Bi[0][0] * dx[0] + Bi[0][1] * dx[1] + Bi[0][2] * dx[2]); + wiBidx[1] = wi * (Bi[1][0] * dx[0] + Bi[1][1] * dx[1] + Bi[1][2] * dx[2]); + wiBidx[2] = wi * (Bi[2][0] * dx[0] + Bi[2][1] * dx[1] + Bi[2][2] * dx[2]); } else { - /* Gradient matrix is not well-behaved, switch to SPH gradients */ - - pi->primitives.gradients.rho[0] -= - wi_dx * dx[0] * (pi->primitives.rho - pj->primitives.rho) * r_inv; - pi->primitives.gradients.rho[1] -= - wi_dx * dx[1] * (pi->primitives.rho - pj->primitives.rho) * r_inv; - pi->primitives.gradients.rho[2] -= - wi_dx * dx[2] * (pi->primitives.rho - pj->primitives.rho) * r_inv; - - pi->primitives.gradients.v[0][0] -= - wi_dx * dx[0] * (pi->primitives.v[0] - pj->primitives.v[0]) * r_inv; - pi->primitives.gradients.v[0][1] -= - wi_dx * dx[1] * (pi->primitives.v[0] - pj->primitives.v[0]) * r_inv; - pi->primitives.gradients.v[0][2] -= - wi_dx * dx[2] * (pi->primitives.v[0] - pj->primitives.v[0]) * r_inv; - pi->primitives.gradients.v[1][0] -= - wi_dx * dx[0] * (pi->primitives.v[1] - pj->primitives.v[1]) * r_inv; - pi->primitives.gradients.v[1][1] -= - wi_dx * dx[1] * (pi->primitives.v[1] - pj->primitives.v[1]) * r_inv; - pi->primitives.gradients.v[1][2] -= - wi_dx * dx[2] * (pi->primitives.v[1] - pj->primitives.v[1]) * r_inv; - - pi->primitives.gradients.v[2][0] -= - wi_dx * dx[0] * (pi->primitives.v[2] - pj->primitives.v[2]) * r_inv; - pi->primitives.gradients.v[2][1] -= - wi_dx * dx[1] * (pi->primitives.v[2] - pj->primitives.v[2]) * r_inv; - pi->primitives.gradients.v[2][2] -= - wi_dx * dx[2] * (pi->primitives.v[2] - pj->primitives.v[2]) * r_inv; - - pi->primitives.gradients.P[0] -= - wi_dx * dx[0] * (pi->primitives.P - pj->primitives.P) * r_inv; - pi->primitives.gradients.P[1] -= - wi_dx * dx[1] * (pi->primitives.P - pj->primitives.P) * r_inv; - pi->primitives.gradients.P[2] -= - wi_dx * dx[2] * (pi->primitives.P - pj->primitives.P) * r_inv; + const float norm = -wi_dx * r_inv; + wiBidx[0] = norm * dx[0]; + wiBidx[1] = norm * dx[1]; + wiBidx[2] = norm * dx[2]; } + /* Compute gradients for pi */ + /* there is a sign difference w.r.t. eqn. (6) because of the inverse + * definition of dx */ + pi->gradients.rho[0] += dW[0] * wiBidx[0]; + pi->gradients.rho[1] += dW[0] * wiBidx[1]; + pi->gradients.rho[2] += dW[0] * wiBidx[2]; + + pi->gradients.v[0][0] += dW[1] * wiBidx[0]; + pi->gradients.v[0][1] += dW[1] * wiBidx[1]; + pi->gradients.v[0][2] += dW[1] * wiBidx[2]; + pi->gradients.v[1][0] += dW[2] * wiBidx[0]; + pi->gradients.v[1][1] += dW[2] * wiBidx[1]; + pi->gradients.v[1][2] += dW[2] * wiBidx[2]; + pi->gradients.v[2][0] += dW[3] * wiBidx[0]; + pi->gradients.v[2][1] += dW[3] * wiBidx[1]; + pi->gradients.v[2][2] += dW[3] * wiBidx[2]; + + pi->gradients.P[0] += dW[4] * wiBidx[0]; + pi->gradients.P[1] += dW[4] * wiBidx[1]; + pi->gradients.P[2] += dW[4] * wiBidx[2]; + hydro_slope_limit_cell_collect(pi, pj, r); } @@ -438,50 +273,33 @@ __attribute__((always_inline)) INLINE static void hydro_gradients_finalize( const float h = p->h; const float h_inv = 1.0f / h; const float ihdim = pow_dimension(h_inv); - const float ihdimp1 = pow_dimension_plus_one(h_inv); - - if (p->density.wcorr > const_gizmo_min_wcorr) { - 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; + float norm; + if (p->geometry.wcorr > const_gizmo_min_wcorr) { + norm = ihdim; } else { - - /* 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; + const float ihdimp1 = pow_dimension_plus_one(h_inv); + norm = ihdimp1 * volume; } + p->gradients.rho[0] *= norm; + p->gradients.rho[1] *= norm; + p->gradients.rho[2] *= norm; + + p->gradients.v[0][0] *= norm; + p->gradients.v[0][1] *= norm; + p->gradients.v[0][2] *= norm; + p->gradients.v[1][0] *= norm; + p->gradients.v[1][1] *= norm; + p->gradients.v[1][2] *= norm; + p->gradients.v[2][0] *= norm; + p->gradients.v[2][1] *= norm; + p->gradients.v[2][2] *= norm; + + p->gradients.P[0] *= norm; + p->gradients.P[1] *= norm; + p->gradients.P[2] *= norm; + hydro_slope_limit_cell(p); } diff --git a/src/hydro/GizmoMFM/hydro_gradients_sph.h b/src/hydro/GizmoMFM/hydro_gradients_sph.h index 169bed74f0b1b7e966f9880248f811d100bec13b..58233c3b75b22c4ba6347bb6e5db5e4e0e2ebe71 100644 --- a/src/hydro/GizmoMFM/hydro_gradients_sph.h +++ b/src/hydro/GizmoMFM/hydro_gradients_sph.h @@ -28,24 +28,24 @@ __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->gradients.rho[0] = 0.0f; + p->gradients.rho[1] = 0.0f; + p->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->gradients.v[0][0] = 0.0f; + p->gradients.v[0][1] = 0.0f; + p->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->gradients.v[1][0] = 0.0f; + p->gradients.v[1][1] = 0.0f; + p->gradients.v[1][2] = 0.0f; + p->gradients.v[2][0] = 0.0f; + p->gradients.v[2][1] = 0.0f; + p->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->gradients.P[0] = 0.0f; + p->gradients.P[1] = 0.0f; + p->gradients.P[2] = 0.0f; hydro_slope_limit_cell_init(p); } @@ -64,7 +64,7 @@ __attribute__((always_inline)) INLINE static void hydro_gradients_collect( float r2, const float *dx, float hi, float hj, struct part *restrict pi, struct part *restrict pj) { - const float r_inv = 1.f / sqrtf(r2); + const float r_inv = 1.0f / sqrtf(r2); const float r = r2 * r_inv; float wi, wi_dx; @@ -72,41 +72,29 @@ __attribute__((always_inline)) INLINE static void hydro_gradients_collect( const float 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_inv; - pi->primitives.gradients.rho[1] -= - wi_dx * dx[1] * (pi->primitives.rho - pj->primitives.rho) * r_inv; - pi->primitives.gradients.rho[2] -= - wi_dx * dx[2] * (pi->primitives.rho - pj->primitives.rho) * r_inv; - - pi->primitives.gradients.v[0][0] -= - wi_dx * dx[0] * (pi->primitives.v[0] - pj->primitives.v[0]) * r_inv; - pi->primitives.gradients.v[0][1] -= - wi_dx * dx[1] * (pi->primitives.v[0] - pj->primitives.v[0]) * r_inv; - pi->primitives.gradients.v[0][2] -= - wi_dx * dx[2] * (pi->primitives.v[0] - pj->primitives.v[0]) * r_inv; - - pi->primitives.gradients.v[1][0] -= - wi_dx * dx[0] * (pi->primitives.v[1] - pj->primitives.v[1]) * r_inv; - pi->primitives.gradients.v[1][1] -= - wi_dx * dx[1] * (pi->primitives.v[1] - pj->primitives.v[1]) * r_inv; - pi->primitives.gradients.v[1][2] -= - wi_dx * dx[2] * (pi->primitives.v[1] - pj->primitives.v[1]) * r_inv; - - pi->primitives.gradients.v[2][0] -= - wi_dx * dx[0] * (pi->primitives.v[2] - pj->primitives.v[2]) * r_inv; - pi->primitives.gradients.v[2][1] -= - wi_dx * dx[1] * (pi->primitives.v[2] - pj->primitives.v[2]) * r_inv; - pi->primitives.gradients.v[2][2] -= - wi_dx * dx[2] * (pi->primitives.v[2] - pj->primitives.v[2]) * r_inv; - - pi->primitives.gradients.P[0] -= - wi_dx * dx[0] * (pi->primitives.P - pj->primitives.P) * r_inv; - pi->primitives.gradients.P[1] -= - wi_dx * dx[1] * (pi->primitives.P - pj->primitives.P) * r_inv; - pi->primitives.gradients.P[2] -= - wi_dx * dx[2] * (pi->primitives.P - pj->primitives.P) * r_inv; + const float dW[5] = {pi->rho - pj->rho, pi->v[0] - pj->v[0], + pi->v[1] - pj->v[1], pi->v[2] - pj->v[2], pi->P - pj->P}; + + const float normi = wi_dx * r_inv; + const float nidx[3] = {normi * dx[0], normi * dx[1], normi * dx[2]}; + + pi->gradients.rho[0] -= dW[0] * nidx[0]; + pi->gradients.rho[1] -= dW[0] * nidx[1]; + pi->gradients.rho[2] -= dW[0] * nidx[2]; + + pi->gradients.v[0][0] -= dW[1] * nidx[0]; + pi->gradients.v[0][1] -= dW[1] * nidx[1]; + pi->gradients.v[0][2] -= dW[1] * nidx[2]; + pi->gradients.v[1][0] -= dW[2] * nidx[0]; + pi->gradients.v[1][1] -= dW[2] * nidx[1]; + pi->gradients.v[1][2] -= dW[2] * nidx[2]; + pi->gradients.v[2][0] -= dW[3] * nidx[0]; + pi->gradients.v[2][1] -= dW[3] * nidx[1]; + pi->gradients.v[2][2] -= dW[3] * nidx[2]; + + pi->gradients.P[0] -= dW[4] * nidx[0]; + pi->gradients.P[1] -= dW[4] * nidx[1]; + pi->gradients.P[2] -= dW[4] * nidx[2]; hydro_slope_limit_cell_collect(pi, pj, r); @@ -115,40 +103,27 @@ __attribute__((always_inline)) INLINE static void hydro_gradients_collect( const float xj = r * hj_inv; kernel_deval(xj, &wj, &wj_dx); + const float normj = wj_dx * r_inv; + const float njdx[3] = {normj * dx[0], normj * dx[1], normj * dx[2]}; + /* 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_inv; - pj->primitives.gradients.rho[1] -= - wj_dx * dx[1] * (pi->primitives.rho - pj->primitives.rho) * r_inv; - pj->primitives.gradients.rho[2] -= - wj_dx * dx[2] * (pi->primitives.rho - pj->primitives.rho) * r_inv; - - pj->primitives.gradients.v[0][0] -= - wj_dx * dx[0] * (pi->primitives.v[0] - pj->primitives.v[0]) * r_inv; - pj->primitives.gradients.v[0][1] -= - wj_dx * dx[1] * (pi->primitives.v[0] - pj->primitives.v[0]) * r_inv; - pj->primitives.gradients.v[0][2] -= - wj_dx * dx[2] * (pi->primitives.v[0] - pj->primitives.v[0]) * r_inv; - - pj->primitives.gradients.v[1][0] -= - wj_dx * dx[0] * (pi->primitives.v[1] - pj->primitives.v[1]) * r_inv; - pj->primitives.gradients.v[1][1] -= - wj_dx * dx[1] * (pi->primitives.v[1] - pj->primitives.v[1]) * r_inv; - pj->primitives.gradients.v[1][2] -= - wj_dx * dx[2] * (pi->primitives.v[1] - pj->primitives.v[1]) * r_inv; - pj->primitives.gradients.v[2][0] -= - wj_dx * dx[0] * (pi->primitives.v[2] - pj->primitives.v[2]) * r_inv; - pj->primitives.gradients.v[2][1] -= - wj_dx * dx[1] * (pi->primitives.v[2] - pj->primitives.v[2]) * r_inv; - pj->primitives.gradients.v[2][2] -= - wj_dx * dx[2] * (pi->primitives.v[2] - pj->primitives.v[2]) * r_inv; - - pj->primitives.gradients.P[0] -= - wj_dx * dx[0] * (pi->primitives.P - pj->primitives.P) * r_inv; - pj->primitives.gradients.P[1] -= - wj_dx * dx[1] * (pi->primitives.P - pj->primitives.P) * r_inv; - pj->primitives.gradients.P[2] -= - wj_dx * dx[2] * (pi->primitives.P - pj->primitives.P) * r_inv; + pj->gradients.rho[0] -= dW[0] * njdx[0]; + pj->gradients.rho[1] -= dW[0] * njdx[1]; + pj->gradients.rho[2] -= dW[0] * njdx[2]; + + pj->gradients.v[0][0] -= dW[1] * njdx[0]; + pj->gradients.v[0][1] -= dW[1] * njdx[1]; + pj->gradients.v[0][2] -= dW[1] * njdx[2]; + pj->gradients.v[1][0] -= dW[2] * njdx[0]; + pj->gradients.v[1][1] -= dW[2] * njdx[1]; + pj->gradients.v[1][2] -= dW[2] * njdx[2]; + pj->gradients.v[2][0] -= dW[3] * njdx[0]; + pj->gradients.v[2][1] -= dW[3] * njdx[1]; + pj->gradients.v[2][2] -= dW[3] * njdx[2]; + + pj->gradients.P[0] -= dW[4] * njdx[0]; + pj->gradients.P[1] -= dW[4] * njdx[1]; + pj->gradients.P[2] -= dW[4] * njdx[2]; hydro_slope_limit_cell_collect(pj, pi, r); } @@ -169,7 +144,7 @@ hydro_gradients_nonsym_collect(float r2, const float *dx, float hi, float hj, struct part *restrict pi, struct part *restrict pj) { - const float r_inv = 1.f / sqrtf(r2); + const float r_inv = 1.0f / sqrtf(r2); const float r = r2 * r_inv; float wi, wi_dx; @@ -177,41 +152,29 @@ hydro_gradients_nonsym_collect(float r2, const float *dx, float hi, float hj, const float 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_inv; - pi->primitives.gradients.rho[1] -= - wi_dx * dx[1] * (pi->primitives.rho - pj->primitives.rho) * r_inv; - pi->primitives.gradients.rho[2] -= - wi_dx * dx[2] * (pi->primitives.rho - pj->primitives.rho) * r_inv; - - pi->primitives.gradients.v[0][0] -= - wi_dx * dx[0] * (pi->primitives.v[0] - pj->primitives.v[0]) * r_inv; - pi->primitives.gradients.v[0][1] -= - wi_dx * dx[1] * (pi->primitives.v[0] - pj->primitives.v[0]) * r_inv; - pi->primitives.gradients.v[0][2] -= - wi_dx * dx[2] * (pi->primitives.v[0] - pj->primitives.v[0]) * r_inv; - - pi->primitives.gradients.v[1][0] -= - wi_dx * dx[0] * (pi->primitives.v[1] - pj->primitives.v[1]) * r_inv; - pi->primitives.gradients.v[1][1] -= - wi_dx * dx[1] * (pi->primitives.v[1] - pj->primitives.v[1]) * r_inv; - pi->primitives.gradients.v[1][2] -= - wi_dx * dx[2] * (pi->primitives.v[1] - pj->primitives.v[1]) * r_inv; - - pi->primitives.gradients.v[2][0] -= - wi_dx * dx[0] * (pi->primitives.v[2] - pj->primitives.v[2]) * r_inv; - pi->primitives.gradients.v[2][1] -= - wi_dx * dx[1] * (pi->primitives.v[2] - pj->primitives.v[2]) * r_inv; - pi->primitives.gradients.v[2][2] -= - wi_dx * dx[2] * (pi->primitives.v[2] - pj->primitives.v[2]) * r_inv; - - pi->primitives.gradients.P[0] -= - wi_dx * dx[0] * (pi->primitives.P - pj->primitives.P) * r_inv; - pi->primitives.gradients.P[1] -= - wi_dx * dx[1] * (pi->primitives.P - pj->primitives.P) * r_inv; - pi->primitives.gradients.P[2] -= - wi_dx * dx[2] * (pi->primitives.P - pj->primitives.P) * r_inv; + const float dW[5] = {pi->rho - pj->rho, pi->v[0] - pj->v[0], + pi->v[1] - pj->v[1], pi->v[2] - pj->v[2], pi->P - pj->P}; + + const float normi = wi_dx * r_inv; + const float nidx[3] = {normi * dx[0], normi * dx[1], normi * dx[2]}; + + pi->gradients.rho[0] -= dW[0] * nidx[0]; + pi->gradients.rho[1] -= dW[0] * nidx[1]; + pi->gradients.rho[2] -= dW[0] * nidx[2]; + + pi->gradients.v[0][0] -= dW[1] * nidx[0]; + pi->gradients.v[0][1] -= dW[1] * nidx[1]; + pi->gradients.v[0][2] -= dW[1] * nidx[2]; + pi->gradients.v[1][0] -= dW[2] * nidx[0]; + pi->gradients.v[1][1] -= dW[2] * nidx[1]; + pi->gradients.v[1][2] -= dW[2] * nidx[2]; + pi->gradients.v[2][0] -= dW[3] * nidx[0]; + pi->gradients.v[2][1] -= dW[3] * nidx[1]; + pi->gradients.v[2][2] -= dW[3] * nidx[2]; + + pi->gradients.P[0] -= dW[4] * nidx[0]; + pi->gradients.P[1] -= dW[4] * nidx[1]; + pi->gradients.P[2] -= dW[4] * nidx[2]; hydro_slope_limit_cell_collect(pi, pj, r); } @@ -229,26 +192,28 @@ __attribute__((always_inline)) INLINE static void hydro_gradients_finalize( const float ihdimp1 = pow_dimension_plus_one(ih); const float volume = p->geometry.volume; + const float norm = ihdimp1 * 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->gradients.rho[0] *= norm; + p->gradients.rho[1] *= norm; + p->gradients.rho[2] *= norm; - 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->gradients.v[0][0] *= norm; + p->gradients.v[0][1] *= norm; + p->gradients.v[0][2] *= norm; - 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->gradients.v[1][0] *= norm; + p->gradients.v[1][1] *= norm; + p->gradients.v[1][2] *= norm; - 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->gradients.v[2][0] *= norm; + p->gradients.v[2][1] *= norm; + p->gradients.v[2][2] *= norm; - p->primitives.gradients.P[0] *= ihdimp1 * volume; - p->primitives.gradients.P[1] *= ihdimp1 * volume; - p->primitives.gradients.P[2] *= ihdimp1 * volume; + p->gradients.P[0] *= norm; + p->gradients.P[1] *= norm; + p->gradients.P[2] *= norm; hydro_slope_limit_cell(p); } diff --git a/src/hydro/GizmoMFM/hydro_iact.h b/src/hydro/GizmoMFM/hydro_iact.h index a1a82e514baa60d5895343ea84ef1c3aedc8a6b7..5bed20d7f894a76d5fe3642c7438dc03195e43d6 100644 --- a/src/hydro/GizmoMFM/hydro_iact.h +++ b/src/hydro/GizmoMFM/hydro_iact.h @@ -57,7 +57,7 @@ __attribute__((always_inline)) INLINE static void runner_iact_density( const float r = sqrtf(r2); /* Compute density of pi. */ - const float hi_inv = 1.f / hi; + const float hi_inv = 1.0f / hi; const float xi = r * hi_inv; kernel_deval(xi, &wi, &wi_dx); @@ -75,7 +75,7 @@ __attribute__((always_inline)) INLINE static void runner_iact_density( pi->geometry.centroid[2] -= dx[2] * wi; /* Compute density of pj. */ - const float hj_inv = 1.f / hj; + const float hj_inv = 1.0f / hj; const float xj = r * hj_inv; kernel_deval(xj, &wj, &wj_dx); @@ -123,7 +123,7 @@ __attribute__((always_inline)) INLINE static void runner_iact_nonsym_density( /* Get r and h inverse. */ const float r = sqrtf(r2); - const float hi_inv = 1.f / hi; + const float hi_inv = 1.0f / hi; const float xi = r * hi_inv; kernel_deval(xi, &wi, &wi_dx); @@ -220,7 +220,7 @@ __attribute__((always_inline)) INLINE static void runner_iact_fluxes_common( float r2, const float *dx, float hi, float hj, struct part *restrict pi, struct part *restrict pj, int mode, float a, float H) { - const float r_inv = 1.f / sqrtf(r2); + const float r_inv = 1.0f / sqrtf(r2); const float r = r2 * r_inv; /* Initialize local variables */ @@ -238,16 +238,16 @@ __attribute__((always_inline)) INLINE static void runner_iact_fluxes_common( const float Vi = pi->geometry.volume; const float Vj = pj->geometry.volume; float Wi[5], Wj[5]; - Wi[0] = pi->primitives.rho; - Wi[1] = pi->primitives.v[0]; - Wi[2] = pi->primitives.v[1]; - Wi[3] = pi->primitives.v[2]; - Wi[4] = pi->primitives.P; - Wj[0] = pj->primitives.rho; - Wj[1] = pj->primitives.v[0]; - Wj[2] = pj->primitives.v[1]; - Wj[3] = pj->primitives.v[2]; - Wj[4] = pj->primitives.P; + Wi[0] = pi->rho; + Wi[1] = pi->v[0]; + Wi[2] = pi->v[1]; + Wi[3] = pi->v[2]; + Wi[4] = pi->P; + Wj[0] = pj->rho; + Wj[1] = pj->v[0]; + Wj[2] = pj->v[1]; + Wj[3] = pj->v[2]; + Wj[4] = pj->P; /* calculate the maximal signal velocity */ float vmax; @@ -258,21 +258,17 @@ __attribute__((always_inline)) INLINE static void runner_iact_fluxes_common( } else vmax = 0.0f; - float dvdr = (pi->v[0] - pj->v[0]) * dx[0] + (pi->v[1] - pj->v[1]) * dx[1] + - (pi->v[2] - pj->v[2]) * dx[2]; - /* Velocity on the axis linking the particles */ - float dvdotdx = (Wi[1] - Wj[1]) * dx[0] + (Wi[2] - Wj[2]) * dx[1] + - (Wi[3] - Wj[3]) * dx[2]; - dvdotdx = min(dvdotdx, dvdr); + float dvdr = (Wi[1] - Wj[1]) * dx[0] + (Wi[2] - Wj[2]) * dx[1] + + (Wi[3] - Wj[3]) * dx[2]; - /* We only care about this velocity for particles moving towards each others + /* We only care about this velocity for particles moving towards each other */ - dvdotdx = min(dvdotdx, 0.f); + const float dvdotdx = min(dvdr, 0.0f); /* Get the signal velocity */ /* the magical factor 3 also appears in Gadget2 */ - vmax -= 3.f * dvdotdx * r_inv; + vmax -= 3.0f * dvdotdx * r_inv; /* Store the signal velocity */ pi->timestepvars.vmax = max(pi->timestepvars.vmax, vmax); @@ -280,14 +276,14 @@ __attribute__((always_inline)) INLINE static void runner_iact_fluxes_common( /* Compute kernel of pi. */ float wi, wi_dx; - const float hi_inv = 1.f / hi; + const float hi_inv = 1.0f / hi; const float hi_inv_dim = pow_dimension(hi_inv); const float xi = r * hi_inv; kernel_deval(xi, &wi, &wi_dx); /* Compute kernel of pj. */ float wj, wj_dx; - const float hj_inv = 1.f / hj; + const float hj_inv = 1.0f / hj; const float hj_inv_dim = pow_dimension(hj_inv); const float xj = r * hj_inv; kernel_deval(xj, &wj, &wj_dx); @@ -298,17 +294,17 @@ __attribute__((always_inline)) INLINE static void runner_iact_fluxes_common( const float wi_dr = hidp1 * wi_dx; const float wj_dr = hjdp1 * wj_dx; dvdr *= r_inv; - if (pj->primitives.rho > 0.) - pi->force.h_dt -= pj->conserved.mass * dvdr / pj->primitives.rho * wi_dr; - if (mode == 1 && pi->primitives.rho > 0.) - pj->force.h_dt -= pi->conserved.mass * dvdr / pi->primitives.rho * wj_dr; + if (pj->rho > 0.0f) + pi->force.h_dt -= pj->conserved.mass * dvdr / pj->rho * wi_dr; + if (mode == 1 && pi->rho > 0.0f) + pj->force.h_dt -= pi->conserved.mass * dvdr / pi->rho * wj_dr; /* Compute (square of) area */ /* eqn. (7) */ float Anorm2 = 0.0f; float A[3]; - if (pi->density.wcorr > const_gizmo_min_wcorr && - pj->density.wcorr > const_gizmo_min_wcorr) { + if (pi->geometry.wcorr > const_gizmo_min_wcorr && + pj->geometry.wcorr > const_gizmo_min_wcorr) { /* in principle, we use Vi and Vj as weights for the left and right contributions to the generalized surface vector. However, if Vi and Vj are very different (because they have very @@ -342,10 +338,10 @@ __attribute__((always_inline)) INLINE static void runner_iact_fluxes_common( /* if the interface has no area, nothing happens and we return */ /* continuing results in dividing by zero and NaN's... */ - if (Anorm2 == 0.f) return; + if (Anorm2 == 0.0f) return; /* Compute the area */ - const float Anorm_inv = 1. / sqrtf(Anorm2); + const float Anorm_inv = 1.0f / sqrtf(Anorm2); const float Anorm = Anorm2 * Anorm_inv; #ifdef SWIFT_DEBUG_CHECKS @@ -375,11 +371,9 @@ __attribute__((always_inline)) INLINE static void runner_iact_fluxes_common( /* Compute interface velocity */ /* eqn. (9) */ - float xijdotdx = xij_i[0] * dx[0] + xij_i[1] * dx[1] + xij_i[2] * dx[2]; - xijdotdx *= r_inv * r_inv; - const float vij[3] = {vi[0] + (vi[0] - vj[0]) * xijdotdx, - vi[1] + (vi[1] - vj[1]) * xijdotdx, - vi[2] + (vi[2] - vj[2]) * xijdotdx}; + const float vij[3] = {vi[0] + (vi[0] - vj[0]) * xfac, + vi[1] + (vi[1] - vj[1]) * xfac, + vi[2] + (vi[2] - vj[2]) * xfac}; /* complete calculation of position of interface */ /* NOTE: dx is not necessarily just pi->x - pj->x but can also contain @@ -391,6 +385,8 @@ __attribute__((always_inline)) INLINE static void runner_iact_fluxes_common( // for ( k = 0 ; k < 3 ; k++ ) // xij[k] += pi->x[k]; + hydro_gradients_predict(pi, pj, hi, hj, dx, r, xij_i, Wi, Wj); + /* Boost the primitive variables to the frame of reference of the interface */ /* Note that velocities are indices 1-3 in W */ Wi[1] -= vij[0]; @@ -400,8 +396,6 @@ __attribute__((always_inline)) INLINE static void runner_iact_fluxes_common( Wj[2] -= vij[1]; Wj[3] -= vij[2]; - hydro_gradients_predict(pi, pj, hi, hj, dx, r, xij_i, Wi, Wj); - /* we don't need to rotate, we can use the unit vector in the Riemann problem * itself (see GIZMO) */ @@ -409,34 +403,24 @@ __attribute__((always_inline)) INLINE static void runner_iact_fluxes_common( riemann_solve_for_middle_state_flux(Wi, Wj, n_unit, vij, totflux); /* Multiply with the interface surface area */ - totflux[0] *= Anorm; totflux[1] *= Anorm; totflux[2] *= Anorm; totflux[3] *= Anorm; totflux[4] *= Anorm; - /* Store mass flux */ - const float mflux_i = totflux[0]; - pi->gravity.mflux[0] += mflux_i * dx[0]; - pi->gravity.mflux[1] += mflux_i * dx[1]; - pi->gravity.mflux[2] += mflux_i * dx[2]; - /* Update conserved variables */ + /* We shamelessly exploit the fact that the mass flux is zero and omit all + terms involving it */ /* eqn. (16) */ - pi->conserved.flux.mass -= totflux[0]; - pi->conserved.flux.momentum[0] -= totflux[1]; - pi->conserved.flux.momentum[1] -= totflux[2]; - pi->conserved.flux.momentum[2] -= totflux[3]; - pi->conserved.flux.energy -= totflux[4]; + pi->flux.momentum[0] -= totflux[1]; + pi->flux.momentum[1] -= totflux[2]; + pi->flux.momentum[2] -= totflux[3]; + pi->flux.energy -= totflux[4]; #ifndef GIZMO_TOTAL_ENERGY - const float ekin_i = 0.5f * (pi->primitives.v[0] * pi->primitives.v[0] + - pi->primitives.v[1] * pi->primitives.v[1] + - pi->primitives.v[2] * pi->primitives.v[2]); - pi->conserved.flux.energy += totflux[1] * pi->primitives.v[0]; - pi->conserved.flux.energy += totflux[2] * pi->primitives.v[1]; - pi->conserved.flux.energy += totflux[3] * pi->primitives.v[2]; - pi->conserved.flux.energy -= totflux[0] * ekin_i; + pi->flux.energy += totflux[1] * pi->v[0]; + pi->flux.energy += totflux[2] * pi->v[1]; + pi->flux.energy += totflux[3] * pi->v[2]; #endif /* Note that this used to be much more complicated in early implementations of @@ -445,26 +429,15 @@ __attribute__((always_inline)) INLINE static void runner_iact_fluxes_common( * conservation anymore and just assume the current fluxes are representative * for the flux over the entire time step. */ if (mode == 1) { - /* Store mass flux */ - const float mflux_j = totflux[0]; - pj->gravity.mflux[0] -= mflux_j * dx[0]; - pj->gravity.mflux[1] -= mflux_j * dx[1]; - pj->gravity.mflux[2] -= mflux_j * dx[2]; - - pj->conserved.flux.mass += totflux[0]; - pj->conserved.flux.momentum[0] += totflux[1]; - pj->conserved.flux.momentum[1] += totflux[2]; - pj->conserved.flux.momentum[2] += totflux[3]; - pj->conserved.flux.energy += totflux[4]; + pj->flux.momentum[0] += totflux[1]; + pj->flux.momentum[1] += totflux[2]; + pj->flux.momentum[2] += totflux[3]; + pj->flux.energy += totflux[4]; #ifndef GIZMO_TOTAL_ENERGY - const float ekin_j = 0.5f * (pj->primitives.v[0] * pj->primitives.v[0] + - pj->primitives.v[1] * pj->primitives.v[1] + - pj->primitives.v[2] * pj->primitives.v[2]); - pj->conserved.flux.energy -= totflux[1] * pj->primitives.v[0]; - pj->conserved.flux.energy -= totflux[2] * pj->primitives.v[1]; - pj->conserved.flux.energy -= totflux[3] * pj->primitives.v[2]; - pj->conserved.flux.energy += totflux[0] * ekin_j; + pj->flux.energy -= totflux[1] * pj->v[0]; + pj->flux.energy -= totflux[2] * pj->v[1]; + pj->flux.energy -= totflux[3] * pj->v[2]; #endif } } diff --git a/src/hydro/GizmoMFM/hydro_io.h b/src/hydro/GizmoMFM/hydro_io.h index 59d579f70cd4aedc728dbf42038eff78d4c507d5..1f956edf3fdc31990c6aba254603ea69a98238eb 100644 --- a/src/hydro/GizmoMFM/hydro_io.h +++ b/src/hydro/GizmoMFM/hydro_io.h @@ -63,7 +63,7 @@ INLINE static void hydro_read_particles(struct part* parts, 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); + UNIT_CONV_DENSITY, parts, rho); } /** @@ -203,12 +203,12 @@ INLINE static void hydro_write_particles(const struct part* parts, parts, xparts, convert_u); list[5] = io_make_output_field("ParticleIDs", ULONGLONG, 1, UNIT_CONV_NO_UNITS, parts, id); - list[6] = io_make_output_field("Density", FLOAT, 1, UNIT_CONV_DENSITY, parts, - primitives.rho); + list[6] = + io_make_output_field("Density", FLOAT, 1, UNIT_CONV_DENSITY, parts, rho); list[7] = io_make_output_field_convert_part( "Entropy", FLOAT, 1, UNIT_CONV_ENTROPY, parts, xparts, convert_A); - list[8] = io_make_output_field("Pressure", FLOAT, 1, UNIT_CONV_PRESSURE, - parts, primitives.P); + list[8] = + io_make_output_field("Pressure", FLOAT, 1, UNIT_CONV_PRESSURE, parts, P); list[9] = io_make_output_field_convert_part( "TotEnergy", FLOAT, 1, UNIT_CONV_ENERGY, parts, xparts, convert_Etot); diff --git a/src/hydro/GizmoMFM/hydro_part.h b/src/hydro/GizmoMFM/hydro_part.h index 857c429ec933ad3eea730e8f0b6f830782cdf77b..0055d7d86a35746a8ba90015b3a6986f8ddb5f9f 100644 --- a/src/hydro/GizmoMFM/hydro_part.h +++ b/src/hydro/GizmoMFM/hydro_part.h @@ -63,31 +63,23 @@ struct part { /* Particle smoothing length. */ float h; - /* The primitive hydrodynamical variables. */ - struct { - - /* Density. */ - float rho; - - /* Fluid velocity. */ - float v[3]; + /* Density. */ + float rho; - /* Pressure. */ - float P; + /* Pressure. */ + float P; - /* Gradients of the primitive variables. */ + union { + /* Quantities used during the volume (=density) loop. */ struct { - /* Density gradients. */ - float rho[3]; + /* Derivative of particle number density. */ + float wcount_dh; - /* Fluid velocity gradients. */ - float v[3][3]; + /* Particle number density. */ + float wcount; - /* Pressure gradients. */ - float P[3]; - - } gradients; + } density; /* Quantities needed by the slope limiter. */ struct { @@ -106,7 +98,56 @@ struct part { } limiter; - } primitives; + struct { + /* Fluxes. */ + struct { + + /* No mass flux, since it is always zero. */ + + /* Momentum flux. */ + float momentum[3]; + + /* Energy flux. */ + float energy; + + } flux; + + /* Variables used for timestep calculation. */ + struct { + + /* Maximum signal velocity among all the neighbours of the particle. The + * signal velocity encodes information about the relative fluid + * velocities + * AND particle velocities of the neighbour and this particle, as well + * as + * the sound speed of both particles. */ + float vmax; + + } timestepvars; + + /* Quantities used during the force loop. */ + struct { + + /* Needed to drift the primitive variables. */ + float h_dt; + + } force; + }; + }; + + /* Gradients of the primitive variables. */ + struct { + + /* Density gradients. */ + float rho[3]; + + /* Fluid velocity gradients. */ + float v[3][3]; + + /* Pressure gradients. */ + float P[3]; + + } gradients; /* The conserved hydrodynamical variables. */ struct { @@ -120,20 +161,6 @@ struct part { /* Fluid thermal energy (not per unit mass!). */ float energy; - /* Fluxes. */ - struct { - - /* Mass flux. */ - float mass; - - /* Momentum flux. */ - float momentum[3]; - - /* Energy flux. */ - float energy; - - } flux; - } conserved; /* Geometrical quantities used for hydro. */ @@ -149,48 +176,10 @@ struct part { /* Centroid of the "cell". */ float centroid[3]; - } geometry; - - /* Variables used for timestep calculation. */ - struct { - - /* Maximum signal velocity among all the neighbours of the particle. The - * signal velocity encodes information about the relative fluid velocities - * AND particle velocities of the neighbour and this particle, as well as - * the sound speed of both particles. */ - float vmax; - - } timestepvars; - - /* Quantities used during the volume (=density) loop. */ - struct { - - /* Derivative of particle number density. */ - float wcount_dh; - - /* Particle number density. */ - float wcount; - /* Correction factor for wcount. */ float wcorr; - } density; - - /* Quantities used during the force loop. */ - struct { - - /* Needed to drift the primitive variables. */ - float h_dt; - - } force; - - /* Specific stuff for the gravity-hydro coupling. */ - struct { - - /* Current value of the mass flux vector. */ - float mflux[3]; - - } gravity; + } geometry; /* Chemistry information */ struct chemistry_part_data chemistry_data; diff --git a/src/hydro/GizmoMFM/hydro_slope_limiters.h b/src/hydro/GizmoMFM/hydro_slope_limiters.h index 78f2785cdae5dc2334d37e3924dd5b259cca8c05..7c9c759830a4b0ee98412d5a200700c0a148d316 100644 --- a/src/hydro/GizmoMFM/hydro_slope_limiters.h +++ b/src/hydro/GizmoMFM/hydro_slope_limiters.h @@ -47,8 +47,8 @@ * @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 *Wi, float *Wj, float *dWi, float *dWj, const float *xij_i, + const float *xij_j, float r) {} #endif diff --git a/src/hydro/GizmoMFM/hydro_slope_limiters_cell.h b/src/hydro/GizmoMFM/hydro_slope_limiters_cell.h index 7dec6f499da31de1f10652a31781a788166957cc..329ca5fda4510a3672bfe698bed52c8f0bebc895 100644 --- a/src/hydro/GizmoMFM/hydro_slope_limiters_cell.h +++ b/src/hydro/GizmoMFM/hydro_slope_limiters_cell.h @@ -29,18 +29,18 @@ __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; + p->limiter.rho[0] = FLT_MAX; + p->limiter.rho[1] = -FLT_MAX; + p->limiter.v[0][0] = FLT_MAX; + p->limiter.v[0][1] = -FLT_MAX; + p->limiter.v[1][0] = FLT_MAX; + p->limiter.v[1][1] = -FLT_MAX; + p->limiter.v[2][0] = FLT_MAX; + p->limiter.v[2][1] = -FLT_MAX; + p->limiter.P[0] = FLT_MAX; + p->limiter.P[1] = -FLT_MAX; + + p->limiter.maxr = -FLT_MAX; } /** @@ -56,30 +56,20 @@ 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] = - min(pj->primitives.rho, pi->primitives.limiter.rho[0]); - pi->primitives.limiter.rho[1] = - max(pj->primitives.rho, pi->primitives.limiter.rho[1]); - - pi->primitives.limiter.v[0][0] = - min(pj->primitives.v[0], pi->primitives.limiter.v[0][0]); - pi->primitives.limiter.v[0][1] = - max(pj->primitives.v[0], pi->primitives.limiter.v[0][1]); - pi->primitives.limiter.v[1][0] = - min(pj->primitives.v[1], pi->primitives.limiter.v[1][0]); - pi->primitives.limiter.v[1][1] = - max(pj->primitives.v[1], pi->primitives.limiter.v[1][1]); - pi->primitives.limiter.v[2][0] = - min(pj->primitives.v[2], pi->primitives.limiter.v[2][0]); - pi->primitives.limiter.v[2][1] = - max(pj->primitives.v[2], pi->primitives.limiter.v[2][1]); - - pi->primitives.limiter.P[0] = - min(pj->primitives.P, pi->primitives.limiter.P[0]); - pi->primitives.limiter.P[1] = - max(pj->primitives.P, pi->primitives.limiter.P[1]); - - pi->primitives.limiter.maxr = max(r, pi->primitives.limiter.maxr); + pi->limiter.rho[0] = min(pj->rho, pi->limiter.rho[0]); + pi->limiter.rho[1] = max(pj->rho, pi->limiter.rho[1]); + + pi->limiter.v[0][0] = min(pj->v[0], pi->limiter.v[0][0]); + pi->limiter.v[0][1] = max(pj->v[0], pi->limiter.v[0][1]); + pi->limiter.v[1][0] = min(pj->v[1], pi->limiter.v[1][0]); + pi->limiter.v[1][1] = max(pj->v[1], pi->limiter.v[1][1]); + pi->limiter.v[2][0] = min(pj->v[2], pi->limiter.v[2][0]); + pi->limiter.v[2][1] = max(pj->v[2], pi->limiter.v[2][1]); + + pi->limiter.P[0] = min(pj->P, pi->limiter.P[0]); + pi->limiter.P[1] = max(pj->P, pi->limiter.P[1]); + + pi->limiter.maxr = max(r, pi->limiter.maxr); } /** @@ -92,94 +82,94 @@ __attribute__((always_inline)) INLINE static void hydro_slope_limit_cell( float gradtrue, gradrho[3], gradv[3][3], gradP[3]; - gradrho[0] = p->primitives.gradients.rho[0]; - gradrho[1] = p->primitives.gradients.rho[1]; - gradrho[2] = p->primitives.gradients.rho[2]; + gradrho[0] = p->gradients.rho[0]; + gradrho[1] = p->gradients.rho[1]; + gradrho[2] = p->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[0][0] = p->gradients.v[0][0]; + gradv[0][1] = p->gradients.v[0][1]; + gradv[0][2] = p->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[1][0] = p->gradients.v[1][0]; + gradv[1][1] = p->gradients.v[1][1]; + gradv[1][2] = p->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]; + gradv[2][0] = p->gradients.v[2][0]; + gradv[2][1] = p->gradients.v[2][1]; + gradv[2][2] = p->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]; + gradP[0] = p->gradients.P[0]; + gradP[1] = p->gradients.P[1]; + gradP[2] = p->gradients.P[2]; gradtrue = sqrtf(gradrho[0] * gradrho[0] + gradrho[1] * gradrho[1] + gradrho[2] * gradrho[2]); if (gradtrue) { - gradtrue *= p->primitives.limiter.maxr; - const float gradmax = p->primitives.limiter.rho[1] - p->primitives.rho; - const float gradmin = p->primitives.rho - p->primitives.limiter.rho[0]; - const float gradtrue_inv = 1.f / gradtrue; + gradtrue *= p->limiter.maxr; + const float gradmax = p->limiter.rho[1] - p->rho; + const float gradmin = p->rho - p->limiter.rho[0]; + const float gradtrue_inv = 1.0f / gradtrue; const float alpha = min3(1.0f, gradmax * gradtrue_inv, gradmin * gradtrue_inv); - p->primitives.gradients.rho[0] *= alpha; - p->primitives.gradients.rho[1] *= alpha; - p->primitives.gradients.rho[2] *= alpha; + p->gradients.rho[0] *= alpha; + p->gradients.rho[1] *= alpha; + p->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; - const float gradmax = p->primitives.limiter.v[0][1] - p->primitives.v[0]; - const float gradmin = p->primitives.v[0] - p->primitives.limiter.v[0][0]; - const float gradtrue_inv = 1.f / gradtrue; + gradtrue *= p->limiter.maxr; + const float gradmax = p->limiter.v[0][1] - p->v[0]; + const float gradmin = p->v[0] - p->limiter.v[0][0]; + const float gradtrue_inv = 1.0f / gradtrue; const float alpha = min3(1.0f, gradmax * gradtrue_inv, gradmin * gradtrue_inv); - p->primitives.gradients.v[0][0] *= alpha; - p->primitives.gradients.v[0][1] *= alpha; - p->primitives.gradients.v[0][2] *= alpha; + p->gradients.v[0][0] *= alpha; + p->gradients.v[0][1] *= alpha; + p->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; - const float gradmax = p->primitives.limiter.v[1][1] - p->primitives.v[1]; - const float gradmin = p->primitives.v[1] - p->primitives.limiter.v[1][0]; - const float gradtrue_inv = 1.f / gradtrue; + gradtrue *= p->limiter.maxr; + const float gradmax = p->limiter.v[1][1] - p->v[1]; + const float gradmin = p->v[1] - p->limiter.v[1][0]; + const float gradtrue_inv = 1.0f / gradtrue; const float alpha = min3(1.0f, gradmax * gradtrue_inv, gradmin * gradtrue_inv); - p->primitives.gradients.v[1][0] *= alpha; - p->primitives.gradients.v[1][1] *= alpha; - p->primitives.gradients.v[1][2] *= alpha; + p->gradients.v[1][0] *= alpha; + p->gradients.v[1][1] *= alpha; + p->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; - const float gradmax = p->primitives.limiter.v[2][1] - p->primitives.v[2]; - const float gradmin = p->primitives.v[2] - p->primitives.limiter.v[2][0]; - const float gradtrue_inv = 1.f / gradtrue; + gradtrue *= p->limiter.maxr; + const float gradmax = p->limiter.v[2][1] - p->v[2]; + const float gradmin = p->v[2] - p->limiter.v[2][0]; + const float gradtrue_inv = 1.0f / gradtrue; const float alpha = min3(1.0f, gradmax * gradtrue_inv, gradmin * gradtrue_inv); - p->primitives.gradients.v[2][0] *= alpha; - p->primitives.gradients.v[2][1] *= alpha; - p->primitives.gradients.v[2][2] *= alpha; + p->gradients.v[2][0] *= alpha; + p->gradients.v[2][1] *= alpha; + p->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; - const float gradmax = p->primitives.limiter.P[1] - p->primitives.P; - const float gradmin = p->primitives.P - p->primitives.limiter.P[0]; - const float gradtrue_inv = 1.f / gradtrue; + gradtrue *= p->limiter.maxr; + const float gradmax = p->limiter.P[1] - p->P; + const float gradmin = p->P - p->limiter.P[0]; + const float gradtrue_inv = 1.0f / gradtrue; const float alpha = min3(1.0f, gradmax * gradtrue_inv, gradmin * gradtrue_inv); - p->primitives.gradients.P[0] *= alpha; - p->primitives.gradients.P[1] *= alpha; - p->primitives.gradients.P[2] *= alpha; + p->gradients.P[0] *= alpha; + p->gradients.P[1] *= alpha; + p->gradients.P[2] *= alpha; } } diff --git a/src/hydro/GizmoMFM/hydro_slope_limiters_face.h b/src/hydro/GizmoMFM/hydro_slope_limiters_face.h index 8f0636c992ccbd615cc62ca09c1b0ca9b08ea56b..a7c0e37d3953d1d385128b4a1c72dd2311ac00ae 100644 --- a/src/hydro/GizmoMFM/hydro_slope_limiters_face.h +++ b/src/hydro/GizmoMFM/hydro_slope_limiters_face.h @@ -56,15 +56,17 @@ hydro_slope_limit_face_quantity(float phi_i, float phi_j, float phi_mid0, float phiplus, phiminus, phi_mid; - if (same_signf(phimax + delta1, phimax)) + if (same_signf(phimax + delta1, phimax)) { phiplus = phimax + delta1; - else + } else { phiplus = phimax / (1.0f + delta1 / (fabsf(phimax) + FLT_MIN)); + } - if (same_signf(phimin - delta1, phimin)) + if (same_signf(phimin - delta1, phimin)) { phiminus = phimin - delta1; - else + } else { phiminus = phimin / (1.0f + delta1 / (fabsf(phimin) + FLT_MIN)); + } if (phi_i < phi_j) { const float temp = min(phibar + delta2, phi_mid0); diff --git a/src/hydro/GizmoMFM/hydro_velocities.h b/src/hydro/GizmoMFM/hydro_velocities.h deleted file mode 100644 index ea30d5a6c9c74d34ffd73fa6ab941640f37b02e4..0000000000000000000000000000000000000000 --- a/src/hydro/GizmoMFM/hydro_velocities.h +++ /dev/null @@ -1,157 +0,0 @@ -/******************************************************************************* - * This file is part of SWIFT. - * Coypright (c) 2017 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_VELOCITIES_H -#define SWIFT_HYDRO_VELOCITIES_H - -/** - * @brief Initialize the GIZMO particle velocities before the start of the - * actual run based on the initial value of the primitive velocity. - * - * @param p The particle to act upon. - * @param xp The extended particle data to act upon. - */ -__attribute__((always_inline)) INLINE static void hydro_velocities_init( - struct part* restrict p, struct xpart* restrict xp) { - -#ifdef GIZMO_FIX_PARTICLES - p->v[0] = 0.f; - p->v[1] = 0.f; - p->v[2] = 0.f; -#else - p->v[0] = p->primitives.v[0]; - p->v[1] = p->primitives.v[1]; - p->v[2] = p->primitives.v[2]; -#endif - - xp->v_full[0] = p->v[0]; - xp->v_full[1] = p->v[1]; - xp->v_full[2] = p->v[2]; -} - -/** - * @brief Set the particle velocity field that will be used to deboost fluid - * velocities during the force loop. - * - * @param p The particle to act upon. - * @param xp The extended particle data to act upon. - */ -__attribute__((always_inline)) INLINE static void -hydro_velocities_prepare_force(struct part* restrict p, - const struct xpart* restrict xp) {} - -/** - * @brief Set the variables that will be used to update the smoothing length - * during the drift (these will depend on the movement of the particles). - * - * @param p The particle to act upon. - */ -__attribute__((always_inline)) INLINE static void hydro_velocities_end_force( - struct part* restrict p) { - -#ifdef GIZMO_FIX_PARTICLES - /* disable the smoothing length update, since the smoothing lengths should - stay the same for all steps (particles don't move) */ - p->force.h_dt = 0.0f; -#else - /* Add normalization to h_dt. */ - p->force.h_dt *= p->h * hydro_dimension_inv; -#endif -} - -/** - * @brief Set the velocity of a GIZMO particle, based on the values of its - * primitive variables and the geometry of its mesh-free "cell". - * - * @param p The particle to act upon. - * @param xp The extended particle data to act upon. - */ -__attribute__((always_inline)) INLINE static void hydro_velocities_set( - struct part* restrict p, struct xpart* restrict xp) { - -/* We first set the particle velocity. */ -#ifdef GIZMO_FIX_PARTICLES - - p->v[0] = 0.f; - p->v[1] = 0.f; - p->v[2] = 0.f; - -#else // GIZMO_FIX_PARTICLES - - if (p->conserved.mass > 0.f && p->primitives.rho > 0.f) { - - const float inverse_mass = 1.f / p->conserved.mass; - - /* Normal case: set particle velocity to fluid velocity. */ - p->v[0] = p->conserved.momentum[0] * inverse_mass; - p->v[1] = p->conserved.momentum[1] * inverse_mass; - p->v[2] = p->conserved.momentum[2] * inverse_mass; - -#ifdef GIZMO_STEER_MOTION - - /* Add a correction to the velocity to keep particle positions close enough - to - the centroid of their mesh-free "cell". */ - /* The correction term below is the same one described in Springel (2010). - */ - float ds[3]; - ds[0] = p->geometry.centroid[0]; - ds[1] = p->geometry.centroid[1]; - ds[2] = p->geometry.centroid[2]; - const float d = sqrtf(ds[0] * ds[0] + ds[1] * ds[1] + ds[2] * ds[2]); - const float R = get_radius_dimension_sphere(p->geometry.volume); - const float eta = 0.25f; - const float etaR = eta * R; - const float xi = 1.f; - const float soundspeed = - sqrtf(hydro_gamma * p->primitives.P / p->primitives.rho); - /* We only apply the correction if the offset between centroid and position - is too large. */ - if (d > 0.9f * etaR) { - float fac = xi * soundspeed / d; - if (d < 1.1f * etaR) { - fac *= 5.f * (d - 0.9f * etaR) / etaR; - } - p->v[0] -= ds[0] * fac; - p->v[1] -= ds[1] * fac; - p->v[2] -= ds[2] * fac; - } - -#endif // GIZMO_STEER_MOTION - } else { - /* Vacuum particles have no fluid velocity. */ - p->v[0] = 0.f; - p->v[1] = 0.f; - p->v[2] = 0.f; - } - -#endif // GIZMO_FIX_PARTICLES - - /* Now make sure all velocity variables are up to date. */ - xp->v_full[0] = p->v[0]; - xp->v_full[1] = p->v[1]; - xp->v_full[2] = p->v[2]; - - if (p->gpart) { - p->gpart->v_full[0] = p->v[0]; - p->gpart->v_full[1] = p->v[1]; - p->gpart->v_full[2] = p->v[2]; - } -} - -#endif /* SWIFT_HYDRO_VELOCITIES_H */ diff --git a/src/hydro/GizmoMFV/hydro.h b/src/hydro/GizmoMFV/hydro.h index 6916fe33272692316354385b723ce9969606b6a2..c1a62e3c16b98e98b881f3fe4ddcd539cf842c9d 100644 --- a/src/hydro/GizmoMFV/hydro.h +++ b/src/hydro/GizmoMFV/hydro.h @@ -68,14 +68,13 @@ __attribute__((always_inline)) INLINE static float hydro_compute_timestep( vmax = max(vmax, p->timestepvars.vmax); // MATTHIEU: Bert is this correct? Do we need more cosmology terms here? - const float psize = - cosmo->a * powf(p->geometry.volume / hydro_dimension_unit_sphere, - hydro_dimension_inv); + const float psize = powf(p->geometry.volume / hydro_dimension_unit_sphere, + hydro_dimension_inv); float dt = FLT_MAX; if (vmax > 0.) { dt = psize / vmax; } - return CFL_condition * dt; + return cosmo->a * cosmo->a * CFL_condition * dt; } /** @@ -544,7 +543,10 @@ __attribute__((always_inline)) INLINE static void hydro_reset_predicted_values( * @param p The particle to act upon. */ __attribute__((always_inline)) INLINE static void hydro_convert_quantities( - struct part* p, struct xpart* xp, const struct cosmology* cosmo) {} + struct part* p, struct xpart* xp, const struct cosmology* cosmo) { + + p->conserved.energy /= cosmo->a_factor_internal_energy; +} /** * @brief Extra operations to be done during the drift @@ -579,24 +581,40 @@ __attribute__((always_inline)) INLINE static void hydro_predict_extra( /* drift the primitive variables based on the old fluxes */ if (p->geometry.volume > 0.) { - p->primitives.rho += p->conserved.flux.mass * dt_drift / p->geometry.volume; + p->primitives.rho += p->conserved.flux.mass * dt_therm / p->geometry.volume; } if (p->conserved.mass > 0.) { p->primitives.v[0] += - p->conserved.flux.momentum[0] * dt_drift / p->conserved.mass; + p->conserved.flux.momentum[0] * dt_therm / p->conserved.mass; p->primitives.v[1] += - p->conserved.flux.momentum[1] * dt_drift / p->conserved.mass; + p->conserved.flux.momentum[1] * dt_therm / p->conserved.mass; p->primitives.v[2] += - p->conserved.flux.momentum[2] * dt_drift / p->conserved.mass; + p->conserved.flux.momentum[2] * dt_therm / p->conserved.mass; #if !defined(EOS_ISOTHERMAL_GAS) - const float u = p->conserved.energy + p->conserved.flux.energy * dt_therm; - p->primitives.P = - hydro_gamma_minus_one * u * p->primitives.rho / p->conserved.mass; +#ifdef GIZMO_TOTAL_ENERGY + const float Etot = + p->conserved.energy + p->conserved.flux.energy * dt_therm; + const float v2 = (p->primitives.v[0] * p->primitives.v[0] + + p->primitives.v[1] * p->primitives.v[1] + + p->primitives.v[2] * p->primitives.v[2]); + const float u = (Etot / p->conserved.mass - 0.5 * v2); +#else + const float u = + (p->conserved.energy + p->conserved.flux.energy * dt_therm) / + p->conserved.mass; +#endif + p->primitives.P = hydro_gamma_minus_one * u * p->primitives.rho; #endif } + /* we use a sneaky way to get the gravitational contribution to the + velocity update */ + p->primitives.v[0] += p->v[0] - xp->v_full[0]; + p->primitives.v[1] += p->v[1] - xp->v_full[1]; + p->primitives.v[2] += p->v[2] - xp->v_full[2]; + #ifdef SWIFT_DEBUG_CHECKS if (p->h <= 0.) { error("Zero or negative smoothing length (%g)!", p->h); @@ -633,30 +651,75 @@ __attribute__((always_inline)) INLINE static void hydro_end_force( /** * @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. + * @param dt_therm Thermal energy time-step @f$\frac{dt}{a^2}@f$. + * @param dt_grav Gravity time-step @f$\frac{dt}{a}@f$. + * @param dt_hydro Hydro acceleration time-step + * @f$\frac{dt}{a^{3(\gamma{}-1)}}@f$. + * @param dt_kick_corr Gravity correction time-step @f$adt@f$. + * @param cosmo Cosmology. + * @param hydro_props Additional hydro properties. */ __attribute__((always_inline)) INLINE static void hydro_kick_extra( - struct part* p, struct xpart* xp, float dt, const struct cosmology* cosmo, + struct part* p, struct xpart* xp, float dt_therm, float dt_grav, + float dt_hydro, float dt_kick_corr, const struct cosmology* cosmo, const struct hydro_props* hydro_props) { float a_grav[3]; + /* Add gravity. We only do this if we have gravity activated. */ + if (p->gpart) { + /* 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.*/ + a_grav[0] = p->gpart->a_grav[0]; + a_grav[1] = p->gpart->a_grav[1]; + a_grav[2] = p->gpart->a_grav[2]; + +#ifdef GIZMO_TOTAL_ENERGY + p->conserved.energy += dt_grav * (p->conserved.momentum[0] * a_grav[0] + + p->conserved.momentum[1] * a_grav[1] + + p->conserved.momentum[2] * a_grav[2]); +#endif + + /* Kick the momentum for half a time step */ + /* Note that this also affects the particle movement, as the velocity for + the particles is set after this. */ + p->conserved.momentum[0] += p->conserved.mass * a_grav[0] * dt_grav; + p->conserved.momentum[1] += p->conserved.mass * a_grav[1] * dt_grav; + p->conserved.momentum[2] += p->conserved.mass * a_grav[2] * dt_grav; + + p->conserved.energy -= + 0.5f * dt_kick_corr * + (p->gravity.mflux[0] * a_grav[0] + p->gravity.mflux[1] * a_grav[1] + + p->gravity.mflux[2] * a_grav[2]); + } + /* Update conserved variables. */ - p->conserved.mass += p->conserved.flux.mass * dt; - p->conserved.momentum[0] += p->conserved.flux.momentum[0] * dt; - p->conserved.momentum[1] += p->conserved.flux.momentum[1] * dt; - p->conserved.momentum[2] += p->conserved.flux.momentum[2] * dt; + p->conserved.mass += p->conserved.flux.mass * dt_therm; + p->conserved.momentum[0] += p->conserved.flux.momentum[0] * dt_therm; + p->conserved.momentum[1] += p->conserved.flux.momentum[1] * dt_therm; + p->conserved.momentum[2] += p->conserved.flux.momentum[2] * dt_therm; #if defined(EOS_ISOTHERMAL_GAS) /* We use the EoS equation in a sneaky way here just to get the constant u */ p->conserved.energy = p->conserved.mass * gas_internal_energy_from_entropy(0.f, 0.f); #else - p->conserved.energy += p->conserved.flux.energy * dt; + p->conserved.energy += p->conserved.flux.energy * dt_therm; +#endif + +#ifndef HYDRO_GAMMA_5_3 + const float Pcorr = (dt_hydro - dt_therm) * p->geometry.volume; + p->conserved.momentum[0] -= Pcorr * p->primitives.gradients.P[0]; + p->conserved.momentum[1] -= Pcorr * p->primitives.gradients.P[1]; + p->conserved.momentum[2] -= Pcorr * p->primitives.gradients.P[2]; +#ifdef GIZMO_TOTAL_ENERGY + p->conserved.energy -= + Pcorr * (p->primitives.v[0] * p->primitives.gradients.P[0] + + p->primitives.v[1] * p->primitives.gradients.P[1] + + p->primitives.v[2] * p->primitives.gradients.P[2]); +#endif #endif /* Apply the minimal energy limit */ @@ -688,28 +751,9 @@ __attribute__((always_inline)) INLINE static void hydro_kick_extra( } #endif - /* Add gravity. We only do this if we have gravity activated. */ if (p->gpart) { - /* 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.*/ - a_grav[0] = p->gpart->a_grav[0]; - a_grav[1] = p->gpart->a_grav[1]; - a_grav[2] = p->gpart->a_grav[2]; - /* Make sure the gpart knows the mass has changed. */ p->gpart->mass = p->conserved.mass; - - /* Kick the momentum for half a time step */ - /* Note that this also affects the particle movement, as the velocity for - the particles is set after this. */ - p->conserved.momentum[0] += dt * p->conserved.mass * a_grav[0]; - p->conserved.momentum[1] += dt * p->conserved.mass * a_grav[1]; - p->conserved.momentum[2] += dt * p->conserved.mass * a_grav[2]; - - p->conserved.energy += dt * (p->gravity.mflux[0] * a_grav[0] + - p->gravity.mflux[1] * a_grav[1] + - p->gravity.mflux[2] * a_grav[2]); } hydro_velocities_set(p, xp); diff --git a/src/hydro/GizmoMFV/hydro_gradients.h b/src/hydro/GizmoMFV/hydro_gradients.h index 387c263775ddfb37e4c7cb31a624ba5dc673beb2..4046e121bad9e329fecc30afb435bffca2815346 100644 --- a/src/hydro/GizmoMFV/hydro_gradients.h +++ b/src/hydro/GizmoMFV/hydro_gradients.h @@ -98,8 +98,7 @@ __attribute__((always_inline)) INLINE static void hydro_gradients_predict( /* perform gradient reconstruction in space and time */ /* Compute interface position (relative to pj, since we don't need the actual * position) eqn. (8) */ - const float xfac = hj / (hi + hj); - const float xij_j[3] = {xfac * dx[0], xfac * dx[1], xfac * dx[2]}; + const float xij_j[3] = {xij_i[0] + dx[0], xij_i[1] + dx[1], xij_i[2] + dx[2]}; float dWi[5]; dWi[0] = pi->primitives.gradients.rho[0] * xij_i[0] + diff --git a/src/hydro/GizmoMFV/hydro_iact.h b/src/hydro/GizmoMFV/hydro_iact.h index bb835094acd285b109383c1f5d04a6f5e2d936df..c766ce3cc9048f8da8b3438c3c27e6998dd5df7e 100644 --- a/src/hydro/GizmoMFV/hydro_iact.h +++ b/src/hydro/GizmoMFV/hydro_iact.h @@ -375,21 +375,11 @@ __attribute__((always_inline)) INLINE static void runner_iact_fluxes_common( /* Compute interface velocity */ /* eqn. (9) */ - float xijdotdx = xij_i[0] * dx[0] + xij_i[1] * dx[1] + xij_i[2] * dx[2]; - xijdotdx *= r_inv * r_inv; - const float vij[3] = {vi[0] + (vi[0] - vj[0]) * xijdotdx, - vi[1] + (vi[1] - vj[1]) * xijdotdx, - vi[2] + (vi[2] - vj[2]) * xijdotdx}; - - /* complete calculation of position of interface */ - /* NOTE: dx is not necessarily just pi->x - pj->x but can also contain - correction terms for periodicity. If we do the interpolation, - we have to use xij w.r.t. the actual particle. - => we need a separate xij for pi and pj... */ - /* tldr: we do not need the code below, but we do need the same code as above - but then with i and j swapped */ - // for ( k = 0 ; k < 3 ; k++ ) - // xij[k] += pi->x[k]; + const float vij[3] = {vi[0] + xfac * (vi[0] - vj[0]), + vi[1] + xfac * (vi[1] - vj[1]), + vi[2] + xfac * (vi[2] - vj[2])}; + + hydro_gradients_predict(pi, pj, hi, hj, dx, r, xij_i, Wi, Wj); /* Boost the primitive variables to the frame of reference of the interface */ /* Note that velocities are indices 1-3 in W */ @@ -400,8 +390,6 @@ __attribute__((always_inline)) INLINE static void runner_iact_fluxes_common( Wj[2] -= vij[1]; Wj[3] -= vij[2]; - hydro_gradients_predict(pi, pj, hi, hj, dx, r, xij_i, Wi, Wj); - /* we don't need to rotate, we can use the unit vector in the Riemann problem * itself (see GIZMO) */ @@ -447,9 +435,9 @@ __attribute__((always_inline)) INLINE static void runner_iact_fluxes_common( if (mode == 1) { /* Store mass flux */ const float mflux_j = totflux[0]; - pj->gravity.mflux[0] -= mflux_j * dx[0]; - pj->gravity.mflux[1] -= mflux_j * dx[1]; - pj->gravity.mflux[2] -= mflux_j * dx[2]; + pj->gravity.mflux[0] += mflux_j * dx[0]; + pj->gravity.mflux[1] += mflux_j * dx[1]; + pj->gravity.mflux[2] += mflux_j * dx[2]; pj->conserved.flux.mass += totflux[0]; pj->conserved.flux.momentum[0] += totflux[1]; diff --git a/src/hydro/GizmoMFV/hydro_velocities.h b/src/hydro/GizmoMFV/hydro_velocities.h index ea30d5a6c9c74d34ffd73fa6ab941640f37b02e4..a61a482683291cfc0662116ada99b94a4ccfe68d 100644 --- a/src/hydro/GizmoMFV/hydro_velocities.h +++ b/src/hydro/GizmoMFV/hydro_velocities.h @@ -103,7 +103,6 @@ __attribute__((always_inline)) INLINE static void hydro_velocities_set( p->v[2] = p->conserved.momentum[2] * inverse_mass; #ifdef GIZMO_STEER_MOTION - /* Add a correction to the velocity to keep particle positions close enough to the centroid of their mesh-free "cell". */ diff --git a/src/hydro/Minimal/hydro.h b/src/hydro/Minimal/hydro.h index 812f8ad72de55ad7990ee6ef88223a401780bc4b..01abe55e7267ca04a7f3e9740c10c681f86f29ea 100644 --- a/src/hydro/Minimal/hydro.h +++ b/src/hydro/Minimal/hydro.h @@ -527,6 +527,7 @@ __attribute__((always_inline)) INLINE static void hydro_end_force( */ __attribute__((always_inline)) INLINE static void hydro_kick_extra( struct part *restrict p, struct xpart *restrict xp, float dt_therm, + float dt_grav, float dt_hydro, float dt_kick_corr, const struct cosmology *cosmo, const struct hydro_props *hydro_props) { /* Do not decrease the energy by more than a factor of 2*/ diff --git a/src/hydro/MinimalMultiMat/hydro.h b/src/hydro/Planetary/hydro.h similarity index 92% rename from src/hydro/MinimalMultiMat/hydro.h rename to src/hydro/Planetary/hydro.h index cfad6b2b2b389da9f423540cb30f1df4cebc5416..106e1a96ae57868c94d1077b74e84909ab0f0830 100644 --- a/src/hydro/MinimalMultiMat/hydro.h +++ b/src/hydro/Planetary/hydro.h @@ -17,11 +17,11 @@ * along with this program. If not, see <http://www.gnu.org/licenses/>. * ******************************************************************************/ -#ifndef SWIFT_MINIMAL_MULTI_MAT_HYDRO_H -#define SWIFT_MINIMAL_MULTI_MAT_HYDRO_H +#ifndef SWIFT_PLANETARY_HYDRO_H +#define SWIFT_PLANETARY_HYDRO_H /** - * @file MinimalMultiMat/hydro.h + * @file Planetary/hydro.h * @brief Minimal conservative implementation of SPH (Non-neighbour loop * equations) with multiple materials. * @@ -44,6 +44,12 @@ #include "kernel_hydro.h" #include "minmax.h" +/* + * Note: Define PLANETARY_SPH_BALSARA to use the Balsara (1995) switch for + * the artificial viscosity, instead of the default Monaghan (1992). + * i.e. compile with: make CFLAGS=-DPLANETARY_SPH_BALSARA to use. + */ + /** * @brief Returns the comoving internal energy of a particle * @@ -257,6 +263,7 @@ __attribute__((always_inline)) INLINE static void hydro_set_internal_energy_dt( p->u_dt = du_dt; } + /** * @brief Computes the hydro time-step of a given particle * @@ -391,23 +398,52 @@ __attribute__((always_inline)) INLINE static void hydro_prepare_force( struct part *restrict p, struct xpart *restrict xp, const struct cosmology *cosmo) { +#ifdef PLANETARY_SPH_BALSARA + const float fac_mu = cosmo->a_factor_mu; + + /* Compute the norm of the curl */ + const float curl_v = sqrtf(p->density.rot_v[0] * p->density.rot_v[0] + + p->density.rot_v[1] * p->density.rot_v[1] + + p->density.rot_v[2] * p->density.rot_v[2]); + + /* Compute the norm of div v */ + const float abs_div_v = fabsf(p->density.div_v); +#endif // PLANETARY_SPH_BALSARA + /* Compute the pressure */ const float pressure = gas_pressure_from_internal_energy(p->rho, p->u, p->mat_id); /* Compute the sound speed */ const float soundspeed = - gas_soundspeed_from_pressure(p->rho, pressure, p->mat_id); + gas_soundspeed_from_internal_energy(p->rho, p->u, p->mat_id); /* Compute the "grad h" term */ const float rho_inv = 1.f / p->rho; - const float grad_h_term = - 1.f / (1.f + hydro_dimension_inv * p->h * p->density.rho_dh * rho_inv); + float grad_h_term; + const float grad_h_term_inv = + 1.f + hydro_dimension_inv * p->h * p->density.rho_dh * rho_inv; + /* Avoid 1/0 from only having one neighbour right at the edge of the kernel */ + if (grad_h_term_inv != 0.f) { + grad_h_term = 1.f / grad_h_term_inv; + } else { + grad_h_term = 0.f; + } + +#ifdef PLANETARY_SPH_BALSARA + /* Compute the Balsara switch */ + const float balsara = + abs_div_v / (abs_div_v + curl_v + 0.0001f * fac_mu * soundspeed / p->h); +#endif // PLANETARY_SPH_BALSARA /* Update variables. */ p->force.f = grad_h_term; p->force.pressure = pressure; p->force.soundspeed = soundspeed; + +#ifdef PLANETARY_SPH_BALSARA + p->force.balsara = balsara; +#endif // PLANETARY_SPH_BALSARA } /** @@ -494,7 +530,7 @@ __attribute__((always_inline)) INLINE static void hydro_predict_extra( /* Compute the new sound speed */ const float soundspeed = - gas_soundspeed_from_pressure(p->rho, pressure, p->mat_id); + gas_soundspeed_from_internal_energy(p->rho, p->u, p->mat_id); p->force.pressure = pressure; p->force.soundspeed = soundspeed; @@ -532,6 +568,7 @@ __attribute__((always_inline)) INLINE static void hydro_end_force( */ __attribute__((always_inline)) INLINE static void hydro_kick_extra( struct part *restrict p, struct xpart *restrict xp, float dt_therm, + float dt_grav, float dt_hydro, float dt_kick_corr, const struct cosmology *cosmo, const struct hydro_props *hydro_props) { /* Do not decrease the energy by more than a factor of 2*/ @@ -631,4 +668,4 @@ hydro_set_init_internal_energy(struct part *p, float u_init) { p->u = u_init; } -#endif /* SWIFT_MINIMAL_MULTI_MAT_HYDRO_H */ +#endif /* SWIFT_PLANETARY_HYDRO_H */ diff --git a/src/hydro/MinimalMultiMat/hydro_debug.h b/src/hydro/Planetary/hydro_debug.h similarity index 89% rename from src/hydro/MinimalMultiMat/hydro_debug.h rename to src/hydro/Planetary/hydro_debug.h index 17b624ad0f660152be4ba685905a3c855e1761f8..74261f3b49e2881af1c403013005560efa53a7f1 100644 --- a/src/hydro/MinimalMultiMat/hydro_debug.h +++ b/src/hydro/Planetary/hydro_debug.h @@ -17,13 +17,12 @@ * along with this program. If not, see <http://www.gnu.org/licenses/>. * ******************************************************************************/ -#ifndef SWIFT_MINIMAL_MULTI_MAT_HYDRO_DEBUG_H -#define SWIFT_MINIMAL_MULTI_MAT_HYDRO_DEBUG_H +#ifndef SWIFT_PLANETARY_HYDRO_DEBUG_H +#define SWIFT_PLANETARY_HYDRO_DEBUG_H /** - * @file MinimalMultiMat/hydro_debug.h - * @brief MinimalMultiMat conservative implementation of SPH (Debugging - * routines) + * @file Planetary/hydro_debug.h + * @brief Minimal conservative implementation of SPH (Debugging routines) * * The thermal variable is the internal energy (u). Simple constant * viscosity term without switches is implemented. No thermal conduction @@ -51,4 +50,4 @@ __attribute__((always_inline)) INLINE static void hydro_debug_particle( p->density.wcount, p->rho, p->density.rho_dh, p->time_bin, p->mat_id); } -#endif /* SWIFT_MINIMAL_MULTI_MAT_HYDRO_DEBUG_H */ +#endif /* SWIFT_PLANETARY_HYDRO_DEBUG_H */ diff --git a/src/hydro/MinimalMultiMat/hydro_iact.h b/src/hydro/Planetary/hydro_iact.h similarity index 89% rename from src/hydro/MinimalMultiMat/hydro_iact.h rename to src/hydro/Planetary/hydro_iact.h index 5984c1c483546d87800792ced0ffcc41e0aaa408..bf96034696806e3adff1d8ba7f385af65461b9ea 100644 --- a/src/hydro/MinimalMultiMat/hydro_iact.h +++ b/src/hydro/Planetary/hydro_iact.h @@ -17,13 +17,12 @@ * along with this program. If not, see <http://www.gnu.org/licenses/>. * ******************************************************************************/ -#ifndef SWIFT_MINIMAL_MULTI_MAT_HYDRO_IACT_H -#define SWIFT_MINIMAL_MULTI_MAT_HYDRO_IACT_H +#ifndef SWIFT_PLANETARY_HYDRO_IACT_H +#define SWIFT_PLANETARY_HYDRO_IACT_H /** - * @file MinimalMultiMat/hydro_iact.h - * @brief MinimalMultiMat conservative implementation of SPH (Neighbour loop - * equations) + * @file Planetary/hydro_iact.h + * @brief Minimal conservative implementation of SPH (Neighbour loop equations) * * The thermal variable is the internal energy (u). Simple constant * viscosity term without switches is implemented. No thermal conduction @@ -177,7 +176,13 @@ __attribute__((always_inline)) INLINE static void runner_iact_force( (pi->v[1] - pj->v[1]) * dx[1] + (pi->v[2] - pj->v[2]) * dx[2] + a2_Hubble * r2; - /* Are the particles moving towards each others ? */ +#ifdef PLANETARY_SPH_BALSARA + /* Balsara term */ + const float balsara_i = pi->force.balsara; + const float balsara_j = pj->force.balsara; +#endif // PLANETARY_SPH_BALSARA + + /* Are the particles moving towards each other? */ const float omega_ij = min(dvdr, 0.f); const float mu_ij = fac_mu * r_inv * omega_ij; /* This is 0 or negative */ @@ -186,9 +191,14 @@ __attribute__((always_inline)) INLINE static void runner_iact_force( const float cj = pj->force.soundspeed; const float v_sig = ci + cj - 3.f * mu_ij; - /* Construct the full viscosity term */ + /* Now construct the full viscosity term */ const float rho_ij = 0.5f * (rhoi + rhoj); +#ifdef PLANETARY_SPH_BALSARA + const float visc = -0.25f * const_viscosity_alpha * v_sig * mu_ij * + (balsara_i + balsara_j) / rho_ij; +#else const float visc = -0.5f * const_viscosity_alpha * v_sig * mu_ij / rho_ij; +#endif // PLANETARY_SPH_BALSARA /* Convolve with the kernel */ const float visc_acc_term = 0.5f * visc * (wi_dr + wj_dr) * r_inv; @@ -220,7 +230,7 @@ __attribute__((always_inline)) INLINE static void runner_iact_force( const float du_dt_i = sph_du_term_i + visc_du_term; const float du_dt_j = sph_du_term_j + visc_du_term; - /* Internal energy time derivatibe */ + /* Internal energy time derivative */ pi->u_dt += du_dt_i * mj; pj->u_dt += du_dt_j * mi; @@ -290,18 +300,31 @@ __attribute__((always_inline)) INLINE static void runner_iact_nonsym_force( (pi->v[1] - pj->v[1]) * dx[1] + (pi->v[2] - pj->v[2]) * dx[2] + a2_Hubble * r2; - /* Are the particles moving towards each others ? */ +#ifdef PLANETARY_SPH_BALSARA + /* Balsara term */ + const float balsara_i = pi->force.balsara; + const float balsara_j = pj->force.balsara; +#endif // PLANETARY_SPH_BALSARA + + /* Are the particles moving towards each other? */ const float omega_ij = min(dvdr, 0.f); const float mu_ij = fac_mu * r_inv * omega_ij; /* This is 0 or negative */ - /* Compute sound speeds and signal velocity */ + /* Compute sound speeds */ const float ci = pi->force.soundspeed; const float cj = pj->force.soundspeed; + + /* Signal velocity */ const float v_sig = ci + cj - 3.f * mu_ij; /* Construct the full viscosity term */ const float rho_ij = 0.5f * (rhoi + rhoj); +#ifdef PLANETARY_SPH_BALSARA + const float visc = -0.25f * const_viscosity_alpha * v_sig * mu_ij * + (balsara_i + balsara_j) / rho_ij; +#else const float visc = -0.5f * const_viscosity_alpha * v_sig * mu_ij / rho_ij; +#endif // PLANETARY_SPH_BALSARA /* Convolve with the kernel */ const float visc_acc_term = 0.5f * visc * (wi_dr + wj_dr) * r_inv; @@ -327,7 +350,7 @@ __attribute__((always_inline)) INLINE static void runner_iact_nonsym_force( /* Assemble the energy equation term */ const float du_dt_i = sph_du_term_i + visc_du_term; - /* Internal energy time derivatibe */ + /* Internal energy time derivative */ pi->u_dt += du_dt_i * mj; /* Get the time derivative for h. */ @@ -337,4 +360,4 @@ __attribute__((always_inline)) INLINE static void runner_iact_nonsym_force( pi->force.v_sig = max(pi->force.v_sig, v_sig); } -#endif /* SWIFT_MINIMAL_MULTI_MAT_HYDRO_IACT_H */ +#endif /* SWIFT_PLANETARY_HYDRO_IACT_H */ diff --git a/src/hydro/MinimalMultiMat/hydro_io.h b/src/hydro/Planetary/hydro_io.h similarity index 95% rename from src/hydro/MinimalMultiMat/hydro_io.h rename to src/hydro/Planetary/hydro_io.h index 7f41f5e227b6c8a8904b5546a2568b4700109abd..afb37d884494fd02e30c143194804a2b49a77be0 100644 --- a/src/hydro/MinimalMultiMat/hydro_io.h +++ b/src/hydro/Planetary/hydro_io.h @@ -17,12 +17,12 @@ * along with this program. If not, see <http://www.gnu.org/licenses/>. * ******************************************************************************/ -#ifndef SWIFT_MINIMAL_MULTI_MAT_HYDRO_IO_H -#define SWIFT_MINIMAL_MULTI_MAT_HYDRO_IO_H +#ifndef SWIFT_PLANETARY_HYDRO_IO_H +#define SWIFT_PLANETARY_HYDRO_IO_H /** - * @file MinimalMultiMat/hydro_io.h - * @brief MinimalMultiMat conservative implementation of SPH (i/o routines) + * @file Planetary/hydro_io.h + * @brief Minimal conservative implementation of SPH (i/o routines) * * The thermal variable is the internal energy (u). Simple constant * viscosity term without switches is implemented. No thermal conduction @@ -197,8 +197,14 @@ INLINE static void hydro_write_flavour(hid_t h_grpsph) { /* Viscosity and thermal conduction */ /* Nothing in this minimal model... */ io_write_attribute_s(h_grpsph, "Thermal Conductivity Model", "No treatment"); +#ifdef PLANETARY_SPH_BALSARA + io_write_attribute_s( + h_grpsph, "Viscosity Model", + "as in Springel (2005), i.e. Monaghan (1992) with Balsara (1995) switch"); +#else io_write_attribute_s(h_grpsph, "Viscosity Model", "Minimal treatment as in Monaghan (1992)"); +#endif // PLANETARY_SPH_BALSARA /* Time integration properties */ io_write_attribute_f(h_grpsph, "Maximal Delta u change over dt", @@ -212,4 +218,4 @@ INLINE static void hydro_write_flavour(hid_t h_grpsph) { */ INLINE static int writeEntropyFlag(void) { return 0; } -#endif /* SWIFT_MINIMAL_MULTI_MAT_HYDRO_IO_H */ +#endif /* SWIFT_PLANETARY_HYDRO_IO_H */ diff --git a/src/hydro/MinimalMultiMat/hydro_part.h b/src/hydro/Planetary/hydro_part.h similarity index 90% rename from src/hydro/MinimalMultiMat/hydro_part.h rename to src/hydro/Planetary/hydro_part.h index dad13e889aa531636e34846825109086177b3dae..7d1fc8f6729992bfdf2eeaba6e33cc9a7b071655 100644 --- a/src/hydro/MinimalMultiMat/hydro_part.h +++ b/src/hydro/Planetary/hydro_part.h @@ -17,13 +17,12 @@ * along with this program. If not, see <http://www.gnu.org/licenses/>. * ******************************************************************************/ -#ifndef SWIFT_MINIMAL_MULTI_MAT_HYDRO_PART_H -#define SWIFT_MINIMAL_MULTI_MAT_HYDRO_PART_H +#ifndef SWIFT_PLANETARY_HYDRO_PART_H +#define SWIFT_PLANETARY_HYDRO_PART_H /** - * @file MinimalMultiMat/hydro_part.h - * @brief MinimalMultiMat conservative implementation of SPH (Particle - * definition) + * @file Planetary/hydro_part.h + * @brief Minimal conservative implementation of SPH (Particle definition) * * The thermal variable is the internal energy (u). Simple constant * viscosity term without switches is implemented. No thermal conduction @@ -127,6 +126,14 @@ struct part { /*! Derivative of density with respect to h */ float rho_dh; +#ifdef PLANETARY_SPH_BALSARA + /*! Velocity divergence. */ + float div_v; + + /*! Velocity curl. */ + float rot_v[3]; +#endif // PLANETARY_SPH_BALSARA + } density; /** @@ -153,6 +160,11 @@ struct part { /*! Time derivative of smoothing length */ float h_dt; +#ifdef PLANETARY_SPH_BALSARA + /*! Balsara switch */ + float balsara; +#endif // PLANETARY_SPH_BALSARA + } force; }; @@ -177,4 +189,4 @@ struct part { } SWIFT_STRUCT_ALIGN; -#endif /* SWIFT_MINIMAL_MULTI_MAT_HYDRO_PART_H */ +#endif /* SWIFT_PLANETARY_HYDRO_PART_H */ diff --git a/src/hydro/PressureEnergy/hydro.h b/src/hydro/PressureEnergy/hydro.h index ea086daeeb1e93d7f1476302564fb4182a6fb611..5082db6c792701511972a52fd2fb00a6a45f7271 100644 --- a/src/hydro/PressureEnergy/hydro.h +++ b/src/hydro/PressureEnergy/hydro.h @@ -581,6 +581,7 @@ __attribute__((always_inline)) INLINE static void hydro_end_force( */ __attribute__((always_inline)) INLINE static void hydro_kick_extra( struct part *restrict p, struct xpart *restrict xp, float dt_therm, + float dt_grav, float dt_hydro, float dt_kick_corr, const struct cosmology *cosmo, const struct hydro_props *restrict hydro_properties) { diff --git a/src/hydro/PressureEntropy/hydro.h b/src/hydro/PressureEntropy/hydro.h index e4b7cf06e083638a94526cc1f9e7212cf19dfad4..3f0f9931ebd557fffcab7e89f3c6297c2fb26474 100644 --- a/src/hydro/PressureEntropy/hydro.h +++ b/src/hydro/PressureEntropy/hydro.h @@ -541,6 +541,7 @@ __attribute__((always_inline)) INLINE static void hydro_end_force( */ __attribute__((always_inline)) INLINE static void hydro_kick_extra( struct part *restrict p, struct xpart *restrict xp, float dt_therm, + float dt_grav, float dt_hydro, float dt_kick_corr, const struct cosmology *cosmo, const struct hydro_props *hydro_props) { /* Do not decrease the entropy (temperature) by more than a factor of 2*/ diff --git a/src/hydro/Shadowswift/hydro.h b/src/hydro/Shadowswift/hydro.h index d70d58c6ba508ba4282ac9dd32565478afb40692..cca2a241866fc797055922a48c25cebd6fa1b140 100644 --- a/src/hydro/Shadowswift/hydro.h +++ b/src/hydro/Shadowswift/hydro.h @@ -443,7 +443,8 @@ __attribute__((always_inline)) INLINE static void hydro_end_force( * @param dt Physical time step. */ __attribute__((always_inline)) INLINE static void hydro_kick_extra( - struct part* p, struct xpart* xp, float dt, const struct cosmology* cosmo, + struct part* p, struct xpart* xp, float dt, float dt_grav, float dt_hydro, + float dt_kick_corr, const struct cosmology* cosmo, const struct hydro_props* hydro_props) { /* Update the conserved variables. We do this here and not in the kick, diff --git a/src/hydro_io.h b/src/hydro_io.h index d752bb8bc03f619fe759fc8f5de32a01b3a61abe..b6e0c36cc7415a1f628a109795aa98b4f583036c 100644 --- a/src/hydro_io.h +++ b/src/hydro_io.h @@ -39,8 +39,8 @@ #include "./hydro/GizmoMFM/hydro_io.h" #elif defined(SHADOWFAX_SPH) #include "./hydro/Shadowswift/hydro_io.h" -#elif defined(MINIMAL_MULTI_MAT_SPH) -#include "./hydro/MinimalMultiMat/hydro_io.h" +#elif defined(PLANETARY_SPH) +#include "./hydro/Planetary/hydro_io.h" #else #error "Invalid choice of SPH variant" #endif diff --git a/src/hydro_properties.c b/src/hydro_properties.c index f79fd832248fba8fbc55bd9fcec57e645be93159..905bf6973447b1ddd1c174b2e65d6841917ef736 100644 --- a/src/hydro_properties.c +++ b/src/hydro_properties.c @@ -135,6 +135,14 @@ void hydro_props_init(struct hydro_props *p, mean_molecular_weight = 4. / (1. + 3. * p->hydrogen_mass_fraction); p->minimal_internal_energy = u_min / mean_molecular_weight; + +#ifdef PLANETARY_SPH +#ifdef PLANETARY_SPH_BALSARA + message("Planetary SPH: Balsara switch enabled"); +#else + message("Planetary SPH: Balsara switch disabled"); +#endif // PLANETARY_SPH_BALSARA +#endif // PLANETARY_SPH } /** diff --git a/src/kick.h b/src/kick.h index 9d10f1e78d3934c4277c14217cbbc46514e87033..50ecaea498bdd401cc0ac27525ed27986a344c59 100644 --- a/src/kick.h +++ b/src/kick.h @@ -68,6 +68,7 @@ __attribute__((always_inline)) INLINE static void kick_gpart( * @param dt_kick_hydro The kick time-step for hydro accelerations. * @param dt_kick_grav The kick time-step for gravity accelerations. * @param dt_kick_therm The kick time-step for changes in thermal state. + * @param dt_kick_corr The kick time-step for the gizmo-mfv gravity correction. * @param cosmo The cosmological model. * @param hydro_props The constants used in the scheme * @param ti_start The starting (integer) time of the kick (for debugging @@ -76,9 +77,9 @@ __attribute__((always_inline)) INLINE static void kick_gpart( */ __attribute__((always_inline)) INLINE static void kick_part( struct part *restrict p, struct xpart *restrict xp, double dt_kick_hydro, - double dt_kick_grav, double dt_kick_therm, const struct cosmology *cosmo, - const struct hydro_props *hydro_props, integertime_t ti_start, - integertime_t ti_end) { + double dt_kick_grav, double dt_kick_therm, double dt_kick_corr, + const struct cosmology *cosmo, const struct hydro_props *hydro_props, + integertime_t ti_start, integertime_t ti_end) { #ifdef SWIFT_DEBUG_CHECKS if (p->ti_kick != ti_start) @@ -110,7 +111,8 @@ __attribute__((always_inline)) INLINE static void kick_part( } /* Extra kick work */ - hydro_kick_extra(p, xp, dt_kick_therm, cosmo, hydro_props); + hydro_kick_extra(p, xp, dt_kick_therm, dt_kick_grav, dt_kick_hydro, + dt_kick_corr, cosmo, hydro_props); if (p->gpart != NULL) gravity_kick_extra(p->gpart, dt_kick_grav); } diff --git a/src/multipole.h b/src/multipole.h index e0e6da32a2950d7fce164b2abc422302b7c7de5e..c05aa36890313ea22f725ee272746bdf63f597ea 100644 --- a/src/multipole.h +++ b/src/multipole.h @@ -240,17 +240,17 @@ INLINE static void gravity_drift(struct gravity_tensors *m, double dt) { m->CoM[2] += dz; #ifdef SWIFT_DEBUG_CHECKS - if (m->m_pole.vel[0] > m->m_pole.max_delta_vel[0]) + if (m->m_pole.vel[0] > m->m_pole.max_delta_vel[0] * 1.1) error("Invalid maximal velocity"); - if (m->m_pole.vel[0] < m->m_pole.min_delta_vel[0]) + if (m->m_pole.vel[0] < m->m_pole.min_delta_vel[0] * 1.1) error("Invalid minimal velocity"); - if (m->m_pole.vel[1] > m->m_pole.max_delta_vel[1]) + if (m->m_pole.vel[1] > m->m_pole.max_delta_vel[1] * 1.1) error("Invalid maximal velocity"); - if (m->m_pole.vel[1] < m->m_pole.min_delta_vel[1]) + if (m->m_pole.vel[1] < m->m_pole.min_delta_vel[1] * 1.1) error("Invalid minimal velocity"); - if (m->m_pole.vel[2] > m->m_pole.max_delta_vel[2]) + if (m->m_pole.vel[2] > m->m_pole.max_delta_vel[2] * 1.1) error("Invalid maximal velocity"); - if (m->m_pole.vel[2] < m->m_pole.min_delta_vel[2]) + if (m->m_pole.vel[2] < m->m_pole.min_delta_vel[2] * 1.1) error("Invalid minimal velocity"); #endif @@ -1037,6 +1037,13 @@ INLINE static void gravity_P2M(struct gravity_tensors *multi, vel[2] += gparts[k].v_full[2] * m; } +#ifdef PLANETARY_SPH + /* Prevent FPE from zero mass with the temporary outside-the-box particles */ + if (mass == 0.f) { + mass = FLT_MIN; + } +#endif // PLANETARY_SPH + /* Final operation on CoM */ const double imass = 1.0 / mass; com[0] *= imass; diff --git a/src/outputlist.c b/src/outputlist.c index 09874ca93cea0c7cc7d91038e49ec33bb851516f..fd33370ca45f25c17ecd2cc8df622138842507f3 100644 --- a/src/outputlist.c +++ b/src/outputlist.c @@ -208,7 +208,8 @@ void output_list_read_next_time(struct output_list *t, const struct engine *e, * time) */ void output_list_init(struct output_list **list, const struct engine *e, - char *name, double *delta_time, double *time_first) { + const char *name, double *delta_time, + double *time_first) { struct swift_params *params = e->parameter_file; /* get cosmo */ diff --git a/src/outputlist.h b/src/outputlist.h index ddc08c84d3739097e990c175cd83e809231845a9..6045d75ea29f0aab44252835147502f3df0de20c 100644 --- a/src/outputlist.h +++ b/src/outputlist.h @@ -56,7 +56,7 @@ void output_list_read_file(struct output_list *outputlist, const char *filename, void output_list_read_next_time(struct output_list *t, const struct engine *e, const char *name, integertime_t *ti_next); void output_list_init(struct output_list **list, const struct engine *e, - char *name, double *delta_time, double *time_first); + const char *name, double *delta_time, double *time_first); void output_list_print(const struct output_list *outputlist); void output_list_clean(struct output_list *outputlist); void output_list_struct_dump(struct output_list *list, FILE *stream); diff --git a/src/parallel_io.c b/src/parallel_io.c index b82443b33ba767cfe2050cf300535db924bfb537..a3a71d0ac5703f194bfa8e53c9b0b62b25e6a602 100644 --- a/src/parallel_io.c +++ b/src/parallel_io.c @@ -928,10 +928,11 @@ void prepare_file(struct engine* e, const char* baseName, long long N_total[6], char fileName[FILENAME_BUFFER_SIZE]; if (e->snapshot_label_delta == 1) snprintf(fileName, FILENAME_BUFFER_SIZE, "%s_%04i.hdf5", baseName, - e->snapshot_output_count); + e->snapshot_output_count + e->snapshot_label_first); else snprintf(fileName, FILENAME_BUFFER_SIZE, "%s_%06i.hdf5", baseName, - e->snapshot_output_count * e->snapshot_label_delta); + e->snapshot_output_count * e->snapshot_label_delta + + e->snapshot_label_first); /* Open HDF5 file with the chosen parameters */ hid_t h_file = H5Fcreate(fileName, H5F_ACC_TRUNC, H5P_DEFAULT, H5P_DEFAULT); @@ -1204,8 +1205,13 @@ void write_output_parallel(struct engine* e, const char* baseName, /* HDF5 File name */ char fileName[FILENAME_BUFFER_SIZE]; - snprintf(fileName, FILENAME_BUFFER_SIZE, "%s_%04i.hdf5", baseName, - e->snapshot_output_count); + if (e->snapshot_label_delta == 1) + snprintf(fileName, FILENAME_BUFFER_SIZE, "%s_%04i.hdf5", baseName, + e->snapshot_output_count + e->snapshot_label_first); + else + snprintf(fileName, FILENAME_BUFFER_SIZE, "%s_%06i.hdf5", baseName, + e->snapshot_output_count * e->snapshot_label_delta + + e->snapshot_label_first); /* Prepare some file-access properties */ hid_t plist_id = H5Pcreate(H5P_FILE_ACCESS); diff --git a/src/part.h b/src/part.h index bca84cc0212e79e15ffbeeeb0bbcfc714d5481be..145bf2111771d8ad254affb213b93b7ac829f1a6 100644 --- a/src/part.h +++ b/src/part.h @@ -69,8 +69,8 @@ #include "./hydro/Shadowswift/hydro_part.h" #define hydro_need_extra_init_loop 0 #define EXTRA_HYDRO_LOOP -#elif defined(MINIMAL_MULTI_MAT_SPH) -#include "./hydro/MinimalMultiMat/hydro_part.h" +#elif defined(PLANETARY_SPH) +#include "./hydro/Planetary/hydro_part.h" #define hydro_need_extra_init_loop 0 #else #error "Invalid choice of SPH variant" diff --git a/src/riemann/riemann_hllc.h b/src/riemann/riemann_hllc.h index d7e376fe667dd3cfeac58d5820053057ab928d3e..a34b907ba5c6142755f2c4107d7b456393c12b42 100644 --- a/src/riemann/riemann_hllc.h +++ b/src/riemann/riemann_hllc.h @@ -33,11 +33,6 @@ #include "riemann_checks.h" #include "riemann_vacuum.h" -#ifndef EOS_IDEAL_GAS -#error \ - "The HLLC Riemann solver currently only supports and ideal gas equation of state. Either select this equation of state, or try using another Riemann solver!" -#endif - __attribute__((always_inline)) INLINE static void riemann_solve_for_flux( const float *WL, const float *WR, const float *n, const float *vij, float *totflux) { @@ -48,19 +43,21 @@ __attribute__((always_inline)) INLINE static void riemann_solve_for_flux( /* Handle pure vacuum */ if (!WL[0] && !WR[0]) { - totflux[0] = 0.f; - totflux[1] = 0.f; - totflux[2] = 0.f; - totflux[3] = 0.f; - totflux[4] = 0.f; + totflux[0] = 0.0f; + totflux[1] = 0.0f; + totflux[2] = 0.0f; + totflux[3] = 0.0f; + totflux[4] = 0.0f; return; } /* STEP 0: obtain velocity in interface frame */ const float uL = WL[1] * n[0] + WL[2] * n[1] + WL[3] * n[2]; const float uR = WR[1] * n[0] + WR[2] * n[1] + WR[3] * n[2]; - const float aL = sqrtf(hydro_gamma * WL[4] / WL[0]); - const float aR = sqrtf(hydro_gamma * WR[4] / WR[0]); + const float rhoLinv = 1.0f / WL[0]; + const float rhoRinv = 1.0f / WR[0]; + const float aL = sqrtf(hydro_gamma * WL[4] * rhoLinv); + const float aR = sqrtf(hydro_gamma * WR[4] * rhoRinv); /* Handle vacuum: vacuum does not require iteration and is always exact */ if (riemann_is_vacuum(WL, WR, uL, uR, aL, aR)) { @@ -69,98 +66,90 @@ __attribute__((always_inline)) INLINE static void riemann_solve_for_flux( } /* STEP 1: pressure estimate */ - const float rhobar = 0.5f * (WL[0] + WR[0]); - const float abar = 0.5f * (aL + aR); - const float pPVRS = 0.5f * (WL[4] + WR[4]) - 0.5f * (uR - uL) * rhobar * abar; - const float pstar = max(0.f, pPVRS); + const float rhobar = WL[0] + WR[0]; + const float abar = aL + aR; + const float pPVRS = + 0.5f * ((WL[4] + WR[4]) - 0.25f * (uR - uL) * rhobar * abar); + const float pstar = max(0.0f, pPVRS); /* STEP 2: wave speed estimates all these speeds are along the interface normal, since uL and uR are */ - float qL = 1.f; - if (pstar > WL[4] && WL[4] > 0.f) { - qL = sqrtf(1.f + 0.5f * hydro_gamma_plus_one * hydro_one_over_gamma * - (pstar / WL[4] - 1.f)); + float qL = 1.0f; + if (pstar > WL[4] && WL[4] > 0.0f) { + qL = sqrtf(1.0f + 0.5f * hydro_gamma_plus_one * hydro_one_over_gamma * + (pstar / WL[4] - 1.0f)); } - float qR = 1.f; - if (pstar > WR[4] && WR[4] > 0.f) { - qR = sqrtf(1.f + 0.5f * hydro_gamma_plus_one * hydro_one_over_gamma * - (pstar / WR[4] - 1.f)); + float qR = 1.0f; + if (pstar > WR[4] && WR[4] > 0.0f) { + qR = sqrtf(1.0f + 0.5f * hydro_gamma_plus_one * hydro_one_over_gamma * + (pstar / WR[4] - 1.0f)); } - const float SL = uL - aL * qL; - const float SR = uR + aR * qR; + const float SLmuL = -aL * qL; + const float SRmuR = aR * qR; const float Sstar = - (WR[4] - WL[4] + WL[0] * uL * (SL - uL) - WR[0] * uR * (SR - uR)) / - (WL[0] * (SL - uL) - WR[0] * (SR - uR)); + (WR[4] - WL[4] + WL[0] * uL * SLmuL - WR[0] * uR * SRmuR) / + (WL[0] * SLmuL - WR[0] * SRmuR); /* STEP 3: HLLC flux in a frame moving with the interface velocity */ - if (Sstar >= 0.f) { + if (Sstar >= 0.0f) { + const float rhoLuL = WL[0] * uL; + const float v2 = WL[1] * WL[1] + WL[2] * WL[2] + WL[3] * WL[3]; + const float eL = + WL[4] * rhoLinv * hydro_one_over_gamma_minus_one + 0.5f * v2; + const float SL = SLmuL + uL; + /* flux FL */ - totflux[0] = WL[0] * uL; + totflux[0] = rhoLuL; /* these are the actual correct fluxes in the boosted lab frame (not rotated to interface frame) */ - totflux[1] = WL[0] * WL[1] * uL + WL[4] * n[0]; - totflux[2] = WL[0] * WL[2] * uL + WL[4] * n[1]; - totflux[3] = WL[0] * WL[3] * uL + WL[4] * n[2]; - const float v2 = WL[1] * WL[1] + WL[2] * WL[2] + WL[3] * WL[3]; - const float eL = WL[4] * hydro_one_over_gamma_minus_one / WL[0] + 0.5f * v2; - totflux[4] = WL[0] * eL * uL + WL[4] * uL; - if (SL < 0.f) { - - float UstarL[5]; - - /* add flux FstarL */ - UstarL[0] = 1.f; - /* we need UstarL in the lab frame: - * subtract the velocity in the interface frame from the lab frame - * velocity and then add Sstar in interface frame */ - UstarL[1] = WL[1] + (Sstar - uL) * n[0]; - UstarL[2] = WL[2] + (Sstar - uL) * n[1]; - UstarL[3] = WL[3] + (Sstar - uL) * n[2]; - UstarL[4] = eL + (Sstar - uL) * (Sstar + WL[4] / (WL[0] * (SL - uL))); - UstarL[0] *= WL[0] * (SL - uL) / (SL - Sstar); - UstarL[1] *= WL[0] * (SL - uL) / (SL - Sstar); - UstarL[2] *= WL[0] * (SL - uL) / (SL - Sstar); - UstarL[3] *= WL[0] * (SL - uL) / (SL - Sstar); - UstarL[4] *= WL[0] * (SL - uL) / (SL - Sstar); - totflux[0] += SL * (UstarL[0] - WL[0]); - totflux[1] += SL * (UstarL[1] - WL[0] * WL[1]); - totflux[2] += SL * (UstarL[2] - WL[0] * WL[2]); - totflux[3] += SL * (UstarL[3] - WL[0] * WL[3]); - totflux[4] += SL * (UstarL[4] - WL[0] * eL); + totflux[1] = rhoLuL * WL[1] + WL[4] * n[0]; + totflux[2] = rhoLuL * WL[2] + WL[4] * n[1]; + totflux[3] = rhoLuL * WL[3] + WL[4] * n[2]; + totflux[4] = rhoLuL * eL + WL[4] * uL; + + if (SL < 0.0f) { + + const float starfac = SLmuL / (SL - Sstar) - 1.0f; + const float rhoLSL = WL[0] * SL; + const float SstarmuL = Sstar - uL; + const float rhoLSLstarfac = rhoLSL * starfac; + const float rhoLSLSstarmuL = rhoLSL * SstarmuL; + + totflux[0] += rhoLSLstarfac; + totflux[1] += rhoLSLstarfac * WL[1] + rhoLSLSstarmuL * n[0]; + totflux[2] += rhoLSLstarfac * WL[2] + rhoLSLSstarmuL * n[1]; + totflux[3] += rhoLSLstarfac * WL[3] + rhoLSLSstarmuL * n[2]; + totflux[4] += rhoLSLstarfac * eL + + rhoLSLSstarmuL * (Sstar + WL[4] / (WL[0] * SLmuL)); } } else { - /* flux FR */ - totflux[0] = WR[0] * uR; - totflux[1] = WR[0] * WR[1] * uR + WR[4] * n[0]; - totflux[2] = WR[0] * WR[2] * uR + WR[4] * n[1]; - totflux[3] = WR[0] * WR[3] * uR + WR[4] * n[2]; + const float rhoRuR = WR[0] * uR; const float v2 = WR[1] * WR[1] + WR[2] * WR[2] + WR[3] * WR[3]; - const float eR = WR[4] * hydro_one_over_gamma_minus_one / WR[0] + 0.5f * v2; - totflux[4] = WR[0] * eR * uR + WR[4] * uR; - if (SR > 0.f) { + const float eR = + WR[4] * rhoRinv * hydro_one_over_gamma_minus_one + 0.5f * v2; + const float SR = SRmuR + uR; - float UstarR[5]; - - /* add flux FstarR */ - UstarR[0] = 1.f; - - /* we need UstarR in the lab frame: - * subtract the velocity in the interface frame from the lab frame - * velocity and then add Sstar in interface frame */ - UstarR[1] = WR[1] + (Sstar - uR) * n[0]; - UstarR[2] = WR[2] + (Sstar - uR) * n[1]; - UstarR[3] = WR[3] + (Sstar - uR) * n[2]; - UstarR[4] = eR + (Sstar - uR) * (Sstar + WR[4] / (WR[0] * (SR - uR))); - UstarR[0] *= WR[0] * (SR - uR) / (SR - Sstar); - UstarR[1] *= WR[0] * (SR - uR) / (SR - Sstar); - UstarR[2] *= WR[0] * (SR - uR) / (SR - Sstar); - UstarR[3] *= WR[0] * (SR - uR) / (SR - Sstar); - UstarR[4] *= WR[0] * (SR - uR) / (SR - Sstar); - totflux[0] += SR * (UstarR[0] - WR[0]); - totflux[1] += SR * (UstarR[1] - WR[0] * WR[1]); - totflux[2] += SR * (UstarR[2] - WR[0] * WR[2]); - totflux[3] += SR * (UstarR[3] - WR[0] * WR[3]); - totflux[4] += SR * (UstarR[4] - WR[0] * eR); + /* flux FR */ + totflux[0] = rhoRuR; + totflux[1] = rhoRuR * WR[1] + WR[4] * n[0]; + totflux[2] = rhoRuR * WR[2] + WR[4] * n[1]; + totflux[3] = rhoRuR * WR[3] + WR[4] * n[2]; + totflux[4] = rhoRuR * eR + WR[4] * uR; + + if (SR > 0.0f) { + + const float starfac = SRmuR / (SR - Sstar) - 1.0f; + const float rhoRSR = WR[0] * SR; + const float SstarmuR = Sstar - uR; + const float rhoRSRstarfac = rhoRSR * starfac; + const float rhoRSRSstarmuR = rhoRSR * SstarmuR; + + totflux[0] += rhoRSRstarfac; + totflux[1] += rhoRSRstarfac * WR[1] + rhoRSRSstarmuR * n[0]; + totflux[2] += rhoRSRstarfac * WR[2] + rhoRSRSstarmuR * n[1]; + totflux[3] += rhoRSRstarfac * WR[3] + rhoRSRSstarmuR * n[2]; + totflux[4] += rhoRSRstarfac * eR + + rhoRSRSstarmuR * (Sstar + WR[4] / (WR[0] * SRmuR)); } } @@ -194,11 +183,11 @@ riemann_solve_for_middle_state_flux(const float *WL, const float *WR, /* Handle pure vacuum */ if (!WL[0] && !WR[0]) { - totflux[0] = 0.f; - totflux[1] = 0.f; - totflux[2] = 0.f; - totflux[3] = 0.f; - totflux[4] = 0.f; + totflux[0] = 0.0f; + totflux[1] = 0.0f; + totflux[2] = 0.0f; + totflux[3] = 0.0f; + totflux[4] = 0.0f; return; } @@ -210,37 +199,38 @@ riemann_solve_for_middle_state_flux(const float *WL, const float *WR, /* Handle vacuum: vacuum does not require iteration and is always exact */ if (riemann_is_vacuum(WL, WR, uL, uR, aL, aR)) { - totflux[0] = 0.f; - totflux[1] = 0.f; - totflux[2] = 0.f; - totflux[3] = 0.f; - totflux[4] = 0.f; + totflux[0] = 0.0f; + totflux[1] = 0.0f; + totflux[2] = 0.0f; + totflux[3] = 0.0f; + totflux[4] = 0.0f; return; } /* STEP 1: pressure estimate */ - const float rhobar = 0.5f * (WL[0] + WR[0]); - const float abar = 0.5f * (aL + aR); - const float pPVRS = 0.5f * (WL[4] + WR[4]) - 0.5f * (uR - uL) * rhobar * abar; + const float rhobar = WL[0] + WR[0]; + const float abar = aL + aR; + const float pPVRS = + 0.5f * ((WL[4] + WR[4]) - 0.25f * (uR - uL) * rhobar * abar); const float pstar = max(0.f, pPVRS); /* STEP 2: wave speed estimates all these speeds are along the interface normal, since uL and uR are */ - float qL = 1.f; - if (pstar > WL[4] && WL[4] > 0.f) { - qL = sqrtf(1.f + 0.5f * hydro_gamma_plus_one * hydro_one_over_gamma * - (pstar / WL[4] - 1.f)); + float qL = 1.0f; + if (pstar > WL[4] && WL[4] > 0.0f) { + qL = sqrtf(1.0f + 0.5f * hydro_gamma_plus_one * hydro_one_over_gamma * + (pstar / WL[4] - 1.0f)); } - float qR = 1.f; - if (pstar > WR[4] && WR[4] > 0.f) { - qR = sqrtf(1.f + 0.5f * hydro_gamma_plus_one * hydro_one_over_gamma * - (pstar / WR[4] - 1.f)); + float qR = 1.0f; + if (pstar > WR[4] && WR[4] > 0.0f) { + qR = sqrtf(1.0f + 0.5f * hydro_gamma_plus_one * hydro_one_over_gamma * + (pstar / WR[4] - 1.0f)); } - const float SL = uL - aL * qL; - const float SR = uR + aR * qR; + const float SLmuL = -aL * qL; + const float SRmuR = aR * qR; const float Sstar = - (WR[4] - WL[4] + WL[0] * uL * (SL - uL) - WR[0] * uR * (SR - uR)) / - (WL[0] * (SL - uL) - WR[0] * (SR - uR)); + (WR[4] - WL[4] + WL[0] * uL * SLmuL - WR[0] * uR * SRmuR) / + (WL[0] * SLmuL - WR[0] * SRmuR); totflux[0] = 0.0f; totflux[1] = pstar * n[0]; diff --git a/src/runner.c b/src/runner.c index 187e601315555fa44f686cd212365694a2e505ff..60c2999b9a3dcc3907eeea17406401f3f56e5f7f 100644 --- a/src/runner.c +++ b/src/runner.c @@ -766,6 +766,7 @@ void runner_do_ghost(struct runner *r, struct cell *c, int timer) { /* Double h and try again */ h_new = 2.f * h_old; + } else { /* Finish the density calculation */ @@ -780,6 +781,46 @@ void runner_do_ghost(struct runner *r, struct cell *c, int timer) { p->density.wcount_dh * h_old_dim + hydro_dimension * p->density.wcount * h_old_dim_minus_one; + /* Skip if h is already h_max and we don't have enough neighbours */ + if ((p->h >= hydro_h_max) && (f < 0.f)) { + + /* We have a particle whose smoothing length is already set (wants to + * be larger but has already hit the maximum). So, just tidy up as if + * the smoothing length had converged correctly */ + +#ifdef EXTRA_HYDRO_LOOP + + /* As of here, particle gradient variables will be set. */ + /* The force variables are set in the extra ghost. */ + + /* Compute variables required for the gradient loop */ + hydro_prepare_gradient(p, xp, cosmo); + + /* The particle gradient values are now set. Do _NOT_ + try to read any particle density variables! */ + + /* Prepare the particle for the gradient loop over neighbours */ + hydro_reset_gradient(p); + +#else + /* As of here, particle force variables will be set. */ + + /* Compute variables required for the force loop */ + hydro_prepare_force(p, xp, cosmo); + + /* The particle force values are now set. Do _NOT_ + try to read any particle density variables! */ + + /* Prepare the particle for the force loop over neighbours */ + hydro_reset_acceleration(p); + +#endif /* EXTRA_HYDRO_LOOP */ + + continue; + } + + /* Normal case: Use Newton-Raphson to get a better value of h */ + /* Avoid floating point exception from f_prime = 0 */ h_new = h_old - f / (f_prime + FLT_MIN); @@ -1101,7 +1142,7 @@ void runner_do_kick1(struct runner *r, struct cell *c, int timer) { #endif /* Time interval for this half-kick */ - double dt_kick_grav, dt_kick_hydro, dt_kick_therm; + double dt_kick_grav, dt_kick_hydro, dt_kick_therm, dt_kick_corr; if (with_cosmology) { dt_kick_hydro = cosmology_get_hydro_kick_factor( cosmo, ti_begin, ti_begin + ti_step / 2); @@ -1109,15 +1150,19 @@ void runner_do_kick1(struct runner *r, struct cell *c, int timer) { ti_begin + ti_step / 2); dt_kick_therm = cosmology_get_therm_kick_factor( cosmo, ti_begin, ti_begin + ti_step / 2); + dt_kick_corr = cosmology_get_corr_kick_factor(cosmo, ti_begin, + ti_begin + ti_step / 2); } else { dt_kick_hydro = (ti_step / 2) * time_base; dt_kick_grav = (ti_step / 2) * time_base; dt_kick_therm = (ti_step / 2) * time_base; + dt_kick_corr = (ti_step / 2) * time_base; } /* do the kick */ - kick_part(p, xp, dt_kick_hydro, dt_kick_grav, dt_kick_therm, cosmo, - hydro_props, ti_begin, ti_begin + ti_step / 2); + kick_part(p, xp, dt_kick_hydro, dt_kick_grav, dt_kick_therm, + dt_kick_corr, cosmo, hydro_props, ti_begin, + ti_begin + ti_step / 2); /* Update the accelerations to be used in the drift for hydro */ if (p->gpart != NULL) { @@ -1267,7 +1312,7 @@ void runner_do_kick2(struct runner *r, struct cell *c, int timer) { ti_begin, ti_step, p->time_bin, ti_current); #endif /* Time interval for this half-kick */ - double dt_kick_grav, dt_kick_hydro, dt_kick_therm; + double dt_kick_grav, dt_kick_hydro, dt_kick_therm, dt_kick_corr; if (with_cosmology) { dt_kick_hydro = cosmology_get_hydro_kick_factor( cosmo, ti_begin + ti_step / 2, ti_begin + ti_step); @@ -1275,15 +1320,19 @@ void runner_do_kick2(struct runner *r, struct cell *c, int timer) { cosmo, ti_begin + ti_step / 2, ti_begin + ti_step); dt_kick_therm = cosmology_get_therm_kick_factor( cosmo, ti_begin + ti_step / 2, ti_begin + ti_step); + dt_kick_corr = cosmology_get_corr_kick_factor( + cosmo, ti_begin + ti_step / 2, ti_begin + ti_step); } else { dt_kick_hydro = (ti_step / 2) * time_base; dt_kick_grav = (ti_step / 2) * time_base; dt_kick_therm = (ti_step / 2) * time_base; + dt_kick_corr = (ti_step / 2) * time_base; } /* Finish the time-step with a second half-kick */ - kick_part(p, xp, dt_kick_hydro, dt_kick_grav, dt_kick_therm, cosmo, - hydro_props, ti_begin + ti_step / 2, ti_begin + ti_step); + kick_part(p, xp, dt_kick_hydro, dt_kick_grav, dt_kick_therm, + dt_kick_corr, cosmo, hydro_props, ti_begin + ti_step / 2, + ti_begin + ti_step); #ifdef SWIFT_DEBUG_CHECKS /* Check that kick and the drift are synchronized */ diff --git a/src/runner_doiact_grav.h b/src/runner_doiact_grav.h index dcc3265f34e405a1a414085851ce8d30b9cd3d3d..812a6e3850fa66f614326c872511c36ba91b5635 100644 --- a/src/runner_doiact_grav.h +++ b/src/runner_doiact_grav.h @@ -1529,7 +1529,6 @@ static INLINE void runner_do_grav_long_range(struct runner *r, struct cell *ci, /* Flag that contributions will be recieved */ struct gravity_tensors *const multi_i = ci->multipole; - multi_i->pot.interacted = 1; /* Recover the top-level multipole (for distance checks) */ struct gravity_tensors *const multi_top = top->multipole; @@ -1585,6 +1584,9 @@ static INLINE void runner_do_grav_long_range(struct runner *r, struct cell *ci, runner_dopair_grav_mm(r, ci, cj); // runner_dopair_recursive_grav_pm(r, ci, cj); + /* Record that this multipole received a contribution */ + multi_i->pot.interacted = 1; + } /* We are in charge of this pair */ } /* Loop over top-level cells */ diff --git a/src/serial_io.c b/src/serial_io.c index dafa75ab0baacb1b5ddeee34020c9773893bced7..3a7d2e5a68873ca9523fe09bbf19fb2e185482dd 100644 --- a/src/serial_io.c +++ b/src/serial_io.c @@ -759,10 +759,11 @@ void write_output_serial(struct engine* e, const char* baseName, char fileName[FILENAME_BUFFER_SIZE]; if (e->snapshot_label_delta == 1) snprintf(fileName, FILENAME_BUFFER_SIZE, "%s_%04i.hdf5", baseName, - e->snapshot_output_count); + e->snapshot_output_count + e->snapshot_label_first); else snprintf(fileName, FILENAME_BUFFER_SIZE, "%s_%06i.hdf5", baseName, - e->snapshot_output_count * e->snapshot_label_delta); + e->snapshot_output_count * e->snapshot_label_delta + + e->snapshot_label_first); /* Compute offset in the file and total number of particles */ size_t N[swift_type_count] = {Ngas, Ndm, 0, 0, Nstars, 0}; diff --git a/src/single_io.c b/src/single_io.c index a0f02878b52c89beca94d15c09ef7d456ce0a4eb..8cbb6743d38a022581273a0a0b03c9b3b6fda32e 100644 --- a/src/single_io.c +++ b/src/single_io.c @@ -625,10 +625,11 @@ void write_output_single(struct engine* e, const char* baseName, char fileName[FILENAME_BUFFER_SIZE]; if (e->snapshot_label_delta == 1) snprintf(fileName, FILENAME_BUFFER_SIZE, "%s_%04i.hdf5", baseName, - e->snapshot_output_count); + e->snapshot_output_count + e->snapshot_label_first); else snprintf(fileName, FILENAME_BUFFER_SIZE, "%s_%06i.hdf5", baseName, - e->snapshot_output_count * e->snapshot_label_delta); + e->snapshot_output_count * e->snapshot_label_delta + + e->snapshot_label_first); /* First time, we need to create the XMF file */ if (e->snapshot_output_count == 0) xmf_create_file(baseName); diff --git a/tests/Makefile.am b/tests/Makefile.am index 2744164e2c794ef4471a51ffb66db3049d9fa048..ae234581228b2ea6035af845292e9cc22d6bcaa8 100644 --- a/tests/Makefile.am +++ b/tests/Makefile.am @@ -28,7 +28,7 @@ TESTS = testGreetings testMaths testReading.sh testSingle testKernel testSymmetr testVoronoi1D testVoronoi2D testVoronoi3D testGravityDerivatives \ testPeriodicBC.sh testPeriodicBCPerturbed.sh testPotentialSelf \ testPotentialPair testEOS testUtilities testSelectOutput.sh \ - testCbrt testCosmology + testCbrt testCosmology testOutputList # List of test programs to compile check_PROGRAMS = testGreetings testReading testSingle testTimeIntegration \ @@ -39,7 +39,7 @@ check_PROGRAMS = testGreetings testReading testSingle testTimeIntegration \ testRiemannHLLC testMatrixInversion testDump testLogger \ testVoronoi1D testVoronoi2D testVoronoi3D testPeriodicBC \ testGravityDerivatives testPotentialSelf testPotentialPair testEOS testUtilities \ - testSelectOutput testCbrt testCosmology + testSelectOutput testCbrt testCosmology testOutputList # Rebuild tests when SWIFT is updated. $(check_PROGRAMS): ../src/.libs/libswiftsim.a @@ -55,6 +55,8 @@ testSelectOutput_SOURCES = testSelectOutput.c testCosmology_SOURCES = testCosmology.c +testOutputList_SOURCES = testOutputList.c + testSymmetry_SOURCES = testSymmetry.c # Added because of issues using memcmp on clang 4.x @@ -126,4 +128,6 @@ EXTRA_DIST = testReading.sh makeInput.py testActivePair.sh \ tolerance_27_normal.dat tolerance_27_perturbed.dat tolerance_27_perturbed_h.dat tolerance_27_perturbed_h2.dat \ tolerance_testInteractions.dat tolerance_pair_active.dat tolerance_pair_force_active.dat \ fft_params.yml tolerance_periodic_BC_normal.dat tolerance_periodic_BC_perturbed.dat \ - testEOS.sh testEOS_plot.sh testSelectOutput.sh selectOutput.yml + testEOS.sh testEOS_plot.sh testSelectOutput.sh selectOutput.yml \ + output_list_params.yml output_list_time.txt output_list_redshift.txt \ + output_list_scale_factor.txt diff --git a/tests/output_list_params.yml b/tests/output_list_params.yml new file mode 100644 index 0000000000000000000000000000000000000000..2aad7573351f6c8fb3f45fc78be3a1a326f23310 --- /dev/null +++ b/tests/output_list_params.yml @@ -0,0 +1,28 @@ +# Cosmological parameters +Cosmology: + h: 0.6777 # Reduced Hubble constant + a_begin: 1e-2 # Initial scale-factor of the simulation + a_end: 1.0 # Final scale factor of the simulation + Omega_m: 0.307 # Matter density parameter + Omega_lambda: 0.693 # Dark-energy density parameter + Omega_b: 0.0455 # Baryon density parameter + +# Define the system of units to use internally. +Units: + UnitMass_in_cgs: 1.48e43 # 10^10 M_sun in grams + UnitLength_in_cgs: 3.08e21 # kpc in centimeters + UnitVelocity_in_cgs: 1e5 # km/s in centimeters per second + UnitCurrent_in_cgs: 1 # Amperes + UnitTemp_in_cgs: 1 # Kelvin + +Redshift: + output_list_on: 1 # (Optional) Enable the output list + output_list: output_list_redshift.txt # (Optional) File containing the output times (see documentation in "Parameter File" section) + +Time: + output_list_on: 1 # (Optional) Enable the output list + output_list: output_list_time.txt # (Optional) File containing the output times (see documentation in "Parameter File" section) + +ScaleFactor: + output_list_on: 1 # (Optional) Enable the output list + output_list: output_list_scale_factor.txt # (Optional) File containing the output times (see documentation in "Parameter File" section) diff --git a/tests/output_list_redshift.txt b/tests/output_list_redshift.txt new file mode 100644 index 0000000000000000000000000000000000000000..311648ebf5fc8199d97bf49f0d9686b28726688c --- /dev/null +++ b/tests/output_list_redshift.txt @@ -0,0 +1,4 @@ +# Redshift +99 +9 +1 diff --git a/tests/output_list_scale_factor.txt b/tests/output_list_scale_factor.txt new file mode 100644 index 0000000000000000000000000000000000000000..94ca1aa88660fb0f6cd6cbcb37a16ae19be69056 --- /dev/null +++ b/tests/output_list_scale_factor.txt @@ -0,0 +1,4 @@ +# Scale Factor +0.01 +0.1 +0.5 diff --git a/tests/output_list_time.txt b/tests/output_list_time.txt new file mode 100644 index 0000000000000000000000000000000000000000..887087651a5c978e4cbdeeedb283918ad770f9be --- /dev/null +++ b/tests/output_list_time.txt @@ -0,0 +1,4 @@ +# Time +0. +10. +12. diff --git a/tests/test125cells.c b/tests/test125cells.c index 70af9dfb19aeee812fdc90733a604f795b7f478f..2a2c20dbb064539b481e169b49b74389e79a8174 100644 --- a/tests/test125cells.c +++ b/tests/test125cells.c @@ -120,7 +120,7 @@ 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) || defined(HOPKINS_PU_SPH) part->u = pressure / (hydro_gamma_minus_one * density); -#elif defined(MINIMAL_MULTI_MAT_SPH) +#elif defined(PLANETARY_SPH) part->u = pressure / (hydro_gamma_minus_one * density); #elif defined(GIZMO_MFV_SPH) || defined(SHADOWFAX_SPH) part->primitives.P = pressure; @@ -407,8 +407,8 @@ void dump_particle_fields(char *fileName, struct cell *main_cell, main_cell->parts[pid].v[0], main_cell->parts[pid].v[1], main_cell->parts[pid].v[2], main_cell->parts[pid].h, hydro_get_comoving_density(&main_cell->parts[pid]), -#if defined(MINIMAL_SPH) || defined(MINIMAL_MULTI_MAT_SPH) || \ - defined(GIZMO_MFV_SPH) || defined(SHADOWFAX_SPH) || \ +#if defined(MINIMAL_SPH) || defined(PLANETARY_SPH) || \ + defined(GIZMO_MFV_SPH) || defined(SHADOWFAX_SPH) || \ defined(HOPKINS_PU_SPH) 0.f, #else diff --git a/tests/testCosmology.c b/tests/testCosmology.c index 698351ad952e7d0b5f7d8e354c45a1a2dd53f968..bafad55471453f7308d1498daa15dbae3a76a6bc 100644 --- a/tests/testCosmology.c +++ b/tests/testCosmology.c @@ -24,7 +24,7 @@ #include "swift.h" #define N_CHECK 20 -#define TOLERANCE 1e-3 +#define TOLERANCE 1e-7 void test_params_init(struct swift_params *params) { parser_init("", params); @@ -72,5 +72,6 @@ int main(int argc, char *argv[]) { message("Everything seems fine with cosmology."); + cosmology_clean(&cosmo); return 0; } diff --git a/tests/testEOS.c b/tests/testEOS.c index d090d83d77a16b2c5b4506c5f9224b3e4434d1be..4a1e666b47acc55a5ed7f1800e7199a1abb5e821 100644 --- a/tests/testEOS.c +++ b/tests/testEOS.c @@ -74,6 +74,11 @@ * P_1_0 ... ... P_1_num_u * ... ... ... ... * P_num_rho_0 ... P_num_rho_num_u + * c_0_0 c_0_1 ... c_0_num_u # Array of sound speeds, c(rho, + * u) + * c_1_0 ... ... c_1_num_u + * ... ... ... ... + * c_num_rho_0 ... c_num_rho_num_u * * Note that the values tested extend beyond the range that most EOS are * designed for (e.g. outside table limits), to help test the EOS in case of @@ -83,21 +88,24 @@ #ifdef EOS_PLANETARY int main(int argc, char *argv[]) { - float rho, log_rho, log_u, P; + float rho, u, log_rho, log_u, P, c; struct unit_system us; + struct swift_params *params = + (struct swift_params *)malloc(sizeof(struct swift_params)); + if (params == NULL) error("Error allocating memory for the parameter file."); const struct phys_const *phys_const = 0; // Unused placeholder - struct swift_params *params = 0; // Unused placeholder const float J_kg_to_erg_g = 1e4; // Convert J/kg to erg/g char filename[64]; // Output table params const int num_rho = 100, num_u = 100; - float log_rho_min = logf(1e-4), log_rho_max = logf(30.f), - log_u_min = logf(1e4), log_u_max = logf(1e10), - log_rho_step = (log_rho_max - log_rho_min) / (num_rho - 1.f), + float log_rho_min = logf(1e-4f), log_rho_max = logf(1e3f), // Densities (cgs) + log_u_min = logf(1e4f), + log_u_max = logf(1e13f), // Sp. int. energies (SI) + log_rho_step = (log_rho_max - log_rho_min) / (num_rho - 1.f), log_u_step = (log_u_max - log_u_min) / (num_u - 1.f); float A1_rho[num_rho], A1_u[num_u]; // Sys args - int mat_id, do_output; + int mat_id_in, do_output; // Default sys args const int mat_id_def = eos_planetary_id_HM80_ice; const int do_output_def = 0; @@ -106,34 +114,40 @@ int main(int argc, char *argv[]) { switch (argc) { case 1: // Default both - mat_id = mat_id_def; + mat_id_in = mat_id_def; do_output = do_output_def; break; case 2: // Read mat_id, default do_output - mat_id = atoi(argv[1]); + mat_id_in = atoi(argv[1]); do_output = do_output_def; break; case 3: // Read both - mat_id = atoi(argv[1]); + mat_id_in = atoi(argv[1]); do_output = atoi(argv[2]); break; default: error("Invalid number of system arguments!\n"); - mat_id = mat_id_def; // Ignored, just here to keep the compiler happy + mat_id_in = mat_id_def; // Ignored, just here to keep the compiler happy do_output = do_output_def; }; + enum eos_planetary_material_id mat_id = + (enum eos_planetary_material_id)mat_id_in; + /* Greeting message */ printf("This is %s\n", package_description()); // Check material ID - // Material base type - switch ((int)(mat_id / eos_planetary_type_factor)) { + const enum eos_planetary_type_id type = + (enum eos_planetary_type_id)(mat_id / eos_planetary_type_factor); + + // Select the material base type + switch (type) { // Tillotson case eos_planetary_type_Til: switch (mat_id) { @@ -174,27 +188,23 @@ int main(int argc, char *argv[]) { }; break; - // ANEOS - case eos_planetary_type_ANEOS: + // SESAME + case eos_planetary_type_SESAME: switch (mat_id) { - case eos_planetary_id_ANEOS_iron: - printf(" ANEOS iron \n"); + case eos_planetary_id_SESAME_iron: + printf(" SESAME basalt 7530 \n"); break; - case eos_planetary_id_MANEOS_forsterite: - printf(" MANEOS forsterite \n"); + case eos_planetary_id_SESAME_basalt: + printf(" SESAME basalt 7530 \n"); break; - default: - error("Unknown material ID! mat_id = %d \n", mat_id); - }; - break; + case eos_planetary_id_SESAME_water: + printf(" SESAME water 7154 \n"); + break; - // SESAME - case eos_planetary_type_SESAME: - switch (mat_id) { - case eos_planetary_id_SESAME_iron: - printf(" SESAME iron \n"); + case eos_planetary_id_SS08_water: + printf(" Senft & Stewart (2008) SESAME-like water \n"); break; default: @@ -206,8 +216,11 @@ int main(int argc, char *argv[]) { error("Unknown material type! mat_id = %d \n", mat_id); } - // Convert to internal units (Earth masses and radii) - units_init(&us, 5.9724e27, 6.3710e8, 1.f, 1.f, 1.f); + // Convert to internal units + // Earth masses and radii + // units_init(&us, 5.9724e27, 6.3710e8, 1.f, 1.f, 1.f); + // SI + units_init(&us, 1000.f, 100.f, 1.f, 1.f, 1.f); log_rho_min -= logf(units_cgs_conversion_factor(&us, UNIT_CONV_DENSITY)); log_rho_max -= logf(units_cgs_conversion_factor(&us, UNIT_CONV_DENSITY)); log_u_min += logf(J_kg_to_erg_g / units_cgs_conversion_factor( @@ -215,11 +228,51 @@ int main(int argc, char *argv[]) { log_u_max += logf(J_kg_to_erg_g / units_cgs_conversion_factor( &us, UNIT_CONV_ENERGY_PER_UNIT_MASS)); + // Set the input parameters + // Which EOS to initialise + parser_set_param(params, "EoS:planetary_use_Til:1"); + parser_set_param(params, "EoS:planetary_use_HM80:1"); + parser_set_param(params, "EoS:planetary_use_SESAME:1"); + // Table file names + parser_set_param(params, + "EoS:planetary_HM80_HHe_table_file:" + "../examples/planetary_HM80_HHe.txt"); + parser_set_param(params, + "EoS:planetary_HM80_ice_table_file:" + "../examples/planetary_HM80_ice.txt"); + parser_set_param(params, + "EoS:planetary_HM80_rock_table_file:" + "../examples/planetary_HM80_rock.txt"); + parser_set_param(params, + "EoS:planetary_SESAME_iron_table_file:" + "../examples/planetary_SESAME_iron_2140.txt"); + parser_set_param(params, + "EoS:planetary_SESAME_basalt_table_file:" + "../examples/planetary_SESAME_basalt_7530.txt"); + parser_set_param(params, + "EoS:planetary_SESAME_water_table_file:" + "../examples/planetary_SESAME_water_7154.txt"); + parser_set_param(params, + "EoS:planetary_SS08_water_table_file:" + "../examples/planetary_SS08_water.txt"); + // Initialise the EOS materials eos_init(&eos, phys_const, &us, params); + // Manual debug testing + if (1) { + printf("\n ### MANUAL DEBUG TESTING ### \n"); + + rho = 5960; + u = 1.7e8; + P = gas_pressure_from_internal_energy(rho, u, eos_planetary_id_HM80_ice); + printf("u = %.2e, rho = %.2e, P = %.2e \n", u, rho, P); + + return 0; + } + // Output file - sprintf(filename, "testEOS_rho_u_P_%d.txt", mat_id); + sprintf(filename, "testEOS_rho_u_P_c_%d.txt", mat_id); FILE *f = fopen(filename, "w"); if (f == NULL) { printf("Could not open output file!\n"); @@ -270,6 +323,21 @@ int main(int argc, char *argv[]) { if (do_output == 1) fprintf(f, "\n"); } + + // Sound speeds + for (int i = 0; i < num_rho; i++) { + rho = A1_rho[i]; + + for (int j = 0; j < num_u; j++) { + c = gas_soundspeed_from_internal_energy(rho, A1_u[j], mat_id); + + if (do_output == 1) + fprintf(f, "%.6e ", + c * units_cgs_conversion_factor(&us, UNIT_CONV_SPEED)); + } + + if (do_output == 1) fprintf(f, "\n"); + } fclose(f); return 0; diff --git a/tests/testEOS.py b/tests/testEOS.py index 363bab200b58c65fa24cc033af4b8d3c04b7b503..a2a31a248a2073a834d9543b706a6a12ba12796c 100644 --- a/tests/testEOS.py +++ b/tests/testEOS.py @@ -18,8 +18,8 @@ # ############################################################################## """ -Plot the output of testEOS to show how the equation of state pressure varies -with density and specific internal energy. +Plot the output of testEOS to show how the equation of state pressure and sound +speed varies with density and specific internal energy. Usage: python testEOS.py (mat_id) @@ -37,9 +37,13 @@ Text file contains: P_1_0 ... ... P_1_num_u ... ... ... ... P_num_rho_0 ... P_num_rho_num_u + c_0_0 c_0_1 ... c_0_num_u # Array of sound speeds, c(rho, u) + c_1_0 ... ... c_1_num_u + ... ... ... ... + c_num_rho_0 ... c_num_rho_num_u Note that the values tested extend beyond the range that most EOS are -designed for (e.g. outside table limits), to help test the EOS in case of +designed for (e.g. outside table limits), to help test the EOS in cases of unexpected particle behaviour. """ @@ -58,8 +62,7 @@ type_factor = 100 Di_type = { 'Til' : 1, 'HM80' : 2, - 'ANEOS' : 3, - 'SESAME' : 4, + 'SESAME' : 3, } Di_material = { # Tillotson @@ -70,11 +73,11 @@ Di_material = { 'HM80_HHe' : Di_type['HM80']*type_factor, # Hydrogen-helium atmosphere 'HM80_ice' : Di_type['HM80']*type_factor + 1, # H20-CH4-NH3 ice mix 'HM80_rock' : Di_type['HM80']*type_factor + 2, # SiO2-MgO-FeS-FeO rock mix - # ANEOS - 'ANEOS_iron' : Di_type['ANEOS']*type_factor, - 'MANEOS_forsterite' : Di_type['ANEOS']*type_factor + 1, # SESAME - 'SESAME_iron' : Di_type['SESAME']*type_factor, + 'SESAME_iron' : Di_type['SESAME']*type_factor, # 2140 + 'SESAME_basalt' : Di_type['SESAME']*type_factor + 1, # 7530 + 'SESAME_water' : Di_type['SESAME']*type_factor + 2, # 7154 + 'SS08_water' : Di_type['SESAME']*type_factor + 3, # Senft & Stewart (2008) } # Invert so the mat_id are the keys Di_mat_id = {mat_id : mat for mat, mat_id in Di_material.iteritems()} @@ -82,6 +85,7 @@ Di_mat_id = {mat_id : mat for mat, mat_id in Di_material.iteritems()} # Unit conversion Ba_to_Mbar = 1e-12 erg_g_to_J_kg = 1e-4 +cm_s_to_m_s = 1e-2 if __name__ == '__main__': # Sys args @@ -101,7 +105,7 @@ if __name__ == '__main__': for mat_id, mat in sorted(Di_mat_id.iteritems()): print " %s%s%d" % (mat, (20 - len("%s" % mat))*" ", mat_id) - filename = "testEOS_rho_u_P_%d.txt" % mat_id + filename = "testEOS_rho_u_P_c_%d.txt" % mat_id # Load the header info and density and energy arrays with open(filename) as f: @@ -110,31 +114,37 @@ if __name__ == '__main__': A1_rho = np.array(f.readline().split(), dtype=float) A1_u = np.array(f.readline().split(), dtype=float) - # Load pressure array + # Load pressure and soundspeed arrays A2_P = np.loadtxt(filename, skiprows=4) + A2_c = A2_P[num_rho:] + A2_P = A2_P[:num_rho] - # Convert pressures from cgs Barye to Mbar - A2_P *= Ba_to_Mbar # Convert energies from cgs to SI A1_u *= erg_g_to_J_kg + # Convert pressures from cgs (Barye) to Mbar + A2_P *= Ba_to_Mbar + # Convert sound speeds from cgs to SI + A1_u *= cm_s_to_m_s # Check that the numbers are right assert A1_rho.shape == (num_rho,) assert A1_u.shape == (num_u,) assert A2_P.shape == (num_rho, num_u) + assert A2_c.shape == (num_rho, num_u) # Plot + # Pressure: P(rho) at fixed u plt.figure(figsize=(7, 7)) ax = plt.gca() - # P(rho) at fixed u - num_u_fix = 9 - A1_idx = np.floor(np.linspace(0, num_u - 1, num_u_fix)).astype(int) - A1_colour = matplotlib.cm.rainbow(np.linspace(0, 1, num_u_fix)) + A1_colour = matplotlib.cm.rainbow(np.linspace(0, 1, num_u)) - for i, idx in enumerate(A1_idx): - plt.plot(A1_rho, A2_P[:, idx], c=A1_colour[i], - label=r"%.2e" % A1_u[idx]) + for i_u, u in enumerate(A1_u): + if i_u%10 == 0: + plt.plot(A1_rho, A2_P[:, i_u], c=A1_colour[i_u], + label=r"%.2e" % u) + else: + plt.plot(A1_rho, A2_P[:, i_u], c=A1_colour[i_u]) plt.legend(title="Sp. Int. Energy (J kg$^{-1}$)") plt.xscale('log') @@ -144,7 +154,31 @@ if __name__ == '__main__': plt.title(mat) plt.tight_layout() - plt.savefig("testEOS_%d.png" % mat_id) + plt.savefig("testEOS_P_%d.png" % mat_id) + plt.close() + + # Sound speed: c(rho) at fixed u + plt.figure(figsize=(7, 7)) + ax = plt.gca() + + A1_colour = matplotlib.cm.rainbow(np.linspace(0, 1, num_u)) + + for i_u, u in enumerate(A1_u): + if i_u%10 == 0: + plt.plot(A1_rho, A2_c[:, i_u], c=A1_colour[i_u], + label=r"%.2e" % u) + else: + plt.plot(A1_rho, A2_c[:, i_u], c=A1_colour[i_u]) + + plt.legend(title="Sp. Int. Energy (J kg$^{-1}$)") + plt.xscale('log') + plt.yscale('log') + plt.xlabel(r"Density (g cm$^{-3}$)") + plt.ylabel(r"Sound Speed (m s^{-1})") + plt.title(mat) + plt.tight_layout() + + plt.savefig("testEOS_c_%d.png" % mat_id) plt.close() diff --git a/tests/testEOS.sh b/tests/testEOS.sh index 411ac746be186bfe5758e03c2a852e081daefd10..bcd87eabbf15a962808843dda76d1829f2917c97 100755 --- a/tests/testEOS.sh +++ b/tests/testEOS.sh @@ -13,6 +13,10 @@ A1_mat_id=( 200 201 202 + 300 + 301 + 302 + 303 ) for mat_id in "${A1_mat_id[@]}" diff --git a/tests/testEOS_plot.sh b/tests/testEOS_plot.sh index 39108c5e19d8f4474de508e205951a1fd0aebcc9..5fd7f4976496223e467aae65b2846a8c4e1b7485 100755 --- a/tests/testEOS_plot.sh +++ b/tests/testEOS_plot.sh @@ -2,6 +2,8 @@ echo "" +rm -f testEOS*.png + echo "Plotting testEOS output for each planetary material" A1_mat_id=( @@ -11,6 +13,10 @@ A1_mat_id=( 200 201 202 + 300 + 301 + 302 + 303 ) for mat_id in "${A1_mat_id[@]}" diff --git a/tests/testInteractions.c b/tests/testInteractions.c index 0a7354f0d2a5e1853ba2c22d696dbb910de2b667..306f14a35ca047430f67e33e9fd63848e9207b68 100644 --- a/tests/testInteractions.c +++ b/tests/testInteractions.c @@ -107,8 +107,8 @@ struct part *make_particles(size_t count, double *offset, double spacing, */ void prepare_force(struct part *parts, size_t count) { -#if !defined(GIZMO_MFV_SPH) && !defined(SHADOWFAX_SPH) && \ - !defined(MINIMAL_SPH) && !defined(MINIMAL_MULTI_MAT_SPH) && \ +#if !defined(GIZMO_MFV_SPH) && !defined(SHADOWFAX_SPH) && \ + !defined(MINIMAL_SPH) && !defined(PLANETARY_SPH) && \ !defined(HOPKINS_PU_SPH) struct part *p; for (size_t i = 0; i < count; ++i) { @@ -136,8 +136,7 @@ void dump_indv_particle_fields(char *fileName, struct part *p) { "%8.5f %8.5f %13e %13e %13e %13e %13e %8.5f %8.5f\n", p->id, p->x[0], p->x[1], p->x[2], p->v[0], p->v[1], p->v[2], p->h, hydro_get_comoving_density(p), -#if defined(MINIMAL_SPH) || defined(MINIMAL_MULTI_MAT_SPH) || \ - defined(SHADOWFAX_SPH) +#if defined(MINIMAL_SPH) || defined(PLANETARY_SPH) || defined(SHADOWFAX_SPH) 0.f, #else p->density.div_v, diff --git a/tests/testOutputList.c b/tests/testOutputList.c new file mode 100644 index 0000000000000000000000000000000000000000..b7df197405ee095cf9bf0a63e8cf7f00585f269f --- /dev/null +++ b/tests/testOutputList.c @@ -0,0 +1,157 @@ +/******************************************************************************* + * This file is part of SWIFT. + * Copyright (C) 2016 James Willis (james.s.willis@durham.ac.uk). + * 2018 Peter W. Draper (p.w.draper@durham.ac.uk) + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published + * by the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this program. If not, see <http://www.gnu.org/licenses/>. + * + ******************************************************************************/ + +#include <math.h> +#include <stdio.h> +#include <string.h> +#include "swift.h" + +#define Ntest 3 +#define tol 1e-12 +#define filename "output_list_params.yml" + +/* Expected values from file */ +const double time_values[Ntest] = { + 0., + 10., + 12., +}; + +/* Expected values from file */ +const double a_values[Ntest] = { + 0.5, + 0.1, + 0.01, +}; + +void test_no_cosmo(struct engine *e, char *name, int with_assert) { + message("Testing output time for %s without cosmology", name); + + struct output_list *list; + double delta_time = 0; + double output_time = 0; + + /* Test Time */ + e->time_begin = 0; + e->time_end = 14; + e->time_base = (e->time_end - e->time_begin) / max_nr_timesteps; + e->ti_current = 0; + e->policy = !engine_policy_cosmology; + + /* initialize output_list */ + output_list_init(&list, e, name, &delta_time, &output_time); + output_list_print(list); + + for (int i = 0; i < Ntest; i++) { + /* Test last value */ + if (with_assert) { + assert(abs(output_time - time_values[i]) < tol); + } + + /* Set current time */ + e->ti_current = (output_time - e->time_begin) / e->time_base; + e->ti_current += 1; + + /* Read next value */ + integertime_t ti_next; + output_list_read_next_time(list, e, name, &ti_next); + + output_time = (double)(ti_next * e->time_base) + e->time_begin; + } + + output_list_clean(list); +}; + +void test_cosmo(struct engine *e, char *name, int with_assert) { + message("Testing output time for %s with cosmology", name); + + struct output_list *list; + double delta_time = 0; + double output_time = 0; + + /* Test Time */ + e->time_base = log(e->time_end / e->cosmology->a_begin) / max_nr_timesteps; + e->ti_current = 0; + e->policy = engine_policy_cosmology; + + /* initialize output_list */ + output_list_init(&list, e, name, &delta_time, &output_time); + output_list_print(list); + + for (int i = 0; i < Ntest; i++) { + /* Test last value */ + if (with_assert) { + assert(abs(output_time - a_values[i]) < tol); + } + + /* Set current time */ + e->ti_current = log(output_time / e->cosmology->a_begin) / e->time_base; + e->ti_current += 1; + + /* Read next value */ + integertime_t ti_next; + output_list_read_next_time(list, e, name, &ti_next); + + output_time = (double)exp(ti_next * e->time_base) * e->cosmology->a_begin; + } + + output_list_clean(list); +}; + +int main(int argc, char *argv[]) { + /* Create a structure to read file into. */ + struct swift_params params; + + /* Read the parameter file. */ + parser_read_file(filename, ¶ms); + + /* initialization of unit system */ + struct unit_system us; + units_init_from_params(&us, ¶ms, "Units"); + + /* initialization of phys_const */ + struct phys_const phys_const; + phys_const_init(&us, ¶ms, &phys_const); + + /* initialization of cosmo */ + struct cosmology cosmo; + cosmology_init(¶ms, &us, &phys_const, &cosmo); + + /* Pseudo initialization of engine */ + struct engine e; + e.cosmology = &cosmo; + e.parameter_file = ¶ms; + e.physical_constants = &phys_const; + e.internal_units = &us; + + int with_assert = 1; + int without_assert = 0; + /* Test without cosmo */ + test_no_cosmo(&e, "Time", with_assert); + + /* Test with cosmo */ + test_cosmo(&e, "Redshift", with_assert); + test_cosmo(&e, "ScaleFactor", with_assert); + test_cosmo(&e, "Time", without_assert); + + /* Write message and leave */ + message("Test done"); + return 0; +} diff --git a/theory/Cosmology/coordinates.tex b/theory/Cosmology/coordinates.tex index 22d0da29330f850df7fc3bdb979b49c70670d96c..38a571aefea68fbe1bc7a8ebc3867109f1c4736e 100644 --- a/theory/Cosmology/coordinates.tex +++ b/theory/Cosmology/coordinates.tex @@ -35,7 +35,7 @@ respectively. Following \cite{Peebles1980} (ch.7), we introduce the gauge transformation $\Lag \rightarrow \Lag + \frac{d}{dt}\Psi$ with $\Psi \equiv \frac{1}{2}a\dot{a}\mathbf{r}_i^2$ and obtain \begin{align} - \Lag &= \frac{1}{2}m_ia^2 \dot{\mathbf{r}}_i^2 - + \Lag &= \frac{1}{2}m_ia^2 \dot{\mathbf{r}}_i'^2 - \frac{1}{\gamma-1}m_iA_i'\left(\frac{\rho_i'}{a^3}\right)^{\gamma-1} -\frac{\phi'}{a},\\ \phi' &= a\phi + \frac{1}{2}a^2\ddot{a}\mathbf{r}_i'^2,\nonumber