Plotting results¶
Rendering¶
In SPH we have access to rendering, it can be used in runscripts as follows :
First define the parameters of the plot
pixel_x = 1920
pixel_y = 1080
radius = 5
center = (0.0, 0.0, 0.0)
aspect = pixel_x / pixel_y
pic_range = [-radius * aspect, radius * aspect, -radius, radius]
delta_x = (radius * 2 * aspect, 0.0, 0.0)
delta_y = (0.0, radius * 2, 0.0)
You can do a column integrated plot :
arr_rho = model.render_cartesian_column_integ(
"rho", "f64", center=(0.0, 0.0, 0.0), delta_x=delta_x, delta_y=delta_y, nx=pixel_x, ny=pixel_y
)
Or a slice :
arr_rho = model.render_cartesian_slice(
"rho", "f64", center=(0.0, 0.0, 0.0), delta_x=delta_x, delta_y=delta_y, nx=pixel_x, ny=pixel_y
)
np.save and recover it using np.load
Matplotlib¶
You can then either do a standard plot like so :
import copy, matplotlib
my_cmap = copy.copy(matplotlib.colormaps.get_cmap("gist_heat")) # copy the default cmap
my_cmap.set_bad(color="black")
plt.figure(figsize=(16 / 2, 9 / 2))
res = plt.imshow(arr_rho, cmap=my_cmap, origin="lower", extent=pic_range, norm="log", vmin=1e-9)
cbar = plt.colorbar(res, extend="both")
cbar.set_label(r"$\int \rho \, \mathrm{d} z$ [code unit]")
# or r"$\rho$ [code unit]" for slices
plt.title("t = {:0.3f} [code unit]".format(model.get_time()))
plt.xlabel("x")
plt.ylabel("z")
This should result in something like this :
Or you do the same plot using the splash cinematic way like so :
import copy, matplotlib
my_cmap = copy.copy(matplotlib.colormaps.get_cmap("gist_heat")) # copy the default cmap
my_cmap.set_bad(color="black")
dpi = 200
plt.figure(dpi=dpi)
plt.gca().set_position((0, 0, 1, 1))
plt.gcf().set_size_inches(pixel_x / dpi, pixel_y / dpi)
plt.axis("off")
res = plt.imshow(arr_rho, cmap=my_cmap, origin="lower", extent=pic_range, norm="log", vmin=1e-9)
axins = plt.gca().inset_axes([0.73, 0.1, 0.25, 0.025])
cbar = plt.colorbar(res, cax=axins, orientation="horizontal", extend="both")
cbar.set_label(r"$\int \rho \, \mathrm{d} z$ [code unit]")
from matplotlib.offsetbox import AnchoredText
anchored_text = AnchoredText("t = {:0.3f} [code unit]".format(model.get_time()), loc=2)
plt.gca().add_artist(anchored_text)
Adding sink particles¶
You can also add sink particles to the plot like so
output_list = []
for s in model.get_sinks():
x, y, z = s["pos"]
output_list.append(plt.Circle((x, z), s["accretion_radius"], color="chartreuse", fill=False))
for circle in output_list:
plt.gca().add_artist(circle)
Details of the rendering function¶
In this sample the core function to be used is model.render_cartesian_slice which will
render the slice using the GPU trees. It will return a numpy array with the slice.
The arguments to be passed to the function are :
field name: the field name to renderfield_type: the type of the data to be renderedcenter: the center of the slicedelta_xanddelta_y: the size of the slicenxandny: the number of pixels in the slice
Column density algorithm¶
The standard SPH kernel is defined as being
If we integrate along the z axis we can define a new kernel
Which can can transform as follows
where
We can use a Riemann sum to integrate this function, this gives the following plot
We can see here that already with only 4 points in the riemann sum we approximate the kernel \(g\) fairly well. We can compare the error with a large number of points (1024 here)
indeed only 4 points yield a sufficient precision for the integrated kernel, which make it sufficiently cheap to be usable as is.