Skip to content

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
)
Note here that you can save the obtained numpy array using 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 : plot

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)
plot

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)
plot

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 render
  • field_type: the type of the data to be rendered
  • center: the center of the slice
  • delta_x and delta_y: the size of the slice
  • nx and ny: the number of pixels in the slice

Column density algorithm

The standard SPH kernel is defined as being

\[ W(\mathbf{r},h) = \frac{C_{norm}}{h^3} f\left(q = \vert \frac{\mathbf{r}}{h}\vert \right) \]

If we integrate along the z axis we can define a new kernel

\[ Y(x,y,h) = \frac{C_{norm}}{h^3} \int \mathrm{d}z \, f\left(q = \vert \frac{\mathbf{r}}{h}\vert \right) \]

Which can can transform as follows

\[ Y(x,y,h) = \frac{C_{norm}}{h^2} \int \mathrm{d}q_z \, f\left(\sqrt{q_x^2 + q_y^2 + q_z^2}\right) = \frac{C_{norm}}{h^2} g\left(\sqrt{q_x^2 + q_y^2 }\right) \]

where

\[ g(q_x) = \int \mathrm{d}q_z \, f\left(\sqrt{q_x^2 + q_z^2}\right) \]

We can use a Riemann sum to integrate this function, this gives the following plot

plot_error

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)

plot_error

indeed only 4 points yield a sufficient precision for the integrated kernel, which make it sufficiently cheap to be usable as is.