|
20 | 20 | # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE |
21 | 21 | # SOFTWARE. |
22 | 22 |
|
23 | | -""".. _ref_plug_flow_reactor: |
| 23 | +r""".. _ref_plug_flow_reactor: |
24 | 24 |
|
25 | 25 | =========================================== |
26 | 26 | Simulate NO reduction in combustion exhaust |
|
31 | 31 | as well as its resemblance of an exhaust duct or a tailpipe. |
32 | 32 |
|
33 | 33 | The PFR model is a steady-state open reactor because materials are allowed to |
34 | | -move in and out of the reactor. The solutions are obtained along the length of the reactor |
35 | | -as the inlet materials march toward the reactor exit. Typically, the pressure of the PFR |
36 | | -is fixed. However, Chemkin does permit the use of a pressure profile to enforce a certain |
37 | | -pressure gradient in the PFR. |
38 | | -
|
39 | | -Use the ``PlugFlowReactor_FixedTemperature()`` or ``PlugFlowReactor_EnergyConservation()`` |
40 | | -method to create a PFR. Unlike the closed batch reactor model, which is instantiated by a mixture, |
| 34 | +move in and out of the reactor. The solutions are obtained along the length of |
| 35 | +the reactor as the inlet materials march toward the reactor exit. Typically, |
| 36 | +the pressure of the PFR is fixed. However, Chemkin does permit the use of |
| 37 | +a pressure profile to enforce a certain pressure gradient in the PFR. |
| 38 | +
|
| 39 | +Use the ``PlugFlowReactor_FixedTemperature()`` or |
| 40 | +``PlugFlowReactor_EnergyConservation()`` method to create a PFR. |
| 41 | +Unlike the closed batch reactor model, which is instantiated by a mixture, |
41 | 42 | the open reactor model, such as the PFR model, is initiated by a stream, which is |
42 | 43 | simply a mixture with the addition of the inlet mass/volumetric |
43 | | -flow rate or velocity. You already know how to create a stream if you know how to create |
44 | | -a mixture. You can specify the inlet flow rate using one of these methods: |
| 44 | +flow rate or velocity. You already know how to create a stream if you know |
| 45 | +how to create a mixture. You can specify the inlet flow rate using one of |
| 46 | +these methods: |
45 | 47 | ``velocity()``, ``mass_flowrate()``, ``vol_flowrate()``, or ``sccm()`` |
46 | 48 | (standard cubic centimeters per minute). |
47 | 49 |
|
48 | 50 | This example shows how to use the Chemkin PFR model to study the |
49 | 51 | reduction of nitric oxide (NO) in the combustion exhaust by using the |
50 | | -CH\ :sub:`4` reburning process. This is achieved by injecting CH\ :sub:`4` into the |
51 | | -hot exhaust gas mixture. As the exhaust gas travels along the tubular reactor, the injected |
52 | | -CH\ :sub:`4` is oxidized by the NO to form N\ :sub:`2`\ , CO, and H\ :sub:`2`. This is why this NO reduction process is called *methane reburning*. |
| 52 | +CH\ :sub:`4` reburning process. This is achieved by injecting CH\ :sub:`4` into |
| 53 | +the hot exhaust gas mixture. As the exhaust gas travels along the tubular reactor, |
| 54 | +the injected CH\ :sub:`4` is oxidized by the NO to form |
| 55 | +N\ :sub:`2`\ , CO, and H\ :sub:`2`. This is why this NO reduction process is called |
| 56 | +*methane reburning*. |
53 | 57 | """ |
54 | 58 |
|
55 | 59 | # sphinx_gallery_thumbnail_path = '_static/plot_plug_flow_reactor.png' |
|
58 | 62 | # Import PyChemkin packages and start the logger |
59 | 63 | # ============================================== |
60 | 64 |
|
61 | | -import os |
| 65 | +from pathlib import Path |
62 | 66 | import time |
63 | 67 |
|
64 | 68 | import matplotlib.pyplot as plt # plotting |
|
73 | 77 | from ansys.chemkin.core.logger import logger |
74 | 78 |
|
75 | 79 | # check working directory |
76 | | -current_dir = os.getcwd() |
| 80 | +current_dir = str(Path.cwd()) |
77 | 81 | logger.debug("working directory: " + current_dir) |
78 | 82 | # set interactive mode for plotting the results |
79 | 83 | # interactive = True: display plot |
|
84 | 88 | ######################## |
85 | 89 | # Create a chemistry set |
86 | 90 | # ====================== |
87 | | -# The mechanism to load is the C2 NOx mechanism for the combustion of C1-C2 hydrocarbons. |
88 | | -# The mechanism comes with the standard Ansys Chemkin |
| 91 | +# The mechanism to load is the C2 NOx mechanism for the combustion o |
| 92 | +# C1-C2 hydrocarbons. The mechanism comes with the standard Ansys Chemkin |
89 | 93 | # installation in the ``/reaction/data`` directory. |
90 | 94 |
|
91 | 95 | # set mechanism directory (the default Chemkin mechanism data directory) |
92 | | -data_dir = os.path.join(ck.ansys_dir, "reaction", "data") |
| 96 | +data_dir = Path(ck.ansys_dir) / "reaction" / "data" |
93 | 97 | mechanism_dir = data_dir |
94 | 98 | # create a chemistry set based on the GRI mechanism |
95 | 99 | MyGasMech = ck.Chemistry(label="C2 NOx") |
96 | 100 | # set mechanism input files |
97 | 101 | # including the full file path is recommended |
98 | | -MyGasMech.chemfile = os.path.join(mechanism_dir, "C2_NOx_SRK.inp") |
| 102 | +MyGasMech.chemfile = str(mechanism_dir / "C2_NOx_SRK.inp") |
99 | 103 |
|
100 | 104 | ###################################### |
101 | 105 | # Preprocess the GRI 3.0 chemistry set |
|
109 | 113 | # ================================= |
110 | 114 | # Create a hot exhaust gas mixture by assigning the mole fractions of the |
111 | 115 | # species. A stream is simply a mixture with the addition of |
112 | | -# mass/volumetric flow rate or velocity. Here, the gas composition ``exhaust.X`` is given |
113 | | -# by a recipe consisting of the common species in the combustion exhaust, such as |
114 | | -# CO\ :sub:`2` and H\ :sub:`2`O and the CH\ :sub:`4` injected. The inlet velocity |
115 | | -# is given by ``exhaust.velocity = 26.815``. |
| 116 | +# mass/volumetric flow rate or velocity. Here, the gas composition ``exhaust.X`` |
| 117 | +# is given by a recipe consisting of the common species in the combustion exhaust, |
| 118 | +# such as CO\ :sub:`2` and H\ :sub:`2`O and the CH\ :sub:`4` injected. |
| 119 | +# The inlet velocity is given by ``exhaust.velocity = 26.815``. |
116 | 120 |
|
117 | 121 | # create the inlet (mixture + flow rate) |
118 | 122 | exhaust = Stream(MyGasMech) |
|
136 | 140 | ##################################### |
137 | 141 | # Create the plug flow reactor object |
138 | 142 | # =================================== |
139 | | -# Use the ``PlugFlowReactor_FixedTemperature()`` method to create a plug flow reactor. |
140 | | -# The required input parameter of the open reactor models in PyChemkin |
141 | | -# is the stream, while PyChemkin batch reactor models take a mixture |
142 | | -# as the input parameter. In this case, the exhaust stream is used to create a |
143 | | -# PFR named ``tubereactor``. |
| 143 | +# Use the ``PlugFlowReactor_FixedTemperature()`` method to create |
| 144 | +# a plug flow reactor. The required input parameter of |
| 145 | +# the open reactor models in PyChemkin is the stream, while PyChemkin |
| 146 | +# batch reactor models take a mixture as the input parameter. In this case, |
| 147 | +# the exhaust stream is used to create a PFR named ``tubereactor``. |
144 | 148 | tubereactor = PlugFlowReactor_FixedTemperature(exhaust) |
145 | 149 |
|
146 | 150 | ############################################ |
147 | 151 | # Set up additional reactor model parameters |
148 | 152 | # ========================================== |
149 | | -# For the PFR, the required reactor parameters are the reactor diameter [cm] or the |
150 | | -# cross-sectional flow area [cm2] and the reactor length [cm]. |
151 | | -# The mixture condition and inlet mass flow rate of the inlet are already defined |
152 | | -# by the stream when the ``tubereactor`` PFR is instantiated. |
| 153 | +# For the PFR, the required reactor parameters are the reactor diameter [cm] |
| 154 | +# or the cross-sectional flow area [cm2] and the reactor length [cm]. |
| 155 | +# The mixture condition and inlet mass flow rate of the inlet are already |
| 156 | +# defined by the stream when the ``tubereactor`` PFR is instantiated. |
153 | 157 |
|
154 | 158 | # set PFR diameter [cm] |
155 | 159 | tubereactor.diameter = 5.8431 |
|
168 | 172 | #################### |
169 | 173 | # Set output options |
170 | 174 | # ================== |
171 | | -# You can turn on adaptive solution saving to resolve the steep variations in the solution |
172 | | -# profile. Here, additional solution data points are saved for every **100** internal solver steps. |
| 175 | +# You can turn on adaptive solution saving to resolve the steep variations |
| 176 | +# in the solution profile. Here, additional solution data points are saved |
| 177 | +# for every **100** internal solver steps. |
173 | 178 | # |
174 | 179 | # .. note:: |
175 | | -# By default, distance intervals for both print and save solution are 1/100 of the |
176 | | -# reactor length. In this case, :math:`dt=time/100=0.001`\ . You can change them |
177 | | -# to different values. |
| 180 | +# By default, distance intervals for both print and save solution are |
| 181 | +# 1/100 of the reactor length. In this case, :math:`dt=time/100=0.001`\ . |
| 182 | +# You can change them to different values. |
178 | 183 |
|
179 | 184 | # set distance between saving solution |
180 | 185 | tubereactor.timestep_for_saving_solution = 0.0005 |
|
219 | 224 | # The postprocessing step parses the solution and packages the solution values at each |
220 | 225 | # time point into a mixture. There are two ways to access the solution profiles: |
221 | 226 | # |
222 | | -# - The raw solution profiles (value as a function of distance) are available for distance, |
223 | | -# temperature, pressure, volume, and species mass fractions. |
| 227 | +# - The raw solution profiles (value as a function of distance) are available |
| 228 | +# for distance, temperature, pressure, volume, and species mass fractions. |
224 | 229 | # |
225 | 230 | # - The mixtures permit the use of all property and rate utilities to extract |
226 | 231 | # information such as viscosity, density, and mole fractions. |
227 | 232 | # |
228 | | -# You can use the ``get_solution_variable_profile()`` method to get the raw solution profiles. You |
229 | | -# can get solution mixtures using either the ``get_solution_mixture_at_index()`` method for the |
230 | | -# solution mixture at the given saved location or the ``get_solution_mixture()`` method for the |
231 | | -# solution mixture at the given distance. (In this case, the mixture is constructed by interpolation.) |
| 233 | +# You can use the ``get_solution_variable_profile()`` method to get |
| 234 | +# the raw solution profiles. You can get solution mixtures using either the |
| 235 | +# ``get_solution_mixture_at_index()`` method for the solution mixture at |
| 236 | +# the given saved location or the ``get_solution_mixture()`` method for the |
| 237 | +# solution mixture at the given distance. |
| 238 | +# (In this case, the mixture is constructed by interpolation.) |
232 | 239 | # |
233 | | -# You can get the outlet solution by simply grabbing the solution values at the very last point by |
234 | | -# using \ :math:`(outlet solution index) = (number of solutions) - 1`\. |
| 240 | +# You can get the outlet solution by simply grabbing the solution values |
| 241 | +# at the very last point by using |
| 242 | +# \ :math:`(outlet solution index) = (number of solutions) - 1`\. |
235 | 243 | # |
236 | 244 |
|
237 | 245 | # postprocess the solution profiles |
|
246 | 254 | # get the temperature profile [K] |
247 | 255 | tempprofile = tubereactor.get_solution_variable_profile("temperature") |
248 | 256 | # get the CH4 mass fraction profile |
249 | | -YCH4profile = tubereactor.get_solution_variable_profile("CH4") |
| 257 | +ch4_y_profile = tubereactor.get_solution_variable_profile("CH4") |
250 | 258 | # get the CO mass fraction profile |
251 | | -YCOprofile = tubereactor.get_solution_variable_profile("CO") |
| 259 | +co_y_profile = tubereactor.get_solution_variable_profile("CO") |
252 | 260 | # get the H2O mass fraction profile |
253 | | -YH2Oprofile = tubereactor.get_solution_variable_profile("H2O") |
| 261 | +h2o_y_profile = tubereactor.get_solution_variable_profile("H2O") |
254 | 262 | # get the H2 mass fraction profile |
255 | | -YH2profile = tubereactor.get_solution_variable_profile("H2") |
| 263 | +h2_y_profile = tubereactor.get_solution_variable_profile("H2") |
256 | 264 | # get the NO mass fraction profile |
257 | | -YNOprofile = tubereactor.get_solution_variable_profile("NO") |
| 265 | +no_y_profile = tubereactor.get_solution_variable_profile("NO") |
258 | 266 | # get the N2 mass fraction profile |
259 | | -YN2profile = tubereactor.get_solution_variable_profile("N2") |
| 267 | +n2_y_profile = tubereactor.get_solution_variable_profile("N2") |
260 | 268 |
|
261 | 269 | # inlet NO mass fraction |
262 | | -YNO_inlet = exhaust.Y[MyGasMech.get_specindex("NO")] |
| 270 | +no_y_inlet = exhaust.Y[MyGasMech.get_specindex("NO")] |
263 | 271 | # outlet grid index |
264 | 272 | xout_index = solutionpoints - 1 |
265 | 273 | print("At the reactor inlet: x = 0 [xm]") |
266 | | -print(f"The NO mass fraction = {YNO_inlet}.") |
| 274 | +print(f"The NO mass fraction = {no_y_inlet}.") |
267 | 275 | print(f"At the reactor outlet: x = {xprofile[xout_index]} [cm]") |
268 | | -print(f"The NO mass fraction = {YNOprofile[xout_index]}.") |
| 276 | +print(f"The NO mass fraction = {no_y_profile[xout_index]}.") |
269 | 277 | print( |
270 | 278 | "The NO conversion rate = " |
271 | | - + f"{(YNO_inlet - YNOprofile[xout_index]) / YNO_inlet * 100.0} %\n." |
| 279 | + + f"{(no_y_inlet - no_y_profile[xout_index]) / no_y_inlet * 100.0} %\n." |
272 | 280 | ) |
273 | 281 |
|
274 | 282 | # more involved postprocessing using mixtures |
|
297 | 305 | # Plot the species and the gas velocity profiles along the tubular reactor. |
298 | 306 | # |
299 | 307 | # You can see from the plots that CH\ :sub:`4` is mainly oxidized by NO to form |
300 | | -# N\ :sub:`2` and H\ :sub:`2`\ in the hot exhaust. The gas velocity accelerates because of |
301 | | -# the net increase in total number of moles of gas species due to the chemical reactions. |
302 | | -# You can conduct more in depth analyses of the reaction pathways of the CH\ :sub:`4` reburning |
303 | | -# mechanism by applying other PyChemkin utilities. |
| 308 | +# N\ :sub:`2` and H\ :sub:`2`\ in the hot exhaust. The gas velocity accelerates |
| 309 | +# because of the net increase in total number of moles of gas species due to |
| 310 | +# the chemical reactions. You can conduct more in depth analyses of |
| 311 | +# the reaction pathways of the CH\ :sub:`4` reburning mechanism by |
| 312 | +# applying other PyChemkin utilities. |
304 | 313 | plt.subplots(2, 2, sharex="col", figsize=(12, 6)) |
305 | 314 | plt.suptitle("Constant Temperature Plug-Flow Reactor", fontsize=16) |
306 | 315 | plt.subplot(221) |
307 | | -plt.plot(xprofile, YN2profile, "r-") |
| 316 | +plt.plot(xprofile, n2_y_profile, "r-") |
308 | 317 | plt.ylabel("N2 Mass Fraction") |
309 | 318 | plt.subplot(222) |
310 | | -plt.plot(xprofile, YH2Oprofile, "b-", label="H2O") |
| 319 | +plt.plot(xprofile, h2o_y_profile, "b-", label="H2O") |
311 | 320 | plt.ylabel("H2O Mass Fraction") |
312 | 321 | plt.subplot(223) |
313 | | -plt.plot(xprofile, YNOprofile, "g-", label="NO") |
314 | | -plt.plot(xprofile, YCH4profile, "g:", label="CH4") |
315 | | -plt.plot(xprofile, YH2profile, "g--", label="H2") |
| 322 | +plt.plot(xprofile, no_y_profile, "g-", label="NO") |
| 323 | +plt.plot(xprofile, ch4_y_profile, "g:", label="CH4") |
| 324 | +plt.plot(xprofile, h2_y_profile, "g--", label="H2") |
316 | 325 | plt.legend() |
317 | 326 | plt.xlabel("distance [cm]") |
318 | 327 | plt.ylabel("Mass Fraction") |
|
0 commit comments