def getKineticsDepository(FullDatabase, family, depositoryLabel):
    """
    Retrieve dictionaries of exact kinetics from NIST depository and approximated kinetics 
    for those same reactions from RMG.  
    Note: does NOT average up the database or create any rate rules from training data.  
    If that is desired it must be done prior to entering this function.
    """
    
    depository = None
    for tempDepository in family.depositories:
        if re.search(re.escape(depositoryLabel), tempDepository.label):
            depository=tempDepository
            break
    else:
        print 'Depository {} not found in {} family.'.format(depositoryLabel, family.label)
        return
            
    
    exactKinetics={}
    approxKinetics={}
    
    for key, entry in depository.entries.iteritems():
        try:
            reaction=entry.item
            template=family.getReactionTemplate(reaction)
            exactKinetics[key]=entry.data
            approxKinetics[key]=family.rules.estimateKinetics(template)[0]
        except UndeterminableKineticsError:
            # See if the reaction was written in the reverse direction
            reaction = Reaction(reactants = copy.deepcopy(entry.item.products),
                                products = copy.deepcopy(entry.item.reactants),
                                kinetics = copy.deepcopy(entry.data)
                                )
            
            template=family.getReactionTemplate(reaction)

            # Getting thermo data erases the atomLabels, so do this after finding the template
            # But we need it for setting the reverse kinetics
            for spec in reaction.reactants + reaction.products:
                spec.getThermoData()

            reverseKinetics = reaction.generateReverseRateCoefficient()
            reaction.kinetics = reverseKinetics
            
            exactKinetics[key]=reaction.kinetics
            approxKinetics[key]=family.rules.estimateKinetics(template)[0]

    return exactKinetics, approxKinetics
Esempio n. 2
0
def getKineticsDepository(FullDatabase, family, depositoryLabel):
    """
    Retrieve dictionaries of exact kinetics from NIST depository and approximated kinetics 
    for those same reactions from RMG.  
    Note: does NOT average up the database or create any rate rules from training data.  
    If that is desired it must be done prior to entering this function.
    """

    depository = None
    for tempDepository in family.depositories:
        if re.search(re.escape(depositoryLabel), tempDepository.label):
            depository = tempDepository
            break
    else:
        print 'Depository {} not found in {} family.'.format(
            depositoryLabel, family.label)
        return

    exactKinetics = {}
    approxKinetics = {}

    for key, entry in depository.entries.iteritems():
        try:
            reaction = entry.item
            template = family.getReactionTemplate(reaction)
            exactKinetics[key] = entry.data
            approxKinetics[key] = family.rules.estimateKinetics(template)[0]
        except UndeterminableKineticsError:
            # See if the reaction was written in the reverse direction
            reaction = Reaction(reactants=copy.deepcopy(entry.item.products),
                                products=copy.deepcopy(entry.item.reactants),
                                kinetics=copy.deepcopy(entry.data))

            template = family.getReactionTemplate(reaction)

            # Getting thermo data erases the atomLabels, so do this after finding the template
            # But we need it for setting the reverse kinetics
            for spec in reaction.reactants + reaction.products:
                spec.getThermoData()

            reverseKinetics = reaction.generateReverseRateCoefficient()
            reaction.kinetics = reverseKinetics

            exactKinetics[key] = reaction.kinetics
            approxKinetics[key] = family.rules.estimateKinetics(template)[0]

    return exactKinetics, approxKinetics
Esempio n. 3
0
class TestReaction(unittest.TestCase):
    """
    Contains unit tests of the Reaction class.
    """
    
    def setUp(self):
        """
        A method that is called prior to each unit test in this class.
        """
        ethylene = Species(
            label = 'C2H4',
            conformer = Conformer(
                E0 = (44.7127, 'kJ/mol'),
                modes = [
                    IdealGasTranslation(
                        mass = (28.0313, 'amu'),
                    ),
                    NonlinearRotor(
                        inertia = (
                            [3.41526, 16.6498, 20.065],
                            'amu*angstrom^2',
                        ),
                        symmetry = 4,
                    ),
                    HarmonicOscillator(
                        frequencies = (
                            [828.397, 970.652, 977.223, 1052.93, 1233.55, 1367.56, 1465.09, 1672.25, 3098.46, 3111.7, 3165.79, 3193.54],
                            'cm^-1',
                        ),
                    ),
                ],
                spinMultiplicity = 1,
                opticalIsomers = 1,
            ),
        )
        
        hydrogen = Species(          
            label = 'H',
            conformer = Conformer(
                E0 = (211.794, 'kJ/mol'),
                modes = [
                    IdealGasTranslation(
                        mass = (1.00783, 'amu'),
                    ),
                ],
                spinMultiplicity = 2,
                opticalIsomers = 1,
            ),
        )
        
        ethyl = Species(
            label = 'C2H5',
            conformer = Conformer(
                E0 = (111.603, 'kJ/mol'),
                modes = [
                    IdealGasTranslation(
                        mass = (29.0391, 'amu'),
                    ),
                    NonlinearRotor(
                        inertia = (
                            [4.8709, 22.2353, 23.9925],
                            'amu*angstrom^2',
                        ),
                        symmetry = 1,
                    ),
                    HarmonicOscillator(
                        frequencies = (
                            [482.224, 791.876, 974.355, 1051.48, 1183.21, 1361.36, 1448.65, 1455.07, 1465.48, 2688.22, 2954.51, 3033.39, 3101.54, 3204.73],
                            'cm^-1',
                        ),
                    ),
                    HinderedRotor(
                        inertia = (1.11481, 'amu*angstrom^2'),
                        symmetry = 6,
                        barrier = (0.244029, 'kJ/mol'),
                        semiclassical = None,
                    ),
                ],
                spinMultiplicity = 2,
                opticalIsomers = 1,
            ),
        )
        
        TS = TransitionState(
            label = 'TS',
            conformer = Conformer(
                E0 = (266.694, 'kJ/mol'),
                modes = [
                    IdealGasTranslation(
                        mass = (29.0391, 'amu'),
                    ),
                    NonlinearRotor(
                        inertia = (
                            [6.78512, 22.1437, 22.2114],
                            'amu*angstrom^2',
                        ),
                        symmetry = 1,
                    ),
                    HarmonicOscillator(
                        frequencies = (
                            [412.75, 415.206, 821.495, 924.44, 982.714, 1024.16, 1224.21, 1326.36, 1455.06, 1600.35, 3101.46, 3110.55, 3175.34, 3201.88],
                            'cm^-1',
                        ),
                    ),
                ],
                spinMultiplicity = 2,
                opticalIsomers = 1,
            ),
            frequency = (-750.232, 'cm^-1'),
        )
        
        self.reaction = Reaction(
            reactants = [hydrogen, ethylene],
            products = [ethyl], 
            kinetics = Arrhenius(
                A = (501366000.0, 'cm^3/(mol*s)'),
                n = 1.637,
                Ea = (4.32508, 'kJ/mol'),
                T0 = (1, 'K'),
                Tmin = (300, 'K'),
                Tmax = (2500, 'K'),
            ),
            transitionState = TS,
        )
    
        # CC(=O)O[O]
        acetylperoxy = Species(
            label='acetylperoxy',
            thermo=Wilhoit(Cp0=(4.0*constants.R,"J/(mol*K)"), CpInf=(21.0*constants.R,"J/(mol*K)"), a0=-3.95, a1=9.26, a2=-15.6, a3=8.55, B=(500.0,"K"), H0=(-6.151e+04,"J/mol"), S0=(-790.2,"J/(mol*K)")),
        )

        # C[C]=O
        acetyl = Species(
            label='acetyl',
            thermo=Wilhoit(Cp0=(4.0*constants.R,"J/(mol*K)"), CpInf=(15.5*constants.R,"J/(mol*K)"), a0=0.2541, a1=-0.4712, a2=-4.434, a3=2.25, B=(500.0,"K"), H0=(-1.439e+05,"J/mol"), S0=(-524.6,"J/(mol*K)")),
        )

        # [O][O]
        oxygen = Species(
            label='oxygen',
            thermo=Wilhoit(Cp0=(3.5*constants.R,"J/(mol*K)"), CpInf=(4.5*constants.R,"J/(mol*K)"), a0=-0.9324, a1=26.18, a2=-70.47, a3=44.12, B=(500.0,"K"), H0=(1.453e+04,"J/mol"), S0=(-12.19,"J/(mol*K)")),
        )
        
        self.reaction2 = Reaction(
            reactants=[acetyl, oxygen], 
            products=[acetylperoxy], 
            kinetics = Arrhenius(
                A = (2.65e12, 'cm^3/(mol*s)'),
                n = 0.0,
                Ea = (0.0, 'kJ/mol'),
                T0 = (1, 'K'),
                Tmin = (300, 'K'),
                Tmax = (2000, 'K'),
            ),
        )
        
    def testIsIsomerization(self):
        """
        Test the Reaction.isIsomerization() method.
        """
        isomerization = Reaction(reactants=[Species()], products=[Species()])
        association = Reaction(reactants=[Species(),Species()], products=[Species()])
        dissociation = Reaction(reactants=[Species()], products=[Species(),Species()])
        bimolecular = Reaction(reactants=[Species(),Species()], products=[Species(),Species()])
        self.assertTrue(isomerization.isIsomerization())
        self.assertFalse(association.isIsomerization())
        self.assertFalse(dissociation.isIsomerization())
        self.assertFalse(bimolecular.isIsomerization())
        
    def testIsAssociation(self):
        """
        Test the Reaction.isAssociation() method.
        """
        isomerization = Reaction(reactants=[Species()], products=[Species()])
        association = Reaction(reactants=[Species(),Species()], products=[Species()])
        dissociation = Reaction(reactants=[Species()], products=[Species(),Species()])
        bimolecular = Reaction(reactants=[Species(),Species()], products=[Species(),Species()])
        self.assertFalse(isomerization.isAssociation())
        self.assertTrue(association.isAssociation())
        self.assertFalse(dissociation.isAssociation())
        self.assertFalse(bimolecular.isAssociation())

    def testIsDissociation(self):
        """
        Test the Reaction.isDissociation() method.
        """
        isomerization = Reaction(reactants=[Species()], products=[Species()])
        association = Reaction(reactants=[Species(),Species()], products=[Species()])
        dissociation = Reaction(reactants=[Species()], products=[Species(),Species()])
        bimolecular = Reaction(reactants=[Species(),Species()], products=[Species(),Species()])
        self.assertFalse(isomerization.isDissociation())
        self.assertFalse(association.isDissociation())
        self.assertTrue(dissociation.isDissociation())
        self.assertFalse(bimolecular.isDissociation())

    def testHasTemplate(self):
        """
        Test the Reaction.hasTemplate() method.
        """
        reactants = self.reaction.reactants[:]
        products = self.reaction.products[:]
        self.assertTrue(self.reaction.hasTemplate(reactants, products))
        self.assertTrue(self.reaction.hasTemplate(products, reactants))
        self.assertFalse(self.reaction2.hasTemplate(reactants, products))
        self.assertFalse(self.reaction2.hasTemplate(products, reactants))
        
        reactants.reverse()
        products.reverse()
        self.assertTrue(self.reaction.hasTemplate(reactants, products))
        self.assertTrue(self.reaction.hasTemplate(products, reactants))
        self.assertFalse(self.reaction2.hasTemplate(reactants, products))
        self.assertFalse(self.reaction2.hasTemplate(products, reactants))
        
        reactants = self.reaction2.reactants[:]
        products = self.reaction2.products[:]
        self.assertFalse(self.reaction.hasTemplate(reactants, products))
        self.assertFalse(self.reaction.hasTemplate(products, reactants))
        self.assertTrue(self.reaction2.hasTemplate(reactants, products))
        self.assertTrue(self.reaction2.hasTemplate(products, reactants))
        
        reactants.reverse()
        products.reverse()
        self.assertFalse(self.reaction.hasTemplate(reactants, products))
        self.assertFalse(self.reaction.hasTemplate(products, reactants))
        self.assertTrue(self.reaction2.hasTemplate(reactants, products))
        self.assertTrue(self.reaction2.hasTemplate(products, reactants))

    def testEnthalpyOfReaction(self):
        """
        Test the Reaction.getEnthalpyOfReaction() method.
        """
        Tlist = numpy.arange(200.0, 2001.0, 200.0, numpy.float64)
        Hlist0 = [float(v) for v in ['-146007', '-145886', '-144195', '-141973', '-139633', '-137341', '-135155', '-133093', '-131150', '-129316']]
        Hlist = self.reaction2.getEnthalpiesOfReaction(Tlist)
        for i in range(len(Tlist)):
            self.assertAlmostEqual(Hlist[i] / 1000., Hlist0[i] / 1000., 2)

    def testEntropyOfReaction(self):
        """
        Test the Reaction.getEntropyOfReaction() method.
        """
        Tlist = numpy.arange(200.0, 2001.0, 200.0, numpy.float64)
        Slist0 = [float(v) for v in ['-156.793', '-156.872', '-153.504', '-150.317', '-147.707', '-145.616', '-143.93', '-142.552', '-141.407', '-140.441']]
        Slist = self.reaction2.getEntropiesOfReaction(Tlist)
        for i in range(len(Tlist)):
            self.assertAlmostEqual(Slist[i], Slist0[i], 2)

    def testFreeEnergyOfReaction(self):
        """
        Test the Reaction.getFreeEnergyOfReaction() method.
        """
        Tlist = numpy.arange(200.0, 2001.0, 200.0, numpy.float64)
        Glist0 = [float(v) for v in ['-114648', '-83137.2', '-52092.4', '-21719.3', '8073.53', '37398.1', '66346.8', '94990.6', '123383', '151565']]
        Glist = self.reaction2.getFreeEnergiesOfReaction(Tlist)
        for i in range(len(Tlist)):
            self.assertAlmostEqual(Glist[i] / 1000., Glist0[i] / 1000., 2)

    def testEquilibriumConstantKa(self):
        """
        Test the Reaction.getEquilibriumConstant() method.
        """
        Tlist = numpy.arange(200.0, 2001.0, 200.0, numpy.float64)
        Kalist0 = [float(v) for v in ['8.75951e+29', '7.1843e+10', '34272.7', '26.1877', '0.378696', '0.0235579', '0.00334673', '0.000792389', '0.000262777', '0.000110053']]
        Kalist = self.reaction2.getEquilibriumConstants(Tlist, type='Ka')
        for i in range(len(Tlist)):
            self.assertAlmostEqual(Kalist[i] / Kalist0[i], 1.0, 4)

    def testEquilibriumConstantKc(self):
        """
        Test the Reaction.getEquilibriumConstant() method.
        """
        Tlist = numpy.arange(200.0, 2001.0, 200.0, numpy.float64)
        Kclist0 = [float(v) for v in ['1.45661e+28', '2.38935e+09', '1709.76', '1.74189', '0.0314866', '0.00235045', '0.000389568', '0.000105413', '3.93273e-05', '1.83006e-05']]
        Kclist = self.reaction2.getEquilibriumConstants(Tlist, type='Kc')
        for i in range(len(Tlist)):
            self.assertAlmostEqual(Kclist[i] / Kclist0[i], 1.0, 4)

    def testEquilibriumConstantKp(self):
        """
        Test the Reaction.getEquilibriumConstant() method.
        """
        Tlist = numpy.arange(200.0, 2001.0, 200.0, numpy.float64)
        Kplist0 = [float(v) for v in ['8.75951e+24', '718430', '0.342727', '0.000261877', '3.78696e-06', '2.35579e-07', '3.34673e-08', '7.92389e-09', '2.62777e-09', '1.10053e-09']]
        Kplist = self.reaction2.getEquilibriumConstants(Tlist, type='Kp')
        for i in range(len(Tlist)):
            self.assertAlmostEqual(Kplist[i] / Kplist0[i], 1.0, 4)

    def testStoichiometricCoefficient(self):
        """
        Test the Reaction.getStoichiometricCoefficient() method.
        """
        for reactant in self.reaction.reactants:
            self.assertEqual(self.reaction.getStoichiometricCoefficient(reactant), -1)
        for product in self.reaction.products:
            self.assertEqual(self.reaction.getStoichiometricCoefficient(product), 1)
        for reactant in self.reaction2.reactants:
            self.assertEqual(self.reaction.getStoichiometricCoefficient(reactant), 0)
        for product in self.reaction2.products:
            self.assertEqual(self.reaction.getStoichiometricCoefficient(product), 0)

    def testRateCoefficient(self):
        """
        Test the Reaction.getRateCoefficient() method.
        """
        Tlist = numpy.arange(200.0, 2001.0, 200.0, numpy.float64)
        P = 1e5
        for T in Tlist:
            self.assertAlmostEqual(self.reaction.getRateCoefficient(T, P) / self.reaction.kinetics.getRateCoefficient(T), 1.0, 6)
    
    def testGenerateReverseRateCoefficient(self):
        """
        Test the Reaction.generateReverseRateCoefficient() method.
        """
        Tlist = numpy.arange(200.0, 2001.0, 200.0, numpy.float64)
        P = 1e5
        reverseKinetics = self.reaction2.generateReverseRateCoefficient()
        for T in Tlist:
            kr0 = self.reaction2.getRateCoefficient(T, P) / self.reaction2.getEquilibriumConstant(T)
            kr = reverseKinetics.getRateCoefficient(T)
            self.assertAlmostEqual(kr0 / kr, 1.0, 0)

    def testTSTCalculation(self):
        """
        A test of the transition state theory k(T) calculation function,
        using the reaction H + C2H4 -> C2H5.
        """
        Tlist = 1000.0/numpy.arange(0.4, 3.35, 0.01)
        klist = numpy.array([self.reaction.calculateTSTRateCoefficient(T) for T in Tlist])
        arrhenius = Arrhenius().fitToData(Tlist, klist, kunits='m^3/(mol*s)')
        klist2 = numpy.array([arrhenius.getRateCoefficient(T) for T in Tlist])
        
        # Check that the correct Arrhenius parameters are returned
        self.assertAlmostEqual(arrhenius.A.value_si, 2265.2488, delta=1e-2)
        self.assertAlmostEqual(arrhenius.n.value_si, 1.45419, delta=1e-4)
        self.assertAlmostEqual(arrhenius.Ea.value_si, 6645.24, delta=1e-2)
        # Check that the fit is satisfactory (defined here as always within 5%)
        for i in range(len(Tlist)):
            self.assertAlmostEqual(klist[i], klist2[i], delta=5e-2 * klist[i])
        
    def testPickle(self):
        """
        Test that a Reaction object can be successfully pickled and
        unpickled with no loss of information.
        """
        import cPickle
        reaction = cPickle.loads(cPickle.dumps(self.reaction,-1))

        self.assertEqual(len(self.reaction.reactants), len(reaction.reactants))
        self.assertEqual(len(self.reaction.products), len(reaction.products))
        for reactant0, reactant in zip(self.reaction.reactants, reaction.reactants):
            self.assertAlmostEqual(reactant0.conformer.E0.value_si / 1e6, reactant.conformer.E0.value_si / 1e6, 2)
            self.assertEqual(reactant0.conformer.E0.units, reactant.conformer.E0.units)
        for product0, product in zip(self.reaction.products, reaction.products):
            self.assertAlmostEqual(product0.conformer.E0.value_si / 1e6, product.conformer.E0.value_si / 1e6, 2)
            self.assertEqual(product0.conformer.E0.units, product.conformer.E0.units)
        self.assertAlmostEqual(self.reaction.transitionState.conformer.E0.value_si / 1e6, reaction.transitionState.conformer.E0.value_si / 1e6, 2)
        self.assertEqual(self.reaction.transitionState.conformer.E0.units, reaction.transitionState.conformer.E0.units)
        self.assertAlmostEqual(self.reaction.transitionState.frequency.value_si, reaction.transitionState.frequency.value_si, 2)
        self.assertEqual(self.reaction.transitionState.frequency.units, reaction.transitionState.frequency.units)
        
        self.assertAlmostEqual(self.reaction.kinetics.A.value_si, reaction.kinetics.A.value_si, delta=1e-6)
        self.assertAlmostEqual(self.reaction.kinetics.n.value_si, reaction.kinetics.n.value_si, delta=1e-6)
        self.assertAlmostEqual(self.reaction.kinetics.T0.value_si, reaction.kinetics.T0.value_si, delta=1e-6)
        self.assertAlmostEqual(self.reaction.kinetics.Ea.value_si, reaction.kinetics.Ea.value_si, delta=1e-6)
        self.assertEqual(self.reaction.kinetics.comment, reaction.kinetics.comment)

        self.assertEqual(self.reaction.duplicate, reaction.duplicate)
        self.assertEqual(self.reaction.degeneracy, reaction.degeneracy)        

    def testOutput(self):
        """
        Test that a Reaction object can be successfully reconstructed
        from its repr() output with no loss of information.
        """
        exec('reaction = %r' % (self.reaction))

        self.assertEqual(len(self.reaction.reactants), len(reaction.reactants))
        self.assertEqual(len(self.reaction.products), len(reaction.products))
        for reactant0, reactant in zip(self.reaction.reactants, reaction.reactants):
            self.assertAlmostEqual(reactant0.conformer.E0.value_si / 1e6, reactant.conformer.E0.value_si / 1e6, 2)
            self.assertEqual(reactant0.conformer.E0.units, reactant.conformer.E0.units)
        for product0, product in zip(self.reaction.products, reaction.products):
            self.assertAlmostEqual(product0.conformer.E0.value_si / 1e6, product.conformer.E0.value_si / 1e6, 2)
            self.assertEqual(product0.conformer.E0.units, product.conformer.E0.units)
        self.assertAlmostEqual(self.reaction.transitionState.conformer.E0.value_si / 1e6, reaction.transitionState.conformer.E0.value_si / 1e6, 2)
        self.assertEqual(self.reaction.transitionState.conformer.E0.units, reaction.transitionState.conformer.E0.units)
        self.assertAlmostEqual(self.reaction.transitionState.frequency.value_si, reaction.transitionState.frequency.value_si, 2)
        self.assertEqual(self.reaction.transitionState.frequency.units, reaction.transitionState.frequency.units)
        
        self.assertAlmostEqual(self.reaction.kinetics.A.value_si, reaction.kinetics.A.value_si, delta=1e-6)
        self.assertAlmostEqual(self.reaction.kinetics.n.value_si, reaction.kinetics.n.value_si, delta=1e-6)
        self.assertAlmostEqual(self.reaction.kinetics.T0.value_si, reaction.kinetics.T0.value_si, delta=1e-6)
        self.assertAlmostEqual(self.reaction.kinetics.Ea.value_si, reaction.kinetics.Ea.value_si, delta=1e-6)
        self.assertEqual(self.reaction.kinetics.comment, reaction.kinetics.comment)
        
        self.assertEqual(self.reaction.duplicate, reaction.duplicate)
        self.assertEqual(self.reaction.degeneracy, reaction.degeneracy)   
Esempio n. 4
0
class TestReaction(unittest.TestCase):
    """
    Contains unit tests of the Reaction class.
    """
    def setUp(self):
        """
        A method that is called prior to each unit test in this class.
        """
        ethylene = Species(
            label='C2H4',
            conformer=Conformer(
                E0=(44.7127, 'kJ/mol'),
                modes=[
                    IdealGasTranslation(mass=(28.0313, 'amu'), ),
                    NonlinearRotor(
                        inertia=(
                            [3.41526, 16.6498, 20.065],
                            'amu*angstrom^2',
                        ),
                        symmetry=4,
                    ),
                    HarmonicOscillator(frequencies=(
                        [
                            828.397, 970.652, 977.223, 1052.93, 1233.55,
                            1367.56, 1465.09, 1672.25, 3098.46, 3111.7,
                            3165.79, 3193.54
                        ],
                        'cm^-1',
                    ), ),
                ],
                spinMultiplicity=1,
                opticalIsomers=1,
            ),
        )

        hydrogen = Species(
            label='H',
            conformer=Conformer(
                E0=(211.794, 'kJ/mol'),
                modes=[
                    IdealGasTranslation(mass=(1.00783, 'amu'), ),
                ],
                spinMultiplicity=2,
                opticalIsomers=1,
            ),
        )

        ethyl = Species(
            label='C2H5',
            conformer=Conformer(
                E0=(111.603, 'kJ/mol'),
                modes=[
                    IdealGasTranslation(mass=(29.0391, 'amu'), ),
                    NonlinearRotor(
                        inertia=(
                            [4.8709, 22.2353, 23.9925],
                            'amu*angstrom^2',
                        ),
                        symmetry=1,
                    ),
                    HarmonicOscillator(frequencies=(
                        [
                            482.224, 791.876, 974.355, 1051.48, 1183.21,
                            1361.36, 1448.65, 1455.07, 1465.48, 2688.22,
                            2954.51, 3033.39, 3101.54, 3204.73
                        ],
                        'cm^-1',
                    ), ),
                    HinderedRotor(
                        inertia=(1.11481, 'amu*angstrom^2'),
                        symmetry=6,
                        barrier=(0.244029, 'kJ/mol'),
                        semiclassical=None,
                    ),
                ],
                spinMultiplicity=2,
                opticalIsomers=1,
            ),
        )

        TS = TransitionState(
            label='TS',
            conformer=Conformer(
                E0=(266.694, 'kJ/mol'),
                modes=[
                    IdealGasTranslation(mass=(29.0391, 'amu'), ),
                    NonlinearRotor(
                        inertia=(
                            [6.78512, 22.1437, 22.2114],
                            'amu*angstrom^2',
                        ),
                        symmetry=1,
                    ),
                    HarmonicOscillator(frequencies=(
                        [
                            412.75, 415.206, 821.495, 924.44, 982.714, 1024.16,
                            1224.21, 1326.36, 1455.06, 1600.35, 3101.46,
                            3110.55, 3175.34, 3201.88
                        ],
                        'cm^-1',
                    ), ),
                ],
                spinMultiplicity=2,
                opticalIsomers=1,
            ),
            frequency=(-750.232, 'cm^-1'),
        )

        self.reaction = Reaction(
            reactants=[hydrogen, ethylene],
            products=[ethyl],
            kinetics=Arrhenius(
                A=(501366000.0, 'cm^3/(mol*s)'),
                n=1.637,
                Ea=(4.32508, 'kJ/mol'),
                T0=(1, 'K'),
                Tmin=(300, 'K'),
                Tmax=(2500, 'K'),
            ),
            transitionState=TS,
        )

        # CC(=O)O[O]
        acetylperoxy = Species(
            label='acetylperoxy',
            thermo=Wilhoit(Cp0=(4.0 * constants.R, "J/(mol*K)"),
                           CpInf=(21.0 * constants.R, "J/(mol*K)"),
                           a0=-3.95,
                           a1=9.26,
                           a2=-15.6,
                           a3=8.55,
                           B=(500.0, "K"),
                           H0=(-6.151e+04, "J/mol"),
                           S0=(-790.2, "J/(mol*K)")),
        )

        # C[C]=O
        acetyl = Species(
            label='acetyl',
            thermo=Wilhoit(Cp0=(4.0 * constants.R, "J/(mol*K)"),
                           CpInf=(15.5 * constants.R, "J/(mol*K)"),
                           a0=0.2541,
                           a1=-0.4712,
                           a2=-4.434,
                           a3=2.25,
                           B=(500.0, "K"),
                           H0=(-1.439e+05, "J/mol"),
                           S0=(-524.6, "J/(mol*K)")),
        )

        # [O][O]
        oxygen = Species(
            label='oxygen',
            thermo=Wilhoit(Cp0=(3.5 * constants.R, "J/(mol*K)"),
                           CpInf=(4.5 * constants.R, "J/(mol*K)"),
                           a0=-0.9324,
                           a1=26.18,
                           a2=-70.47,
                           a3=44.12,
                           B=(500.0, "K"),
                           H0=(1.453e+04, "J/mol"),
                           S0=(-12.19, "J/(mol*K)")),
        )

        self.reaction2 = Reaction(
            reactants=[acetyl, oxygen],
            products=[acetylperoxy],
            kinetics=Arrhenius(
                A=(2.65e12, 'cm^3/(mol*s)'),
                n=0.0,
                Ea=(0.0, 'kJ/mol'),
                T0=(1, 'K'),
                Tmin=(300, 'K'),
                Tmax=(2000, 'K'),
            ),
        )

    def testIsIsomerization(self):
        """
        Test the Reaction.isIsomerization() method.
        """
        isomerization = Reaction(reactants=[Species()], products=[Species()])
        association = Reaction(reactants=[Species(), Species()],
                               products=[Species()])
        dissociation = Reaction(reactants=[Species()],
                                products=[Species(), Species()])
        bimolecular = Reaction(reactants=[Species(), Species()],
                               products=[Species(), Species()])
        self.assertTrue(isomerization.isIsomerization())
        self.assertFalse(association.isIsomerization())
        self.assertFalse(dissociation.isIsomerization())
        self.assertFalse(bimolecular.isIsomerization())

    def testIsAssociation(self):
        """
        Test the Reaction.isAssociation() method.
        """
        isomerization = Reaction(reactants=[Species()], products=[Species()])
        association = Reaction(reactants=[Species(), Species()],
                               products=[Species()])
        dissociation = Reaction(reactants=[Species()],
                                products=[Species(), Species()])
        bimolecular = Reaction(reactants=[Species(), Species()],
                               products=[Species(), Species()])
        self.assertFalse(isomerization.isAssociation())
        self.assertTrue(association.isAssociation())
        self.assertFalse(dissociation.isAssociation())
        self.assertFalse(bimolecular.isAssociation())

    def testIsDissociation(self):
        """
        Test the Reaction.isDissociation() method.
        """
        isomerization = Reaction(reactants=[Species()], products=[Species()])
        association = Reaction(reactants=[Species(), Species()],
                               products=[Species()])
        dissociation = Reaction(reactants=[Species()],
                                products=[Species(), Species()])
        bimolecular = Reaction(reactants=[Species(), Species()],
                               products=[Species(), Species()])
        self.assertFalse(isomerization.isDissociation())
        self.assertFalse(association.isDissociation())
        self.assertTrue(dissociation.isDissociation())
        self.assertFalse(bimolecular.isDissociation())

    def testHasTemplate(self):
        """
        Test the Reaction.hasTemplate() method.
        """
        reactants = self.reaction.reactants[:]
        products = self.reaction.products[:]
        self.assertTrue(self.reaction.hasTemplate(reactants, products))
        self.assertTrue(self.reaction.hasTemplate(products, reactants))
        self.assertFalse(self.reaction2.hasTemplate(reactants, products))
        self.assertFalse(self.reaction2.hasTemplate(products, reactants))

        reactants.reverse()
        products.reverse()
        self.assertTrue(self.reaction.hasTemplate(reactants, products))
        self.assertTrue(self.reaction.hasTemplate(products, reactants))
        self.assertFalse(self.reaction2.hasTemplate(reactants, products))
        self.assertFalse(self.reaction2.hasTemplate(products, reactants))

        reactants = self.reaction2.reactants[:]
        products = self.reaction2.products[:]
        self.assertFalse(self.reaction.hasTemplate(reactants, products))
        self.assertFalse(self.reaction.hasTemplate(products, reactants))
        self.assertTrue(self.reaction2.hasTemplate(reactants, products))
        self.assertTrue(self.reaction2.hasTemplate(products, reactants))

        reactants.reverse()
        products.reverse()
        self.assertFalse(self.reaction.hasTemplate(reactants, products))
        self.assertFalse(self.reaction.hasTemplate(products, reactants))
        self.assertTrue(self.reaction2.hasTemplate(reactants, products))
        self.assertTrue(self.reaction2.hasTemplate(products, reactants))

    def testEnthalpyOfReaction(self):
        """
        Test the Reaction.getEnthalpyOfReaction() method.
        """
        Tlist = numpy.arange(200.0, 2001.0, 200.0, numpy.float64)
        Hlist0 = [
            float(v) for v in [
                '-146007', '-145886', '-144195', '-141973', '-139633',
                '-137341', '-135155', '-133093', '-131150', '-129316'
            ]
        ]
        Hlist = self.reaction2.getEnthalpiesOfReaction(Tlist)
        for i in range(len(Tlist)):
            self.assertAlmostEqual(Hlist[i] / 1000., Hlist0[i] / 1000., 2)

    def testEntropyOfReaction(self):
        """
        Test the Reaction.getEntropyOfReaction() method.
        """
        Tlist = numpy.arange(200.0, 2001.0, 200.0, numpy.float64)
        Slist0 = [
            float(v) for v in [
                '-156.793', '-156.872', '-153.504', '-150.317', '-147.707',
                '-145.616', '-143.93', '-142.552', '-141.407', '-140.441'
            ]
        ]
        Slist = self.reaction2.getEntropiesOfReaction(Tlist)
        for i in range(len(Tlist)):
            self.assertAlmostEqual(Slist[i], Slist0[i], 2)

    def testFreeEnergyOfReaction(self):
        """
        Test the Reaction.getFreeEnergyOfReaction() method.
        """
        Tlist = numpy.arange(200.0, 2001.0, 200.0, numpy.float64)
        Glist0 = [
            float(v) for v in [
                '-114648', '-83137.2', '-52092.4', '-21719.3', '8073.53',
                '37398.1', '66346.8', '94990.6', '123383', '151565'
            ]
        ]
        Glist = self.reaction2.getFreeEnergiesOfReaction(Tlist)
        for i in range(len(Tlist)):
            self.assertAlmostEqual(Glist[i] / 1000., Glist0[i] / 1000., 2)

    def testEquilibriumConstantKa(self):
        """
        Test the Reaction.getEquilibriumConstant() method.
        """
        Tlist = numpy.arange(200.0, 2001.0, 200.0, numpy.float64)
        Kalist0 = [
            float(v) for v in [
                '8.75951e+29', '7.1843e+10', '34272.7', '26.1877', '0.378696',
                '0.0235579', '0.00334673', '0.000792389', '0.000262777',
                '0.000110053'
            ]
        ]
        Kalist = self.reaction2.getEquilibriumConstants(Tlist, type='Ka')
        for i in range(len(Tlist)):
            self.assertAlmostEqual(Kalist[i] / Kalist0[i], 1.0, 4)

    def testEquilibriumConstantKc(self):
        """
        Test the Reaction.getEquilibriumConstant() method.
        """
        Tlist = numpy.arange(200.0, 2001.0, 200.0, numpy.float64)
        Kclist0 = [
            float(v) for v in [
                '1.45661e+28', '2.38935e+09', '1709.76', '1.74189',
                '0.0314866', '0.00235045', '0.000389568', '0.000105413',
                '3.93273e-05', '1.83006e-05'
            ]
        ]
        Kclist = self.reaction2.getEquilibriumConstants(Tlist, type='Kc')
        for i in range(len(Tlist)):
            self.assertAlmostEqual(Kclist[i] / Kclist0[i], 1.0, 4)

    def testEquilibriumConstantKp(self):
        """
        Test the Reaction.getEquilibriumConstant() method.
        """
        Tlist = numpy.arange(200.0, 2001.0, 200.0, numpy.float64)
        Kplist0 = [
            float(v) for v in [
                '8.75951e+24', '718430', '0.342727', '0.000261877',
                '3.78696e-06', '2.35579e-07', '3.34673e-08', '7.92389e-09',
                '2.62777e-09', '1.10053e-09'
            ]
        ]
        Kplist = self.reaction2.getEquilibriumConstants(Tlist, type='Kp')
        for i in range(len(Tlist)):
            self.assertAlmostEqual(Kplist[i] / Kplist0[i], 1.0, 4)

    def testStoichiometricCoefficient(self):
        """
        Test the Reaction.getStoichiometricCoefficient() method.
        """
        for reactant in self.reaction.reactants:
            self.assertEqual(
                self.reaction.getStoichiometricCoefficient(reactant), -1)
        for product in self.reaction.products:
            self.assertEqual(
                self.reaction.getStoichiometricCoefficient(product), 1)
        for reactant in self.reaction2.reactants:
            self.assertEqual(
                self.reaction.getStoichiometricCoefficient(reactant), 0)
        for product in self.reaction2.products:
            self.assertEqual(
                self.reaction.getStoichiometricCoefficient(product), 0)

    def testRateCoefficient(self):
        """
        Test the Reaction.getRateCoefficient() method.
        """
        Tlist = numpy.arange(200.0, 2001.0, 200.0, numpy.float64)
        P = 1e5
        for T in Tlist:
            self.assertAlmostEqual(
                self.reaction.getRateCoefficient(T, P) /
                self.reaction.kinetics.getRateCoefficient(T), 1.0, 6)

    def testGenerateReverseRateCoefficient(self):
        """
        Test the Reaction.generateReverseRateCoefficient() method.
        """
        Tlist = numpy.arange(200.0, 2001.0, 200.0, numpy.float64)
        P = 1e5
        reverseKinetics = self.reaction2.generateReverseRateCoefficient()
        for T in Tlist:
            kr0 = self.reaction2.getRateCoefficient(
                T, P) / self.reaction2.getEquilibriumConstant(T)
            kr = reverseKinetics.getRateCoefficient(T)
            self.assertAlmostEqual(kr0 / kr, 1.0, 0)

    def testTSTCalculation(self):
        """
        A test of the transition state theory k(T) calculation function,
        using the reaction H + C2H4 -> C2H5.
        """
        Tlist = 1000.0 / numpy.arange(0.4, 3.35, 0.01)
        klist = numpy.array(
            [self.reaction.calculateTSTRateCoefficient(T) for T in Tlist])
        arrhenius = Arrhenius().fitToData(Tlist, klist, kunits='m^3/(mol*s)')
        klist2 = numpy.array([arrhenius.getRateCoefficient(T) for T in Tlist])

        # Check that the correct Arrhenius parameters are returned
        self.assertAlmostEqual(arrhenius.A.value_si, 2265.2488, delta=1e-2)
        self.assertAlmostEqual(arrhenius.n.value_si, 1.45419, delta=1e-4)
        self.assertAlmostEqual(arrhenius.Ea.value_si, 6645.24, delta=1e-2)
        # Check that the fit is satisfactory (defined here as always within 5%)
        for i in range(len(Tlist)):
            self.assertAlmostEqual(klist[i], klist2[i], delta=5e-2 * klist[i])

    def testPickle(self):
        """
        Test that a Reaction object can be successfully pickled and
        unpickled with no loss of information.
        """
        import cPickle
        reaction = cPickle.loads(cPickle.dumps(self.reaction, -1))

        self.assertEqual(len(self.reaction.reactants), len(reaction.reactants))
        self.assertEqual(len(self.reaction.products), len(reaction.products))
        for reactant0, reactant in zip(self.reaction.reactants,
                                       reaction.reactants):
            self.assertAlmostEqual(reactant0.conformer.E0.value_si / 1e6,
                                   reactant.conformer.E0.value_si / 1e6, 2)
            self.assertEqual(reactant0.conformer.E0.units,
                             reactant.conformer.E0.units)
        for product0, product in zip(self.reaction.products,
                                     reaction.products):
            self.assertAlmostEqual(product0.conformer.E0.value_si / 1e6,
                                   product.conformer.E0.value_si / 1e6, 2)
            self.assertEqual(product0.conformer.E0.units,
                             product.conformer.E0.units)
        self.assertAlmostEqual(
            self.reaction.transitionState.conformer.E0.value_si / 1e6,
            reaction.transitionState.conformer.E0.value_si / 1e6, 2)
        self.assertEqual(self.reaction.transitionState.conformer.E0.units,
                         reaction.transitionState.conformer.E0.units)
        self.assertAlmostEqual(
            self.reaction.transitionState.frequency.value_si,
            reaction.transitionState.frequency.value_si, 2)
        self.assertEqual(self.reaction.transitionState.frequency.units,
                         reaction.transitionState.frequency.units)

        self.assertAlmostEqual(self.reaction.kinetics.A.value_si,
                               reaction.kinetics.A.value_si,
                               delta=1e-6)
        self.assertAlmostEqual(self.reaction.kinetics.n.value_si,
                               reaction.kinetics.n.value_si,
                               delta=1e-6)
        self.assertAlmostEqual(self.reaction.kinetics.T0.value_si,
                               reaction.kinetics.T0.value_si,
                               delta=1e-6)
        self.assertAlmostEqual(self.reaction.kinetics.Ea.value_si,
                               reaction.kinetics.Ea.value_si,
                               delta=1e-6)
        self.assertEqual(self.reaction.kinetics.comment,
                         reaction.kinetics.comment)

        self.assertEqual(self.reaction.duplicate, reaction.duplicate)
        self.assertEqual(self.reaction.degeneracy, reaction.degeneracy)

    def testOutput(self):
        """
        Test that a Reaction object can be successfully reconstructed
        from its repr() output with no loss of information.
        """
        exec('reaction = %r' % (self.reaction))

        self.assertEqual(len(self.reaction.reactants), len(reaction.reactants))
        self.assertEqual(len(self.reaction.products), len(reaction.products))
        for reactant0, reactant in zip(self.reaction.reactants,
                                       reaction.reactants):
            self.assertAlmostEqual(reactant0.conformer.E0.value_si / 1e6,
                                   reactant.conformer.E0.value_si / 1e6, 2)
            self.assertEqual(reactant0.conformer.E0.units,
                             reactant.conformer.E0.units)
        for product0, product in zip(self.reaction.products,
                                     reaction.products):
            self.assertAlmostEqual(product0.conformer.E0.value_si / 1e6,
                                   product.conformer.E0.value_si / 1e6, 2)
            self.assertEqual(product0.conformer.E0.units,
                             product.conformer.E0.units)
        self.assertAlmostEqual(
            self.reaction.transitionState.conformer.E0.value_si / 1e6,
            reaction.transitionState.conformer.E0.value_si / 1e6, 2)
        self.assertEqual(self.reaction.transitionState.conformer.E0.units,
                         reaction.transitionState.conformer.E0.units)
        self.assertAlmostEqual(
            self.reaction.transitionState.frequency.value_si,
            reaction.transitionState.frequency.value_si, 2)
        self.assertEqual(self.reaction.transitionState.frequency.units,
                         reaction.transitionState.frequency.units)

        self.assertAlmostEqual(self.reaction.kinetics.A.value_si,
                               reaction.kinetics.A.value_si,
                               delta=1e-6)
        self.assertAlmostEqual(self.reaction.kinetics.n.value_si,
                               reaction.kinetics.n.value_si,
                               delta=1e-6)
        self.assertAlmostEqual(self.reaction.kinetics.T0.value_si,
                               reaction.kinetics.T0.value_si,
                               delta=1e-6)
        self.assertAlmostEqual(self.reaction.kinetics.Ea.value_si,
                               reaction.kinetics.Ea.value_si,
                               delta=1e-6)
        self.assertEqual(self.reaction.kinetics.comment,
                         reaction.kinetics.comment)

        self.assertEqual(self.reaction.duplicate, reaction.duplicate)
        self.assertEqual(self.reaction.degeneracy, reaction.degeneracy)
Esempio n. 5
0
class TestReaction(unittest.TestCase):
    """
    Contains unit tests of the Reaction class.
    """

    def setUp(self):
        """
        A method that is called prior to each unit test in this class.
        """
        ethylene = Species(
            label="C2H4",
            conformer=Conformer(
                E0=(44.7127, "kJ/mol"),
                modes=[
                    IdealGasTranslation(mass=(28.0313, "amu")),
                    NonlinearRotor(inertia=([3.41526, 16.6498, 20.065], "amu*angstrom^2"), symmetry=4),
                    HarmonicOscillator(
                        frequencies=(
                            [
                                828.397,
                                970.652,
                                977.223,
                                1052.93,
                                1233.55,
                                1367.56,
                                1465.09,
                                1672.25,
                                3098.46,
                                3111.7,
                                3165.79,
                                3193.54,
                            ],
                            "cm^-1",
                        )
                    ),
                ],
                spinMultiplicity=1,
                opticalIsomers=1,
            ),
        )

        hydrogen = Species(
            label="H",
            conformer=Conformer(
                E0=(211.794, "kJ/mol"),
                modes=[IdealGasTranslation(mass=(1.00783, "amu"))],
                spinMultiplicity=2,
                opticalIsomers=1,
            ),
        )

        ethyl = Species(
            label="C2H5",
            conformer=Conformer(
                E0=(111.603, "kJ/mol"),
                modes=[
                    IdealGasTranslation(mass=(29.0391, "amu")),
                    NonlinearRotor(inertia=([4.8709, 22.2353, 23.9925], "amu*angstrom^2"), symmetry=1),
                    HarmonicOscillator(
                        frequencies=(
                            [
                                482.224,
                                791.876,
                                974.355,
                                1051.48,
                                1183.21,
                                1361.36,
                                1448.65,
                                1455.07,
                                1465.48,
                                2688.22,
                                2954.51,
                                3033.39,
                                3101.54,
                                3204.73,
                            ],
                            "cm^-1",
                        )
                    ),
                    HinderedRotor(
                        inertia=(1.11481, "amu*angstrom^2"),
                        symmetry=6,
                        barrier=(0.244029, "kJ/mol"),
                        semiclassical=None,
                    ),
                ],
                spinMultiplicity=2,
                opticalIsomers=1,
            ),
        )

        TS = TransitionState(
            label="TS",
            conformer=Conformer(
                E0=(266.694, "kJ/mol"),
                modes=[
                    IdealGasTranslation(mass=(29.0391, "amu")),
                    NonlinearRotor(inertia=([6.78512, 22.1437, 22.2114], "amu*angstrom^2"), symmetry=1),
                    HarmonicOscillator(
                        frequencies=(
                            [
                                412.75,
                                415.206,
                                821.495,
                                924.44,
                                982.714,
                                1024.16,
                                1224.21,
                                1326.36,
                                1455.06,
                                1600.35,
                                3101.46,
                                3110.55,
                                3175.34,
                                3201.88,
                            ],
                            "cm^-1",
                        )
                    ),
                ],
                spinMultiplicity=2,
                opticalIsomers=1,
            ),
            frequency=(-750.232, "cm^-1"),
        )

        self.reaction = Reaction(
            reactants=[hydrogen, ethylene],
            products=[ethyl],
            kinetics=Arrhenius(
                A=(501366000.0, "cm^3/(mol*s)"),
                n=1.637,
                Ea=(4.32508, "kJ/mol"),
                T0=(1, "K"),
                Tmin=(300, "K"),
                Tmax=(2500, "K"),
            ),
            transitionState=TS,
        )

        # CC(=O)O[O]
        acetylperoxy = Species(
            label="acetylperoxy",
            thermo=Wilhoit(
                Cp0=(4.0 * constants.R, "J/(mol*K)"),
                CpInf=(21.0 * constants.R, "J/(mol*K)"),
                a0=-3.95,
                a1=9.26,
                a2=-15.6,
                a3=8.55,
                B=(500.0, "K"),
                H0=(-6.151e04, "J/mol"),
                S0=(-790.2, "J/(mol*K)"),
            ),
        )

        # C[C]=O
        acetyl = Species(
            label="acetyl",
            thermo=Wilhoit(
                Cp0=(4.0 * constants.R, "J/(mol*K)"),
                CpInf=(15.5 * constants.R, "J/(mol*K)"),
                a0=0.2541,
                a1=-0.4712,
                a2=-4.434,
                a3=2.25,
                B=(500.0, "K"),
                H0=(-1.439e05, "J/mol"),
                S0=(-524.6, "J/(mol*K)"),
            ),
        )

        # [O][O]
        oxygen = Species(
            label="oxygen",
            thermo=Wilhoit(
                Cp0=(3.5 * constants.R, "J/(mol*K)"),
                CpInf=(4.5 * constants.R, "J/(mol*K)"),
                a0=-0.9324,
                a1=26.18,
                a2=-70.47,
                a3=44.12,
                B=(500.0, "K"),
                H0=(1.453e04, "J/mol"),
                S0=(-12.19, "J/(mol*K)"),
            ),
        )

        self.reaction2 = Reaction(
            reactants=[acetyl, oxygen],
            products=[acetylperoxy],
            kinetics=Arrhenius(
                A=(2.65e12, "cm^3/(mol*s)"), n=0.0, Ea=(0.0, "kJ/mol"), T0=(1, "K"), Tmin=(300, "K"), Tmax=(2000, "K")
            ),
        )

    def testIsIsomerization(self):
        """
        Test the Reaction.isIsomerization() method.
        """
        isomerization = Reaction(reactants=[Species()], products=[Species()])
        association = Reaction(reactants=[Species(), Species()], products=[Species()])
        dissociation = Reaction(reactants=[Species()], products=[Species(), Species()])
        bimolecular = Reaction(reactants=[Species(), Species()], products=[Species(), Species()])
        self.assertTrue(isomerization.isIsomerization())
        self.assertFalse(association.isIsomerization())
        self.assertFalse(dissociation.isIsomerization())
        self.assertFalse(bimolecular.isIsomerization())

    def testIsAssociation(self):
        """
        Test the Reaction.isAssociation() method.
        """
        isomerization = Reaction(reactants=[Species()], products=[Species()])
        association = Reaction(reactants=[Species(), Species()], products=[Species()])
        dissociation = Reaction(reactants=[Species()], products=[Species(), Species()])
        bimolecular = Reaction(reactants=[Species(), Species()], products=[Species(), Species()])
        self.assertFalse(isomerization.isAssociation())
        self.assertTrue(association.isAssociation())
        self.assertFalse(dissociation.isAssociation())
        self.assertFalse(bimolecular.isAssociation())

    def testIsDissociation(self):
        """
        Test the Reaction.isDissociation() method.
        """
        isomerization = Reaction(reactants=[Species()], products=[Species()])
        association = Reaction(reactants=[Species(), Species()], products=[Species()])
        dissociation = Reaction(reactants=[Species()], products=[Species(), Species()])
        bimolecular = Reaction(reactants=[Species(), Species()], products=[Species(), Species()])
        self.assertFalse(isomerization.isDissociation())
        self.assertFalse(association.isDissociation())
        self.assertTrue(dissociation.isDissociation())
        self.assertFalse(bimolecular.isDissociation())

    def testHasTemplate(self):
        """
        Test the Reaction.hasTemplate() method.
        """
        reactants = self.reaction.reactants[:]
        products = self.reaction.products[:]
        self.assertTrue(self.reaction.hasTemplate(reactants, products))
        self.assertTrue(self.reaction.hasTemplate(products, reactants))
        self.assertFalse(self.reaction2.hasTemplate(reactants, products))
        self.assertFalse(self.reaction2.hasTemplate(products, reactants))

        reactants.reverse()
        products.reverse()
        self.assertTrue(self.reaction.hasTemplate(reactants, products))
        self.assertTrue(self.reaction.hasTemplate(products, reactants))
        self.assertFalse(self.reaction2.hasTemplate(reactants, products))
        self.assertFalse(self.reaction2.hasTemplate(products, reactants))

        reactants = self.reaction2.reactants[:]
        products = self.reaction2.products[:]
        self.assertFalse(self.reaction.hasTemplate(reactants, products))
        self.assertFalse(self.reaction.hasTemplate(products, reactants))
        self.assertTrue(self.reaction2.hasTemplate(reactants, products))
        self.assertTrue(self.reaction2.hasTemplate(products, reactants))

        reactants.reverse()
        products.reverse()
        self.assertFalse(self.reaction.hasTemplate(reactants, products))
        self.assertFalse(self.reaction.hasTemplate(products, reactants))
        self.assertTrue(self.reaction2.hasTemplate(reactants, products))
        self.assertTrue(self.reaction2.hasTemplate(products, reactants))

    def testEnthalpyOfReaction(self):
        """
        Test the Reaction.getEnthalpyOfReaction() method.
        """
        Tlist = numpy.arange(200.0, 2001.0, 200.0, numpy.float64)
        Hlist0 = [
            float(v)
            for v in [
                "-146007",
                "-145886",
                "-144195",
                "-141973",
                "-139633",
                "-137341",
                "-135155",
                "-133093",
                "-131150",
                "-129316",
            ]
        ]
        Hlist = self.reaction2.getEnthalpiesOfReaction(Tlist)
        for i in range(len(Tlist)):
            self.assertAlmostEqual(Hlist[i] / 1000.0, Hlist0[i] / 1000.0, 2)

    def testEntropyOfReaction(self):
        """
        Test the Reaction.getEntropyOfReaction() method.
        """
        Tlist = numpy.arange(200.0, 2001.0, 200.0, numpy.float64)
        Slist0 = [
            float(v)
            for v in [
                "-156.793",
                "-156.872",
                "-153.504",
                "-150.317",
                "-147.707",
                "-145.616",
                "-143.93",
                "-142.552",
                "-141.407",
                "-140.441",
            ]
        ]
        Slist = self.reaction2.getEntropiesOfReaction(Tlist)
        for i in range(len(Tlist)):
            self.assertAlmostEqual(Slist[i], Slist0[i], 2)

    def testFreeEnergyOfReaction(self):
        """
        Test the Reaction.getFreeEnergyOfReaction() method.
        """
        Tlist = numpy.arange(200.0, 2001.0, 200.0, numpy.float64)
        Glist0 = [
            float(v)
            for v in [
                "-114648",
                "-83137.2",
                "-52092.4",
                "-21719.3",
                "8073.53",
                "37398.1",
                "66346.8",
                "94990.6",
                "123383",
                "151565",
            ]
        ]
        Glist = self.reaction2.getFreeEnergiesOfReaction(Tlist)
        for i in range(len(Tlist)):
            self.assertAlmostEqual(Glist[i] / 1000.0, Glist0[i] / 1000.0, 2)

    def testEquilibriumConstantKa(self):
        """
        Test the Reaction.getEquilibriumConstant() method.
        """
        Tlist = numpy.arange(200.0, 2001.0, 200.0, numpy.float64)
        Kalist0 = [
            float(v)
            for v in [
                "8.75951e+29",
                "7.1843e+10",
                "34272.7",
                "26.1877",
                "0.378696",
                "0.0235579",
                "0.00334673",
                "0.000792389",
                "0.000262777",
                "0.000110053",
            ]
        ]
        Kalist = self.reaction2.getEquilibriumConstants(Tlist, type="Ka")
        for i in range(len(Tlist)):
            self.assertAlmostEqual(Kalist[i] / Kalist0[i], 1.0, 4)

    def testEquilibriumConstantKc(self):
        """
        Test the Reaction.getEquilibriumConstant() method.
        """
        Tlist = numpy.arange(200.0, 2001.0, 200.0, numpy.float64)
        Kclist0 = [
            float(v)
            for v in [
                "1.45661e+28",
                "2.38935e+09",
                "1709.76",
                "1.74189",
                "0.0314866",
                "0.00235045",
                "0.000389568",
                "0.000105413",
                "3.93273e-05",
                "1.83006e-05",
            ]
        ]
        Kclist = self.reaction2.getEquilibriumConstants(Tlist, type="Kc")
        for i in range(len(Tlist)):
            self.assertAlmostEqual(Kclist[i] / Kclist0[i], 1.0, 4)

    def testEquilibriumConstantKp(self):
        """
        Test the Reaction.getEquilibriumConstant() method.
        """
        Tlist = numpy.arange(200.0, 2001.0, 200.0, numpy.float64)
        Kplist0 = [
            float(v)
            for v in [
                "8.75951e+24",
                "718430",
                "0.342727",
                "0.000261877",
                "3.78696e-06",
                "2.35579e-07",
                "3.34673e-08",
                "7.92389e-09",
                "2.62777e-09",
                "1.10053e-09",
            ]
        ]
        Kplist = self.reaction2.getEquilibriumConstants(Tlist, type="Kp")
        for i in range(len(Tlist)):
            self.assertAlmostEqual(Kplist[i] / Kplist0[i], 1.0, 4)

    def testStoichiometricCoefficient(self):
        """
        Test the Reaction.getStoichiometricCoefficient() method.
        """
        for reactant in self.reaction.reactants:
            self.assertEqual(self.reaction.getStoichiometricCoefficient(reactant), -1)
        for product in self.reaction.products:
            self.assertEqual(self.reaction.getStoichiometricCoefficient(product), 1)
        for reactant in self.reaction2.reactants:
            self.assertEqual(self.reaction.getStoichiometricCoefficient(reactant), 0)
        for product in self.reaction2.products:
            self.assertEqual(self.reaction.getStoichiometricCoefficient(product), 0)

    def testRateCoefficient(self):
        """
        Test the Reaction.getRateCoefficient() method.
        """
        Tlist = numpy.arange(200.0, 2001.0, 200.0, numpy.float64)
        P = 1e5
        for T in Tlist:
            self.assertAlmostEqual(
                self.reaction.getRateCoefficient(T, P) / self.reaction.kinetics.getRateCoefficient(T), 1.0, 6
            )

    def testGenerateReverseRateCoefficient(self):
        """
        Test the Reaction.generateReverseRateCoefficient() method.
        """
        Tlist = numpy.arange(200.0, 2001.0, 200.0, numpy.float64)
        P = 1e5
        reverseKinetics = self.reaction2.generateReverseRateCoefficient()
        for T in Tlist:
            kr0 = self.reaction2.getRateCoefficient(T, P) / self.reaction2.getEquilibriumConstant(T)
            kr = reverseKinetics.getRateCoefficient(T)
            self.assertAlmostEqual(kr0 / kr, 1.0, 0)

    def testGenerateReverseRateCoefficientArrhenius(self):
        """
        Test the Reaction.generateReverseRateCoefficient() method works for the Arrhenius format.
        """
        original_kinetics = Arrhenius(
            A=(2.65e12, "cm^3/(mol*s)"), n=0.0, Ea=(0.0, "kJ/mol"), T0=(1, "K"), Tmin=(300, "K"), Tmax=(2000, "K")
        )
        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(original_kinetics.Tmin.value_si, original_kinetics.Tmax.value_si, 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)

    @work_in_progress
    def testGenerateReverseRateCoefficientArrheniusEP(self):
        """
        Test the Reaction.generateReverseRateCoefficient() method works for the ArrheniusEP format.
        """
        from rmgpy.kinetics import ArrheniusEP

        original_kinetics = ArrheniusEP(
            A=(2.65e12, "cm^3/(mol*s)"), n=0.0, alpha=0.5, E0=(41.84, "kJ/mol"), Tmin=(300, "K"), Tmax=(2000, "K")
        )
        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(original_kinetics.Tmin, original_kinetics.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 testGenerateReverseRateCoefficientPDepArrhenius(self):
        """
        Test the Reaction.generateReverseRateCoefficient() method works for the PDepArrhenius format.
        """
        from rmgpy.kinetics import PDepArrhenius

        arrhenius0 = 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 = Arrhenius(
            A=(1.0e12, "s^-1"),
            n=1.0,
            Ea=(20.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])
        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
        Tmax = 2000.0
        Pmin = 0.1
        Pmax = 10.0
        comment = """This data is completely made up"""

        arrhenius = [
            Arrhenius(
                A=(9.3e-14, "cm^3/(molecule*s)"),
                n=0.0,
                Ea=(4740 * constants.R * 0.001, "kJ/mol"),
                T0=(1, "K"),
                Tmin=(Tmin, "K"),
                Tmax=(Tmax, "K"),
                comment=comment,
            ),
            Arrhenius(
                A=(1.4e-9, "cm^3/(molecule*s)"),
                n=0.0,
                Ea=(11200 * constants.R * 0.001, "kJ/mol"),
                T0=(1, "K"),
                Tmin=(Tmin, "K"),
                Tmax=(Tmax, "K"),
                comment=comment,
            ),
        ]

        original_kinetics = MultiArrhenius(arrhenius=arrhenius, Tmin=(Tmin, "K"), Tmax=(Tmax, "K"), 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 testGenerateReverseRateCoefficientMultiPDepArrhenius(self):
        """
        Test the Reaction.generateReverseRateCoefficient() method works for the MultiPDepArrhenius format.
        """
        from rmgpy.kinetics import PDepArrhenius, MultiPDepArrhenius

        Tmin = 350.0
        Tmax = 1500.0
        Pmin = 1e-1
        Pmax = 1e1
        pressures = numpy.array([1e-1, 1e1])
        comment = "CH3 + C2H6 <=> CH4 + C2H5 (Baulch 2005)"
        arrhenius = [
            PDepArrhenius(
                pressures=(pressures, "bar"),
                arrhenius=[
                    Arrhenius(
                        A=(9.3e-16, "cm^3/(molecule*s)"),
                        n=0.0,
                        Ea=(4740 * constants.R * 0.001, "kJ/mol"),
                        T0=(1, "K"),
                        Tmin=(Tmin, "K"),
                        Tmax=(Tmax, "K"),
                        comment=comment,
                    ),
                    Arrhenius(
                        A=(9.3e-14, "cm^3/(molecule*s)"),
                        n=0.0,
                        Ea=(4740 * constants.R * 0.001, "kJ/mol"),
                        T0=(1, "K"),
                        Tmin=(Tmin, "K"),
                        Tmax=(Tmax, "K"),
                        comment=comment,
                    ),
                ],
                Tmin=(Tmin, "K"),
                Tmax=(Tmax, "K"),
                Pmin=(Pmin, "bar"),
                Pmax=(Pmax, "bar"),
                comment=comment,
            ),
            PDepArrhenius(
                pressures=(pressures, "bar"),
                arrhenius=[
                    Arrhenius(
                        A=(1.4e-11, "cm^3/(molecule*s)"),
                        n=0.0,
                        Ea=(11200 * constants.R * 0.001, "kJ/mol"),
                        T0=(1, "K"),
                        Tmin=(Tmin, "K"),
                        Tmax=(Tmax, "K"),
                        comment=comment,
                    ),
                    Arrhenius(
                        A=(1.4e-9, "cm^3/(molecule*s)"),
                        n=0.0,
                        Ea=(11200 * constants.R * 0.001, "kJ/mol"),
                        T0=(1, "K"),
                        Tmin=(Tmin, "K"),
                        Tmax=(Tmax, "K"),
                        comment=comment,
                    ),
                ],
                Tmin=(Tmin, "K"),
                Tmax=(Tmax, "K"),
                Pmin=(Pmin, "bar"),
                Pmax=(Pmax, "bar"),
                comment=comment,
            ),
        ]

        original_kinetics = MultiPDepArrhenius(
            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 testGenerateReverseRateCoefficientThirdBody(self):
        """
        Test the Reaction.generateReverseRateCoefficient() method works for the ThirdBody format.
        """

        from rmgpy.kinetics import ThirdBody

        arrheniusLow = Arrhenius(A=(2.62e33, "cm^6/(mol^2*s)"), n=-4.76, Ea=(10.21, "kJ/mol"), T0=(1, "K"))
        efficiencies = {"C": 3, "C(=O)=O": 2, "CC": 3, "O": 6, "[Ar]": 0.7, "[C]=O": 1.5, "[H][H]": 2}
        Tmin = 300.0
        Tmax = 2000.0
        Pmin = 0.01
        Pmax = 100.0
        comment = """H + CH3 -> CH4"""
        thirdBody = ThirdBody(
            arrheniusLow=arrheniusLow,
            Tmin=(Tmin, "K"),
            Tmax=(Tmax, "K"),
            Pmin=(Pmin, "bar"),
            Pmax=(Pmax, "bar"),
            efficiencies=efficiencies,
            comment=comment,
        )

        original_kinetics = thirdBody

        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 testGenerateReverseRateCoefficientLindemann(self):
        """
        Test the Reaction.generateReverseRateCoefficient() method works for the Lindemann format.
        """

        from rmgpy.kinetics import Lindemann

        arrheniusHigh = Arrhenius(A=(1.39e16, "cm^3/(mol*s)"), n=-0.534, Ea=(2.243, "kJ/mol"), T0=(1, "K"))
        arrheniusLow = Arrhenius(A=(2.62e33, "cm^6/(mol^2*s)"), n=-4.76, Ea=(10.21, "kJ/mol"), T0=(1, "K"))
        efficiencies = {"C": 3, "C(=O)=O": 2, "CC": 3, "O": 6, "[Ar]": 0.7, "[C]=O": 1.5, "[H][H]": 2}
        Tmin = 300.0
        Tmax = 2000.0
        Pmin = 0.01
        Pmax = 100.0
        comment = """H + CH3 -> CH4"""
        lindemann = Lindemann(
            arrheniusHigh=arrheniusHigh,
            arrheniusLow=arrheniusLow,
            Tmin=(Tmin, "K"),
            Tmax=(Tmax, "K"),
            Pmin=(Pmin, "bar"),
            Pmax=(Pmax, "bar"),
            efficiencies=efficiencies,
            comment=comment,
        )

        original_kinetics = lindemann

        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 testGenerateReverseRateCoefficientTroe(self):
        """
        Test the Reaction.generateReverseRateCoefficient() method works for the Troe format.
        """

        from rmgpy.kinetics import Troe

        arrheniusHigh = Arrhenius(A=(1.39e16, "cm^3/(mol*s)"), n=-0.534, Ea=(2.243, "kJ/mol"), T0=(1, "K"))
        arrheniusLow = Arrhenius(A=(2.62e33, "cm^6/(mol^2*s)"), n=-4.76, Ea=(10.21, "kJ/mol"), T0=(1, "K"))
        alpha = 0.783
        T3 = 74
        T1 = 2941
        T2 = 6964
        efficiencies = {"C": 3, "C(=O)=O": 2, "CC": 3, "O": 6, "[Ar]": 0.7, "[C]=O": 1.5, "[H][H]": 2}
        Tmin = 300.0
        Tmax = 2000.0
        Pmin = 0.01
        Pmax = 100.0
        comment = """H + CH3 -> CH4"""
        troe = Troe(
            arrheniusHigh=arrheniusHigh,
            arrheniusLow=arrheniusLow,
            alpha=alpha,
            T3=(T3, "K"),
            T1=(T1, "K"),
            T2=(T2, "K"),
            Tmin=(Tmin, "K"),
            Tmax=(Tmax, "K"),
            Pmin=(Pmin, "bar"),
            Pmax=(Pmax, "bar"),
            efficiencies=efficiencies,
            comment=comment,
        )

        original_kinetics = troe

        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 testTSTCalculation(self):
        """
        A test of the transition state theory k(T) calculation function,
        using the reaction H + C2H4 -> C2H5.
        """
        Tlist = 1000.0 / numpy.arange(0.4, 3.35, 0.01)
        klist = numpy.array([self.reaction.calculateTSTRateCoefficient(T) for T in Tlist])
        arrhenius = Arrhenius().fitToData(Tlist, klist, kunits="m^3/(mol*s)")
        klist2 = numpy.array([arrhenius.getRateCoefficient(T) for T in Tlist])

        # Check that the correct Arrhenius parameters are returned
        self.assertAlmostEqual(arrhenius.A.value_si, 2265.2488, delta=1e-2)
        self.assertAlmostEqual(arrhenius.n.value_si, 1.45419, delta=1e-4)
        self.assertAlmostEqual(arrhenius.Ea.value_si, 6645.24, delta=1e-2)
        # Check that the fit is satisfactory (defined here as always within 5%)
        for i in range(len(Tlist)):
            self.assertAlmostEqual(klist[i], klist2[i], delta=5e-2 * klist[i])

    def testPickle(self):
        """
        Test that a Reaction object can be successfully pickled and
        unpickled with no loss of information.
        """
        import cPickle

        reaction = cPickle.loads(cPickle.dumps(self.reaction, -1))

        self.assertEqual(len(self.reaction.reactants), len(reaction.reactants))
        self.assertEqual(len(self.reaction.products), len(reaction.products))
        for reactant0, reactant in zip(self.reaction.reactants, reaction.reactants):
            self.assertAlmostEqual(reactant0.conformer.E0.value_si / 1e6, reactant.conformer.E0.value_si / 1e6, 2)
            self.assertEqual(reactant0.conformer.E0.units, reactant.conformer.E0.units)
        for product0, product in zip(self.reaction.products, reaction.products):
            self.assertAlmostEqual(product0.conformer.E0.value_si / 1e6, product.conformer.E0.value_si / 1e6, 2)
            self.assertEqual(product0.conformer.E0.units, product.conformer.E0.units)
        self.assertAlmostEqual(
            self.reaction.transitionState.conformer.E0.value_si / 1e6,
            reaction.transitionState.conformer.E0.value_si / 1e6,
            2,
        )
        self.assertEqual(self.reaction.transitionState.conformer.E0.units, reaction.transitionState.conformer.E0.units)
        self.assertAlmostEqual(
            self.reaction.transitionState.frequency.value_si, reaction.transitionState.frequency.value_si, 2
        )
        self.assertEqual(self.reaction.transitionState.frequency.units, reaction.transitionState.frequency.units)

        self.assertAlmostEqual(self.reaction.kinetics.A.value_si, reaction.kinetics.A.value_si, delta=1e-6)
        self.assertAlmostEqual(self.reaction.kinetics.n.value_si, reaction.kinetics.n.value_si, delta=1e-6)
        self.assertAlmostEqual(self.reaction.kinetics.T0.value_si, reaction.kinetics.T0.value_si, delta=1e-6)
        self.assertAlmostEqual(self.reaction.kinetics.Ea.value_si, reaction.kinetics.Ea.value_si, delta=1e-6)
        self.assertEqual(self.reaction.kinetics.comment, reaction.kinetics.comment)

        self.assertEqual(self.reaction.duplicate, reaction.duplicate)
        self.assertEqual(self.reaction.degeneracy, reaction.degeneracy)

    def testOutput(self):
        """
        Test that a Reaction object can be successfully reconstructed
        from its repr() output with no loss of information.
        """
        exec("reaction = %r" % (self.reaction))

        self.assertEqual(len(self.reaction.reactants), len(reaction.reactants))
        self.assertEqual(len(self.reaction.products), len(reaction.products))
        for reactant0, reactant in zip(self.reaction.reactants, reaction.reactants):
            self.assertAlmostEqual(reactant0.conformer.E0.value_si / 1e6, reactant.conformer.E0.value_si / 1e6, 2)
            self.assertEqual(reactant0.conformer.E0.units, reactant.conformer.E0.units)
        for product0, product in zip(self.reaction.products, reaction.products):
            self.assertAlmostEqual(product0.conformer.E0.value_si / 1e6, product.conformer.E0.value_si / 1e6, 2)
            self.assertEqual(product0.conformer.E0.units, product.conformer.E0.units)
        self.assertAlmostEqual(
            self.reaction.transitionState.conformer.E0.value_si / 1e6,
            reaction.transitionState.conformer.E0.value_si / 1e6,
            2,
        )
        self.assertEqual(self.reaction.transitionState.conformer.E0.units, reaction.transitionState.conformer.E0.units)
        self.assertAlmostEqual(
            self.reaction.transitionState.frequency.value_si, reaction.transitionState.frequency.value_si, 2
        )
        self.assertEqual(self.reaction.transitionState.frequency.units, reaction.transitionState.frequency.units)

        self.assertAlmostEqual(self.reaction.kinetics.A.value_si, reaction.kinetics.A.value_si, delta=1e-6)
        self.assertAlmostEqual(self.reaction.kinetics.n.value_si, reaction.kinetics.n.value_si, delta=1e-6)
        self.assertAlmostEqual(self.reaction.kinetics.T0.value_si, reaction.kinetics.T0.value_si, delta=1e-6)
        self.assertAlmostEqual(self.reaction.kinetics.Ea.value_si, reaction.kinetics.Ea.value_si, delta=1e-6)
        self.assertEqual(self.reaction.kinetics.comment, reaction.kinetics.comment)

        self.assertEqual(self.reaction.duplicate, reaction.duplicate)
        self.assertEqual(self.reaction.degeneracy, reaction.degeneracy)