1+ r"""
2+ Sensitivity analysis
3+ ========================================
4+ In this example we simulate an impinging jet flame, premixed ammonia/hydrogen-air flame,
5+ calculating the sensitivity of N2O to the A-factor reaction rate constants.
6+ Requires: cantera >= 3.0.0, pandas
7+ .. tags:: Python, combustion, 1D flow, species reaction, premixed flame,
8+ sensitivity analysis, plotting
9+ """
10+ import cantera as ct
11+ import numpy as np
12+ import pandas as pd
13+ import matplotlib .pyplot as plt
14+
15+ # Define the gas mixture
16+ gas = ct .Solution ("example_data/nakamura.yaml" ) # Use the Nakamura mechanism for ammonia combustion blends
17+ gas .TP = 295 , ct .one_atm
18+ air = "O2:0.21,N2:0.79"
19+ gas .set_equivalence_ratio (phi = 0.6 , fuel = "NH3:0.7, H2:0.3" , oxidizer = air )
20+ flame = ct .ImpingingJet (gas = gas , width = 0.02 )
21+ flame .inlet .mdot = 0.255 * gas .density
22+ flame .surface .T = 493.5
23+ flame .set_initial_guess ("equil" )
24+
25+
26+ # Refine grid to improve accuracy
27+ flame .set_refine_criteria (ratio = 3 , slope = 0.025 , curve = 0.05 )
28+
29+ # Solve the flame
30+ flame .solve (loglevel = 1 , auto = True ) # Increase loglevel for more output
31+
32+ # Plot temperature profile
33+ plt .figure (figsize = (8 , 6 ))
34+ plt .plot (flame .grid * 1e3 , flame .T , label = "Flame Temperature" , color = "red" )
35+ plt .xlabel ("Distance (mm)" )
36+ plt .ylabel ("Temperature (K)" )
37+ plt .title ("Temperature Profile of a Flame" )
38+ plt .grid (True , linestyle = '--' , alpha = 0.7 )
39+ plt .legend ()
40+ plt .tight_layout ()
41+ plt .show ()
42+
43+ # Create a DataFrame to store sensitivity-analysis data
44+ sens = pd .DataFrame (index = gas .reaction_equations (), columns = ["sensitivity" ])
45+
46+ # Use the adjoint method to calculate species sensitivities at a set distance in the flame domain
47+ distance = 0.02
48+ species = "N2O"
49+ sens .sensitivity = flame .get_species_reaction_sensitivities (species , distance )
50+
51+ sens = sens .iloc [(- sens ['sensitivity' ].abs ()).argsort ()]
52+ fig , ax = plt .subplots ()
53+
54+ sens .head (15 ).plot .barh (ax = ax , legend = None )
55+ ax .invert_yaxis () # put the largest sensitivity on top
56+ ax .set_title (f"Sensitivities for { species } Using the Nakamura mechanism" )
57+ ax .set_xlabel (r"Sensitivity: $\frac{\partial\:\ln X_{N2O}}{\partial\:\ln k}$" )
58+ ax .grid (axis = 'x' )
59+ plt .tight_layout ()
60+ plt .show ()
61+
62+
63+ # Forward sensitivities
64+ dk = 3e-4
65+
66+ # get index in the grid at distance
67+ ix = np .argmin (np .abs (flame .grid - distance ))
68+
69+ Su0 = flame .X [gas .species_index (species ), ix ]
70+ fwd = []
71+ for m in range (flame .gas .n_reactions ):
72+ flame .gas .set_multiplier (1.0 ) # reset all multipliers
73+ flame .gas .set_multiplier (1 + dk , m ) # perturb reaction m
74+ flame .solve (loglevel = 0 , refine_grid = False )
75+ Suplus = flame .X [gas .species_index (species ), ix ]
76+ flame .gas .set_multiplier (1 - dk , m ) # perturb reaction m
77+ flame .solve (loglevel = 0 , refine_grid = False )
78+ Suminus = flame .X [gas .species_index (species ), ix ]
79+ fwd .append ((Suplus - Suminus ) / (2 * Su0 * dk ))
80+ sens = pd .DataFrame (index = gas .reaction_equations (), columns = ["sensitivity with forward" ], data = fwd )
81+ sens = sens .iloc [(- sens ['sensitivity with forward' ].abs ()).argsort ()]
82+ fig , ax = plt .subplots ()
83+
84+ sens .head (15 ).plot .barh (ax = ax , legend = None )
85+ ax .invert_yaxis () # put the largest sensitivity on top
86+ ax .set_title (f"Sensitivities for { species } Using Nakamura Mech" )
87+ ax .set_xlabel (r"Sensitivity: $\frac{\partial\:\ln X_{i}}{\partial\:\ln k}$" )
88+ ax .grid (axis = 'x' )
89+ plt .tight_layout ()
90+ plt .show ()
0 commit comments