[ck2cti] Added ability to convert falloff reactions with explicit third bodies

For reactions written as: R1+R2(+S1)=P1(+S1), the implication is that
the third-body efficiencies for all colliders besides S1 are zero.
This commit is contained in:
Ray Speth 2013-01-11 22:56:05 +00:00
parent 121f039ea1
commit 994acf84ea
4 changed files with 289 additions and 15 deletions

View file

@ -34,6 +34,7 @@ import logging
import types
import os.path
import numpy as np
import re
UNIT_OPTIONS = {'CAL/': 'cal/mol',
'CAL/MOL': 'cal/mol',
@ -228,6 +229,7 @@ class Reaction(object):
self.reversible = reversible
self.duplicate = duplicate
self.fwdOrders = fwdOrders if fwdOrders is not None else {}
self.thirdBody = None
def _coeff_string(self, coeffs):
L = []
@ -236,8 +238,11 @@ class Reaction(object):
L.append('{0} {1}'.format(stoichiometry, species))
else:
L.append(str(species))
expression = ' + '.join(L)
if self.thirdBody:
expression += ' (+ {0})'.format(self.thirdBody)
return ' + '.join(L)
return expression
@property
def reactantString(self):
@ -483,7 +488,7 @@ class Chebyshev(KineticsModel):
return True
def to_cti(self, reactantstr, arrow, productstr, indent=0):
rxnstr = reactantstr + ' (+ M)' + arrow + productstr + ' (+ M)'
rxnstr = reactantstr + arrow + productstr
prefix = ' '*(indent+19)
lines = ['chebyshev_reaction({0!r},'.format(rxnstr),
prefix + 'Tmin={0.Tmin}, Tmax={0.Tmax},'.format(self),
@ -588,7 +593,7 @@ class Lindemann(ThirdBody):
self.arrheniusLow = arrheniusLow
def to_cti(self, reactantstr, arrow, productstr, indent=0):
rxnstr = reactantstr + ' (+ M)' + arrow + productstr + ' (+ M)'
rxnstr = reactantstr + arrow + productstr
prefix = ' '*(indent + 17)
lines = ['falloff_reaction({0!r},'.format(rxnstr)]
lines.append(prefix + 'kf={0},'.format(self.arrheniusHigh.rateStr()))
@ -662,7 +667,7 @@ class Troe(Lindemann):
self.T2 = T2
def to_cti(self, reactantstr, arrow, productstr, indent=0):
rxnstr = reactantstr + ' (+ M)' + arrow + productstr + ' (+ M)'
rxnstr = reactantstr + arrow + productstr
prefix = ' '*17
lines = ['falloff_reaction({0!r},'.format(rxnstr),
prefix + 'kf={0},'.format(self.arrheniusHigh.rateStr()),
@ -713,7 +718,7 @@ class Sri(Lindemann):
self.E = E
def to_cti(self, reactantstr, arrow, productstr, indent=0):
rxnstr = reactantstr + ' (+ M)' + arrow + productstr + ' (+ M)'
rxnstr = reactantstr + arrow + productstr
prefix = ' '*17
lines = ['falloff_reaction({0!r},'.format(rxnstr),
prefix + 'kf={0},'.format(self.arrheniusHigh.rateStr()),
@ -942,16 +947,26 @@ def readKineticsEntry(entry, speciesDict, energyUnits, moleculeUnits):
else:
raise InputParseError("Failed to find reactant/product delimiter in reaction string.")
reactants = reactants.replace('(+M)','')
reactants = reactants.replace('(+m)','')
products = products.replace('(+M)','')
products = products.replace('(+m)','')
# Create a new Reaction object for this reaction
reaction = Reaction(reactants=[], products=[], reversible=reversible)
def parseExpression(expression, dest):
thirdBody = False
falloff3b = None
thirdBody = False # simple third body reaction (non-falloff)
# Look for third-body species for falloff reactions
if re.search(r'\(\+[Mm]\)', expression):
falloff3b = 'M'
expression = re.sub(r'(\(\+[Mm]\))', '', expression)
elif re.search(r'\(\+.*\)', expression):
# See if it matches a known species
for species in speciesDict:
if re.search(r'\(\+%s\)' % re.escape(species), expression):
falloff3b = species
expression = re.sub(r'(\(\+%s\))' % re.escape(species),
'', expression)
break
for term in expression.split('+'):
term = term.strip()
if not term[0].isalpha():
@ -970,14 +985,20 @@ def readKineticsEntry(entry, speciesDict, energyUnits, moleculeUnits):
if species == 'M' or species == 'm':
thirdBody = True
elif species not in speciesDict:
raise InputParseError('Unexpected species "{0}" in reaction {1}.'.format(species, reaction))
raise InputParseError('Unexpected species "{0}" in reaction expression "{1}".'.format(species, expression))
else:
dest.append((stoichiometry, speciesDict[species]))
return thirdBody
return falloff3b, thirdBody
thirdBody = parseExpression(reactants, reaction.reactants)
parseExpression(products, reaction.products)
falloff_3b_r, thirdBody = parseExpression(reactants, reaction.reactants)
falloff_3b_p, thirdBody = parseExpression(products, reaction.products)
if falloff_3b_r != falloff_3b_p:
raise InputParseError('Third bodies do not match: "{0}" and "{1}" in'
' reaction entry:\n\n{2}'.format(falloff_3b_r, falloff_3b_p, entry))
reaction.thirdBody = falloff_3b_r
# Determine the appropriate units for k(T) and k(T,P) based on the number of reactants
# This assumes elementary kinetics for all reactions

View file

@ -0,0 +1,38 @@
ELEMENTS
H C AR
END
SPECIES
H
R1A R1B P1
R2 SP)X
END
THERMO
300.000 1000.000 5000.000
SP)X C 1H 3 G 200.000 3500.000 1000.000 1
7.48514950E-02 1.33909467E-02-5.73285809E-06 1.22292535E-09-1.01815230E-13 2
-9.46834459E+03 1.84373180E+01 5.14987613E+00-1.36709788E-02 4.91800599E-05 3
-4.84743026E-08 1.66693956E-11-1.02466476E+04-4.64130376E+00 4
END
REACTIONS
R1A+R1B+m = P1+H+M 3.0E19 -2.0 1900
DUPLICATE
R1A+R1B(+ M ) = P1+H(+m) 1.0E18 -2.0 1000
LOW/4.0E25 -3.0 0/
R2/0.0/ SP)X/0/
DUPLICATE
R1A+R1B(+R2) = P1+H(+ R2) 2.0E18 -3.0 1200
LOW/3.0E25 -2.0 0/
DUPLICATE
! A really pathological species name
R1A+R1B(+SP)X) = P1+H(+SP)X) 3.0E18 -1.0 1400
LOW/1.0E25 -1.0 0/
DUPLICATE
END

View file

@ -0,0 +1,205 @@
<?xml version="1.0"?>
<ctml>
<validate reactions="yes" species="yes"/>
<!-- phase gas -->
<phase dim="3" id="gas">
<elementArray datasrc="elements.xml">H C Ar</elementArray>
<speciesArray datasrc="#species_data">
H R1A R1B P1 R2
SP)X</speciesArray>
<reactionArray datasrc="#reaction_data"/>
<state>
<temperature units="K">300.0</temperature>
<pressure units="Pa">101325.0</pressure>
</state>
<thermo model="IdealGas"/>
<kinetics model="GasKinetics"/>
<transport model="None"/>
</phase>
<!-- species definitions -->
<speciesData id="species_data">
<!-- species H -->
<species name="H">
<atomArray>H:1 </atomArray>
<thermo>
<NASA Tmax="1000.0" Tmin="200.0" P0="100000.0">
<floatArray name="coeffs" size="7">
2.500000000E+00, 7.053328190E-13, -1.995919640E-15, 2.300816320E-18,
-9.277323320E-22, 2.547365990E+04, -4.466828530E-01</floatArray>
</NASA>
<NASA Tmax="3500.0" Tmin="1000.0" P0="100000.0">
<floatArray name="coeffs" size="7">
2.500000010E+00, -2.308429730E-11, 1.615619480E-14, -4.735152350E-18,
4.981973570E-22, 2.547365990E+04, -4.466829140E-01</floatArray>
</NASA>
</thermo>
</species>
<!-- species R1A -->
<species name="R1A">
<atomArray>H:4 C:1 </atomArray>
<thermo>
<NASA Tmax="1000.0" Tmin="200.0" P0="100000.0">
<floatArray name="coeffs" size="7">
5.149876130E+00, -1.367097880E-02, 4.918005990E-05, -4.847430260E-08,
1.666939560E-11, -1.024664760E+04, -4.641303760E+00</floatArray>
</NASA>
<NASA Tmax="3500.0" Tmin="1000.0" P0="100000.0">
<floatArray name="coeffs" size="7">
7.485149500E-02, 1.339094670E-02, -5.732858090E-06, 1.222925350E-09,
-1.018152300E-13, -9.468344590E+03, 1.843731800E+01</floatArray>
</NASA>
</thermo>
</species>
<!-- species R1B -->
<species name="R1B">
<atomArray>H:4 C:1 </atomArray>
<thermo>
<NASA Tmax="1000.0" Tmin="200.0" P0="100000.0">
<floatArray name="coeffs" size="7">
5.149876130E+00, -1.367097880E-02, 4.918005990E-05, -4.847430260E-08,
1.666939560E-11, -1.024664760E+04, -4.641303760E+00</floatArray>
</NASA>
<NASA Tmax="3500.0" Tmin="1000.0" P0="100000.0">
<floatArray name="coeffs" size="7">
7.485149500E-02, 1.339094670E-02, -5.732858090E-06, 1.222925350E-09,
-1.018152300E-13, -9.468344590E+03, 1.843731800E+01</floatArray>
</NASA>
</thermo>
</species>
<!-- species P1 -->
<species name="P1">
<atomArray>H:7 C:2 </atomArray>
<thermo>
<NASA Tmax="1000.0" Tmin="200.0" P0="100000.0">
<floatArray name="coeffs" size="7">
5.149876130E+00, -1.367097880E-02, 4.918005990E-05, -4.847430260E-08,
1.666939560E-11, -1.024664760E+04, -4.641303760E+00</floatArray>
</NASA>
<NASA Tmax="3500.0" Tmin="1000.0" P0="100000.0">
<floatArray name="coeffs" size="7">
7.485149500E-02, 1.339094670E-02, -5.732858090E-06, 1.222925350E-09,
-1.018152300E-13, -9.468344590E+03, 1.843731800E+01</floatArray>
</NASA>
</thermo>
</species>
<!-- species R2 -->
<species name="R2">
<atomArray>H:7 C:2 </atomArray>
<thermo>
<NASA Tmax="1000.0" Tmin="200.0" P0="100000.0">
<floatArray name="coeffs" size="7">
5.149876130E+00, -1.367097880E-02, 4.918005990E-05, -4.847430260E-08,
1.666939560E-11, -1.024664760E+04, -4.641303760E+00</floatArray>
</NASA>
<NASA Tmax="3500.0" Tmin="1000.0" P0="100000.0">
<floatArray name="coeffs" size="7">
7.485149500E-02, 1.339094670E-02, -5.732858090E-06, 1.222925350E-09,
-1.018152300E-13, -9.468344590E+03, 1.843731800E+01</floatArray>
</NASA>
</thermo>
</species>
<!-- species SP)X -->
<species name="SP)X">
<atomArray>H:3 C:1 </atomArray>
<thermo>
<NASA Tmax="1000.0" Tmin="200.0" P0="100000.0">
<floatArray name="coeffs" size="7">
5.149876130E+00, -1.367097880E-02, 4.918005990E-05, -4.847430260E-08,
1.666939560E-11, -1.024664760E+04, -4.641303760E+00</floatArray>
</NASA>
<NASA Tmax="3500.0" Tmin="1000.0" P0="100000.0">
<floatArray name="coeffs" size="7">
7.485149500E-02, 1.339094670E-02, -5.732858090E-06, 1.222925350E-09,
-1.018152300E-13, -9.468344590E+03, 1.843731800E+01</floatArray>
</NASA>
</thermo>
</species>
</speciesData>
<reactionData id="reaction_data">
<!-- reaction 0001 -->
<reaction duplicate="yes" reversible="yes" type="threeBody" id="0001">
<equation>R1A + R1B + M [=] P1 + H + M</equation>
<rateCoeff>
<Arrhenius>
<A>3.000000E+13</A>
<b>-2.0</b>
<E units="cal/mol">1900.000000</E>
</Arrhenius>
</rateCoeff>
<reactants>R1B:1 R1A:1.0</reactants>
<products>H:1 P1:1.0</products>
</reaction>
<!-- reaction 0002 -->
<reaction duplicate="yes" reversible="yes" type="falloff" id="0002">
<equation>R1A + R1B (+ M) [=] P1 + H (+ M)</equation>
<rateCoeff>
<Arrhenius>
<A>1.000000E+15</A>
<b>-2.0</b>
<E units="cal/mol">1000.000000</E>
</Arrhenius>
<Arrhenius name="k0">
<A>4.000000E+19</A>
<b>-3.0</b>
<E units="cal/mol">0.000000</E>
</Arrhenius>
<efficiencies default="1.0">SP)X:0.0 R2:0.0</efficiencies>
<falloff type="Lindemann"/>
</rateCoeff>
<reactants>R1B:1 R1A:1.0</reactants>
<products>H:1 P1:1.0</products>
</reaction>
<!-- reaction 0003 -->
<reaction duplicate="yes" reversible="yes" type="falloff" id="0003">
<equation>R1A + R1B (+ R2) [=] P1 + H (+ R2)</equation>
<rateCoeff>
<Arrhenius>
<A>2.000000E+15</A>
<b>-3.0</b>
<E units="cal/mol">1200.000000</E>
</Arrhenius>
<Arrhenius name="k0">
<A>3.000000E+19</A>
<b>-2.0</b>
<E units="cal/mol">0.000000</E>
</Arrhenius>
<efficiencies default="0.0">R2:1.0</efficiencies>
<falloff type="Lindemann"/>
</rateCoeff>
<reactants>R1B:1 R1A:1.0</reactants>
<products>H:1 P1:1.0</products>
</reaction>
<!-- reaction 0004 -->
<reaction duplicate="yes" reversible="yes" type="falloff" id="0004">
<equation>R1A + R1B (+ SP)X) [=] P1 + H (+ SP)X)</equation>
<rateCoeff>
<Arrhenius>
<A>3.000000E+15</A>
<b>-1.0</b>
<E units="cal/mol">1400.000000</E>
</Arrhenius>
<Arrhenius name="k0">
<A>1.000000E+19</A>
<b>-1.0</b>
<E units="cal/mol">0.000000</E>
</Arrhenius>
<efficiencies default="0.0">SP)X:1.0</efficiencies>
<falloff type="Lindemann"/>
</rateCoeff>
<reactants>R1B:1 R1A:1.0</reactants>
<products>H:1 P1:1.0</products>
</reaction>
</reactionData>
</ctml>

View file

@ -124,6 +124,16 @@ class chemkinConverterTest(utilities.CanteraTest):
'sri-falloff.cti')
self.checkKinetics(ref, gas, [300, 800, 1450, 2800], [5e3, 1e5, 2e6])
def test_explicit_third_bodies(self):
if os.path.exists('explicit-third-bodies.cti'):
os.path.remove('explicit-third-bodies.cti')
ck2cti.convertMech('../data/explicit-third-bodies.inp',
thermoFile='../data/dummy-thermo.dat', quiet=True)
ref, gas = self.checkConversion('explicit-third-bodies.cti',
'../data/explicit-third-bodies.xml')
self.checkKinetics(ref, gas, [300, 800, 1450, 2800], [5e3, 1e5, 2e6])
def test_explicit_reverse_rate(self):
if os.path.exists('explicit-reverse-rate.cti'):
os.remove('explicit-reverse-rate.cti')