Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 2 additions & 1 deletion environment.yml
Original file line number Diff line number Diff line change
Expand Up @@ -3,10 +3,11 @@ channels:
- defaults
- rmg
- conda-forge
- cantera
dependencies:
- cairo
- cairocffi
- rmg::cantera >=2.3.0
- cantera::cantera=2.6
- conda-forge::cclib >=1.6.3
- rmg::chemprop
- coolprop
Expand Down
31 changes: 19 additions & 12 deletions rmgpy/kinetics/arrhenius.pyx
Original file line number Diff line number Diff line change
Expand Up @@ -227,11 +227,14 @@ cdef class Arrhenius(KineticsModel):
"""
self._A.value_si *= factor

def to_cantera_kinetics(self):
def to_cantera_kinetics(self, arrhenius_class=False):
"""
Converts the Arrhenius object to a cantera Arrhenius object
Converts the RMG Arrhenius object to a cantera ArrheniusRate or
the auxiliary cantera Arrhenius class (used by falloff reactions).
Inputs for both are (A,b,E) where A is in units of m^3/kmol/s, b is dimensionless, and E is in J/kmol

Arrhenius(A,b,E) where A is in units of m^3/kmol/s, b is dimensionless, and E is in J/kmol
arrhenius_class: If ``True``, uses cantera.Arrhenius (for falloff reactions). If ``False``, uses
Cantera.ArrheniusRate
"""

import cantera as ct
Expand Down Expand Up @@ -261,15 +264,18 @@ cdef class Arrhenius(KineticsModel):

b = self._n.value_si
E = self._Ea.value_si * 1000 # convert from J/mol to J/kmol
return ct.Arrhenius(A, b, E)
if arrhenius_class:
return ct.Arrhenius(A, b, E)
else:
return ct.ArrheniusRate(A, b, E)

def set_cantera_kinetics(self, ct_reaction, species_list):
"""
Passes in a cantera ElementaryReaction() object and sets its
rate to a Cantera Arrhenius() object.
Passes in a cantera Reaction() object and sets its
rate to a Cantera ArrheniusRate object.
"""
import cantera as ct
assert isinstance(ct_reaction, ct.ElementaryReaction), "Must be a Cantera ElementaryReaction object"
assert isinstance(ct_reaction.rate, ct.ArrheniusRate), "Must have a Cantera ArrheniusRate attribute"

# Set the rate parameter to a cantera Arrhenius object
ct_reaction.rate = self.to_cantera_kinetics()
Expand Down Expand Up @@ -449,7 +455,7 @@ cdef class ArrheniusEP(KineticsModel):

def set_cantera_kinetics(self, ct_reaction, species_list):
"""
Sets a cantera ElementaryReaction() object with the modified Arrhenius object
Sets a cantera Reaction() object with the modified Arrhenius object
converted to an Arrhenius form.
"""
raise NotImplementedError('set_cantera_kinetics() is not implemented for ArrheniusEP class kinetics.')
Expand Down Expand Up @@ -703,7 +709,7 @@ cdef class ArrheniusBM(KineticsModel):

def set_cantera_kinetics(self, ct_reaction, species_list):
"""
Sets a cantera ElementaryReaction() object with the modified Arrhenius object
Sets a cantera Reaction() object with the modified Arrhenius object
converted to an Arrhenius form.
"""
raise NotImplementedError('set_cantera_kinetics() is not implemented for ArrheniusBM class kinetics.')
Expand Down Expand Up @@ -863,12 +869,13 @@ cdef class PDepArrhenius(PDepKineticsModel):
"""
import cantera as ct
import copy
assert isinstance(ct_reaction, ct.PlogReaction), "Must be a Cantera PlogReaction object"
assert isinstance(ct_reaction.rate, ct.PlogRate), "Must have a Cantera PlogRate attribute"

pressures = copy.deepcopy(self._pressures.value_si)
ctArrhenius = [arr.to_cantera_kinetics() for arr in self.arrhenius]
ctArrhenius = [arr.to_cantera_kinetics(arrhenius_class=True) for arr in self.arrhenius]

ct_reaction.rates = list(zip(pressures, ctArrhenius))
new_rates = ct.PlogRate(list(zip(pressures, ctArrhenius)))
ct_reaction.rate = new_rates

################################################################################

Expand Down
2 changes: 1 addition & 1 deletion rmgpy/kinetics/arrheniusTest.py
Original file line number Diff line number Diff line change
Expand Up @@ -233,7 +233,7 @@ def test_change_rate(self):
def test_to_cantera_kinetics(self):
"""
Test that the Arrhenius cantera object can be set properly within
a cantera ElementaryReaction object
a cantera Reaction object
"""
ctArrhenius = self.arrhenius.to_cantera_kinetics()
self.assertAlmostEqual(ctArrhenius.pre_exponential_factor, 1e9, 6)
Expand Down
6 changes: 4 additions & 2 deletions rmgpy/kinetics/chebyshev.pyx
Original file line number Diff line number Diff line change
Expand Up @@ -268,7 +268,7 @@ cdef class Chebyshev(PDepKineticsModel):
"""
import cantera as ct
import copy
assert isinstance(ct_reaction, ct.ChebyshevReaction), "Must be a Cantera ChebyshevReaction object"
assert isinstance(ct_reaction.rate, ct.ChebyshevRate), "Must have a Cantera Chebychev rate attribute"

Tmin = self.Tmin.value_si
Tmax = self.Tmax.value_si
Expand All @@ -294,4 +294,6 @@ cdef class Chebyshev(PDepKineticsModel):
except:
raise Exception('Chebyshev units {0} not found among accepted units for converting to '
'Cantera Chebyshev object.'.format(self.kunits))
ct_reaction.set_parameters(Tmin, Tmax, Pmin, Pmax, coeffs)

new_chebyshev = ct.ChebyshevRate(temperature_range=(Tmin, Tmax), pressure_range=(Pmin, Pmax), data=coeffs)
ct_reaction.rate = new_chebyshev
45 changes: 36 additions & 9 deletions rmgpy/kinetics/falloff.pyx
Original file line number Diff line number Diff line change
Expand Up @@ -220,17 +220,29 @@ cdef class Lindemann(PDepKineticsModel):
self.arrheniusLow.change_rate(factor)
self.arrheniusHigh.change_rate(factor)



def set_cantera_kinetics(self, ct_reaction, species_list):
"""
Sets the efficiencies and kinetics for a cantera reaction.
"""
import cantera as ct
assert isinstance(ct_reaction, ct.FalloffReaction), "Must be a Cantera FalloffReaction object"
assert isinstance(ct_reaction.rate, ct.LindemannRate), "Must have a Cantera LindemannRate attribute"

ct_reaction.efficiencies = PDepKineticsModel.get_cantera_efficiencies(self, species_list)
ct_reaction.high_rate = self.arrheniusHigh.to_cantera_kinetics()
ct_reaction.low_rate = self.arrheniusLow.to_cantera_kinetics()
ct_reaction.falloff = ct.Falloff()
ct_reaction.rate = self.to_cantera_kinetics()


def to_cantera_kinetics(self):
"""
Converts the Lindemann object to a cantera LindemannRate object
"""
import cantera as ct

high_rate = self.arrheniusHigh.to_cantera_kinetics(arrhenius_class=True)
low_rate = self.arrheniusLow.to_cantera_kinetics(arrhenius_class=True)
return ct.LindemannRate(low=low_rate, high=high_rate)


################################################################################

Expand Down Expand Up @@ -389,15 +401,30 @@ cdef class Troe(PDepKineticsModel):
"""
import cantera as ct

assert isinstance(ct_reaction, ct.FalloffReaction), "Must be a Cantera FalloffReaction object"
assert isinstance(ct_reaction.rate, ct.TroeRate), "Must have a Cantera TroeRate attribute"

ct_reaction.efficiencies = PDepKineticsModel.get_cantera_efficiencies(self, species_list)
ct_reaction.high_rate = self.arrheniusHigh.to_cantera_kinetics()
ct_reaction.low_rate = self.arrheniusLow.to_cantera_kinetics()

ct_reaction.rate = self.to_cantera_kinetics()

def to_cantera_kinetics(self):
"""
Converts the Troe object to a cantera Troe object
"""
import cantera as ct
A = self.alpha
T3 = self.T3.value_si
T1 = self.T1.value_si
if self.T2 is None:
ct_reaction.falloff = ct.TroeFalloff(params=[A, T3, T1])
falloff = [A, T3, T1]
else:
T2 = self.T2.value_si
ct_reaction.falloff = ct.TroeFalloff(params=[A, T3, T1, T2])
falloff = [A, T3, T1, T2]

high = self.arrheniusHigh.to_cantera_kinetics(arrhenius_class=True)
low = self.arrheniusLow.to_cantera_kinetics(arrhenius_class=True)
return ct.TroeRate(high=high, low=low, falloff_coeffs=falloff)




60 changes: 51 additions & 9 deletions rmgpy/reaction.py
Original file line number Diff line number Diff line change
Expand Up @@ -281,39 +281,81 @@ def to_cantera(self, species_list=None, use_chemkin_identifier=False):
ct_products[product_name] += 1
else:
ct_products[product_name] = 1

if self.specific_collider: # add a specific collider if exists
ct_collider[self.specific_collider.to_chemkin() if use_chemkin_identifier else self.specific_collider.label] = 1

if self.kinetics:
if isinstance(self.kinetics, Arrhenius):
# Create an Elementary Reaction
ct_reaction = ct.ElementaryReaction(reactants=ct_reactants, products=ct_products)
ct_reaction = ct.Reaction(reactants=ct_reactants, products=ct_products, rate=ct.ArrheniusRate())
elif isinstance(self.kinetics, MultiArrhenius):
# Return a list of elementary reactions which are duplicates
ct_reaction = [ct.ElementaryReaction(reactants=ct_reactants, products=ct_products)
ct_reaction = [ct.Reaction(reactants=ct_reactants, products=ct_products, rate=ct.ArrheniusRate())
for arr in self.kinetics.arrhenius]

elif isinstance(self.kinetics, PDepArrhenius):
ct_reaction = ct.PlogReaction(reactants=ct_reactants, products=ct_products)
ct_reaction = ct.Reaction(reactants=ct_reactants, products=ct_products, rate=ct.PlogRate())

elif isinstance(self.kinetics, MultiPDepArrhenius):
ct_reaction = [ct.PlogReaction(reactants=ct_reactants, products=ct_products)
ct_reaction = [ct.Reaction(reactants=ct_reactants, products=ct_products, rate=ct.PlogRate())
for arr in self.kinetics.arrhenius]

elif isinstance(self.kinetics, Chebyshev):
ct_reaction = ct.ChebyshevReaction(reactants=ct_reactants, products=ct_products)
ct_reaction = ct.Reaction(reactants=ct_reactants, products=ct_products, rate=ct.ChebyshevRate())

elif isinstance(self.kinetics, ThirdBody):
if ct_collider is not None:
ct_reaction = ct.ThreeBodyReaction(reactants=ct_reactants, products=ct_products, tbody=ct_collider)
ct_reaction = ct.ThreeBodyReaction(reactants=ct_reactants, products=ct_products, third_body=ct_collider)
else:
ct_reaction = ct.ThreeBodyReaction(reactants=ct_reactants, products=ct_products)

elif isinstance(self.kinetics, Lindemann) or isinstance(self.kinetics, Troe):
elif isinstance(self.kinetics, Troe):
high_rate = self.kinetics.arrheniusHigh.to_cantera_kinetics(arrhenius_class=True)
low_rate = self.kinetics.arrheniusLow.to_cantera_kinetics(arrhenius_class=True)
A = self.kinetics.alpha
T3 = self.kinetics.T3.value_si
T1 = self.kinetics.T1.value_si

if self.kinetics.T2 is None:
rate = ct.TroeRate(
high=high_rate, low=low_rate, falloff_coeffs=[A, T3, T1]
)
else:
T2 = self.kinetics.T2.value_si
rate = ct.TroeRate(
high=high_rate, low=low_rate, falloff_coeffs=[A, T3, T1, T2]
)

if ct_collider is not None:
ct_reaction = ct.FalloffReaction(reactants=ct_reactants, products=ct_products, tbody=ct_collider)
ct_reaction = ct.FalloffReaction(
reactants=ct_reactants,
products=ct_products,
tbody=ct_collider,
rate=rate,
)
else:
ct_reaction = ct.FalloffReaction(reactants=ct_reactants, products=ct_products)
ct_reaction = ct.FalloffReaction(
reactants=ct_reactants, products=ct_products, rate=rate
)

elif isinstance(self.kinetics, Lindemann):
high_rate = self.kinetics.arrheniusHigh.to_cantera_kinetics(arrhenius_class=True)
low_rate = self.kinetics.arrheniusLow.to_cantera_kinetics(arrhenius_class=True)
falloff = []
rate = ct.LindemannRate(low_rate, high_rate, falloff)
if ct_collider is not None:
ct_reaction = ct.FalloffReaction(
reactants=ct_reactants,
products=ct_products,
tbody=ct_collider,
rate=rate,
)
else:
ct_reaction = ct.FalloffReaction(
reactants=ct_reactants, products=ct_products, rate=rate
)

else:
raise NotImplementedError('Unable to set cantera kinetics for {0}'.format(self.kinetics))

Expand Down
Loading