def setUp(self): """ A function run before each unit test in this class. """ self.inertia = 1.56764 self.symmetry = 3 self.barrier = 11.373 self.quantum = True self.mode = HinderedRotor( inertia=(self.inertia, "amu*angstrom^2"), symmetry=self.symmetry, barrier=(self.barrier, "kJ/mol"), fourier=([[4.58375, 0.841648, -5702.71, 6.02657, 4.7446], [0.726951, -0.677255, 0.207032, 0.553307, -0.503303]], "J/mol"), quantum=self.quantum, )
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)
def setUp(self): """ A function run before each unit test in this class. """ self.inertia = 1.56764 self.symmetry = 3 self.barrier = 11.373 self.quantum = True self.mode = HinderedRotor( inertia = (self.inertia,"amu*angstrom^2"), symmetry = self.symmetry, barrier = (self.barrier,"kJ/mol"), fourier = ([ [4.58375, 0.841648, -5702.71, 6.02657, 4.7446], [0.726951, -0.677255, 0.207032, 0.553307, -0.503303] ],"J/mol"), quantum = self.quantum, )
class TestHinderedRotor(unittest.TestCase): """ Contains unit tests of the HinderedRotor class. """ def setUp(self): """ A function run before each unit test in this class. """ self.inertia = 1.56764 self.symmetry = 3 self.barrier = 11.373 self.quantum = True self.mode = HinderedRotor( inertia=(self.inertia, "amu*angstrom^2"), symmetry=self.symmetry, barrier=(self.barrier, "kJ/mol"), fourier=([[4.58375, 0.841648, -5702.71, 6.02657, 4.7446], [0.726951, -0.677255, 0.207032, 0.553307, -0.503303]], "J/mol"), quantum=self.quantum, ) self.freemode = FreeRotor( inertia=(self.inertia, "amu*angstrom^2"), symmetry=self.symmetry, ) def test_getRotationalConstant(self): """ Test getting the HinderedRotor.rotationalConstant property. """ Bexp = 10.7535 Bact = self.mode.rotationalConstant.value_si self.assertAlmostEqual(Bexp, Bact, 4) Bact2 = self.freemode.rotationalConstant.value_si self.assertAlmostEqual(Bexp, Bact2, 4) def test_setRotationalConstant(self): """ Test setting the HinderedRotor.rotationalConstant property. """ B = self.mode.rotationalConstant B.value_si *= 2 self.mode.rotationalConstant = B self.freemode.rotationalConstant = B Iexp = 0.5 * self.inertia Iact = self.mode.inertia.value_si * constants.Na * 1e23 Iact2 = self.freemode.inertia.value_si * constants.Na * 1e23 self.assertAlmostEqual(Iexp, Iact, 4) self.assertAlmostEqual(Iexp, Iact2, 4) def test_getPotential_cosine(self): """ Test the HinderedRotor.getPotential() method for a cosine potential. """ self.mode.fourier = None phi = numpy.arange(0.0, 2 * constants.pi + 0.0001, constants.pi / 24.) V = numpy.zeros_like(phi) for i in range(phi.shape[0]): V[i] = self.mode.getPotential(phi[i]) def test_getPotential_fourier(self): """ Test the HinderedRotor.getPotential() method for a Fourier series potential. """ phi = numpy.arange(0.0, 2 * constants.pi + 0.0001, constants.pi / 24.) V = numpy.zeros_like(phi) for i in range(phi.shape[0]): V[i] = self.mode.getPotential(phi[i]) def test_getPartitionFunction_free(self): """ Test the FreeRotor.getPartitionFunction() method """ Tlist = numpy.array([300, 500, 1000, 1500, 2000]) Qexplist = numpy.sqrt( 8 * numpy.pi**3 * constants.kB * Tlist * self.freemode.inertia.value_si) / (self.symmetry * constants.h) for T, Qexp in zip(Tlist, Qexplist): Qact = self.freemode.getPartitionFunction(T) self.assertAlmostEqual(Qexp, Qact, delta=1e-4 * Qexp) def test_getPartitionFunction_classical_cosine(self): """ Test the HinderedRotor.getPartitionFunction() method for a cosine potential in the classical limit. """ self.mode.quantum = False self.mode.fourier = None Tlist = numpy.array([300, 500, 1000, 1500, 2000]) Qexplist = numpy.array([0.741953, 1.30465, 2.68553, 3.88146, 4.91235]) for T, Qexp in zip(Tlist, Qexplist): Qact = self.mode.getPartitionFunction(T) self.assertAlmostEqual(Qexp, Qact, delta=1e-4 * Qexp) def test_getPartitionFunction_classical_fourier(self): """ Test the HinderedRotor.getPartitionFunction() method for a Fourier series potential in the classical limit. """ self.mode.quantum = False Tlist = numpy.array([300, 500, 1000, 1500, 2000]) Qexplist = numpy.array([0.745526, 1.30751, 2.68722, 3.88258, 4.91315]) for T, Qexp in zip(Tlist, Qexplist): Qact = self.mode.getPartitionFunction(T) self.assertAlmostEqual(Qexp, Qact, delta=1e-4 * Qexp) def test_getPartitionFunction_quantum_cosine(self): """ Test the HinderedRotor.getPartitionFunction() method for a cosine potential in the quantum limit. """ self.mode.quantum = True self.mode.fourier = None Tlist = numpy.array([300, 500, 1000, 1500, 2000]) Qexplist = numpy.array([1.39947, 1.94793, 3.30171, 4.45856, 5.45188]) for T, Qexp in zip(Tlist, Qexplist): Qact = self.mode.getPartitionFunction(T) self.assertAlmostEqual(Qexp, Qact, delta=1e-4 * Qexp) def test_getPartitionFunction_quantum_fourier(self): """ Test the HinderedRotor.getPartitionFunction() method for a Fourier series potential in the quantum limit. """ self.mode.quantum = True Tlist = numpy.array([300, 500, 1000, 1500, 2000]) Qexplist = numpy.array([1.39364, 1.94182, 3.29509, 4.45205, 5.44563]) for T, Qexp in zip(Tlist, Qexplist): Qact = self.mode.getPartitionFunction(T) self.assertAlmostEqual(Qexp, Qact, delta=5e-4 * Qexp) def test_getHeatCapacity_free(self): """ Test the FreeRotor.getHeatCapacity() method """ Cvexp = constants.R / 2.0 Tlist = numpy.array([300, 500, 1000, 1500, 2000]) for T in Tlist: Cvact = self.freemode.getHeatCapacity(T) self.assertAlmostEqual(Cvexp, Cvact, delta=1e-4 * Cvexp) def test_getHeatCapacity_classical_cosine(self): """ Test the HinderedRotor.getHeatCapacity() method using a cosine potential in the classical limit. """ self.mode.quantum = False self.mode.fourier = None Tlist = numpy.array([300, 500, 1000, 1500, 2000]) Cvexplist = numpy.array( [1.01741, 0.951141, 0.681919, 0.589263, 0.552028]) * constants.R for T, Cvexp in zip(Tlist, Cvexplist): Cvact = self.mode.getHeatCapacity(T) self.assertAlmostEqual(Cvexp, Cvact, delta=1e-4 * Cvexp) def test_getHeatCapacity_classical_fourier(self): """ Test the HinderedRotor.getHeatCapacity() method using a Fourier series potential in the classical limit. """ self.mode.quantum = False Tlist = numpy.array([300, 500, 1000, 1500, 2000]) Cvexplist = numpy.array( [1.17682, 1.01369, 0.698588, 0.596797, 0.556293]) * constants.R for T, Cvexp in zip(Tlist, Cvexplist): Cvact = self.mode.getHeatCapacity(T) self.assertAlmostEqual(Cvexp, Cvact, delta=1e-4 * Cvexp) def test_getHeatCapacity_quantum_cosine(self): """ Test the HinderedRotor.getHeatCapacity() method using a cosine potential in the quantum limit. """ self.mode.quantum = True self.mode.fourier = None Tlist = numpy.array([300, 500, 1000, 1500, 2000]) Cvexplist = numpy.array( [1.01271, 0.945341, 0.684451, 0.591949, 0.554087]) * constants.R for T, Cvexp in zip(Tlist, Cvexplist): Cvact = self.mode.getHeatCapacity(T) self.assertAlmostEqual(Cvexp, Cvact, delta=1e-4 * Cvexp) def test_getHeatCapacity_quantum_fourier(self): """ Test the HinderedRotor.getHeatCapacity() method using a Fourier series potential in the quantum limit. """ self.mode.quantum = True Tlist = numpy.array([300, 500, 1000, 1500, 2000]) Cvexplist = numpy.array( [1.01263, 0.946618, 0.685345, 0.592427, 0.554374]) * constants.R for T, Cvexp in zip(Tlist, Cvexplist): Cvact = self.mode.getHeatCapacity(T) self.assertAlmostEqual(Cvexp, Cvact, delta=1e-3 * Cvexp) def test_getEnthalpy_free(self): """ Test the FreeRotor.getEnthalpy() method """ Tlist = numpy.array([300, 500, 1000, 1500, 2000]) Hexplist = constants.R * Tlist / 2.0 for T, Hexp in zip(Tlist, Hexplist): Hact = self.freemode.getEnthalpy(T) self.assertAlmostEqual(Hexp, Hact, delta=1e-4 * Hexp) def test_getEnthalpy_classical_cosine(self): """ Test the HinderedRotor.getEnthalpy() method using a cosine potential in the classical limit. """ self.mode.quantum = False self.mode.fourier = None Tlist = numpy.array([300, 500, 1000, 1500, 2000]) Hexplist = numpy.array([ 1.09556, 1.09949, 0.962738, 0.854617, 0.784333 ]) * constants.R * Tlist for T, Hexp in zip(Tlist, Hexplist): Hact = self.mode.getEnthalpy(T) self.assertAlmostEqual(Hexp, Hact, delta=1e-4 * Hexp) def test_getEnthalpy_classical_fourier(self): """ Test the HinderedRotor.getEnthalpy() method using a Fourier series potential in the classical limit. """ self.mode.quantum = False Tlist = numpy.array([300, 500, 1000, 1500, 2000]) Hexplist = numpy.array([ 1.08882, 1.09584, 0.961543, 0.854054, 0.784009 ]) * constants.R * Tlist for T, Hexp in zip(Tlist, Hexplist): Hact = self.mode.getEnthalpy(T) self.assertAlmostEqual(Hexp, Hact, delta=1e-4 * Hexp) def test_getEnthalpy_quantum_cosine(self): """ Test the HinderedRotor.getEnthalpy() method using a cosine potential in the quantum limit. """ self.mode.quantum = True self.mode.fourier = None Tlist = numpy.array([300, 500, 1000, 1500, 2000]) Hexplist = numpy.array([ 0.545814, 0.727200, 0.760918, 0.717496, 0.680767 ]) * constants.R * Tlist for T, Hexp in zip(Tlist, Hexplist): Hact = self.mode.getEnthalpy(T) self.assertAlmostEqual(Hexp, Hact, delta=1e-4 * Hexp) def test_getEnthalpy_quantum_fourier(self): """ Test the HinderedRotor.getEnthalpy() method using a Fourier series potential in the quantum limit. """ self.mode.quantum = True Tlist = numpy.array([300, 500, 1000, 1500, 2000]) Hexplist = numpy.array([ 0.548251, 0.728974, 0.762396, 0.718702, 0.681764 ]) * constants.R * Tlist for T, Hexp in zip(Tlist, Hexplist): Hact = self.mode.getEnthalpy(T) self.assertAlmostEqual(Hexp, Hact, delta=1e-3 * Hexp) def test_getEntropy_free(self): Tlist = numpy.array([300, 500, 1000, 1500, 2000]) Q = numpy.array([self.freemode.getPartitionFunction(T) for T in Tlist]) Sexplist = constants.R * (numpy.log(Q) + .5) for T, Sexp in zip(Tlist, Sexplist): Sact = self.freemode.getEntropy(T) self.assertAlmostEqual(Sexp, Sact, delta=1e-4 * Sexp) def test_getEntropy_classical_cosine(self): """ Test the HinderedRotor.getEntropy() method using a cosine potential in the classical limit. """ self.mode.quantum = False self.mode.fourier = None Tlist = numpy.array([300, 500, 1000, 1500, 2000]) Sexplist = numpy.array([0.797089, 1.36543, 1.95062, 2.21083, 2.37608 ]) * constants.R for T, Sexp in zip(Tlist, Sexplist): Sact = self.mode.getEntropy(T) self.assertAlmostEqual(Sexp, Sact, delta=1e-4 * Sexp) def test_getEntropy_classical_fourier(self): """ Test the HinderedRotor.getEntropy() method using a Fourier series potential in the classical limit. """ self.mode.quantum = False Tlist = numpy.array([300, 500, 1000, 1500, 2000]) Sexplist = numpy.array([0.795154, 1.36396, 1.95005, 2.21055, 2.37592 ]) * constants.R for T, Sexp in zip(Tlist, Sexplist): Sact = self.mode.getEntropy(T) self.assertAlmostEqual(Sexp, Sact, delta=1e-4 * Sexp) def test_getEntropy_quantum_cosine(self): """ Test the HinderedRotor.getEntropy() method using a cosine potential in the quantum limit. """ self.mode.quantum = True self.mode.fourier = None Tlist = numpy.array([300, 500, 1000, 1500, 2000]) Sexplist = numpy.array([0.881906, 1.39397, 1.95536, 2.21232, 2.37673 ]) * constants.R for T, Sexp in zip(Tlist, Sexplist): Sact = self.mode.getEntropy(T) self.assertAlmostEqual(Sexp, Sact, delta=1e-4 * Sexp) def test_getEntropy_quantum_fourier(self): """ Test the HinderedRotor.getEntropy() method using a Fourier series potential in the quantum limit. """ self.mode.quantum = True Tlist = numpy.array([300, 500, 1000, 1500, 2000]) Sexplist = numpy.array([0.880170, 1.39260, 1.95483, 2.21207, 2.37658 ]) * constants.R for T, Sexp in zip(Tlist, Sexplist): Sact = self.mode.getEntropy(T) self.assertAlmostEqual(Sexp, Sact, delta=1e-3 * Sexp) def test_getSumOfStates_classical_cosine(self): """ Test the HinderedRotor.getSumOfStates() method using a cosine potential in the classical limit. """ self.mode.quantum = False self.mode.fourier = None Elist = numpy.arange(0, 10000 * 11.96, 1 * 11.96) sumStates = self.mode.getSumOfStates(Elist) densStates = self.mode.getDensityOfStates(Elist) for n in range(10, len(Elist)): self.assertTrue( 0.8 < numpy.sum(densStates[0:n]) / sumStates[n - 1] < 1.25, '{0} != {1}'.format(numpy.sum(densStates[0:n]), sumStates[n])) def test_getSumOfStates_classical_fourier(self): """ Test the HinderedRotor.getSumOfStates() method using a Fourier series potential in the classical limit. """ self.mode.quantum = False Elist = numpy.arange(0, 10000 * 11.96, 1 * 11.96) try: sumStates = self.mode.getSumOfStates(Elist) self.fail( 'NotImplementedError not raised by HinderedRotor.getSumOfStates()' ) except NotImplementedError: pass def test_getSumOfStates_quantum_cosine(self): """ Test the HinderedRotor.getSumOfStates() method using a cosine potential in the quantum limit. """ self.mode.quantum = True self.mode.fourier = None Elist = numpy.arange(0, 10000 * 11.96, 1 * 11.96) sumStates = self.mode.getSumOfStates(Elist) densStates = self.mode.getDensityOfStates(Elist) for n in range(10, len(Elist)): self.assertTrue( 0.8 < numpy.sum(densStates[0:n]) / sumStates[n - 1] < 1.25, '{0} != {1}'.format(numpy.sum(densStates[0:n]), sumStates[n])) def test_getSumOfStates_quantum_fourier(self): """ Test the HinderedRotor.getSumOfStates() method using a Fourier series potential in the quantum limit. """ self.mode.quantum = True Elist = numpy.arange(0, 10000 * 11.96, 1 * 11.96) sumStates = self.mode.getSumOfStates(Elist) densStates = self.mode.getDensityOfStates(Elist) for n in range(10, len(Elist)): self.assertTrue( 0.8 < numpy.sum(densStates[0:n]) / sumStates[n - 1] < 1.25, '{0} != {1}'.format(numpy.sum(densStates[0:n]), sumStates[n])) def test_getDensityOfStates_classical_cosine(self): """ Test the HinderedRotor.getDensityOfStates() method using a classical potential in the classical limit. """ self.mode.quantum = False self.mode.fourier = None Elist = numpy.arange(0, 10000 * 11.96, 1 * 11.96) densStates = self.mode.getDensityOfStates(Elist) T = 100 Qact = numpy.sum(densStates * numpy.exp(-Elist / constants.R / T)) Qexp = self.mode.getPartitionFunction(T) self.assertAlmostEqual(Qexp, Qact, delta=1e-2 * Qexp) def test_getDensityOfStates_classical_fourier(self): """ Test the HinderedRotor.getDensityOfStates() method using a Fourier series potential in the classical limit. """ self.mode.quantum = False Elist = numpy.arange(0, 10000 * 11.96, 1 * 11.96) try: densStates = self.mode.getDensityOfStates(Elist) self.fail( 'NotImplementedError not raised by HinderedRotor.getDensityOfStates()' ) except NotImplementedError: pass def test_getDensityOfStates_quantum_cosine(self): """ Test the HinderedRotor.getDensityOfStates() method using a classical potential in the quantum limit. """ self.mode.quantum = True self.mode.fourier = None Elist = numpy.arange(0, 10000 * 11.96, 1 * 11.96) densStates = self.mode.getDensityOfStates(Elist) T = 100 Qact = numpy.sum(densStates * numpy.exp(-Elist / constants.R / T)) Qexp = self.mode.getPartitionFunction(T) self.assertAlmostEqual(Qexp, Qact, delta=1e-2 * Qexp) def test_getDensityOfStates_quantum_fourier(self): """ Test the HinderedRotor.getDensityOfStates() method using a Fourier series potential in the quantum limit. """ self.mode.quantum = True Elist = numpy.arange(0, 10000 * 11.96, 1 * 11.96) densStates = self.mode.getDensityOfStates(Elist) T = 100 Qact = numpy.sum(densStates * numpy.exp(-Elist / constants.R / T)) Qexp = self.mode.getPartitionFunction(T) self.assertAlmostEqual(Qexp, Qact, delta=1e-2 * Qexp) def test_repr(self): """ Test that a HinderedRotor object can be reconstructed from its repr() output with no loss of information. """ mode = None exec('mode = {0!r}'.format(self.mode)) self.assertAlmostEqual(self.mode.inertia.value, mode.inertia.value, 6) self.assertEqual(self.mode.inertia.units, mode.inertia.units, 6) self.assertEqual(self.mode.fourier.value.shape, mode.fourier.value.shape) for A0, A in zip(self.mode.fourier.value.flat, mode.fourier.value.flat): self.assertAlmostEqual(A0 / A, 1.0, 6) self.assertEqual(self.mode.fourier.units, mode.fourier.units) self.assertAlmostEqual(self.mode.barrier.value, mode.barrier.value, 6) self.assertEqual(self.mode.barrier.units, mode.barrier.units) self.assertEqual(self.mode.symmetry, mode.symmetry) self.assertEqual(self.mode.quantum, mode.quantum) def test_pickle(self): """ Test that a HinderedRotor object can be pickled and unpickled with no loss of information. """ import cPickle mode = cPickle.loads(cPickle.dumps(self.mode, -1)) self.assertAlmostEqual(self.mode.inertia.value, mode.inertia.value, 6) self.assertEqual(self.mode.inertia.units, mode.inertia.units, 6) self.assertEqual(self.mode.fourier.value.shape, mode.fourier.value.shape) for A0, A in zip(self.mode.fourier.value.flat, mode.fourier.value.flat): self.assertAlmostEqual(A0 / A, 1.0, 6) self.assertEqual(self.mode.fourier.units, mode.fourier.units) self.assertAlmostEqual(self.mode.barrier.value, mode.barrier.value, 6) self.assertEqual(self.mode.barrier.units, mode.barrier.units) self.assertEqual(self.mode.symmetry, mode.symmetry) self.assertEqual(self.mode.quantum, mode.quantum)
class StatMechJob: """ A representation of a CanTherm statistical mechanics job. This job is used to compute and save the statistical mechanics information for a single species or transition state. """ def __init__(self, species, path): self.species = species self.path = path self.modelChemistry = '' self.frequencyScaleFactor = 1.0 self.includeHinderedRotors = True self.applyBondEnergyCorrections = True def execute(self, outputFile=None, plot=False): """ Execute the statistical mechanics job, saving the results to the given `outputFile` on disk. """ self.load() if outputFile is not None: self.save(outputFile) def load(self): """ Load the statistical mechanics parameters for each conformer from the associated files on disk. Creates :class:`Conformer` objects for each conformer and appends them to the list of confomers on the species object. """ logging.info( 'Loading statistical mechanics parameters for {0}...'.format( self.species.label)) path = self.path TS = isinstance(self.species, TransitionState) global_context = { '__builtins__': None, } local_context = { '__builtins__': None, 'True': True, 'False': False, 'HinderedRotor': hinderedRotor, # File formats 'GaussianLog': GaussianLog, 'QchemLog': QchemLog, 'MoleProLog': MoleProLog, 'ScanLog': ScanLog, } directory = os.path.abspath(os.path.dirname(path)) with open(path, 'r') as f: try: exec f in global_context, local_context except (NameError, TypeError, SyntaxError), e: logging.error('The species file {0} was invalid:'.format(path)) raise try: atoms = local_context['atoms'] except KeyError: raise InputError( 'Required attribute "atoms" not found in species file {0!r}.'. format(path)) try: bonds = local_context['bonds'] except KeyError: bonds = {} try: linear = local_context['linear'] except KeyError: raise InputError( 'Required attribute "linear" not found in species file {0!r}.'. format(path)) try: externalSymmetry = local_context['externalSymmetry'] except KeyError: raise InputError( 'Required attribute "externalSymmetry" not found in species file {0!r}.' .format(path)) try: spinMultiplicity = local_context['spinMultiplicity'] except KeyError: raise InputError( 'Required attribute "spinMultiplicity" not found in species file {0!r}.' .format(path)) try: opticalIsomers = local_context['opticalIsomers'] except KeyError: raise InputError( 'Required attribute "opticalIsomers" not found in species file {0!r}.' .format(path)) try: energy = local_context['energy'] except KeyError: raise InputError( 'Required attribute "energy" not found in species file {0!r}.'. format(path)) if isinstance(energy, dict): try: energy = energy[self.modelChemistry] except KeyError: raise InputError( 'Model chemistry {0!r} not found in from dictionary of energy values in species file {1!r}.' .format(self.modelChemistry, path)) if isinstance(energy, GaussianLog): energyLog = energy E0 = None energyLog.path = os.path.join(directory, energyLog.path) elif isinstance(energy, QchemLog): energyLog = energy E0 = None energyLog.path = os.path.join(directory, energyLog.path) elif isinstance(energy, MoleProLog): energyLog = energy E0 = None energyLog.path = os.path.join(directory, energyLog.path) elif isinstance(energy, float): energyLog = None E0 = energy try: geomLog = local_context['geometry'] except KeyError: raise InputError( 'Required attribute "geometry" not found in species file {0!r}.' .format(path)) geomLog.path = os.path.join(directory, geomLog.path) try: statmechLog = local_context['frequencies'] except KeyError: raise InputError( 'Required attribute "frequencies" not found in species file {0!r}.' .format(path)) statmechLog.path = os.path.join(directory, statmechLog.path) if 'frequencyScaleFactor' in local_context: logging.warning( 'Ignoring frequency scale factor in species file {0!r}.'. format(path)) try: rotors = local_context['rotors'] except KeyError: rotors = [] # But don't consider hindered rotors if flag is not set if not self.includeHinderedRotors: rotors = [] logging.debug(' Reading molecular degrees of freedom...') conformer = statmechLog.loadConformer( symmetry=externalSymmetry, spinMultiplicity=spinMultiplicity, opticalIsomers=opticalIsomers) logging.debug(' Reading optimized geometry...') coordinates, number, mass = geomLog.loadGeometry() conformer.coordinates = (coordinates, "angstroms") conformer.number = number conformer.mass = (mass, "amu") logging.debug(' Reading energy...') # The E0 that is read from the log file is without the ZPE and corresponds to E_elec if E0 is None: E0 = energyLog.loadEnergy(self.frequencyScaleFactor) else: E0 = E0 * constants.E_h * constants.Na # Hartree/particle to J/mol E0 = applyEnergyCorrections( E0, self.modelChemistry, atoms, bonds if self.applyBondEnergyCorrections else {}) ZPE = statmechLog.loadZeroPointEnergy() * self.frequencyScaleFactor # The E0_withZPE at this stage contains the ZPE E0_withZPE = E0 + ZPE logging.debug(' Scaling factor used = {0:g}'.format( self.frequencyScaleFactor)) logging.debug(' ZPE (0 K) = {0:g} kcal/mol'.format(ZPE / 4184.)) logging.debug(' E0 (0 K) = {0:g} kcal/mol'.format(E0_withZPE / 4184.)) conformer.E0 = (E0_withZPE * 0.001, "kJ/mol") # If loading a transition state, also read the imaginary frequency if TS: self.species.frequency = (statmechLog.loadNegativeFrequency() * self.frequencyScaleFactor, "cm^-1") # Read and fit the 1D hindered rotors if applicable # If rotors are found, the vibrational frequencies are also # recomputed with the torsional modes removed F = statmechLog.loadForceConstantMatrix() if F is not None and len(mass) > 1 and len(rotors) > 0: logging.debug(' Fitting {0} hindered rotors...'.format( len(rotors))) rotorCount = 0 for scanLog, pivots, top, symmetry, fit in rotors: # Load the hindered rotor scan energies if isinstance(scanLog, GaussianLog): scanLog.path = os.path.join(directory, scanLog.path) Vlist, angle = scanLog.loadScanEnergies() scanLogOutput = ScanLog( os.path.join( directory, '{0}_rotor_{1}.txt'.format(self.species.label, rotorCount + 1))) scanLogOutput.save(angle, Vlist) elif isinstance(scanLog, QchemLog): scanLog.path = os.path.join(directory, scanLog.path) Vlist, angle = scanLog.loadScanEnergies() scanLogOutput = ScanLog( os.path.join( directory, '{0}_rotor_{1}.txt'.format(self.species.label, rotorCount + 1))) scanLogOutput.save(angle, Vlist) elif isinstance(scanLog, ScanLog): scanLog.path = os.path.join(directory, scanLog.path) angle, Vlist = scanLog.load() else: raise Exception( 'Invalid log file type {0} for scan log.'.format( scanLog.__class__)) inertia = conformer.getInternalReducedMomentOfInertia( pivots, top) * constants.Na * 1e23 cosineRotor = HinderedRotor(inertia=(inertia, "amu*angstrom^2"), symmetry=symmetry) cosineRotor.fitCosinePotentialToData(angle, Vlist) fourierRotor = HinderedRotor(inertia=(inertia, "amu*angstrom^2"), symmetry=symmetry) fourierRotor.fitFourierPotentialToData(angle, Vlist) Vlist_cosine = numpy.zeros_like(angle) Vlist_fourier = numpy.zeros_like(angle) for i in range(angle.shape[0]): Vlist_cosine[i] = cosineRotor.getPotential(angle[i]) Vlist_fourier[i] = fourierRotor.getPotential(angle[i]) if fit == 'cosine': rotor = cosineRotor elif fit == 'fourier': rotor = fourierRotor elif fit == 'best': rms_cosine = numpy.sqrt( numpy.sum( (Vlist_cosine - Vlist) * (Vlist_cosine - Vlist)) / (len(Vlist) - 1)) / 4184. rms_fourier = numpy.sqrt( numpy.sum((Vlist_fourier - Vlist) * (Vlist_fourier - Vlist)) / (len(Vlist) - 1)) / 4184. # Keep the rotor with the most accurate potential rotor = cosineRotor if rms_cosine < rms_fourier else fourierRotor # However, keep the cosine rotor if it is accurate enough, the # fourier rotor is not significantly more accurate, and the cosine # rotor has the correct symmetry if rms_cosine < 0.05 and rms_cosine / rms_fourier < 2.0 and rms_cosine / rms_fourier < 4.0 and symmetry == cosineRotor.symmetry: rotor = cosineRotor conformer.modes.append(rotor) self.plotHinderedRotor(angle, Vlist, cosineRotor, fourierRotor, rotor, rotorCount, directory) rotorCount += 1 logging.debug( ' Determining frequencies from reduced force constant matrix...' ) frequencies = numpy.array( projectRotors(conformer, F, rotors, linear, TS)) # The frequencies have changed after projection, hence we need to recompute the ZPE # We might need to multiply the scaling factor to the frequencies ZPE = self.getZPEfromfrequencies(frequencies) E0_withZPE = E0 + ZPE # Reset the E0 of the conformer conformer.E0 = (E0_withZPE * 0.001, "kJ/mol") elif len(conformer.modes) > 2: frequencies = conformer.modes[2].frequencies.value_si rotors = numpy.array([]) else: frequencies = numpy.array([]) rotors = numpy.array([]) for mode in conformer.modes: if isinstance(mode, HarmonicOscillator): mode.frequencies = (frequencies * self.frequencyScaleFactor, "cm^-1") self.species.conformer = conformer
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}, )
class TestHinderedRotor(unittest.TestCase): """ Contains unit tests of the HinderedRotor class. """ def setUp(self): """ A function run before each unit test in this class. """ self.inertia = 1.56764 self.symmetry = 3 self.barrier = 11.373 self.quantum = True self.mode = HinderedRotor( inertia=(self.inertia, "amu*angstrom^2"), symmetry=self.symmetry, barrier=(self.barrier, "kJ/mol"), fourier=([[4.58375, 0.841648, -5702.71, 6.02657, 4.7446], [0.726951, -0.677255, 0.207032, 0.553307, -0.503303]], "J/mol"), quantum=self.quantum, ) self.freemode = FreeRotor( inertia=(self.inertia, "amu*angstrom^2"), symmetry=self.symmetry, ) def test_get_rotational_constant(self): """ Test getting the HinderedRotor.rotationalConstant property. """ b_exp = 10.7535 b_act = self.mode.rotationalConstant.value_si self.assertAlmostEqual(b_exp, b_act, 4) b_act2 = self.freemode.rotationalConstant.value_si self.assertAlmostEqual(b_exp, b_act2, 4) def test_set_rotational_constant(self): """ Test setting the HinderedRotor.rotationalConstant property. """ rotational_constant = self.mode.rotationalConstant rotational_constant.value_si *= 2 self.mode.rotationalConstant = rotational_constant self.freemode.rotationalConstant = rotational_constant i_exp = 0.5 * self.inertia i_act = self.mode.inertia.value_si * constants.Na * 1e23 i_act2 = self.freemode.inertia.value_si * constants.Na * 1e23 self.assertAlmostEqual(i_exp, i_act, 4) self.assertAlmostEqual(i_exp, i_act2, 4) def test_get_potential_cosine(self): """ Test the HinderedRotor.get_potential() method for a cosine potential. """ self.mode.fourier = None phi = np.arange(0.0, 2 * constants.pi + 0.0001, constants.pi / 24.) potential = np.zeros_like(phi) for i in range(phi.shape[0]): potential[i] = self.mode.get_potential(phi[i]) def test_get_potential_fourier(self): """ Test the HinderedRotor.get_potential() method for a Fourier series potential. """ phi = np.arange(0.0, 2 * constants.pi + 0.0001, constants.pi / 24.) potential = np.zeros_like(phi) for i in range(phi.shape[0]): potential[i] = self.mode.get_potential(phi[i]) def test_get_partition_function_free(self): """ Test the FreeRotor.get_partition_function() method """ t_list = np.array([300, 500, 1000, 1500, 2000]) q_exp_list = np.sqrt( 8 * np.pi**3 * constants.kB * t_list * self.freemode.inertia.value_si) / (self.symmetry * constants.h) for temperature, q_exp in zip(t_list, q_exp_list): q_act = self.freemode.get_partition_function(temperature) self.assertAlmostEqual(q_exp, q_act, delta=1e-4 * q_exp) def test_get_partition_function_classical_cosine(self): """ Test the HinderedRotor.get_partition_function() method for a cosine potential in the classical limit. """ self.mode.quantum = False self.mode.fourier = None t_list = np.array([300, 500, 1000, 1500, 2000]) q_exp_list = np.array([0.741953, 1.30465, 2.68553, 3.88146, 4.91235]) for temperature, q_exp in zip(t_list, q_exp_list): q_act = self.mode.get_partition_function(temperature) self.assertAlmostEqual(q_exp, q_act, delta=1e-4 * q_exp) def test_get_partition_function_classical_fourier(self): """ Test the HinderedRotor.get_partition_function() method for a Fourier series potential in the classical limit. """ self.mode.quantum = False t_list = np.array([300, 500, 1000, 1500, 2000]) q_exp_list = np.array([0.745526, 1.30751, 2.68722, 3.88258, 4.91315]) for temperature, q_exp in zip(t_list, q_exp_list): q_act = self.mode.get_partition_function(temperature) self.assertAlmostEqual(q_exp, q_act, delta=1e-4 * q_exp) def test_get_partition_function_quantum_cosine(self): """ Test the HinderedRotor.get_partition_function() method for a cosine potential in the quantum limit. """ self.mode.quantum = True self.mode.fourier = None t_list = np.array([300, 500, 1000, 1500, 2000]) q_exp_list = np.array([1.39947, 1.94793, 3.30171, 4.45856, 5.45188]) for temperature, q_exp in zip(t_list, q_exp_list): q_act = self.mode.get_partition_function(temperature) self.assertAlmostEqual(q_exp, q_act, delta=1e-4 * q_exp) def test_get_partition_function_quantum_fourier(self): """ Test the HinderedRotor.get_partition_function() method for a Fourier series potential in the quantum limit. """ self.mode.quantum = True t_list = np.array([300, 500, 1000, 1500, 2000]) q_exp_list = np.array([1.39364, 1.94182, 3.29509, 4.45205, 5.44563]) for temperature, q_exp in zip(t_list, q_exp_list): q_act = self.mode.get_partition_function(temperature) self.assertAlmostEqual(q_exp, q_act, delta=5e-4 * q_exp) def test_get_heat_capacity_free(self): """ Test the FreeRotor.get_heat_capacity() method """ cv_exp = constants.R / 2.0 t_list = np.array([300, 500, 1000, 1500, 2000]) for temperature in t_list: cv_act = self.freemode.get_heat_capacity(temperature) self.assertAlmostEqual(cv_exp, cv_act, delta=1e-4 * cv_exp) def test_get_heat_capacity_classical_cosine(self): """ Test the HinderedRotor.get_heat_capacity() method using a cosine potential in the classical limit. """ self.mode.quantum = False self.mode.fourier = None t_list = np.array([300, 500, 1000, 1500, 2000]) cv_exp_list = np.array( [1.01741, 0.951141, 0.681919, 0.589263, 0.552028]) * constants.R for temperature, cv_exp in zip(t_list, cv_exp_list): cv_act = self.mode.get_heat_capacity(temperature) self.assertAlmostEqual(cv_exp, cv_act, delta=1e-4 * cv_exp) def test_get_heat_capacity_classical_fourier(self): """ Test the HinderedRotor.get_heat_capacity() method using a Fourier series potential in the classical limit. """ self.mode.quantum = False t_list = np.array([300, 500, 1000, 1500, 2000]) cv_exp_list = np.array( [1.17682, 1.01369, 0.698588, 0.596797, 0.556293]) * constants.R for temperature, cv_exp in zip(t_list, cv_exp_list): cv_act = self.mode.get_heat_capacity(temperature) self.assertAlmostEqual(cv_exp, cv_act, delta=1e-4 * cv_exp) def test_get_heat_capacity_quantum_cosine(self): """ Test the HinderedRotor.get_heat_capacity() method using a cosine potential in the quantum limit. """ self.mode.quantum = True self.mode.fourier = None t_list = np.array([300, 500, 1000, 1500, 2000]) cv_exp_list = np.array( [1.01271, 0.945341, 0.684451, 0.591949, 0.554087]) * constants.R for temperature, cv_exp in zip(t_list, cv_exp_list): cv_act = self.mode.get_heat_capacity(temperature) self.assertAlmostEqual(cv_exp, cv_act, delta=1e-4 * cv_exp) def test_get_heat_capacity_quantum_fourier(self): """ Test the HinderedRotor.get_heat_capacity() method using a Fourier series potential in the quantum limit. """ self.mode.quantum = True t_list = np.array([300, 500, 1000, 1500, 2000]) cv_exp_list = np.array( [1.01263, 0.946618, 0.685345, 0.592427, 0.554374]) * constants.R for temperature, cv_exp in zip(t_list, cv_exp_list): cv_act = self.mode.get_heat_capacity(temperature) self.assertAlmostEqual(cv_exp, cv_act, delta=1e-3 * cv_exp) def test_get_enthalpy_free(self): """ Test the FreeRotor.get_enthalpy() method """ t_list = np.array([300, 500, 1000, 1500, 2000]) h_exp_list = constants.R * t_list / 2.0 for temperature, h_exp in zip(t_list, h_exp_list): h_act = self.freemode.get_enthalpy(temperature) self.assertAlmostEqual(h_exp, h_act, delta=1e-4 * h_exp) def test_get_enthalpy_classical_cosine(self): """ Test the HinderedRotor.get_enthalpy() method using a cosine potential in the classical limit. """ self.mode.quantum = False self.mode.fourier = None t_list = np.array([300, 500, 1000, 1500, 2000]) h_exp_list = np.array([1.09556, 1.09949, 0.962738, 0.854617, 0.784333 ]) * constants.R * t_list for temperature, h_exp in zip(t_list, h_exp_list): h_act = self.mode.get_enthalpy(temperature) self.assertAlmostEqual(h_exp, h_act, delta=1e-4 * h_exp) def test_get_enthalpy_classical_fourier(self): """ Test the HinderedRotor.get_enthalpy() method using a Fourier series potential in the classical limit. """ self.mode.quantum = False t_list = np.array([300, 500, 1000, 1500, 2000]) h_exp_list = np.array([1.08882, 1.09584, 0.961543, 0.854054, 0.784009 ]) * constants.R * t_list for temperature, h_exp in zip(t_list, h_exp_list): h_act = self.mode.get_enthalpy(temperature) self.assertAlmostEqual(h_exp, h_act, delta=1e-4 * h_exp) def test_get_enthalpy_quantum_cosine(self): """ Test the HinderedRotor.get_enthalpy() method using a cosine potential in the quantum limit. """ self.mode.quantum = True self.mode.fourier = None t_list = np.array([300, 500, 1000, 1500, 2000]) h_exp_list = np.array([ 0.545814, 0.727200, 0.760918, 0.717496, 0.680767 ]) * constants.R * t_list for temperature, h_exp in zip(t_list, h_exp_list): h_act = self.mode.get_enthalpy(temperature) self.assertAlmostEqual(h_exp, h_act, delta=1e-4 * h_exp) def test_get_enthalpy_quantum_fourier(self): """ Test the HinderedRotor.get_enthalpy() method using a Fourier series potential in the quantum limit. """ self.mode.quantum = True t_list = np.array([300, 500, 1000, 1500, 2000]) h_exp_list = np.array([ 0.548251, 0.728974, 0.762396, 0.718702, 0.681764 ]) * constants.R * t_list for temperature, h_exp in zip(t_list, h_exp_list): h_act = self.mode.get_enthalpy(temperature) self.assertAlmostEqual(h_exp, h_act, delta=1e-3 * h_exp) def test_get_entropy_free(self): t_list = np.array([300, 500, 1000, 1500, 2000]) pf = np.array([ self.freemode.get_partition_function(temperature) for temperature in t_list ]) s_exp_list = constants.R * (np.log(pf) + .5) for temperature, s_exp in zip(t_list, s_exp_list): s_act = self.freemode.get_entropy(temperature) self.assertAlmostEqual(s_exp, s_act, delta=1e-4 * s_exp) def test_get_entropy_classical_cosine(self): """ Test the HinderedRotor.get_entropy() method using a cosine potential in the classical limit. """ self.mode.quantum = False self.mode.fourier = None t_list = np.array([300, 500, 1000, 1500, 2000]) s_exp_list = np.array([0.797089, 1.36543, 1.95062, 2.21083, 2.37608 ]) * constants.R for temperature, s_exp in zip(t_list, s_exp_list): s_act = self.mode.get_entropy(temperature) self.assertAlmostEqual(s_exp, s_act, delta=1e-4 * s_exp) def test_get_entropy_classical_fourier(self): """ Test the HinderedRotor.get_entropy() method using a Fourier series potential in the classical limit. """ self.mode.quantum = False t_list = np.array([300, 500, 1000, 1500, 2000]) s_exp_list = np.array([0.795154, 1.36396, 1.95005, 2.21055, 2.37592 ]) * constants.R for temperature, s_exp in zip(t_list, s_exp_list): s_act = self.mode.get_entropy(temperature) self.assertAlmostEqual(s_exp, s_act, delta=1e-4 * s_exp) def test_get_entropy_quantum_cosine(self): """ Test the HinderedRotor.get_entropy() method using a cosine potential in the quantum limit. """ self.mode.quantum = True self.mode.fourier = None t_list = np.array([300, 500, 1000, 1500, 2000]) s_exp_list = np.array([0.881906, 1.39397, 1.95536, 2.21232, 2.37673 ]) * constants.R for temperature, s_exp in zip(t_list, s_exp_list): s_act = self.mode.get_entropy(temperature) self.assertAlmostEqual(s_exp, s_act, delta=1e-4 * s_exp) def test_get_entropy_quantum_fourier(self): """ Test the HinderedRotor.get_entropy() method using a Fourier series potential in the quantum limit. """ self.mode.quantum = True t_list = np.array([300, 500, 1000, 1500, 2000]) s_exp_list = np.array([0.880170, 1.39260, 1.95483, 2.21207, 2.37658 ]) * constants.R for temperature, s_exp in zip(t_list, s_exp_list): s_act = self.mode.get_entropy(temperature) self.assertAlmostEqual(s_exp, s_act, delta=1e-3 * s_exp) def test_get_sum_of_states_classical_cosine(self): """ Test the HinderedRotor.get_sum_of_states() method using a cosine potential in the classical limit. """ self.mode.quantum = False self.mode.fourier = None e_list = np.arange(0, 10000 * 11.96, 1 * 11.96) sum_states = self.mode.get_sum_of_states(e_list) dens_states = self.mode.get_density_of_states(e_list) for n in range(10, len(e_list)): self.assertTrue( 0.8 < np.sum(dens_states[0:n]) / sum_states[n - 1] < 1.25, '{0} != {1}'.format(np.sum(dens_states[0:n]), sum_states[n])) def test_get_sum_of_states_classical_fourier(self): """ Test the HinderedRotor.get_sum_of_states() method using a Fourier series potential in the classical limit. """ self.mode.quantum = False e_list = np.arange(0, 10000 * 11.96, 1 * 11.96) try: sum_states = self.mode.get_sum_of_states(e_list) self.fail( 'NotImplementedError not raised by HinderedRotor.get_sum_of_states()' ) except NotImplementedError: pass def test_get_sum_of_states_quantum_cosine(self): """ Test the HinderedRotor.get_sum_of_states() method using a cosine potential in the quantum limit. """ self.mode.quantum = True self.mode.fourier = None e_list = np.arange(0, 10000 * 11.96, 1 * 11.96) sum_states = self.mode.get_sum_of_states(e_list) dens_states = self.mode.get_density_of_states(e_list) for n in range(10, len(e_list)): self.assertTrue( 0.8 < np.sum(dens_states[0:n]) / sum_states[n - 1] < 1.25, '{0} != {1}'.format(np.sum(dens_states[0:n]), sum_states[n])) def test_get_sum_of_states_quantum_fourier(self): """ Test the HinderedRotor.get_sum_of_states() method using a Fourier series potential in the quantum limit. """ self.mode.quantum = True e_list = np.arange(0, 10000 * 11.96, 1 * 11.96) sum_states = self.mode.get_sum_of_states(e_list) dens_states = self.mode.get_density_of_states(e_list) for n in range(10, len(e_list)): self.assertTrue( 0.8 < np.sum(dens_states[0:n]) / sum_states[n - 1] < 1.25, '{0} != {1}'.format(np.sum(dens_states[0:n]), sum_states[n])) def test_get_density_of_states_classical_cosine(self): """ Test the HinderedRotor.get_density_of_states() method using a classical potential in the classical limit. """ self.mode.quantum = False self.mode.fourier = None e_list = np.arange(0, 10000 * 11.96, 1 * 11.96) dens_states = self.mode.get_density_of_states(e_list) temperature = 100 q_act = np.sum(dens_states * np.exp(-e_list / constants.R / temperature)) q_exp = self.mode.get_partition_function(temperature) self.assertAlmostEqual(q_exp, q_act, delta=1e-2 * q_exp) def test_get_density_of_states_classical_fourier(self): """ Test the HinderedRotor.get_density_of_states() method using a Fourier series potential in the classical limit. """ self.mode.quantum = False e_list = np.arange(0, 10000 * 11.96, 1 * 11.96) try: dens_states = self.mode.get_density_of_states(e_list) self.fail( 'NotImplementedError not raised by HinderedRotor.get_density_of_states()' ) except NotImplementedError: pass def test_get_density_of_states_quantum_cosine(self): """ Test the HinderedRotor.get_density_of_states() method using a classical potential in the quantum limit. """ self.mode.quantum = True self.mode.fourier = None e_list = np.arange(0, 10000 * 11.96, 1 * 11.96) dens_states = self.mode.get_density_of_states(e_list) temperature = 100 q_act = np.sum(dens_states * np.exp(-e_list / constants.R / temperature)) q_exp = self.mode.get_partition_function(temperature) self.assertAlmostEqual(q_exp, q_act, delta=1e-2 * q_exp) def test_get_density_of_states_quantum_fourier(self): """ Test the HinderedRotor.get_density_of_states() method using a Fourier series potential in the quantum limit. """ self.mode.quantum = True e_list = np.arange(0, 10000 * 11.96, 1 * 11.96) dens_states = self.mode.get_density_of_states(e_list) temperature = 100 q_act = np.sum(dens_states * np.exp(-e_list / constants.R / temperature)) q_exp = self.mode.get_partition_function(temperature) self.assertAlmostEqual(q_exp, q_act, delta=1e-2 * q_exp) def test_repr(self): """ Test that a HinderedRotor object can be reconstructed from its repr() output with no loss of information. """ namespace = {} exec('mode = {0!r}'.format(self.mode), globals(), namespace) self.assertIn('mode', namespace) mode = namespace['mode'] self.assertAlmostEqual(self.mode.inertia.value, mode.inertia.value, 6) self.assertEqual(self.mode.inertia.units, mode.inertia.units, 6) self.assertEqual(self.mode.fourier.value.shape, mode.fourier.value.shape) for A0, A in zip(self.mode.fourier.value.flat, mode.fourier.value.flat): self.assertAlmostEqual(A0 / A, 1.0, 6) self.assertEqual(self.mode.fourier.units, mode.fourier.units) self.assertAlmostEqual(self.mode.barrier.value, mode.barrier.value, 6) self.assertEqual(self.mode.barrier.units, mode.barrier.units) self.assertEqual(self.mode.symmetry, mode.symmetry) self.assertEqual(self.mode.quantum, mode.quantum) def test_pickle(self): """ Test that a HinderedRotor object can be pickled and unpickled with no loss of information. """ import pickle mode = pickle.loads(pickle.dumps(self.mode, -1)) self.assertAlmostEqual(self.mode.inertia.value, mode.inertia.value, 6) self.assertEqual(self.mode.inertia.units, mode.inertia.units, 6) self.assertEqual(self.mode.fourier.value.shape, mode.fourier.value.shape) for A0, A in zip(self.mode.fourier.value.flat, mode.fourier.value.flat): self.assertAlmostEqual(A0 / A, 1.0, 6) self.assertEqual(self.mode.fourier.units, mode.fourier.units) self.assertAlmostEqual(self.mode.barrier.value, mode.barrier.value, 6) self.assertEqual(self.mode.barrier.units, mode.barrier.units) self.assertEqual(self.mode.symmetry, mode.symmetry) self.assertEqual(self.mode.quantum, mode.quantum)
class TestHinderedRotor(unittest.TestCase): """ Contains unit tests of the HinderedRotor class. """ def setUp(self): """ A function run before each unit test in this class. """ self.inertia = 1.56764 self.symmetry = 3 self.barrier = 11.373 self.quantum = True self.mode = HinderedRotor( inertia = (self.inertia,"amu*angstrom^2"), symmetry = self.symmetry, barrier = (self.barrier,"kJ/mol"), fourier = ([ [4.58375, 0.841648, -5702.71, 6.02657, 4.7446], [0.726951, -0.677255, 0.207032, 0.553307, -0.503303] ],"J/mol"), quantum = self.quantum, ) self.freemode = FreeRotor( inertia = (self.inertia,"amu*angstrom^2"), symmetry = self.symmetry, ) def test_getRotationalConstant(self): """ Test getting the HinderedRotor.rotationalConstant property. """ Bexp = 10.7535 Bact = self.mode.rotationalConstant.value_si self.assertAlmostEqual(Bexp, Bact, 4) Bact2 = self.freemode.rotationalConstant.value_si self.assertAlmostEqual(Bexp,Bact2,4) def test_setRotationalConstant(self): """ Test setting the HinderedRotor.rotationalConstant property. """ B = self.mode.rotationalConstant B.value_si *= 2 self.mode.rotationalConstant = B self.freemode.rotationalConstant = B Iexp = 0.5 * self.inertia Iact = self.mode.inertia.value_si * constants.Na * 1e23 Iact2 = self.freemode.inertia.value_si * constants.Na * 1e23 self.assertAlmostEqual(Iexp, Iact, 4) self.assertAlmostEqual(Iexp, Iact2, 4) def test_getPotential_cosine(self): """ Test the HinderedRotor.getPotential() method for a cosine potential. """ self.mode.fourier = None phi = numpy.arange(0.0, 2 * constants.pi + 0.0001, constants.pi / 24.) V = numpy.zeros_like(phi) for i in range(phi.shape[0]): V[i] = self.mode.getPotential(phi[i]) def test_getPotential_fourier(self): """ Test the HinderedRotor.getPotential() method for a Fourier series potential. """ phi = numpy.arange(0.0, 2 * constants.pi + 0.0001, constants.pi / 24.) V = numpy.zeros_like(phi) for i in range(phi.shape[0]): V[i] = self.mode.getPotential(phi[i]) def test_getPartitionFunction_free(self): """ Test the FreeRotor.getPartitionFunction() method """ Tlist = numpy.array([300,500,1000,1500,2000]) Qexplist = numpy.sqrt(8*numpy.pi**3*constants.kB*Tlist*self.freemode.inertia.value_si)/(self.symmetry*constants.h) for T, Qexp in zip(Tlist,Qexplist): Qact = self.freemode.getPartitionFunction(T) self.assertAlmostEqual(Qexp,Qact,delta=1e-4*Qexp) def test_getPartitionFunction_classical_cosine(self): """ Test the HinderedRotor.getPartitionFunction() method for a cosine potential in the classical limit. """ self.mode.quantum = False self.mode.fourier = None Tlist = numpy.array([300,500,1000,1500,2000]) Qexplist = numpy.array([0.741953, 1.30465, 2.68553, 3.88146, 4.91235]) for T, Qexp in zip(Tlist, Qexplist): Qact = self.mode.getPartitionFunction(T) self.assertAlmostEqual(Qexp, Qact, delta=1e-4*Qexp) def test_getPartitionFunction_classical_fourier(self): """ Test the HinderedRotor.getPartitionFunction() method for a Fourier series potential in the classical limit. """ self.mode.quantum = False Tlist = numpy.array([300,500,1000,1500,2000]) Qexplist = numpy.array([0.745526, 1.30751, 2.68722, 3.88258, 4.91315]) for T, Qexp in zip(Tlist, Qexplist): Qact = self.mode.getPartitionFunction(T) self.assertAlmostEqual(Qexp, Qact, delta=1e-4*Qexp) def test_getPartitionFunction_quantum_cosine(self): """ Test the HinderedRotor.getPartitionFunction() method for a cosine potential in the quantum limit. """ self.mode.quantum = True self.mode.fourier = None Tlist = numpy.array([300,500,1000,1500,2000]) Qexplist = numpy.array([1.39947, 1.94793, 3.30171, 4.45856, 5.45188]) for T, Qexp in zip(Tlist, Qexplist): Qact = self.mode.getPartitionFunction(T) self.assertAlmostEqual(Qexp, Qact, delta=1e-4*Qexp) def test_getPartitionFunction_quantum_fourier(self): """ Test the HinderedRotor.getPartitionFunction() method for a Fourier series potential in the quantum limit. """ self.mode.quantum = True Tlist = numpy.array([300,500,1000,1500,2000]) Qexplist = numpy.array([1.39364, 1.94182, 3.29509, 4.45205, 5.44563]) for T, Qexp in zip(Tlist, Qexplist): Qact = self.mode.getPartitionFunction(T) self.assertAlmostEqual(Qexp, Qact, delta=5e-4*Qexp) def test_getHeatCapacity_free(self): """ Test the FreeRotor.getHeatCapacity() method """ Cvexp = constants.R/2.0 Tlist = numpy.array([300,500,1000,1500,2000]) for T in Tlist: Cvact = self.freemode.getHeatCapacity(T) self.assertAlmostEqual(Cvexp,Cvact,delta=1e-4*Cvexp) def test_getHeatCapacity_classical_cosine(self): """ Test the HinderedRotor.getHeatCapacity() method using a cosine potential in the classical limit. """ self.mode.quantum = False self.mode.fourier = None Tlist = numpy.array([300,500,1000,1500,2000]) Cvexplist = numpy.array([1.01741, 0.951141, 0.681919, 0.589263, 0.552028]) * constants.R for T, Cvexp in zip(Tlist, Cvexplist): Cvact = self.mode.getHeatCapacity(T) self.assertAlmostEqual(Cvexp, Cvact, delta=1e-4*Cvexp) def test_getHeatCapacity_classical_fourier(self): """ Test the HinderedRotor.getHeatCapacity() method using a Fourier series potential in the classical limit. """ self.mode.quantum = False Tlist = numpy.array([300,500,1000,1500,2000]) Cvexplist = numpy.array([1.17682, 1.01369, 0.698588, 0.596797, 0.556293]) * constants.R for T, Cvexp in zip(Tlist, Cvexplist): Cvact = self.mode.getHeatCapacity(T) self.assertAlmostEqual(Cvexp, Cvact, delta=1e-4*Cvexp) def test_getHeatCapacity_quantum_cosine(self): """ Test the HinderedRotor.getHeatCapacity() method using a cosine potential in the quantum limit. """ self.mode.quantum = True self.mode.fourier = None Tlist = numpy.array([300,500,1000,1500,2000]) Cvexplist = numpy.array([1.01271, 0.945341, 0.684451, 0.591949, 0.554087]) * constants.R for T, Cvexp in zip(Tlist, Cvexplist): Cvact = self.mode.getHeatCapacity(T) self.assertAlmostEqual(Cvexp, Cvact, delta=1e-4*Cvexp) def test_getHeatCapacity_quantum_fourier(self): """ Test the HinderedRotor.getHeatCapacity() method using a Fourier series potential in the quantum limit. """ self.mode.quantum = True Tlist = numpy.array([300,500,1000,1500,2000]) Cvexplist = numpy.array([1.01263, 0.946618, 0.685345, 0.592427, 0.554374]) * constants.R for T, Cvexp in zip(Tlist, Cvexplist): Cvact = self.mode.getHeatCapacity(T) self.assertAlmostEqual(Cvexp, Cvact, delta=1e-3*Cvexp) def test_getEnthalpy_free(self): """ Test the FreeRotor.getEnthalpy() method """ Tlist = numpy.array([300,500,1000,1500,2000]) Hexplist = constants.R*Tlist/2.0 for T, Hexp in zip(Tlist, Hexplist): Hact = self.freemode.getEnthalpy(T) self.assertAlmostEqual(Hexp, Hact, delta=1e-4*Hexp) def test_getEnthalpy_classical_cosine(self): """ Test the HinderedRotor.getEnthalpy() method using a cosine potential in the classical limit. """ self.mode.quantum = False self.mode.fourier = None Tlist = numpy.array([300,500,1000,1500,2000]) Hexplist = numpy.array([1.09556, 1.09949, 0.962738, 0.854617, 0.784333]) * constants.R * Tlist for T, Hexp in zip(Tlist, Hexplist): Hact = self.mode.getEnthalpy(T) self.assertAlmostEqual(Hexp, Hact, delta=1e-4*Hexp) def test_getEnthalpy_classical_fourier(self): """ Test the HinderedRotor.getEnthalpy() method using a Fourier series potential in the classical limit. """ self.mode.quantum = False Tlist = numpy.array([300,500,1000,1500,2000]) Hexplist = numpy.array([1.08882, 1.09584, 0.961543, 0.854054, 0.784009]) * constants.R * Tlist for T, Hexp in zip(Tlist, Hexplist): Hact = self.mode.getEnthalpy(T) self.assertAlmostEqual(Hexp, Hact, delta=1e-4*Hexp) def test_getEnthalpy_quantum_cosine(self): """ Test the HinderedRotor.getEnthalpy() method using a cosine potential in the quantum limit. """ self.mode.quantum = True self.mode.fourier = None Tlist = numpy.array([300,500,1000,1500,2000]) Hexplist = numpy.array([0.545814, 0.727200, 0.760918, 0.717496, 0.680767]) * constants.R * Tlist for T, Hexp in zip(Tlist, Hexplist): Hact = self.mode.getEnthalpy(T) self.assertAlmostEqual(Hexp, Hact, delta=1e-4*Hexp) def test_getEnthalpy_quantum_fourier(self): """ Test the HinderedRotor.getEnthalpy() method using a Fourier series potential in the quantum limit. """ self.mode.quantum = True Tlist = numpy.array([300,500,1000,1500,2000]) Hexplist = numpy.array([0.548251, 0.728974, 0.762396, 0.718702, 0.681764]) * constants.R * Tlist for T, Hexp in zip(Tlist, Hexplist): Hact = self.mode.getEnthalpy(T) self.assertAlmostEqual(Hexp, Hact, delta=1e-3*Hexp) def test_getEntropy_free(self): Tlist = numpy.array([300,500,1000,1500,2000]) Q = numpy.array([self.freemode.getPartitionFunction(T) for T in Tlist]) Sexplist = constants.R*(numpy.log(Q)+.5) for T, Sexp in zip(Tlist, Sexplist): Sact = self.freemode.getEntropy(T) self.assertAlmostEqual(Sexp, Sact, delta=1e-4*Sexp) def test_getEntropy_classical_cosine(self): """ Test the HinderedRotor.getEntropy() method using a cosine potential in the classical limit. """ self.mode.quantum = False self.mode.fourier = None Tlist = numpy.array([300,500,1000,1500,2000]) Sexplist = numpy.array([0.797089, 1.36543, 1.95062, 2.21083, 2.37608]) * constants.R for T, Sexp in zip(Tlist, Sexplist): Sact = self.mode.getEntropy(T) self.assertAlmostEqual(Sexp, Sact, delta=1e-4*Sexp) def test_getEntropy_classical_fourier(self): """ Test the HinderedRotor.getEntropy() method using a Fourier series potential in the classical limit. """ self.mode.quantum = False Tlist = numpy.array([300,500,1000,1500,2000]) Sexplist = numpy.array([0.795154, 1.36396, 1.95005, 2.21055, 2.37592]) * constants.R for T, Sexp in zip(Tlist, Sexplist): Sact = self.mode.getEntropy(T) self.assertAlmostEqual(Sexp, Sact, delta=1e-4*Sexp) def test_getEntropy_quantum_cosine(self): """ Test the HinderedRotor.getEntropy() method using a cosine potential in the quantum limit. """ self.mode.quantum = True self.mode.fourier = None Tlist = numpy.array([300,500,1000,1500,2000]) Sexplist = numpy.array([0.881906, 1.39397, 1.95536, 2.21232, 2.37673]) * constants.R for T, Sexp in zip(Tlist, Sexplist): Sact = self.mode.getEntropy(T) self.assertAlmostEqual(Sexp, Sact, delta=1e-4*Sexp) def test_getEntropy_quantum_fourier(self): """ Test the HinderedRotor.getEntropy() method using a Fourier series potential in the quantum limit. """ self.mode.quantum = True Tlist = numpy.array([300,500,1000,1500,2000]) Sexplist = numpy.array([0.880170, 1.39260, 1.95483, 2.21207, 2.37658]) * constants.R for T, Sexp in zip(Tlist, Sexplist): Sact = self.mode.getEntropy(T) self.assertAlmostEqual(Sexp, Sact, delta=1e-3*Sexp) def test_getSumOfStates_classical_cosine(self): """ Test the HinderedRotor.getSumOfStates() method using a cosine potential in the classical limit. """ self.mode.quantum = False self.mode.fourier = None Elist = numpy.arange(0, 10000*11.96, 1*11.96) sumStates = self.mode.getSumOfStates(Elist) densStates = self.mode.getDensityOfStates(Elist) for n in range(10, len(Elist)): self.assertTrue(0.8 < numpy.sum(densStates[0:n]) / sumStates[n-1] < 1.25, '{0} != {1}'.format(numpy.sum(densStates[0:n]), sumStates[n])) def test_getSumOfStates_classical_fourier(self): """ Test the HinderedRotor.getSumOfStates() method using a Fourier series potential in the classical limit. """ self.mode.quantum = False Elist = numpy.arange(0, 10000*11.96, 1*11.96) try: sumStates = self.mode.getSumOfStates(Elist) self.fail('NotImplementedError not raised by HinderedRotor.getSumOfStates()') except NotImplementedError: pass def test_getSumOfStates_quantum_cosine(self): """ Test the HinderedRotor.getSumOfStates() method using a cosine potential in the quantum limit. """ self.mode.quantum = True self.mode.fourier = None Elist = numpy.arange(0, 10000*11.96, 1*11.96) sumStates = self.mode.getSumOfStates(Elist) densStates = self.mode.getDensityOfStates(Elist) for n in range(10, len(Elist)): self.assertTrue(0.8 < numpy.sum(densStates[0:n]) / sumStates[n-1] < 1.25, '{0} != {1}'.format(numpy.sum(densStates[0:n]), sumStates[n])) def test_getSumOfStates_quantum_fourier(self): """ Test the HinderedRotor.getSumOfStates() method using a Fourier series potential in the quantum limit. """ self.mode.quantum = True Elist = numpy.arange(0, 10000*11.96, 1*11.96) sumStates = self.mode.getSumOfStates(Elist) densStates = self.mode.getDensityOfStates(Elist) for n in range(10, len(Elist)): self.assertTrue(0.8 < numpy.sum(densStates[0:n]) / sumStates[n-1] < 1.25, '{0} != {1}'.format(numpy.sum(densStates[0:n]), sumStates[n])) def test_getDensityOfStates_classical_cosine(self): """ Test the HinderedRotor.getDensityOfStates() method using a classical potential in the classical limit. """ self.mode.quantum = False self.mode.fourier = None Elist = numpy.arange(0, 10000*11.96, 1*11.96) densStates = self.mode.getDensityOfStates(Elist) T = 100 Qact = numpy.sum(densStates * numpy.exp(-Elist / constants.R / T)) Qexp = self.mode.getPartitionFunction(T) self.assertAlmostEqual(Qexp, Qact, delta=1e-2*Qexp) def test_getDensityOfStates_classical_fourier(self): """ Test the HinderedRotor.getDensityOfStates() method using a Fourier series potential in the classical limit. """ self.mode.quantum = False Elist = numpy.arange(0, 10000*11.96, 1*11.96) try: densStates = self.mode.getDensityOfStates(Elist) self.fail('NotImplementedError not raised by HinderedRotor.getDensityOfStates()') except NotImplementedError: pass def test_getDensityOfStates_quantum_cosine(self): """ Test the HinderedRotor.getDensityOfStates() method using a classical potential in the quantum limit. """ self.mode.quantum = True self.mode.fourier = None Elist = numpy.arange(0, 10000*11.96, 1*11.96) densStates = self.mode.getDensityOfStates(Elist) T = 100 Qact = numpy.sum(densStates * numpy.exp(-Elist / constants.R / T)) Qexp = self.mode.getPartitionFunction(T) self.assertAlmostEqual(Qexp, Qact, delta=1e-2*Qexp) def test_getDensityOfStates_quantum_fourier(self): """ Test the HinderedRotor.getDensityOfStates() method using a Fourier series potential in the quantum limit. """ self.mode.quantum = True Elist = numpy.arange(0, 10000*11.96, 1*11.96) densStates = self.mode.getDensityOfStates(Elist) T = 100 Qact = numpy.sum(densStates * numpy.exp(-Elist / constants.R / T)) Qexp = self.mode.getPartitionFunction(T) self.assertAlmostEqual(Qexp, Qact, delta=1e-2*Qexp) def test_repr(self): """ Test that a HinderedRotor object can be reconstructed from its repr() output with no loss of information. """ mode = None exec('mode = {0!r}'.format(self.mode)) self.assertAlmostEqual(self.mode.inertia.value, mode.inertia.value, 6) self.assertEqual(self.mode.inertia.units, mode.inertia.units, 6) self.assertEqual(self.mode.fourier.value.shape, mode.fourier.value.shape) for A0, A in zip(self.mode.fourier.value.flat, mode.fourier.value.flat): self.assertAlmostEqual(A0 / A, 1.0, 6) self.assertEqual(self.mode.fourier.units, mode.fourier.units) self.assertAlmostEqual(self.mode.barrier.value, mode.barrier.value, 6) self.assertEqual(self.mode.barrier.units, mode.barrier.units) self.assertEqual(self.mode.symmetry, mode.symmetry) self.assertEqual(self.mode.quantum, mode.quantum) def test_pickle(self): """ Test that a HinderedRotor object can be pickled and unpickled with no loss of information. """ import cPickle mode = cPickle.loads(cPickle.dumps(self.mode,-1)) self.assertAlmostEqual(self.mode.inertia.value, mode.inertia.value, 6) self.assertEqual(self.mode.inertia.units, mode.inertia.units, 6) self.assertEqual(self.mode.fourier.value.shape, mode.fourier.value.shape) for A0, A in zip(self.mode.fourier.value.flat, mode.fourier.value.flat): self.assertAlmostEqual(A0 / A, 1.0, 6) self.assertEqual(self.mode.fourier.units, mode.fourier.units) self.assertAlmostEqual(self.mode.barrier.value, mode.barrier.value, 6) self.assertEqual(self.mode.barrier.units, mode.barrier.units) self.assertEqual(self.mode.symmetry, mode.symmetry) self.assertEqual(self.mode.quantum, mode.quantum)
inertia=(inertia, "amu*angstrom^2"), symmetry=symmetry, ) Q = mode.get_partition_function(T) print('FreeRotor') print('1/Q: %.2f' % (1 / Q)) print('V/RT: %.1f' % (0)) entropy = mode.get_entropy(T) print('S: %.3f' % (entropy / 4.184)) print('') ############################################################################ barrier = 16 * (constants.R * T) / 1000 mode = HinderedRotor( inertia=(inertia, "amu*angstrom^2"), symmetry=symmetry, barrier=(barrier, "kJ/mol"), quantum=True, ) print('HinderedRotor') phi = np.arange(0.0, 2 * constants.pi + 0.0001, constants.pi / 18.) potential = np.zeros_like(phi) for i in range(phi.shape[0]): potential[i] = mode.get_potential(phi[i]) / (constants.Na * constants.E_h) #print(potential[i]) freq = mode.get_frequency() # in cm-1 #print(freq) print('1/Q: %.2f' % (1 / Q)) print('V/RT: %.1f' % (barrier / ((constants.R * T) / 1000))) k = (freq * (2 * np.pi * constants.c * 100))**2 # in 1/s^2 #print('M: ',inertia) #print('K: ',k)
def setUp(self): """ A method that is called prior to each unit test in this class. """ ethylene = Species( label='C2H4', conformer=Conformer( E0=(44.7127, 'kJ/mol'), modes=[ IdealGasTranslation(mass=(28.0313, 'amu'), ), NonlinearRotor( inertia=( [3.41526, 16.6498, 20.065], 'amu*angstrom^2', ), symmetry=4, ), HarmonicOscillator(frequencies=( [ 828.397, 970.652, 977.223, 1052.93, 1233.55, 1367.56, 1465.09, 1672.25, 3098.46, 3111.7, 3165.79, 3193.54 ], 'cm^-1', ), ), ], spinMultiplicity=1, opticalIsomers=1, ), ) hydrogen = Species( label='H', conformer=Conformer( E0=(211.794, 'kJ/mol'), modes=[ IdealGasTranslation(mass=(1.00783, 'amu'), ), ], spinMultiplicity=2, opticalIsomers=1, ), ) ethyl = Species( label='C2H5', conformer=Conformer( E0=(111.603, 'kJ/mol'), modes=[ IdealGasTranslation(mass=(29.0391, 'amu'), ), NonlinearRotor( inertia=( [4.8709, 22.2353, 23.9925], 'amu*angstrom^2', ), symmetry=1, ), HarmonicOscillator(frequencies=( [ 482.224, 791.876, 974.355, 1051.48, 1183.21, 1361.36, 1448.65, 1455.07, 1465.48, 2688.22, 2954.51, 3033.39, 3101.54, 3204.73 ], 'cm^-1', ), ), HinderedRotor( inertia=(1.11481, 'amu*angstrom^2'), symmetry=6, barrier=(0.244029, 'kJ/mol'), semiclassical=None, ), ], spinMultiplicity=2, opticalIsomers=1, ), ) TS = TransitionState( label='TS', conformer=Conformer( E0=(266.694, 'kJ/mol'), modes=[ IdealGasTranslation(mass=(29.0391, 'amu'), ), NonlinearRotor( inertia=( [6.78512, 22.1437, 22.2114], 'amu*angstrom^2', ), symmetry=1, ), HarmonicOscillator(frequencies=( [ 412.75, 415.206, 821.495, 924.44, 982.714, 1024.16, 1224.21, 1326.36, 1455.06, 1600.35, 3101.46, 3110.55, 3175.34, 3201.88 ], 'cm^-1', ), ), ], spinMultiplicity=2, opticalIsomers=1, ), frequency=(-750.232, 'cm^-1'), ) self.reaction = Reaction( reactants=[hydrogen, ethylene], products=[ethyl], kinetics=Arrhenius( A=(501366000.0, 'cm^3/(mol*s)'), n=1.637, Ea=(4.32508, 'kJ/mol'), T0=(1, 'K'), Tmin=(300, 'K'), Tmax=(2500, 'K'), ), transitionState=TS, ) # CC(=O)O[O] acetylperoxy = Species( label='acetylperoxy', thermo=Wilhoit(Cp0=(4.0 * constants.R, "J/(mol*K)"), CpInf=(21.0 * constants.R, "J/(mol*K)"), a0=-3.95, a1=9.26, a2=-15.6, a3=8.55, B=(500.0, "K"), H0=(-6.151e+04, "J/mol"), S0=(-790.2, "J/(mol*K)")), ) # C[C]=O acetyl = Species( label='acetyl', thermo=Wilhoit(Cp0=(4.0 * constants.R, "J/(mol*K)"), CpInf=(15.5 * constants.R, "J/(mol*K)"), a0=0.2541, a1=-0.4712, a2=-4.434, a3=2.25, B=(500.0, "K"), H0=(-1.439e+05, "J/mol"), S0=(-524.6, "J/(mol*K)")), ) # [O][O] oxygen = Species( label='oxygen', thermo=Wilhoit(Cp0=(3.5 * constants.R, "J/(mol*K)"), CpInf=(4.5 * constants.R, "J/(mol*K)"), a0=-0.9324, a1=26.18, a2=-70.47, a3=44.12, B=(500.0, "K"), H0=(1.453e+04, "J/mol"), S0=(-12.19, "J/(mol*K)")), ) self.reaction2 = Reaction( reactants=[acetyl, oxygen], products=[acetylperoxy], kinetics=Arrhenius( A=(2.65e12, 'cm^3/(mol*s)'), n=0.0, Ea=(0.0, 'kJ/mol'), T0=(1, 'K'), Tmin=(300, 'K'), Tmax=(2000, 'K'), ), )