Пример #1
0
 def setUp(self):
     self.alpha0 = 0.5
     self.T0 = 300.
     self.n = 0.85
     self.singleExponentialDown = SingleExponentialDown(
         alpha0 = (self.alpha0,"kJ/mol"),
         T0 = (self.T0,"K"),
         n = self.n,
     )
Пример #2
0
 def test_species_atomic_nasa_polynomial(self):
     """
     Test loading a atom with NASA polynomials
     """
     label0 = "H(1)"
     kwargs = {
         "structure":
         SMILES('[H]'),
         "thermo":
         NASA(polynomials=[
             NASAPolynomial(coeffs=[2.5, 0, 0, 0, 0, 25473.7, -0.446683],
                            Tmin=(200, 'K'),
                            Tmax=(1000, 'K')),
             NASAPolynomial(coeffs=[2.5, 0, 0, 0, 0, 25473.7, -0.446683],
                            Tmin=(1000, 'K'),
                            Tmax=(6000, 'K'))
         ],
              Tmin=(200, 'K'),
              Tmax=(6000, 'K'),
              comment="""Thermo library: FFCM1(-)"""),
         "energyTransferModel":
         SingleExponentialDown(alpha0=(3.5886, 'kJ/mol'),
                               T0=(300, 'K'),
                               n=0.85)
     }
     spc0 = species(label0, **kwargs)
     self.assertEqual(spc0.label, label0)
     self.assertEqual(spc0.smiles, '[H]')
     self.assertTrue(spc0.has_statmech())
     self.assertEqual(spc0.thermo, kwargs['thermo'])
Пример #3
0
 def test_species_polyatomic_nasa_polynomial(self):
     """
     Test loading a species with NASA polynomials
     """
     label0 = "benzyl"
     kwargs = {
         "structure":
         SMILES('[c]1ccccc1'),
         "thermo":
         NASA(polynomials=[
             NASAPolynomial(coeffs=[
                 2.78632, 0.00784632, 7.97887e-05, -1.11617e-07,
                 4.39429e-11, 39695, 11.5114
             ],
                            Tmin=(100, 'K'),
                            Tmax=(943.73, 'K')),
             NASAPolynomial(coeffs=[
                 13.2455, 0.0115667, -2.49996e-06, 4.66496e-10,
                 -4.12376e-14, 35581.1, -49.6793
             ],
                            Tmin=(943.73, 'K'),
                            Tmax=(5000, 'K'))
         ],
              Tmin=(100, 'K'),
              Tmax=(5000, 'K'),
              comment="""Thermo library: Fulvene_H + radical(CbJ)"""),
         "energyTransferModel":
         SingleExponentialDown(alpha0=(3.5886, 'kJ/mol'),
                               T0=(300, 'K'),
                               n=0.85)
     }
     spc0 = species(label0, **kwargs)
     self.assertEqual(spc0.label, label0)
     self.assertTrue(spc0.has_statmech())
     self.assertEqual(spc0.thermo, kwargs['thermo'])
 def setUp(self):
     self.alpha0 = 0.5
     self.T0 = 300.
     self.n = 0.85
     self.singleExponentialDown = SingleExponentialDown(
         alpha0 = (self.alpha0,"kJ/mol"),
         T0 = (self.T0,"K"),
         n = self.n,
     )
Пример #5
0
    def setUp(self):
        """
        A function run before each unit test in this class.
        """
        self.nC4H10O = Species(
            label = 'n-C4H10O',
            conformer = Conformer(
                E0 = (-317.807,'kJ/mol'),
                modes = [
                    IdealGasTranslation(mass=(74.07,"g/mol")),
                    NonlinearRotor(inertia=([41.5091,215.751,233.258],"amu*angstrom^2"), symmetry=1),
                    HarmonicOscillator(frequencies=([240.915,341.933,500.066,728.41,809.987,833.93,926.308,948.571,1009.3,1031.46,1076,1118.4,1184.66,1251.36,1314.36,1321.42,1381.17,1396.5,1400.54,1448.08,1480.18,1485.34,1492.24,1494.99,1586.16,2949.01,2963.03,2986.19,2988.1,2995.27,3026.03,3049.05,3053.47,3054.83,3778.88],"cm^-1")),
                    HinderedRotor(inertia=(0.854054,"amu*angstrom^2"), symmetry=1, fourier=([[0.25183,-1.37378,-2.8379,0.0305112,0.0028088], [0.458307,0.542121,-0.599366,-0.00283925,0.0398529]],"kJ/mol")),
                    HinderedRotor(inertia=(8.79408,"amu*angstrom^2"), symmetry=1, fourier=([[0.26871,-0.59533,-8.15002,-0.294325,-0.145357], [1.1884,0.99479,-0.940416,-0.186538,0.0309834]],"kJ/mol")),
                    HinderedRotor(inertia=(7.88153,"amu*angstrom^2"), symmetry=1, fourier=([[-4.67373,2.03735,-6.25993,-0.27325,-0.048748], [-0.982845,1.76637,-1.57619,0.474364,-0.000681718]],"kJ/mol")),
                    HinderedRotor(inertia=(2.81525,"amu*angstrom^2"), symmetry=3, barrier=(2.96807,"kcal/mol")),
                ],
                spinMultiplicity = 1,
                opticalIsomers = 1,
            ),
            molecularWeight = (74.07,"g/mol"),
            transportData=TransportData(sigma=(5.94, 'angstrom'), epsilon=(559, 'K')),
            energyTransferModel = SingleExponentialDown(alpha0=(447.5*0.011962,"kJ/mol"), T0=(300,"K"), n=0.85),
        )
        
        self.nC4H8 = Species(
            label = 'n-C4H8',
            conformer = Conformer(
                E0 = (-17.8832,'kJ/mol'),
                modes = [
                    IdealGasTranslation(mass=(56.06,"g/mol")),
                    NonlinearRotor(inertia=([22.2748,122.4,125.198],"amu*angstrom^2"), symmetry=1),
                    HarmonicOscillator(frequencies=([308.537,418.67,636.246,788.665,848.906,936.762,979.97,1009.48,1024.22,1082.96,1186.38,1277.55,1307.65,1332.87,1396.67,1439.09,1469.71,1484.45,1493.19,1691.49,2972.12,2994.31,3018.48,3056.87,3062.76,3079.38,3093.54,3174.52],"cm^-1")),
                    HinderedRotor(inertia=(5.28338,"amu*angstrom^2"), symmetry=1, fourier=([[-0.579364,-0.28241,-4.46469,0.143368,0.126756], [1.01804,-0.494628,-0.00318651,-0.245289,0.193728]],"kJ/mol")),
                    HinderedRotor(inertia=(2.60818,"amu*angstrom^2"), symmetry=3, fourier=([[0.0400372,0.0301986,-6.4787,-0.0248675,-0.0324753], [0.0312541,0.0538,-0.493785,0.0965968,0.125292]],"kJ/mol")),
                ],
                spinMultiplicity = 1,
                opticalIsomers = 1,
            ),
        )
        
        self.H2O = Species(
            label = 'H2O',
            conformer = Conformer(
                E0 = (-269.598,'kJ/mol'),
                modes = [
                    IdealGasTranslation(mass=(18.01,"g/mol")),
                    NonlinearRotor(inertia=([0.630578,1.15529,1.78586],"amu*angstrom^2"), symmetry=2),
                    HarmonicOscillator(frequencies=([1622.09,3771.85,3867.85],"cm^-1")),
                ],
                spinMultiplicity = 1,
                opticalIsomers = 1,
            ),
        )

        self.configuration = Configuration(self.nC4H8, self.H2O)
Пример #6
0
    def test_species(self):
        """
        Test loading a species from input file-like kew word arguments
        """
        label0 = 'CH2O'
        kwargs = {
            'E0': (28.69, 'kcal/mol'),
            'structure':
            SMILES('C=O'),
            'collisionModel':
            TransportData(sigma=(3.69e-10, 'm'), epsilon=(4.0, 'kJ/mol')),
            'energyTransferModel':
            SingleExponentialDown(alpha0=(0.956, 'kJ/mol'),
                                  T0=(300, 'K'),
                                  n=0.95),
            'spinMultiplicity':
            1,
            'opticalIsomers':
            1,
            'modes': [
                HarmonicOscillator(
                    frequencies=([1180, 1261, 1529, 1764, 2931, 2999],
                                 'cm^-1')),
                NonlinearRotor(rotationalConstant=([
                    1.15498821005263, 1.3156969584727, 9.45570474524524
                ], "cm^-1"),
                               symmetry=2,
                               quantum=False),
                IdealGasTranslation(mass=(30.0106, "g/mol")),
            ]
        }

        spc0 = species(label0, **kwargs)
        self.assertEqual(spc0.label, 'CH2O')
        self.assertEqual(spc0.smiles, 'C=O')
        self.assertAlmostEqual(spc0.conformer.E0.value_si, 120038.96)
        self.assertEqual(spc0.conformer.spin_multiplicity, 1)
        self.assertEqual(spc0.conformer.optical_isomers, 1)
        self.assertEqual(len(spc0.conformer.modes), 3)
        self.assertIsInstance(spc0.transport_data, TransportData)
        self.assertIsInstance(spc0.energy_transfer_model,
                              SingleExponentialDown)
Пример #7
0
    def setUp(self):
        """
        A function run before each unit test in this class.
        """
        self.nC4H10O = Species(
            label='n-C4H10O',
            conformer=Conformer(
                E0=(-317.807, 'kJ/mol'),
                modes=[
                    IdealGasTranslation(mass=(74.07, "g/mol")),
                    NonlinearRotor(inertia=([41.5091, 215.751,
                                             233.258], "amu*angstrom^2"),
                                   symmetry=1),
                    HarmonicOscillator(frequencies=([
                        240.915, 341.933, 500.066, 728.41, 809.987, 833.93,
                        926.308, 948.571, 1009.3, 1031.46, 1076, 1118.4,
                        1184.66, 1251.36, 1314.36, 1321.42, 1381.17, 1396.5,
                        1400.54, 1448.08, 1480.18, 1485.34, 1492.24, 1494.99,
                        1586.16, 2949.01, 2963.03, 2986.19, 2988.1, 2995.27,
                        3026.03, 3049.05, 3053.47, 3054.83, 3778.88
                    ], "cm^-1")),
                    HinderedRotor(inertia=(0.854054, "amu*angstrom^2"),
                                  symmetry=1,
                                  fourier=([[
                                      0.25183, -1.37378, -2.8379, 0.0305112,
                                      0.0028088
                                  ],
                                            [
                                                0.458307, 0.542121, -0.599366,
                                                -0.00283925, 0.0398529
                                            ]], "kJ/mol")),
                    HinderedRotor(
                        inertia=(8.79408, "amu*angstrom^2"),
                        symmetry=1,
                        fourier=([[
                            0.26871, -0.59533, -8.15002, -0.294325, -0.145357
                        ], [1.1884, 0.99479, -0.940416, -0.186538,
                            0.0309834]], "kJ/mol")),
                    HinderedRotor(inertia=(7.88153, "amu*angstrom^2"),
                                  symmetry=1,
                                  fourier=([[
                                      -4.67373, 2.03735, -6.25993, -0.27325,
                                      -0.048748
                                  ],
                                            [
                                                -0.982845, 1.76637, -1.57619,
                                                0.474364, -0.000681718
                                            ]], "kJ/mol")),
                    HinderedRotor(inertia=(2.81525, "amu*angstrom^2"),
                                  symmetry=3,
                                  barrier=(2.96807, "kcal/mol")),
                ],
                spin_multiplicity=1,
                optical_isomers=1,
            ),
            molecular_weight=(74.07, "g/mol"),
            transport_data=TransportData(sigma=(5.94, 'angstrom'),
                                         epsilon=(559, 'K')),
            energy_transfer_model=SingleExponentialDown(
                alpha0=(447.5 * 0.011962, "kJ/mol"), T0=(300, "K"), n=0.85),
        )

        self.nC4H8 = Species(
            label='n-C4H8',
            conformer=Conformer(
                E0=(-17.8832, 'kJ/mol'),
                modes=[
                    IdealGasTranslation(mass=(56.06, "g/mol")),
                    NonlinearRotor(inertia=([22.2748, 122.4,
                                             125.198], "amu*angstrom^2"),
                                   symmetry=1),
                    HarmonicOscillator(frequencies=([
                        308.537, 418.67, 636.246, 788.665, 848.906, 936.762,
                        979.97, 1009.48, 1024.22, 1082.96, 1186.38, 1277.55,
                        1307.65, 1332.87, 1396.67, 1439.09, 1469.71, 1484.45,
                        1493.19, 1691.49, 2972.12, 2994.31, 3018.48, 3056.87,
                        3062.76, 3079.38, 3093.54, 3174.52
                    ], "cm^-1")),
                    HinderedRotor(inertia=(5.28338, "amu*angstrom^2"),
                                  symmetry=1,
                                  fourier=([[
                                      -0.579364, -0.28241, -4.46469, 0.143368,
                                      0.126756
                                  ],
                                            [
                                                1.01804, -0.494628,
                                                -0.00318651, -0.245289,
                                                0.193728
                                            ]], "kJ/mol")),
                    HinderedRotor(
                        inertia=(2.60818, "amu*angstrom^2"),
                        symmetry=3,
                        fourier=([[
                            0.0400372, 0.0301986, -6.4787, -0.0248675,
                            -0.0324753
                        ], [0.0312541, 0.0538, -0.493785, 0.0965968,
                            0.125292]], "kJ/mol")),
                ],
                spin_multiplicity=1,
                optical_isomers=1,
            ),
        )

        self.H2O = Species(
            label='H2O',
            conformer=Conformer(
                E0=(-269.598, 'kJ/mol'),
                modes=[
                    IdealGasTranslation(mass=(18.01, "g/mol")),
                    NonlinearRotor(inertia=([0.630578, 1.15529,
                                             1.78586], "amu*angstrom^2"),
                                   symmetry=2),
                    HarmonicOscillator(
                        frequencies=([1622.09, 3771.85, 3867.85], "cm^-1")),
                ],
                spin_multiplicity=1,
                optical_isomers=1,
            ),
        )

        self.N2 = Species(
            label='N2',
            molecular_weight=(28.04, "g/mol"),
            transport_data=TransportData(sigma=(3.41, "angstrom"),
                                         epsilon=(124, "K")),
            energy_transfer_model=None,
        )

        self.TS = TransitionState(
            label='TS',
            conformer=Conformer(
                E0=(-42.4373, "kJ/mol"),
                modes=[
                    IdealGasTranslation(mass=(74.07, "g/mol")),
                    NonlinearRotor(inertia=([40.518, 232.666,
                                             246.092], "u*angstrom**2"),
                                   symmetry=1,
                                   quantum=False),
                    HarmonicOscillator(frequencies=([
                        134.289, 302.326, 351.792, 407.986, 443.419, 583.988,
                        699.001, 766.1, 777.969, 829.671, 949.753, 994.731,
                        1013.59, 1073.98, 1103.79, 1171.89, 1225.91, 1280.67,
                        1335.08, 1373.9, 1392.32, 1417.43, 1469.51, 1481.61,
                        1490.16, 1503.73, 1573.16, 2972.85, 2984.3, 3003.67,
                        3045.78, 3051.77, 3082.37, 3090.44, 3190.73, 3708.52
                    ], "kayser")),
                    HinderedRotor(inertia=(2.68206, "amu*angstrom^2"),
                                  symmetry=3,
                                  barrier=(3.35244, "kcal/mol")),
                    HinderedRotor(inertia=(9.77669, "amu*angstrom^2"),
                                  symmetry=1,
                                  fourier=([[
                                      0.208938, -1.55291, -4.05398, -0.105798,
                                      -0.104752
                                  ],
                                            [
                                                2.00518, -0.020767, -0.333595,
                                                0.137791, -0.274578
                                            ]], "kJ/mol")),
                ],
                spin_multiplicity=1,
                optical_isomers=1,
            ),
            frequency=(-2038.34, 'cm^-1'),
        )

        self.reaction = Reaction(
            label='dehydration',
            reactants=[self.nC4H10O],
            products=[self.nC4H8, self.H2O],
            transition_state=self.TS,
        )

        self.network = Network(
            label='n-butanol',
            isomers=[Configuration(self.nC4H10O)],
            reactants=[],
            products=[Configuration(self.nC4H8, self.H2O)],
            path_reactions=[self.reaction],
            bath_gas={self.N2: 1.0},
        )
Пример #8
0
class TestSingleExponentialDown(unittest.TestCase):
    """
    Contains unit tests of the SingleExponentialDown class.
    """
    
    def setUp(self):
        self.alpha0 = 0.5
        self.T0 = 300.
        self.n = 0.85
        self.singleExponentialDown = SingleExponentialDown(
            alpha0 = (self.alpha0,"kJ/mol"),
            T0 = (self.T0,"K"),
            n = self.n,
        )
       
    def test_alpha0(self):
        """
        Test the SingleExponentialDown.sigma attribute.
        """
        self.assertAlmostEqual(self.singleExponentialDown.alpha0.value_si*0.001, self.alpha0, 4)

    def test_T0(self):
        """
        Test the SingleExponentialDown.T0 attribute.
        """
        self.assertAlmostEqual(self.singleExponentialDown.T0.value_si, self.T0, 4)

    def test_n(self):
        """
        Test the SingleExponentialDown.n attribute.
        """
        self.assertAlmostEqual(self.singleExponentialDown.n, self.n, 4)

    def test_getAlpha(self):
        """
        Test the SingleExponentialDown.getAlpha() method.
        """
        for T in [300,400,500,600,800,1000,1500,2000]:
            dEdown0 = 1000. * self.alpha0 * (T / self.T0) ** self.n
            dEdown = self.singleExponentialDown.getAlpha(T)
            self.assertAlmostEqual(dEdown0, dEdown, 6)

    def test_pickle(self):
        """
        Test that a SingleExponentialDown object can be successfully pickled
        and unpickled with no loss of information.
        """
        import cPickle
        singleExponentialDown = cPickle.loads(cPickle.dumps(self.singleExponentialDown,-1))
        self.assertAlmostEqual(self.singleExponentialDown.alpha0.value, singleExponentialDown.alpha0.value, 6)
        self.assertEqual(self.singleExponentialDown.alpha0.units, singleExponentialDown.alpha0.units)
        self.assertAlmostEqual(self.singleExponentialDown.T0.value, singleExponentialDown.T0.value, 6)
        self.assertEqual(self.singleExponentialDown.T0.units, singleExponentialDown.T0.units)
        self.assertAlmostEqual(self.singleExponentialDown.n, singleExponentialDown.n, 4)

    def test_repr(self):
        """
        Test that a SingleExponentialDown object can be successfully 
        reconstructed from its repr() with no loss of information.
        """
        exec('singleExponentialDown = {0!r}'.format(self.singleExponentialDown))
        self.assertAlmostEqual(self.singleExponentialDown.alpha0.value, singleExponentialDown.alpha0.value, 6)
        self.assertEqual(self.singleExponentialDown.alpha0.units, singleExponentialDown.alpha0.units)
        self.assertAlmostEqual(self.singleExponentialDown.T0.value, singleExponentialDown.T0.value, 6)
        self.assertEqual(self.singleExponentialDown.T0.units, singleExponentialDown.T0.units)
        self.assertAlmostEqual(self.singleExponentialDown.n, singleExponentialDown.n, 4)
Пример #9
0
    def test_reaction(self):
        """
        Test loading a reaction from input file-like kew word arguments
        """

        species(label='methoxy',
                structure=SMILES('C[O]'),
                E0=(9.44, 'kcal/mol'),
                modes=[
                    HarmonicOscillator(frequencies=(
                        [758, 960, 1106, 1393, 1403, 1518, 2940, 3019, 3065],
                        'cm^-1')),
                    NonlinearRotor(rotationalConstant=([0.916, 0.921,
                                                        5.251], "cm^-1"),
                                   symmetry=3,
                                   quantum=False),
                    IdealGasTranslation(mass=(31.01843, "g/mol"))
                ],
                spinMultiplicity=2,
                opticalIsomers=1,
                molecularWeight=(31.01843, 'amu'),
                collisionModel=TransportData(sigma=(3.69e-10, 'm'),
                                             epsilon=(4.0, 'kJ/mol')),
                energyTransferModel=SingleExponentialDown(alpha0=(0.956,
                                                                  'kJ/mol'),
                                                          T0=(300, 'K'),
                                                          n=0.95))

        species(label='formaldehyde',
                E0=(28.69, 'kcal/mol'),
                molecularWeight=(30.0106, "g/mol"),
                collisionModel=TransportData(sigma=(3.69e-10, 'm'),
                                             epsilon=(4.0, 'kJ/mol')),
                energyTransferModel=SingleExponentialDown(alpha0=(0.956,
                                                                  'kJ/mol'),
                                                          T0=(300, 'K'),
                                                          n=0.95),
                spinMultiplicity=1,
                opticalIsomers=1,
                modes=[
                    HarmonicOscillator(
                        frequencies=([1180, 1261, 1529, 1764, 2931, 2999],
                                     'cm^-1')),
                    NonlinearRotor(rotationalConstant=([
                        1.15498821005263, 1.3156969584727, 9.45570474524524
                    ], "cm^-1"),
                                   symmetry=2,
                                   quantum=False),
                    IdealGasTranslation(mass=(30.0106, "g/mol"))
                ])

        species(label='H',
                E0=(0.000, 'kcal/mol'),
                molecularWeight=(1.00783, "g/mol"),
                collisionModel=TransportData(sigma=(3.69e-10, 'm'),
                                             epsilon=(4.0, 'kJ/mol')),
                energyTransferModel=SingleExponentialDown(alpha0=(0.956,
                                                                  'kJ/mol'),
                                                          T0=(300, 'K'),
                                                          n=0.95),
                modes=[IdealGasTranslation(mass=(1.00783, "g/mol"))],
                spinMultiplicity=2,
                opticalIsomers=1)

        transitionState(
            label='TS3',
            E0=(34.1, 'kcal/mol'),
            spinMultiplicity=2,
            opticalIsomers=1,
            frequency=(-967, 'cm^-1'),
            modes=[
                HarmonicOscillator(frequencies=(
                    [466, 581, 1169, 1242, 1499, 1659, 2933, 3000], 'cm^-1')),
                NonlinearRotor(rotationalConstant=([0.970, 1.029,
                                                    3.717], "cm^-1"),
                               symmetry=1,
                               quantum=False),
                IdealGasTranslation(mass=(31.01843, "g/mol"))
            ])

        reactants = ['formaldehyde', 'H']
        products = ['methoxy']
        tunneling = 'Eckart'

        rxn = reaction('CH2O+H=Methoxy',
                       reactants,
                       products,
                       'TS3',
                       tunneling=tunneling)
        self.assertEqual(rxn.label, 'CH2O+H=Methoxy')
        self.assertEqual(len(rxn.reactants), 2)
        self.assertEqual(len(rxn.products), 1)
        self.assertAlmostEqual(rxn.reactants[0].conformer.E0.value_si, 0)
        self.assertAlmostEqual(rxn.reactants[1].conformer.E0.value_si,
                               120038.96)
        self.assertAlmostEqual(rxn.products[0].conformer.E0.value_si, 39496.96)
        self.assertAlmostEqual(rxn.transition_state.conformer.E0.value_si,
                               142674.4)
        self.assertAlmostEqual(rxn.transition_state.frequency.value_si, -967.0)
        self.assertIsInstance(rxn.transition_state.tunneling, Eckart)
class TestSingleExponentialDown(unittest.TestCase):
    """
    Contains unit tests of the SingleExponentialDown class.
    """
    
    def setUp(self):
        self.alpha0 = 0.5
        self.T0 = 300.
        self.n = 0.85
        self.singleExponentialDown = SingleExponentialDown(
            alpha0 = (self.alpha0,"kJ/mol"),
            T0 = (self.T0,"K"),
            n = self.n,
        )
       
    def test_alpha0(self):
        """
        Test the SingleExponentialDown.sigma attribute.
        """
        self.assertAlmostEqual(self.singleExponentialDown.alpha0.value_si*0.001, self.alpha0, 4)

    def test_T0(self):
        """
        Test the SingleExponentialDown.T0 attribute.
        """
        self.assertAlmostEqual(self.singleExponentialDown.T0.value_si, self.T0, 4)

    def test_n(self):
        """
        Test the SingleExponentialDown.n attribute.
        """
        self.assertAlmostEqual(self.singleExponentialDown.n, self.n, 4)

    def test_getAlpha(self):
        """
        Test the SingleExponentialDown.getAlpha() method.
        """
        for T in [300,400,500,600,800,1000,1500,2000]:
            dEdown0 = 1000. * self.alpha0 * (T / self.T0) ** self.n
            dEdown = self.singleExponentialDown.getAlpha(T)
            self.assertAlmostEqual(dEdown0, dEdown, 6)

    def test_pickle(self):
        """
        Test that a SingleExponentialDown object can be successfully pickled
        and unpickled with no loss of information.
        """
        import cPickle
        singleExponentialDown = cPickle.loads(cPickle.dumps(self.singleExponentialDown,-1))
        self.assertAlmostEqual(self.singleExponentialDown.alpha0.value, singleExponentialDown.alpha0.value, 6)
        self.assertEqual(self.singleExponentialDown.alpha0.units, singleExponentialDown.alpha0.units)
        self.assertAlmostEqual(self.singleExponentialDown.T0.value, singleExponentialDown.T0.value, 6)
        self.assertEqual(self.singleExponentialDown.T0.units, singleExponentialDown.T0.units)
        self.assertAlmostEqual(self.singleExponentialDown.n, singleExponentialDown.n, 4)

    def test_repr(self):
        """
        Test that a SingleExponentialDown object can be successfully 
        reconstructed from its repr() with no loss of information.
        """
        exec('singleExponentialDown = {0!r}'.format(self.singleExponentialDown))
        self.assertAlmostEqual(self.singleExponentialDown.alpha0.value, singleExponentialDown.alpha0.value, 6)
        self.assertEqual(self.singleExponentialDown.alpha0.units, singleExponentialDown.alpha0.units)
        self.assertAlmostEqual(self.singleExponentialDown.T0.value, singleExponentialDown.T0.value, 6)
        self.assertEqual(self.singleExponentialDown.T0.units, singleExponentialDown.T0.units)
        self.assertAlmostEqual(self.singleExponentialDown.n, singleExponentialDown.n, 4)
Пример #11
0
    def update(self, reactionModel, pdepSettings):
        """
        Regenerate the :math:`k(T,P)` values for this partial network if the
        network is marked as invalid.
        """
        from rmgpy.kinetics import Arrhenius, KineticsData, MultiArrhenius
        from rmgpy.pdep.collision import SingleExponentialDown
        from rmgpy.pdep.reaction import fitInterpolationModel

        # Get the parameters for the pressure dependence calculation
        job = pdepSettings
        job.network = self
        outputDirectory = pdepSettings.outputFile

        Tmin = job.Tmin.value_si
        Tmax = job.Tmax.value_si
        Pmin = job.Pmin.value_si
        Pmax = job.Pmax.value_si
        Tlist = job.Tlist.value_si
        Plist = job.Plist.value_si
        maximumGrainSize = job.maximumGrainSize.value_si if job.maximumGrainSize is not None else 0.0
        minimumGrainCount = job.minimumGrainCount
        method = job.method
        interpolationModel = job.interpolationModel
        activeJRotor = job.activeJRotor
        activeKRotor = job.activeKRotor
        rmgmode = job.rmgmode

        # Figure out which configurations are isomers, reactant channels, and product channels
        self.updateConfigurations(reactionModel)

        # Make sure we have high-P kinetics for all path reactions
        for rxn in self.pathReactions:
            if rxn.kinetics is None and rxn.reverse.kinetics is None:
                raise PressureDependenceError(
                    'Path reaction {0} with no high-pressure-limit kinetics encountered in PDepNetwork #{1:d}.'
                    .format(rxn, self.index))
            elif rxn.kinetics is not None and rxn.kinetics.isPressureDependent(
            ):
                raise PressureDependenceError(
                    'Pressure-dependent kinetics encountered for path reaction {0} in PDepNetwork #{1:d}.'
                    .format(rxn, self.index))

        # Do nothing if the network is already valid
        if self.valid: return
        # Do nothing if there are no explored wells
        if len(self.explored) == 0 and len(self.source) > 1: return
        # Log the network being updated
        logging.info("Updating {0:s}".format(self))

        # Generate states data for unimolecular isomers and reactants if necessary
        for isomer in self.isomers:
            spec = isomer.species[0]
            if not spec.hasStatMech(): spec.generateStatMech()
        for reactants in self.reactants:
            for spec in reactants.species:
                if not spec.hasStatMech(): spec.generateStatMech()
        # Also generate states data for any path reaction reactants, so we can
        # always apply the ILT method in the direction the kinetics are known
        for reaction in self.pathReactions:
            for spec in reaction.reactants:
                if not spec.hasStatMech(): spec.generateStatMech()
        # While we don't need the frequencies for product channels, we do need
        # the E0, so create a conformer object with the E0 for the product
        # channel species if necessary
        for products in self.products:
            for spec in products.species:
                if spec.conformer is None:
                    spec.conformer = Conformer(E0=spec.getThermoData().E0)

        # Determine transition state energies on potential energy surface
        # In the absence of any better information, we simply set it to
        # be the reactant ground-state energy + the activation energy
        # Note that we need Arrhenius kinetics in order to do this
        for rxn in self.pathReactions:
            if rxn.kinetics is None:
                raise Exception(
                    'Path reaction "{0}" in PDepNetwork #{1:d} has no kinetics!'
                    .format(rxn, self.index))
            elif isinstance(rxn.kinetics, KineticsData):
                if len(rxn.reactants) == 1:
                    kunits = 's^-1'
                elif len(rxn.reactants) == 2:
                    kunits = 'm^3/(mol*s)'
                elif len(rxn.reactants) == 3:
                    kunits = 'm^6/(mol^2*s)'
                else:
                    kunits = ''
                rxn.kinetics = Arrhenius().fitToData(
                    Tlist=rxn.kinetics.Tdata.value_si,
                    klist=rxn.kinetics.kdata.value_si,
                    kunits=kunits)
            elif isinstance(rxn.kinetics, MultiArrhenius):
                logging.info(
                    'Converting multiple kinetics to a single Arrhenius expression for reaction {rxn}'
                    .format(rxn=rxn))
                rxn.kinetics = rxn.kinetics.toArrhenius(Tmin=Tmin, Tmax=Tmax)
            elif not isinstance(rxn.kinetics, Arrhenius):
                raise Exception(
                    'Path reaction "{0}" in PDepNetwork #{1:d} has invalid kinetics type "{2!s}".'
                    .format(rxn, self.index, rxn.kinetics.__class__))
            rxn.fixBarrierHeight(forcePositive=True)
            E0 = sum([spec.conformer.E0.value_si
                      for spec in rxn.reactants]) + rxn.kinetics.Ea.value_si
            rxn.transitionState = rmgpy.species.TransitionState(
                conformer=Conformer(E0=(E0 * 0.001, "kJ/mol")), )

        # Set collision model
        bathGas = [
            spec for spec in reactionModel.core.species if not spec.reactive
        ]
        self.bathGas = {}
        for spec in bathGas:
            # is this really the only/best way to weight them? And what is alpha0?
            self.bathGas[spec] = 1.0 / len(bathGas)
            spec.collisionModel = SingleExponentialDown(alpha0=(4.86,
                                                                'kcal/mol'))

        # Save input file
        if not self.label: self.label = str(self.index)
        job.saveInputFile(
            os.path.join(
                outputDirectory, 'pdep',
                'network{0:d}_{1:d}.py'.format(self.index, len(self.isomers))))

        self.printSummary(level=logging.INFO)

        # Calculate the rate coefficients
        self.initialize(Tmin, Tmax, Pmin, Pmax, maximumGrainSize,
                        minimumGrainCount, activeJRotor, activeKRotor, rmgmode)
        K = self.calculateRateCoefficients(Tlist, Plist, method)

        # Generate PDepReaction objects
        configurations = []
        configurations.extend([isom.species[:] for isom in self.isomers])
        configurations.extend(
            [reactant.species[:] for reactant in self.reactants])
        configurations.extend(
            [product.species[:] for product in self.products])
        j = configurations.index(self.source)

        for i in range(K.shape[2]):
            if i != j:
                # Find the path reaction
                netReaction = None
                for r in self.netReactions:
                    if r.hasTemplate(configurations[j], configurations[i]):
                        netReaction = r
                # If net reaction does not already exist, make a new one
                if netReaction is None:
                    netReaction = PDepReaction(reactants=configurations[j],
                                               products=configurations[i],
                                               network=self,
                                               kinetics=None)
                    netReaction = reactionModel.makeNewPDepReaction(
                        netReaction)
                    self.netReactions.append(netReaction)

                    # Place the net reaction in the core or edge if necessary
                    # Note that leak reactions are not placed in the edge
                    if all([
                            s in reactionModel.core.species
                            for s in netReaction.reactants
                    ]) and all([
                            s in reactionModel.core.species
                            for s in netReaction.products
                    ]):
                        reactionModel.addReactionToCore(netReaction)
                    else:
                        reactionModel.addReactionToEdge(netReaction)

                # Set/update the net reaction kinetics using interpolation model
                Tdata = job.Tlist.value_si
                Pdata = job.Plist.value_si
                kdata = K[:, :, i, j].copy()
                order = len(netReaction.reactants)
                kdata *= 1e6**(order - 1)
                kunits = {
                    1: 's^-1',
                    2: 'cm^3/(mol*s)',
                    3: 'cm^6/(mol^2*s)'
                }[order]
                netReaction.kinetics = job.fitInterpolationModel(
                    Tlist, Plist, kdata, kunits)

                # Check: For each net reaction that has a path reaction, make
                # sure the k(T,P) values for the net reaction do not exceed
                # the k(T) values of the path reaction
                # Only check the k(T,P) value at the highest P and lowest T,
                # as this is the one most likely to be in the high-pressure
                # limit
                t = 0
                p = len(Plist) - 1
                for pathReaction in self.pathReactions:
                    if pathReaction.isIsomerization():
                        # Don't check isomerization reactions, since their
                        # k(T,P) values potentially contain both direct and
                        # well-skipping contributions, and therefore could be
                        # significantly larger than the direct k(T) value
                        # (This can also happen for association/dissocation
                        # reactions, but the effect is generally not too large)
                        continue
                    if pathReaction.reactants == netReaction.reactants and pathReaction.products == netReaction.products:
                        kinf = pathReaction.kinetics.getRateCoefficient(
                            Tlist[t])
                        if K[t, p, i,
                             j] > 2 * kinf:  # To allow for a small discretization error
                            logging.warning(
                                'k(T,P) for net reaction {0} exceeds high-P k(T) by {1:g} at {2:g} K, {3:g} bar'
                                .format(netReaction, K[t, p, i, j] / kinf,
                                        Tlist[t], Plist[p] / 1e5))
                            logging.info(
                                '    k(T,P) = {0:9.2e}    k(T) = {1:9.2e}'.
                                format(K[t, p, i, j], kinf))
                        break
                    elif pathReaction.products == netReaction.reactants and pathReaction.reactants == netReaction.products:
                        kinf = pathReaction.kinetics.getRateCoefficient(
                            Tlist[t]) / pathReaction.getEquilibriumConstant(
                                Tlist[t])
                        if K[t, p, i,
                             j] > 2 * kinf:  # To allow for a small discretization error
                            logging.warning(
                                'k(T,P) for net reaction {0} exceeds high-P k(T) by {1:g} at {2:g} K, {3:g} bar'
                                .format(netReaction, K[t, p, i, j] / kinf,
                                        Tlist[t], Plist[p] / 1e5))
                            logging.info(
                                '    k(T,P) = {0:9.2e}    k(T) = {1:9.2e}'.
                                format(K[t, p, i, j], kinf))
                        break

        # Delete intermediate arrays to conserve memory
        self.cleanup()

        # We're done processing this network, so mark it as valid
        self.valid = True