Tutorial 5: plotting#

There are three ways to plot a PyTES solution:

  1. PyBaMM’s QuickPlot, for a quick look at any outputs, with a slider for time;

  2. the standard plots of pytes.plotting, which compare designs the same way every time;

  3. your own matplotlib figures, from the values in the solution.

All three work on the same solutions. Here they are a discharge of the finned-tube battery (Tutorial 2) and a charge of the packed bed (Tutorial 3).

import matplotlib.pyplot as plt
import numpy as np
import pybamm

import pytes
from pytes import plotting

t_eval = np.linspace(0, 3600, 121)
finned = pybamm.Simulation(pytes.SharpFrontModel()).solve([0, 3600], t_interp=t_eval)
bed = pybamm.Simulation(pytes.PackedBedModel()).solve([0, 3600], t_interp=t_eval)

QuickPlot#

pybamm.dynamic_plot plots any outputs of one or more solutions, by name, with a slider for time. Outputs in a nested list share an axis. Outputs that vary in space, such as the fluid temperature along the flow path, are drawn at the time of the slider.

pybamm.dynamic_plot(
    finned,
    [
        ["Inlet temperature [degC]", "Outlet temperature [degC]"],
        "Heat transfer fluid temperature [degC]",
        "Power [kW]",
        "Average liquid fraction",
    ],
    time_unit="minutes",
    spatial_unit="m",
);

For a static figure at a chosen time, as in a report, build a pybamm.QuickPlot and call its plot method with the time, in the plot’s time unit. Outputs that vary in two dimensions are drawn as a map, here the temperature and the liquid fraction across the storage and along the tube, after 25 minutes.

quick_plot = pybamm.QuickPlot(
    finned,
    [
        "Phase-change material temperature [degC]",
        "Liquid fraction",
        ["Inlet temperature [degC]", "Outlet temperature [degC]"],
        "Power [kW]",
    ],
    time_unit="minutes",
    spatial_unit="m",
)
quick_plot.plot(25)
../../_images/63eab3cee670efafe6403d940f2ff98f86519dbd88b0ef749d0084f45f7b31e8.png

Standard plots#

pytes.plotting (installed with pip install "pytes-thermal[plot]") has the plots used most often to compare designs. Every model has the same outputs, so they apply to any model. plot_summary gives the inlet and outlet temperatures, the power and the discharged energy; the bed is charging, so its power and discharged energy are negative.

fig, axes = plotting.plot_summary([finned, bed], labels=["finned tube", "packed bed"])
plt.show()
../../_images/8c2a15614103a0fc26f804bf50408422395f803ab36f54c9b4c045350f3540f1.png

plot_power_against_energy shows how the power a battery delivers falls as it gives up its energy, the key comparison between designs. plot_fluid_profiles gives the fluid temperature along the flow path at chosen times, here the thermal front moving up the bed.

plotting.plot_power_against_energy(finned, labels=["finned tube"])
plotting.plot_fluid_profiles(bed, [0, 600, 1200, 1800, 2400, 3000, 3600])
plt.show()
../../_images/fcece495a8303fc05e40c8c20dbef24926299e8393957c43cfadc96bfee54376.png ../../_images/853643efe52cb3152dc85b7258d2bcb7e6a507ad2eac372575a0a94bf99d2a50.png

Your own figures#

Each output in the solution gives its values at the solution times with .entries. Calling an output gives its value at any time, and at any position for the outputs that vary in space (z along the flow path, y across the storage of a finned tube, r across a capsule). Positions outside the mesh points, output.mesh.nodes, are extrapolated, so it is best to stay within them. With these, any matplotlib figure is a few lines. Here the fluid temperature along the bed over time is drawn as a map, with the PyTES colourmap ember (see the plot colours example for the colour cycles and colourmaps).

Z = pytes.PackedBedModel().default_parameter_values["Bed length [m]"]
fluid = bed["Heat transfer fluid temperature [degC]"]
z = fluid.mesh.nodes
T = fluid(t=t_eval, z=z)

fig, ax = plt.subplots(figsize=(6, 3.5), layout="constrained")
field = ax.pcolormesh(t_eval / 60, z, T, cmap="pytes.ember", shading="nearest")
fig.colorbar(field, label="Fluid temperature [°C]")
ax.set_xlabel("Time [min]")
ax.set_ylabel("Height in the bed [m]")
plt.show()
../../_images/23ac7679aa799d91c7b20380d6c7f5406bfbc6f2e6ad254322f82932e942babe.png

The PyTES colour cycle applies to any figure with a matplotlib style, for one figure with plt.style.context("pytes.thermal") or for every figure with plt.style.use("pytes.thermal").

with plt.style.context("pytes.thermal"):
    fig, ax = plt.subplots(figsize=(6, 4))
    for fraction in [0.2, 0.4, 0.6, 0.8, 1]:
        ax.plot(
            t_eval / 60,
            bed["Heat transfer fluid temperature [degC]"](t=t_eval, z=fraction * Z),
            label=f"{fraction:g} L",
        )
    ax.set_xlabel("Time [min]")
    ax.set_ylabel("Fluid temperature [°C]")
    ax.legend(title="Height")
    plt.show()
../../_images/83dc0128bb1d07d62f04a54e5c9254bb5937c3df54d9d136eaa4c855c120b1f6.png

Next: Tutorial 6: experiments.