diff --git a/examples/GravityTests/HydrostaticHalo/makeIC.py b/examples/GravityTests/HydrostaticHalo/makeIC.py index b8a4036b77c430866f700047fd06bf2c8de490e7..4b9b1488765d4c4f9db49048954e541fbb49298a 100644 --- a/examples/GravityTests/HydrostaticHalo/makeIC.py +++ b/examples/GravityTests/HydrostaticHalo/makeIC.py @@ -62,15 +62,15 @@ M_vir_cgs = r_vir_cgs * v_c_cgs**2 / CONST_G_CGS const_unit_mass_in_cgs = M_vir_cgs const_unit_length_in_cgs = r_vir_cgs -print "UnitMass_in_cgs: ", const_unit_mass_in_cgs -print "UnitLength_in_cgs: ", const_unit_length_in_cgs -print "UnitVelocity_in_cgs: ", const_unit_velocity_in_cgs +print("UnitMass_in_cgs: ", const_unit_mass_in_cgs) +print("UnitLength_in_cgs: ", const_unit_length_in_cgs) +print("UnitVelocity_in_cgs: ", const_unit_velocity_in_cgs) #derived quantities const_unit_time_in_cgs = (const_unit_length_in_cgs / const_unit_velocity_in_cgs) -print "UnitTime_in_cgs: ", const_unit_time_in_cgs +print("UnitTime_in_cgs: ", const_unit_time_in_cgs) const_G = ((CONST_G_CGS*const_unit_mass_in_cgs*const_unit_time_in_cgs*const_unit_time_in_cgs/(const_unit_length_in_cgs*const_unit_length_in_cgs*const_unit_length_in_cgs))) -print 'G=', const_G +print('G=', const_G) # Parameters periodic= 1 # 1 For periodic box @@ -108,9 +108,9 @@ coords[:,2] = radius * ctheta #shift to centre of box coords += np.full((N,3),boxSize/2.) -print "x range = (%f,%f)" %(np.min(coords[:,0]),np.max(coords[:,0])) -print "y range = (%f,%f)" %(np.min(coords[:,1]),np.max(coords[:,1])) -print "z range = (%f,%f)" %(np.min(coords[:,2]),np.max(coords[:,2])) +print("x range = (%f,%f)" %(np.min(coords[:,0]),np.max(coords[:,0]))) +print("y range = (%f,%f)" %(np.min(coords[:,1]),np.max(coords[:,1]))) +print("z range = (%f,%f)" %(np.min(coords[:,2]),np.max(coords[:,2]))) #print np.mean(coords[:,0]) #print np.mean(coords[:,1]) @@ -156,7 +156,7 @@ z_coords = z_coords[ind] N = x_coords.size -print "Number of particles in the box = " , N +print("Number of particles in the box = " , N) #make the coords and radius arrays again coords_2 = np.zeros((N,3)) @@ -168,13 +168,13 @@ radius = np.sqrt(coords_2[:,0]**2 + coords_2[:,1]**2 + coords_2[:,2]**2) #test we've done it right -print "x range = (%f,%f)" %(np.min(coords_2[:,0]),np.max(coords_2[:,0])) -print "y range = (%f,%f)" %(np.min(coords_2[:,1]),np.max(coords_2[:,1])) -print "z range = (%f,%f)" %(np.min(coords_2[:,2]),np.max(coords_2[:,2])) +print("x range = (%f,%f)" %(np.min(coords_2[:,0]),np.max(coords_2[:,0]))) +print("y range = (%f,%f)" %(np.min(coords_2[:,1]),np.max(coords_2[:,1]))) +print("z range = (%f,%f)" %(np.min(coords_2[:,2]),np.max(coords_2[:,2]))) -print np.mean(coords_2[:,0]) -print np.mean(coords_2[:,1]) -print np.mean(coords_2[:,2]) +print(np.mean(coords_2[:,0])) +print(np.mean(coords_2[:,1])) +print(np.mean(coords_2[:,2])) # Header grp = file.create_group("/Header") diff --git a/examples/HydroTests/SodShock_BCC_3D/README b/examples/HydroTests/SodShock_BCC_3D/README new file mode 100644 index 0000000000000000000000000000000000000000..b836f33c6024a0de626d24b71309da2e5cccdbcd --- /dev/null +++ b/examples/HydroTests/SodShock_BCC_3D/README @@ -0,0 +1,7 @@ +SodShock BCC 3D +--------------- + +This example is the exact same as the SodShock_3D, but instead +of using a glass file, it uses a 'fake glass' that is generated +as an exact body centered cubic lattice with the makeGlass.py +script. diff --git a/examples/HydroTests/SodShock_BCC_3D/analyticSolution.py b/examples/HydroTests/SodShock_BCC_3D/analyticSolution.py new file mode 100644 index 0000000000000000000000000000000000000000..2cac6b0fabde207c325a1969434b6de9e90df9ca --- /dev/null +++ b/examples/HydroTests/SodShock_BCC_3D/analyticSolution.py @@ -0,0 +1,179 @@ +############################################################################### +# This file is part of SWIFT. +# Copyright (c) 2016 Matthieu Schaller (matthieu.schaller@durham.ac.uk) +# 2019 Josh Borrow (joshua.boorrow@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/>. +# +############################################################################## + +from numpy import * + + +def analytic( + time, # Simulation t + gas_gamma=5.0 / 3.0, # Polytropic index + rho_L=1.0, # Density left state + rho_R=0.125, # Density right state + v_L=0.0, # Velocity left state + v_R=0.0, # Velocity right state + P_L=1.0, # Pressure left state + P_R=0.1, # Pressure right state + N=1000, + x_min=-1.0, + x_max=1.0, +): + # Analytic solution + c_L = sqrt(gas_gamma * P_L / rho_L) # Speed of the rarefaction wave + c_R = sqrt(gas_gamma * P_R / rho_R) # Speed of the shock front + + # Helpful variable + Gama = (gas_gamma - 1.0) / (gas_gamma + 1.0) + beta = (gas_gamma - 1.0) / (2.0 * gas_gamma) + + # Characteristic function and its derivative, following Toro (2009) + def compute_f(P_3, P, c): + u = P_3 / P + if u > 1: + term1 = gas_gamma * ((gas_gamma + 1.0) * u + gas_gamma - 1.0) + term2 = sqrt(2.0 / term1) + fp = (u - 1.0) * c * term2 + dfdp = ( + c * term2 / P + + (u - 1.0) + * c + / term2 + * (-1.0 / term1 ** 2) + * gas_gamma + * (gas_gamma + 1.0) + / P + ) + else: + fp = (u ** beta - 1.0) * (2.0 * c / (gas_gamma - 1.0)) + dfdp = 2.0 * c / (gas_gamma - 1.0) * beta * u ** (beta - 1.0) / P + return (fp, dfdp) + + # Solution of the Riemann problem following Toro (2009) + def RiemannProblem(rho_L, P_L, v_L, rho_R, P_R, v_R): + P_new = ( + (c_L + c_R + (v_L - v_R) * 0.5 * (gas_gamma - 1.0)) + / (c_L / P_L ** beta + c_R / P_R ** beta) + ) ** (1.0 / beta) + P_3 = 0.5 * (P_R + P_L) + f_L = 1.0 + while fabs(P_3 - P_new) > 1e-6: + P_3 = P_new + (f_L, dfdp_L) = compute_f(P_3, P_L, c_L) + (f_R, dfdp_R) = compute_f(P_3, P_R, c_R) + f = f_L + f_R + (v_R - v_L) + df = dfdp_L + dfdp_R + dp = -f / df + prnew = P_3 + dp + v_3 = v_L - f_L + return (P_new, v_3) + + # Solve Riemann problem for post-shock region + (P_3, v_3) = RiemannProblem(rho_L, P_L, v_L, rho_R, P_R, v_R) + + # Check direction of shocks and wave + shock_R = P_3 > P_R + shock_L = P_3 > P_L + + # Velocity of shock front and and rarefaction wave + if shock_R: + v_right = v_R + c_R ** 2 * (P_3 / P_R - 1.0) / (gas_gamma * (v_3 - v_R)) + else: + v_right = c_R + 0.5 * (gas_gamma + 1.0) * v_3 - 0.5 * (gas_gamma - 1.0) * v_R + + if shock_L: + v_left = v_L + c_L ** 2 * (P_3 / p_L - 1.0) / (gas_gamma * (v_3 - v_L)) + else: + v_left = c_L - 0.5 * (gas_gamma + 1.0) * v_3 + 0.5 * (gas_gamma - 1.0) * v_L + + # Compute position of the transitions + x_23 = -fabs(v_left) * time + if shock_L: + x_12 = -fabs(v_left) * time + else: + x_12 = -(c_L - v_L) * time + + x_34 = v_3 * time + + x_45 = fabs(v_right) * time + if shock_R: + x_56 = fabs(v_right) * time + else: + x_56 = (c_R + v_R) * time + + # Prepare arrays + delta_x = (x_max - x_min) / N + x_s = arange(x_min, x_max, delta_x) + rho_s = zeros(N) + P_s = zeros(N) + v_s = zeros(N) + + # Compute solution in the different regions + for i in range(N): + if x_s[i] <= x_12: + rho_s[i] = rho_L + P_s[i] = P_L + v_s[i] = v_L + if x_s[i] >= x_12 and x_s[i] < x_23: + if shock_L: + rho_s[i] = rho_L * (Gama + P_3 / P_L) / (1.0 + Gama * P_3 / P_L) + P_s[i] = P_3 + v_s[i] = v_3 + else: + rho_s[i] = rho_L * ( + Gama * (0.0 - x_s[i]) / (c_L * time) + + Gama * v_L / c_L + + (1.0 - Gama) + ) ** (2.0 / (gas_gamma - 1.0)) + P_s[i] = P_L * (rho_s[i] / rho_L) ** gas_gamma + v_s[i] = (1.0 - Gama) * (c_L - (0.0 - x_s[i]) / time) + Gama * v_L + if x_s[i] >= x_23 and x_s[i] < x_34: + if shock_L: + rho_s[i] = rho_L * (Gama + P_3 / P_L) / (1 + Gama * P_3 / p_L) + else: + rho_s[i] = rho_L * (P_3 / P_L) ** (1.0 / gas_gamma) + P_s[i] = P_3 + v_s[i] = v_3 + if x_s[i] >= x_34 and x_s[i] < x_45: + if shock_R: + rho_s[i] = rho_R * (Gama + P_3 / P_R) / (1.0 + Gama * P_3 / P_R) + else: + rho_s[i] = rho_R * (P_3 / P_R) ** (1.0 / gas_gamma) + P_s[i] = P_3 + v_s[i] = v_3 + if x_s[i] >= x_45 and x_s[i] < x_56: + if shock_R: + rho_s[i] = rho_R + P_s[i] = P_R + v_s[i] = v_R + else: + rho_s[i] = rho_R * ( + Gama * (x_s[i]) / (c_R * time) - Gama * v_R / c_R + (1.0 - Gama) + ) ** (2.0 / (gas_gamma - 1.0)) + P_s[i] = p_R * (rho_s[i] / rho_R) ** gas_gamma + v_s[i] = (1.0 - Gama) * (-c_R - (-x_s[i]) / time) + Gama * v_R + if x_s[i] >= x_56: + rho_s[i] = rho_R + P_s[i] = P_R + v_s[i] = v_R + + # Additional arrays + u_s = P_s / (rho_s * (gas_gamma - 1.0)) # internal energy + s_s = P_s / rho_s ** gas_gamma # entropic function + + return dict(x=x_s + 1, v=v_s, rho=rho_s, P=P_s, u=u_s, S=s_s) diff --git a/examples/HydroTests/SodShock_BCC_3D/makeGlass.py b/examples/HydroTests/SodShock_BCC_3D/makeGlass.py new file mode 100644 index 0000000000000000000000000000000000000000..974c445668e4f6a93bd6328e2f5f2c953e8ef1a6 --- /dev/null +++ b/examples/HydroTests/SodShock_BCC_3D/makeGlass.py @@ -0,0 +1,90 @@ +""" +Create a fcc glass. +""" + +import numpy as np +import h5py + +from unyt import cm, g, s, erg +from unyt.unit_systems import cgs_unit_system + +from swiftsimio import Writer + + +def generate_cube(num_on_side, side_length=1.0): + """ + Generates a cube + """ + + values = np.linspace(0.0, side_length, num_on_side + 1)[:-1] + + positions = np.empty((num_on_side**3, 3), dtype=float) + + for x in range(num_on_side): + for y in range(num_on_side): + for z in range(num_on_side): + index = x * num_on_side + y * num_on_side**2 + z + + positions[index, 0] = values[x] + positions[index, 1] = values[y] + positions[index, 2] = values[z] + + return positions + + +def generate_two_cube(num_on_side, side_length=1.0): + cube = generate_cube(num_on_side // 2, side_length) + + mips = side_length / num_on_side + + positions = np.concatenate([cube, cube + mips * 0.5]) + + return positions + + +def write_out_glass(filename, cube, side_length=1.0): + x = Writer(cgs_unit_system, side_length * cm) + + x.gas.coordinates = cube * cm + + x.gas.velocities = np.zeros_like(cube) * cm / s + + x.gas.masses = np.ones(cube.shape[0], dtype=float) * g + + x.gas.internal_energy = np.ones(cube.shape[0], dtype=float) * erg / g + + x.gas.generate_smoothing_lengths(boxsize=side_length * cm, dimension=3) + + x.write(filename) + + return + + +if __name__ == "__main__": + import argparse as ap + + parser = ap.ArgumentParser( + description="Generate a glass file with a FCC lattice" + ) + + parser.add_argument( + "-n", + "--numparts", + help="Number of particles on a side. Default: 64", + default=1, + type=int + ) + + parser.add_argument( + "-o", + "--output", + help="Output filename.", + type=str, + required=False + ) + + args = parser.parse_args() + + glass_cube = generate_two_cube(args.numparts) + write_out_glass(args.output, glass_cube) + diff --git a/examples/HydroTests/SodShock_BCC_3D/makeIC.py b/examples/HydroTests/SodShock_BCC_3D/makeIC.py new file mode 100644 index 0000000000000000000000000000000000000000..69f1bc506680d3f2f149c0fd7b75b069f9b00b64 --- /dev/null +++ b/examples/HydroTests/SodShock_BCC_3D/makeIC.py @@ -0,0 +1,119 @@ +############################################################################### + # This file is part of SWIFT. + # Copyright (c) 2016 Matthieu Schaller (matthieu.schaller@durham.ac.uk) + # + # This program is free software: you can redistribute it and/or modify + # it under the terms of the GNU Lesser General Public License as published + # by the Free Software Foundation, either version 3 of the License, or + # (at your option) any later version. + # + # This program is distributed in the hope that it will be useful, + # but WITHOUT ANY WARRANTY; without even the implied warranty of + # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + # GNU General Public License for more details. + # + # You should have received a copy of the GNU Lesser General Public License + # along with this program. If not, see <http://www.gnu.org/licenses/>. + # + ############################################################################## + +import h5py +from numpy import * + +# Generates a swift IC file for the 3D Sod Shock in a periodic box + +# Parameters +gamma = 5./3. # Gas adiabatic index +x_min = -1. +x_max = 1. +rho_L = 1. # Density left state +rho_R = 0.125 # Density right state +v_L = 0. # Velocity left state +v_R = 0. # Velocity right state +P_L = 1. # Pressure left state +P_R = 0.1 # Pressure right state +fileName = "sodShock.hdf5" + + +#--------------------------------------------------- +boxSize = (x_max - x_min) + +glass_L = h5py.File("glassCube_64.hdf5", "r") +glass_R = h5py.File("glassCube_32.hdf5", "r") + +pos_L = glass_L["/PartType0/Coordinates"][:,:] * 0.5 +pos_R = glass_R["/PartType0/Coordinates"][:,:] * 0.5 +h_L = glass_L["/PartType0/SmoothingLength"][:] * 0.5 +h_R = glass_R["/PartType0/SmoothingLength"][:] * 0.5 + +# Merge things +aa = pos_L - array([0.5, 0., 0.]) +pos_LL = append(pos_L, pos_L + array([0.5, 0., 0.]), axis=0) +pos_RR = append(pos_R, pos_R + array([0.5, 0., 0.]), axis=0) +pos = append(pos_LL - array([1.0, 0., 0.]), pos_RR, axis=0) +h_LL = append(h_L, h_L) +h_RR = append(h_R, h_R) +h = append(h_LL, h_RR) + +numPart_L = size(h_LL) +numPart_R = size(h_RR) +numPart = size(h) + +vol_L = 0.25 +vol_R = 0.25 + +# Generate extra arrays +v = zeros((numPart, 3)) +ids = linspace(1, numPart, numPart) +m = zeros(numPart) +u = zeros(numPart) + +for i in range(numPart): + x = pos[i,0] + + if x < 0: #left + u[i] = P_L / (rho_L * (gamma - 1.)) + m[i] = rho_L * vol_L / numPart_L + v[i,0] = v_L + else: #right + u[i] = P_R / (rho_R * (gamma - 1.)) + m[i] = rho_R * vol_R / numPart_R + v[i,0] = v_R + +# Shift particles +pos[:,0] -= x_min + +#File +file = h5py.File(fileName, 'w') + +# Header +grp = file.create_group("/Header") +grp.attrs["BoxSize"] = [boxSize, 0.5, 0.5] +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 + +#Units +grp = file.create_group("/Units") +grp.attrs["Unit length in cgs (U_L)"] = 1. +grp.attrs["Unit mass in cgs (U_M)"] = 1. +grp.attrs["Unit time in cgs (U_t)"] = 1. +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=pos, dtype='d') +grp.create_dataset('Velocities', data=v, dtype='f') +grp.create_dataset('Masses', data=m, dtype='f') +grp.create_dataset('SmoothingLength', data=h, dtype='f') +grp.create_dataset('InternalEnergy', data=u, dtype='f') +grp.create_dataset('ParticleIDs', data=ids, dtype='L') + + +file.close() diff --git a/examples/HydroTests/SodShock_BCC_3D/plotSolution.py b/examples/HydroTests/SodShock_BCC_3D/plotSolution.py new file mode 100644 index 0000000000000000000000000000000000000000..dc1b15c3eac862365d4422f95a14ffe1713f91a6 --- /dev/null +++ b/examples/HydroTests/SodShock_BCC_3D/plotSolution.py @@ -0,0 +1,221 @@ +############################################################################### +# This file is part of the ANARCHY paper. +# Copyright (c) 2016 Matthieu Schaller (matthieu.schaller@durham.ac.uk) +# 2019 Josh Borrow (joshua.boorrow@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/>. +# +################################################################################ + +# Compares the swift result for the 2D spherical Sod shock with a high +# resolution 2D reference result + +import sys +import matplotlib + +matplotlib.use("Agg") + +import matplotlib.pyplot as plt +import numpy as np +from scipy import stats + +from swiftsimio import load +from analyticSolution import analytic + +snap = int(sys.argv[1]) + +sim = load(f"sodshock_{snap:04d}.hdf5") + +# Set up plotting stuff +try: + plt.style.use("mnras_durham") +except: + rcParams = { + "font.serif": ["STIX", "Times New Roman", "Times"], + "font.family": ["serif"], + "mathtext.fontset": "stix", + "font.size": 8, + } + plt.rcParams.update(rcParams) + + +# See analyticSolution for params. + + +def get_data_dump(metadata): + """ + Gets a big data dump from the SWIFT metadata + """ + + try: + viscosity = metadata.viscosity_info + except: + viscosity = "No info" + + try: + diffusion = metadata.diffusion_info + except: + diffusion = "No info" + + output = ( + "$\\bf{SWIFT}$\n" + + metadata.code_info + + "\n\n" + + "$\\bf{Compiler}$\n" + + metadata.compiler_info + + "\n\n" + + "$\\bf{Hydrodynamics}$\n" + + metadata.hydro_info + + "\n\n" + + "$\\bf{Viscosity}$\n" + + viscosity + + "\n\n" + + "$\\bf{Diffusion}$\n" + + diffusion + ) + + return output + + +# Read the simulation data +time = sim.metadata.t.value + +data = dict( + x=sim.gas.coordinates.value[:, 0], + v=sim.gas.velocities.value[:, 0], + u=sim.gas.internal_energy.value, + S=sim.gas.entropy.value, + P=sim.gas.pressure.value, + rho=sim.gas.density.value, + y=sim.gas.coordinates.value[:, 1], + z=sim.gas.coordinates.value[:, 2], +) + +# Try to add on the viscosity and diffusion. +try: + data["visc"] = sim.gas.viscosity.value +except: + pass + +try: + data["diff"] = 100.0 * sim.gas.diffusion.value +except: + pass + +# Read in the "solution" data and calculate those that don't exist. + +ref = analytic(time=time) + +# We only want to plot this for the region that we actually have data for, hence the masking. +mask = np.logical_and(ref["x"] < np.max(data["x"]), ref["x"] > np.min(data["x"])) +ref = {k: v[mask] for k, v in ref.items()} + +# Now we can do the plotting. +fig, ax = plt.subplots(2, 3, figsize=(6.974, 6.974 * (2.0 / 3.0))) +ax = ax.flatten() + +# These are stored in priority order +plot = dict( + v="Velocity ($v_x$)", + u="Internal Energy ($u$)", + rho=r"Density ($\rho$)", + P="Pressure ($P$)", + diff=r"100$\times$ Diffusion Coefficient ($\alpha_D$)", + visc=r"Viscosity Coefficient ($\alpha_V$)", + S="Entropy ($A$)", +) + +log = dict(v=False, u=False, S=False, P=False, rho=False, visc=False, diff=False) +ylim = dict(v=(-0.05, 1.0), diff=(0.0, None), visc=(0.0, None)) + +current_axis = 0 + +for key, label in plot.items(): + if current_axis > 4: + break + else: + axis = ax[current_axis] + + try: + if log[key]: + axis.semilogy() + + # Raw data + axis.plot( + data["x"], + data[key], + ".", + color="C1", + markersize=0.5, + alpha=0.5, + rasterized=True, + markeredgecolor="none", + zorder=-1, + ) + + mask_noraster = np.logical_and.reduce([ + data["y"] < 0.52, + data["y"] > 0.48, + data["z"] < 0.52, + data["z"] > 0.48 + ]) + + axis.plot( + data["x"][mask_noraster], + data[key][mask_noraster], + ".", + color="C3", + rasterized=False, + markeredgecolor="none", + markersize=3, + zorder=0, + ) + + # Exact solution + try: + axis.plot(ref["x"], ref[key], c="C0", ls="dashed", zorder=1, lw=1) + except KeyError: + # No solution :( + pass + + axis.set_xlabel("Position ($x$)", labelpad=0) + axis.set_ylabel(label, labelpad=0) + + axis.set_xlim(0.6, 1.5) + + try: + axis.set_ylim(*ylim[key]) + except KeyError: + # No worries pal + pass + + current_axis += 1 + except KeyError: + # Mustn't have that data! + continue + + +info_axis = ax[-1] + +info = get_data_dump(sim.metadata) + +info_axis.text( + 0.5, 0.45, info, ha="center", va="center", fontsize=5, transform=info_axis.transAxes +) + +info_axis.axis("off") + + +fig.tight_layout(pad=0.5) +fig.savefig("SodShock.pdf", dpi=300) diff --git a/examples/HydroTests/SodShock_BCC_3D/run.sh b/examples/HydroTests/SodShock_BCC_3D/run.sh new file mode 100755 index 0000000000000000000000000000000000000000..70cb3a97b1adf3944b9ed8965afabecfe280f7af --- /dev/null +++ b/examples/HydroTests/SodShock_BCC_3D/run.sh @@ -0,0 +1,15 @@ +#!/bin/bash + +# Generate the initial conditions if they are not present. +if [ ! -e sodShock.hdf5 ] +then + echo "Generating initial conditions for the Sod shock example..." + python makeGlass.py -n 64 -o glassCube_64.hdf5 + python makeGlass.py -n 32 -o glassCube_32.hdf5 + python makeIC.py +fi + +# Run SWIFT +../../swift --hydro --threads=4 sodShock.yml 2>&1 | tee output.log + +python plotSolution.py 1 diff --git a/examples/HydroTests/SodShock_BCC_3D/sodShock.yml b/examples/HydroTests/SodShock_BCC_3D/sodShock.yml new file mode 100644 index 0000000000000000000000000000000000000000..373a70bf6b6782d7bdb4ed91417a13270f6521e6 --- /dev/null +++ b/examples/HydroTests/SodShock_BCC_3D/sodShock.yml @@ -0,0 +1,85 @@ +# Define the system of units to use internally. +InternalUnitSystem: + UnitMass_in_cgs: 1 # Grams + UnitLength_in_cgs: 1 # Centimeters + UnitVelocity_in_cgs: 1 # Centimeters per second + UnitCurrent_in_cgs: 1 # Amperes + UnitTemp_in_cgs: 1 # Kelvin + +# Parameters governing the time integration +TimeIntegration: + time_begin: 0. # The starting time of the simulation (in internal units). + time_end: 0.2 # The end time of the simulation (in internal units). + dt_min: 1e-7 # 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 snapshots +Snapshots: + basename: sodShock # Common part of the name of output files + time_first: 0. # Time of the first output (in internal units) + delta_time: 0.2 # Time difference between consecutive outputs (in internal units) + compression: 1 + +# Parameters governing the conserved quantities statistics +Statistics: + delta_time: 1e-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 (1.2348 == 48Ngbs with the cubic spline kernel). + CFL_condition: 0.1 # Courant-Friedrich-Levy condition for time integration. + viscosity_alpha: 1.0 + viscosity_alpha_max: 1.0 + viscosity_alpha_min: 1.0 + +# Parameters related to the initial conditions +InitialConditions: + file_name: ./sodShock.hdf5 # The file to read + periodic: 1 + +EAGLEChemistry: # Solar abundances + init_abundance_metal: 0.014 + init_abundance_Hydrogen: 0.70649785 + init_abundance_Helium: 0.28055534 + init_abundance_Carbon: 2.0665436e-3 + init_abundance_Nitrogen: 8.3562563e-4 + init_abundance_Oxygen: 5.4926244e-3 + init_abundance_Neon: 1.4144605e-3 + init_abundance_Magnesium: 5.907064e-4 + init_abundance_Silicon: 6.825874e-4 + init_abundance_Iron: 1.1032152e-3 + +EAGLECooling: + dir_name: ./coolingtables/ + H_reion_z: 11.5 + H_reion_eV_p_H: 2.0 + He_reion_z_centre: 3.5 + He_reion_z_sigma: 0.5 + He_reion_eV_p_H: 2.0 + +# EAGLE star formation parameters +EAGLEStarFormation: + EOS_density_norm_H_p_cm3: 0.1 # Physical density used for the normalisation of the EOS assumed for the star-forming gas in Hydrogen atoms per cm^3. + EOS_temperature_norm_K: 8000 # Temperature om the polytropic EOS assumed for star-forming gas at the density normalisation in Kelvin. + EOS_gamma_effective: 1.3333333 # Slope the of the polytropic EOS assumed for the star-forming gas. + KS_normalisation: 1.515e-4 # The normalization of the Kennicutt-Schmidt law in Msun / kpc^2 / yr. + KS_exponent: 1.4 # The exponent of the Kennicutt-Schmidt law. + KS_min_over_density: 57.7 # The over-density above which star-formation is allowed. + KS_high_density_threshold_H_p_cm3: 1e3 # Hydrogen number density above which the Kennicut-Schmidt law changes slope in Hydrogen atoms per cm^3. + KS_high_density_exponent: 2.0 # Slope of the Kennicut-Schmidt law above the high-density threshold. + KS_temperature_margin_dex: 0.5 # Logarithm base 10 of the maximal temperature difference above the EOS allowed to form stars. + threshold_norm_H_p_cm3: 0.1 # Normalisation of the metal-dependant density threshold for star formation in Hydrogen atoms per cm^3. + threshold_Z0: 0.002 # Reference metallicity (metal mass fraction) for the metal-dependant threshold for star formation. + threshold_slope: -0.64 # Slope of the metal-dependant star formation threshold + threshold_max_density_H_p_cm3: 10.0 # Maximal density of the metal-dependant density threshold for star formation in Hydrogen atoms per cm^3. + +# Parameters for the EAGLE "equation of state" +EAGLEEntropyFloor: + Jeans_density_threshold_H_p_cm3: 0.1 # Physical density above which the EAGLE Jeans limiter entropy floor kicks in expressed in Hydrogen atoms per cm^3. + Jeans_over_density_threshold: 10. # Overdensity above which the EAGLE Jeans limiter entropy floor can kick in. + Jeans_temperature_norm_K: 8000 # Temperature of the EAGLE Jeans limiter entropy floor at the density threshold expressed in Kelvin. + Jeans_gamma_effective: 1.3333333 # Slope the of the EAGLE Jeans limiter entropy floor + Cool_density_threshold_H_p_cm3: 1e-5 # Physical density above which the EAGLE Cool limiter entropy floor kicks in expressed in Hydrogen atoms per cm^3. + Cool_over_density_threshold: 10. # Overdensity above which the EAGLE Cool limiter entropy floor can kick in. + Cool_temperature_norm_K: 8000 # Temperature of the EAGLE Cool limiter entropy floor at the density threshold expressed in Kelvin. + Cool_gamma_effective: 1. # Slope the of the EAGLE Cool limiter entropy floor diff --git a/examples/HydroTests/SquareTest_2D/README b/examples/HydroTests/SquareTest_2D/README new file mode 100644 index 0000000000000000000000000000000000000000..fc07b9d9d17fc746752bd6eb47f03899b4b335a0 --- /dev/null +++ b/examples/HydroTests/SquareTest_2D/README @@ -0,0 +1,20 @@ +Square Test +----------- + +This is a very challenging test that aims to figure out +if contact discontinuities are properly handled. If there +is residual surface tension, then the square will quickly +become a sphere. Otherwise, it will remain a square. For +more information see Hopkins' 2013 and 2015 papers. + +There are two initial condition generation files present. +For the SWIFT method of finding an un-mass weighted number +of particles in the kernel, it makes more sense to have +different mass particles (makeICDifferentMasses.py). For +comparison to previous methods, we also provide a script +that creates initial conditions with a different density +of particles, all with equal masses, in the square and +outside of the square. + +If you do not have the swiftsimio library, you can use +the plotSolutionLegacy.py to plot the solution. diff --git a/examples/HydroTests/SquareTest_2D/makeIC.py b/examples/HydroTests/SquareTest_2D/makeIC.py index 12a394873edf42f7ecfdf07c9795b62e3ad89745..bbb6837c019dde14d833588924901cb49e301b25 100644 --- a/examples/HydroTests/SquareTest_2D/makeIC.py +++ b/examples/HydroTests/SquareTest_2D/makeIC.py @@ -29,15 +29,15 @@ rho0 = 4 # Gas central density rho1 = 1 # Gas outskirt density P0 = 2.5 # Gas central pressure P1 = 2.5 # Gas central pressure -vx = 142.3 # Random velocity for all particles -vy = -31.4 +vx = 0.0 # Random velocity for all particles +vy = 0.0 fileOutputName = "square.hdf5" #--------------------------------------------------- vol = 1. numPart_out = L * L -numPart_in = L * L * rho0 / rho1 / 4 +numPart_in = int(L * L * rho0 / rho1 / 4) L_out = int(sqrt(numPart_out)) L_in = int(sqrt(numPart_in)) diff --git a/examples/HydroTests/SquareTest_2D/makeICDifferentMasses.py b/examples/HydroTests/SquareTest_2D/makeICDifferentMasses.py new file mode 100644 index 0000000000000000000000000000000000000000..6c7af6d33ea020be773805d223095c99fbf78951 --- /dev/null +++ b/examples/HydroTests/SquareTest_2D/makeICDifferentMasses.py @@ -0,0 +1,110 @@ +############################################################################### +# This file is part of SWIFT. +# Copyright (c) 2019 Josh Borrow (joshua.borrow@durham.ac.uk) +# 2016 Matthieu Schaller (matthieu.schaller@durham.ac.uk) +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU Lesser General Public License as published +# by the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU Lesser General Public License +# along with this program. If not, see <http://www.gnu.org/licenses/>. +# +############################################################################## + +import h5py +from numpy import * + +# Generates a swift IC file for the Square test in a periodic box + +# Parameters +L = 2 * 64 # Number of particles on the side +gamma = 5.0 / 3.0 # Gas adiabatic index +rho0 = 4 # Gas central density +rho1 = 1 # Gas outskirt density +P0 = 2.5 # Gas central pressure +P1 = 2.5 # Gas central pressure +vx = 0.0 # Random velocity for all particles +vy = 0.0 +fileOutputName = "square.hdf5" +# --------------------------------------------------- + +vol = 1.0 + +numPart = L * L + +pos_x = arange(0, 1, 1.0 / L) +xv, yv = meshgrid(pos_x, pos_x) +pos = zeros((numPart, 3), dtype=float) +pos[:, 0] = xv.flatten() +pos[:, 1] = yv.flatten() + +# Now we can get 2d masks! +inside = logical_and.reduce([xv < 0.75, xv > 0.25, yv < 0.75, yv > 0.25]) + +mass_in = rho0 / numPart +mass_out = rho1 / numPart + +m = ones_like(xv) * mass_out +m[inside] = mass_in +m = m.flatten() + +h = ones_like(m) / L + +u_in = P0 / ((gamma - 1) * rho0) +u_out = P1 / ((gamma - 1) * rho1) +u = ones_like(xv) * u_out +u[inside] = u_in +u = u.flatten() + +vel = zeros_like(pos) + +ids = arange(numPart) + + +# File +fileOutput = h5py.File(fileOutputName, "w") + +# Header +grp = fileOutput.create_group("/Header") +grp.attrs["BoxSize"] = [vol, vol, 0.2] +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, 0, 0, 0, 0, 0] +grp.attrs["Dimension"] = 2 + +# Units +grp = fileOutput.create_group("/Units") +grp.attrs["Unit length in cgs (U_L)"] = 1.0 +grp.attrs["Unit mass in cgs (U_M)"] = 1.0 +grp.attrs["Unit time in cgs (U_t)"] = 1.0 +grp.attrs["Unit current in cgs (U_I)"] = 1.0 +grp.attrs["Unit temperature in cgs (U_T)"] = 1.0 + +# Particle group +grp = fileOutput.create_group("/PartType0") +ds = grp.create_dataset("Coordinates", (numPart, 3), "d") +ds[()] = pos +ds = grp.create_dataset("Velocities", (numPart, 3), "f") +ds[()] = vel +ds = grp.create_dataset("Masses", (numPart, 1), "f") +ds[()] = m.reshape((numPart, 1)) +ds = grp.create_dataset("SmoothingLength", (numPart, 1), "f") +ds[()] = h.reshape((numPart, 1)) +ds = grp.create_dataset("InternalEnergy", (numPart, 1), "f") +ds[()] = u.reshape((numPart, 1)) +ds = grp.create_dataset("ParticleIDs", (numPart, 1), "L") +ds[()] = ids.reshape((numPart, 1)) + +fileOutput.close() + diff --git a/examples/HydroTests/SquareTest_2D/makeMovie.py b/examples/HydroTests/SquareTest_2D/makeMovie.py new file mode 100644 index 0000000000000000000000000000000000000000..ccddca6e05b1103b8ece425c097f3ddec7bf2bb9 --- /dev/null +++ b/examples/HydroTests/SquareTest_2D/makeMovie.py @@ -0,0 +1,136 @@ +############################################################################### +# This file is part of SWIFT. +# Copyright (c) 2019 Josh Borrow (joshua.borrow@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/>. +# +############################################################################## + +from swiftsimio import load +from swiftsimio.visualisation import project_gas_pixel_grid +from matplotlib.animation import FuncAnimation +import matplotlib.pyplot as plt + +from numpy import max, min + +try: + # Try and load this, otherwise we're stuck with serial + from p_tqdm import p_map + + map = p_map +except: + print("Try installing the p_tqdm package to make movie frames in parallel") + pass + + +def load_and_make_image(number, res, property): + filename = "square_{:04d}.hdf5".format(number) + data = load(filename) + image = project_gas_pixel_grid(data, res, property) + image_none = project_gas_pixel_grid(data, res, None) + + return image / image_none + + +def create_movie(filename, start, stop, resolution, property, output_filename): + """ + Creates the movie with: + + snapshots named {filename}_{start}.hdf5 to {filename}_{stop}.hdf5 + at {resolution} x {resolution} pixel size and smoothing the given + {property} and outputting to {output_filename}. + """ + + def baked_in_load(n): + return load_and_make_image(n, resolution, property) + + # Make frames in parallel (reading also parallel!) + frames = map(baked_in_load, list(range(start, stop))) + + vmax = max(list(map(max, frames))) + vmin = min(list(map(min, frames))) + + fig, ax = plt.subplots(figsize=(1, 1)) + ax.axis("off") + fig.subplots_adjust(0, 0, 1, 1) + + image = ax.imshow(frames[0], origin="lower", vmax=vmax, vmin=vmin) + + def frame(n): + image.set_array(frames[n]) + + return (image,) + + animation = FuncAnimation(fig, frame, range(0, 40), interval=40) + animation.save(output_filename, dpi=resolution) + + +if __name__ == "__main__": + from argparse import ArgumentParser + + parser = ArgumentParser(description="""Creates a movie of the whole box.""") + + parser.add_argument( + "-s", + "--snapshot", + help="Snapshot name. Default: square", + type=str, + default="square", + ) + + parser.add_argument( + "-i", "--initial", help="Initial snapshot. Default: 0", type=int, default=0 + ) + + parser.add_argument( + "-f", "--final", help="Final snapshot. Default: 40", type=int, default=40 + ) + + parser.add_argument( + "-o", + "--output", + help="Output filename. Default: EnergyMovie.mp4", + type=str, + default="EnergyMovie.mp4", + ) + + parser.add_argument( + "-p", + "--property", + help="(swiftsimio) Property to plot. Default: internal_energy", + type=str, + default="internal_energy", + ) + + parser.add_argument( + "-r", + "--resolution", + help="Resolution to make the movie at. Default: 512", + type=int, + default=512, + ) + + vars = parser.parse_args() + + create_movie( + filename=vars.snapshot, + start=vars.initial, + stop=vars.final, + resolution=vars.resolution, + property=vars.property, + output_filename=vars.output, + ) + + exit(0) + diff --git a/examples/HydroTests/SquareTest_2D/plotSolution.py b/examples/HydroTests/SquareTest_2D/plotSolution.py index f182b4d7437348d29065b51df79e5334aa26f9a4..ae351abb47eb5bf63f71b55b33a060067c8a6a01 100644 --- a/examples/HydroTests/SquareTest_2D/plotSolution.py +++ b/examples/HydroTests/SquareTest_2D/plotSolution.py @@ -1,186 +1,171 @@ ############################################################################### - # This file is part of SWIFT. - # Copyright (c) 2016 Matthieu Schaller (matthieu.schaller@durham.ac.uk) - # - # This program is free software: you can redistribute it and/or modify - # it under the terms of the GNU Lesser General Public License as published - # by the Free Software Foundation, either version 3 of the License, or - # (at your option) any later version. - # - # This program is distributed in the hope that it will be useful, - # but WITHOUT ANY WARRANTY; without even the implied warranty of - # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - # GNU General Public License for more details. - # - # You should have received a copy of the GNU Lesser General Public License - # along with this program. If not, see <http://www.gnu.org/licenses/>. - # - ############################################################################## - -# Computes the analytical solution of the square test - -# Parameters -gas_gamma = 5./3. # Gas adiabatic index -gamma = 5./3. # Gas adiabatic index -rho0 = 4 # Gas central density -rho1 = 1 # Gas outskirt density -P0 = 2.5 # Gas central pressure -P1 = 2.5 # Gas central pressure -vx = 142.3 # Random velocity for all particles -vy = -31.4 - -# --------------------------------------------------------------- -# Don't touch anything after this. -# --------------------------------------------------------------- - +# This file is part of SWIFT. +# Copyright (c) 2019 Josh Borrow (joshua.borrow@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/>. +# +############################################################################## +""" +Plots the solution of the square test in a smoothed way using SWIFTsimIO's +smoothed plotting. +""" + +import sys import matplotlib + matplotlib.use("Agg") -from pylab import * -import h5py - -# 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.045, -'figure.subplot.right' : 0.99, -'figure.subplot.bottom' : 0.05, -'figure.subplot.top' : 0.99, -'figure.subplot.wspace' : 0.15, -'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']}) + +import matplotlib.pyplot as plt +import numpy as np +from scipy import stats + +from swiftsimio import load +from swiftsimio.visualisation import project_gas_pixel_grid snap = int(sys.argv[1]) -# Read the simulation data -sim = h5py.File("square_%04d.hdf5"%snap, "r") -boxSize = sim["/Header"].attrs["BoxSize"][0] -time = sim["/Header"].attrs["Time"][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"] - -# Analytical soltion -centre_x = 0.5 + time * vx -centre_y = 0.5 + time * vy - -while centre_x > 1.: - centre_x -= 1. -while centre_x < 0.: - centre_x += 1. -while centre_y > 1.: - centre_y -= 1. -while centre_y < 0.: - centre_y += 1. - -pos = sim["/PartType0/Coordinates"][:,:] -vel = sim["/PartType0/Velocities"][:,:] -v_norm = sqrt(vel[:,0]**2 + vel[:,1]**2) -rho = sim["/PartType0/Density"][:] -u = sim["/PartType0/InternalEnergy"][:] -S = sim["/PartType0/Entropy"][:] -P = sim["/PartType0/Pressure"][:] -x = pos[:,0] - centre_x -y = pos[:,1] - centre_y - -# Box wrapping -x[x>0.5] -= 1. -x[x<-0.5] += 1. -y[y>0.5] -= 1. -y[y<-0.5] += 1. - -# Azimuthal velocity profile ----------------------------- -subplot(231) -scatter(x, y, c=v_norm, cmap="PuBu", edgecolors='face', s=4, vmin=-1., vmax=1.) -text(0.47, 0.47, "${\\rm{Velocity~norm}}$", ha="right", va="top", backgroundcolor="w") -plot([-0.25, 0.25], [0.25, 0.25], '--', color='k', alpha=0.8, lw=2) -plot([-0.25, 0.25], [-0.25, -0.25], '--', color='k', alpha=0.8, lw=2) -plot([0.25, 0.25], [-0.25, 0.25], '--', color='k', alpha=0.8, lw=2) -plot([-0.25, -0.25], [-0.25, 0.25], '--', color='k', alpha=0.8, lw=2) -xlabel("${\\rm{Position}}~x$", labelpad=0) -ylabel("${\\rm{Position}}~y$", labelpad=-7) -xlim(-0.5, 0.5) -ylim(-0.5, 0.5) - -# Radial density profile -------------------------------- -subplot(232) -scatter(x, y, c=rho, cmap="PuBu", edgecolors='face', s=4, vmin=0., vmax=4.) -text(0.47, 0.47, "${\\rm{Density}}$", ha="right", va="top", backgroundcolor="w") -plot([-0.25, 0.25], [0.25, 0.25], '--', color='k', alpha=0.8, lw=2) -plot([-0.25, 0.25], [-0.25, -0.25], '--', color='k', alpha=0.8, lw=2) -plot([0.25, 0.25], [-0.25, 0.25], '--', color='k', alpha=0.8, lw=2) -plot([-0.25, -0.25], [-0.25, 0.25], '--', color='k', alpha=0.8, lw=2) -xlabel("${\\rm{Position}}~x$", labelpad=0) -ylabel("${\\rm{Position}}~y$", labelpad=-7) -xlim(-0.5, 0.5) -ylim(-0.5, 0.5) - -# Radial pressure profile -------------------------------- -subplot(233) -scatter(x, y, c=P, cmap="PuBu", edgecolors='face', s=4, vmin=2, vmax=4) -text(0.47, 0.47, "${\\rm{Pressure}}$", ha="right", va="top", backgroundcolor="w") -plot([-0.25, 0.25], [0.25, 0.25], '--', color='k', alpha=0.8, lw=2) -plot([-0.25, 0.25], [-0.25, -0.25], '--', color='k', alpha=0.8, lw=2) -plot([0.25, 0.25], [-0.25, 0.25], '--', color='k', alpha=0.8, lw=2) -plot([-0.25, -0.25], [-0.25, 0.25], '--', color='k', alpha=0.8, lw=2) -xlabel("${\\rm{Position}}~x$", labelpad=0) -ylabel("${\\rm{Position}}~y$", labelpad=-7) -xlim(-0.5, 0.5) -ylim(-0.5, 0.5) - -# Internal energy profile -------------------------------- -subplot(234) -scatter(x, y, c=u, cmap="PuBu", edgecolors='face', s=4, vmin=0.5, vmax=4.) -text(0.47, 0.47, "${\\rm{Internal~energy}}$", ha="right", va="top", backgroundcolor="w") -plot([-0.25, 0.25], [0.25, 0.25], '--', color='k', alpha=0.8, lw=2) -plot([-0.25, 0.25], [-0.25, -0.25], '--', color='k', alpha=0.8, lw=2) -plot([0.25, 0.25], [-0.25, 0.25], '--', color='k', alpha=0.8, lw=2) -plot([-0.25, -0.25], [-0.25, 0.25], '--', color='k', alpha=0.8, lw=2) -xlabel("${\\rm{Position}}~x$", labelpad=0) -ylabel("${\\rm{Position}}~y$", labelpad=-7) -xlim(-0.5, 0.5) -ylim(-0.5, 0.5) - -# Radial entropy profile -------------------------------- -subplot(235) -scatter(x, y, c=S, cmap="PuBu", edgecolors='face', s=4, vmin=0., vmax=3.) -text(0.47, 0.47, "${\\rm{Entropy}}$", ha="right", va="top", backgroundcolor="w") -plot([-0.25, 0.25], [0.25, 0.25], '--', color='k', alpha=0.8, lw=2) -plot([-0.25, 0.25], [-0.25, -0.25], '--', color='k', alpha=0.8, lw=2) -plot([0.25, 0.25], [-0.25, 0.25], '--', color='k', alpha=0.8, lw=2) -plot([-0.25, -0.25], [-0.25, 0.25], '--', color='k', alpha=0.8, lw=2) -xlabel("${\\rm{Position}}~x$", labelpad=0) -ylabel("${\\rm{Position}}~y$", labelpad=-7) -xlim(-0.5, 0.5) -ylim(-0.5, 0.5) - - -# Information ------------------------------------- -subplot(236, frameon=False) - -text(-0.49, 0.9, "Square test with $\\gamma=%.3f$ at $t=%.2f$"%(gas_gamma,time), fontsize=10) -text(-0.49, 0.8, "Centre:~~~ $(P, \\rho) = (%.3f, %.3f)$"%(P0, rho0), fontsize=10) -text(-0.49, 0.7, "Outskirts: $(P, \\rho) = (%.3f, %.3f)$"%(P1, rho1), fontsize=10) -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("SquareTest.png", dpi=200) +sim = load(f"square_{snap:04d}.hdf5") +resolution = 512 + +# First create a grid that gets the particle density so we can divide it out later +unweighted_grid = project_gas_pixel_grid(sim, 512, None) + +# Set up plotting stuff +try: + plt.style.use("mnras_durham") +except: + rcParams = { + "font.serif": ["STIX", "Times New Roman", "Times"], + "font.family": ["serif"], + "mathtext.fontset": "stix", + "font.size": 8, + } + plt.rcParams.update(rcParams) + + +def get_data_dump(metadata): + """ + Gets a big data dump from the SWIFT metadata + """ + + try: + viscosity = metadata.viscosity_info + except: + viscosity = "No info" + + try: + diffusion = metadata.diffusion_info + except: + diffusion = "No info" + + output = ( + "$\\bf{SWIFT}$\n" + + metadata.code_info + + "\n\n" + + "$\\bf{Compiler}$\n" + + metadata.compiler_info + + "\n\n" + + "$\\bf{Hydrodynamics}$\n" + + metadata.hydro_info + + "\n\n" + + "$\\bf{Viscosity}$\n" + + viscosity + + "\n\n" + + "$\\bf{Diffusion}$\n" + + diffusion + ) + + return output + + +# Now we can do the plotting. +fig, ax = plt.subplots(2, 3, figsize=(6.974, 6.974 * (2.0 / 3.0))) +ax = ax.flatten() + +# These are stored in priority order +plot = dict( + internal_energy="Internal Energy ($u$)", + density=r"Density ($\rho$)", + pressure="Pressure ($P$)", + entropy="Entropy ($A$)", + diffusion=r"Diffusion ($\alpha$)", +) + +current_axis = 0 + +for key, label in plot.items(): + if current_axis > 4: + break + else: + axis = ax[current_axis] + + try: + # Raw data + try: + grid = ( + project_gas_pixel_grid(sim, resolution=resolution, project=key) + / unweighted_grid + ) + axis.imshow(grid, origin="lower", extent=[0, 1, 0, 1], cmap="cividis") + except: + continue + + # Exact solution, a square! + axis.plot( + [0.25, 0.75, 0.75, 0.25, 0.25], + [0.25, 0.25, 0.75, 0.75, 0.25], + linestyle="dashed", + color="white", + ) + + circle = plt.Circle( + (0.8, 0.8), + radius=np.sqrt(1.0 / sim.metadata.n_gas) * 1.25, + linestyle="solid", + color="white", + fill=False, + ) + + axis.add_artist(circle) + + axis.tick_params( + axis="both", + which="both", + labelbottom=False, + labelleft=False, + bottom=False, + left=False, + ) + + axis.set_title(label) + + current_axis += 1 + except KeyError: + # Mustn't have that data! + continue + + +info_axis = ax[-1] + +info = get_data_dump(sim.metadata) + +info_axis.text( + 0.5, 0.45, info, ha="center", va="center", fontsize=5, transform=info_axis.transAxes +) + +info_axis.axis("off") + + +fig.tight_layout(pad=1.0) +fig.savefig("SquareTest.pdf", dpi=300) diff --git a/examples/HydroTests/SquareTest_2D/plotSolutionLegacy.py b/examples/HydroTests/SquareTest_2D/plotSolutionLegacy.py new file mode 100644 index 0000000000000000000000000000000000000000..956da800c9096232d2e82cf4cff4c780672e0a8f --- /dev/null +++ b/examples/HydroTests/SquareTest_2D/plotSolutionLegacy.py @@ -0,0 +1,186 @@ +############################################################################### + # This file is part of SWIFT. + # Copyright (c) 2016 Matthieu Schaller (matthieu.schaller@durham.ac.uk) + # + # This program is free software: you can redistribute it and/or modify + # it under the terms of the GNU Lesser General Public License as published + # by the Free Software Foundation, either version 3 of the License, or + # (at your option) any later version. + # + # This program is distributed in the hope that it will be useful, + # but WITHOUT ANY WARRANTY; without even the implied warranty of + # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + # GNU General Public License for more details. + # + # You should have received a copy of the GNU Lesser General Public License + # along with this program. If not, see <http://www.gnu.org/licenses/>. + # + ############################################################################## + +# Computes the analytical solution of the square test + +# Parameters +gas_gamma = 5./3. # Gas adiabatic index +gamma = 5./3. # Gas adiabatic index +rho0 = 4 # Gas central density +rho1 = 1 # Gas outskirt density +P0 = 2.5 # Gas central pressure +P1 = 2.5 # Gas central pressure +vx = 0.0 # Random velocity for all particles +vy = 0.0 + +# --------------------------------------------------------------- +# Don't touch anything after this. +# --------------------------------------------------------------- + +import matplotlib +matplotlib.use("Agg") +from pylab import * +import h5py + +# 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.045, +'figure.subplot.right' : 0.99, +'figure.subplot.bottom' : 0.05, +'figure.subplot.top' : 0.99, +'figure.subplot.wspace' : 0.15, +'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']}) + +snap = int(sys.argv[1]) + +# Read the simulation data +sim = h5py.File("square_%04d.hdf5"%snap, "r") +boxSize = sim["/Header"].attrs["BoxSize"][0] +time = sim["/Header"].attrs["Time"][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"] + +# Analytical soltion +centre_x = 0.5 + time * vx +centre_y = 0.5 + time * vy + +while centre_x > 1.: + centre_x -= 1. +while centre_x < 0.: + centre_x += 1. +while centre_y > 1.: + centre_y -= 1. +while centre_y < 0.: + centre_y += 1. + +pos = sim["/PartType0/Coordinates"][:,:] +vel = sim["/PartType0/Velocities"][:,:] +v_norm = sqrt(vel[:,0]**2 + vel[:,1]**2) +rho = sim["/PartType0/Density"][:] +u = sim["/PartType0/InternalEnergy"][:] +S = sim["/PartType0/Entropy"][:] +P = sim["/PartType0/Pressure"][:] +x = pos[:,0] - centre_x +y = pos[:,1] - centre_y + +# Box wrapping +x[x>0.5] -= 1. +x[x<-0.5] += 1. +y[y>0.5] -= 1. +y[y<-0.5] += 1. + +# Azimuthal velocity profile ----------------------------- +subplot(231) +scatter(x, y, c=v_norm, cmap="PuBu", edgecolors='face', s=4, vmin=-1., vmax=1.) +text(0.47, 0.47, "${\\rm{Velocity~norm}}$", ha="right", va="top", backgroundcolor="w") +plot([-0.25, 0.25], [0.25, 0.25], '--', color='k', alpha=0.8, lw=2) +plot([-0.25, 0.25], [-0.25, -0.25], '--', color='k', alpha=0.8, lw=2) +plot([0.25, 0.25], [-0.25, 0.25], '--', color='k', alpha=0.8, lw=2) +plot([-0.25, -0.25], [-0.25, 0.25], '--', color='k', alpha=0.8, lw=2) +xlabel("${\\rm{Position}}~x$", labelpad=0) +ylabel("${\\rm{Position}}~y$", labelpad=-7) +xlim(-0.5, 0.5) +ylim(-0.5, 0.5) + +# Radial density profile -------------------------------- +subplot(232) +scatter(x, y, c=rho, cmap="PuBu", edgecolors='face', s=4, vmin=0., vmax=4.) +text(0.47, 0.47, "${\\rm{Density}}$", ha="right", va="top", backgroundcolor="w") +plot([-0.25, 0.25], [0.25, 0.25], '--', color='k', alpha=0.8, lw=2) +plot([-0.25, 0.25], [-0.25, -0.25], '--', color='k', alpha=0.8, lw=2) +plot([0.25, 0.25], [-0.25, 0.25], '--', color='k', alpha=0.8, lw=2) +plot([-0.25, -0.25], [-0.25, 0.25], '--', color='k', alpha=0.8, lw=2) +xlabel("${\\rm{Position}}~x$", labelpad=0) +ylabel("${\\rm{Position}}~y$", labelpad=-7) +xlim(-0.5, 0.5) +ylim(-0.5, 0.5) + +# Radial pressure profile -------------------------------- +subplot(233) +scatter(x, y, c=P, cmap="PuBu", edgecolors='face', s=4, vmin=2, vmax=4) +text(0.47, 0.47, "${\\rm{Pressure}}$", ha="right", va="top", backgroundcolor="w") +plot([-0.25, 0.25], [0.25, 0.25], '--', color='k', alpha=0.8, lw=2) +plot([-0.25, 0.25], [-0.25, -0.25], '--', color='k', alpha=0.8, lw=2) +plot([0.25, 0.25], [-0.25, 0.25], '--', color='k', alpha=0.8, lw=2) +plot([-0.25, -0.25], [-0.25, 0.25], '--', color='k', alpha=0.8, lw=2) +xlabel("${\\rm{Position}}~x$", labelpad=0) +ylabel("${\\rm{Position}}~y$", labelpad=-7) +xlim(-0.5, 0.5) +ylim(-0.5, 0.5) + +# Internal energy profile -------------------------------- +subplot(234) +scatter(x, y, c=u, cmap="PuBu", edgecolors='face', s=4, vmin=0.5, vmax=4.) +text(0.47, 0.47, "${\\rm{Internal~energy}}$", ha="right", va="top", backgroundcolor="w") +plot([-0.25, 0.25], [0.25, 0.25], '--', color='k', alpha=0.8, lw=2) +plot([-0.25, 0.25], [-0.25, -0.25], '--', color='k', alpha=0.8, lw=2) +plot([0.25, 0.25], [-0.25, 0.25], '--', color='k', alpha=0.8, lw=2) +plot([-0.25, -0.25], [-0.25, 0.25], '--', color='k', alpha=0.8, lw=2) +xlabel("${\\rm{Position}}~x$", labelpad=0) +ylabel("${\\rm{Position}}~y$", labelpad=-7) +xlim(-0.5, 0.5) +ylim(-0.5, 0.5) + +# Radial entropy profile -------------------------------- +subplot(235) +scatter(x, y, c=S, cmap="PuBu", edgecolors='face', s=4, vmin=0., vmax=3.) +text(0.47, 0.47, "${\\rm{Entropy}}$", ha="right", va="top", backgroundcolor="w") +plot([-0.25, 0.25], [0.25, 0.25], '--', color='k', alpha=0.8, lw=2) +plot([-0.25, 0.25], [-0.25, -0.25], '--', color='k', alpha=0.8, lw=2) +plot([0.25, 0.25], [-0.25, 0.25], '--', color='k', alpha=0.8, lw=2) +plot([-0.25, -0.25], [-0.25, 0.25], '--', color='k', alpha=0.8, lw=2) +xlabel("${\\rm{Position}}~x$", labelpad=0) +ylabel("${\\rm{Position}}~y$", labelpad=-7) +xlim(-0.5, 0.5) +ylim(-0.5, 0.5) + + +# Information ------------------------------------- +subplot(236, frameon=False) + +text(-0.49, 0.9, "Square test with $\\gamma=%.3f$ at $t=%.2f$"%(gas_gamma,time), fontsize=10) +text(-0.49, 0.8, "Centre:~~~ $(P, \\rho) = (%.3f, %.3f)$"%(P0, rho0), fontsize=10) +text(-0.49, 0.7, "Outskirts: $(P, \\rho) = (%.3f, %.3f)$"%(P1, rho1), fontsize=10) +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("SquareTest.png", dpi=200) diff --git a/examples/HydroTests/SquareTest_2D/run.sh b/examples/HydroTests/SquareTest_2D/run.sh index dae0d742e706d73f3a5efc26a9d82ac59c883757..f5e0160627f7417af4f7bf38e50c03214e2f3c90 100755 --- a/examples/HydroTests/SquareTest_2D/run.sh +++ b/examples/HydroTests/SquareTest_2D/run.sh @@ -4,11 +4,12 @@ if [ ! -e square.hdf5 ] then echo "Generating initial conditions for the square test ..." - python makeIC.py + python makeICDifferentMasses.py fi # Run SWIFT -../../swift --hydro --threads=1 square.yml 2>&1 | tee output.log +../../swift --hydro --threads=4 square.yml 2>&1 | tee output.log # Plot the solution -python plotSolution.py 5 +python plotSolution.py 40 +python makeMovie.py