Plotting Examples#

There are a variety of methods that can be used to visualize a network.

[1]:
import pynucastro as pyna

Standard view#

Let’s build a quick network that represents He, C, and O burning

[2]:
library = pyna.ReacLibLibrary()
[3]:
sub = library.linking_nuclei(["p", "n", "he4", "c12", "n13", "n14", "o16",
                              "ne20", "ne21", "na23", "mg23", "mg24", "al27",
                              "si27", "si28"])
rc = pyna.RateCollection(libraries=sub)
/opt/hostedtoolcache/Python/3.11.10/x64/lib/python3.11/site-packages/pynucastro/networks/rate_collection.py:576: UserWarning: ReacLib neutron decay rate (<n_to_p_weak_wc12>) does not account for degeneracy at high densities. Consider using tabular rate from Langanke.
  warnings.warn(msg)

The standard network plot of this is:

[4]:
fig = rc.plot()
_images/plot-types_7_0.png

Rotated view#

Since everything lies close to the diagonal, it is hard to see the structure. We can instead look at a rotated view of the network.

While we’re at it, we’ll also color the rates by reaction rate strength

[5]:
rho = 1.e4
T = 1.e8
comp = pyna.Composition(rc.get_nuclei())
comp.set_solar_like()
[6]:
fig = rc.plot(rho, T, comp, rotated=True)
_images/plot-types_10_0.png

This looks a bit crowded, since it is showing all of the links to \({}^4\mathrm{He}\) from reactions of the form \(A(x, \alpha)B\). We can hide those links with hide_xalpha=True

[7]:
fig = rc.plot(rho, T, comp, rotated=True, hide_xalpha=True)
_images/plot-types_12_0.png

We can also plot the edges curved, to help distinguish the forward and reverse rates

[8]:
fig = rc.plot(rho, T, comp, rotated=True, hide_xalpha=True,
              curved_edges=True)
_images/plot-types_14_0.png

We can also label edges if desired

[9]:
edge_labels = {(pyna.Nucleus("he4"), pyna.Nucleus("c12")):
               r"$\alpha(\alpha\alpha,\gamma){}^{12}\mathrm{C}$"}
[10]:
fig = rc.plot(rho, T, comp, rotated=True, hide_xalpha=True,
              edge_labels=edge_labels, size=(1200, 700),
              curved_edges=True)
_images/plot-types_17_0.png

Filters#

We can use a rate filter to show only certain links. For example, to show only links involving proton capture, we can do:

[11]:
fig = rc.plot(rho, T, comp, rotated=True, hide_xalpha=True,
              rate_filter_function=lambda r: pyna.Nucleus("p") in r.reactants)
_images/plot-types_19_0.png

We can also highlight rates using the highlight_filter_function mechanism. This takes a function that operates on a rate and returns True if we wish to highlight the rate (i.e., as if we used a highlighter marker over the line).

Here’s an example where we highlight the rates that have \(Q > 0\)

[12]:
fig = rc.plot(rotated=True, hide_xalpha=True, size=(1500, 600),
              highlight_filter_function=lambda r: r.Q > 0,
              curved_edges=True)
_images/plot-types_21_0.png

Plotting the Jacobian#

For implicit integration, we solve:

\[\dot{\bf Y} = {\bf f}({\bf Y})\]

and the Jacobian, \({\bf J} = \partial {\bf f} / \partial {\bf Y}\) plays an important role in solving for the update.

We can visualize the Jacobian of our network easily. By default, we will show all elements where

\[\frac{\mathrm{max}_{i,j} (|J_{ij}|)}{|J_{ij}|} > 10^{10}\]

but this ratio can be set via the rate_scaling keyword argument.

[13]:
fig = rc.plot_jacobian(rho, T, comp, rate_scaling=1.e50)
_images/plot-types_23_0.png

Plot nuclides on a grid#

Nuclides in a network may also be visualized as cells on a grid of Z vs. N, colored by some quantity. This can be more interpretable for large networks. Calling gridplot without any arguments will just plot the grid - to see anything interesting we need to supply some conditions. Here is a plot of nuclide mass fraction on a log scale, with a 36 square inch figure:

[14]:
rate_names = ["c12(p,g)n13",
              "c13(p,g)n14",
              "n13(,)c13",
              "n13(p,g)o14",
              "n14(p,g)o15",
              "n15(p,a)c12",
              "o14(,)n14",
              "o15(,)n15"]
rates = library.get_rate_by_name(rate_names)
rc = pyna.RateCollection(rates=rates)
[15]:
rho = 1.e4
T = 1.e8
comp = pyna.Composition(rc.get_nuclei())
comp.set_solar_like()
[16]:
fig = rc.gridplot(comp=comp, color_field="X", scale="log", area=36)
_images/plot-types_28_0.png

The plot is configurable through a large number of keyword arguments. Here we want to look at the rates at which nuclides are being created or destroyed, so we color by \(\dot{Y}\), the rate of change of molar abundance. Density and temperature need to be supplied to evaluate the rates. A full list of valid keyword arguments can be found in the API documentation.

[17]:
fig = rc.gridplot(comp=comp, rho=rho, T=T, color_field="ydot", area=36,
                  cmap="RdGy", cbar_bounds=(-0.1, 0.1))
_images/plot-types_30_0.png

Unlike the network plot, this won’t omit hydrogen and helium by default. To just look at the heavier nuclides, we can define a function to filter by proton number. Here we also plot activity, which is the sum of all rates contributions to Ydot ignoring the sign.

[18]:
ff = lambda nuc: nuc.Z > 2
fig = rc.gridplot(comp=comp, rho=rho, T=T, color_field="activity", scale="log",
                  filter_function=ff, area=20, cmap="Blues")
_images/plot-types_32_0.png

Network Chart#

A network chart shows how each rate affects each nucleus

[19]:
fig = rc.plot_network_chart(rho, T, comp)
_images/plot-types_35_0.png