Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Support reversing PDepArrhenius objects containing MultiArrhenius rates #1659

Merged
merged 5 commits into from
Jul 23, 2019
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
6 changes: 3 additions & 3 deletions rmgpy/data/kinetics/groups.py
Original file line number Diff line number Diff line change
Expand Up @@ -409,7 +409,7 @@ def generateGroupAdditivityValues(self, trainingSet, kunits, method='Arrhenius')
b = numpy.array(b)
kdata = numpy.array(kdata)

x, residues, rank, s = numpy.linalg.lstsq(A, b)
x, residues, rank, s = numpy.linalg.lstsq(A, b, rcond=None)

for t, T in enumerate(Tdata):

Expand Down Expand Up @@ -513,7 +513,7 @@ def generateGroupAdditivityValues(self, trainingSet, kunits, method='Arrhenius')
b = numpy.array(b)
kdata = numpy.array(kdata)

x, residues, rank, s = numpy.linalg.lstsq(A, b)
x, residues, rank, s = numpy.linalg.lstsq(A, b, rcond=None)

# Store the results
self.top[0].data = Arrhenius(
Expand Down Expand Up @@ -564,7 +564,7 @@ def generateGroupAdditivityValues(self, trainingSet, kunits, method='Arrhenius')
A = numpy.array(A)
b = numpy.array(b)

x, residues, rank, s = numpy.linalg.lstsq(A, b)
x, residues, rank, s = numpy.linalg.lstsq(A, b, rcond=None)

# Store the results
self.top[0].data = Arrhenius(
Expand Down
2 changes: 1 addition & 1 deletion rmgpy/kinetics/arrhenius.pyx
Original file line number Diff line number Diff line change
Expand Up @@ -162,7 +162,7 @@ cdef class Arrhenius(KineticsModel):
for n in range(b.size):
A[n,:] *= weights[n]
b[n] *= weights[n]
x, residues, rank, s = numpy.linalg.lstsq(A,b)
x, residues, rank, s = numpy.linalg.lstsq(A, b, rcond=None)

# Determine covarianace matrix to obtain parameter uncertainties
count = klist.size
Expand Down
2 changes: 1 addition & 1 deletion rmgpy/kinetics/chebyshev.pyx
Original file line number Diff line number Diff line change
Expand Up @@ -217,7 +217,7 @@ cdef class Chebyshev(PDepKineticsModel):
b[p1*nT+t1] = log10(K[t1,p1])

# Do linear least-squares fit to get coefficients
x, residues, rank, s = numpy.linalg.lstsq(A, b)
x, residues, rank, s = numpy.linalg.lstsq(A, b, rcond=None)

# Extract coefficients
coeffs = numpy.zeros((degreeT,degreeP), numpy.float64)
Expand Down
2 changes: 1 addition & 1 deletion rmgpy/kinetics/surface.pyx
Original file line number Diff line number Diff line change
Expand Up @@ -157,7 +157,7 @@ cdef class StickingCoefficient(KineticsModel):
for n in range(b.size):
A[n, :] *= weights[n]
b[n] *= weights[n]
x, residues, rank, s = numpy.linalg.lstsq(A, b)
x, residues, rank, s = numpy.linalg.lstsq(A, b, rcond=None)

# Determine covarianace matrix to obtain parameter uncertainties
count = klist.size
Expand Down
4 changes: 2 additions & 2 deletions rmgpy/reaction.pxd
Original file line number Diff line number Diff line change
Expand Up @@ -99,9 +99,9 @@ cdef class Reaction:

cpdef fixBarrierHeight(self, bint forcePositive=?)

cpdef reverseThisArrheniusRate(self, Arrhenius kForward, str reverseUnits)
cpdef reverseThisArrheniusRate(self, Arrhenius kForward, str reverseUnits, Tmin=?, Tmax=?)

cpdef generateReverseRateCoefficient(self, bint network_kinetics=?)
cpdef generateReverseRateCoefficient(self, bint network_kinetics=?, Tmin=?, Tmax=?)

cpdef numpy.ndarray calculateTSTRateCoefficients(self, numpy.ndarray Tlist)

Expand Down
31 changes: 15 additions & 16 deletions rmgpy/reaction.py
Original file line number Diff line number Diff line change
Expand Up @@ -761,7 +761,7 @@ def fixBarrierHeight(self, forcePositive=False):
" kJ/mol.".format(self.kinetics.Ea.value_si / 1000.,self))
self.kinetics.Ea.value_si = 0

def reverseThisArrheniusRate(self, kForward, reverseUnits):
def reverseThisArrheniusRate(self, kForward, reverseUnits, Tmin=None, Tmax=None):
"""
Reverses the given kForward, which must be an Arrhenius type.
You must supply the correct units for the reverse rate.
Expand All @@ -771,7 +771,10 @@ def reverseThisArrheniusRate(self, kForward, reverseUnits):
cython.declare(Tlist=numpy.ndarray, klist=numpy.ndarray, i=cython.int)
kf = kForward
assert isinstance(kf, Arrhenius), "Only reverses Arrhenius rates"
Tlist = 1.0 / numpy.arange(0.0005, 0.0034, 0.0001) # 294 K to 2000 K
if Tmin is not None and Tmax is not None:
Tlist = 1.0 / numpy.linspace(1.0 / Tmax.value, 1.0 / Tmin.value, 50)
else:
Tlist = 1.0 / numpy.arange(0.0005, 0.0034, 0.0001)
# Determine the values of the reverse rate coefficient k_r(T) at each temperature
klist = numpy.zeros_like(Tlist)
for i in range(len(Tlist)):
Expand All @@ -780,7 +783,7 @@ def reverseThisArrheniusRate(self, kForward, reverseUnits):
kr.fitToData(Tlist, klist, reverseUnits, kf.T0.value_si)
return kr

def generateReverseRateCoefficient(self, network_kinetics=False):
def generateReverseRateCoefficient(self, network_kinetics=False, Tmin=None, Tmax=None):
"""
Generate and return a rate coefficient model for the reverse reaction.
Currently this only works if the `kinetics` attribute is one of several
Expand Down Expand Up @@ -817,7 +820,7 @@ def generateReverseRateCoefficient(self, network_kinetics=False):
return kr

elif isinstance(kf, Arrhenius):
return self.reverseThisArrheniusRate(kf, kunits)
return self.reverseThisArrheniusRate(kf, kunits, Tmin, Tmax)

elif network_kinetics and self.network_kinetics is not None:
kf = self.network_kinetics
Expand All @@ -834,19 +837,15 @@ def generateReverseRateCoefficient(self, network_kinetics=False):
kr.fitToData(Tlist, Plist, K, kunits, kf.degreeT, kf.degreeP, kf.Tmin.value, kf.Tmax.value, kf.Pmin.value, kf.Pmax.value)
return kr

elif isinstance(kf, PDepArrhenius):
if kf.Tmin is not None and kf.Tmax is not None:
Tlist = 1.0/numpy.linspace(1.0/kf.Tmax.value, 1.0/kf.Tmin.value, 50)
else:
Tlist = 1.0/numpy.arange(0.0005, 0.0035, 0.0001)
Plist = kf.pressures.value_si
K = numpy.zeros((len(Tlist), len(Plist)), numpy.float64)
for Tindex, T in enumerate(Tlist):
for Pindex, P in enumerate(Plist):
K[Tindex, Pindex] = kf.getRateCoefficient(T, P) / self.getEquilibriumConstant(T)
elif isinstance(kf, PDepArrhenius):
kr = PDepArrhenius()
kr.fitToData(Tlist, Plist, K, kunits, kf.arrhenius[0].T0.value)
return kr
kr.pressures = kf.pressures
kr.arrhenius = []
rxn = Reaction(reactants=self.reactants, products=self.products)
for kinetics in kf.arrhenius:
rxn.kinetics = kinetics
kr.arrhenius.append(rxn.generateReverseRateCoefficient(kf.Tmin, kf.Tmax))
return kr

elif isinstance(kf, MultiArrhenius):
kr = MultiArrhenius()
Expand Down
92 changes: 68 additions & 24 deletions rmgpy/reactionTest.py
Original file line number Diff line number Diff line change
Expand Up @@ -32,23 +32,26 @@
This module contains unit tests of the rmgpy.reaction module.
"""

import numpy
import unittest

import cantera as ct
import numpy
from external.wip import work_in_progress

from rmgpy.quantity import Quantity
from rmgpy.species import Species, TransitionState
import rmgpy.constants as constants
from rmgpy.kinetics import Arrhenius, ArrheniusEP, MultiArrhenius, PDepArrhenius, MultiPDepArrhenius, \
ThirdBody, Troe, Lindemann, Chebyshev, SurfaceArrhenius, StickingCoefficient
from rmgpy.molecule import Molecule
from rmgpy.reaction import Reaction
from rmgpy.quantity import Quantity
from rmgpy.statmech.translation import Translation, IdealGasTranslation
from rmgpy.statmech.rotation import Rotation, LinearRotor, NonlinearRotor, KRotor, SphericalTopRotor
from rmgpy.statmech.vibration import Vibration, HarmonicOscillator
from rmgpy.statmech.torsion import Torsion, HinderedRotor
from rmgpy.reaction import Reaction
from rmgpy.species import Species, TransitionState
from rmgpy.statmech.conformer import Conformer
from rmgpy.kinetics import Arrhenius, ArrheniusEP, SurfaceArrhenius, StickingCoefficient
from rmgpy.statmech.rotation import NonlinearRotor
from rmgpy.statmech.torsion import HinderedRotor
from rmgpy.statmech.translation import IdealGasTranslation
from rmgpy.statmech.vibration import HarmonicOscillator
from rmgpy.thermo import Wilhoit, ThermoData, NASA, NASAPolynomial
import rmgpy.constants as constants


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

Expand Down Expand Up @@ -689,7 +692,6 @@ def testGenerateReverseRateCoefficientPDepArrhenius(self):
"""
Test the Reaction.generateReverseRateCoefficient() method works for the PDepArrhenius format.
"""
from rmgpy.kinetics import PDepArrhenius
amarkpayne marked this conversation as resolved.
Show resolved Hide resolved

arrhenius0 = Arrhenius(
A = (1.0e6,"s^-1"),
Expand Down Expand Up @@ -746,12 +748,66 @@ def testGenerateReverseRateCoefficientPDepArrhenius(self):
krevrev = reversereverseKinetics.getRateCoefficient(T, P)
self.assertAlmostEqual(korig / krevrev, 1.0, 0)

def testGenerateReverseRateCoefficientPDepMultiArrhenius(self):
"""
Test the Reaction.generateReverseRateCoefficient() method works for the PDepArrhenius format with MultiArrhenius rates.
"""

arrhenius0 = MultiArrhenius(
arrhenius=[
Arrhenius(A=(1.0e6, "s^-1"), n=1.0, Ea=(10.0, "kJ/mol"), T0=(300.0, "K"), Tmin=(300.0, "K"), Tmax=(2000.0, "K")),
Arrhenius(A=(1.0e6, "s^-1"), n=1.0, Ea=(10.0, "kJ/mol"), T0=(300.0, "K"), Tmin=(300.0, "K"), Tmax=(2000.0, "K")),
],
comment="""This data is completely made up""",
)

arrhenius1 = MultiArrhenius(
arrhenius=[
Arrhenius(A=(1.0e12, "s^-1"), n=1.0, Ea=(10.0, "kJ/mol"), T0=(300.0, "K"), Tmin=(300.0, "K"), Tmax=(2000.0, "K")),
Arrhenius(A=(1.0e12, "s^-1"), n=1.0, Ea=(10.0, "kJ/mol"), T0=(300.0, "K"), Tmin=(300.0, "K"), Tmax=(2000.0, "K")),
],
comment="""This data is completely made up""",
)

pressures = numpy.array([0.1, 10.0])
amarkpayne marked this conversation as resolved.
Show resolved Hide resolved
arrhenius = [arrhenius0, arrhenius1]
Tmin = 300.0
Tmax = 2000.0
Pmin = 0.1
Pmax = 10.0
comment = """This data is completely made up"""

original_kinetics = PDepArrhenius(
pressures=(pressures, "bar"),
arrhenius=arrhenius,
Tmin=(Tmin, "K"),
Tmax=(Tmax, "K"),
Pmin=(Pmin, "bar"),
Pmax=(Pmax, "bar"),
comment=comment,
)

self.reaction2.kinetics = original_kinetics

reverseKinetics = self.reaction2.generateReverseRateCoefficient()

self.reaction2.kinetics = reverseKinetics
# reverse reactants, products to ensure Keq is correctly computed
self.reaction2.reactants, self.reaction2.products = self.reaction2.products, self.reaction2.reactants
reversereverseKinetics = self.reaction2.generateReverseRateCoefficient()

# check that reverting the reverse yields the original
Tlist = numpy.arange(Tmin, Tmax, 200.0, numpy.float64)
P = 1e5
for T in Tlist:
korig = original_kinetics.getRateCoefficient(T, P)
krevrev = reversereverseKinetics.getRateCoefficient(T, P)
self.assertAlmostEqual(korig / krevrev, 1.0, 0)

def testGenerateReverseRateCoefficientMultiArrhenius(self):
"""
Test the Reaction.generateReverseRateCoefficient() method works for the MultiArrhenius format.
"""
from rmgpy.kinetics import MultiArrhenius

pressures = numpy.array([0.1, 10.0])
Tmin = 300.0
Expand Down Expand Up @@ -809,7 +865,6 @@ def testGenerateReverseRateCoefficientMultiPDepArrhenius(self):
"""
Test the Reaction.generateReverseRateCoefficient() method works for the MultiPDepArrhenius format.
"""
from rmgpy.kinetics import PDepArrhenius, MultiPDepArrhenius

Tmin = 350.
Tmax = 1500.
Expand Down Expand Up @@ -907,8 +962,6 @@ def testGenerateReverseRateCoefficientThirdBody(self):
Test the Reaction.generateReverseRateCoefficient() method works for the ThirdBody format.
"""

from rmgpy.kinetics import ThirdBody

arrheniusLow = Arrhenius(
A = (2.62e+33,"cm^6/(mol^2*s)"),
n = -4.76,
Expand Down Expand Up @@ -955,8 +1008,6 @@ def testGenerateReverseRateCoefficientLindemann(self):
Test the Reaction.generateReverseRateCoefficient() method works for the Lindemann format.
"""

from rmgpy.kinetics import Lindemann

arrheniusHigh = Arrhenius(
A = (1.39e+16,"cm^3/(mol*s)"),
n = -0.534,
Expand Down Expand Up @@ -1011,8 +1062,6 @@ def testGenerateReverseRateCoefficientTroe(self):
Test the Reaction.generateReverseRateCoefficient() method works for the Troe format.
"""

from rmgpy.kinetics import Troe

arrheniusHigh = Arrhenius(
A = (1.39e+16,"cm^3/(mol*s)"),
n = -0.534,
Expand Down Expand Up @@ -1184,11 +1233,6 @@ def setUp(self):
"""
A method that is called prior to each unit test in this class.
"""
from rmgpy.kinetics import Arrhenius, MultiArrhenius, PDepArrhenius, MultiPDepArrhenius, ThirdBody, Troe, Lindemann, Chebyshev
from rmgpy.molecule import Molecule
from rmgpy.thermo import NASA, NASAPolynomial
import cantera as ct

# define some species:
ch3 = Species(index=13, label="CH3", thermo=NASA(polynomials=[NASAPolynomial(coeffs=[3.91547,0.00184154,3.48744e-06,-3.3275e-09,8.49964e-13,16285.6,0.351739], Tmin=(100,'K'), Tmax=(1337.62,'K')), NASAPolynomial(coeffs=[3.54145,0.00476788,-1.82149e-06,3.28878e-10,-2.22547e-14,16224,1.6604], Tmin=(1337.62,'K'), Tmax=(5000,'K'))], Tmin=(100,'K'), Tmax=(5000,'K'), comment="""
Thermo library: primaryThermoLibrary + radical(CH3)
Expand Down
5 changes: 2 additions & 3 deletions rmgpy/rmg/modelTest.py
Original file line number Diff line number Diff line change
Expand Up @@ -594,10 +594,9 @@ def setUpClass(cls):
A method that is run ONCE before all unit tests in this class.
"""
cls.dirname = os.path.abspath(os.path.join(os.path.dirname(__file__), 'temp'))
print cls.dirname
os.makedirs(os.path.join(cls.dirname, 'pdep'))

TESTFAMILY = 'R_Recombination'
test_family = 'R_Recombination'

cls.rmg = RMG()

Expand All @@ -620,7 +619,7 @@ def setUpClass(cls):
cls.rmg.database.load(
path=settings['database.directory'],
thermoLibraries=['primaryThermoLibrary'],
kineticsFamilies=[TESTFAMILY],
kineticsFamilies=[test_family],
reactionLibraries=[],
)

Expand Down
2 changes: 1 addition & 1 deletion rmgpy/statmech/torsion.pyx
Original file line number Diff line number Diff line change
Expand Up @@ -539,7 +539,7 @@ cdef class HinderedRotor(Torsion):
# This row forces dV/dangle = 0 at angle = 0
for m in range(numterms):
A[N,m+numterms] = 1
x, residues, rank, s = numpy.linalg.lstsq(A, b)
x, residues, rank, s = numpy.linalg.lstsq(A, b, rcond=None)
fit = numpy.dot(A,x)
x *= 0.001
# This checks if there are any negative values in the forier fit.
Expand Down
2 changes: 1 addition & 1 deletion rmgpy/thermo/wilhoit.pyx
Original file line number Diff line number Diff line change
Expand Up @@ -277,7 +277,7 @@ cdef class Wilhoit(HeatCapacityModel):
for j in range(4):
A[i,j] = (y*y*y - y*y) * y**j
b[i] = ((Cpdata[i] - Cp0) / (CpInf - Cp0) - y*y)
x, residues, rank, s = numpy.linalg.lstsq(A, b)
x, residues, rank, s = numpy.linalg.lstsq(A, b, rcond=None)

self.B = (float(B),"K")
self.a0 = float(x[0])
Expand Down