Commit c4b75e9f authored by Josh Borrow's avatar Josh Borrow Committed by Matthieu Schaller
Browse files

Feedback Energy Injection Changes

parent 0cb55120
......@@ -30,6 +30,7 @@ examples/fof_mpi
examples/*/*/*.xmf
examples/*/*/*.dat
examples/*/*/*.png
examples/*/*/*.pdf
examples/*/*/*.mp4
examples/*/*/*.txt
examples/*/*/*.rst
......
......@@ -17,3 +17,11 @@ This test emulates what the EAGLE model does to particles for feedback, i.e.
+ Heats a single particle to 10^7.5 K
+ Does _not_ switch off cooling
+ Runs to completion.
Running Multiple Tests
----------------------
If you would like to run a suite of tests, try the runs.sh script. You'll
need to set the directories in the parameter file to be one higher, i.e.
../coolingtables rather than ./coolingtables.
......@@ -9,20 +9,20 @@ InternalUnitSystem:
# Parameters governing the time integration
TimeIntegration:
time_begin: 0. # The starting time of the simulation (in internal units).
time_end: 1e-3 # The end time of the simulation (in internal units).
time_end: 1e-4 # The end time of the simulation (in internal units).
dt_min: 1e-9 # 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: 1e-4 # The maximal time-step size of the simulation (in internal units).
# Parameters governing the snapshots
Snapshots:
basename: feedback # Common part of the name of output files
time_first: 0. # Time of the first output (in internal units)
delta_time: 1e-4 # Time difference between consecutive outputs (in internal units)
delta_time: 1e-5 # Time difference between consecutive outputs (in internal units)
compression: 1
# Parameters governing the conserved quantities statistics
Statistics:
delta_time: 1e-3 # Time between statistics output
delta_time: 1e-6 # Time between statistics output
# Parameters for the hydrodynamics scheme
SPH:
......@@ -76,3 +76,15 @@ EAGLECooling:
He_reion_z_centre: 3.5
He_reion_z_sigma: 0.5
He_reion_eV_p_H: 2.0
# 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
......@@ -30,43 +30,44 @@ import numpy as np
# Parameters
gamma = 5.0 / 3.0
initial_density = 0.1 * mh / (cm ** 3)
initial_temperature = 1e4 * K
initial_temperature = 2550 * (5/4) * K # Equilibrium temperature at solar abundance
inject_temperature = 10 ** (7.5) * K
mu = 0.5
particle_mass = 1e6 * msun
unit_system = cosmo_units
file_name = "feedback.hdf5"
if __name__ == "__main__":
unit_system = cosmo_units
file_name = "feedback.hdf5"
# Read in glass file
with h5py.File("glassCube_32.hdf5", "r") as handle:
# Read in glass file
with h5py.File("glassCube_32.hdf5", "r") as handle:
positions = handle["/PartType0/Coordinates"][:]
h = handle["PartType0/SmoothingLength"][:] * 0.3
number_of_particles = len(h)
side_length = (number_of_particles * particle_mass / initial_density) ** (1 / 3)
side_length.convert_to_base(unit_system)
number_of_particles = len(h)
side_length = (number_of_particles * particle_mass / initial_density) ** (1 / 3)
side_length.convert_to_base(unit_system)
print(f"Your box has a side length of {side_length}")
print(f"Your box has a side length of {side_length}")
# Find the central particle
central_particle = np.sum((positions - 0.5) ** 2, axis=1).argmin()
# Find the central particle
central_particle = np.sum((positions - 0.5) ** 2, axis=1).argmin()
# Inject the feedback into that central particle
background_internal_energy = (
# Inject the feedback into that central particle
background_internal_energy = (
(1.0 / (mu * mh)) * (kb / (gamma - 1.0)) * initial_temperature
)
heated_internal_energy = (1.0 / (mu * mh)) * (kb / (gamma - 1.0)) * inject_temperature
internal_energy = np.ones_like(h) * background_internal_energy
internal_energy[central_particle] = heated_internal_energy
)
heated_internal_energy = (1.0 / (mu * mh)) * (kb / (gamma - 1.0)) * inject_temperature
internal_energy = np.ones_like(h) * background_internal_energy
internal_energy[central_particle] = heated_internal_energy
# Now we have all the information we need to set up the initial conditions!
output = Writer(unit_system=unit_system, box_size=side_length)
# Now we have all the information we need to set up the initial conditions!
output = Writer(unit_system=unit_system, box_size=side_length)
output.gas.coordinates = positions * side_length
output.gas.velocities = np.zeros_like(positions) * cm / s
output.gas.smoothing_length = h * side_length
output.gas.internal_energy = internal_energy
output.gas.masses = np.ones_like(h) * particle_mass
output.gas.coordinates = positions * side_length
output.gas.velocities = np.zeros_like(positions) * cm / s
output.gas.smoothing_length = h * side_length
output.gas.internal_energy = internal_energy
output.gas.masses = np.ones_like(h) * particle_mass
output.write(file_name)
output.write(file_name)
"""
Plots the energy from the energy.txt file for this simulation.
"""
import matplotlib.pyplot as plt
import numpy as np
from swiftsimio import load
from unyt import Gyr, erg, mh, kb
from makeIC import gamma, initial_density, initial_temperature, inject_temperature, mu, particle_mass
try:
plt.style.use("mnras_durham")
except:
pass
# Snapshot for grabbing the units.
snapshot = load("feedback_0000.hdf5")
units = snapshot.metadata.units
energy_units = units.mass * units.length ** 2 / (units.time ** 2)
data = np.loadtxt("energy.txt").T
# Assign correct units to each
time = data[0] * units.time
mass = data[1] * units.mass
total_energy = data[2] * energy_units
kinetic_energy = data[3] * energy_units
thermal_energy = data[4] * energy_units
radiative_cool = data[8] * energy_units
# Now we have to figure out how much energy we actually 'injected'
background_internal_energy = (
(1.0 / (mu * mh)) * (kb / (gamma - 1.0)) * initial_temperature
)
heated_internal_energy = (1.0 / (mu * mh)) * (kb / (gamma - 1.0)) * inject_temperature
injected_energy = (heated_internal_energy - background_internal_energy) * particle_mass
# Also want to remove the 'background' energy
n_parts = snapshot.metadata.n_gas
total_background_energy = background_internal_energy * n_parts * particle_mass
# Now we can plot
fig, ax = plt.subplots()
ax.plot(
time.to(Gyr),
(kinetic_energy).to(erg),
label="Kinetic"
)
ax.plot(
time.to(Gyr),
(thermal_energy - total_background_energy).to(erg),
label="Thermal"
)
ax.plot(
time.to(Gyr),
(radiative_cool ).to(erg),
label="Lost to cooling"
)
ax.set_xlim(0, 0.05 * Gyr)
ax.set_xlabel("Time [Gyr]")
ax.set_ylabel("Energy [erg]")
ax.legend()
fig.tight_layout()
fig.savefig("Energy.pdf")
\ No newline at end of file
"""
Plots the energy from the energy.txt file for this simulation.
"""
import matplotlib.pyplot as plt
import numpy as np
from swiftsimio import load
from unyt import Gyr, erg, mh, kb, Myr
from scipy.interpolate import interp1d
from makeIC import gamma, initial_density, initial_temperature, inject_temperature, mu, particle_mass
try:
plt.style.use("mnras_durham")
except:
pass
time_to_plot = 25 * Myr
diffusion_parameters = [0.1 * x for x in range(11)]
plot_directory_name = "default_diffmax"
kinetic_energy_at_time = []
thermal_energy_at_time = []
radiative_energy_at_time = []
for diffusion in diffusion_parameters:
directory_name = f"{plot_directory_name}_{diffusion:1.1f}"
# Snapshot for grabbing the units.
snapshot = load(f"{directory_name}/feedback_0000.hdf5")
units = snapshot.metadata.units
energy_units = units.mass * units.length ** 2 / (units.time ** 2)
data = np.loadtxt(f"{directory_name}/energy.txt").T
# Assign correct units to each
time = data[0] * units.time
mass = data[1] * units.mass
total_energy = data[2] * energy_units
kinetic_energy = data[3] * energy_units
thermal_energy = data[4] * energy_units
radiative_cool = data[8] * energy_units
# Now we have to figure out how much energy we actually 'injected'
background_internal_energy = (
(1.0 / (mu * mh)) * (kb / (gamma - 1.0)) * initial_temperature
)
heated_internal_energy = (1.0 / (mu * mh)) * (kb / (gamma - 1.0)) * inject_temperature
injected_energy = (heated_internal_energy - background_internal_energy) * particle_mass
# Also want to remove the 'background' energy
n_parts = snapshot.metadata.n_gas
total_background_energy = background_internal_energy * n_parts * particle_mass
kinetic_energy_interpolated = interp1d(
time.to(Myr),
kinetic_energy.to(erg)
)
thermal_energy_interpolated = interp1d(
time.to(Myr),
(thermal_energy - total_background_energy).to(erg)
)
radiative_cool_interpolated = interp1d(
time.to(Myr),
radiative_cool.to(erg)
)
kinetic_energy_at_time.append(kinetic_energy_interpolated(time_to_plot.to(Myr)))
thermal_energy_at_time.append(thermal_energy_interpolated(time_to_plot.to(Myr)))
radiative_energy_at_time.append(radiative_cool_interpolated(time_to_plot.to(Myr)))
# Now we can plot
fig, ax = plt.subplots()
ax.plot(
diffusion_parameters,
kinetic_energy_at_time,
label="Kinetic"
)
ax.plot(
diffusion_parameters,
thermal_energy_at_time,
label="Thermal"
)
ax.plot(
diffusion_parameters,
radiative_energy_at_time,
label="Lost to cooling"
)
ax.set_xlim(0, 1.0)
ax.set_xlabel(r"Diffusion $\alpha_{\rm max}$")
ax.set_ylabel(f"Energy in component at $t=${time_to_plot} [erg]")
ax.legend()
fig.tight_layout()
fig.savefig("EnergyFuncDiff.pdf")
......@@ -29,6 +29,7 @@ from scipy import stats
from unyt import cm, s, km, kpc, Pa, msun, K, keV, mh
kPa = 1000 * Pa
plot_radius = 7 * kpc
from swiftsimio import load
......@@ -155,7 +156,7 @@ log = dict(
v_r=False, v_phi=False, u=False, S=False, P=False, rho=False, visc=False, diff=False
)
ylim = dict(
v_r=[-8, 5], u=[3500, 5500], rho=[0.02, 0.15], visc=[0, 2.0], diff=[0, 0.25],
v_r=[-4, 25], u=[4750, 6000], rho=[0.09, 0.16], visc=[0, 2.0], diff=[0, 0.25],
P=[3e-18, 10e-18], S=[-0.5e60, 4e60]
)
......@@ -198,7 +199,7 @@ for key, label in plot.items():
axis.set_xlabel("Radius ($r$) [kpc]", labelpad=0)
axis.set_ylabel(label, labelpad=0)
axis.set_xlim(0.0, 0.7 * boxSize.to(kpc).value)
axis.set_xlim(0.0, plot_radius.to(kpc))
try:
axis.set_ylim(*ylim[key])
......
......@@ -5,3 +5,4 @@
# Plot the solution
python plotSolution.py 5
python plotEnergy.py
#!/bin/bash -l
#SBATCH -J SWIFTDiffusionCalibration
#SBATCH -N 1
#SBATCH -o swift_diffusion.out
#SBATCH -e swift_diffusion.err
#SBATCH -p cosma
#SBATCH -A durham
#SBATCH --exclusive
#SBATCH -t 1:00:00
for diffusion_alpha_max in 0.0 0.1 0.2 0.3 0.4 0.5 0.6 0.7 0.8 0.9 1.0;
do
mkdir default_diffmax_$diffusion_alpha_max
cd default_diffmax_$diffusion_alpha_max
../../../swift --hydro --cooling --limiter --threads=16 --param="SPH:diffusion_alpha_max:${diffusion_alpha_max}" ../feedback.yml 2>&1 | tee output.log
cd ..
mkdir nocool_diffmax_$diffusion_alpha_max
cd nocool_diffmax_$diffusion_alpha_max
../../../swift --hydro --temperature --limiter --threads=16 --param="SPH:diffusion_alpha_max:${diffusion_alpha_max}" ../feedback.yml 2>&1 | tee output.log
cd ..
done
"""
Makes a movie of the output of the blob test.
Josh Borrow (joshua.borrow@durham.ac.uk) 2019
LGPLv3
"""
from swiftsimio import load
from swiftsimio.visualisation import slice
from p_tqdm import p_map
import matplotlib.pyplot as plt
import numpy as np
from matplotlib.colors import LogNorm
from matplotlib.animation import FuncAnimation
info_frames = 15
start_frame = 0
end_frame = 101
resolution = 1024
snapshot_name = "blob"
cmap = "Spectral_r"
text_args = dict(color="black")
# plot = "pressure"
# name = "Pressure $P$"
plot = "density"
name = "Fluid Density $\\rho$"
def get_image(n):
"""
Gets the image for snapshot n, and also returns the associated
SWIFT metadata object.
"""
filename = f"{snapshot_name}_{n:04d}.hdf5"
data = load(filename)
boxsize = data.metadata.boxsize[0].value
output = np.zeros((resolution, resolution * 4), dtype=float)
x, y, z = data.gas.coordinates.value.T
# This is an oblong box but we can only make squares!
for box, box_edges in enumerate([[0.0, 1.1], [0.9, 2.1], [1.9, 3.1], [2.9, 4.0]]):
mask = np.logical_and(x >= box_edges[0], x <= box_edges[1])
masked_x = x[mask] - np.float64(box)
masked_y = y[mask]
masked_z = z[mask]
hsml = data.gas.smoothing_length.value[mask]
if plot == "density":
mass = data.gas.masses.value[mask]
image = slice(
x=masked_y,
y=masked_x,
z=masked_z,
m=mass,
h=hsml,
z_slice=0.5,
res=resolution,
)
else:
quantity = getattr(data.gas, plot).value[mask]
# Need to divide out the particle density for non-projected density quantities
image = scatter(
x=masked_y,
y=masked_x,
z=masked_z,
m=quantity,
h=hsml,
z_slice=0.5,
res=resolution,
) / scatter(
x=masked_y,
y=masked_x,
z=masked_z,
m=np.ones_like(quantity),
h=hsml,
z_slice=0.5,
res=resolution,
)
output[:, box * resolution : (box + 1) * resolution] = image
return output, data.metadata
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{Blob}$ $\\bf{Test}$\n\n"
"$\\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
def time_formatter(metadata):
return f"$t = {metadata.t:2.2f}$"
# Generate the frames and unpack our variables
images, metadata = zip(*p_map(get_image, list(range(start_frame, end_frame))))
# The edges are funny because of the non-periodicity.
central_region = images[0][
resolution // 10 : resolution - resolution // 10,
resolution // 10 : resolution - resolution // 10,
]
norm = LogNorm(vmin=np.min(central_region), vmax=np.max(central_region), clip="black")
fig, ax = plt.subplots(figsize=(8 * 4, 8), dpi=resolution // 8)
fig.subplots_adjust(0, 0, 1, 1)
ax.axis("off")
# Set up the initial state
image = ax.imshow(np.zeros_like(images[0]), norm=norm, cmap=cmap, origin="lower")
description_text = ax.text(
0.5,
0.5,
get_data_dump(metadata[0]),
va="center",
ha="center",
**text_args,
transform=ax.transAxes,
)
time_text = ax.text(
(1 - 0.025 * 0.25),
0.975,
time_formatter(metadata[0]),
**text_args,
va="top",
ha="right",
transform=ax.transAxes,
)
info_text = ax.text(
0.025 * 0.25, 0.975, name, **text_args, va="top", ha="left", transform=ax.transAxes
)
def animate(n):
# Display just our original frames at t < 0
if n >= 0:
image.set_array(images[n])
description_text.set_text("")
time_text.set_text(time_formatter(metadata[n]))
return (image,)
animation = FuncAnimation(
fig, animate, range(start_frame - info_frames, end_frame), interval=40
)
animation.save("blob_slice.mp4")
......@@ -71,7 +71,7 @@ if __name__ == "__main__":
import matplotlib.pyplot as plt
filename = "kelvinhelmholtz"
filename = "kelvinHelmholtz"
dpi = 512
......@@ -93,7 +93,7 @@ if __name__ == "__main__":
fig, ax = plt.subplots(1, 1, figsize=(1, 1), frameon=False)
ax.