
:html_theme.sidebar_secondary.remove:

.. py:currentmodule:: cantera


.. DO NOT EDIT.
.. THIS FILE WAS AUTOMATICALLY GENERATED BY SPHINX-GALLERY.
.. TO MAKE CHANGES, EDIT THE SOURCE PYTHON FILE:
.. "examples/python/kinetics/interactive_path_diagram.py"
.. LINE NUMBERS ARE GIVEN BELOW.

.. only:: html

    .. note::
        :class: sphx-glr-download-link-note

        :ref:`Go to the end <sphx_glr_download_examples_python_kinetics_interactive_path_diagram.py>`
        to download the full example code.

.. rst-class:: sphx-glr-example-title

.. _sphx_glr_examples_python_kinetics_interactive_path_diagram.py:


Interactive Reaction Path Diagrams
==================================

This example uses ``ipywidgets`` to create interactive displays of reaction path
diagrams from Cantera simulations.

Requires: cantera >= 3.2.0, matplotlib >= 2.0, ipywidgets, graphviz, scipy

.. tags:: Python, combustion, reactor network, plotting, reaction path analysis

.. tip::
   To try the interactive features, download the Jupyter notebook version of this
   example: :download:`interactive_path_diagram.ipynb`.

.. GENERATED FROM PYTHON SOURCE LINES 18-48

.. code-block:: Python

    import numpy as np
    from scipy import integrate
    import graphviz
    import os
    from matplotlib import pyplot as plt
    from collections import defaultdict
    import cantera as ct

    print(f"Using Cantera version: {ct.__version__}")

    # Determine if we're running in a Jupyter Notebook. If so, we can enable the interactive
    # diagrams. Otherwise, just draw output for a single set of inputs.
    try:
        from IPython import get_ipython
        if "IPKernelApp" not in get_ipython().config:
            raise ImportError("console")
        if "VSCODE_PID" in os.environ:
            raise ImportError("vscode")
    except (ImportError, AttributeError):
        is_interactive = False
    else:
        is_interactive = True

    if is_interactive:
        from IPython.display import display
        from matplotlib_inline.backend_inline import set_matplotlib_formats
        set_matplotlib_formats('pdf', 'svg')
        from ipywidgets import widgets, interact






.. rst-class:: sphx-glr-script-out

 .. code-block:: none

    Using Cantera version: 3.2.0




.. GENERATED FROM PYTHON SOURCE LINES 49-51

When using Cantera, the first thing you usually need is an object representing some
phase of matter. Here, we'll create a gas mixture using GRI-Mech:

.. GENERATED FROM PYTHON SOURCE LINES 51-54

.. code-block:: Python


    gas = ct.Solution("gri30.yaml")








.. GENERATED FROM PYTHON SOURCE LINES 55-62

Use Shock tube ignition delay measurement conditions corresponding to the experiments
by Spadaccini and Colket [1]_.

* CH₄-C₂H₆-O₂-Ar (3.29%-0.21%-7%-89.5%)
* :math:`\phi` = 1.045
* P = 6.1 - 7.6 atm
* T = 1356 - 1688 K

.. GENERATED FROM PYTHON SOURCE LINES 62-66

.. code-block:: Python


    # Set temperature, pressure, and composition
    gas.TPX = 1550.0, 6.5 * ct.one_atm, "CH4:3.29, C2H6:0.21, O2:7 , Ar:89.5"








.. GENERATED FROM PYTHON SOURCE LINES 67-68

Residence time is close to ignition delay reported by Spadaccini and Colket (1994).

.. GENERATED FROM PYTHON SOURCE LINES 68-71

.. code-block:: Python


    residence_time = 1e-3








.. GENERATED FROM PYTHON SOURCE LINES 72-73

Create a batch reactor object and set solver tolerances

.. GENERATED FROM PYTHON SOURCE LINES 73-79

.. code-block:: Python


    reactor = ct.IdealGasConstPressureReactor(gas, energy="on", clone=False)
    reactor_network = ct.ReactorNet([reactor])
    reactor_network.atol = 1e-12
    reactor_network.rtol = 1e-12








.. GENERATED FROM PYTHON SOURCE LINES 80-81

Store time, pressure, temperature and mole fractions

.. GENERATED FROM PYTHON SOURCE LINES 81-93

.. code-block:: Python


    profiles = defaultdict(list)
    time = 0
    steps = 0
    while time < residence_time:
        profiles["time"].append(time)
        profiles["pressure"].append(reactor.phase.P)
        profiles["temperature"].append(reactor.phase.T)
        profiles["mole_fractions"].append(reactor.phase.X)
        time = reactor_network.step()
        steps += 1








.. GENERATED FROM PYTHON SOURCE LINES 94-99

Interactive reaction path diagram
---------------------------------

When executed as a Jupyter Notebook, the plotted time step, threshold and element can
be changed using the slider provided by IPyWidgets.

.. GENERATED FROM PYTHON SOURCE LINES 99-140

.. code-block:: Python


    def plot_reaction_path_diagrams(plot_step, threshold, details, element):
        P = profiles["pressure"][plot_step]
        T = profiles["temperature"][plot_step]
        X = profiles["mole_fractions"][plot_step]
        time = profiles["time"][plot_step]
        gas.TPX = T, P, X

        diagram = ct.ReactionPathDiagram(gas, element)
        diagram.threshold = threshold
        diagram.title = f"time = {time:.2g} s"

        diagram.show_details = details
        graph = graphviz.Source(diagram.get_dot())
        if is_interactive:
            display(graph)
        else:
            return graph

    if is_interactive:
        interact(
            plot_reaction_path_diagrams,
            plot_step=widgets.IntSlider(value=100, min=0, max=steps-1, step=10),
            threshold=widgets.FloatSlider(value=0.1, min=0.001, max=0.4, step=0.01),
            details=widgets.ToggleButton(),
            element=widgets.Dropdown(
                options=gas.element_names,
                value="C",
                description="Element",
                disabled=False,
            ),
        )
    else:
        # For non-interactive use, just draw the diagram for a specified time step
        diagram = plot_reaction_path_diagrams(
            plot_step=100,
            threshold=0.1,
            details=False,
            element="C"
        )




.. image-sg:: /examples/python/kinetics/images/sphx_glr_interactive_path_diagram_001.svg
   :alt: interactive path diagram
   :srcset: /examples/python/kinetics/images/sphx_glr_interactive_path_diagram_001.svg
   :class: sphx-glr-single-img





.. GENERATED FROM PYTHON SOURCE LINES 141-145

Interactive plot of instantaneous fluxes
----------------------------------------

Find reactions containing the species of interest, C₂H₆ in this case.

.. GENERATED FROM PYTHON SOURCE LINES 145-152

.. code-block:: Python


    C2H6_stoichiometry = np.zeros_like(gas.reactions())
    for i, r in enumerate(gas.reactions()):
        C2H6_moles = r.products.get("C2H6", 0) - r.reactants.get("C2H6", 0)
        C2H6_stoichiometry[i] = C2H6_moles
    C2H6_reaction_indices = C2H6_stoichiometry.nonzero()[0]








.. GENERATED FROM PYTHON SOURCE LINES 153-155

The following cell calculates net rates of progress of reactions containing the
species of interest and stores them.

.. GENERATED FROM PYTHON SOURCE LINES 155-228

.. code-block:: Python


    profiles["C2H6_production_rates"] = []
    for i in range(len(profiles["time"])):
        X = profiles["mole_fractions"][i]
        t = profiles["time"][i]
        T = profiles["temperature"][i]
        P = profiles["pressure"][i]
        gas.TPX = (T, P, X)
        C2H6_production_rates = (
            gas.net_rates_of_progress
            * C2H6_stoichiometry  #  [kmol/m^3/s]
            * gas.volume_mass  # Specific volume [m^3/kg].
        )  # overall, mol/s/g  (g total in reactor, same basis as N_atoms_in_fuel)

        profiles["C2H6_production_rates"].append(
            C2H6_production_rates[C2H6_reaction_indices]
        )

    # Create the instantaneous flux plot. When executed as a Jupyter Notebook, the threshold
    # for annotating of reaction strings can be changed using the slider provided by
    # IPyWidgets.

    plt.rcParams["figure.constrained_layout.use"] = True

    def plot_instantaneous_fluxes(profiles, annotation_cutoff):
        profiles = profiles
        fig = plt.figure(figsize=(6, 6))
        plt.plot(profiles["time"], np.array(profiles["C2H6_production_rates"]))

        for i, C2H6_production_rate in enumerate(
            np.array(profiles["C2H6_production_rates"]).T
        ):
            peak_index = abs(C2H6_production_rate).argmax()
            peak_time = profiles["time"][peak_index]
            peak_C2H6_production = C2H6_production_rate[peak_index]
            reaction_string = gas.reaction_equations(C2H6_reaction_indices)[i]

            if abs(peak_C2H6_production) > annotation_cutoff:
                plt.annotate(
                    reaction_string.replace("<=>", "="),
                    xy=(peak_time, peak_C2H6_production),
                    xytext=(
                        peak_time * 2,
                        (
                            peak_C2H6_production
                            + 0.003
                            * (peak_C2H6_production / abs(peak_C2H6_production))
                            * (abs(peak_C2H6_production) > 0.005)
                            * (peak_C2H6_production < 0.06)
                        ),
                    ),
                    arrowprops=dict(
                        arrowstyle="->",
                        color="black",
                        relpos=(0, 0.6),
                        linewidth=2,
                    ),
                    horizontalalignment="left",
                )

        plt.xlabel("Time (s)")
        plt.ylabel("Net rates of C2H6 production")
        plt.show()

    if is_interactive:
        interact(
            plot_instantaneous_fluxes,
            annotation_cutoff=widgets.FloatSlider(value=0.1, min=1e-2, max=4, steps=10),
            profiles=widgets.fixed(profiles)
        )
    else:
        plot_instantaneous_fluxes(annotation_cutoff=0.1, profiles=profiles)




.. image-sg:: /examples/python/kinetics/images/sphx_glr_interactive_path_diagram_002.png
   :alt: interactive path diagram
   :srcset: /examples/python/kinetics/images/sphx_glr_interactive_path_diagram_002.png, /examples/python/kinetics/images/sphx_glr_interactive_path_diagram_002_2_00x.png 2.00x
   :class: sphx-glr-single-img





.. GENERATED FROM PYTHON SOURCE LINES 229-234

Interactive plot of integrated fluxes
-------------------------------------

When executed as a Jupyter Notebook, the threshold for annotating of reaction strings
can be changed using the slider provided by iPyWidgets

.. GENERATED FROM PYTHON SOURCE LINES 234-278

.. code-block:: Python


    # Integrate fluxes over time
    integrated_fluxes = integrate.cumulative_trapezoid(
        np.array(profiles["C2H6_production_rates"]),
        np.array(profiles["time"]),
        axis=0,
        initial=0,
    )

    def plot_integrated_fluxes(profiles, integrated_fluxes, annotation_cutoff):
        profiles = profiles
        integrated_fluxes = integrated_fluxes
        fig = plt.figure(figsize=(6, 6))
        plt.plot(profiles["time"], integrated_fluxes)
        final_time = profiles["time"][-1]
        for i, C2H6_production in enumerate(integrated_fluxes.T):
            total_C2H6_production = C2H6_production[-1]
            reaction_string = gas.reaction_equations(C2H6_reaction_indices)[i]

            if abs(total_C2H6_production) > annotation_cutoff:
                plt.text(final_time * 1.06, total_C2H6_production, reaction_string,
                         fontsize=8)

        plt.xlabel("Time (s)")
        plt.ylabel("Integrated net rate of progress")
        plt.title("Cumulative C₂H₆ formation")
        plt.show()

    if is_interactive:
        interact(
            plot_integrated_fluxes,
            annotation_cutoff=widgets.FloatLogSlider(
                value=1e-5, min=-5, max=-4, base=10, step=0.1
            ),
            profiles=widgets.fixed(profiles),
            integrated_fluxes=widgets.fixed(integrated_fluxes)
        )
    else:
        plot_integrated_fluxes(
            profiles=profiles,
            integrated_fluxes=integrated_fluxes,
            annotation_cutoff=1e-5
        )




.. image-sg:: /examples/python/kinetics/images/sphx_glr_interactive_path_diagram_003.png
   :alt: Cumulative C₂H₆ formation
   :srcset: /examples/python/kinetics/images/sphx_glr_interactive_path_diagram_003.png, /examples/python/kinetics/images/sphx_glr_interactive_path_diagram_003_2_00x.png 2.00x
   :class: sphx-glr-single-img





.. GENERATED FROM PYTHON SOURCE LINES 279-285

References
----------
.. [1] L. J. Spadaccini and M. B. Colket (1994). "Ignition delay characteristics of
       methane fuels", *Progress in Energy and Combustion Science,* 20:5, 431-460.
       Prog. Energy Combust. Sci. 20, 431.
       https://doi.org/10.1016/0360-1285(94)90011-6.


.. rst-class:: sphx-glr-timing

   **Total running time of the script:** (0 minutes 2.561 seconds)


.. _sphx_glr_download_examples_python_kinetics_interactive_path_diagram.py:

.. only:: html

  .. container:: sphx-glr-footer sphx-glr-footer-example

    .. container:: sphx-glr-download sphx-glr-download-jupyter

      :download:`Download Jupyter notebook: interactive_path_diagram.ipynb <interactive_path_diagram.ipynb>`

    .. container:: sphx-glr-download sphx-glr-download-python

      :download:`Download Python source code: interactive_path_diagram.py <interactive_path_diagram.py>`

    .. container:: sphx-glr-download sphx-glr-download-zip

      :download:`Download zipped: interactive_path_diagram.zip <interactive_path_diagram.zip>`


.. only:: html

 .. rst-class:: sphx-glr-signature

    `Gallery generated by Sphinx-Gallery <https://sphinx-gallery.github.io>`_
