
: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/onedim/diffusion_flame_batch.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_onedim_diffusion_flame_batch.py>`
        to download the full example code.

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

.. _sphx_glr_examples_python_onedim_diffusion_flame_batch.py:


Scaling of diffusion flames with pressure and strain rate
=========================================================

This example creates two batches of counterflow diffusion flame simulations.
The first batch computes counterflow flames at increasing pressure, the second
at increasing strain rates.

The tutorial makes use of the scaling rules derived by Fiala and Sattelmayer
(doi:10.1155/2014/484372). Please refer to this publication for a detailed
explanation. Also, please don't forget to cite it if you make use of it.

This example can, for example, be used to iterate to a counterflow diffusion flame to an
awkward pressure and strain rate, or to create the basis for a flamelet table.

Requires: cantera >= 3.2, matplotlib >= 2.0

.. tags:: Python, combustion, 1D flow, extinction, diffusion flame, strained flame,
          saving output, plotting

.. GENERATED FROM PYTHON SOURCE LINES 24-36

.. code-block:: Python


    from pathlib import Path
    import numpy as np
    import matplotlib.pyplot as plt

    import cantera as ct


    class FlameExtinguished(Exception):
        pass









.. GENERATED FROM PYTHON SOURCE LINES 37-42

Initialization
--------------

Set up an initial hydrogen-oxygen counterflow flame at 1 bar and low strain
rate (maximum axial velocity gradient = 2414 1/s)

.. GENERATED FROM PYTHON SOURCE LINES 42-60

.. code-block:: Python


    reaction_mechanism = 'h2o2.yaml'
    gas = ct.Solution(reaction_mechanism)
    width = 18e-3  # 18mm wide
    f = ct.CounterflowDiffusionFlame(gas, width=width)

    # Define the operating pressure and boundary conditions
    f.P = 1.e5  # 1 bar
    f.fuel_inlet.mdot = 0.5  # kg/m^2/s
    f.fuel_inlet.X = 'H2:1'
    f.fuel_inlet.T = 300  # K
    f.oxidizer_inlet.mdot = 3.0  # kg/m^2/s
    f.oxidizer_inlet.X = 'O2:1'
    f.oxidizer_inlet.T = 300  # K

    # Set refinement parameters, if used
    f.set_refine_criteria(ratio=3.0, slope=0.1, curve=0.2, prune=0.03)








.. GENERATED FROM PYTHON SOURCE LINES 61-64

Define a limit for the maximum temperature below which the flame is
considered as extinguished and the computation is aborted
This increases the speed of refinement, if enabled

.. GENERATED FROM PYTHON SOURCE LINES 64-75

.. code-block:: Python

    temperature_limit_extinction = 900  # K


    def interrupt_extinction(t):
        if np.max(f.T) < temperature_limit_extinction:
            raise FlameExtinguished('Flame extinguished')
        return 0.


    f.set_interrupt(interrupt_extinction)








.. GENERATED FROM PYTHON SOURCE LINES 76-77

Initialize and solve

.. GENERATED FROM PYTHON SOURCE LINES 77-103

.. code-block:: Python

    print('Creating the initial solution')
    f.solve(loglevel=0, auto=True)

    # Define output locations
    output_path = Path() / "diffusion_flame_batch_data"
    output_path.mkdir(parents=True, exist_ok=True)

    hdf_output = "native" in ct.hdf_support()
    if hdf_output:
        file_name = output_path / "flame_data.h5"
        file_name.unlink(missing_ok=True)

    def names(test):
        if hdf_output:
            # use internal container structure for HDF
            file_name = output_path / "flame_data.h5"
            return file_name, test
        # use separate files for YAML
        file_name = output_path / f"{test}.yaml".replace("-", "_").replace("/", "_")
        return file_name, "solution"

    # Save to data directory
    file_name, entry = names("initial-solution")
    desc = "Initial hydrogen-oxygen counterflow flame at 1 bar and low strain rate"
    f.save(file_name, name=entry, description=desc, overwrite=True)





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

 .. code-block:: none

    Creating the initial solution




.. GENERATED FROM PYTHON SOURCE LINES 104-108

Batch Pressure Loop
-------------------

Compute counterflow diffusion flames over a range of pressures

.. GENERATED FROM PYTHON SOURCE LINES 108-112

.. code-block:: Python


    # Arbitrarily define a pressure range (in bar)
    p_range = np.round(np.logspace(0, 2, 50), decimals=1)








.. GENERATED FROM PYTHON SOURCE LINES 113-117

Exponents for the initial solution variation with changes in pressure Taken
from Fiala and Sattelmayer (2014). The exponents are adjusted such that the
strain rates increases proportional to :math:`p^{3/2}`, which results in flames
similar with respect to the extinction strain rate.

.. GENERATED FROM PYTHON SOURCE LINES 117-157

.. code-block:: Python

    exp_d_p = -5. / 4.
    exp_u_p = 1. / 4.
    exp_V_p = 3. / 2.
    exp_lam_p = 4.
    exp_mdot_p = 5. / 4.

    # The variable p_previous (in bar) is used for the pressure scaling
    p_previous = f.P / 1.e5
    # Iterate over the pressure range
    for p in p_range:
        print('pressure = {0} bar'.format(p))
        # set new pressure
        f.P = p * 1.e5
        # Create an initial guess based on the previous solution
        rel_pressure_increase = p / p_previous
        # Update grid
        f.flame.grid *= rel_pressure_increase ** exp_d_p
        # Update mass fluxes
        f.fuel_inlet.mdot *= rel_pressure_increase ** exp_mdot_p
        f.oxidizer_inlet.mdot *= rel_pressure_increase ** exp_mdot_p
        # Update velocities
        f.flame.set_values("velocity", f.flame.velocity * rel_pressure_increase ** exp_u_p)
        f.flame.set_values(
            "spreadRate", f.flame.spread_rate * rel_pressure_increase ** exp_V_p)
        # Update pressure curvature
        f.flame.set_values(
            "Lambda", f.flame.radial_pressure_gradient * rel_pressure_increase ** exp_lam_p)

        try:
            # Try solving the flame
            f.solve(loglevel=0)
            file_name, entry = names(f"pressure-loop/{p:05.1f}")
            f.save(file_name, name=entry, description=f"pressure = {p} bar",
                   overwrite=True)
            p_previous = p
        except ct.CanteraError as e:
            print('Error occurred while solving:', e, 'Try next pressure level')
            # If solution failed: Restore the last successful solution and continue
            f.restore(file_name, name=entry)





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

 .. code-block:: none

    pressure = 1.0 bar
    pressure = 1.1 bar
    pressure = 1.2 bar
    pressure = 1.3 bar
    pressure = 1.5 bar
    pressure = 1.6 bar
    pressure = 1.8 bar
    pressure = 1.9 bar
    pressure = 2.1 bar
    pressure = 2.3 bar
    pressure = 2.6 bar
    pressure = 2.8 bar
    pressure = 3.1 bar
    pressure = 3.4 bar
    pressure = 3.7 bar
    pressure = 4.1 bar
    pressure = 4.5 bar
    pressure = 4.9 bar
    pressure = 5.4 bar
    pressure = 6.0 bar
    pressure = 6.6 bar
    pressure = 7.2 bar
    pressure = 7.9 bar
    pressure = 8.7 bar
    pressure = 9.5 bar
    pressure = 10.5 bar
    pressure = 11.5 bar
    pressure = 12.6 bar
    pressure = 13.9 bar
    pressure = 15.3 bar
    pressure = 16.8 bar
    pressure = 18.4 bar
    pressure = 20.2 bar
    pressure = 22.2 bar
    pressure = 24.4 bar
    pressure = 26.8 bar
    pressure = 29.5 bar
    pressure = 32.4 bar
    pressure = 35.6 bar
    pressure = 39.1 bar
    pressure = 42.9 bar
    pressure = 47.1 bar
    pressure = 51.8 bar
    pressure = 56.9 bar
    pressure = 62.5 bar
    pressure = 68.7 bar
    pressure = 75.4 bar
    pressure = 82.9 bar
    pressure = 91.0 bar
    pressure = 100.0 bar




.. GENERATED FROM PYTHON SOURCE LINES 158-163

Strain Rate Loop
----------------
Compute counterflow diffusion flames at increasing strain rates at 1 bar
The strain rate is assumed to increase by 25% in each step until the flame is
extinguished

.. GENERATED FROM PYTHON SOURCE LINES 163-165

.. code-block:: Python

    strain_factor = 1.25








.. GENERATED FROM PYTHON SOURCE LINES 166-168

Exponents for the initial solution variation with changes in strain rate.
Taken from Fiala and Sattelmayer (2014).

.. GENERATED FROM PYTHON SOURCE LINES 168-209

.. code-block:: Python

    exp_d_a = - 1. / 2.
    exp_u_a = 1. / 2.
    exp_V_a = 1.
    exp_lam_a = 2.
    exp_mdot_a = 1. / 2.

    # Restore initial solution
    file_name, entry = names("initial-solution")
    f.restore(file_name, name=entry)

    # Counter to identify the loop
    n = 0
    # Do the strain rate loop
    while np.max(f.T) > temperature_limit_extinction:
        n += 1
        print('strain rate iteration', n)
        # Create an initial guess based on the previous solution
        # Update grid
        f.flame.grid *= strain_factor ** exp_d_a
        # Update mass fluxes
        f.fuel_inlet.mdot *= strain_factor ** exp_mdot_a
        f.oxidizer_inlet.mdot *= strain_factor ** exp_mdot_a
        # Update velocities
        f.flame.set_values("velocity", f.flame.velocity * strain_factor ** exp_u_a)
        f.flame.set_values("spreadRate", f.flame.spread_rate * strain_factor ** exp_V_a)
        # Update pressure curvature
        f.flame.set_values(
            "Lambda", f.flame.radial_pressure_gradient * strain_factor ** exp_lam_a)
        try:
            # Try solving the flame
            f.solve(loglevel=0)
            file_name, entry = names(f"strain-loop/{n:02d}")
            f.save(file_name, name=entry,
                   description=f"strain rate iteration {n}", overwrite=True)
        except FlameExtinguished:
            print('Flame extinguished')
            break
        except ct.CanteraError as e:
            print('Error occurred while solving:', e)
            break





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

 .. code-block:: none

    strain rate iteration 1
    strain rate iteration 2
    strain rate iteration 3
    strain rate iteration 4
    strain rate iteration 5
    strain rate iteration 6
    strain rate iteration 7
    strain rate iteration 8
    strain rate iteration 9
    strain rate iteration 10
    strain rate iteration 11
    strain rate iteration 12
    strain rate iteration 13
    strain rate iteration 14
    strain rate iteration 15
    strain rate iteration 16
    strain rate iteration 17
    strain rate iteration 18
    strain rate iteration 19
    strain rate iteration 20
    strain rate iteration 21
    strain rate iteration 22
    strain rate iteration 23
    strain rate iteration 24
    strain rate iteration 25
    strain rate iteration 26
    Flame extinguished




.. GENERATED FROM PYTHON SOURCE LINES 210-212

Plotting Results
----------------

.. GENERATED FROM PYTHON SOURCE LINES 212-241

.. code-block:: Python


    fig1 = plt.figure()
    fig2 = plt.figure()
    ax1 = fig1.add_subplot(1, 1, 1)
    ax2 = fig2.add_subplot(1, 1, 1)
    p_selected = p_range[::7]

    for p in p_selected:
        file_name, entry = names(f"pressure-loop/{p:05.1f}")
        f.restore(file_name, name=entry)

        # Plot the temperature profiles for selected pressures
        ax1.plot(f.grid / f.grid[-1], f.T, label=f"{p:05.1f} bar")

        # Plot the axial velocity profiles (normalized by the fuel inlet velocity)
        # for selected pressures
        ax2.plot(f.grid / f.grid[-1], f.velocity / f.velocity[0], label=f"{p:05.1f} bar")

    ax1.legend(loc=0)
    ax1.set_xlabel(r'$z/z_{max}$')
    ax1.set_ylabel(r'$T$ [K]')
    fig1.savefig(output_path / "figure_T_p.png")

    ax2.legend(loc=0)
    ax2.set_xlabel(r'$z/z_{max}$')
    ax2.set_ylabel(r'$u/u_f$')
    fig2.savefig(output_path / "figure_u_p.png")
    plt.show()




.. rst-class:: sphx-glr-horizontal


    *

      .. image-sg:: /examples/python/onedim/images/sphx_glr_diffusion_flame_batch_001.png
         :alt: diffusion flame batch
         :srcset: /examples/python/onedim/images/sphx_glr_diffusion_flame_batch_001.png, /examples/python/onedim/images/sphx_glr_diffusion_flame_batch_001_2_00x.png 2.00x
         :class: sphx-glr-multi-img

    *

      .. image-sg:: /examples/python/onedim/images/sphx_glr_diffusion_flame_batch_002.png
         :alt: diffusion flame batch
         :srcset: /examples/python/onedim/images/sphx_glr_diffusion_flame_batch_002.png, /examples/python/onedim/images/sphx_glr_diffusion_flame_batch_002_2_00x.png 2.00x
         :class: sphx-glr-multi-img





.. GENERATED FROM PYTHON SOURCE LINES 242-269

.. code-block:: Python

    fig3 = plt.figure()
    fig4 = plt.figure()
    ax3 = fig3.add_subplot(1, 1, 1)
    ax4 = fig4.add_subplot(1, 1, 1)
    n_selected = range(1, n, 5)
    for n in n_selected:
        file_name, entry = names(f"strain-loop/{n:02d}")
        f.restore(file_name, name=entry)
        a_max = f.strain_rate('max')  # the maximum axial strain rate

        # Plot the temperature profiles for the strain rate loop (selected)
        ax3.plot(f.grid / f.grid[-1], f.T, label=f"{a_max:.2e} 1/s")

        # Plot the axial velocity profiles (normalized by the fuel inlet velocity)
        # for the strain rate loop (selected)
        ax4.plot(f.grid / f.grid[-1], f.velocity / f.velocity[0], label=f"{a_max:.2e} 1/s")

    ax3.legend(loc=0)
    ax3.set_xlabel(r'$z/z_{max}$')
    ax3.set_ylabel(r'$T$ [K]')
    fig3.savefig(output_path / "figure_T_a.png")

    ax4.legend(loc=0)
    ax4.set_xlabel(r'$z/z_{max}$')
    ax4.set_ylabel(r'$u/u_f$')
    fig4.savefig(output_path / "figure_u_a.png")
    plt.show()



.. rst-class:: sphx-glr-horizontal


    *

      .. image-sg:: /examples/python/onedim/images/sphx_glr_diffusion_flame_batch_003.png
         :alt: diffusion flame batch
         :srcset: /examples/python/onedim/images/sphx_glr_diffusion_flame_batch_003.png, /examples/python/onedim/images/sphx_glr_diffusion_flame_batch_003_2_00x.png 2.00x
         :class: sphx-glr-multi-img

    *

      .. image-sg:: /examples/python/onedim/images/sphx_glr_diffusion_flame_batch_004.png
         :alt: diffusion flame batch
         :srcset: /examples/python/onedim/images/sphx_glr_diffusion_flame_batch_004.png, /examples/python/onedim/images/sphx_glr_diffusion_flame_batch_004_2_00x.png 2.00x
         :class: sphx-glr-multi-img






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

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


.. _sphx_glr_download_examples_python_onedim_diffusion_flame_batch.py:

.. only:: html

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

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

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

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

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

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

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


.. only:: html

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

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