.. DO NOT EDIT. .. THIS FILE WAS AUTOMATICALLY GENERATED BY SPHINX-GALLERY. .. TO MAKE CHANGES, EDIT THE SOURCE PYTHON FILE: .. "examples/reactor_network/PSRChain_network.py" .. LINE NUMBERS ARE GIVEN BELOW. .. only:: html .. note:: :class: sphx-glr-download-link-note :ref:`Go to the end ` to download the full example code. .. rst-class:: sphx-glr-example-title .. _sphx_glr_examples_reactor_network_PSRChain_network.py: .. _ref_chain_reactor_network: ==================================================== Use a chain reactor network to model a gas combustor ==================================================== This example shows how to set up and solve a series of linked PSRs (perfectly-stirred reactors). This is the simplest reactor network as it does not contain any recycling streams or outflow splittings. Here is a PSR chain model of a fictional gas combustor: .. figure:: chain_reactor_network.png :scale: 80 % :alt: Chain reactor network The primary inlet stream to the first reactor, the *combustor*, is the fuel-lean methane-air mixture that is formed by mixing the fuel (methane) and the heated air. The exhaust from the combustor enters the second reactor, the *dilution zone*, where the hot combustion products are cooled by the introduction of additional cool air. The cooled and diluted gas mixture in the dilution zone then travel to the third reactor, the *reburning zone*. A mixture of fuel (methane) and carbon dioxide is injected to the gas in the reburning zone, attempting to convert any remaining carbon monoxide or nitric oxide in the exhaust gas to carbon dioxide or nitrogen, respectively. This example uses the ``ReactorNetwork`` module to configure and solve this chain reactor network. This module automatically handles the tasks of running the individual reactors and setting up the inlet to the downstream reactor. .. GENERATED FROM PYTHON SOURCE LINES 53-55 .. code-block:: Python :dedent: 1 .. GENERATED FROM PYTHON SOURCE LINES 57-59 Import PyChemkin packages and start the logger ============================================== .. GENERATED FROM PYTHON SOURCE LINES 59-79 .. code-block:: Python from pathlib import Path import time import ansys.chemkin.core as ck # Chemkin from ansys.chemkin.core import Color from ansys.chemkin.core.hybridreactornetwork import ReactorNetwork as ERN from ansys.chemkin.core.inlet import Stream # external gaseous inlet from ansys.chemkin.core.inlet import adiabatic_mixing_streams from ansys.chemkin.core.logger import logger # Chemkin PSR model (steady-state) from ansys.chemkin.core.stirreactors.PSR import PSRSetResTimeEnergyConservation as Psr # check working directory current_dir = str(Path.cwd()) logger.debug("working directory: " + current_dir) # set verbose mode ck.set_verbose(True) .. GENERATED FROM PYTHON SOURCE LINES 80-85 Create a chemistry set ====================== The mechanism to load is the GRI 3.0 mechanism for methane combustion. This mechanism and its associated data files come with the standard Ansys Chemkin installation in the ``/reaction/data`` directory. .. GENERATED FROM PYTHON SOURCE LINES 85-96 .. code-block:: Python # set mechanism directory (the default Chemkin mechanism data directory) data_dir = Path(ck.ansys_dir) / "reaction" / "data" mechanism_dir = data_dir # create a chemistry set based on the GRI mechanism MyGasMech = ck.Chemistry(label="GRI 3.0") # set mechanism input files # including the full file path is recommended MyGasMech.chemfile = str(mechanism_dir / "grimech30_chem.inp") MyGasMech.thermfile = str(mechanism_dir / "grimech30_thermo.dat") .. GENERATED FROM PYTHON SOURCE LINES 97-99 Preprocess the gasoline chemistry set ===================================== .. GENERATED FROM PYTHON SOURCE LINES 99-103 .. code-block:: Python # preprocess the mechanism files ierror = MyGasMech.preprocess() .. GENERATED FROM PYTHON SOURCE LINES 104-124 Set up gas mixtures based on the species in this chemistry set ============================================================== Create the ``fuel`` and ``air`` streams before setting up the external inlet streams. The fuel in this case is pure methane. The main ``premixed`` inlet stream to the combustor is formed by mixing the ``fuel`` and ``air`` streams adiabatically. The fuel-to-air mass ratio is provided implicitly by the mass flow rates of the two streams. The external inlet to the second reactor, the ``dilution zone``, is simply the ``air`` stream with a different mass flow rate (and different temperature if desirable). The ``reburn_fuel`` stream to inject to the downstream reburning zone is a mixture of methane and carbon dioxide. .. note:: PyChemkin has ``air`` predefined as a convenient way to set up the air stream/mixture in simulations. Use the ``ansys.chemkin.core.Air.x()`` or ``ansys.chemkin.core.Air.y()`` method when the mechanism uses "O2" and "N2" for oxygen and nitrogen. Use the ``ansys.chemkin.core.Air.x('L')`` or ``ansys.chemkin.core.Air.y('L')`` method when the mechanism uses "o2" and "n2" for oxygen and nitrogen. .. GENERATED FROM PYTHON SOURCE LINES 124-140 .. code-block:: Python # fuel is pure methane fuel = Stream(MyGasMech) fuel.temperature = 300.0 # [K] fuel.pressure = 2.1 * ck.P_ATM # [atm] => [dyne/cm2] fuel.x = [("CH4", 1.0)] fuel.mass_flowrate = 3.275 # [g/sec] # air is modeled as a mixture of oxygen and nitrogen air = Stream(MyGasMech) air.temperature = 550.0 # [K] air.pressure = 2.1 * ck.P_ATM # use predefined "air" recipe in mole fractions (with upper cased symbols) air.x = ck.Air.x() air.mass_flowrate = 45.0 # [g/sec] .. GENERATED FROM PYTHON SOURCE LINES 141-149 Create external inlet streams from the mixtures =============================================== Use the ``adiabatic_mixing_streams()`` method to combine the ``fuel`` and the ``air`` streams. The final gas temperature should land between the temperatures of the two source streams. The mass flow rate of the ``premixed`` stream should be the sum of the sources. Use a simple PyChemkin composition recipe to create the ``reburn_fuel`` stream. .. GENERATED FROM PYTHON SOURCE LINES 149-170 .. code-block:: Python # premixed stream for the combustor premixed = adiabatic_mixing_streams(fuel, air) # verify the premixed stream properties print(f"Premixed stream temperature = {premixed.temperature} [K].") print(f"Premixed stream mass flow rate = {premixed.mass_flowrate} [g/sec].") # additional fuel injection for the reburning zone reburn_fuel = Stream(MyGasMech) reburn_fuel.temperature = 300.0 # [K] reburn_fuel.pressure = 2.1 * ck.P_ATM # [atm] => [dyne/cm2] reburn_fuel.x = [("CH4", 0.6), ("CO2", 0.4)] reburn_fuel.mass_flowrate = 0.12 # [g/sec] # find the species index ch4_index = MyGasMech.get_specindex("CH4") o2_index = MyGasMech.get_specindex("O2") no_index = MyGasMech.get_specindex("NO") co_index = MyGasMech.get_specindex("CO") .. GENERATED FROM PYTHON SOURCE LINES 171-192 Create PSRs for each zone ========================= Set up the PSR for each zone one by one with *external inlets only*. For PSR creation, use the ``set_inlet()`` method to add the external inlets to the reactor. A PFR always requires one external inlet when it is instantiated. There are three reactors in the network. From upstream to downstream, they are ``combustor``, ``dilution zone``, and ``reburning zone``. All of them have one external inlet. .. note:: PyChemkin requires that the first reactor/zone must have at least one external inlet. Because the rest of the reactors have at least the through flow from the immediate upstream reactor, they do not require an external inlet. .. note:: The ``Stream`` parameter used to instantiate a PSR is used to establish the *guessed reactor solution* and is modified when the network is solved by the ``ERN``. .. GENERATED FROM PYTHON SOURCE LINES 192-218 .. code-block:: Python # PSR #1: combustor combustor = Psr(premixed, label="combustor") # use the equilibrium state of the inlet gas mixture as the guessed solution combustor.set_estimate_conditions(option="HP") # set PSR residence time (sec): required for PSRSetResTimeEnergyConservation model combustor.residence_time = 2.0 * 1.0e-3 # add external inlet combustor.set_inlet(premixed) # PSR #2: dilution zone dilution = Psr(premixed, label="dilution zone") # set PSR residence time (sec): required for PSRSetResTimeEnergyConservation model dilution.residence_time = 1.5 * 1.0e-3 # add external inlet # assign the correct mass flow rate to the "air" stream air.mass_flowrate = 62.0 # [g/sec] dilution.set_inlet(air) # PSR #3: reburning zone reburn = Psr(premixed, label="reburning zone") # set PSR residence time (sec): required for PSRSetResTimeEnergyConservation model reburn.residence_time = 3.5 * 1.0e-3 # add external inlet reburn.set_inlet(reburn_fuel) .. GENERATED FROM PYTHON SOURCE LINES 219-239 Create the reactor network ========================== Create a hybrid reactor network named ``PSRChain`` and use the ``add_reactor()`` method to add the reactors one by one from upstream to downstream. For a simple chain network such as the one used in this example, you do not need to define the connectivity among the reactors. The reactor network model automatically figures out the through-flow connections. .. note:: - Use the ``show_reactors()`` method to get the list of reactors in the network in the order they are added. - Use the ``remove_reactor()`` method to remove an existing reactor from the network by the reactor ``name/label``. Similarly, use the ``clear_connections()`` method to undo the network connectivity. - The order of the reactor addition is important as it dictates the solution sequence and thus the convergence rate. .. GENERATED FROM PYTHON SOURCE LINES 239-251 .. code-block:: Python # instantiate the chain PSR network as a hybrid reactor network PSRChain = ERN(MyGasMech) # add the reactors from upstream to downstream PSRChain.add_reactor(combustor) PSRChain.add_reactor(dilution) PSRChain.add_reactor(reburn) # list the reactors in the network PSRChain.show_reactors() .. GENERATED FROM PYTHON SOURCE LINES 252-258 Solve the reactor network ========================= Use the ``run()`` method to solve the entire reactor network. The hybrid reactor network solves the reactors one by one in the order that they are added to the network. .. GENERATED FROM PYTHON SOURCE LINES 258-273 .. code-block:: Python # set the start wall time start_time = time.time() # solve the reactor network status = PSRChain.run() if status != 0: print(Color.RED + "Failed to solve the reactor network." + Color.END) exit() # compute the total runtime runtime = time.time() - start_time print() print(f"Total simulation duration: {runtime} [sec]") .. GENERATED FROM PYTHON SOURCE LINES 274-288 Postprocess reactor network results =================================== There are two ways to process results from a reactor network. You can extract the solution of an individual reactor member as a stream by using the ``get_reactor_stream()`` method to get the reactor by its name. Or, you can get the stream properties of a specific network outlet by using the ``get_external_stream()`` method to get the stream by its outlet index. Once you get the solution as a stream, you can use any stream or mixture method to further manipulate the solutions. .. note:: Use the ``number_external_outlets()`` method to find out the number of external outlets of the reactor network. .. GENERATED FROM PYTHON SOURCE LINES 288-309 .. code-block:: Python # get the outlet stream from the reactor network solutions # find the number of external outlet streams from the reactor network print(f"Number of outlet streams = {PSRChain.number_external_outlets}.") # get the first (and the only) external outlet stream properties network_outflow = PSRChain.get_external_stream(1) # set the stream label network_outflow.label = "outflow" # print the desired outlet stream properties print() print("=" * 10) print("outflow") print("=" * 10) print(f"temperature = {network_outflow.temperature} [K]") print(f"mass flow rate = {network_outflow.mass_flowrate} [g/sec]") print(f"CH4 = {network_outflow.x[ch4_index]}") print(f"O2 = {network_outflow.x[o2_index]}") print(f"CO = {network_outflow.x[co_index]}") print(f"NO = {network_outflow.x[no_index]}") .. _sphx_glr_download_examples_reactor_network_PSRChain_network.py: .. only:: html .. container:: sphx-glr-footer sphx-glr-footer-example .. container:: sphx-glr-download sphx-glr-download-jupyter :download:`Download Jupyter notebook: PSRChain_network.ipynb ` .. container:: sphx-glr-download sphx-glr-download-python :download:`Download Python source code: PSRChain_network.py ` .. container:: sphx-glr-download sphx-glr-download-zip :download:`Download zipped: PSRChain_network.zip ` .. only:: html .. rst-class:: sphx-glr-signature `Gallery generated by Sphinx-Gallery `_