[Cython] Translated more samples to use use the new API
This commit is contained in:
parent
7da738d238
commit
840bdfffab
8 changed files with 774 additions and 0 deletions
|
|
@ -0,0 +1,94 @@
|
|||
"""
|
||||
A detached flat flame stabilized at a stagnation point
|
||||
|
||||
This script simulates a lean hydrogen-oxygen flame stabilized in a strained
|
||||
flowfield at an axisymmetric stagnation point on a non-reacting surface. The
|
||||
solution begins with a flame attached to the inlet (burner), and the mass flow
|
||||
rate is progressively increased, causing the flame to detach and move closer
|
||||
to the surface.
|
||||
|
||||
This example illustrates use of the new 'prune' grid refinement parameter,
|
||||
which allows grid points to be removed if they are no longer required to
|
||||
resolve the solution. This is important here, since the flamefront moves as
|
||||
the mass flowrate is increased. Without using 'prune', a large number of grid
|
||||
points would be concentrated upsteam of the flame, where the flamefront had
|
||||
been previously. (To see this, try setting prune to zero.)
|
||||
"""
|
||||
|
||||
import cantera as ct
|
||||
import numpy as np
|
||||
import os
|
||||
|
||||
# parameter values
|
||||
p = 0.05 * ct.one_atm # pressure
|
||||
tburner = 373.0 # burner temperature
|
||||
tsurf = 500.0
|
||||
|
||||
# each mdot value will be solved to convergence, with grid refinement, and
|
||||
# then that solution will be used for the next mdot
|
||||
mdot = [0.06, 0.07, 0.08, 0.09, 0.1, 0.11, 0.12] # kg/m^2/s
|
||||
|
||||
rxnmech = 'h2o2.cti' # reaction mechanism file
|
||||
comp = 'H2:1.8, O2:1, AR:7' # premixed gas composition
|
||||
|
||||
# The solution domain is chosen to be 50 cm, and a point very near the
|
||||
# downstream boundary is added to help with the zero-gradient boundary
|
||||
# condition at this boundary.
|
||||
initial_grid = np.linspace(0.0, 0.2, 12) # m
|
||||
|
||||
tol_ss = [1.0e-5, 1.0e-13] # [rtol atol] for steady-state problem
|
||||
tol_ts = [1.0e-4, 1.0e-9] # [rtol atol] for time stepping
|
||||
loglevel = 1 # amount of diagnostic output (0 to 5)
|
||||
refine_grid = True
|
||||
|
||||
# Grid refinement parameters
|
||||
ratio = 3
|
||||
slope = 0.1
|
||||
curve = 0.2
|
||||
prune = 0.06
|
||||
|
||||
# Set up the problem
|
||||
gas = ct.Solution(rxnmech)
|
||||
|
||||
# set state to that of the unburned gas at the burner
|
||||
gas.TPX = tburner, p, comp
|
||||
|
||||
# Create the stagnation flow object with a non-reactive surface. (To make the
|
||||
# surface reactive, supply a surface reaction mechanism. See example
|
||||
# catalytic_combustion.py for how to do this.)
|
||||
sim = ct.ImpingingJet(gas=gas, grid=initial_grid)
|
||||
|
||||
# set the properties at the inlet
|
||||
sim.inlet.mdot = mdot[0]
|
||||
sim.inlet.X = comp
|
||||
sim.inlet.T = tburner
|
||||
|
||||
# set the surface state
|
||||
sim.surface.T = tsurf
|
||||
|
||||
sim.flame.set_steady_tolerances(default=tol_ss)
|
||||
sim.flame.set_transient_tolerances(default=tol_ts)
|
||||
sim.set_grid_min(1e-4)
|
||||
sim.energy_enabled = False
|
||||
|
||||
sim.set_initial_guess(products='equil') # assume adiabatic equilibrium products
|
||||
sim.show_solution()
|
||||
|
||||
sim.solve(loglevel, refine_grid)
|
||||
|
||||
sim.set_refine_criteria(ratio=ratio, slope=slope, curve=curve, prune=prune)
|
||||
sim.energy_enabled = True
|
||||
|
||||
outfile = 'stflame1.xml'
|
||||
if os.path.exists(outfile):
|
||||
os.remove(outfile)
|
||||
|
||||
for m,md in enumerate(mdot):
|
||||
sim.inlet.mdot = md
|
||||
sim.solve(loglevel,refine_grid)
|
||||
sim.save(outfile, 'mdot{}'.format(m), 'mdot = {} kg/m2/s'.format(md))
|
||||
|
||||
# write the velocity, temperature, and mole fractions to a CSV file
|
||||
sim.write_csv('stflame1_{}.csv'.format(m), quiet=False)
|
||||
|
||||
sim.show_stats()
|
||||
92
interfaces/cython/cantera/examples/reactors/combustor.py
Normal file
92
interfaces/cython/cantera/examples/reactors/combustor.py
Normal file
|
|
@ -0,0 +1,92 @@
|
|||
"""
|
||||
A combustor. Two separate stream - one pure methane and the other air, both at
|
||||
300 K and 1 atm flow into an adiabatic combustor where they mix. We are
|
||||
interested in the steady-state burning solution. Since at 300 K no reaction
|
||||
will occur between methane and air, we need to use an 'igniter' to initiate
|
||||
the chemistry. A simple igniter is a pulsed flow of atomic hydrogen. After the
|
||||
igniter is turned off, the system approaches the steady burning solution.
|
||||
"""
|
||||
|
||||
import math
|
||||
import csv
|
||||
|
||||
import cantera as ct
|
||||
|
||||
# use reaction mechanism GRI-Mech 3.0
|
||||
|
||||
gas = ct.Solution('gri30.xml')
|
||||
|
||||
# create a reservoir for the fuel inlet, and set to pure methane.
|
||||
gas.TPX = 300.0, ct.one_atm, 'CH4:1.0'
|
||||
fuel_in = ct.Reservoir(gas)
|
||||
fuel_mw = gas.mean_molecular_weight
|
||||
|
||||
# use predefined function Air() for the air inlet
|
||||
air = ct.Solution('air.xml')
|
||||
air_in = ct.Reservoir(air)
|
||||
air_mw = air.mean_molecular_weight
|
||||
|
||||
# to ignite the fuel/air mixture, we'll introduce a pulse of radicals. The
|
||||
# steady-state behavior is independent of how we do this, so we'll just use a
|
||||
# stream of pure atomic hydrogen.
|
||||
gas.TPX = 300.0, ct.one_atm, 'H:1.0'
|
||||
igniter = ct.Reservoir(gas)
|
||||
|
||||
# create the combustor, and fill it in initially with N2
|
||||
gas.TPX = 300.0, ct.one_atm, 'N2:1.0'
|
||||
combustor = ct.Reactor(gas)
|
||||
combustor.volume = 1.0
|
||||
|
||||
# create a reservoir for the exhaust
|
||||
exhaust = ct.Reservoir(gas)
|
||||
|
||||
# lean combustion, phi = 0.5
|
||||
equiv_ratio = 0.5
|
||||
|
||||
# compute fuel and air mass flow rates
|
||||
factor = 0.1
|
||||
air_mdot = factor * 9.52 * air_mw
|
||||
fuel_mdot = factor * equiv_ratio * fuel_mw
|
||||
|
||||
# create and install the mass flow controllers. Controllers m1 and m2 provide
|
||||
# constant mass flow rates, and m3 provides a short Gaussian pulse only to
|
||||
# ignite the mixture
|
||||
m1 = ct.MassFlowController(fuel_in, combustor, mdot=fuel_mdot)
|
||||
|
||||
# note that this connects two reactors with different reaction mechanisms and
|
||||
# different numbers of species. Downstream and upstream species are matched by
|
||||
# name.
|
||||
m2 = ct.MassFlowController(air_in, combustor, mdot=air_mdot)
|
||||
|
||||
# The igniter will use a Gaussian time-dependent mass flow rate.
|
||||
fwhm = 0.2
|
||||
amplitude = 0.1
|
||||
t0 = 1.0
|
||||
igniter_mdot = lambda t: amplitude * math.exp(-(t-t0)**2 * 4 * math.log(2) / fwhm**2)
|
||||
m3 = ct.MassFlowController(igniter, combustor, mdot=igniter_mdot)
|
||||
|
||||
# put a valve on the exhaust line to regulate the pressure
|
||||
v = ct.Valve(combustor, exhaust, K=1.0)
|
||||
|
||||
# the simulation only contains one reactor
|
||||
sim = ct.ReactorNet([combustor])
|
||||
|
||||
# take single steps to 6 s, writing the results to a CSV file for later
|
||||
# plotting.
|
||||
tfinal = 6.0
|
||||
tnow = 0.0
|
||||
Tprev = combustor.T
|
||||
tprev = tnow
|
||||
outfile = open('combustor.csv','w')
|
||||
csvwriter = csv.writer(outfile)
|
||||
|
||||
while tnow < tfinal:
|
||||
tnow = sim.step(tfinal)
|
||||
tres = combustor.mass/v.mdot(tnow)
|
||||
Tnow = combustor.T
|
||||
if abs(Tnow - Tprev) > 1.0 or tnow-tprev > 2e-2:
|
||||
tprev = tnow
|
||||
Tprev = Tnow
|
||||
csvwriter.writerow([tnow, combustor.T, tres] +
|
||||
list(combustor.thermo.X))
|
||||
outfile.close()
|
||||
72
interfaces/cython/cantera/examples/reactors/mix1.py
Normal file
72
interfaces/cython/cantera/examples/reactors/mix1.py
Normal file
|
|
@ -0,0 +1,72 @@
|
|||
"""
|
||||
Mixing two streams.
|
||||
|
||||
Since reactors can have multiple inlets and outlets, they can be used to
|
||||
implement mixers, splitters, etc. In this example, air and methane are mixed
|
||||
in stoichiometric proportions. Due to the low temperature, no reactions occur.
|
||||
Note that the air stream and the methane stream use *different* reaction
|
||||
mechanisms, with different numbers of species and reactions. When gas flows
|
||||
from one reactor or reservoir to another one with a different reaction
|
||||
mechanism, species are matched by name. If the upstream reactor contains a
|
||||
species that is not present in the downstream reaction mechanism, it will be
|
||||
ignored. In general, reaction mechanisms for downstream reactors should
|
||||
contain all species that might be present in any upstream reactor.
|
||||
"""
|
||||
|
||||
import cantera as ct
|
||||
|
||||
# Use air for stream a.
|
||||
gas_a = ct.Solution('air.xml')
|
||||
gas_a.TPX = 300.0, ct.one_atm, 'O2:0.21, N2:0.78, AR:0.01'
|
||||
rho_a = gas_a.density
|
||||
|
||||
|
||||
# Use GRI-Mech 3.0 for stream b (methane) and for the mixer. If it is desired
|
||||
# to have a pure mixer, with no chemistry, use instead a reaction mechanism
|
||||
# for gas_b that has no reactions.
|
||||
gas_b = ct.Solution('gri30.xml')
|
||||
gas_b.TPX = 300.0, ct.one_atm, 'CH4:1'
|
||||
rho_b = gas_b.density
|
||||
|
||||
# Create reservoirs for the two inlet streams and for the outlet stream. The
|
||||
# upsteam reservoirs could be replaced by reactors, which might themselves be
|
||||
# connected to reactors further upstream. The outlet reservoir could be
|
||||
# replaced with a reactor with no outlet, if it is desired to integrate the
|
||||
# composition leaving the mixer in time, or by an arbitrary network of
|
||||
# downstream reactors.
|
||||
res_a = ct.Reservoir(gas_a)
|
||||
res_b = ct.Reservoir(gas_b)
|
||||
downstream = ct.Reservoir(gas_b)
|
||||
|
||||
# Create a reactor for the mixer. A reactor is required instead of a
|
||||
# reservoir, since the state will change with time if the inlet mass flow
|
||||
# rates change or if there is chemistry occurring.
|
||||
gas_b.TPX = 300.0, ct.one_atm, 'O2:0.21, N2:0.78, AR:0.01'
|
||||
mixer = ct.Reactor(gas_b)
|
||||
|
||||
# create two mass flow controllers connecting the upstream reservoirs to the
|
||||
# mixer, and set their mass flow rates to values corresponding to
|
||||
# stoichiometric combustion.
|
||||
mfc1 = ct.MassFlowController(res_a, mixer, mdot=rho_a*2.5/0.21)
|
||||
mfc2 = ct.MassFlowController(res_b, mixer, mdot=rho_b*1.0)
|
||||
|
||||
# connect the mixer to the downstream reservoir with a valve.
|
||||
outlet = ct.Valve(mixer, downstream, K=10.0)
|
||||
|
||||
sim = ct.ReactorNet([mixer])
|
||||
|
||||
# Since the mixer is a reactor, we need to integrate in time to reach steady
|
||||
# state. A few residence times should be enough.
|
||||
print('{:>14s} {:>14s} {:>14s} {:>14s} {:>14s}'.format(
|
||||
't [s]', 'T [K]', 'h [J/kg]', 'P [Pa]', 'X_CH4'))
|
||||
|
||||
t = 0.0
|
||||
for n in range(30):
|
||||
tres = mixer.mass/(mfc1.mdot(t) + mfc2.mdot(t))
|
||||
t += 0.5*tres
|
||||
sim.advance(t)
|
||||
print('{:14.5g} {:14.5g} {:14.5g} {:14.5g} {:14.5g}'.format(
|
||||
t, mixer.T, mixer.thermo.h, mixer.thermo.P, mixer.thermo['CH4'].X[0]))
|
||||
|
||||
# view the state of the gas in the mixer
|
||||
print(mixer.thermo.report())
|
||||
90
interfaces/cython/cantera/examples/reactors/piston.py
Normal file
90
interfaces/cython/cantera/examples/reactors/piston.py
Normal file
|
|
@ -0,0 +1,90 @@
|
|||
"""
|
||||
Gas 1: a stoichiometric H2/O2/Ar mixture
|
||||
Gas 2: a wet CO/O2 mixture
|
||||
|
||||
-------------------------------------
|
||||
| || |
|
||||
| || |
|
||||
| gas 1 || gas 2 |
|
||||
| || |
|
||||
| || |
|
||||
-------------------------------------
|
||||
|
||||
The two volumes are connected by an adiabatic free piston. The piston speed is
|
||||
proportional to the pressure difference between the two chambers.
|
||||
|
||||
Note that each side uses a *different* reaction mechanism
|
||||
"""
|
||||
|
||||
import sys
|
||||
|
||||
import cantera as ct
|
||||
|
||||
fmt = '%10.3f %10.1f %10.4f %10.4g %10.4g %10.4g %10.4g'
|
||||
print('%10s %10s %10s %10s %10s %10s %10s' % ('time [s]','T1 [K]','T2 [K]',
|
||||
'V1 [m^3]', 'V2 [m^3]',
|
||||
'V1+V2 [m^3]','X(CO)'))
|
||||
|
||||
gas1 = ct.Solution('h2o2.cti')
|
||||
gas1.TPX = 900.0, ct.one_atm, 'H2:2, O2:1, AR:20'
|
||||
|
||||
gas2 = ct.Solution('gri30.xml')
|
||||
gas2.TPX = 900.0, ct.one_atm, 'CO:2, H2O:0.01, O2:5'
|
||||
|
||||
r1 = ct.Reactor(gas1)
|
||||
r1.volume = 0.5
|
||||
r2 = ct.Reactor(gas2)
|
||||
r2.volume = 0.1
|
||||
w = ct.Wall(r1, r2, K=1.0e3)
|
||||
|
||||
net = ct.ReactorNet([r1, r2])
|
||||
|
||||
tim = []
|
||||
t1 = []
|
||||
t2 = []
|
||||
v1 = []
|
||||
v2 = []
|
||||
v = []
|
||||
xco = []
|
||||
xh2 = []
|
||||
|
||||
for n in range(30):
|
||||
time = (n+1)*0.002
|
||||
net.advance(time)
|
||||
print(fmt % (time, r1.T, r2.T, r1.volume, r2.volume,
|
||||
r1.volume + r2.volume, r2.thermo['CO'].X[0]))
|
||||
|
||||
tim.append(time * 1000)
|
||||
t1.append(r1.T)
|
||||
t2.append(r2.T)
|
||||
v1.append(r1.volume)
|
||||
v2.append(r2.volume)
|
||||
v.append(r1.volume + r2.volume)
|
||||
xco.append(r2.thermo['CO'].X[0])
|
||||
xh2.append(r1.thermo['H2'].X[0])
|
||||
|
||||
|
||||
# plot the results if matplotlib is installed.
|
||||
if '--plot' in sys.argv:
|
||||
import matplotlib.pyplot as plt
|
||||
plt.subplot(2,2,1)
|
||||
plt.plot(tim,t1,'-',tim,t2,'r-')
|
||||
plt.xlabel('Time (ms)')
|
||||
plt.ylabel('Temperature (K)')
|
||||
plt.subplot(2,2,2)
|
||||
plt.plot(tim,v1,'-',tim,v2,'r-',tim,v,'g-')
|
||||
plt.xlabel('Time (ms)')
|
||||
plt.ylabel('Volume (m3)')
|
||||
plt.subplot(2,2,3)
|
||||
plt.plot(tim,xco)
|
||||
plt.xlabel('Time (ms)')
|
||||
plt.ylabel('CO Mole Fraction (right)')
|
||||
plt.subplot(2,2,4)
|
||||
plt.plot(tim,xh2)
|
||||
plt.xlabel('Time (ms)')
|
||||
plt.ylabel('H2 Mole Fraction (left)')
|
||||
plt.tight_layout()
|
||||
plt.show()
|
||||
|
||||
else:
|
||||
print("""To view a plot of these results, run this script with the option --plot""")
|
||||
63
interfaces/cython/cantera/examples/reactors/reactor1.py
Normal file
63
interfaces/cython/cantera/examples/reactors/reactor1.py
Normal file
|
|
@ -0,0 +1,63 @@
|
|||
"""
|
||||
Constant-pressure, adiabatic kinetics simulation.
|
||||
"""
|
||||
|
||||
import sys
|
||||
import numpy as np
|
||||
|
||||
import cantera as ct
|
||||
|
||||
gri3 = ct.Solution('gri30.xml')
|
||||
air = ct.Solution('air.xml')
|
||||
|
||||
gri3.TPX = 1001.0, ct.one_atm, 'H2:2,O2:1,N2:4'
|
||||
r = ct.Reactor(gri3)
|
||||
env = ct.Reservoir(air)
|
||||
|
||||
# Define a wall between the reactor and the environment, and
|
||||
# make it flexible, so that the pressure in the reactor is held
|
||||
# at the environment pressure.
|
||||
w = ct.Wall(r, env)
|
||||
w.expansion_rate_coeff = 1.0e6 # set expansion parameter. dV/dt = KA(P_1 - P_2)
|
||||
w.area = 1.0
|
||||
|
||||
sim = ct.ReactorNet([r])
|
||||
time = 0.0
|
||||
times = np.zeros(100)
|
||||
data = np.zeros((100,4))
|
||||
|
||||
print('%10s %10s %10s %14s' % ('t [s]','T [K]','P [Pa]','u [J/kg]'))
|
||||
for n in range(100):
|
||||
time += 1.e-5
|
||||
sim.advance(time)
|
||||
times[n] = time * 1e3 # time in ms
|
||||
data[n,0] = r.T
|
||||
data[n,1:] = r.thermo['OH','H','H2'].X
|
||||
print('%10.3e %10.3f %10.3f %14.6e' % (sim.time, r.T,
|
||||
r.thermo.P, r.thermo.u))
|
||||
|
||||
# Plot the results if matplotlib is installed.
|
||||
# See http://matplotlib.org/ to get it.
|
||||
if '--plot' in sys.argv[1:]:
|
||||
import matplotlib.pyplot as plt
|
||||
plt.clf()
|
||||
plt.subplot(2, 2, 1)
|
||||
plt.plot(times, data[:,0])
|
||||
plt.xlabel('Time (ms)')
|
||||
plt.ylabel('Temperature (K)')
|
||||
plt.subplot(2, 2, 2)
|
||||
plt.plot(times, data[:,1])
|
||||
plt.xlabel('Time (ms)')
|
||||
plt.ylabel('OH Mole Fraction')
|
||||
plt.subplot(2, 2, 3)
|
||||
plt.plot(times, data[:,2])
|
||||
plt.xlabel('Time (ms)')
|
||||
plt.ylabel('H Mole Fraction')
|
||||
plt.subplot(2, 2, 4)
|
||||
plt.plot(times,data[:,3])
|
||||
plt.xlabel('Time (ms)')
|
||||
plt.ylabel('H2 Mole Fraction')
|
||||
plt.tight_layout()
|
||||
plt.show()
|
||||
else:
|
||||
print("To view a plot of these results, run this script with the option --plot")
|
||||
113
interfaces/cython/cantera/examples/reactors/reactor2.py
Normal file
113
interfaces/cython/cantera/examples/reactors/reactor2.py
Normal file
|
|
@ -0,0 +1,113 @@
|
|||
"""
|
||||
This script simulates the following situation. A closed cylinder with volume 2
|
||||
m^3 is divided into two equal parts by a massless piston that moves with speed
|
||||
proportional to the pressure difference between the two sides. It is
|
||||
initially held in place in the middle. One side is filled with 1000 K argon at
|
||||
20 atm, and the other with a combustible 500 K methane/air mixture at 0.1 atm
|
||||
(phi = 1.1). At t = 0 the piston is released and begins to move due to the
|
||||
large pressure difference, compressing and heating the methane/air mixture,
|
||||
which eventually explodes. At the same time, the argon cools as it expands.
|
||||
The piston is adiabatic, but some heat is lost through the outer cylinder
|
||||
walls to the environment.
|
||||
|
||||
Note that this simulation, being zero-dimensional, takes no account of shock
|
||||
wave propagation. It is somewhat artifical, but nevertheless instructive.
|
||||
"""
|
||||
|
||||
import sys
|
||||
import os
|
||||
import csv
|
||||
import numpy as np
|
||||
|
||||
import cantera as ct
|
||||
|
||||
#-----------------------------------------------------------------------
|
||||
# First create each gas needed, and a reactor or reservoir for each one.
|
||||
#-----------------------------------------------------------------------
|
||||
|
||||
# create an argon gas object and set its state
|
||||
ar = ct.Solution('argon.xml')
|
||||
ar.TP = 1000.0, 20.0 * ct.one_atm
|
||||
|
||||
# create a reactor to represent the side of the cylinder filled with argon
|
||||
r1 = ct.Reactor(ar)
|
||||
|
||||
# create a reservoir for the environment, and fill it with air.
|
||||
env = ct.Reservoir(ct.Solution('air.xml'))
|
||||
|
||||
# use GRI-Mech 3.0 for the methane/air mixture, and set its initial state
|
||||
gri3 = ct.Solution('gri30.xml')
|
||||
gri3.TPX = 500.0, 0.2 * ct.one_atm, 'CH4:1.1, O2:2, N2:7.52'
|
||||
|
||||
# create a reactor for the methane/air side
|
||||
r2 = ct.Reactor(gri3)
|
||||
|
||||
#-----------------------------------------------------------------------------
|
||||
# Now couple the reactors by defining common walls that may move (a piston) or
|
||||
# conduct heat
|
||||
#-----------------------------------------------------------------------------
|
||||
|
||||
# add a flexible wall (a piston) between r2 and r1
|
||||
w = ct.Wall(r2, r1, A=1.0, K=0.5e-4, U=100.0)
|
||||
|
||||
# heat loss to the environment. Heat loss always occur through walls, so we
|
||||
# create a wall separating r1 from the environment, give it a non-zero area,
|
||||
# and specify the overall heat transfer coefficient through the wall.
|
||||
w2 = ct.Wall(r2, env, A=1.0, U=500.0)
|
||||
|
||||
sim = ct.ReactorNet([r1, r2])
|
||||
|
||||
# Now the problem is set up, and we're ready to solve it.
|
||||
print('finished setup, begin solution...')
|
||||
|
||||
time = 0.0
|
||||
n_steps = 300
|
||||
outfile = open('piston.csv', 'w')
|
||||
csvfile = csv.writer(outfile)
|
||||
csvfile.writerow(['time (s)','T1 (K)','P1 (Bar)','V1 (m3)',
|
||||
'T2 (K)','P2 (Bar)','V2 (m3)'])
|
||||
temp = np.zeros((n_steps, 2))
|
||||
pres = np.zeros((n_steps, 2))
|
||||
vol = np.zeros((n_steps, 2))
|
||||
tm = np.zeros(n_steps)
|
||||
|
||||
for n in range(n_steps):
|
||||
time += 4.e-4
|
||||
print(n, time, r2.T)
|
||||
sim.advance(time)
|
||||
tm[n] = time
|
||||
temp[n,:] = r1.T, r2.T
|
||||
pres[n,:] = 1.0e-5*r1.thermo.P, 1.0e-5*r2.thermo.P
|
||||
vol[n,:] = r1.volume, r2.volume
|
||||
csvfile.writerow([tm[n], temp[n,0], pres[n,0], vol[n,0],
|
||||
temp[n,1], pres[n,1], vol[n,1]])
|
||||
outfile.close()
|
||||
print('Output written to file piston.csv')
|
||||
print('Directory: '+os.getcwd())
|
||||
|
||||
if '--plot' in sys.argv:
|
||||
import matplotlib.pyplot as plt
|
||||
plt.clf()
|
||||
plt.subplot(2,2,1)
|
||||
h = plt.plot(tm, temp[:,0],'g-',tm, temp[:,1],'b-')
|
||||
#plt.legend(['Reactor 1','Reactor 2'],2)
|
||||
plt.xlabel('Time (s)')
|
||||
plt.ylabel('Temperature (K)')
|
||||
|
||||
plt.subplot(2,2,2)
|
||||
plt.plot(tm, pres[:,0],'g-',tm, pres[:,1],'b-')
|
||||
#plt.legend(['Reactor 1','Reactor 2'],2)
|
||||
plt.xlabel('Time (s)')
|
||||
plt.ylabel('Pressure (Bar)')
|
||||
|
||||
plt.subplot(2,2,3)
|
||||
plt.plot(tm, vol[:,0],'g-',tm, vol[:,1],'b-')
|
||||
#plt.legend(['Reactor 1','Reactor 2'],2)
|
||||
plt.xlabel('Time (s)')
|
||||
plt.ylabel('Volume (m$^3$)')
|
||||
|
||||
plt.figlegend(h, ['Reactor 1', 'Reactor 2'], loc='lower right')
|
||||
plt.tight_layout()
|
||||
plt.show()
|
||||
else:
|
||||
print("""To view a plot of these results, run this script with the option -plot""")
|
||||
92
interfaces/cython/cantera/examples/reactors/sensitivity1.py
Normal file
92
interfaces/cython/cantera/examples/reactors/sensitivity1.py
Normal file
|
|
@ -0,0 +1,92 @@
|
|||
"""
|
||||
Constant-pressure, adiabatic kinetics simulation with sensitivity analysis
|
||||
"""
|
||||
|
||||
import sys
|
||||
import numpy as np
|
||||
|
||||
import cantera as ct
|
||||
|
||||
gri3 = ct.Solution('gri30.xml')
|
||||
temp = 1500.0
|
||||
pres = ct.one_atm
|
||||
|
||||
gri3.TPX = temp, pres, 'CH4:0.1, O2:2, N2:7.52'
|
||||
r = ct.Reactor(gri3)
|
||||
|
||||
air = ct.Solution('air.xml')
|
||||
air.TP = temp, pres
|
||||
env = ct.Reservoir(air)
|
||||
|
||||
# Define a wall between the reactor and the environment, and make it flexible,
|
||||
# so that the pressure in the reactor is held at the environment pressure.
|
||||
w = ct.Wall(r, env)
|
||||
w.expansion_rate_coeff = 1.0e6 # set expansion parameter. dV/dt = KA(P_1 - P_2)
|
||||
w.area = 1.0
|
||||
|
||||
sim = ct.ReactorNet([r])
|
||||
|
||||
# enable sensitivity with respect to the rates of the first 10
|
||||
# reactions (reactions 0 through 9)
|
||||
for i in range(10):
|
||||
r.add_sensitivity_reaction(i)
|
||||
|
||||
# set the tolerances for the solution and for the sensitivity coefficients
|
||||
sim.rtol = 1.0e-6
|
||||
sim.atol = 1.0e-15
|
||||
sim.rtol_sensitivity = 1.0e-6
|
||||
sim.atol_sensitivity = 1.0e-6
|
||||
|
||||
|
||||
n_times = 400
|
||||
tim = np.zeros(n_times)
|
||||
data = np.zeros((n_times,6))
|
||||
|
||||
time = 0.0
|
||||
for n in range(n_times):
|
||||
time += 5.0e-6
|
||||
sim.advance(time)
|
||||
tim[n] = 1000 * time
|
||||
data[n,0] = r.T
|
||||
data[n,1:4] = r.thermo['OH','H','CH4'].X
|
||||
|
||||
# sensitivity of OH to reaction 2
|
||||
data[n,4] = sim.sensitivity('OH',2)
|
||||
|
||||
# sensitivity of OH to reaction 3
|
||||
data[n,5] = sim.sensitivity('OH',3)
|
||||
|
||||
print('%10.3e %10.3f %10.3f %14.6e %10.3f %10.3f' %
|
||||
(sim.time, r.T, r.thermo.P, r.thermo.u, data[n,4], data[n,5]))
|
||||
|
||||
# plot the results if matplotlib is installed.
|
||||
# see http://matplotlib.org/ to get it
|
||||
if '--plot' in sys.argv:
|
||||
import matplotlib.pyplot as plt
|
||||
plt.subplot(2,2,1)
|
||||
plt.plot(tim,data[:,0])
|
||||
plt.xlabel('Time (ms)')
|
||||
plt.ylabel('Temperature (K)')
|
||||
plt.subplot(2,2,2)
|
||||
plt.plot(tim,data[:,1])
|
||||
plt.xlabel('Time (ms)')
|
||||
plt.ylabel('OH Mole Fraction')
|
||||
plt.subplot(2,2,3)
|
||||
plt.plot(tim,data[:,2])
|
||||
plt.xlabel('Time (ms)')
|
||||
plt.ylabel('H Mole Fraction')
|
||||
plt.subplot(2,2,4)
|
||||
plt.plot(tim,data[:,3])
|
||||
plt.xlabel('Time (ms)')
|
||||
plt.ylabel('H2 Mole Fraction')
|
||||
plt.tight_layout()
|
||||
|
||||
plt.figure(2)
|
||||
plt.plot(tim,data[:,4],'-',tim,data[:,5],'-g')
|
||||
plt.legend([sim.sensitivity_parameter_name(2),sim.sensitivity_parameter_name(3)],'best')
|
||||
plt.xlabel('Time (ms)')
|
||||
plt.ylabel('OH Sensitivity')
|
||||
plt.tight_layout()
|
||||
plt.show()
|
||||
else:
|
||||
print("""To view a plot of these results, run this script with the option '--plot""")
|
||||
158
interfaces/cython/cantera/examples/reactors/surf_pfr.py
Normal file
158
interfaces/cython/cantera/examples/reactors/surf_pfr.py
Normal file
|
|
@ -0,0 +1,158 @@
|
|||
"""
|
||||
This example solves a plug flow reactor problem, where the chemistry is
|
||||
surface chemistry. The specific problem simulated is the partial oxidation of
|
||||
methane over a platinum catalyst in a packed bed reactor.
|
||||
"""
|
||||
|
||||
import csv
|
||||
|
||||
import cantera as ct
|
||||
|
||||
# unit conversion factors to SI
|
||||
cm = 0.01
|
||||
minute = 60.0
|
||||
|
||||
#######################################################################
|
||||
# Input Parameters
|
||||
#######################################################################
|
||||
|
||||
tc = 800.0 # Temperature in Celsius
|
||||
length = 0.3 * cm # Catalyst bed length
|
||||
area = 1.0 * cm**2 # Catalyst bed area
|
||||
cat_area_per_vol = 1000.0 / cm # Catalyst particle surface area per unit volume
|
||||
velocity = 40.0 * cm / minute # gas velocity
|
||||
porosity = 0.3 # Catalyst bed porosity
|
||||
|
||||
# input file containing the surface reaction mechanism
|
||||
cti_file = 'methane_pox_on_pt.cti'
|
||||
|
||||
output_filename = 'surf_pfr_output.csv'
|
||||
|
||||
# The PFR will be simulated by a chain of 'NReactors' stirred reactors.
|
||||
NReactors = 201
|
||||
dt = 1.0
|
||||
|
||||
#####################################################################
|
||||
|
||||
t = tc + 273.15 # convert to Kelvin
|
||||
|
||||
# import the gas model and set the initial conditions
|
||||
gas = ct.Solution(cti_file, 'gas')
|
||||
gas.TPX = t, ct.one_atm, 'CH4:1, O2:1.5, AR:0.1'
|
||||
|
||||
# import the surface model
|
||||
surf = ct.Interface(cti_file,'Pt_surf', [gas])
|
||||
surf.TP = t, ct.one_atm
|
||||
|
||||
rlen = length/(NReactors-1)
|
||||
rvol = area * rlen * porosity
|
||||
|
||||
outfile = open(output_filename,'w')
|
||||
writer = csv.writer(outfile)
|
||||
writer.writerow(['Distance (mm)', 'T (C)', 'P (atm)'] +
|
||||
gas.species_names + surf.species_names)
|
||||
|
||||
# catalyst area in one reactor
|
||||
cat_area = cat_area_per_vol * rvol
|
||||
|
||||
mass_flow_rate = velocity * gas.density * area
|
||||
|
||||
# The plug flow reactor is represented by a linear chain of zero-dimensional
|
||||
# reactors. The gas at the inlet to the first one has the specified inlet
|
||||
# composition, and for all others the inlet composition is fixed at the
|
||||
# composition of the reactor immediately upstream. Since in a PFR model there
|
||||
# is no diffusion, the upstream reactors are not affected by any downstream
|
||||
# reactors, and therefore the problem may be solved by simply marching from
|
||||
# the first to last reactor, integrating each one to steady state.
|
||||
|
||||
TDY = gas.TDY
|
||||
cov = surf.coverages
|
||||
|
||||
print((' {:>10s}'*4).format('distance', 'X_CH4', 'X_H2', 'X_CO'))
|
||||
|
||||
for n in range(NReactors):
|
||||
surf.TP = TDY[0], ct.one_atm
|
||||
surf.coverages = cov
|
||||
|
||||
# create a new reactor
|
||||
gas.TDY = TDY
|
||||
r = ct.Reactor(gas, energy='off')
|
||||
r.volume = rvol
|
||||
|
||||
# create a reservoir to represent the reactor immediately upstream. Note
|
||||
# that the gas object is set already to the state of the upstream reactor
|
||||
upstream = ct.Reservoir(gas, name='upstream')
|
||||
|
||||
# create a reservoir for the reactor to exhaust into. The composition of
|
||||
# this reservoir is irrelevant.
|
||||
downstream = ct.Reservoir(gas, name='downstream')
|
||||
|
||||
# use a 'Wall' object to implement the reacting surface in the reactor.
|
||||
# Since walls have to be installed between two reactors/reserviors, we'll
|
||||
# install it between the upstream reservoir and the reactor. The area is
|
||||
# set to the desired catalyst area in the reactor, and surface reactions
|
||||
# are included only on the side facing the reactor.
|
||||
w = ct.Wall(upstream, r, A=cat_area, kinetics=[None, surf])
|
||||
|
||||
# We need a valve between the reactor and the downstream reservoir. This
|
||||
# will determine the pressure in the reactor. Set K large enough that the
|
||||
# pressure difference is very small.
|
||||
v = ct.Valve(r, downstream, K=1e-4)
|
||||
|
||||
# The mass flow rate into the reactor will be fixed by using a
|
||||
# MassFlowController object.
|
||||
m = ct.MassFlowController(upstream, r, mdot=mass_flow_rate)
|
||||
|
||||
sim = ct.ReactorNet([r])
|
||||
sim.max_err_test_fails = 12
|
||||
|
||||
# set relative and absolute tolerances on the simulation
|
||||
sim.rtol = 1.0e-9
|
||||
sim.atol = 1.0e-21
|
||||
|
||||
T_start, rho_start, Y_start = r.thermo.TDY
|
||||
cov_start = surf.coverages
|
||||
V_start = r.volume
|
||||
|
||||
Tu_start, rhou_start, Yu_start = upstream.thermo.TDY
|
||||
|
||||
time = 0
|
||||
all_done = False
|
||||
while not all_done:
|
||||
time += dt
|
||||
sim.advance(time)
|
||||
|
||||
# check whether surface coverages are in steady state. This will be
|
||||
# the case if the creation and destruction rates for a surface (but
|
||||
# not gas) species are equal.
|
||||
all_done = True
|
||||
|
||||
# Note: netProduction = creation - destruction. By supplying the
|
||||
# surface object as an argument, only the values for the surface
|
||||
# species are returned by these methods
|
||||
sdot = surf.get_net_production_rates(surf)
|
||||
cdot = surf.get_creation_rates(surf)
|
||||
ddot = surf.get_destruction_rates(surf)
|
||||
|
||||
for ks in range(surf.n_species):
|
||||
ratio = abs(sdot[ks]/(cdot[ks] + ddot[ks]))
|
||||
if ratio > 1.0e-9 or time < 10*dt:
|
||||
all_done = False
|
||||
|
||||
# Save the reactor and surface states, in preparation for the simulation
|
||||
# of the next reactor downstream, where this object will set the inlet
|
||||
# conditions and the initial surface coverages
|
||||
TDY = r.thermo.TDY
|
||||
cov = surf.coverages
|
||||
|
||||
dist = n * rlen * 1.0e3 # distance in mm
|
||||
|
||||
if not n % 10:
|
||||
print((' {:10f}'*4).format(dist, *gas['CH4','H2','CO'].X))
|
||||
|
||||
# write the gas mole fractions and surface coverages vs. distance
|
||||
writer.writerow([dist, r.T - 273.15, r.thermo.P/ct.one_atm] +
|
||||
list(gas.X) + list(surf.coverages))
|
||||
|
||||
outfile.close()
|
||||
print("Results saved to '{}'".format(output_filename))
|
||||
Loading…
Add table
Reference in a new issue