Exemplo n.º 1
0
    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")),
            ],
            spin_multiplicity=1,
            optical_isomers=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")),
            ],
            spin_multiplicity=3,
            optical_isomers=1,
        )

        # The following data is for ethane at the CBS-QB3 level
        self.coordinates = np.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 = np.array([6, 1, 1, 1, 6, 1, 1, 1])
        self.mass = np.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),
            ],
            spin_multiplicity=1,
            optical_isomers=1,
            coordinates=(self.coordinates, "angstrom"),
            number=self.number,
            mass=(self.mass, "amu"),
        )
Exemplo n.º 2
0
    def load_conformer(self, symmetry=None, spin_multiplicity=0, optical_isomers=None, label=''):
        """
        Load the molecular degree of freedom data from a log file created as
        the result of a Gaussian "Freq" quantum chemistry calculation. As
        Gaussian's guess of the external symmetry number is not always correct,
        you can use the `symmetry` parameter to substitute your own value; if
        not provided, the value in the Gaussian log file will be adopted. In a
        log file with multiple Thermochemistry sections, only the last one will
        be kept.
        """
        modes = []
        unscaled_frequencies = []
        e0 = 0.0
        if optical_isomers is None or symmetry is None:
            _optical_isomers, _symmetry, _ = self.get_symmetry_properties()
            if optical_isomers is None:
                optical_isomers = _optical_isomers
            if symmetry is None:
                symmetry = _symmetry
        with open(self.path, 'r') as f:
            line = f.readline()
            while line != '':

                # Read the spin multiplicity if not explicitly given
                if spin_multiplicity == 0 and 'Multiplicity =' in line:
                    spin_multiplicity = int(line.split()[-1])
                    logging.debug('Conformer {0} is assigned a spin multiplicity of {1}'
                                  .format(label, spin_multiplicity))

                # The data we want is in the Thermochemistry section of the output
                if '- Thermochemistry -' in line:
                    modes = []
                    in_partition_functions = False
                    line = f.readline()
                    while line != '':

                        # This marks the end of the thermochemistry section
                        if '-------------------------------------------------------------------' in line:
                            break

                        # Read molecular mass for external translational modes
                        elif 'Molecular mass:' in line:
                            mass = float(line.split()[2])
                            translation = IdealGasTranslation(mass=(mass, "amu"))
                            modes.append(translation)

                        # Read moments of inertia for external rotational modes
                        elif 'Rotational constants (GHZ):' in line:
                            inertia = [float(d) for d in line.split()[-3:]]
                            for i in range(3):
                                inertia[i] = constants.h / (8 * constants.pi * constants.pi * inertia[i] * 1e9) \
                                             * constants.Na * 1e23
                            rotation = NonlinearRotor(inertia=(inertia, "amu*angstrom^2"), symmetry=symmetry)
                            modes.append(rotation)
                        elif 'Rotational constant (GHZ):' in line:
                            inertia = [float(line.split()[3])]
                            inertia[0] = constants.h / (8 * constants.pi * constants.pi * inertia[0] * 1e9) \
                                         * constants.Na * 1e23
                            rotation = LinearRotor(inertia=(inertia[0], "amu*angstrom^2"), symmetry=symmetry)
                            modes.append(rotation)

                        # Read vibrational modes
                        elif 'Vibrational temperatures:' in line:
                            frequencies = []
                            frequencies.extend([float(d) for d in line.split()[2:]])
                            line = f.readline()
                            frequencies.extend([float(d) for d in line.split()[1:]])
                            line = f.readline()
                            while line.strip() != '':
                                frequencies.extend([float(d) for d in line.split()])
                                line = f.readline()
                            # Convert from K to cm^-1
                            if len(frequencies) > 0:
                                frequencies = [freq * 0.695039 for freq in frequencies]  # kB = 0.695039 cm^-1/K
                                unscaled_frequencies = frequencies
                                vibration = HarmonicOscillator(frequencies=(frequencies, "cm^-1"))
                                modes.append(vibration)

                        # Read ground-state energy
                        elif 'Sum of electronic and zero-point Energies=' in line:
                            e0 = float(line.split()[6]) * 4.35974394e-18 * constants.Na

                        # Read spin multiplicity if above method was unsuccessful
                        elif 'Electronic' in line and in_partition_functions and spin_multiplicity == 0:
                            spin_multiplicity = int(float(line.split()[1].replace('D', 'E')))

                        elif 'Log10(Q)' in line:
                            in_partition_functions = True

                        # Read the next line in the file
                        line = f.readline()

                if 'Error termination' in line:
                    raise LogError(f'The Gaussian job in {self.path} did not converge.')

                # Read the next line in the file
                line = f.readline()

        return Conformer(E0=(e0 * 0.001, "kJ/mol"), modes=modes, spin_multiplicity=spin_multiplicity,
                         optical_isomers=optical_isomers), unscaled_frequencies
Exemplo n.º 3
0
    def load_conformer(self,
                       symmetry=None,
                       spin_multiplicity=0,
                       optical_isomers=None,
                       label=''):
        """
        Load the molecular degree of freedom data from a log file created as
        the result of a MolPro "Freq" quantum chemistry calculation with the thermo printed.
        """

        modes = []
        unscaled_frequencies = []
        e0 = 0.0
        if optical_isomers is None or symmetry is None:
            _optical_isomers, _symmetry, _ = self.get_symmetry_properties()
            if optical_isomers is None:
                optical_isomers = _optical_isomers
            if symmetry is None:
                symmetry = _symmetry
        with open(self.path, 'r') as f:
            line = f.readline()
            while line != '':

                # Read the spin multiplicity if not explicitly given
                if spin_multiplicity == 0 and 'spin' in line:
                    splits = line.replace('=', ' ').replace(',',
                                                            ' ').split(' ')
                    for i, s in enumerate(splits):
                        if 'spin' in s:
                            spin_multiplicity = int(splits[i + 1]) + 1
                            logging.debug(
                                'Conformer {0} is assigned a spin multiplicity of {1}'
                                .format(label, spin_multiplicity))
                            break
                if spin_multiplicity == 0 and 'SPIN SYMMETRY' in line:
                    spin_symmetry = line.split()[-1]
                    if spin_symmetry == 'Singlet':
                        spin_multiplicity = 1
                    elif spin_symmetry == 'Doublet':
                        spin_multiplicity = 2
                    elif spin_symmetry == 'Triplet':
                        spin_multiplicity = 3
                    elif spin_symmetry == 'Quartet':
                        spin_multiplicity = 4
                    elif spin_symmetry == 'Quintet':
                        spin_multiplicity = 5
                    elif spin_symmetry == 'Sextet':
                        spin_multiplicity = 6
                    if spin_multiplicity:
                        logging.debug(
                            'Conformer {0} is assigned a spin multiplicity of {1}'
                            .format(label, spin_multiplicity))
                        break

                # The data we want is in the Thermochemistry section of the output
                if 'THERMODYNAMICAL' in line:
                    modes = []
                    line = f.readline()
                    while line != '':

                        # This marks the end of the thermochemistry section
                        if '*************************************************' in line:
                            break

                        # Read molecular mass for external translational modes
                        elif 'Molecular Mass:' in line:
                            mass = float(line.split()[2])
                            translation = IdealGasTranslation(mass=(mass,
                                                                    "amu"))
                            modes.append(translation)

                        # Read moments of inertia for external rotational modes
                        elif 'Rotational Constants' in line and line.split(
                        )[-1] == '[GHz]':
                            inertia = [float(d) for d in line.split()[-4:-1]]
                            for i in range(3):
                                inertia[i] = constants.h / (8 * constants.pi * constants.pi * inertia[i] * 1e9) \
                                             * constants.Na * 1e23
                            rotation = NonlinearRotor(
                                inertia=(inertia, "amu*angstrom^2"),
                                symmetry=symmetry)
                            modes.append(rotation)

                        elif 'Rotational Constant' in line and line.split(
                        )[3] == '[GHz]':
                            inertia = float(line.split()[2])
                            inertia = constants.h / (8 * constants.pi * constants.pi * inertia * 1e9) \
                                * constants.Na * 1e23
                            rotation = LinearRotor(inertia=(inertia,
                                                            "amu*angstrom^2"),
                                                   symmetry=symmetry)
                            modes.append(rotation)

                        # Read vibrational modes
                        elif 'Vibrational Temperatures' in line:
                            frequencies = []
                            frequencies.extend(
                                [float(d) for d in line.split()[3:]])
                            line = f.readline()
                            while line.strip() != '':
                                frequencies.extend(
                                    [float(d) for d in line.split()])
                                line = f.readline()
                            # Convert from K to cm^-1
                            if len(frequencies) > 0:
                                frequencies = [
                                    freq * 0.695039 for freq in frequencies
                                ]  # kB = 0.695039 cm^-1/K
                                unscaled_frequencies = frequencies
                                vibration = HarmonicOscillator(
                                    frequencies=(frequencies, "cm^-1"))
                                modes.append(vibration)

                        # Read the next line in the file
                        line = f.readline()

                # Read the next line in the file
                line = f.readline()

        return Conformer(E0=(e0 * 0.001, "kJ/mol"),
                         modes=modes,
                         spin_multiplicity=spin_multiplicity,
                         optical_isomers=optical_isomers), unscaled_frequencies
Exemplo n.º 4
0
    def loadConformer(self, symmetry=None, spinMultiplicity=0, opticalIsomers=None, label=''):
        """
        Load the molecular degree of freedom data from an output file created as the result of a
        QChem "Freq" calculation. As QChem's guess of the external symmetry number is not always correct,
        you can use the `symmetry` parameter to substitute your own value;
        if not provided, the value in the QChem output file will be adopted.
        """
        modes = []; freq = []; mmass = []; rot = []; inertia = []
        unscaled_frequencies = []
        E0 = 0.0
        if opticalIsomers is None or symmetry is None:
            _opticalIsomers, _symmetry = self.get_optical_isomers_and_symmetry_number()
            if opticalIsomers is None:
                opticalIsomers = _opticalIsomers
            if symmetry is None:
                symmetry = _symmetry
        f = open(self.path, 'r')
        line = f.readline()
        while line != '':
            # Read spin multiplicity if not explicitly given
            if '$molecule' in line and spinMultiplicity == 0:
                line = f.readline()
                if len(line.split()) == 2:
                    spinMultiplicity = int(float(line.split()[1]))
                    logging.debug('Conformer {0} is assigned a spin multiplicity of {1}'.format(label,spinMultiplicity))
            # The rest of the data we want is in the Thermochemistry section of the output
            elif 'VIBRATIONAL ANALYSIS' in line:
                modes = []
                line = f.readline()
                while line != '':

                    # This marks the end of the thermochemistry section
                    if 'Thank you very much for using Q-Chem.' in line:
                        break

                    # Read vibrational modes
                    elif 'VIBRATIONAL FREQUENCIES (CM**-1)' in line:
                        frequencies = []
                        while 'STANDARD THERMODYNAMIC QUANTITIES AT' not in line:
                            if ' Frequency:' in line:
                                if len(line.split()) == 4:
                                    frequencies.extend([float(d) for d in line.split()[-3:]])
                                elif len(line.split()) == 3:
                                    frequencies.extend([float(d) for d in line.split()[-2:]])
                                elif len(line.split()) == 2:
                                    frequencies.extend([float(d) for d in line.split()[-1:]])
                            line = f.readline()
                        line = f.readline()
                        # If there is an imaginary frequency, remove it
                        if frequencies[0] < 0.0:
                            frequencies = frequencies[1:]

                        unscaled_frequencies = frequencies
                        vibration = HarmonicOscillator(frequencies=(frequencies,"cm^-1"))
                        # modes.append(vibration)
                        freq.append(vibration)
                    # Read molecular mass for external translational modes
                    elif 'Molecular Mass:' in line:
                        mass = float(line.split()[2])
                        translation = IdealGasTranslation(mass=(mass,"amu"))
                        # modes.append(translation)
                        mmass.append(translation)

                    # Read moments of inertia for external rotational modes, given in atomic units
                    elif 'Eigenvalues --' in line:
                        inertia = [float(d) for d in line.split()[-3:]]

                    # Read the next line in the file
                    line = f.readline()

            # Read the next line in the file
            line = f.readline()

            if len(inertia):
                if inertia[0] == 0.0:
                    # If the first eigenvalue is 0, the rotor is linear
                    inertia.remove(0.0)
                    logging.debug('inertia is {}'.format(str(inertia)))
                    for i in range(2):
                        inertia[i] *= (constants.a0 / 1e-10) ** 2
                    inertia = numpy.sqrt(inertia[0] * inertia[1])
                    rotation = LinearRotor(inertia=(inertia, "amu*angstrom^2"), symmetry=symmetry)
                    rot.append(rotation)
                else:
                    for i in range(3):
                        inertia[i] *= (constants.a0 / 1e-10) ** 2
                        rotation = NonlinearRotor(inertia=(inertia, "amu*angstrom^2"), symmetry=symmetry)
                        # modes.append(rotation)
                    rot.append(rotation)

                inertia = []

        # Close file when finished
        f.close()
        modes = mmass + rot + freq
        return Conformer(E0=(E0*0.001,"kJ/mol"), modes=modes, spinMultiplicity=spinMultiplicity,
                         opticalIsomers=opticalIsomers), unscaled_frequencies
    def loadConformer(self, symmetry=None, spinMultiplicity=None, opticalIsomers=1):
        """
        Load the molecular degree of freedom data from a log file created as
        the result of a Gaussian "Freq" quantum chemistry calculation. As
        Gaussian's guess of the external symmetry number is not always correct,
        you can use the `symmetry` parameter to substitute your own value; if
        not provided, the value in the Gaussian log file will be adopted. In a
        log file with multiple Thermochemistry sections, only the last one will
        be kept.
        """

        modes = []
        E0 = 0.0

        f = open(self.path, 'r')
        line = f.readline()
        while line != '':

            # The data we want is in the Thermochemistry section of the output
            if '- Thermochemistry -' in line:
                modes = []
                inPartitionFunctions = False
                line = f.readline()
                while line != '':

                    # This marks the end of the thermochemistry section
                    if '-------------------------------------------------------------------' in line:
                        break

                    # Read molecular mass for external translational modes
                    elif 'Molecular mass:' in line:
                        mass = float(line.split()[2])
                        translation = IdealGasTranslation(mass=(mass,"amu"))
                        modes.append(translation)

                    # Read Gaussian's estimate of the external symmetry number
                    elif 'Rotational symmetry number' in line and symmetry is None:
                        symmetry = int(float(line.split()[3]))

                    # Read moments of inertia for external rotational modes
                    elif 'Rotational constants (GHZ):' in line:
                        inertia = [float(d) for d in line.split()[-3:]]
                        for i in range(3):
                            inertia[i] = constants.h / (8 * constants.pi * constants.pi * inertia[i] * 1e9) *constants.Na*1e23
                        rotation = NonlinearRotor(inertia=(inertia,"amu*angstrom^2"), symmetry=symmetry)
                        modes.append(rotation)
                    elif 'Rotational constant (GHZ):' in line:
                        inertia = [float(line.split()[3])]
                        inertia[0] = constants.h / (8 * constants.pi * constants.pi * inertia[0] * 1e9) *constants.Na*1e23
                        rotation = LinearRotor(inertia=(inertia[0],"amu*angstrom^2"), symmetry=symmetry)
                        modes.append(rotation)

                    # Read vibrational modes
                    elif 'Vibrational temperatures:' in line:
                        frequencies = []
                        frequencies.extend([float(d) for d in line.split()[2:]])
                        line = f.readline()
                        frequencies.extend([float(d) for d in line.split()[1:]])
                        line = f.readline()
                        while line.strip() != '':
                            frequencies.extend([float(d) for d in line.split()])
                            line = f.readline()
                        # Convert from K to cm^-1
                        if len(frequencies) > 0:
                            frequencies = [freq * 0.695039 for freq in frequencies]  # kB = 0.695039 cm^-1/K
                            vibration = HarmonicOscillator(frequencies=(frequencies,"cm^-1"))
                            modes.append(vibration)

                    # Read ground-state energy
                    elif 'Sum of electronic and zero-point Energies=' in line:
                        E0 = float(line.split()[6]) * 4.35974394e-18 * constants.Na

                    # Read spin multiplicity if not explicitly given
                    elif 'Electronic' in line and inPartitionFunctions and spinMultiplicity is None:
                        spinMultiplicity = int(float(line.split()[1].replace('D', 'E')))

                    elif 'Log10(Q)' in line:
                        inPartitionFunctions = True

                    # Read the next line in the file
                    line = f.readline()

            # Read the next line in the file
            line = f.readline()

        # Close file when finished
        f.close()

        return Conformer(E0=(E0*0.001,"kJ/mol"), modes=modes, spinMultiplicity=spinMultiplicity, opticalIsomers=opticalIsomers)
Exemplo n.º 6
0
    def get_enthalpy_of_formation(self,
                                  freq_scale_factor=1.0,
                                  apply_bond_corrections=True):
        """
        Calculate the enthalpy of formation at 298.15 K.
        Apply bond energy corrections if desired and if
        model chemistry is compatible.
        """
        temperature = 298.15
        mol = pybel.readstring('smi',
                               self.smiles)  # Use OBMol to extract bond types

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

        # Translation
        translation = IdealGasTranslation()

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

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

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

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

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

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

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

                e0 += bond_energy * 4184.0

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

        return self.hf298
Exemplo n.º 7
0
    def loadConformer(self,
                      symmetry=None,
                      spinMultiplicity=None,
                      opticalIsomers=1):
        """
        Load the molecular degree of freedom data from a log file created as
        the result of a Qchem "Freq"  calculation. As
        Qchem's guess of the external symmetry number is not always correct,
        you can use the `symmetry` parameter to substitute your own value; if
        not provided, the value in the Qchem output file will be adopted.
        """

        modes = []
        freq = []
        mmass = []
        rot = []
        E0 = 0.0

        f = open(self.path, 'r')
        line = f.readline()
        while line != '':

            # The data we want is in the Thermochemistry section of the output
            if 'VIBRATIONAL ANALYSIS' in line:
                modes = []

                inPartitionFunctions = False
                line = f.readline()
                while line != '':

                    # This marks the end of the thermochemistry section
                    if 'Thank you very much for using Q-Chem.' in line:
                        break

                    # Read vibrational modes
                    elif 'VIBRATIONAL FREQUENCIES (CM**-1)' in line:
                        frequencies = []
                        while 'STANDARD THERMODYNAMIC QUANTITIES AT' not in line:
                            if ' Frequency:' in line:
                                frequencies.extend(
                                    [float(d) for d in line.split()[-3:]])
                            line = f.readline()
                        line = f.readline()
                        # If there is an imaginary frequency, remove it
                        if frequencies[0] < 0.0:
                            frequencies = frequencies[1:]

                        vibration = HarmonicOscillator(
                            frequencies=(frequencies, "cm^-1"))
                        #modes.append(vibration)
                        freq.append(vibration)
                    # Read molecular mass for external translational modes
                    elif 'Molecular Mass:' in line:
                        mass = float(line.split()[2])
                        translation = IdealGasTranslation(mass=(mass, "amu"))
                        #modes.append(translation)
                        mmass.append(translation)

                    # Read moments of inertia for external rotational modes, given in atomic units
                    elif 'Eigenvalues --' in line:
                        inertia = [float(d) for d in line.split()[-3:]]
                        # If the first eigenvalue is 0, the rotor is linear
                        if inertia[0] == 0.0:
                            inertia.remove(0.0)
                            for i in range(2):
                                inertia[i] *= (constants.a0 / 1e-10)**2
                                rotation = LinearRotor(
                                    inertia=(inertia, "amu*angstrom^2"),
                                    symmetry=symmetry)
                                #modes.append(rotation)
                            rot.append(rotation)
                        else:
                            for i in range(3):
                                inertia[i] *= (constants.a0 / 1e-10)**2
                                rotation = NonlinearRotor(
                                    inertia=(inertia, "amu*angstrom^2"),
                                    symmetry=symmetry)
                                #modes.append(rotation)
                            rot.append(rotation)

                    # Read Qchem's estimate of the external rotational symmetry number, which may very well be incorrect
                    elif 'Rotational Symmetry Number is' in line and symmetry is None:
                        symmetry = int(float(line.split()[4]))

                    elif 'Final energy is' in line:
                        E0 = float(
                            line.split()[3]) * constants.E_h * constants.Na
                        print 'energy is' + str(E0)
                    # Read ZPE and add to ground-state energy
                    # NEED TO MULTIPLY ZPE BY scaling factor!
                    elif 'Zero point vibrational energy:' in line:
                        ZPE = float(line.split()[4]) * 4184
                        E0 = E0 + ZPE
                    # Read spin multiplicity if not explicitly given
#                    elif 'Electronic' in line and inPartitionFunctions and spinMultiplicity is None:
#                        spinMultiplicity = int(float(line.split()[1].replace('D', 'E')))

#                    elif 'Log10(Q)' in line:
#                        inPartitionFunctions = True

# Read the next line in the file
                    line = f.readline()

            # Read the next line in the file
            line = f.readline()

        # Close file when finished
        f.close()
        modes = mmass + rot + freq
        #modes.append(mmass), modes.append(rot), modes.append(freq)
        return Conformer(E0=(E0 * 0.001, "kJ/mol"),
                         modes=modes,
                         spinMultiplicity=spinMultiplicity,
                         opticalIsomers=opticalIsomers)
Exemplo n.º 8
0
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