示例#1
0
class TestConformer(unittest.TestCase):
    """
    Contains unit tests of the :class:`Conformer` class.
    """
    
    def setUp(self):
        """
        A function run before each unit test in this class.
        """
        self.ethylene = Conformer(
            E0 = (0.0,"kJ/mol"),
            modes = [
                IdealGasTranslation(mass=(28.03,"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,
        )
        self.oxygen = Conformer(
            E0 = (0.0,"kJ/mol"),
            modes = [
                IdealGasTranslation(mass=(31.99,"amu")),
                LinearRotor(inertia=(11.6056,"amu*angstrom^2"), symmetry=2),
                HarmonicOscillator(frequencies=([1621.54],"cm^-1")),
            ],
            spinMultiplicity = 3,
            opticalIsomers = 1,
        )
        
        # The following data is for ethane at the CBS-QB3 level
        self.coordinates = numpy.array([
            [  0.0000,  0.0000,  0.0000],
            [ -0.0000, -0.0000,  1.0936],
            [  1.0430, -0.0000, -0.3288],
            [ -0.4484,  0.9417, -0.3288],
            [ -0.7609, -1.2051, -0.5580],
            [ -0.7609, -1.2051, -1.6516],
            [ -0.3125, -2.1468, -0.2292],
            [ -1.8039, -1.2051, -0.2293],
        ])
        self.number = numpy.array([6, 1, 1, 1, 6, 1, 1, 1])
        self.mass = numpy.array([12, 1.007825, 1.007825, 1.007825, 12, 1.007825, 1.007825, 1.007825])
        self.E0 = -93.5097
        self.conformer = Conformer(
            E0 = (self.E0,"kJ/mol"),
            modes = [
                IdealGasTranslation(mass=(30.0469,"amu")),
                NonlinearRotor(inertia=([6.27071,25.3832,25.3833],"amu*angstrom^2"), symmetry=6),
                HarmonicOscillator(frequencies=([818.917,819.479,987.099,1206.76,1207.05,1396,1411.35,1489.73,1489.95,1492.49,1492.66,2995.36,2996.06,3040.77,3041,3065.86,3066.02],"cm^-1")),
                HinderedRotor(inertia=(1.56768,"amu*angstrom^2"), symmetry=3, barrier=(2.69401,"kcal/mol"), quantum=False, semiclassical=False),
            ],
            spinMultiplicity = 1,
            opticalIsomers = 1,
            coordinates = (self.coordinates,"angstrom"),
            number = self.number,
            mass = (self.mass,"amu"),
        )
        
    def test_getPartitionFunction_ethylene(self):
        """
        Test the StatMech.getPartitionFunction() method for ethylene.
        """
        Tlist = numpy.array([300,500,1000,1500,2000])
        Qexplist = numpy.array([4.05311e+09, 4.19728e+10, 2.82309e+12, 7.51135e+13, 1.16538e+15])
        for T, Qexp in zip(Tlist, Qexplist):
            Qact = self.ethylene.getPartitionFunction(T)
            self.assertAlmostEqual(Qexp, Qact, delta=1e-4*Qexp)

    def test_getHeatCapacity_ethylene(self):
        """
        Test the StatMech.getHeatCapacity() method for ethylene.
        """
        Tlist = numpy.array([300,500,1000,1500,2000])
        Cvexplist = numpy.array([5.11186, 7.40447, 11.1659, 13.1221, 14.1617]) * constants.R
        for T, Cvexp in zip(Tlist, Cvexplist):
            Cvact = self.ethylene.getHeatCapacity(T)
            self.assertAlmostEqual(Cvexp, Cvact, 3)
    
    def test_getEnthalpy_ethylene(self):
        """
        Test the StatMech.getEnthalpy() method for ethylene.
        """
        Tlist = numpy.array([300,500,1000,1500,2000])
        Hexplist = numpy.array([4.23129, 5.04826, 7.27337, 8.93167, 10.1223]) * constants.R * Tlist
        for T, Hexp in zip(Tlist, Hexplist):
            Hact = self.ethylene.getEnthalpy(T)
            self.assertAlmostEqual(Hexp, Hact, delta=1e-4*Hexp)
    
    def test_getEntropy_ethylene(self):
        """
        Test the StatMech.getEntropy() method for ethylene.
        """
        Tlist = numpy.array([300,500,1000,1500,2000])
        Sexplist = numpy.array([26.3540, 29.5085, 35.9422, 40.8817, 44.8142]) * constants.R
        for T, Sexp in zip(Tlist, Sexplist):
            Sact = self.ethylene.getEntropy(T)
            self.assertAlmostEqual(Sexp, Sact, 3)
    
    def test_getSumOfStates_ethylene(self):
        """
        Test the StatMech.getSumOfStates() method for ethylene.
        """
        Elist = numpy.arange(0, 5000*11.96, 2*11.96)
        sumStates = self.ethylene.getSumOfStates(Elist)
        densStates = self.ethylene.getDensityOfStates(Elist)
        for n in range(10, len(Elist)):
            self.assertTrue(0.8 < numpy.sum(densStates[0:n+1]) / sumStates[n] < 1.25, '{0} != {1}'.format(numpy.sum(densStates[0:n+1]), sumStates[n]))
            
    def test_getDensityOfStates_ethylene(self):
        """
        Test the StatMech.getDensityOfStates() method for ethylene.
        """
        Elist = numpy.arange(0, 5000*11.96, 2*11.96)
        densStates = self.ethylene.getDensityOfStates(Elist)
        T = 100
        Qact = numpy.sum(densStates * numpy.exp(-Elist / constants.R / T))
        Qexp = self.ethylene.getPartitionFunction(T)
        self.assertAlmostEqual(Qexp, Qact, delta=1e-1*Qexp)

    def test_getPartitionFunction_oxygen(self):
        """
        Test the StatMech.getPartitionFunction() method for oxygen.
        """
        Tlist = numpy.array([300,500,1000,1500,2000])
        Qexplist = numpy.array([1.55584e+09, 9.38339e+09, 1.16459e+11, 5.51016e+11, 1.72794e+12])
        for T, Qexp in zip(Tlist, Qexplist):
            Qact = self.oxygen.getPartitionFunction(T)
            self.assertAlmostEqual(Qexp, Qact, delta=1e-4*Qexp)

    def test_getHeatCapacity_oxygen(self):
        """
        Test the StatMech.getHeatCapacity() method for oxygen.
        """
        Tlist = numpy.array([300,500,1000,1500,2000])
        Cvexplist = numpy.array([3.52538, 3.70877, 4.14751, 4.32063, 4.39392]) * constants.R
        for T, Cvexp in zip(Tlist, Cvexplist):
            Cvact = self.oxygen.getHeatCapacity(T)
            self.assertAlmostEqual(Cvexp, Cvact, 3)
    
    def test_getEnthalpy_oxygen(self):
        """
        Test the StatMech.getEnthalpy() method for oxygen.
        """
        Tlist = numpy.array([300,500,1000,1500,2000])
        Hexplist = numpy.array([3.50326, 3.54432, 3.75062, 3.91623, 4.02765]) * constants.R * Tlist
        for T, Hexp in zip(Tlist, Hexplist):
            Hact = self.oxygen.getEnthalpy(T)
            self.assertAlmostEqual(Hexp, Hact, delta=1e-4*Hexp)
    
    def test_getEntropy_oxygen(self):
        """
        Test the StatMech.getEntropy() method for oxygen.
        """
        Tlist = numpy.array([300,500,1000,1500,2000])
        Sexplist = numpy.array([24.6685, 26.5065, 29.2314, 30.9513, 32.2056]) * constants.R
        for T, Sexp in zip(Tlist, Sexplist):
            Sact = self.oxygen.getEntropy(T)
            self.assertAlmostEqual(Sexp, Sact, 3)
    
    def test_getSumOfStates_oxygen(self):
        """
        Test the StatMech.getSumOfStates() method for oxygen.
        """
        Elist = numpy.arange(0, 5000*11.96, 2*11.96)
        sumStates = self.oxygen.getSumOfStates(Elist)
        densStates = self.oxygen.getDensityOfStates(Elist)
        for n in range(10, len(Elist)):
            self.assertTrue(0.8 < numpy.sum(densStates[0:n+1]) / sumStates[n] < 1.25, '{0} != {1}'.format(numpy.sum(densStates[0:n+1]), sumStates[n]))
            
    def test_getDensityOfStates_oxygen(self):
        """
        Test the StatMech.getDensityOfStates() method for oxygen.
        """
        Elist = numpy.arange(0, 5000*11.96, 2*11.96)
        densStates = self.oxygen.getDensityOfStates(Elist)
        T = 100
        Qact = numpy.sum(densStates * numpy.exp(-Elist / constants.R / T))
        Qexp = self.oxygen.getPartitionFunction(T)
        self.assertAlmostEqual(Qexp, Qact, delta=1e-1*Qexp)

    def test_getTotalMass(self):
        """
        Test the Conformer.getTotalMass() method.
        """
        self.assertAlmostEqual(self.conformer.getTotalMass()*constants.Na*1000., numpy.sum(self.mass), 6)

    def test_getCenterOfMass(self):
        """
        Test the Conformer.getCenterOfMass() method.
        """
        cm = self.conformer.getCenterOfMass()
        self.assertAlmostEqual(cm[0]*1e10, -0.38045, 4)
        self.assertAlmostEqual(cm[1]*1e10, -0.60255, 4)
        self.assertAlmostEqual(cm[2]*1e10, -0.27900, 4)

    def test_getMomentOfInertiaTensor(self):
        """
        Test the Conformer.getMomentOfInertiaTensor() method.
        """
        I = self.conformer.getMomentOfInertiaTensor()
        self.assertAlmostEqual(I[0,0]*constants.Na*1e23, 20.65968, 4)
        self.assertAlmostEqual(I[0,1]*constants.Na*1e23, -7.48115, 4)
        self.assertAlmostEqual(I[0,2]*constants.Na*1e23, -3.46416, 4)
        self.assertAlmostEqual(I[1,0]*constants.Na*1e23, -7.48115, 4)
        self.assertAlmostEqual(I[1,1]*constants.Na*1e23, 13.53472, 4)
        self.assertAlmostEqual(I[1,2]*constants.Na*1e23, -5.48630, 4)
        self.assertAlmostEqual(I[2,0]*constants.Na*1e23, -3.46416, 4)
        self.assertAlmostEqual(I[2,1]*constants.Na*1e23, -5.48630, 4)
        self.assertAlmostEqual(I[2,2]*constants.Na*1e23, 22.84296, 4)

    def test_getPrincipalMomentsOfInertia(self):
        """
        Test the Conformer.getPrincipalMomentsOfInertia() method.
        """
        I, V = self.conformer.getPrincipalMomentsOfInertia()
        self.assertAlmostEqual(I[0]*constants.Na*1e23,  6.27074, 4)
        self.assertAlmostEqual(I[1]*constants.Na*1e23, 25.38321, 3)
        self.assertAlmostEqual(I[2]*constants.Na*1e23, 25.38341, 3)
        #print V
        # For some reason the axes seem to jump around (positioning and signs change)
        # but the absolute values should be the same as we expect
        expected = sorted([0.497140,
                           0.610114,
                           0.616938,
                           0.787360,
                           0.018454,
                           0.616218,
                           0.364578,
                           0.792099,
                           0.489554])
        result = sorted(abs(V).flat)
        for i,j in zip(expected, result):
            self.assertAlmostEqual(i, j, 4)
        return # now because the following often fails:
        self.assertAlmostEqual(V[0,0],  0.497140, 4)
        self.assertAlmostEqual(V[0,1], -0.610114, 4)
        self.assertAlmostEqual(V[0,2], -0.616938, 4)
        self.assertAlmostEqual(V[1,0],  0.787360, 4)
        self.assertAlmostEqual(V[1,1],  0.018454, 4)
        self.assertAlmostEqual(V[1,2],  0.616218, 4)
        self.assertAlmostEqual(V[2,0],  0.364578, 4)
        self.assertAlmostEqual(V[2,1],  0.792099, 4)
        self.assertAlmostEqual(V[2,2], -0.489554, 4)

    def test_getInternalReducedMomentOfInertia(self):
        """
        Test the Conformer.getInternalReducedMomentOfInertia() method.
        """
        I = self.conformer.getInternalReducedMomentOfInertia(pivots=[1,5], top1=[1,2,3,4])
        self.assertAlmostEqual(I*constants.Na*1e23, 1.56768, 4)

    def test_getNumberDegreesOfFreedom(self):
        """
        Test the Conformer.getNumberDegreesOfFreedom() method.
        """
        #this is for ethane:
        numberDegreesOfFreedom = self.conformer.getNumberDegreesOfFreedom()
        self.assertEqual(numberDegreesOfFreedom, 24)

        #this is for ethylene:
        # It doesn't check aganist 3*Natoms, because Natoms is not declared.
        numberDegreesOfFreedom = self.ethylene.getNumberDegreesOfFreedom()
        self.assertEqual(numberDegreesOfFreedom, 18)

        #this is for CO
        # It doesn't check aganist 3*Natoms, because Natoms is not declared.
        numberDegreesOfFreedom = self.oxygen.getNumberDegreesOfFreedom()
        self.assertEqual(numberDegreesOfFreedom, 6)
示例#2
0
    def get_enthalpy_of_formation(self,
                                  freq_scale_factor=1.0,
                                  apply_bond_corrections=True):
        """
        Calculate the enthalpy of formation at 298.15 K.
        Apply bond energy corrections if desired and if
        model chemistry is compatible.
        """
        temperature = 298.15
        mol = pybel.readstring('smi',
                               self.smiles)  # Use OBMol to extract bond types

        # Use RMG molecule to determine if it's linear
        # Assume it's not linear if we can't parse SMILES with RMG
        rmg_mol = None
        try:
            rmg_mol = Molecule().fromSMILES(self.smiles)
        except AtomTypeError:
            try:
                rmg_mol = Molecule().fromSMILES(self.smiles2)
            except AtomTypeError:
                try:
                    rmg_mol = Molecule().fromInChI(self.inchi)
                except AtomTypeError:
                    warnings.warn(
                        'Could not determine linearity from RMG molecule in {}'
                        .format(self.file_name))
        if rmg_mol is not None:
            is_linear = rmg_mol.isLinear()
        else:
            is_linear = False

        # Translation
        translation = IdealGasTranslation()

        # Rotation
        if is_linear:
            rotation = LinearRotor()
        else:
            rotation = NonlinearRotor(
                rotationalConstant=(self.rotational_consts, 'GHz'))

        # Vibration
        freqs = [f * freq_scale_factor
                 for f in self.freqs]  # Apply scale factor
        vibration = HarmonicOscillator(frequencies=(freqs, 'cm^-1'))

        # Group modes
        modes = [translation, rotation, vibration]
        conformer = Conformer(modes=modes)

        # Energy
        e0 = self.e0 * constants.E_h * constants.Na
        zpe = self.zpe * constants.E_h * constants.Na * freq_scale_factor

        # Bring energy to gas phase reference state at 298.15K
        atom_energies = energy_data.atom_energies[self.model_chemistry]
        for element in self.elements:
            e0 -= atom_energies[element] * constants.E_h * constants.Na
            e0 += self.enthalpy_corrections[element] * 4184.0

        if apply_bond_corrections:
            bond_energies = energy_data.bond_energy_corrections[
                self.model_chemistry]
            for bond in pybel.ob.OBMolBondIter(mol.OBMol):
                bond_symbol_split = [
                    self.atomic_num_dict[bond.GetBeginAtom().GetAtomicNum()],
                    self.bond_symbols[bond.GetBondOrder()],
                    self.atomic_num_dict[bond.GetEndAtom().GetAtomicNum()]
                ]

                try:
                    bond_energy = bond_energies[''.join(bond_symbol_split)]
                except KeyError:
                    bond_energy = bond_energies[''.join(
                        bond_symbol_split[::-1])]  # Try reverse order

                e0 += bond_energy * 4184.0

        conformer.E0 = (e0 + zpe, 'J/mol')
        self.hf298 = conformer.getEnthalpy(temperature) + conformer.E0.value_si

        return self.hf298
示例#3
0
class TestConformer(unittest.TestCase):
    """
    Contains unit tests of the :class:`Conformer` class.
    """
    
    def setUp(self):
        """
        A function run before each unit test in this class.
        """
        self.ethylene = Conformer(
            E0 = (0.0,"kJ/mol"),
            modes = [
                IdealGasTranslation(mass=(28.03,"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,
        )
        self.oxygen = Conformer(
            E0 = (0.0,"kJ/mol"),
            modes = [
                IdealGasTranslation(mass=(31.99,"amu")),
                LinearRotor(inertia=(11.6056,"amu*angstrom^2"), symmetry=2),
                HarmonicOscillator(frequencies=([1621.54],"cm^-1")),
            ],
            spinMultiplicity = 3,
            opticalIsomers = 1,
        )
        
        # The following data is for ethane at the CBS-QB3 level
        self.coordinates = numpy.array([
            [  0.0000,  0.0000,  0.0000],
            [ -0.0000, -0.0000,  1.0936],
            [  1.0430, -0.0000, -0.3288],
            [ -0.4484,  0.9417, -0.3288],
            [ -0.7609, -1.2051, -0.5580],
            [ -0.7609, -1.2051, -1.6516],
            [ -0.3125, -2.1468, -0.2292],
            [ -1.8039, -1.2051, -0.2293],
        ])
        self.number = numpy.array([6, 1, 1, 1, 6, 1, 1, 1])
        self.mass = numpy.array([12, 1.007825, 1.007825, 1.007825, 12, 1.007825, 1.007825, 1.007825])
        self.E0 = -93.5097
        self.conformer = Conformer(
            E0 = (self.E0,"kJ/mol"),
            modes = [
                IdealGasTranslation(mass=(30.0469,"amu")),
                NonlinearRotor(inertia=([6.27071,25.3832,25.3833],"amu*angstrom^2"), symmetry=6),
                HarmonicOscillator(frequencies=([818.917,819.479,987.099,1206.76,1207.05,1396,1411.35,1489.73,1489.95,1492.49,1492.66,2995.36,2996.06,3040.77,3041,3065.86,3066.02],"cm^-1")),
                HinderedRotor(inertia=(1.56768,"amu*angstrom^2"), symmetry=3, barrier=(2.69401,"kcal/mol"), quantum=False, semiclassical=False),
            ],
            spinMultiplicity = 1,
            opticalIsomers = 1,
            coordinates = (self.coordinates,"angstrom"),
            number = self.number,
            mass = (self.mass,"amu"),
        )
        
    def test_getPartitionFunction_ethylene(self):
        """
        Test the StatMech.getPartitionFunction() method for ethylene.
        """
        Tlist = numpy.array([300,500,1000,1500,2000])
        Qexplist = numpy.array([4.05311e+09, 4.19728e+10, 2.82309e+12, 7.51135e+13, 1.16538e+15])
        for T, Qexp in zip(Tlist, Qexplist):
            Qact = self.ethylene.getPartitionFunction(T)
            self.assertAlmostEqual(Qexp, Qact, delta=1e-4*Qexp)

    def test_getHeatCapacity_ethylene(self):
        """
        Test the StatMech.getHeatCapacity() method for ethylene.
        """
        Tlist = numpy.array([300,500,1000,1500,2000])
        Cvexplist = numpy.array([5.11186, 7.40447, 11.1659, 13.1221, 14.1617]) * constants.R
        for T, Cvexp in zip(Tlist, Cvexplist):
            Cvact = self.ethylene.getHeatCapacity(T)
            self.assertAlmostEqual(Cvexp, Cvact, 3)
    
    def test_getEnthalpy_ethylene(self):
        """
        Test the StatMech.getEnthalpy() method for ethylene.
        """
        Tlist = numpy.array([300,500,1000,1500,2000])
        Hexplist = numpy.array([4.23129, 5.04826, 7.27337, 8.93167, 10.1223]) * constants.R * Tlist
        for T, Hexp in zip(Tlist, Hexplist):
            Hact = self.ethylene.getEnthalpy(T)
            self.assertAlmostEqual(Hexp, Hact, delta=1e-4*Hexp)
    
    def test_getEntropy_ethylene(self):
        """
        Test the StatMech.getEntropy() method for ethylene.
        """
        Tlist = numpy.array([300,500,1000,1500,2000])
        Sexplist = numpy.array([26.3540, 29.5085, 35.9422, 40.8817, 44.8142]) * constants.R
        for T, Sexp in zip(Tlist, Sexplist):
            Sact = self.ethylene.getEntropy(T)
            self.assertAlmostEqual(Sexp, Sact, 3)
    
    def test_getSumOfStates_ethylene(self):
        """
        Test the StatMech.getSumOfStates() method for ethylene.
        """
        Elist = numpy.arange(0, 5000*11.96, 2*11.96)
        sumStates = self.ethylene.getSumOfStates(Elist)
        densStates = self.ethylene.getDensityOfStates(Elist)
        for n in range(10, len(Elist)):
            self.assertTrue(0.8 < numpy.sum(densStates[0:n+1]) / sumStates[n] < 1.25, '{0} != {1}'.format(numpy.sum(densStates[0:n+1]), sumStates[n]))
            
    def test_getDensityOfStates_ethylene(self):
        """
        Test the StatMech.getDensityOfStates() method for ethylene.
        """
        Elist = numpy.arange(0, 5000*11.96, 2*11.96)
        densStates = self.ethylene.getDensityOfStates(Elist)
        T = 100
        Qact = numpy.sum(densStates * numpy.exp(-Elist / constants.R / T))
        Qexp = self.ethylene.getPartitionFunction(T)
        self.assertAlmostEqual(Qexp, Qact, delta=1e-1*Qexp)

    def test_getPartitionFunction_oxygen(self):
        """
        Test the StatMech.getPartitionFunction() method for oxygen.
        """
        Tlist = numpy.array([300,500,1000,1500,2000])
        Qexplist = numpy.array([1.55584e+09, 9.38339e+09, 1.16459e+11, 5.51016e+11, 1.72794e+12])
        for T, Qexp in zip(Tlist, Qexplist):
            Qact = self.oxygen.getPartitionFunction(T)
            self.assertAlmostEqual(Qexp, Qact, delta=1e-4*Qexp)

    def test_getHeatCapacity_oxygen(self):
        """
        Test the StatMech.getHeatCapacity() method for oxygen.
        """
        Tlist = numpy.array([300,500,1000,1500,2000])
        Cvexplist = numpy.array([3.52538, 3.70877, 4.14751, 4.32063, 4.39392]) * constants.R
        for T, Cvexp in zip(Tlist, Cvexplist):
            Cvact = self.oxygen.getHeatCapacity(T)
            self.assertAlmostEqual(Cvexp, Cvact, 3)
    
    def test_getEnthalpy_oxygen(self):
        """
        Test the StatMech.getEnthalpy() method for oxygen.
        """
        Tlist = numpy.array([300,500,1000,1500,2000])
        Hexplist = numpy.array([3.50326, 3.54432, 3.75062, 3.91623, 4.02765]) * constants.R * Tlist
        for T, Hexp in zip(Tlist, Hexplist):
            Hact = self.oxygen.getEnthalpy(T)
            self.assertAlmostEqual(Hexp, Hact, delta=1e-4*Hexp)
    
    def test_getEntropy_oxygen(self):
        """
        Test the StatMech.getEntropy() method for oxygen.
        """
        Tlist = numpy.array([300,500,1000,1500,2000])
        Sexplist = numpy.array([24.6685, 26.5065, 29.2314, 30.9513, 32.2056]) * constants.R
        for T, Sexp in zip(Tlist, Sexplist):
            Sact = self.oxygen.getEntropy(T)
            self.assertAlmostEqual(Sexp, Sact, 3)
    
    def test_getSumOfStates_oxygen(self):
        """
        Test the StatMech.getSumOfStates() method for oxygen.
        """
        Elist = numpy.arange(0, 5000*11.96, 2*11.96)
        sumStates = self.oxygen.getSumOfStates(Elist)
        densStates = self.oxygen.getDensityOfStates(Elist)
        for n in range(10, len(Elist)):
            self.assertTrue(0.8 < numpy.sum(densStates[0:n+1]) / sumStates[n] < 1.25, '{0} != {1}'.format(numpy.sum(densStates[0:n+1]), sumStates[n]))
            
    def test_getDensityOfStates_oxygen(self):
        """
        Test the StatMech.getDensityOfStates() method for oxygen.
        """
        Elist = numpy.arange(0, 5000*11.96, 2*11.96)
        densStates = self.oxygen.getDensityOfStates(Elist)
        T = 100
        Qact = numpy.sum(densStates * numpy.exp(-Elist / constants.R / T))
        Qexp = self.oxygen.getPartitionFunction(T)
        self.assertAlmostEqual(Qexp, Qact, delta=1e-1*Qexp)

    def test_getTotalMass(self):
        """
        Test the Conformer.getTotalMass() method.
        """
        self.assertAlmostEqual(self.conformer.getTotalMass()*constants.Na*1000., numpy.sum(self.mass), 6)

    def test_getCenterOfMass(self):
        """
        Test the Conformer.getCenterOfMass() method.
        """
        cm = self.conformer.getCenterOfMass()
        self.assertAlmostEqual(cm[0]*1e10, -0.38045, 4)
        self.assertAlmostEqual(cm[1]*1e10, -0.60255, 4)
        self.assertAlmostEqual(cm[2]*1e10, -0.27900, 4)

    def test_getMomentOfInertiaTensor(self):
        """
        Test the Conformer.getMomentOfInertiaTensor() method.
        """
        I = self.conformer.getMomentOfInertiaTensor()
        self.assertAlmostEqual(I[0,0]*constants.Na*1e23, 20.65968, 4)
        self.assertAlmostEqual(I[0,1]*constants.Na*1e23, -7.48115, 4)
        self.assertAlmostEqual(I[0,2]*constants.Na*1e23, -3.46416, 4)
        self.assertAlmostEqual(I[1,0]*constants.Na*1e23, -7.48115, 4)
        self.assertAlmostEqual(I[1,1]*constants.Na*1e23, 13.53472, 4)
        self.assertAlmostEqual(I[1,2]*constants.Na*1e23, -5.48630, 4)
        self.assertAlmostEqual(I[2,0]*constants.Na*1e23, -3.46416, 4)
        self.assertAlmostEqual(I[2,1]*constants.Na*1e23, -5.48630, 4)
        self.assertAlmostEqual(I[2,2]*constants.Na*1e23, 22.84296, 4)

    def test_getPrincipalMomentsOfInertia(self):
        """
        Test the Conformer.getPrincipalMomentsOfInertia() method.
        """
        I, V = self.conformer.getPrincipalMomentsOfInertia()
        self.assertAlmostEqual(I[0]*constants.Na*1e23,  6.27074, 4)
        self.assertAlmostEqual(I[1]*constants.Na*1e23, 25.38321, 3)
        self.assertAlmostEqual(I[2]*constants.Na*1e23, 25.38341, 3)
        #print V
        # For some reason the axes seem to jump around (positioning and signs change)
        # but the absolute values should be the same as we expect
        expected = sorted([0.497140,
                           0.610114,
                           0.616938,
                           0.787360,
                           0.018454,
                           0.616218,
                           0.364578,
                           0.792099,
                           0.489554])
        result = sorted(abs(V).flat)
        for i,j in zip(expected, result):
            self.assertAlmostEqual(i, j, 4)
        return

    def test_getInternalReducedMomentOfInertia(self):
        """
        Test the Conformer.getInternalReducedMomentOfInertia() method.
        """
        I = self.conformer.getInternalReducedMomentOfInertia(pivots=[1,5], top1=[1,2,3,4])
        self.assertAlmostEqual(I*constants.Na*1e23, 1.56768, 4)

    def test_getNumberDegreesOfFreedom(self):
        """
        Test the Conformer.getNumberDegreesOfFreedom() method.
        """
        #this is for ethane:
        numberDegreesOfFreedom = self.conformer.getNumberDegreesOfFreedom()
        self.assertEqual(numberDegreesOfFreedom, 24)

        #this is for ethylene:
        # It doesn't check aganist 3*Natoms, because Natoms is not declared.
        numberDegreesOfFreedom = self.ethylene.getNumberDegreesOfFreedom()
        self.assertEqual(numberDegreesOfFreedom, 18)

        #this is for CO
        # It doesn't check aganist 3*Natoms, because Natoms is not declared.
        numberDegreesOfFreedom = self.oxygen.getNumberDegreesOfFreedom()
        self.assertEqual(numberDegreesOfFreedom, 6)
示例#4
0
文件: thermo.py 项目: cgrambow/q2t
def get_thermo(optfreq_log, optfreq_level, energy_level, energy_log=None,
               mol=None, bacs=None, soc=False,
               infer_symmetry=False, infer_chirality=False, unique_id='0', scr_dir='SCRATCH'):

    q = QChem(logfile=optfreq_log)
    symbols, coords = q.get_geometry()
    inertia = q.get_moments_of_inertia()
    freqs = q.get_frequencies()
    zpe = q.get_zpe()

    if energy_log is None:
        e0 = q.get_energy()
        multiplicity = q.get_multiplicity()
    else:
        m = Molpro(logfile=energy_log)
        e0 = m.get_energy()
        multiplicity = m.get_multiplicity()

    # Infer connections only if not given explicitly
    if mol is None:
        mol = geo_to_rmg_mol((symbols, coords))  # Does not contain bond orders

    # Try to infer point group to calculate symmetry number and chirality
    symmetry = optical_isomers = 1
    point_group = None
    if infer_symmetry or infer_chirality:
        qmdata = QMData(
            groundStateDegeneracy=multiplicity,  # Only needed to check if valid QMData
            numberOfAtoms=len(symbols),
            atomicNumbers=[atomic_symbol_dict[sym] for sym in symbols],
            atomCoords=(coords, 'angstrom'),
            energy=(e0 * 627.5095, 'kcal/mol')  # Only needed to avoid error
        )
        settings = type("", (), dict(symmetryPath='symmetry', scratchDirectory=scr_dir))()  # Creates anonymous class
        pgc = PointGroupCalculator(settings, unique_id, qmdata)
        point_group = pgc.calculate()
    if point_group is not None:
        if infer_symmetry:
            symmetry = point_group.symmetryNumber
        if infer_chirality and point_group.chiral:
            optical_isomers = 2

    # Translational mode
    mass = mol.getMolecularWeight()
    translation = IdealGasTranslation(mass=(mass, 'kg/mol'))

    # Rotational mode
    if isinstance(inertia, list):  # Nonlinear
        rotation = NonlinearRotor(inertia=(inertia, 'amu*angstrom^2'), symmetry=symmetry)
    else:
        rotation = LinearRotor(inertia=(inertia, 'amu*angstrom^2'), symmetry=symmetry)

    # Vibrational mode
    freq_scale_factor = freq_scale_factors.get(optfreq_level, 1.0)
    freqs = [f * freq_scale_factor for f in freqs]
    vibration = HarmonicOscillator(frequencies=(freqs, 'cm^-1'))

    # Bring energy to gas phase reference state
    e0 *= constants.E_h * constants.Na
    zpe *= constants.E_h * constants.Na * freq_scale_factor
    for sym in symbols:
        if soc:
            e0 -= (atom_energies[energy_level][sym] - atom_socs[sym]) * constants.E_h * constants.Na
        else:
            e0 -= atom_energies[energy_level][sym] * constants.E_h * constants.Na
        e0 += (h0expt[sym] - h298corr[sym]) * 4184.0

    if bacs is not None:
        e0 -= get_bac_correction(mol, **bacs) * 4184.0

    # Group modes into Conformer object
    modes = [translation, rotation, vibration]
    conformer = Conformer(modes=modes, spinMultiplicity=multiplicity, opticalIsomers=optical_isomers)

    # Calculate heat of formation, entropy of formation, and heat capacities
    conformer.E0 = (e0 + zpe, 'J/mol')
    hf298 = conformer.getEnthalpy(298.0) + conformer.E0.value_si
    s298 = conformer.getEntropy(298.0)

    Tlist = [300.0, 400.0, 500.0, 600.0, 800.0, 1000.0, 1500.0]
    cp = np.zeros(len(Tlist))
    for i, T in enumerate(Tlist):
        cp[i] = conformer.getHeatCapacity(T)

    # Return in kcal/mol and cal/mol/K
    return hf298/4184.0, s298/4.184, cp/4.184