From b48e7498a90d976783d82bf2db180f3884583371 Mon Sep 17 00:00:00 2001 From: Santosh Shanbhogue Date: Sun, 24 Jul 2016 22:39:09 -0400 Subject: [PATCH 1/6] Corrected method of calculating strain-rate. Added functionality to compute consumption speed --- .../onedim/premixed_counterflow_twin_flame.py | 128 +++++++++++++----- 1 file changed, 94 insertions(+), 34 deletions(-) diff --git a/interfaces/cython/cantera/examples/onedim/premixed_counterflow_twin_flame.py b/interfaces/cython/cantera/examples/onedim/premixed_counterflow_twin_flame.py index 36f23118f9..4b32c3cfee 100644 --- a/interfaces/cython/cantera/examples/onedim/premixed_counterflow_twin_flame.py +++ b/interfaces/cython/cantera/examples/onedim/premixed_counterflow_twin_flame.py @@ -1,20 +1,59 @@ # coding: utf-8 -""" -Simulate two counter-flow jets of reactants shooting into each other. This -simulation differs from the similar premixed_counterflow_flame.py example as the -latter simulates a jet of reactants shooting into products. -""" - import cantera as ct import numpy as np -# This function is called to run the solver +#Trapz is used solely to compute consumption speed +from scipy.integrate import trapz + +import pylab as plt + +#Differentiation function for data that has variable grid spacing +#Used here to compute normal strain-rate +def derivative(x, y): + dydx = np.zeros(y.shape, y.dtype.type) + + dx = np.diff(x) + dy = np.diff(y) + dydx[0:-1] = dy/dx + + dydx[-1] = (y[-1] - y[-2])/(x[-1] - x[-2]) + + return dydx + +def computeStrainRates(oppFlame): + #Compute the derivative of axial velocity to obtain normal strain rate + strainRates = derivative(oppFlame.grid, oppFlame.u) + + #Obtain the location of the max. strain rate upstream of the pre-heat zone. This is the characteristic strain rate + maxStrLocation = abs(strainRates).argmax() + minVelocityPoint = oppFlame.u[:maxStrLocation].argmin() + + #Characteristic Strain Rate = K + strainRatePoint = abs(strainRates[:minVelocityPoint]).argmax() + K = abs(strainRates[strainRatePoint]) + + return strainRates, strainRatePoint, K + +def computeConsumptionSpeed(oppFlame): + + Tb = max(oppFlame.T) + Tu = min(oppFlame.T) + rho_u = max(oppFlame.density) + + integrand = oppFlame.heat_release_rate/oppFlame.cp + + I = trapz(integrand, oppFlame.grid) + Sc = I/(Tb - Tu)/rho_u + + return Sc + +# This function is called to run the solver def solveOpposedFlame(oppFlame, massFlux=0.12, loglevel=1, - ratio=3, slope=0.15, curve=0.25, prune=0.05): - """ - Execute this function to run the Oppposed Flow Simulation This function - takes a CounterFlowTwinPremixedFlame object as the first argument + ratio=2, slope=0.3, curve=0.3, prune=0.05): + """ + Execute this function to run the Oppposed Flow Simulation This function + takes a CounterFlowTwinPremixedFlame object as the first argument """ oppFlame.reactants.mdot = massFlux @@ -23,42 +62,63 @@ def solveOpposedFlame(oppFlame, massFlux=0.12, loglevel=1, oppFlame.show_solution() oppFlame.solve(loglevel, auto=True) - # Compute the strain rate, just before the flame. It also turns out to the - # maximum. This is the strain rate that computations comprare against, like - # when plotting Su vs. K - peakStrain = np.max(np.gradient(oppFlame.u, np.gradient(oppFlame.grid))) - return np.max(oppFlame.T), peakStrain + # Compute the strain rate, just before the flame. This is not necessarily the maximum + # We use the max. strain rate just upstream of the pre-heat zone as this is the strain rate that + # computations comprare against, like when plotting Su vs. K + strainRates, strainRatePoint, K = computeStrainRates(oppFlame) + + return np.max(oppFlame.T), K, strainRatePoint - -# Use the standard GRI3.0 Mechanism for CH4 +# Select the reaction mechanism gas = ct.Solution('gri30.cti') -# Create a CH4/Air premixed mixture with equivalence ratio=0.75, and at room -# temperature and pressure. +# Create a CH4/Air premixed mixture with equivalence ratio=0.75, and at room temperature and pressure + gas.set_equivalence_ratio(0.75, 'CH4', {'O2':1.0, 'N2':3.76}) gas.TP = 300, ct.one_atm -# Set the velocity -axial_velocity = 0.25 # in m/s +# Set the velocity +axial_velocity = 2.0 # in m/s -# Domain half-width of 2.5 cm, meaning the whole domain is 5 cm wide +# Domain half-width of 2.5 cm, meaning the whole domain is 5 cm wide width = 0.025 -# Done with initial conditions - -# Compute the mass flux, as this is what the Flame object requires +# Done with initial conditions +# Compute the mass flux, as this is what the Flame object requires massFlux = gas.density * axial_velocity # units kg/m2/s -# Create the flame object + +# Create the flame object oppFlame = ct.CounterflowTwinPremixedFlame(gas, width=width) -# Now run the solver +# Now run the solver -# The solver returns the peak temperature and strain rate. You can plot/see all -# state space variables by calling oppFlame.foo where foo is T, Y[i] or whatever -# The spatial variable (distance in meters) is in oppFlame.grid Thus to plot +# The solver returns the peak temperature, strain rate and the point which we +# ascribe to the characteristic strain rate. + +# You can plot/see all +# state space variables by calling oppFlame.foo where foo is T, Y[i] or whatever +# The spatial variable (distance in meters) is in oppFlame.grid Thus to plot # temperature vs distance, use oppFlame.grid and oppFlame.T -(T, K) = solveOpposedFlame(oppFlame, massFlux) -print("Peak temperature: {0}".format(T)) -print("Strain Rate: {0}".format(K)) +(T, K, strainRatePoint) = solveOpposedFlame(oppFlame, massFlux, loglevel=1) + +Sc = computeConsumptionSpeed(oppFlame) + +print("Peak temperature: {0} K".format(T)) +print("Strain Rate: {0} 1/s".format(K)) +print("Consumption Speed: {0} cm/s".format(Sc*100)) oppFlame.write_csv("premixed_twin_flame.csv", quiet=False) + +""" +#Uncomment to generate plots and verify the solution +plt.plot(oppFlame.grid, oppFlame.u/max(oppFlame.u),'bs') +plt.plot(oppFlame.grid, oppFlame.T/max(oppFlame.T),'gd') + +plt.axvline(oppFlame.grid[strainRatePoint], color='k') + +plt.title("Normalized velocity and strain-rate. Vertical line is location of characterstic strain rate") + +plt.xlabel('Distance (m)') +plt.show() +""" + From 901d318740269c138084033f4354ac5d280676c9 Mon Sep 17 00:00:00 2001 From: Santosh Shanbhogue Date: Mon, 25 Jul 2016 15:51:52 -0400 Subject: [PATCH 2/6] Removed the need for a scipy function. Removed trailing whitespace --- .../onedim/premixed_counterflow_twin_flame.py | 53 +++++++++---------- 1 file changed, 25 insertions(+), 28 deletions(-) diff --git a/interfaces/cython/cantera/examples/onedim/premixed_counterflow_twin_flame.py b/interfaces/cython/cantera/examples/onedim/premixed_counterflow_twin_flame.py index 4b32c3cfee..90b70131b8 100644 --- a/interfaces/cython/cantera/examples/onedim/premixed_counterflow_twin_flame.py +++ b/interfaces/cython/cantera/examples/onedim/premixed_counterflow_twin_flame.py @@ -3,20 +3,17 @@ import cantera as ct import numpy as np -#Trapz is used solely to compute consumption speed -from scipy.integrate import trapz - import pylab as plt #Differentiation function for data that has variable grid spacing #Used here to compute normal strain-rate def derivative(x, y): dydx = np.zeros(y.shape, y.dtype.type) - + dx = np.diff(x) dy = np.diff(y) dydx[0:-1] = dy/dx - + dydx[-1] = (y[-1] - y[-2])/(x[-1] - x[-2]) return dydx @@ -31,29 +28,29 @@ def computeStrainRates(oppFlame): #Characteristic Strain Rate = K strainRatePoint = abs(strainRates[:minVelocityPoint]).argmax() - K = abs(strainRates[strainRatePoint]) - + K = abs(strainRates[strainRatePoint]) + return strainRates, strainRatePoint, K def computeConsumptionSpeed(oppFlame): - + Tb = max(oppFlame.T) Tu = min(oppFlame.T) rho_u = max(oppFlame.density) integrand = oppFlame.heat_release_rate/oppFlame.cp - I = trapz(integrand, oppFlame.grid) + I = np.trapz(integrand, oppFlame.grid) Sc = I/(Tb - Tu)/rho_u - + return Sc -# This function is called to run the solver +# This function is called to run the solver def solveOpposedFlame(oppFlame, massFlux=0.12, loglevel=1, ratio=2, slope=0.3, curve=0.3, prune=0.05): - """ - Execute this function to run the Oppposed Flow Simulation This function - takes a CounterFlowTwinPremixedFlame object as the first argument + """ + Execute this function to run the Oppposed Flow Simulation This function + takes a CounterFlowTwinPremixedFlame object as the first argument """ oppFlame.reactants.mdot = massFlux @@ -64,12 +61,12 @@ def solveOpposedFlame(oppFlame, massFlux=0.12, loglevel=1, # Compute the strain rate, just before the flame. This is not necessarily the maximum # We use the max. strain rate just upstream of the pre-heat zone as this is the strain rate that - # computations comprare against, like when plotting Su vs. K + # computations comprare against, like when plotting Su vs. K strainRates, strainRatePoint, K = computeStrainRates(oppFlame) - + return np.max(oppFlame.T), K, strainRatePoint -# Select the reaction mechanism +# Select the reaction mechanism gas = ct.Solution('gri30.cti') # Create a CH4/Air premixed mixture with equivalence ratio=0.75, and at room temperature and pressure @@ -77,27 +74,27 @@ def solveOpposedFlame(oppFlame, massFlux=0.12, loglevel=1, gas.set_equivalence_ratio(0.75, 'CH4', {'O2':1.0, 'N2':3.76}) gas.TP = 300, ct.one_atm -# Set the velocity -axial_velocity = 2.0 # in m/s +# Set the velocity +axial_velocity = 2.0 # in m/s -# Domain half-width of 2.5 cm, meaning the whole domain is 5 cm wide +# Domain half-width of 2.5 cm, meaning the whole domain is 5 cm wide width = 0.025 -# Done with initial conditions -# Compute the mass flux, as this is what the Flame object requires +# Done with initial conditions +# Compute the mass flux, as this is what the Flame object requires massFlux = gas.density * axial_velocity # units kg/m2/s -# Create the flame object +# Create the flame object oppFlame = ct.CounterflowTwinPremixedFlame(gas, width=width) -# Now run the solver +# Now run the solver -# The solver returns the peak temperature, strain rate and the point which we +# The solver returns the peak temperature, strain rate and the point which we # ascribe to the characteristic strain rate. -# You can plot/see all -# state space variables by calling oppFlame.foo where foo is T, Y[i] or whatever -# The spatial variable (distance in meters) is in oppFlame.grid Thus to plot +# You can plot/see all +# state space variables by calling oppFlame.foo where foo is T, Y[i] or whatever +# The spatial variable (distance in meters) is in oppFlame.grid Thus to plot # temperature vs distance, use oppFlame.grid and oppFlame.T (T, K, strainRatePoint) = solveOpposedFlame(oppFlame, massFlux, loglevel=1) From 05f95551d5cc12a556f8e5e43aa1eccd3c464de3 Mon Sep 17 00:00:00 2001 From: Santosh Shanbhogue Date: Mon, 25 Jul 2016 16:39:05 -0400 Subject: [PATCH 3/6] Added a line to enable mixture-averaged tranport. The example now works with cantera2.3.0a2 --- .../cantera/examples/onedim/premixed_counterflow_twin_flame.py | 3 +++ 1 file changed, 3 insertions(+) diff --git a/interfaces/cython/cantera/examples/onedim/premixed_counterflow_twin_flame.py b/interfaces/cython/cantera/examples/onedim/premixed_counterflow_twin_flame.py index 90b70131b8..c0a22708d5 100644 --- a/interfaces/cython/cantera/examples/onedim/premixed_counterflow_twin_flame.py +++ b/interfaces/cython/cantera/examples/onedim/premixed_counterflow_twin_flame.py @@ -87,6 +87,9 @@ def solveOpposedFlame(oppFlame, massFlux=0.12, loglevel=1, # Create the flame object oppFlame = ct.CounterflowTwinPremixedFlame(gas, width=width) +# Use mixture-averaged properties +oppFlame.transport_model = 'Mix' + # Now run the solver # The solver returns the peak temperature, strain rate and the point which we From e73800105c545144f2f6e73102fc255a1d9383a5 Mon Sep 17 00:00:00 2001 From: Santosh Shanbhogue Date: Tue, 26 Jul 2016 11:41:10 -0400 Subject: [PATCH 4/6] Reinserted summary, removed redundant 'Mix' transport model and removed code in comments --- .../onedim/premixed_counterflow_twin_flame.py | 23 +++++++------------ 1 file changed, 8 insertions(+), 15 deletions(-) diff --git a/interfaces/cython/cantera/examples/onedim/premixed_counterflow_twin_flame.py b/interfaces/cython/cantera/examples/onedim/premixed_counterflow_twin_flame.py index c0a22708d5..568fb09fb9 100644 --- a/interfaces/cython/cantera/examples/onedim/premixed_counterflow_twin_flame.py +++ b/interfaces/cython/cantera/examples/onedim/premixed_counterflow_twin_flame.py @@ -1,5 +1,11 @@ # coding: utf-8 +""" +-Simulate two counter-flow jets of reactants shooting into each other. This +-simulation differs from the similar premixed_counterflow_flame.py example as the +-latter simulates a jet of reactants shooting into products. +""" + import cantera as ct import numpy as np @@ -87,8 +93,8 @@ def solveOpposedFlame(oppFlame, massFlux=0.12, loglevel=1, # Create the flame object oppFlame = ct.CounterflowTwinPremixedFlame(gas, width=width) -# Use mixture-averaged properties -oppFlame.transport_model = 'Mix' +# Uncomment this line to use a Multi-component formulation. Default is mixture-averaged +#oppFlame.transport_model = 'Mix' # Now run the solver @@ -109,16 +115,3 @@ def solveOpposedFlame(oppFlame, massFlux=0.12, loglevel=1, print("Consumption Speed: {0} cm/s".format(Sc*100)) oppFlame.write_csv("premixed_twin_flame.csv", quiet=False) -""" -#Uncomment to generate plots and verify the solution -plt.plot(oppFlame.grid, oppFlame.u/max(oppFlame.u),'bs') -plt.plot(oppFlame.grid, oppFlame.T/max(oppFlame.T),'gd') - -plt.axvline(oppFlame.grid[strainRatePoint], color='k') - -plt.title("Normalized velocity and strain-rate. Vertical line is location of characterstic strain rate") - -plt.xlabel('Distance (m)') -plt.show() -""" - From 833e85098c795f16c4deeca5bfe9d5ebc601a5d5 Mon Sep 17 00:00:00 2001 From: Santosh Shanbhogue Date: Tue, 26 Jul 2016 12:08:39 -0400 Subject: [PATCH 5/6] Fixed typo, bychanging 'Mix' to 'Multi' --- .../cantera/examples/onedim/premixed_counterflow_twin_flame.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/interfaces/cython/cantera/examples/onedim/premixed_counterflow_twin_flame.py b/interfaces/cython/cantera/examples/onedim/premixed_counterflow_twin_flame.py index 568fb09fb9..4576729488 100644 --- a/interfaces/cython/cantera/examples/onedim/premixed_counterflow_twin_flame.py +++ b/interfaces/cython/cantera/examples/onedim/premixed_counterflow_twin_flame.py @@ -94,7 +94,7 @@ def solveOpposedFlame(oppFlame, massFlux=0.12, loglevel=1, oppFlame = ct.CounterflowTwinPremixedFlame(gas, width=width) # Uncomment this line to use a Multi-component formulation. Default is mixture-averaged -#oppFlame.transport_model = 'Mix' +#oppFlame.transport_model = 'Multi' # Now run the solver From 7b746a7e88866a17858ac67fffff816958cd88c0 Mon Sep 17 00:00:00 2001 From: Santosh Shanbhogue Date: Tue, 26 Jul 2016 13:18:05 -0400 Subject: [PATCH 6/6] Added option to plot results --- .../onedim/premixed_counterflow_twin_flame.py | 34 ++++++++++++++++++- 1 file changed, 33 insertions(+), 1 deletion(-) diff --git a/interfaces/cython/cantera/examples/onedim/premixed_counterflow_twin_flame.py b/interfaces/cython/cantera/examples/onedim/premixed_counterflow_twin_flame.py index 4576729488..44adfc5a52 100644 --- a/interfaces/cython/cantera/examples/onedim/premixed_counterflow_twin_flame.py +++ b/interfaces/cython/cantera/examples/onedim/premixed_counterflow_twin_flame.py @@ -9,7 +9,7 @@ import cantera as ct import numpy as np -import pylab as plt +import sys #Differentiation function for data that has variable grid spacing #Used here to compute normal strain-rate @@ -115,3 +115,35 @@ def solveOpposedFlame(oppFlame, massFlux=0.12, loglevel=1, print("Consumption Speed: {0} cm/s".format(Sc*100)) oppFlame.write_csv("premixed_twin_flame.csv", quiet=False) +#Generate plots to see results, if user desires +if '--plot' in sys.argv[1:]: + + import matplotlib.pyplot as plt + + plt.figure(figsize=(8,6), facecolor='white') + + #Axial Velocity Plot + plt.subplot(1,2,1) + plt.plot(oppFlame.grid, oppFlame.u,'ro') + plt.xlabel('Distance (m)') + plt.ylabel('Axial Velocity (m/s)') + + #Identify the point where the strain rate is calculated + plt.plot(oppFlame.grid[strainRatePoint], oppFlame.u[strainRatePoint],'gs') + plt.annotate('Strain-Rate point', + xy=(oppFlame.grid[strainRatePoint], oppFlame.u[strainRatePoint]), xytext=(0,0), + arrowprops=dict(arrowstyle='->')) + + #Temperature Plot + plt.subplot(1,2,2) + plt.plot(oppFlame.grid, oppFlame.T,'bs') + plt.xlabel('Distance (m)') + plt.ylabel('Temperature (K)') + + plt.tight_layout() + plt.show() + +else: + print('************') + print('Plotting option not enabled. Re-run script with --plot to see key plots.') + print('************')