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)
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
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)
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