#!/usr/bin/env python3
###############################################################################
# This file is part of SWIFT.
# Copyright (c) 2022 Mladen Ivkovic (mladen.ivkovic@hotmail.com)
# 2022 Tsang Keung Chan (chantsangkeung@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 .
#
##############################################################################
# ----------------------------------------------------
# Plot the hydrogen number density, pressure,
# temperature, and hydrogen mass fraction.
# ----------------------------------------------------
import gc
import os
import sys
import matplotlib as mpl
import swiftsimio
import unyt
from matplotlib import pyplot as plt
from matplotlib.colors import LogNorm
from mpl_toolkits.axes_grid1 import make_axes_locatable
# Parameters users should/may tweak
# snapshot basename
snapshot_base = "output"
# parameters for imshow plots
imshow_kwargs = {"origin": "lower"}
# parameters for swiftsimio projections
projection_kwargs = {"resolution": 1000, "parallel": True}
# -----------------------------------------------------------------------
# Read in cmdline arg: Are we plotting only one snapshot, or all?
plot_all = False
try:
snapnr = int(sys.argv[1])
except IndexError:
plot_all = True
mpl.rcParams["text.usetex"] = True
def get_snapshot_list(snapshot_basename="output"):
"""
Find the snapshot(s) that are to be plotted
and return their names as list
"""
snaplist = []
if plot_all:
dirlist = os.listdir()
for f in dirlist:
if f.startswith(snapshot_basename) and f.endswith("hdf5"):
snaplist.append(f)
snaplist = sorted(snaplist)
else:
fname = snapshot_basename + "_" + str(snapnr).zfill(4) + ".hdf5"
if not os.path.exists(fname):
print("Didn't find file", fname)
quit(1)
snaplist.append(fname)
return snaplist
def mean_molecular_weight(XH0, XHp, XHe0, XHep, XHepp):
"""
Determines the mean molecular weight for given
mass fractions of
hydrogen: XH0
H+: XHp
He: XHe0
He+: XHep
He++: XHepp
returns:
mu: mean molecular weight [in atomic mass units]
NOTE: to get the actual mean mass, you still need
to multiply it by m_u, as is tradition in the formulae
"""
# 1/mu = sum_j X_j / A_j * (1 + E_j)
# A_H = 1, E_H = 0
# A_Hp = 1, E_Hp = 1
# A_He = 4, E_He = 0
# A_Hep = 4, E_Hep = 1
# A_Hepp = 4, E_Hepp = 2
one_over_mu = XH0 + 2 * XHp + 0.25 * XHe0 + 0.5 * XHep + 0.75 * XHepp
return 1.0 / one_over_mu
def gas_temperature(u, mu, gamma):
"""
Compute the gas temperature given the specific internal
energy u and the mean molecular weight mu
"""
# Using u = 1 / (gamma - 1) * p / rho
# and p = N/V * kT = rho / (mu * m_u) * kT
T = u * (gamma - 1) * mu * unyt.atomic_mass_unit / unyt.boltzmann_constant
return T.to("K")
def set_colorbar(ax, im):
"""
Adapt the colorbar a bit for axis object and
imshow instance
"""
divider = make_axes_locatable(ax)
cax = divider.append_axes("right", size="5%", pad=0.05)
plt.colorbar(im, cax=cax)
return
def plot_result(filename):
"""
Create and save the plot
"""
print("working on", filename)
data = swiftsimio.load(filename)
meta = data.metadata
global imshow_kwargs
imshow_kwargs["extent"] = [
0.0 * meta.boxsize[0].v,
0.9 * meta.boxsize[0].v,
0.0 * meta.boxsize[1].v,
0.9 * meta.boxsize[1].v,
]
cutoff = int(0.05 * projection_kwargs["resolution"])
mass_map = swiftsimio.visualisation.projection.project_gas(
data, project="masses", **projection_kwargs
)
gamma = meta.hydro_scheme["Adiabatic index"][0]
data.gas.mXHI = data.gas.ion_mass_fractions.HI * data.gas.masses
data.gas.mXHII = data.gas.ion_mass_fractions.HII * data.gas.masses
data.gas.mP = data.gas.pressures * data.gas.masses
data.gas.mrho = data.gas.densities * data.gas.masses
imf = data.gas.ion_mass_fractions
mu = mean_molecular_weight(imf.HI, imf.HII, imf.HeI, imf.HeII, imf.HeIII)
data.gas.mT = (
gas_temperature(data.gas.internal_energies, mu, gamma) * data.gas.masses
)
mass_weighted_hydrogen_map = swiftsimio.visualisation.projection.project_gas(
data, project="mXHI", **projection_kwargs
)
mass_weighted_pressure_map = swiftsimio.visualisation.projection.project_gas(
data, project="mP", **projection_kwargs
)
mass_weighted_density_map = swiftsimio.visualisation.projection.project_gas(
data, project="mrho", **projection_kwargs
)
mass_weighted_temperature_map = swiftsimio.visualisation.projection.project_gas(
data, project="mT", **projection_kwargs
)
hydrogen_map = mass_weighted_hydrogen_map / mass_map
hydrogen_map = hydrogen_map[cutoff:-cutoff, cutoff:-cutoff]
pressure_map = mass_weighted_pressure_map / mass_map
pressure_map = pressure_map[cutoff:-cutoff, cutoff:-cutoff]
pressure_map = pressure_map.to("g/cm/s**2")
density_map = mass_weighted_density_map / mass_map
density_map = density_map[cutoff:-cutoff, cutoff:-cutoff]
density_map = density_map.to("kg/cm**3")
number_density_map = density_map / unyt.proton_mass
temperature_map = mass_weighted_temperature_map / mass_map
temperature_map = temperature_map[cutoff:-cutoff, cutoff:-cutoff]
temperature_map = temperature_map.to("K")
fig = plt.figure(figsize=(12, 12), dpi=200)
figname = filename[:-5] + ".png"
ax1 = fig.add_subplot(221)
ax2 = fig.add_subplot(222)
ax3 = fig.add_subplot(223)
ax4 = fig.add_subplot(224)
try:
im1 = ax1.imshow(
number_density_map.T,
**imshow_kwargs,
norm=LogNorm(vmin=1e-4, vmax=1e-1),
cmap="bone",
)
set_colorbar(ax1, im1)
ax1.set_title(r"Gas Number Density [cm$^{-3}$]")
except (ValueError, TypeError):
print(
filename,
"densities wrong? min",
data.gas.densities.min(),
"max",
data.gas.densities.max(),
)
return
try:
im2 = ax2.imshow(
hydrogen_map.T,
**imshow_kwargs,
norm=LogNorm(vmin=1e-3, vmax=1.0),
cmap="cividis",
)
set_colorbar(ax2, im2)
ax2.set_title("Neutral Hydrogen Mass Fraction [1]")
except (ValueError, TypeError):
print(
filename,
"mass fraction wrong? min",
data.gas.ion_mass_fractions.HI.min(),
"max",
data.gas.ion_mass_fractions.HI.max(),
)
return
try:
im3 = ax3.imshow(
pressure_map.T,
**imshow_kwargs,
norm=LogNorm(vmin=1e-15, vmax=1e-12),
cmap="viridis",
)
set_colorbar(ax3, im3)
ax3.set_title(r"Pressure [g/cm/s$^2$]")
except (ValueError, TypeError):
print(
filename,
"pressures wrong? min",
data.gas.pressures.min(),
"max",
data.gas.pressures.max(),
)
return
try:
im4 = ax4.imshow(
temperature_map.T,
**imshow_kwargs,
norm=LogNorm(vmin=1e2, vmax=4e4),
cmap="inferno",
)
set_colorbar(ax4, im4)
ax4.set_title(r"Temperature [K]")
except (ValueError, TypeError):
print(
filename,
"temperatures wrong? min",
temperature_map.min(),
"max",
temperature_map.max(),
)
return
for ax in [ax1, ax2, ax3, ax4]:
ax.set_xlabel("[kpc]")
ax.set_ylabel("[kpc]")
title = filename.replace("_", r"\_") # exception handle underscore for latex
if meta.cosmology is not None:
title += ", $z$ = {0:.2f}".format(meta.z)
title += ", $t$ = {0:.2f}".format(meta.time.to("Myr"))
fig.suptitle(title)
plt.tight_layout()
plt.savefig(figname)
plt.close()
gc.collect()
return
if __name__ == "__main__":
snaplist = get_snapshot_list(snapshot_base)
# snaplist = snaplist[118:]
for f in snaplist:
plot_result(f)
gc.collect()