Пример #1
0
def banner(text, type=1, width=35):
    """Function to print *text* to output file in a banner of
    minimum width *width* and minimum three-line height for
    *type* = 1 or one-line height for *type* = 2.

    """
    lines = text.split("\n")
    max_length = 0
    for line in lines:
        if len(line) > max_length:
            max_length = len(line)

    max_length = max([width, max_length])

    null = ""
    if type == 1:
        banner = "  //" + null.center(max_length, ">") + "//\n"
        for line in lines:
            banner += "  //" + line.center(max_length) + "//\n"
        banner += "  //" + null.center(max_length, "<") + "//\n"

    if type == 2:
        banner = ""
        for line in lines:
            banner += (" " + line + " ").center(max_length, "=")

    psi4.print_out(banner)
Пример #2
0
def compare_vectors(expected, computed, digits, label):
    """Function to compare two vectors. Prints :py:func:`util.success`
    when elements of vector *computed* match elements of vector *expected* to
    number of *digits*. Performs a system exit on failure to match symmetry
    structure, dimension, or element values. Used in input files in the test suite.

    """
    if (expected.nirrep() != computed.nirrep()):
        print("\t%s has %d irreps, but %s has %d\n." % (expected.name(), expected.nirrep(), computed.name(), computed.nirrep()))
        sys.exit(1)
    nirreps = expected.nirrep()
    for irrep in range(nirreps):
        if(expected.dim(irrep) != computed.dim(irrep)):
            print("\tThe reference has %d entries in irrep %d, but the computed vector has %d\n." % (expected.dim(irrep), irrep, computed.dim(irrep)))
            sys.exit(1)
        dim = expected.dim(irrep)
        failed = 0
        for entry in range(dim):
            if(abs(expected.get(irrep, entry) - computed.get(irrep, entry)) > 10 ** (-digits)):
                print("\t%s: computed value (%s) does not match (%s)." % (label, computed.get(irrep, entry), expected.get(irrep, entry)))
                failed = 1
                break

        if(failed):
            psi4.print_out("The computed vector\n")
            computed.print_out()
            psi4.print_out("The reference vector\n")
            expected.print_out()
            sys.exit(1)
    success(label)
Пример #3
0
 def __init__(self, circs):
     if circs[5] == '':
         msg = """{0}: Method '{1}' with {2} '{3}' and REFERENCE '{4}' not available{5}""".format(*circs)
     else:
         msg = """{0}: Method '{1}' with {2} '{3}' and REFERENCE '{4}' not directable to QC_MODULE '{5}'""".format(*circs)
     PsiException.__init__(self, msg)
     self.message = msg
     psi4.print_out('\nPsiException: %s\n\n' % (msg))
Пример #4
0
    def compute_energy(self):
        uhf = self.uhf
        e, nocc, norb, gmo = self.uhf.e, self.uhf.nocc, self.uhf.norb, self.gmo

        Ec = 0.0
        for i in range(nocc):
            for j in range(nocc):
                for a in range(nocc, norb):
                    for b in range(nocc, norb):
                        Ec += (1/4.0) * gmo[i, j, a, b]**2 / (e[i]+e[j]-e[a]-e[b])

        self.E = uhf.E + Ec

        psi4.print_out('MP2            E                  Ec\n')
        psi4.print_out('     {:20.15f}  {:20.15f}'.format(self.E, Ec))

        return Ec
Пример #5
0
def extract_sowreap_from_output(sowout, quantity, sownum, linkage, allvital=False):
    """Function to examine file *sowout* from a sow/reap distributed job
    for formatted line with electronic energy information about index
    *sownum* to be used for construction of *quantity* computations as
    directed by master input file with *linkage* kwarg. When file *sowout*
    is missing or incomplete files, function will either return zero
    (*allvital* is ``False``) or terminate (*allvital* is ``True``) since
    some sow/reap procedures can produce meaningful results (database)
    from an incomplete set of sown files, while others cannot (gradient,
    hessian).

    """
    E = 0.0

    try:
        freagent = open('%s.out' % (sowout), 'r')
    except IOError:
        if allvital:
            raise ValidationError('Aborting upon output file \'%s.out\' not found.\n' % (sowout))
        else:
            ValidationError('Aborting upon output file \'%s.out\' not found.\n' % (sowout))
            return 0.0
    else:
        while True:
            line = freagent.readline()
            if not line:
                if E == 0.0:
                    if allvital:
                        raise ValidationError('Aborting upon output file \'%s.out\' has no %s RESULT line.\n' % (sowout, quantity))
                    else:
                        ValidationError('Aborting upon output file \'%s.out\' has no %s RESULT line.\n' % (sowout, quantity))
                break
            s = line.split()
            if (len(s) != 0) and (s[0:3] == [quantity, 'RESULT:', 'computation']):
                if int(s[3]) != linkage:
                    raise ValidationError('Output file \'%s.out\' has linkage %s incompatible with master.in linkage %s.'
                        % (sowout, str(s[3]), str(linkage)))
                if s[6] != str(sownum + 1):
                    raise ValidationError('Output file \'%s.out\' has nominal affiliation %s incompatible with item %s.'
                        % (sowout, s[6], str(sownum + 1)))
                if (s[8:10] == ['electronic', 'energy']):
                    E = float(s[10])
                    psi4.print_out('%s RESULT: electronic energy = %20.12f\n' % (quantity, E))
        freagent.close()
    return E
Пример #6
0
    def fitGeneral(self):
        """Function to perform a general fit of diffuse charges
        to wavefunction density.

        """
        psi4.print_out("    => Diffuse Charge Fitting (Determines da) <=\n\n")
        self.wfn = psi4.wavefunction()
        self.Da = self.wfn.Da()
        self.basis = self.wfn.basisset()
        parser = psi4.Gaussian94BasisSetParser()
        self.ribasis = psi4.BasisSet.construct(parser, self.molecule, "DF_BASIS_SCF")

        fitter = psi4.DFChargeFitter()
        fitter.setPrimary(self.basis)
        fitter.setAuxiliary(self.ribasis)
        fitter.setD(self.Da)
        self.da = fitter.fit()
        self.da.scale(2.0)
Пример #7
0
    def compute_energy(self):
        """
        Compute the MP2 energy
        :return: MP2 energy
        """
        ndocc = self.ndocc
        nbf = self.nbf
        gmo = self.gmo
        e = self.e
        E = 0.0
        for i in range(ndocc):
            for j in range(ndocc):
                for a in range(ndocc, nbf):
                    for b in range(ndocc, nbf):
                        E += gmo[i, a, j, b]*(2*gmo[i, a, j, b] - gmo[i, b, j, a])/\
                             (e[i] + e[j] - e[a] - e[b])

        psi4.print_out('@MP2 correlation energy: {:20.15f}\n'.format(E))
        psi4.print_out('@Total MP2 energy: {:20.15f}\n'.format(E + self.ehf))

        self.emp2 = E
Пример #8
0
def _print_nbody_energy(energy_body_dict, header):
        psi4.print_out("""\n   ==> N-Body: %s  energies <==\n\n""" % header)
        psi4.print_out("""   n-Body     Total Energy [Eh]       I.E. [kcal/mol]      Delta [kcal/mol]\n""")
        previous_e = energy_body_dict[1]
        nbody_range = energy_body_dict.keys()
        nbody_range.sort()
        for n in nbody_range:
            delta_e = (energy_body_dict[n] - previous_e)
            delta_e_kcal = delta_e * p4const.psi_hartree2kcalmol
            int_e_kcal = (energy_body_dict[n] - energy_body_dict[1]) * p4const.psi_hartree2kcalmol
            psi4.print_out("""     %4s  %20.12f  %20.12f  %20.12f\n""" %
                                        (n, energy_body_dict[n], int_e_kcal, delta_e_kcal))
            previous_e = energy_body_dict[n]
        psi4.print_out("\n")
Пример #9
0
    def compute_energy(self):

        S = np.matrix(la.block_diag(self.S, self.S))
        T = np.matrix(la.block_diag(self.T, self.T))
        V = np.matrix(la.block_diag(self.V, self.V))
        D = np.matrix(np.zeros((self.nsbf, self.nsbf)))
        X = np.matrix(la.inv(la.sqrtm(S)))
        h = T + V
        E0 = 0
        for count in range(self.maxiter):
            F = h + self.vu
            Ft = X * F * X
            e, Ct = la.eigh(Ft)
            C = X * np.matrix(Ct)
            OC = np.matrix(C[:,:self.nelec])
            D = OC*OC.T
            self.vu = np.einsum('upvq,qp->uv', self.G, D)
            E1 = np.sum((np.array(h) + 0.5 * np.array(self.vu))*np.array(D.T)) + self.V_nuc
            psi4.print_out('Iteration {:<d}   {:.10f}    {:.10f}\n'.format(count, E1, E1-E0))
            if abs(E1 - E0) < self.e_convergence:
                psi4.print_out('\nFinal HF Energy: {:<5.10f}'.format(E1))
                self.C = C
                self.epsi = e
                self.ehf = E1
                break
            else:
                E0 = E1
        else:
            psi4.print_out('\n:(   Does not converge   :(')
Пример #10
0
 def compute_energy(self):
     """
     Compute the rhf energy
     :return: energy
     """
     X = np.matrix(la.inv(la.sqrtm(self.S)))
     D = np.matrix(np.zeros((self.nbf, self.nbf)))
     h = self.T + self.V
     E0 = 0
     for count in range(self.maxiter):
         F = h + self.vu
         Ft = X * F * X
         e, Ct = la.eigh(Ft)
         C = X * np.matrix(Ct)
         DOC = np.matrix(C[:,:self.ndocc])
         D = DOC*DOC.T
         G = 2*self.g - self.g.swapaxes(2,3)
         self.vu = np.einsum('upvq,qp->uv', G, D) 
         E1 = np.sum((2 * np.array(h) + np.array(self.vu))*np.array(D.T)) + self.V_nuc
         psi4.print_out('Iteration {:<d}   {:.10f}    {:.10f}\n'.format(count, E1, E1-E0))
         if abs(E1 - E0) < self.e_convergence:
             psi4.print_out('\nFinal Energy: {:<5.10f}'.format(E1))
             break
         else:
             E0 = E1
     else:
         psi4.print_out('\n:(   Does not converge   :(')
Пример #11
0
    def fitScf(self):
        """Function to run scf and fit a system of diffuse charges to
        resulting density.

        """
        basisChanged = psi4.has_option_changed("BASIS")
        ribasisChanged = psi4.has_option_changed("DF_BASIS_SCF")
        scftypeChanged = psi4.has_option_changed("SCF_TYPE")

        basis = psi4.get_option("BASIS")
        ribasis = psi4.get_option("DF_BASIS_SCF")
        scftype = psi4.get_option("SCF_TYPE")

        psi4.print_out("    => Diffuse SCF (Determines Da) <=\n\n")
        activate(self.molecule)

        psi4.set_global_option("BASIS", self.basisname)
        psi4.set_global_option("DF_BASIS_SCF", self.ribasisname)
        psi4.set_global_option("SCF_TYPE", "DF")
        energy('scf')
        psi4.print_out("\n")

        self.fitGeneral()

        psi4.clean()

        psi4.set_global_option("BASIS", basis)
        psi4.set_global_option("DF_BASIS_SCF", ribasis)
        psi4.set_global_option("SCF_TYPE", scftype)

        if not basisChanged:
            psi4.revoke_option_changed("BASIS")
        if not ribasisChanged:
            psi4.revoke_option_changed("DF_BASIS_SCF")
        if not scftypeChanged:
            psi4.revoke_option_changed("SCF_TYPE")
Пример #12
0
    def compute_energy(self):
        """
        Compute the rhf energy
        :return: energy
        """
        V_nuc, T, S, V, g = self.V_nuc, self.T, self.S, self.V, self.g
        nbf, ndocc = self.nbf, self.ndocc

        D = np.zeros((self.nbf, self.nbf))
        C = np.zeros((self.nbf, self.nbf))

        # S^{-1/2}
        X = la.inv(la.sqrtm(S)).view(np.matrix)

        psi4.print_out('Iter.        Energy\n')
        scf_form = '{: >3d}  {: >20.15f}\n'
        i = 0
        converged = False
        e_old = 0
        # Begin SCF iterations
        while not converged and i < self.maxiter:
            F = self.build_fock(D)

            # Transformed Fock matrix to an orthogonal basis
            tF = X*F*X

            # Diagonalized the transformed Fock matrix
            e, tC = la.eigh(tF)

            # Convert eigenvectors to AO basis (from orthogonal basis)
            C = X*tC

            # Form density matrix
            D = C[:, :ndocc]*C[:, :ndocc].T

            # Compute the energy
            E = np.trace((F + T +V)*D) + V_nuc

            i += 1
            # Check convergence
            if abs(E - e_old) < self.e_convergence:
                converged = True
            e_old = E

            psi4.print_out(scf_form.format(i, E))

        psi4.print_out('RHF Energy: {:20.15f}\n'.format(E))

        self.e  = e
        self.C = C
        self.E = E

        return E
Пример #13
0
    def compute_energy(self):
        """
        Compute the rhf energy
        :return: energy
        """
        T, V, h, S, X = self.T, self.V, self.h, self.S, self.X
        V_nuc, nocc = self.V_nuc, self.nocc

        # Use an empty density guess
        D = np.zeros(T.shape)

        psi4.print_out('\nIter.        Energy\n')
        scf_form = '{: >3d}  {: >20.15f}\n'
        i = 0
        converged = False
        e_old = 0
        # Begin SCF iterations
        while not converged and i < self.maxiter:
            # build the Fock with the previous density
            f = self.build_fock(D)

            # Transform the Fock matrix to an orthogonal basis
            tf = X*f*X

            # Diagonalize the transformed Fock matrix
            e, tC = la.eigh(tf)

            # Convert eigenvectors to AO basis (from orthogonal basis)
            C = X*tC

            # Form density matrix
            D = C[:, :nocc]*C[:, :nocc].T

            # Compute the energy
            E = np.trace((h/2 + f/2)*D) + V_nuc

            i += 1
            # Check convergence
            if abs(E - e_old) < self.e_convergence:
                converged = True
            e_old = E

            psi4.print_out(scf_form.format(i, E))

        psi4.print_out('RHF Energy: {:20.15f}\n'.format(E))

        self.E = E
        self.C = C
        self.e = e

        return E
Пример #14
0
def compare_matrices(expected, computed, digits, label):
    """Function to compare two matrices. Prints :py:func:`util.success`
    when elements of matrix *computed* match elements of matrix *expected* to
    number of *digits*. Performs a system exit on failure to match symmetry
    structure, dimensions, or element values. Used in input files in the test suite.

    """
    if (expected.nirrep() != computed.nirrep()):
        print("\t%s has %d irreps, but %s has %d\n." % (expected.name(), expected.nirrep(), computed.name(), computed.nirrep()))
        sys.exit(1)
    if (expected.symmetry() != computed.symmetry()):
        print("\t%s has %d symmetry, but %s has %d\n." % (expected.name(), expected.symmetry(), computed.name(), computed.symmetry()))
        sys.exit(1)
    nirreps = expected.nirrep()
    symmetry = expected.symmetry()
    for irrep in range(nirreps):
        if(expected.rows(irrep) != computed.rows(irrep)):
            print("\t%s has %d rows in irrep %d, but %s has %d\n." % (expected.name(), expected.rows(irrep), irrep, computed.name(), computed.rows(irrep)))
            sys.exit(1)
        if(expected.cols(irrep ^ symmetry) != computed.cols(irrep ^ symmetry)):
            print("\t%s has %d columns in irrep, but %s has %d\n." % (expected.name(), expected.cols(irrep), irrep, computed.name(), computed.cols(irrep)))
            sys.exit(1)
        rows = expected.rows(irrep)
        cols = expected.cols(irrep ^ symmetry)
        failed = 0
        for row in range(rows):
            for col in range(cols):
                if(abs(expected.get(irrep, row, col) - computed.get(irrep, row, col)) > 10 ** (-digits)):
                    print("\t%s: computed value (%s) does not match (%s)." % (label, expected.get(irrep, row, col), computed.get(irrep, row, col)))
                    failed = 1
                    break

        if(failed):
            print("Check your output file for reporting of the matrices.")
            psi4.print_out("The Failed Test Matrices\n")
            psi4.print_out("Computed Matrix (2nd matrix passed in)\n")
            computed.print_out()
            psi4.print_out("Expected Matrix (1st matrix passed in)\n")
            expected.print_out()
            sys.exit(1)
    success(label)
Пример #15
0
def writeCSX(name, **kwargs):
    """function to write the CSX file

    """

    if not psi4.get_global_option('WRITE_CSX'):
        return

    # import csx_api for csx writing
    import os
    import math
    import inspect
    #import openbabel
    import qcdb
    import qcdb.periodictable
    import csx2_api as api
    lowername = name.lower()
    # Make sure the molecule the user provided is the active one
    if ('molecule' in kwargs):
        activate(kwargs['molecule'])
        del kwargs['molecule']
    molecule = psi4.get_active_molecule()
    molecule.update_geometry()
    # Determine the derivative type
    calledby = inspect.stack()[1][3]
    derdict = {
        'energy': 0,
        'property': 0,
        'gradient': 1,
        'optimize': 1,
        'frequency': 2,
        'frequencies': 2,
        'hessian': 2,
        }
    dertype = derdict[calledby]
    hasFreq = False
    # Start to write the CSX file
    # First grab molecular information and energies from psi4
    geom = molecule.save_string_xyz()  # OB
    atomLine = geom.split('\n')  # OB

    # general molecular information
    atomNum = molecule.natom()
    molSym = molecule.schoenflies_symbol()
    molCharge = molecule.molecular_charge()
    molMulti = molecule.multiplicity()
    # energy information
    molBasis = psi4.get_global_option('BASIS')
    molSpin = psi4.get_global_option('REFERENCE')
    molMethod = psi4.get_global_option('WFN')
    mol1E = psi4.get_variable('ONE-ELECTRON ENERGY')
    mol2E = psi4.get_variable('TWO-ELECTRON ENERGY')
    molNE = psi4.get_variable('NUCLEAR REPULSION ENERGY')
    molPE = mol1E + mol2E
    molEE = psi4.get_variable('CURRENT ENERGY')
    # wavefunction information
    try:
        wfn = kwargs['wfn']
    except AttributeError:
        pass
    if wfn:
        molOrbE = wfn.epsilon_a()
        molOrbEb = wfn.epsilon_b()
        orbNmopi = wfn.nmopi()
        orbNsopi = wfn.nsopi()
        orbNum = wfn.nmo() if molOrbE else 0
        orbSNum = wfn.nso()
        molOrb = wfn.Ca()
        orbNirrep = wfn.nirrep()
        orbAotoso = wfn.aotoso()
        orbDoccpi = wfn.doccpi()
        orbSoccpi = wfn.soccpi()
        basisNbf = wfn.basisset().nbf()
        basisDim = psi4.Dimension(1, 'basisDim')
        basisDim.__setitem__(0, basisNbf)
        wfnRestricted = True
        orbE = []
        hlist = []
        orblist = []
        orbOcc = []
        molOrbmo = psi4.Matrix('molOrbmo', basisDim, orbNmopi)
        molOrbmo.gemm(False, False, 1.0, orbAotoso, molOrb, 0.0)
        if molSpin == 'UHF':
            wfnRestricted = False
            orbEb = []
            hlistCb = []
            orblistCb = []
            orbOccCb = []
            molOrbCb = wfn.Cb()
            molOrbmoCb = psi4.Matrix('molOrbmoCb', basisDim, orbNmopi)
            molOrbmoCb.gemm(False, False, 1.0, orbAotoso, molOrbCb, 0.0)
        count = 0
        eleExtra = 1 if wfnRestricted else 0
        for ih in range(orbNirrep):
            for iorb in range(orbNmopi.__getitem__(ih)):
                hlist.append(ih)
                orblist.append(iorb)
                if molOrbE:
                    orbE.append(molOrbE.get(count))
                eleNum = 1 if iorb < (orbDoccpi.__getitem__(ih) + orbSoccpi.__getitem__(ih)) else 0
                eleNum += eleExtra if iorb < orbDoccpi.__getitem__(ih) else 0
                orbOcc.append(eleNum)
                count += 1
        orbMos = sorted(zip(orbE, zip(hlist, orblist)))
        orbOccString = ' '.join(str(x) for x in sorted(orbOcc, reverse=True))
        orbCaString = []
        for imos in range(orbNum):
            (h, s) = orbMos[imos][1]
            orbCa = []
            for iso in range(orbSNum):
                orbEle = molOrbmo.get(h, iso, s)
                orbCa.append(orbEle)
            orbCaString.append(' '.join(str(x) for x in orbCa))
        orbEString = ' '.join(str(x) for x in sorted(orbE))
        # now for beta spin
        if not wfnRestricted:
            count = 0
            for ih in range(orbNirrep):
                for iorb in range(orbNmopi.__getitem__(ih)):
                    hlistCb.append(ih)
                    orblist.append(iorb)
                    if molOrbEb:
                        orbEb.append(molOrbEb.get(count))
                    eleNum = 1 if iorb < (orbDoccpi.__getitem__(ih) + orbSoccpi.__getitem__(ih)) else 0
                    if iorb < orbDoccpi.__getitem__(ih):
                        eleNum += eleExtra
                    orbOccCb.append(eleNum)
                    count += 1
            orbMosCb = sorted(zip(orbEb, zip(hlist, orblist)))
            orbOccCbString = ' '.join(str(x) for x in sorted(orbOccCb, reverse=True))
            orbCbString = []
            for imos in range(orbNum):
                (h, s) = orbMosCb[imos][1]
                orbCb = []
                for iso in range(orbSNum):
                    orbEle = molOrbmoCb.get(h, iso, s)
                    orbCb.append(orbEle)
                orbCbString.append(' '.join(str(x) for x in orbCb))
            orbEbString = ' '.join(str(x) for x in sorted(orbEb))
        #   orbColString = ' '.join(str(x) for x in orbCol)
        if wfnRestricted:
            wfn1 = api.waveFunctionType(
                orbitalCount=orbNum,
                orbitalOccupancies=orbOccString)
            orbe1 = api.stringArrayType(unit='gc:hartree')
            orbe1.set_valueOf_(orbEString)
            orbs1 = api.orbitalsType()
            for iorb in range(orbNum):
                orb1 = api.stringArrayType(id=iorb+1)
                orb1.set_valueOf_(orbCaString[iorb])
                orbs1.add_orbital(orb1)
            wfn1.set_orbitals(orbs1)
            wfn1.set_orbitalEnergies(orbe1)
        else:
            wfn1 = api.waveFunctionType(orbitalCount=orbNum)
            # alpha electron: 1.5
            orbe1 = api.stringArrayType(unit='gc:hartree')
            orbe1.set_valueOf_(orbEString)
            wfn1.set_alphaOrbitalEnergies(orbe1)
            wfn1.set_alphaOrbitalOccupancies(orbOccString)
            aorbs1 = api.orbitalsType()
            for iorb in range(orbNum):
                orb1 = api.stringArrayType(id=iorb+1)
                orb1.set_valueOf_(orbCaString[iorb])
                aorbs1.add_orbital(orb1)
            wfn1.set_alphaOrbitals(aorbs1)
            # beta electron: 1.5
            orbeb1 = api.stringArrayType(unit='gc:hartree')
            orbeb1.set_valueOf_(orbEbString)
            wfn1.set_betaOrbitalEnergies(orbeb1)
            wfn1.set_betaOrbitalOccupancies(orbOccCbString)
            borbs1 = api.orbitalsType()
            for iorb in range(orbNum):
                orb1 = api.stringArrayType(id=iorb+1)
                orb1.set_valueOf_(orbCbString[iorb])
                borbs1.add_orbital(orb1)
            wfn1.set_betaOrbitals(borbs1)
    # frequency information
    if dertype == 2:
        hasFreq = True
        molFreq = psi4.get_frequencies()
        molFreqNum = molFreq.dim(0)
        frq = []
        irInt = []
        for ifrq in range(molFreqNum):
            frq.append(molFreq.get(ifrq))
            irInt.append(0.0)
        frqString = ' '.join(str(x) for x in frq)
        intString = ' '.join(str(x) for x in irInt)
        normMod = psi4.get_normalmodes()
        normMdString = []
        count = 0
        for ifrq in range(molFreqNum):
            normM = []
            for iatm in range(atomNum):
                for ixyz in range(3):
                    normM.append(normMod.get(count))
                    count += 1
            normMdString.append(' '.join(str(x) for x in normM))
        vib1 = api.vibAnalysisType(vibrationCount=molFreqNum)
        freq1 = api.stringArrayType(unit="gc:cm-1")
        freq1.set_valueOf_(frqString)
        vib1.set_frequencies(freq1)
        irint1 = api.stringArrayType()
        irint1.set_valueOf_(intString)
        vib1.set_irIntensities(irint1)
        norms1 = api.normalModesType()
        for ifrq in range(molFreqNum):
            norm1 = api.normalModeType(id=ifrq+1)
            norm1.set_valueOf_(normMdString[ifrq])
            norms1.add_normalMode(norm1)
        vib1.set_normalModes(norms1)
    # dipole moment information
    molDipoleX = psi4.get_variable('CURRENT DIPOLE X')
    molDipoleY = psi4.get_variable('CURRENT DIPOLE Y')
    molDipoleZ = psi4.get_variable('CURRENT DIPOLE Z')
    molDipoleTot = math.sqrt(
        molDipoleX * molDipoleX +
        molDipoleY * molDipoleY +
        molDipoleZ * molDipoleZ)
    prop1 = api.propertiesType()
    sprop1 = api.propertyType(
        name='dipoleMomentX',
        unit='gc:debye')
    sprop1.set_valueOf_(molDipoleX)
    sprop2 = api.propertyType(
        name='dipoleMomentY',
        unit='gc:debye')
    sprop2.set_valueOf_(molDipoleY)
    sprop3 = api.propertyType(
        name='dipoleMomentZ',
        unit='gc:debye')
    sprop3.set_valueOf_(molDipoleZ)
    sprop4 = api.propertyType(
        name='dipoleMomentAverage',
        unit='gc:debye')
    sprop4.set_valueOf_(molDipoleTot)
    prop1.add_systemProperty(sprop1)
    prop1.add_systemProperty(sprop2)
    prop1.add_systemProperty(sprop3)
    prop1.add_systemProperty(sprop4)

    # get the basename for the CSX file
    psio = psi4.IO.shared_object()
    namespace = psio.get_default_namespace()
    #csxfilename = '.'.join([namespace, str(os.getpid()), 'csx'])
    csxfilename = os.path.splitext(psi4.outfile_name())[0] + '.csx'
    csxfile = open(csxfilename, 'w')
    csxVer = psi4.get_global_option('CSX_VERSION')

    # Both CSX versions 0 and 1 depended on the procedures table, which in
    #   turn required the writeCSX function to be in the driver.py file
    #   itself. Starting with 1.5 (1, to run), this dependence is broken and
    #   CSX has been shifted into a plugin.

    # Start to generate CSX elements
    # CSX version 1.5
    if csxVer == 2.0:
        #       import csx1_api as api
        cs1 = api.csType(version='2.0') #5')

        # molPublication section: 1.5
        mp1 = api.mpubType(
            title=psi4.get_global_option('PUBLICATIONTITLE'),
            abstract=psi4.get_global_option('PUBLICATIONABSTRACT'),
            publisher=psi4.get_global_option('PUBLICATIONPUBLISHER'),
            status=['PRELIMINARY', 'DRAFT', 'FINAL'].index(psi4.get_global_option('PUBLICATIONSTATUS')),
            category=psi4.get_global_option('PUBLICATIONCATEGORY'),
            visibility=['PRIVATE', 'PROTECTED', 'PUBLIC'].index(psi4.get_global_option('PUBLICATIONVISIBILITY')),
            tags=psi4.get_global_option('PUBLICATIONTAGS'),
            key=psi4.get_global_option('PUBLICATIONKEY'))
        email = psi4.get_global_option('EMAIL').replace('__', '@')
        mp1.add_author(api.authorType(
            creator=psi4.get_global_option('CORRESPONDINGAUTHOR'),
            type_='gc:CorrespondingAuthor',
            organization=psi4.get_global_option('ORGANIZATION'),
            email=None if email == '' else email))
        #mp1 = api.mpType(
        #   title='', abstract='', publisher='', status=0, category=2, visibility=0, tags='', key='')
        mp1.set_sourcePackage(api.sourcePackageType(name='Psi4', version=psi4.version()))
        #mp1.add_author(api.authorType(creator='', type_='cs:corresponding', organization='', email=''))
        cs1.set_molecularPublication(mp1)

        # molSystem section: 1.5
        ms1 = api.msysType(
            systemCharge=molCharge,
            systemMultiplicity=molMulti, id='s1')
        temp1 = api.dataWithUnitsType(unit='gc:kelvin')
        temp1.set_valueOf_(0.0)  # LAB dispute
        ms1.set_systemTemperature(temp1)
        mol1 = api.moleculeType(id='m1', atomCount=molecule.natom())
        #OBmol1 = api.moleculeType(id='m1', atomCount=atomNum)
        #OBobmol1 = openbabel.OBMol()
        #OBfor iatm in range(atomNum):
        #OB    atomField = atomLine[iatm + 1].split()
        #OB    atmSymbol = atomField[0]
        #OB    xCoord = float(atomField[1])
        #OB    yCoord = float(atomField[2])
        #OB    zCoord = float(atomField[3])
        #OB    obatm = obmol1.NewAtom()
        #OB    obatm.SetAtomicNum(qcdb.periodictable.el2z[atmSymbol.upper()])
        #OB    obatm.SetVector(xCoord, yCoord, zCoord)
        #OBobmol1.ConnectTheDots()
        #OBobmol1.PerceiveBondOrders()
        #OBobmol1.SetTotalSpinMultiplicity(molMulti)
        #OBobmol1.SetTotalCharge(molCharge)
        #OBconv1 = openbabel.OBConversion()
        #OBconv1.SetInAndOutFormats('mol', 'inchi')
        #OBconv1.SetOptions('K', conv1.OUTOPTIONS)
        #OBinchikey = conv1.WriteString(obmol1)
        #OBmol1.set_inchiKey(inchikey.rstrip())
        #OBiatm = 0
        for at in range(molecule.natom()):
            #xCoord1 = api.dataWithUnitsType(unit='cs:angstrom')
            #yCoord1 = api.dataWithUnitsType(unit='cs:angstrom')
            #zCoord1 = api.dataWithUnitsType(unit='cs:angstrom')
            #xCoord1.set_valueOf_(molecule.x(at) * p4const.psi_bohr2angstroms)
            #yCoord1.set_valueOf_(molecule.y(at) * p4const.psi_bohr2angstroms)
            #zCoord1.set_valueOf_(molecule.z(at) * p4const.psi_bohr2angstroms)
            xCoord1 = api.dataWithUnitsType(unit='gc:bohr')
            yCoord1 = api.dataWithUnitsType(unit='gc:bohr')
            zCoord1 = api.dataWithUnitsType(unit='gc:bohr')
            xCoord1.set_valueOf_(molecule.x(at))
            yCoord1.set_valueOf_(molecule.y(at))
            zCoord1.set_valueOf_(molecule.z(at))
            # LAB 8jun2015: not getting masses from OB anymore so now dependent on qc programs
            #   current proposition is changing API so masses only go into CSX if relevant (e.g., vib)
            #   same situation as temperature
            atm = api.atomType(
                id='a' + str(at + 1),
                elementSymbol=molecule.symbol(at),
                atomMass=molecule.mass(at),  # psi4 uses mass of most common isotope; OB uses natural distribution mass
                xCoord3D=xCoord1,
                yCoord3D=yCoord1,
                zCoord3D=zCoord1,
                basisSet='bse:' + molBasis,
                calculatedAtomCharge=0,
                formalAtomCharge=0)
            #OBiatm += 1
            #OBcoord1 = api.coordinationType()
            #OBibond = 0
            #OBfor nb_atom in openbabel.OBAtomAtomIter(obatom):
            #OB    bond = obatom.GetBond(nb_atom)
            #OB    bond1 = api.bondType(
            #OB        id1='a' + str(obatom.GetId() + 1),
            #OB        id2='a' + str(nb_atom.GetId() + 1))
            #OB    if bond.GetBondOrder() == 1:
            #OB        bond1.set_valueOf_('single')
            #OB    elif bond.GetBondOrder() == 2:
            #OB        bond1.set_valueOf_('double')
            #OB    elif bond.GetBondOrder() == 3:
            #OB        bond1.set_valueOf_('triple')
            #OB    elif bond.GetBondOrder() == 5:
            #OB        bond1.set_valueOf_('aromatic')
            #OB    else:
            #OB        print('wrong bond order')
            #OB    coord1.add_bond(bond1)
            #OB    ibond += 1
            #OBcoord1.set_bondCount(ibond)
            #OBatm.set_coordination(coord1)
            mol1.add_atom(atm)
        ms1.add_molecule(mol1)
        cs1.set_molecularSystem(ms1)

        # molCalculation section: 1.5
        mc1 = api.mcalType(id='c1')
        qm1 = api.qmCalcType()
        srs1 = api.srsMethodType()
        psivars = psi4.get_variables()

        def form_ene(mandatoryPsivars, optionalPsivars={}, excessPsivars={}):
            """

            """
            ene = api.energiesType(unit='gc:hartree')
            for pv, csx in mandatoryPsivars.iteritems():
                term = api.energyType(type_=csx)
                term.set_valueOf_(psivars.pop(pv))
                ene.add_energy(term)
            for pv, csx in optionalPsivars.iteritems():
                if pv in psivars:
                    term = api.energyType(type_=csx)
                    term.set_valueOf_(psivars.pop(pv))
                    ene.add_energy(term)
            for pv in excessPsivars:
                if pv in psivars:
                    psivars.pop(pv)
            return ene

        # Reference stage- every calc has one
        if 'CCSD TOTAL ENERGY' in psivars or 'CCSD(T) TOTAL ENERGY' in psivars \
                or 'CISD TOTAL ENERGY' in psivars or 'FCI TOTAL ENERGY' in psivars \
                or 'QCISD TOTAL ENERGY' in psivars or 'QCISD(T) TOTAL ENERGY' in psivars:
            mdm1 = api.srsmdMethodType()
            # CCSD(T): 1.5
            if 'CCSD(T) TOTAL ENERGY' in psivars:
                mandatoryPsivars = {
                    'CCSD(T) CORRELATION ENERGY': 'gc:correlation',
                    'CCSD(T) TOTAL ENERGY': 'gc:electronic'}
                if not all([pv in psivars for pv in mandatoryPsivars.keys()]):
                    raise CSXError("""Malformed CCSD(T) computation""")

                block = api.resultType(  # TODO should be pointing to HF for correlation, maybe to MP2 for guess
                    methodology='gc:normal',  # TODO handle dfcc
                    spinType='gc:' + molSpin,  # TODO could have a closed-shell corl mtd atop open-shell scf?
                    basisSet='bse:' + molBasis)
                block.set_energies(form_ene(mandatoryPsivars))
                if hasFreq:
                    block.set_vibrationalAnalysis(vib1)
                mdm1.set_ccsd_t(block)
            # CCSD: 1.5
            elif 'CCSD TOTAL ENERGY' in psivars:
                mandatoryPsivars = {
                    'CCSD CORRELATION ENERGY': 'gc:correlation',
                    'CCSD TOTAL ENERGY': 'gc:electronic'}
                if not all([pv in psivars for pv in mandatoryPsivars.keys()]):
                    raise CSXError("""Malformed CCSD computation""")

                block = api.resultType(  # TODO should be pointing to HF for correlation, maybe to MP2 for guess
                    methodology='gc:normal',  # TODO handle dfcc
                    spinType='gc:' + molSpin,  # TODO could have a closed-shell corl mtd atop open-shell scf?
                    basisSet='bse:' + molBasis)
                block.set_energies(form_ene(mandatoryPsivars))
                if hasFreq:
                    block.set_vibrationalAnalysis(vib1)
                mdm1.set_ccsd(block)
            # CISD: 1.5
            elif 'CISD TOTAL ENERGY' in psivars:
                mandatoryPsivars = {
                    'CISD CORRELATION ENERGY': 'gc:correlation',
                    'CISD TOTAL ENERGY': 'gc:electronic'}
                if not all([pv in psivars for pv in mandatoryPsivars.keys()]):
                    raise CSXError("""Malformed CISD computation""")

                block = api.resultType(  # TODO should be pointing to HF for correlation, maybe to MP2 for guess
                    methodology='gc:normal',  # TODO handle dfcc
                    spinType='gc:' + molSpin,  # TODO could have a closed-shell corl mtd atop open-shell scf?
                    basisSet='bse:' + molBasis)
                block.set_energies(form_ene(mandatoryPsivars))
                if hasFreq:
                    block.set_vibrationalAnalysis(vib1)
                mdm1.set_cisd(block)
            # FCI: 1.5
            elif 'FCI TOTAL ENERGY' in psivars:
                mandatoryPsivars = {
                    'FCI CORRELATION ENERGY': 'gc:correlation',
                    'FCI TOTAL ENERGY': 'gc:electronic'}
                if not all([pv in psivars for pv in mandatoryPsivars.keys()]):
                    raise CSXError("""Malformed FCI computation""")

                block = api.resultType(  # TODO should be pointing to HF for correlation, maybe to MP2 for guess
                    methodology='gc:normal',  # TODO handle dfcc
                    spinType='gc:' + molSpin,  # TODO could have a closed-shell corl mtd atop open-shell scf?
                    basisSet='bse:' + molBasis)
                block.set_energies(form_ene(mandatoryPsivars))
                mdm1.set_fci(block)
            # QCISD(T): 1.5
            elif 'QCISD(T) TOTAL ENERGY' in psivars:
                mandatoryPsivars = {
                    'QCISD(T) CORRELATION ENERGY': 'gc:correlation',
                    'QCISD(T) TOTAL ENERGY': 'gc:electronic'}
                if not all([pv in psivars for pv in mandatoryPsivars.keys()]):
                    raise CSXError("""Malformed QCISD(T) computation""")

                block = api.resultType(  # TODO should be pointing to HF for correlation, maybe to MP2 for guess
                    methodology='gc:normal',  # TODO handle dfcc
                    spinType='gc:' + molSpin,  # TODO could have a closed-shell corl mtd atop open-shell scf?
                    basisSet='bse:' + molBasis)
                block.set_energies(form_ene(mandatoryPsivars))
                if hasFreq:
                    block.set_vibrationalAnalysis(vib1)
                mdm1.set_qcisd_t(block)
            # QCISD: 1.5
            elif 'QCISD TOTAL ENERGY' in psivars:
                mandatoryPsivars = {
                    'QCISD CORRELATION ENERGY': 'gc:correlation',
                    'QCISD TOTAL ENERGY': 'gc:electronic'}
                if not all([pv in psivars for pv in mandatoryPsivars.keys()]):
                    raise CSXError("""Malformed QCISD computation""")

                block = api.resultType(  # TODO should be pointing to HF for correlation, maybe to MP2 for guess
                    methodology='gc:normal',  # TODO handle dfcc
                    spinType='gc:' + molSpin,  # TODO could have a closed-shell corl mtd atop open-shell scf?
                    basisSet='bse:' + molBasis)
                block.set_energies(form_ene(mandatoryPsivars))
                if hasFreq:
                    block.set_vibrationalAnalysis(vib1)
                mdm1.set_qcisd(block)
            srs1.set_multipleDeterminant(mdm1)

        elif 'DFT TOTAL ENERGY' in psivars or 'HF TOTAL ENERGY' in psivars \
                or 'MP2 TOTAL ENERGY' in psivars or 'MP3 TOTAL ENERGY' in psivars \
                or 'MP4 TOTAL ENERGY' in psivars:
            sdm1 = api.srssdMethodType()
            # DFT 1.5
            if 'DFT TOTAL ENERGY' in psivars:  # TODO robust enough to avoid MP2C, etc.?
                mandatoryPsivars = {
                    'NUCLEAR REPULSION ENERGY': 'gc:nuclearRepulsion',
                    'DFT FUNCTIONAL TOTAL ENERGY': 'gc:dftFunctional',
                    'DFT TOTAL ENERGY': 'gc:electronic'}
                optionalPsivars = {
                    'DOUBLE-HYBRID CORRECTION ENERGY': 'gc:doubleHybrid correction',
                    'DISPERSION CORRECTION ENERGY': 'gc:dispersion correction'}
                excessPsivars = [
                    'MP2 TOTAL ENERGY',
                    'MP2 CORRELATION ENERGY',
                    'MP2 SAME-SPIN CORRELATION ENERGY']

                if not all([pv in psivars for pv in mandatoryPsivars.keys()]):
                    raise CSXError("""Malformed DFT computation""")

                block = api.resultType(
                    methodology='gc:normal',  # TODO handle dfhf, dfmp
                    spinType='gc:' + molSpin,
                    basisSet='bse:' + molBasis,
                    dftFunctional=name)  # TODO this'll need to be exported
                block.set_energies(form_ene(mandatoryPsivars, optionalPsivars, excessPsivars))
                if wfn:
                    block.set_waveFunction(wfn1)
                if hasFreq:
                    block.set_vibrationalAnalysis(vib1)
                block.set_properties(prop1)
                sdm1.set_dft(block)


            # post-reference block
            # MP4: 1.5
            elif 'MP4 TOTAL ENERGY' in psivars:
                mandatoryPsivars = {
                    'MP4 CORRELATION ENERGY': 'gc:correlation',
                    'MP4 TOTAL ENERGY': 'gc:electronic'}
                optionalPsivars = {
                    'MP4 SAME-SPIN CORRELATION ENERGY': 'gc:sameSpin correlation'}
                if not all([pv in psivars for pv in mandatoryPsivars.keys()]):
                    raise CSXError("""Malformed MP4 computation""")

                block = api.resultType(  # TODO should be pointing to HF for correlation
                    methodology='gc:normal',  # TODO handle dfmp
                    spinType='gc:' + molSpin,  # TODO could have a closed-shell corl mtd atop open-shell scf?
                    basisSet='bse:' + molBasis)
                block.set_energies(form_ene(mandatoryPsivars, optionalPsivars))
                if wfn:
                    block.set_waveFunction(wfn1)
                if hasFreq:
                    block.set_vibrationalAnalysis(vib1)
                block.set_properties(prop1)
                sdm1.set_mp4(block)

            # MP3: 1.5
            elif 'MP3 TOTAL ENERGY' in psivars:
                mandatoryPsivars = {
                    'MP3 CORRELATION ENERGY': 'gc:correlation',
                    'MP3 TOTAL ENERGY': 'gc:electronic'}
                optionalPsivars = {
                    'MP3 SAME-SPIN CORRELATION ENERGY': 'gc:sameSpin correlation'}
                if not all([pv in psivars for pv in mandatoryPsivars.keys()]):
                    raise CSXError("""Malformed MP3 computation""")

                block = api.resultType(  # TODO should be pointing to HF for correlation
                    methodology='gc:normal',  # TODO handle dfmp
                    spinType='gc:' + molSpin,  # TODO could have a closed-shell corl mtd atop open-shell scf?
                    basisSet='bse:' + molBasis)
                block.set_energies(form_ene(mandatoryPsivars, optionalPsivars))
                if wfn:
                    block.set_waveFunction(wfn1)
                if hasFreq:
                    block.set_vibrationalAnalysis(vib1)
                block.set_properties(prop1)
                sdm1.set_mp3(block)

            # MP2: 1.5
            elif 'MP2 TOTAL ENERGY' in psivars:
                mandatoryPsivars = {
                    'MP2 CORRELATION ENERGY': 'gc:correlation',
                    'MP2 TOTAL ENERGY': 'gc:electronic'}
                optionalPsivars = {
                    'MP2 SAME-SPIN CORRELATION ENERGY': 'gc:sameSpin correlation'}
                if not all([pv in psivars for pv in mandatoryPsivars.keys()]):
                    raise CSXError("""Malformed MP2 computation""")

                block = api.resultType(  # TODO should be pointing to HF for correlation
                    methodology='gc:normal',  # TODO handle dfmp
                    spinType='gc:' + molSpin,  # TODO could have a closed-shell corl mtd atop open-shell scf?
                    basisSet='bse:' + molBasis)
                block.set_energies(form_ene(mandatoryPsivars, optionalPsivars))
                if wfn:
                    block.set_waveFunction(wfn1)
                if hasFreq:
                    block.set_vibrationalAnalysis(vib1)
                block.set_properties(prop1)
                sdm1.set_mp2(block)

            # SCF: 1.5
            elif 'HF TOTAL ENERGY' in psivars:
                mandatoryPsivars = {
                    'NUCLEAR REPULSION ENERGY': 'gc:nuclearRepulsion',
                    'HF TOTAL ENERGY': 'gc:electronic'}

                if not all([pv in psivars for pv in mandatoryPsivars.keys()]):
                    raise CSXError("""Malformed HF computation""")

                block = api.resultType(
                    methodology='gc:normal',  # TODO handle dfhf, dfmp
                    spinType='gc:' + molSpin,
                    basisSet='bse:' + molBasis)
                block.set_energies(form_ene(mandatoryPsivars))
                if wfn:
                    block.set_waveFunction(wfn1)
                if hasFreq:
                    block.set_vibrationalAnalysis(vib1)
                block.set_properties(prop1)
                sdm1.set_abinitioScf(block)
            else:
                psi4.print_out("""\nCSX version {0} does not support """
                               """method {1} for {2}\n""".format(
                               csxVer, lowername, 'energies'))

            srs1.set_singleDeterminant(sdm1)

        #print('CSX not harvesting: ', ', '.join(psivars))

        qm1.set_singleReferenceState(srs1)
        mc1.set_quantumMechanics(qm1)
        cs1.set_molecularCalculation(mc1)

    else:
        print('The future CSX file is here')

    csxfile.write('<?xml version="1.0" encoding="UTF-8"?>\n')
    cs1.export(csxfile, 0)
    csxfile.close()
Пример #16
0
def auto_fragments(**kwargs):
    r"""Detects fragments if the user does not supply them.
    Currently only used for the WebMO implementation of SAPT.

    :returns: :ref:`Molecule<sec:psimod_Molecule>`) |w--w| fragmented molecule.

    :type molecule: :ref:`molecule <op_py_molecule>`
    :param molecule: ``h2o`` || etc.

        The target molecule, if not the last molecule defined.

    :examples:

    >>> # [1] replicates with cbs() the simple model chemistry scf/cc-pVDZ: set basis cc-pVDZ energy('scf')
    >>> molecule mol {\nH 0.0 0.0 0.0\nH 2.0 0.0 0.0\nF 0.0 1.0 0.0\nF 2.0 1.0 0.0\n}
    >>> print mol.nfragments()  # 1
    >>> fragmol = auto_fragments()
    >>> print fragmol.nfragments()  # 2

    """
    # Make sure the molecule the user provided is the active one
    molecule = kwargs.pop('molecule', psi4.get_active_molecule())
    molecule.update_geometry()
    molname = molecule.name()

    geom = molecule.save_string_xyz()

    numatoms = molecule.natom()
    VdW = [1.2, 1.7, 1.5, 1.55, 1.52, 1.9, 1.85, 1.8]

    symbol = list(range(numatoms))
    X = [0.0] * numatoms
    Y = [0.0] * numatoms
    Z = [0.0] * numatoms

    Queue = []
    White = []
    Black = []
    F = geom.split('\n')
    for f in range(numatoms):
        A = F[f + 1].split()
        symbol[f] = A[0]
        X[f] = float(A[1])
        Y[f] = float(A[2])
        Z[f] = float(A[3])
        White.append(f)
    Fragment = [[] for i in range(numatoms)]  # stores fragments

    start = 0  # starts with the first atom in the list
    Queue.append(start)
    White.remove(start)

    frag = 0

    while((len(White) > 0) or (len(Queue) > 0)):  # Iterates to the next fragment
        while(len(Queue) > 0):  # BFS within a fragment
            for u in Queue:  # find all nearest Neighbors
                             #   (still coloured white) to vertex u
                for i in White:
                    Distance = math.sqrt((X[i] - X[u]) * (X[i] - X[u]) +
                                         (Y[i] - Y[u]) * (Y[i] - Y[u]) +
                                         (Z[i] - Z[u]) * (Z[i] - Z[u]))
                    if Distance < _autofragment_convert(u, symbol) + _autofragment_convert(i, symbol):
                        Queue.append(i)  # if you find you, put it in the que
                        White.remove(i)  # and remove it from the untouched list
            Queue.remove(u)  # remove focus from Queue
            Black.append(u)
            Fragment[frag].append(int(u + 1))  # add to group (adding 1 to start
                                           #   list at one instead of zero)

        if(len(White) != 0):  # cant move White->Queue if no more exist
            Queue.append(White[0])
            White.remove(White[0])
        frag += 1

    new_geom = """\n"""
    for i in Fragment[0]:
        new_geom = new_geom + F[i].lstrip() + """\n"""
    new_geom = new_geom + """--\n"""
    for j in Fragment[1]:
        new_geom = new_geom + F[j].lstrip() + """\n"""
    new_geom = new_geom + """units angstrom\n"""

    moleculenew = psi4.Molecule.create_molecule_from_string(new_geom)
    moleculenew.set_name(molname)
    moleculenew.update_geometry()
    moleculenew.print_cluster()
    psi4.print_out("""  Exiting auto_fragments\n""")

    return moleculenew
Пример #17
0
 def __init__(self, msg):
     PsiException.__init__(self, msg)
     self.message = msg
     psi4.print_out('\nCSXException: %s\n\n' % (msg))
Пример #18
0
def run_roa(name, **kwargs):

    # Get list of omega values -> Make sure we only have one wavelength
    # Catch this now before any real work gets done
    omega = psi4.get_option('CCRESPONSE','OMEGA')
    if len(omega) > 2:
        raise Exception('ROA scattering can only be performed for one wavelength.')
    else:
        pass

    psi4.print_out('Running ROA computation. Subdirectories for each '
              'required displaced geometry have been created.\n\n')

    ### Initialize database
    db = shelve.open('database',writeback=True)
    if 'inputs_generated' not in db:
        initialize_database(db)

    ### Generate input files
    if not db['inputs_generated']:
        generate_inputs(name, db)
        db['inputs_generated'] = True

    ### If 'serial' calculation, proceed with subdir execution
    
    ### Check job status
    if db['inputs_generated'] and not db['jobs_complete']:
        print('Checking status')
        roa_stat(db)
        for job,status in db['job_status'].items():
            print("{} --> {}".format(job,status))

    ### Compute ROA Scattering
    if db['jobs_complete']:
#   SAVE this for when multiple wavelengths works
#        # Get list of omega values
#        omega = psi4.get_option('CCRESPONSE','OMEGA')
#        if len(omega) > 1:
#            units = copy.copy(omega[-1])
#            omega.pop()
#        else:
#            units = 'atomic'
#        wavelength = copy.copy(omega[0])
#        # Set up units for scatter.cc
#        if units == 'NM':
#            wavelength = (psi_c * psi_h * 1*(10**-9))/(wavelength * psi_hartree2J)
#        if units == 'HZ':
#            wavelength = wavelength * psi_h / psi_hartree2J
#        if units == 'EV':
#            wavelength = wavelength / psi_hartree2ev
#        if units == 'atomic':
#            pass
        # Initialize tensor lists
        dip_polar_list = []
        opt_rot_list = []
        dip_quad_polar_list = []
        gauge_list = []
        make_gauge_list(gauge_list)
        # Gather data
        synthesize_dipole_polar(db,dip_polar_list)
        synthesize_opt_rot(db,opt_rot_list)
        synthesize_dip_quad_polar(db,dip_quad_polar_list)
        # Compute Scattering
	    # Run new function (src/bin/ccresponse/scatter.cc)
        psi4.print_out('Running scatter function')
        step = psi4.get_local_option('FINDIF','DISP_SIZE')
        for gauge in opt_rot_list:
            g_idx = opt_rot_list.index(gauge)
#            print('\n\n----------------------------------------------------------------------')
#            print('\t%%%%%%%%%% {} %%%%%%%%%%'.format(gauge_list[g_idx]))
#            print('----------------------------------------------------------------------\n\n')
            psi4.print_out('\n\n----------------------------------------------------------------------\n')
            psi4.print_out('\t%%%%%%%%%% {} %%%%%%%%%%\n'.format(gauge_list[g_idx]))
            psi4.print_out('----------------------------------------------------------------------\n\n')
            print('roa.py:85 I am not being passed a molecule, grabbing from global :(')
            psi4.scatter(psi4.get_active_molecule(), step, dip_polar_list, gauge, dip_quad_polar_list)

    db.close()
Пример #19
0
def process_input(raw_input, print_level=1):
    """Function to preprocess *raw input*, the text of the input file, then
    parse it, validate it for format, and convert it into legitimate Python.
    *raw_input* is printed to the output file unless *print_level* =0. Does
    a series of regular expression filters, where the matching portion of the
    input is replaced by the output of the corresponding function (in this
    module) call. Returns a string concatenating module import lines, a copy
    of the user's .psi4rc files, a setting of the scratch directory, a dummy
    molecule, and the processed *raw_input*.

    """
    # Check if the infile is actually an outfile (yeah we did)
    psi4_id = re.compile(r'PSI4: An Open-Source Ab Initio Electronic Structure Package')
    if (re.search(psi4_id, raw_input)):
        input_lines = raw_input.split("\n")
        input_re = re.compile(r'^\s*?\=\=> Input File <\=\=')
        input_start = -1
        for line_count in range(len(input_lines)):
            line = input_lines[line_count]
            if re.match(input_re, line):
                input_start = line_count + 3
                break

        stop_re = re.compile(r'^-{74}')
        input_stop = -1
        for line_count in range(input_start, len(input_lines)):
            line = input_lines[line_count]
            if re.match(stop_re, line):
                input_stop = line_count
                break

        if (input_start == -1 or input_stop == -1):
            print('Cannot extract infile from outfile.')
            sys.exit(1)

        raw_input = '\n'.join(input_lines[input_start:input_stop])
        raw_input += '\n'

    # Echo the infile on the outfile
    if print_level > 0:
        psi4.print_out("\n  ==> Input File <==\n\n")
        psi4.print_out("--------------------------------------------------------------------------\n")
        psi4.print_out(raw_input)
        psi4.print_out("--------------------------------------------------------------------------\n")
        psi4.flush_outfile()

    #NOTE: If adding mulitline data to the preprocessor, use ONLY the following syntax:
    #   function [objname] { ... }
    #   which has the regex capture group:
    #
    #   r'^(\s*?)FUNCTION\s*(\w*?)\s*\{(.*?)\}', re.MULTILINE | re.DOTALL | re.IGNORECASE
    #
    #   your function is in capture group #1
    #   your objname is in capture group #2
    #   your data is in capture group #3

    # Nuke all comments
    comment = re.compile(r'[^\\]#.*')
    temp = re.sub(comment, '', raw_input)
    # Now, nuke any escapes from comment lines
    comment = re.compile(r'\\#')
    temp = re.sub(comment, '#', temp)

    # Check the brackets and parentheses match up, as long as this is not a pickle input file
    if not re.search(r'pickle_kw', temp):
        check_parentheses_and_brackets(temp, 1)

    # First, remove everything from lines containing only spaces
    blankline = re.compile(r'^\s*$')
    temp = re.sub(blankline, '', temp, re.MULTILINE)

    # Look for things like
    # set matrix [
    #              [ 1, 2 ],
    #              [ 3, 4 ]
    #            ]
    # and put them on a single line
    temp = process_multiline_arrays(temp)

    # Process all "set name? { ... }"
    set_commands = re.compile(r'^(\s*?)set\s*([-,\w]*?)[\s=]*\{(.*?)\}',
                              re.MULTILINE | re.DOTALL | re.IGNORECASE)
    temp = re.sub(set_commands, process_set_commands, temp)

    # Process all individual "set (module_list) key  {[value_list] or $value or value}"
    # N.B. We have to be careful here, because \s matches \n, leading to potential problems
    # with undesired multiline matches.  Better the double-negative [^\S\n] instead, which
    # will match any space, tab, etc., except a newline
    set_command = re.compile(r'^(\s*?)set\s+(?:([-,\w]+)[^\S\n]+)?(\w+)(?:[^\S\n]|=)+((\[.*\])|(\$?[-+,*()\.\w]+))\s*$',
                             re.MULTILINE | re.IGNORECASE)
    temp = re.sub(set_command, process_set_command, temp)

    # Process "molecule name? { ... }"
    molecule = re.compile(r'^(\s*?)molecule[=\s]*(\w*?)\s*\{(.*?)\}',
                          re.MULTILINE | re.DOTALL | re.IGNORECASE)
    temp = re.sub(molecule, process_molecule_command, temp)

    # Process "external name? { ... }"
    external = re.compile(r'^(\s*?)external[=\s]*(\w*?)\s*\{(.*?)\}',
                          re.MULTILINE | re.DOTALL | re.IGNORECASE)
    temp = re.sub(external, process_external_command, temp)

    # Process "pcm name? { ... }"
    pcm = re.compile(r'^(\s*?)pcm[=\s]*(\w*?)\s*\{(.*?)^\}',
                          re.MULTILINE | re.DOTALL | re.IGNORECASE)
    temp = re.sub(pcm, process_pcm_command, temp)

    # Then remove repeated newlines
    multiplenewlines = re.compile(r'\n+')
    temp = re.sub(multiplenewlines, '\n', temp)

    # Process " extract"
    extract = re.compile(r'(\s*?)(\w+)\s*=\s*\w+\.extract_subsets.*',
                         re.IGNORECASE)
    temp = re.sub(extract, process_extract_command, temp)

    # Process "print" and transform it to "psi4.print_out()"
    #print_string = re.compile(r'(\s*?)print\s+(.*)', re.IGNORECASE)
    #temp = re.sub(print_string, process_print_command, temp)

    # Process "memory ... "
    memory_string = re.compile(r'(\s*?)memory\s+([+-]?\d*\.?\d+)\s+([KMG]i?B)',
                               re.IGNORECASE)
    temp = re.sub(memory_string, process_memory_command, temp)

    # Process "basis file ... "
    basis_file = re.compile(r'(\s*?)basis\s+file\s*(\b.*\b)\s*$',
                            re.MULTILINE | re.IGNORECASE)
    temp = re.sub(basis_file, process_basis_file, temp)

    # Process "basis name { ... }"
    basis_block = re.compile(r'(\s*?)basis[=\s]*\{(.*?)\}',
                             re.MULTILINE | re.DOTALL | re.IGNORECASE)
    temp = re.sub(basis_block, process_basis_block, temp)

    # Process "basis file ... "
    file_pid = re.compile(r'(\s*?)filename\s*(\b.*\b)\s*$',
                            re.MULTILINE | re.IGNORECASE)
    temp = re.sub(file_pid, process_filename, temp)

    # imports
    imports = 'from psi4 import *\n'
    imports += 'from p4const import *\n'
    imports += 'from p4util import *\n'
    imports += 'from molutil import *\n'
    imports += 'from driver import *\n'
    imports += 'from wrappers import *\n'
    imports += 'from gaussian_n import *\n'
    imports += 'from aliases import *\n'
    imports += 'from functional import *\n'
    imports += 'from qmmm import *\n'
    imports += 'psi4_io = psi4.IOManager.shared_object()\n'

    # psirc (a baby PSIthon script that might live in ~/.psi4rc)
    psirc = ''
    homedir = os.path.expanduser('~')
    psirc_file = homedir + '/.psi4rc'
    if os.path.isfile(psirc_file):
        fh = open(psirc_file)
        psirc = fh.read()
        fh.close()

    # Override scratch directory if user specified via env_var
    scratch = ''
    scratch_env = psi4.Process.environment['PSI_SCRATCH']
    if len(scratch_env):
        scratch += 'psi4_io.set_default_path("%s")\n' % (scratch_env)

    blank_mol = 'geometry("""\n'
    blank_mol += '0 1\nH\nH 1 0.74\n'
    blank_mol += '""","blank_molecule_psi4_yo")\n'

    temp = imports + psirc + scratch + blank_mol + temp

    return temp
Пример #20
0
def _nbody_gufunc(func, method_string, **kwargs):
    """
    Computes the nbody interaction energy, gradient, or Hessian depending on input.

    Parameters
    ----------
    func : python function
        Python function that accepts method_string and a molecule and returns a energy, gradient, or Hessian.
    method_string : str
        Lowername to be passed to function
    molecule : psi4.Molecule (default: Global Molecule)
        Molecule to use in all computations
    return_wfn : bool (default: False)
        Return a wavefunction or not
    bsse_type : str or list (default: None, this function is not called)
        Type of BSSE correction to compute: CP, NoCP, or VMFC. The first in this list is returned by this function.
    max_nbody : int
        Maximum n-body to compute, cannot exceede the number of fragments in the moleucle
    ptype : str
        Type of the procedure passed in
    return_total_data : bool (default: False)
        If True returns the total data (energy/gradient/etc) of the system otherwise returns interaction data

    Returns
    -------
    data : return type of func
        The interaction data
    wfn : psi4.Wavefunction (optional)
        A wavefunction with energy/gradient/hessian set appropriotely. This wavefunction also contains 

    Notes
    -----
    This is a generalized univeral function for compute interaction quantities.

    Examples
    --------
    """

    ### ==> Parse some kwargs <==
    kwargs = p4util.kwargs_lower(kwargs)
    return_wfn = kwargs.pop('return_wfn', False)
    ptype = kwargs.pop('ptype', None)
    return_total_data = kwargs.pop('return_total_data', False)
    molecule = kwargs.pop('molecule', psi4.get_active_molecule())
    molecule.update_geometry()
    psi4.clean_variables()

    if ptype not in ['energy', 'gradient', 'hessian']:
        raise ValidationError("""N-Body driver: The ptype '%s' is not regonized.""" % ptype)

    # Figure out BSSE types
    do_cp = False
    do_nocp = False
    do_vmfc = False
    return_method = False

    # Must be passed bsse_type
    bsse_type_list = kwargs.pop('bsse_type')
    if bsse_type_list is None:
        raise ValidationError("N-Body GUFunc: Must pass a bsse_type")
    if not isinstance(bsse_type_list, list):
        bsse_type_list = [bsse_type_list]

    for num, btype in enumerate(bsse_type_list):
        if btype.lower() == 'cp':
            do_cp = True
            if (num == 0): return_method = 'cp'
        elif btype.lower() == 'nocp':
            do_nocp = True
            if (num == 0): return_method = 'nocp'
        elif btype.lower() == 'vmfc':
            do_vmfc = True
            if (num == 0): return_method = 'vmfc'
        else:
            raise ValidationError("N-Body GUFunc: bsse_type '%s' is not recognized" % btype.lower())

    max_nbody = kwargs.get('max_nbody', -1)
    max_frag = molecule.nfragments()
    if max_nbody == -1:
        max_nbody = molecule.nfragments()
    else:
        max_nbody = min(max_nbody, max_frag)

    # What levels do we need?
    nbody_range = range(1, max_nbody + 1)
    fragment_range = range(1, max_frag + 1)

    # If we are doing CP lets save them integrals
    if 'cp' in bsse_type_list and (len(bsse_type_list) == 1):
        # Set to save RI integrals for repeated full-basis computations
        ri_ints_io = psi4.get_global_option('DF_INTS_IO')

        # inquire if above at all applies to dfmp2 or just scf
        psi4.set_global_option('DF_INTS_IO', 'SAVE')
        psioh = psi4.IOManager.shared_object()
        psioh.set_specific_retention(97, True)


    bsse_str = bsse_type_list[0]
    if len(bsse_type_list) >1:
        bsse_str =  str(bsse_type_list)
    psi4.print_out("\n\n")
    psi4.print_out("   ===> N-Body Interaction Abacus <===\n")
    psi4.print_out("        BSSE Treatment:                     %s\n" % bsse_str)


    cp_compute_list = {x:set() for x in nbody_range}
    nocp_compute_list = {x:set() for x in nbody_range}
    vmfc_compute_list = {x:set() for x in nbody_range}
    vmfc_level_list = {x:set() for x in nbody_range} # Need to sum something slightly different

    # Build up compute sets
    if do_cp:
        # Everything is in dimer basis
        basis_tuple = tuple(fragment_range)
        for nbody in nbody_range:
            for x in it.combinations(fragment_range, nbody):
                cp_compute_list[nbody].add( (x, basis_tuple) )

    if do_nocp:
        # Everything in monomer basis
        for nbody in nbody_range:
            for x in it.combinations(fragment_range, nbody):
                nocp_compute_list[nbody].add( (x, x) )

    if do_vmfc:
        # Like a CP for all combinations of pairs or greater
        for nbody in nbody_range:
            for cp_combos in it.combinations(fragment_range, nbody):
                basis_tuple = tuple(cp_combos)
                for interior_nbody in nbody_range:
                    for x in it.combinations(cp_combos, interior_nbody):
                        combo_tuple = (x, basis_tuple)
                        vmfc_compute_list[interior_nbody].add( combo_tuple )
                        vmfc_level_list[len(basis_tuple)].add( combo_tuple )

    # Build a comprehensive compute_range
    compute_list = {x:set() for x in nbody_range}
    for n in nbody_range:
        compute_list[n] |= cp_compute_list[n]
        compute_list[n] |= nocp_compute_list[n]
        compute_list[n] |= vmfc_compute_list[n]
        psi4.print_out("        Number of %d-body computations:     %d\n" % (n, len(compute_list[n])))


    # Build size and slices dictionaries
    fragment_size_dict = {frag: molecule.extract_subsets(frag).natom() for
                                           frag in range(1, max_frag+1)}

    start = 0
    fragment_slice_dict = {}
    for k, v in fragment_size_dict.items():
        fragment_slice_dict[k] = slice(start, start + v)
        start += v

    molecule_total_atoms = sum(fragment_size_dict.values())

    # Now compute the energies
    energies_dict = {}
    ptype_dict = {}
    for n in compute_list.keys():
        psi4.print_out("\n   ==> N-Body: Now computing %d-body complexes <==\n\n" % n)
        print("\n   ==> N-Body: Now computing %d-body complexes <==\n" % n)
        total = len(compute_list[n])
        for num, pair in enumerate(compute_list[n]):
            psi4.print_out("\n       N-Body: Computing complex (%d/%d) with fragments %s in the basis of fragments %s.\n\n" %
                                                                    (num + 1, total, str(pair[0]), str(pair[1])))
            ghost = list(set(pair[1]) - set(pair[0]))

            current_mol = molecule.extract_subsets(list(pair[0]), ghost)
            ptype_dict[pair] = func(method_string, molecule=current_mol, **kwargs)
            energies_dict[pair] = psi4.get_variable("CURRENT ENERGY")
            psi4.print_out("\n       N-Body: Complex Energy (fragments = %s, basis = %s: %20.14f)\n" % 
                                                                (str(pair[0]), str(pair[1]), energies_dict[pair]))

            if 'cp' in bsse_type_list and (len(bsse_type_list) == 1):
                psi4.set_global_option('DF_INTS_IO', 'LOAD')

            psi4.clean()

    # Final dictionaries
    cp_energy_by_level   = {n: 0.0 for n in nbody_range}
    nocp_energy_by_level = {n: 0.0 for n in nbody_range}

    cp_energy_body_dict =   {n: 0.0 for n in nbody_range}
    nocp_energy_body_dict = {n: 0.0 for n in nbody_range}
    vmfc_energy_body_dict = {n: 0.0 for n in nbody_range}

    # Build out ptype dictionaries if needed
    if ptype != 'energy':
        if ptype == 'gradient':
            arr_shape = (molecule_total_atoms, 3)
        elif ptype == 'hessian':
            arr_shape = (molecule_total_atoms * 3, molecule_total_atoms * 3)
        else:
            raise KeyError("N-Body: ptype '%s' not recognized" % ptype)

        cp_ptype_by_level   =  {n: np.zeros(arr_shape) for n in nbody_range}
        nocp_ptype_by_level =  {n: np.zeros(arr_shape) for n in nbody_range}

        cp_ptype_body_dict   = {n: np.zeros(arr_shape) for n in nbody_range}
        nocp_ptype_body_dict = {n: np.zeros(arr_shape) for n in nbody_range}
        vmfc_ptype_body_dict = {n: np.zeros(arr_shape) for n in nbody_range}
    else:
        cp_ptype_by_level, cp_ptype_body_dict = None, None
        nocp_ptype_by_level, nocp_ptype_body_dict = None, None
        vmfc_ptype_by_level= None


    # Sum up all of the levels
    for n in nbody_range:

        # Energy
        cp_energy_by_level[n]   = sum(energies_dict[v] for v in cp_compute_list[n])
        nocp_energy_by_level[n] = sum(energies_dict[v] for v in nocp_compute_list[n])

        # Special vmfc case
        if n > 1:
            vmfc_energy_body_dict[n] = vmfc_energy_body_dict[n - 1]
        for tup in vmfc_level_list[n]:
            vmfc_energy_body_dict[n] += ((-1) ** (n - len(tup[0]))) * energies_dict[tup]


        # Do ptype
        if ptype != 'energy':
            _sum_cluster_ptype_data(ptype, ptype_dict, cp_compute_list[n],
                                      fragment_slice_dict, fragment_size_dict,
                                      cp_ptype_by_level[n])
            _sum_cluster_ptype_data(ptype, ptype_dict, nocp_compute_list[n],
                                      fragment_slice_dict, fragment_size_dict,
                                      nocp_ptype_by_level[n])
            _sum_cluster_ptype_data(ptype, ptype_dict, vmfc_level_list[n],
                                      fragment_slice_dict, fragment_size_dict,
                                      vmfc_ptype_by_level[n], vmfc=True)
    # Compute cp energy and ptype
    if do_cp:
        for n in nbody_range:
            if n == max_frag:
                cp_energy_body_dict[n] = cp_energy_by_level[n]
                if ptype != 'energy':
                    cp_ptype_body_dict[n][:] = cp_ptype_by_level[n]
                continue

            for k in range(1, n + 1):
                take_nk =  nCr(max_frag - k - 1, n - k)
                sign = ((-1) ** (n - k))
                value = cp_energy_by_level[k]
                cp_energy_body_dict[n] += take_nk * sign * value

                if ptype != 'energy':
                    value = cp_ptype_by_level[k]
                    cp_ptype_body_dict[n] += take_nk * sign * value

        _print_nbody_energy(cp_energy_body_dict, "Counterpoise Corrected (CP)")
        cp_interaction_energy = cp_energy_body_dict[max_nbody] - cp_energy_body_dict[1]
        psi4.set_variable('Counterpoise Corrected Total Energy', cp_energy_body_dict[max_nbody])
        psi4.set_variable('Counterpoise Corrected Interaction Energy', cp_interaction_energy)

        for n in nbody_range[1:]:
            var_key = 'CP-CORRECTED %d-BODY INTERACTION ENERGY' % n
            psi4.set_variable(var_key, cp_energy_body_dict[n] - cp_energy_body_dict[1])

    # Compute nocp energy and ptype
    if do_nocp:
        for n in nbody_range:
            if n == max_frag:
                nocp_energy_body_dict[n] = nocp_energy_by_level[n]
                if ptype != 'energy':
                    nocp_ptype_body_dict[n][:] = nocp_ptype_by_level[n]
                continue

            for k in range(1, n + 1):
                take_nk =  nCr(max_frag - k - 1, n - k)
                sign = ((-1) ** (n - k))
                value = nocp_energy_by_level[k]
                nocp_energy_body_dict[n] += take_nk * sign * value

                if ptype != 'energy':
                    value = nocp_ptype_by_level[k]
                    nocp_ptype_body_dict[n] += take_nk * sign * value

        _print_nbody_energy(nocp_energy_body_dict, "Non-Counterpoise Corrected (NoCP)")
        nocp_interaction_energy = nocp_energy_body_dict[max_nbody] - nocp_energy_body_dict[1]
        psi4.set_variable('Non-Counterpoise Corrected Total Energy', nocp_energy_body_dict[max_nbody])
        psi4.set_variable('Non-Counterpoise Corrected Interaction Energy', nocp_interaction_energy)

        for n in nbody_range[1:]:
            var_key = 'NOCP-CORRECTED %d-BODY INTERACTION ENERGY' % n
            psi4.set_variable(var_key, nocp_energy_body_dict[n] - nocp_energy_body_dict[1])


    # Compute vmfc energy and ptype
    if do_vmfc:
        _print_nbody_energy(vmfc_energy_body_dict, "Valiron-Mayer Function Couterpoise (VMFC)")
        vmfc_interaction_energy = vmfc_energy_body_dict[max_nbody] - vmfc_energy_body_dict[1]
        psi4.set_variable('Valiron-Mayer Function Couterpoise Total Energy', vmfc_energy_body_dict[max_nbody])
        psi4.set_variable('Valiron-Mayer Function Couterpoise Interaction Energy', vmfc_interaction_energy)

        for n in nbody_range[1:]:
            var_key = 'VMFC-CORRECTED %d-BODY INTERACTION ENERGY' % n
            psi4.set_variable(var_key, vmfc_energy_body_dict[n] - vmfc_energy_body_dict[1])

    if return_method == 'cp':
        ptype_body_dict = cp_ptype_body_dict
        energy_body_dict = cp_energy_body_dict
    elif return_method == 'nocp':
        ptype_body_dict = nocp_ptype_body_dict
        energy_body_dict = nocp_energy_body_dict
    elif return_method == 'vmfc':
        ptype_body_dict = vmfc_ptype_body_dict
        energy_body_dict = vmfc_energy_body_dict
    else:
        raise ValidationError("N-Body Wrapper: Invalid return type. Should never be here, please post this error on github.")


    # Figure out and build return types
    if return_total_data:
        ret_energy = energy_body_dict[max_nbody]
    else:
        ret_energy = energy_body_dict[max_nbody]
        ret_energy -= energy_body_dict[1]


    if ptype != 'energy':
        if return_total_data:
            np_final_ptype = ptype_body_dict[max_nbody].copy()
        else:
            np_final_ptype = ptype_body_dict[max_nbody].copy()
            np_final_ptype -= ptype_body_dict[1]

            ret_ptype = psi4.Matrix(*np_cp_final_ptype.shape)
            ret_ptype_view = np.asarray(final_ptype)
            ret_ptype_view[:] = np_final_ptype
    else:
        ret_ptype = ret_energy

    # Build and set a wavefunction
    wfn = psi4.new_wavefunction(molecule, 'sto-3g')
    wfn.nbody_energy = energies_dict
    wfn.nbody_ptype = ptype_dict
    wfn.nbody_body_energy = energy_body_dict
    wfn.nbody_body_ptype = ptype_body_dict

    if ptype == 'gradient':
        wfn.set_gradient(ret_ptype)
    elif ptype == 'hessian':
        wfn.set_hessian(ret_ptype)

    psi4.set_variable("CURRENT ENERGY", ret_energy)

    if return_wfn:
        return (ret_ptype, wfn)
    else:
        return ret_ptype
Пример #21
0
def ip_fitting(molecule, omega_l, omega_r, **kwargs):
    kwargs = p4util.kwargs_lower(kwargs)

    # By default, zero the omega to 3 digits
    omega_tol = kwargs.get('omega_tolerance', 1.0E-3)

    # By default, do up to twenty iterations
    maxiter = kwargs.get('maxiter', 20)

    # By default, do not read previous 180 orbitals file
    read = False
    read180 = ''
    if 'read' in kwargs:
        read = True
        read180 = kwargs['read']

    # The molecule is required, and should be the neutral species
    molecule.update_geometry()
    charge0 = molecule.molecular_charge()
    mult0 = molecule.multiplicity()

    # How many electrons are there?
    N = 0
    for A in range(molecule.natom()):
        N += molecule.Z(A)
    N -= charge0
    N = int(N)
    Nb = int((N - mult0 + 1) / 2)
    Na = int(N - Nb)

    # Work in the ot namespace for this procedure
    psi4.IO.set_default_namespace("ot")

    # Burn in to determine orbital eigenvalues
    if read:
        psi4.set_global_option("GUESS", "READ")
        copy_file_to_scratch(read180, 'psi', 'ot', 180)
    old_guess = psi4.get_global_option("GUESS")
    psi4.set_global_option("DF_INTS_IO", "SAVE")
    psi4.print_out("""\n\t==> IP Fitting SCF: Burn-in <==\n""")
    E, wfn = energy('scf', return_wfn=True, molecule=molecule, **kwargs)
    psi4.set_global_option("DF_INTS_IO", "LOAD")

    # Determine H**O, to determine mult1
    eps_a = wfn.epsilon_a()
    eps_b = wfn.epsilon_b()
    if Na == Nb:
        H**O = -Nb
    elif Nb == 0:
        H**O = Na
    else:
        E_a = eps_a[int(Na - 1)]
        E_b = eps_b[int(Nb - 1)]
        if E_a >= E_b:
            H**O = Na
        else:
            H**O = -Nb

    Na1 = Na
    Nb1 = Nb
    if H**O > 0:
        Na1 = Na1 - 1
    else:
        Nb1 = Nb1 - 1

    charge1 = charge0 + 1
    mult1 = Na1 - Nb1 + 1

    omegas = []
    E0s = []
    E1s = []
    kIPs = []
    IPs = []
    types = []

    # Right endpoint
    psi4.set_global_option('DFT_OMEGA', omega_r)

    # Neutral
    if read:
        psi4.set_global_option("GUESS", "READ")
        p4util.copy_file_to_scratch(read180, 'psi', 'ot', 180)

    molecule.set_molecular_charge(charge0)
    molecule.set_multiplicity(mult0)
    psi4.print_out("""\n\t==> IP Fitting SCF: Neutral, Right Endpoint <==\n""")
    E0r, wfn = energy('scf', return_wfn=True, molecule=molecule, **kwargs)
    eps_a = wfn.epsilon_a()
    eps_b = wfn.epsilon_b()
    E_HOMO = 0.0
    if Nb == 0:
        E_HOMO = eps_a[int(Na - 1)]
    else:
        E_a = eps_a[int(Na - 1)]
        E_b = eps_b[int(Nb - 1)]
        if E_a >= E_b:
            E_HOMO = E_a
        else:
            E_HOMO = E_b
    E_HOMOr = E_HOMO
    psi4.IO.change_file_namespace(180, "ot", "neutral")

    # Cation
    if read:
        psi4.set_global_option("GUESS", "READ")
        p4util.copy_file_to_scratch(read180, 'psi', 'ot', 180)

    molecule.set_molecular_charge(charge1)
    molecule.set_multiplicity(mult1)
    psi4.print_out("""\n\t==> IP Fitting SCF: Cation, Right Endpoint <==\n""")
    E1r = energy('scf', molecule=molecule, **kwargs)
    psi4.IO.change_file_namespace(180, "ot", "cation")

    IPr = E1r - E0r
    kIPr = -E_HOMOr
    delta_r = IPr - kIPr

    if IPr > kIPr:
        message = (
            """\n***IP Fitting Error: Right Omega limit should have kIP > IP"""
        )
        raise ValidationError(message)

    omegas.append(omega_r)
    types.append('Right Limit')
    E0s.append(E0r)
    E1s.append(E1r)
    IPs.append(IPr)
    kIPs.append(kIPr)

    # Use previous orbitals from here out
    psi4.set_global_option("GUESS", "READ")

    # Left endpoint
    psi4.set_global_option('DFT_OMEGA', omega_l)

    # Neutral
    psi4.IO.change_file_namespace(180, "neutral", "ot")
    molecule.set_molecular_charge(charge0)
    molecule.set_multiplicity(mult0)
    psi4.print_out("""\n\t==> IP Fitting SCF: Neutral, Left Endpoint <==\n""")
    E0l, wfn = energy('scf', return_wfn=True, molecule=molecule, **kwargs)
    eps_a = wfn.epsilon_a()
    eps_b = wfn.epsilon_b()
    E_HOMO = 0.0
    if Nb == 0:
        E_HOMO = eps_a[int(Na - 1)]
    else:
        E_a = eps_a[int(Na - 1)]
        E_b = eps_b[int(Nb - 1)]
        if E_a >= E_b:
            E_HOMO = E_a
        else:
            E_HOMO = E_b
    E_HOMOl = E_HOMO
    psi4.IO.change_file_namespace(180, "ot", "neutral")

    # Cation
    psi4.IO.change_file_namespace(180, "cation", "ot")
    molecule.set_molecular_charge(charge1)
    molecule.set_multiplicity(mult1)
    psi4.print_out("""\n\t==> IP Fitting SCF: Cation, Left Endpoint <==\n""")
    E1l = energy('scf', molecule=molecule, **kwargs)
    psi4.IO.change_file_namespace(180, "ot", "cation")

    IPl = E1l - E0l
    kIPl = -E_HOMOl
    delta_l = IPl - kIPl

    if IPl < kIPl:
        message = (
            """\n***IP Fitting Error: Left Omega limit should have kIP < IP""")
        raise ValidationError(message)

    omegas.append(omega_l)
    types.append('Left Limit')
    E0s.append(E0l)
    E1s.append(E1l)
    IPs.append(IPl)
    kIPs.append(kIPl)

    converged = False
    repeat_l = 0
    repeat_r = 0
    step = 0
    while True:

        step = step + 1

        # Regula Falsi (modified)
        if repeat_l > 1:
            delta_l = delta_l / 2.0
        if repeat_r > 1:
            delta_r = delta_r / 2.0
        omega = -(omega_r - omega_l) / (delta_r - delta_l) * delta_l + omega_l
        psi4.set_global_option('DFT_OMEGA', omega)

        # Neutral
        psi4.IO.change_file_namespace(180, "neutral", "ot")
        molecule.set_molecular_charge(charge0)
        molecule.set_multiplicity(mult0)
        psi4.print_out(
            """\n\t==> IP Fitting SCF: Neutral, Omega = %11.3E <==\n""" %
            omega)
        E0, wfn = energy('scf', return_wfn=True, molecule=molecule, **kwargs)
        eps_a = wfn.epsilon_a()
        eps_b = wfn.epsilon_b()
        E_HOMO = 0.0
        if Nb == 0:
            E_HOMO = eps_a[int(Na - 1)]
        else:
            E_a = eps_a[int(Na - 1)]
            E_b = eps_b[int(Nb - 1)]
            if E_a >= E_b:
                E_HOMO = E_a
            else:
                E_HOMO = E_b
        psi4.IO.change_file_namespace(180, "ot", "neutral")

        # Cation
        psi4.IO.change_file_namespace(180, "cation", "ot")
        molecule.set_molecular_charge(charge1)
        molecule.set_multiplicity(mult1)
        psi4.print_out(
            """\n\t==> IP Fitting SCF: Cation, Omega = %11.3E <==\n""" % omega)
        E1 = energy('scf', molecule=molecule, **kwargs)
        psi4.IO.change_file_namespace(180, "ot", "cation")

        IP = E1 - E0
        kIP = -E_HOMO
        delta = IP - kIP

        if kIP > IP:
            omega_r = omega
            E0r = E0
            E1r = E1
            IPr = IP
            kIPr = kIP
            delta_r = delta
            repeat_r = 0
            repeat_l = repeat_l + 1
        else:
            omega_l = omega
            E0l = E0
            E1l = E1
            IPl = IP
            kIPl = kIP
            delta_l = delta
            repeat_l = 0
            repeat_r = repeat_r + 1

        omegas.append(omega)
        types.append('Regula-Falsi')
        E0s.append(E0)
        E1s.append(E1)
        IPs.append(IP)
        kIPs.append(kIP)

        # Termination
        if (abs(omega_l - omega_r) < omega_tol or step > maxiter):
            converged = True
            break

    # Properly, should clone molecule but since not returned and easy to unblemish,
    molecule.set_molecular_charge(charge0)
    molecule.set_multiplicity(mult0)
    psi4.IO.set_default_namespace("")

    psi4.print_out("""\n\t==> IP Fitting Results <==\n\n""")

    psi4.print_out("""\t => Occupation Determination <= \n\n""")
    psi4.print_out("""\t          %6s %6s %6s %6s %6s %6s\n""" %
                   ('N', 'Na', 'Nb', 'Charge', 'Mult', 'H**O'))
    psi4.print_out("""\t Neutral: %6d %6d %6d %6d %6d %6d\n""" %
                   (N, Na, Nb, charge0, mult0, H**O))
    psi4.print_out("""\t Cation:  %6d %6d %6d %6d %6d\n\n""" %
                   (N - 1, Na1, Nb1, charge1, mult1))

    psi4.print_out("""\t => Regula Falsi Iterations <=\n\n""")
    psi4.print_out("""\t%3s %11s %14s %14s %14s %s\n""" %
                   ('N', 'Omega', 'IP', 'kIP', 'Delta', 'Type'))
    for k in range(len(omegas)):
        psi4.print_out(
            """\t%3d %11.3E %14.6E %14.6E %14.6E %s\n""" %
            (k + 1, omegas[k], IPs[k], kIPs[k], IPs[k] - kIPs[k], types[k]))
    if converged:
        psi4.print_out("""\n\tIP Fitting Converged\n""")
        psi4.print_out("""\tFinal omega = %14.6E\n""" %
                       ((omega_l + omega_r) / 2))
        psi4.print_out(
            """\n\t"M,I. does the dying. Fleet just does the flying."\n""")
        psi4.print_out("""\t\t\t-Starship Troopers\n""")

    else:
        psi4.print_out("""\n\tIP Fitting did not converge!\n""")

    psi4.set_global_option("DF_INTS_IO", "NONE")
    psi4.set_global_option("GUESS", old_guess)
Пример #22
0
 def __init__(self, msg):
     PsiException.__init__(self, msg)
     self.msg = msg
     psi4.print_out('\nPsiException: %s\n\n' % (msg))
Пример #23
0
def ip_fitting(mol, omega_l, omega_r, **kwargs):
    kwargs = p4util.kwargs_lower(kwargs)

    # By default, zero the omega to 3 digits
    omega_tol = 1.0E-3;
    if (kwargs.has_key('omega_tolerance')):
        omega_tol = kwargs['omega_tolerance']

    # By default, do up to twenty iterations
    maxiter = 20;
    if (kwargs.has_key('maxiter')):
        maxiter = kwargs['maxiter']

    # By default, do not read previous 180 orbitals file
    read = False;
    read180 = ''
    if (kwargs.has_key('read')):
        read = True;
        read180 = kwargs['read']

    # The molecule is required, and should be the neutral species
    mol.update_geometry()
    activate(mol)
    charge0 = mol.molecular_charge()
    mult0   = mol.multiplicity()

    # How many electrons are there?
    N = 0;
    for A in range(mol.natom()):
        N += mol.Z(A)
    N -= charge0
    N  = int(N)
    Nb = int((N - mult0 + 1)/2)
    Na = int(N - Nb)

    # Work in the ot namespace for this procedure
    psi4.IO.set_default_namespace("ot")

    # Burn in to determine orbital eigenvalues
    if (read):
        psi4.set_global_option("GUESS", "READ")
        copy_file_to_scratch(read180, 'psi', 'ot', 180)
    old_guess = psi4.get_global_option("GUESS")
    psi4.set_global_option("DF_INTS_IO", "SAVE")
    psi4.print_out('\n\t==> IP Fitting SCF: Burn-in <==\n')
    energy('scf')
    psi4.set_global_option("DF_INTS_IO", "LOAD")

    # Determine H**O, to determine mult1
    ref = psi4.wavefunction()
    eps_a = ref.epsilon_a()
    eps_b = ref.epsilon_b()
    if (Na == Nb):
        H**O = -Nb
    elif (Nb == 0):
        H**O = Na
    else:
        E_a = eps_a[int(Na - 1)]
        E_b = eps_b[int(Nb - 1)]
        if (E_a >= E_b):
            H**O = Na
        else:
            H**O = -Nb

    Na1 = Na;
    Nb1 = Nb;
    if (H**O > 0):
        Na1 = Na1-1;
    else:
        Nb1 = Nb1-1;

    charge1 = charge0 + 1;
    mult1 = Na1 - Nb1 + 1

    omegas = [];
    E0s = [];
    E1s = [];
    kIPs = [];
    IPs = [];
    types = [];

    # Right endpoint
    psi4.set_global_option('DFT_OMEGA',omega_r)

    # Neutral
    if (read):
        psi4.set_global_option("GUESS", "READ")
        p4util.copy_file_to_scratch(read180, 'psi', 'ot', 180)

    mol.set_molecular_charge(charge0)
    mol.set_multiplicity(mult0)
    psi4.print_out('\n\t==> IP Fitting SCF: Neutral, Right Endpoint <==\n')
    E0r = energy('scf')
    ref = psi4.wavefunction()
    eps_a = ref.epsilon_a()
    eps_b = ref.epsilon_b()
    E_HOMO = 0.0;
    if (Nb == 0):
        E_HOMO = eps_a[int(Na-1)]
    else:
        E_a = eps_a[int(Na - 1)]
        E_b = eps_b[int(Nb - 1)]
        if (E_a >= E_b):
            E_HOMO = E_a;
        else:
            E_HOMO = E_b;
    E_HOMOr = E_HOMO;
    psi4.IO.change_file_namespace(180,"ot","neutral")

    # Cation
    if (read):
        psi4.set_global_option("GUESS", "READ")
        p4util.copy_file_to_scratch(read180, 'psi', 'ot', 180)

    mol.set_molecular_charge(charge1)
    mol.set_multiplicity(mult1)
    psi4.print_out('\n\t==> IP Fitting SCF: Cation, Right Endpoint <==\n')
    E1r = energy('scf')
    psi4.IO.change_file_namespace(180,"ot","cation")

    IPr = E1r - E0r;
    kIPr = -E_HOMOr;
    delta_r = IPr - kIPr;

    if (IPr > kIPr):
        psi4.print_out('\n***IP Fitting Error: Right Omega limit should have kIP > IP')
        sys.exit(1)

    omegas.append(omega_r)
    types.append('Right Limit')
    E0s.append(E0r)
    E1s.append(E1r)
    IPs.append(IPr)
    kIPs.append(kIPr)

    # Use previous orbitals from here out
    psi4.set_global_option("GUESS","READ")

    # Left endpoint
    psi4.set_global_option('DFT_OMEGA',omega_l)

    # Neutral
    psi4.IO.change_file_namespace(180,"neutral","ot")
    mol.set_molecular_charge(charge0)
    mol.set_multiplicity(mult0)
    psi4.print_out('\n\t==> IP Fitting SCF: Neutral, Left Endpoint <==\n')
    E0l = energy('scf')
    ref = psi4.wavefunction()
    eps_a = ref.epsilon_a()
    eps_b = ref.epsilon_b()
    E_HOMO = 0.0;
    if (Nb == 0):
        E_HOMO = eps_a[int(Na-1)]
    else:
        E_a = eps_a[int(Na - 1)]
        E_b = eps_b[int(Nb - 1)]
        if (E_a >= E_b):
            E_HOMO = E_a;
        else:
            E_HOMO = E_b;
    E_HOMOl = E_HOMO;
    psi4.IO.change_file_namespace(180,"ot","neutral")

    # Cation
    psi4.IO.change_file_namespace(180,"cation","ot")
    mol.set_molecular_charge(charge1)
    mol.set_multiplicity(mult1)
    psi4.print_out('\n\t==> IP Fitting SCF: Cation, Left Endpoint <==\n')
    E1l = energy('scf')
    psi4.IO.change_file_namespace(180,"ot","cation")

    IPl = E1l - E0l;
    kIPl = -E_HOMOl;
    delta_l = IPl - kIPl;

    if (IPl < kIPl):
        psi4.print_out('\n***IP Fitting Error: Left Omega limit should have kIP < IP')
        sys.exit(1)

    omegas.append(omega_l)
    types.append('Left Limit')
    E0s.append(E0l)
    E1s.append(E1l)
    IPs.append(IPl)
    kIPs.append(kIPl)

    converged = False
    repeat_l = 0;
    repeat_r = 0;
    step = 0;
    while True:

        step = step + 1;

        # Regula Falsi (modified)
        if (repeat_l > 1):
            delta_l = delta_l / 2.0;
        if (repeat_r > 1):
            delta_r = delta_r / 2.0;
        omega = - (omega_r - omega_l) / (delta_r - delta_l) * delta_l + omega_l;
        psi4.set_global_option('DFT_OMEGA',omega)

        # Neutral
        psi4.IO.change_file_namespace(180,"neutral","ot")
        mol.set_molecular_charge(charge0)
        mol.set_multiplicity(mult0)
        psi4.print_out('\n\t==> IP Fitting SCF: Neutral, Omega = %11.3E <==\n' % omega)
        E0 = energy('scf')
        ref = psi4.wavefunction()
        eps_a = ref.epsilon_a()
        eps_b = ref.epsilon_b()
        E_HOMO = 0.0;
        if (Nb == 0):
            E_HOMO = eps_a[int(Na-1)]
        else:
            E_a = eps_a[int(Na - 1)]
            E_b = eps_b[int(Nb - 1)]
            if (E_a >= E_b):
                E_HOMO = E_a;
            else:
                E_HOMO = E_b;
        psi4.IO.change_file_namespace(180,"ot","neutral")

        # Cation
        psi4.IO.change_file_namespace(180,"cation","ot")
        mol.set_molecular_charge(charge1)
        mol.set_multiplicity(mult1)
        psi4.print_out('\n\t==> IP Fitting SCF: Cation, Omega = %11.3E <==\n' % omega)
        E1 = energy('scf')
        psi4.IO.change_file_namespace(180,"ot","cation")

        IP = E1 - E0;
        kIP = -E_HOMO;
        delta = IP - kIP;

        if (kIP > IP):
            omega_r = omega
            E0r = E0
            E1r = E1
            IPr = IP
            kIPr = kIP
            delta_r = delta
            repeat_r = 0;
            repeat_l = repeat_l + 1;
        else:
            omega_l = omega
            E0l = E0
            E1l = E1
            IPl = IP
            kIPl = kIP
            delta_l = delta
            repeat_l = 0;
            repeat_r = repeat_r + 1;

        omegas.append(omega)
        types.append('Regula-Falsi')
        E0s.append(E0)
        E1s.append(E1)
        IPs.append(IP)
        kIPs.append(kIP)

        # Termination
        if (abs(omega_l - omega_r) < omega_tol or step > maxiter):
            converged = True;
            break

    psi4.IO.set_default_namespace("")

    psi4.print_out('\n\t==> IP Fitting Results <==\n\n')

    psi4.print_out('\t => Occupation Determination <= \n\n')
    psi4.print_out('\t          %6s %6s %6s %6s %6s %6s\n' %('N', 'Na', 'Nb', 'Charge', 'Mult', 'H**O'))
    psi4.print_out('\t Neutral: %6d %6d %6d %6d %6d %6d\n' %(N, Na, Nb, charge0, mult0, H**O))
    psi4.print_out('\t Cation:  %6d %6d %6d %6d %6d\n\n' %(N-1, Na1, Nb1, charge1, mult1))

    psi4.print_out('\t => Regula Falsi Iterations <=\n\n')
    psi4.print_out('\t%3s %11s %14s %14s %14s %s\n' % ('N','Omega','IP','kIP','Delta','Type'))
    for k in range(len(omegas)):
        psi4.print_out('\t%3d %11.3E %14.6E %14.6E %14.6E %s\n' % (k+1,omegas[k],IPs[k],kIPs[k],IPs[k] - kIPs[k], types[k]))
    if (converged):
        psi4.print_out('\n\tIP Fitting Converged\n')
        psi4.print_out('\tFinal omega = %14.6E\n' % ((omega_l + omega_r) / 2))
        psi4.print_out('\n\t"M,I. does the dying. Fleet just does the flying."\n')
        psi4.print_out('\t\t\t-Starship Troopers\n')

    else:
        psi4.print_out('\n\tIP Fitting did not converge!\n')

    psi4.set_global_option("DF_INTS_IO", "NONE")
    psi4.set_global_option("GUESS", old_guess)
Пример #24
0
 def __init__(self, msg):
     PsiException.__init__(self, msg)
     self.msg = msg
     psi4.print_out('\nPsiException: %s\n\n' % (msg))
Пример #25
0
    def ccsd_energy(self):
        indx, Ep1, Ep2, g = self.indx, self.Ep1, self.Ep2, self.g
        t1 = indx.zeros('ia')
        t2 = indx.einsum('ijab', (g, "ijab"), (Ep2, "ijab"))

        for i in range(maxiter):

            t1 = Ep1 * indx.meinsums(
                'ia',  # Crawford p. 59
                [1., I, (g, "kaci"), (t1, "kc")],
                [1. / 2, I, (g, "kacd"), (t2, "kicd")],
                [-1. / 2, I, (g, "klci"), (t2, "klca")],
                [-1., I, (g, "klci"), (t1, "kc"), (t1, "la")],
                [1., I, (g, "kacd"), (t1, "kc"), (t1, "id")],
                [-1., I, (g, "klcd"), (t1, "kc"), (t1, "id"), (t1, "la")],
                [1., I, (g, "klcd"), (t1, "kc"), (t2, "lida")],
                [-1. / 2, I, (g, "klcd"), (t2, "kicd"), (t1, "la")],
                [-1. / 2, I, (g, "klcd"), (t2, "klca"), (t1, "id")])

            t2 = Ep2 * indx.meinsums(
                'ijab',  # Crawford, p. 59-60
                [1., I, (g, "abij")],
                [1. / 2, I, (g, "klij"), (t2, "klab")],
                [1. / 2, I, (g, "abcd"), (t2, "ijcd")],
                [1., P("ij|ab"), (g, "kbcj"), (t2, "ikac")],
                [1., P("ij"), (g, "abcj"), (t1, "ic")],
                [-1., P("ab"), (g, "kbij"), (t1, "ka")],
                [1. / 2,
                 P("ij|ab"), (g, "klcd"), (t2, "ikac"), (t2, "ljdb")],
                [1. / 4, I, (g, "klcd"), (t2, "ijcd"), (t2, "klab")],
                [-1. / 2,
                 P("ab"), (g, "klcd"), (t2, "ijac"), (t2, "klbd")],
                [-1. / 2,
                 P("ij"), (g, "klcd"), (t2, "ikab"), (t2, "jlcd")],
                [1. / 2, P("ab"), (g, "klij"), (t1, "ka"), (t1, "lb")],
                [1. / 2, P("ij"), (g, "abcd"), (t1, "ic"), (t1, "jd")],
                [-1., P("ij|ab"), (g, "kbic"), (t1, "ka"), (t1, "jc")],
                [-1., P("ij"), (g, "klci"), (t1, "kc"), (t2, "ljab")],
                [1., P("ab"), (g, "kacd"), (t1, "kc"), (t2, "ijdb")],
                [1., P("ij|ab"), (g, "akdc"), (t1, "id"), (t2, "jkbc")],
                [1., P("ij|ab"), (g, "klic"), (t1, "la"), (t2, "jkbc")],
                [1. / 2,
                 P("ij"), (g, "klcj"), (t1, "ic"), (t2, "klab")],
                [-1. / 2,
                 P("ab"), (g, "kbcd"), (t1, "ka"), (t2, "ijcd")],
                [
                    -1. / 2,
                    P("ij|ab"), (g, "kbcd"), (t1, "ic"), (t1, "ka"), (t1, "jd")
                ],
                [
                    1. / 2,
                    P("ij|ab"), (g, "klcj"), (t1, "ic"), (t1, "ka"), (t1, "lb")
                ],
                [
                    -1.,
                    P("ij"), (g, "klcd"), (t1, "kc"), (t1, "id"), (t2, "ljab")
                ],
                [
                    -1.,
                    P("ab"), (g, "klcd"), (t1, "kc"), (t1, "la"), (t2, "ijdb")
                ],
                [
                    1. / 4,
                    P("ij"), (g, "klcd"), (t1, "ic"), (t1, "jd"), (t2, "klab")
                ],
                [
                    1. / 4,
                    P("ab"), (g, "klcd"), (t1, "ka"), (t1, "lb"), (t2, "ijcd")
                ],
                [
                    1.,
                    P("ij|ab"), (g, "klcd"), (t1, "ic"), (t1, "lb"),
                    (t2, "kjad")
                ],
                [
                    1. / 4,
                    P("ij|ab"), (g, "klcd"), (t1, "ic"), (t1, "ka"),
                    (t1, "jd"), (t1, "lb")
                ])

            E = indx.meinsums('', [1. / 4, I, (g, "ijab"), (t2, "ijab")],
                              [1. / 2, I, (g, "ijab"), (t1, "ia"), (t1, "jb")])
            dE = E - self.E
            self.E = E

            psi4.print_out('\n@CCSD{:-3d}{:20.15f}{:20.15f}'.format(i, E, dE))
            if (abs(dE) < econv): break

        return self.E
Пример #26
0
def anharmonicity(rvals, energies, mol=None):
    """Generates spectroscopic constants for a diatomic molecules.
       Fits a diatomic potential energy curve using either a 5 or 9 point Legendre fit, locates the minimum
       energy point, and then applies second order vibrational perturbation theory to obtain spectroscopic
       constants.  The r values provided must bracket the minimum energy point, or an error will result.

       A dictionary with the following keys, which correspond to spectroscopic constants, is returned:

       :type rvals: list
       :param rvals: The bond lengths (in Angstrom) for which energies are
           provided of length either 5 or 9 but must be the same length as
           the energies array

       :type energies: list
       :param energies: The energies (Eh) computed at the bond lengths in the rvals list

       :returns: (*dict*) Keys: "re", "r0", "we", "wexe", "nu", "ZPVE(harmonic)", "ZPVE(anharmonic)", "Be", "B0", "ae", "De"
                 corresponding to the spectroscopic constants in cm-1
    """

    angstrom_to_bohr = 1.0 / p4const.psi_bohr2angstroms
    angstrom_to_meter = 10e-10

    if len(rvals) != len(energies):
        raise Exception(
            "The number of energies must match the number of distances")

    npoints = len(rvals)

    if npoints != 5 and npoints != 9:
        raise Exception("Only 5- or 9-point fits are implemented right now")

    psi4.print_out("\n\nPerforming a %d-point fit\n" % npoints)

    psi4.print_out("\nOptimizing geometry based on current surface:\n\n")
    if (npoints == 5):
        optx = rvals[2]
    elif (npoints == 9):
        optx = rvals[4]

    # Molecule can be passed in be user. Look at the function definition above.
    if mol == None:
        mol = psi4.get_active_molecule()
    natoms = mol.natom()
    if natoms != 2:
        raise Exception(
            "The current molecule must be a diatomic for this code to work!")
    m1 = mol.mass(0)
    m2 = mol.mass(1)

    maxit = 30
    thres = 1.0e-9
    for i in range(maxit):
        if (npoints == 5):
            grad = first_deriv_5pt(rvals, energies, optx)
            secd = second_deriv_5pt(rvals, energies, optx)
            energy = function_5pt(rvals, energies, optx)
        elif (npoints == 9):
            grad = first_deriv_9pt(rvals, energies, optx)
            secd = second_deriv_9pt(rvals, energies, optx)
            energy = function_9pt(rvals, energies, optx)
        psi4.print_out("       E = %20.14f, x = %14.7f, grad = %20.14f\n" %
                       (energy, optx, grad))
        if abs(grad) < thres:
            break
        optx -= grad / secd
    psi4.print_out(" Final E = %20.14f, x = %14.7f, grad = %20.14f\n" %
                   (function_5pt(rvals, energies, optx), optx, grad))

    if optx < min(rvals):
        raise Exception(
            "Minimum energy point is outside range of points provided.  Use a lower range of r values."
        )
    if optx > max(rvals):
        raise Exception(
            "Minimum energy point is outside range of points provided.  Use a higher range of r values."
        )

    if (npoints == 5):
        energy = function_5pt(rvals, energies, optx)
        first = first_deriv_5pt(rvals, energies, optx)
        secd = second_deriv_5pt(rvals, energies, optx) * p4const.psi_hartree2aJ
        third = third_deriv_5pt(rvals, energies, optx) * p4const.psi_hartree2aJ
        fourth = fourth_deriv_5pt(rvals, energies,
                                  optx) * p4const.psi_hartree2aJ
    elif (npoints == 9):
        energy = function_9pt(rvals, energies, optx)
        first = first_deriv_9pt(rvals, energies, optx)
        secd = second_deriv_9pt(rvals, energies, optx) * p4const.psi_hartree2aJ
        third = third_deriv_9pt(rvals, energies, optx) * p4const.psi_hartree2aJ
        fourth = fourth_deriv_9pt(rvals, energies,
                                  optx) * p4const.psi_hartree2aJ

    psi4.print_out("\nEquilibrium Energy %20.14f Hartrees\n" % energy)
    psi4.print_out("Gradient           %20.14f\n" % first)
    psi4.print_out("Quadratic Force Constant %14.7f MDYNE/A\n" % secd)
    psi4.print_out("Cubic Force Constant     %14.7f MDYNE/A**2\n" % third)
    psi4.print_out("Quartic Force Constant   %14.7f MDYNE/A**3\n" % fourth)

    hbar = p4const.psi_h / (2.0 * pi)
    mu = ((m1 * m2) / (m1 + m2)) * p4const.psi_amu2kg
    we = 5.3088375e-11 * sqrt(secd / mu)
    wexe = (1.2415491e-6) * (we / secd)**2 * ((5.0 * third * third) /
                                              (3.0 * secd) - fourth)

    # Rotational constant: Be
    I = ((m1 * m2) /
         (m1 + m2)) * p4const.psi_amu2kg * (optx * angstrom_to_meter)**2
    B = p4const.psi_h / (8.0 * pi**2 * p4const.psi_c * I)

    # alpha_e and quartic centrifugal distortion constant
    ae = -(6.0 * B**2 / we) * ((1.05052209e-3 * we * third) /
                               (sqrt(B * secd**3)) + 1.0)
    de = 4.0 * B**3 / we**2

    # B0 and r0 (plus re check using Be)
    B0 = B - ae / 2.0
    r0 = sqrt(p4const.psi_h / (8.0 * pi**2 * mu * p4const.psi_c * B0))
    recheck = sqrt(p4const.psi_h / (8.0 * pi**2 * mu * p4const.psi_c * B))
    r0 /= angstrom_to_meter
    recheck /= angstrom_to_meter

    # Fundamental frequency nu
    nu = we - 2.0 * wexe
    zpve_nu = 0.5 * we - 0.25 * wexe

    psi4.print_out("\nre     = %10.6f A  check: %10.6f\n" % (optx, recheck))
    psi4.print_out("r0       = %10.6f A\n" % r0)
    psi4.print_out("we       = %10.4f cm-1\n" % we)
    psi4.print_out("wexe     = %10.4f cm-1\n" % wexe)
    psi4.print_out("nu       = %10.4f cm-1\n" % nu)
    psi4.print_out("ZPVE(nu) = %10.4f cm-1\n" % zpve_nu)
    psi4.print_out("Be       = %10.4f cm-1\n" % B)
    psi4.print_out("B0       = %10.4f cm-1\n" % B0)
    psi4.print_out("ae       = %10.4f cm-1\n" % ae)
    psi4.print_out("De       = %10.7f cm-1\n" % de)
    results = {
        "re": optx,
        "r0": r0,
        "we": we,
        "wexe": wexe,
        "nu": nu,
        "ZPVE(harmonic)": zpve_nu,
        "ZPVE(anharmonic)": zpve_nu,
        "Be": B,
        "B0": B0,
        "ae": ae,
        "De": de
    }
    return results
Пример #27
0
def run_roa(name, **kwargs):
    """
        Main driver for managing Raman Optical activity computations with
        CC response theory.

        Uses distributed finite differences approach -->
            1. Sets up a database to keep track of running/finished/waiting
                computations.
            2. Generates separate input files for displaced geometries.
            3. When all displacements are run, collects the necessary information
                from each displaced computation, and computes final result.
    """

    # Get list of omega values -> Make sure we only have one wavelength
    # Catch this now before any real work gets done
    omega = psi4.get_option('CCRESPONSE', 'OMEGA')
    if len(omega) > 2:
        raise Exception(
            'ROA scattering can only be performed for one wavelength.')
    else:
        pass

    psi4.print_out('Running ROA computation. Subdirectories for each '
                   'required displaced geometry have been created.\n\n')

    dbno = 0
    # Initialize database
    db = shelve.open('database', writeback=True)
    # Check if final result is in here
    # ->if we have already computed roa, back up the dict
    # ->copy it setting this flag to false and continue
    if ('roa_computed' in db) and (db['roa_computed']):
        db2 = shelve.open('.database.bak{}'.format(dbno), writeback=True)
        dbno += 1
        for key, value in db.iteritems():
            db2[key] = value

        db2.close()
        db['roa_computed'] = False
    else:
        db['roa_computed'] = False

    if 'inputs_generated' not in db:
        findif_response_utils.initialize_database(db, name, "roa",
                                                  ["roa_tensor"])

    # Generate input files
    if not db['inputs_generated']:
        findif_response_utils.generate_inputs(db, name)
        # handled by helper db['inputs_generated'] = True

    # Check job status
    if db['inputs_generated'] and not db['jobs_complete']:
        print('Checking status')
        findif_response_utils.stat(db)
        for job, status in db['job_status'].items():
            print("{} --> {}".format(job, status))

    # Compute ROA Scattering
    if db['jobs_complete']:
        mygauge = psi4.get_option('CCRESPONSE', 'GAUGE')
        consider_gauge = {
            'LENGTH': ['Length Gauge'],
            'VELOCITY': ['Modified Velocity Gauge'],
            'BOTH': ['Length Gauge', 'Modified Velocity Gauge']
        }
        gauge_list = ["{} Results".format(x) for x in consider_gauge[mygauge]]
        # Gather data
        dip_polar_list = findif_response_utils.collect_displaced_matrix_data(
            db, 'Dipole Polarizability', 3)
        opt_rot_list = [
            x for x in (findif_response_utils.collect_displaced_matrix_data(
                db, "Optical Rotation Tensor ({})".format(gauge), 3)
                        for gauge in consider_gauge[mygauge])
        ]
        dip_quad_polar_list = findif_response_utils.collect_displaced_matrix_data(
            db, "Electric-Dipole/Quadrupole Polarizability", 9)
        # Compute Scattering
        # Run new function (src/bin/ccresponse/scatter.cc)
        psi4.print_out('Running scatter function')
        step = psi4.get_local_option('FINDIF', 'DISP_SIZE')
        for g_idx, gauge in enumerate(opt_rot_list):
            print(
                '\n\n----------------------------------------------------------------------'
            )
            print('\t%%%%%%%%%% {} %%%%%%%%%%'.format(gauge_list[g_idx]))
            print(
                '----------------------------------------------------------------------\n\n'
            )
            psi4.print_out(
                '\n\n----------------------------------------------------------------------\n'
            )
            psi4.print_out('\t%%%%%%%%%% {} %%%%%%%%%%\n'.format(
                gauge_list[g_idx]))
            psi4.print_out(
                '----------------------------------------------------------------------\n\n'
            )
            print(
                'roa.py:85 I am not being passed a molecule, grabbing from global :('
            )
            psi4.scatter(psi4.get_active_molecule(), step, dip_polar_list,
                         gauge, dip_quad_polar_list)

        db['roa_computed'] = True

    db.close()
Пример #28
0
def frac_traverse(molecule, **kwargs):
    kwargs = p4util.kwargs_lower(kwargs)

    # The molecule is required, and should be the neutral species
    molecule.update_geometry()
    charge0 = molecule.molecular_charge()
    mult0 = molecule.multiplicity()

    chargep = charge0 + 1
    chargem = charge0 - 1

    # By default, the multiplicity of the cation/anion are mult0 + 1
    # These are overridden with the cation_mult and anion_mult kwargs
    multp = kwargs.get('cation_mult', mult0 + 1)
    multm = kwargs.get('anion_mult', mult0 + 1)

    # By default, we start the frac procedure on the 25th iteration
    # when not reading a previous guess
    frac_start = kwargs.get('frac_start', 25)

    # By default, we occupy by tenths of electrons
    HOMO_occs = kwargs.get(
        'HOMO_occs', [1.0, 0.9, 0.8, 0.7, 0.6, 0.5, 0.4, 0.3, 0.2, 0.1, 0.0])
    LUMO_occs = kwargs.get(
        'LUMO_occs', [1.0, 0.9, 0.8, 0.7, 0.6, 0.5, 0.4, 0.3, 0.2, 0.1, 0.0])

    # By default, H**O and LUMO are both in alpha
    Z = 0
    for A in range(molecule.natom()):
        Z += molecule.Z(A)
    Z -= charge0
    H**O = kwargs.get('H**O', (Z / 2 + 1 if (Z % 2) else Z / 2))
    LUMO = kwargs.get('LUMO', H**O + 1)

    # By default, DIIS in FRAC (1.0 occupation is always DIIS'd)
    frac_diis = kwargs.get('frac_diis', True)

    # By default, use the neutral orbitals as a guess for the anion
    neutral_guess = kwargs.get('neutral_guess', True)

    # By default, burn-in with UHF first, if UKS
    hf_guess = False
    if psi4.get_global_option('REFERENCE') == 'UKS':
        hf_guess = kwargs.get('hf_guess', True)

    # By default, re-guess at each N
    continuous_guess = kwargs.get('continuous_guess', False)

    # By default, drop the files to the molecule's name
    root = kwargs.get('filename', molecule.name())
    traverse_filename = root + '.traverse.dat'
    # => Traverse <= #
    occs = []
    energies = []
    potentials = []
    convs = []

    # => Run the neutral for its orbitals, if requested <= #

    old_df_ints_io = psi4.get_global_option("DF_INTS_IO")
    psi4.set_global_option("DF_INTS_IO", "SAVE")

    old_guess = psi4.get_global_option("GUESS")
    if (neutral_guess):
        if (hf_guess):
            psi4.set_global_option("REFERENCE", "UHF")
        energy('scf')
        psi4.set_global_option("GUESS", "READ")
        psi4.set_global_option("DF_INTS_IO", "LOAD")

    # => Run the anion first <= #

    molecule.set_molecular_charge(chargem)
    molecule.set_multiplicity(multm)

    # => Burn the anion in with hf, if requested <= #
    if hf_guess:
        psi4.set_global_option("REFERENCE", "UHF")
        energy('scf', molecule=molecule, **kwargs)
        psi4.set_global_option("REFERENCE", "UKS")
        psi4.set_global_option("GUESS", "READ")
        psi4.set_global_option("DF_INTS_IO", "SAVE")

    psi4.set_global_option("FRAC_START", frac_start)
    psi4.set_global_option("FRAC_RENORMALIZE", True)
    psi4.set_global_option("FRAC_LOAD", False)

    for occ in LUMO_occs:

        psi4.set_global_option("FRAC_OCC", [LUMO])
        psi4.set_global_option("FRAC_VAL", [occ])

        E, wfn = energy('scf', return_wfn=True, molecule=molecule, **kwargs)
        C = 1
        if E == 0.0:
            E = psi4.get_variable('SCF ITERATION ENERGY')
            C = 0

        if LUMO > 0:
            eps = wfn.epsilon_a()
            potentials.append(eps[int(LUMO) - 1])
        else:
            eps = wfn.epsilon_b()
            potentials.append(eps[-int(LUMO) - 1])

        occs.append(occ)
        energies.append(E)
        convs.append(C)

        psi4.set_global_option("FRAC_START", 2)
        psi4.set_global_option("FRAC_LOAD", True)
        psi4.set_global_option("GUESS", "READ")
        psi4.set_global_option("FRAC_DIIS", frac_diis)
        psi4.set_global_option("DF_INTS_IO", "LOAD")

    # => Run the neutral next <= #

    molecule.set_molecular_charge(charge0)
    molecule.set_multiplicity(mult0)

    # Burn the neutral in with hf, if requested <= #

    if not continuous_guess:
        psi4.set_global_option("GUESS", old_guess)
        if hf_guess:
            psi4.set_global_option("FRAC_START", 0)
            psi4.set_global_option("REFERENCE", "UHF")
            energy('scf', molecule=molecule, **kwargs)
            psi4.set_global_option("REFERENCE", "UKS")
            psi4.set_global_option("GUESS", "READ")
        psi4.set_global_option("FRAC_LOAD", False)

    psi4.set_global_option("FRAC_START", frac_start)
    psi4.set_global_option("FRAC_RENORMALIZE", True)

    for occ in HOMO_occs:

        psi4.set_global_option("FRAC_OCC", [H**O])
        psi4.set_global_option("FRAC_VAL", [occ])

        E, wfn = energy('scf', return_wfn=True, molecule=molecule, **kwargs)
        C = 1
        if E == 0.0:
            E = psi4.get_variable('SCF ITERATION ENERGY')
            C = 0

        if LUMO > 0:
            eps = wfn.epsilon_a()
            potentials.append(eps[int(H**O) - 1])
        else:
            eps = wfn.epsilon_b()
            potentials.append(eps[-int(H**O) - 1])

        occs.append(occ - 1.0)
        energies.append(E)
        convs.append(C)

        psi4.set_global_option("FRAC_START", 2)
        psi4.set_global_option("FRAC_LOAD", True)
        psi4.set_global_option("GUESS", "READ")
        psi4.set_global_option("FRAC_DIIS", frac_diis)
        psi4.set_global_option("DF_INTS_IO", "LOAD")

    psi4.set_global_option("DF_INTS_IO", old_df_ints_io)

    # => Print the results out <= #
    E = {}
    psi4.print_out(
        """\n    ==> Fractional Occupation Traverse Results <==\n\n""")
    psi4.print_out("""\t%-11s %-24s %-24s %11s\n""" %
                   ('N', 'Energy', 'H**O Energy', 'Converged'))
    for k in range(len(occs)):
        psi4.print_out("""\t%11.3E %24.16E %24.16E %11d\n""" %
                       (occs[k], energies[k], potentials[k], convs[k]))
        E[occs[k]] = energies[k]

    psi4.print_out('\n\t"You trying to be a hero Watkins?"\n')
    psi4.print_out('\t"Just trying to kill some bugs sir!"\n')
    psi4.print_out('\t\t\t-Starship Troopers\n')

    # Drop the files out
    fh = open(traverse_filename, 'w')
    fh.write("""\t%-11s %-24s %-24s %11s\n""" %
             ('N', 'Energy', 'H**O Energy', 'Converged'))
    for k in range(len(occs)):
        fh.write("""\t%11.3E %24.16E %24.16E %11d\n""" %
                 (occs[k], energies[k], potentials[k], convs[k]))
    fh.close()

    # Properly, should clone molecule but since not returned and easy to unblemish,
    molecule.set_molecular_charge(charge0)
    molecule.set_multiplicity(mult0)

    return E
Пример #29
0
def run_roa(name, **kwargs):

    # Get list of omega values -> Make sure we only have one wavelength
    # Catch this now before any real work gets done
    omega = psi4.get_option('CCRESPONSE', 'OMEGA')
    if len(omega) > 2:
        raise Exception(
            'ROA scattering can only be performed for one wavelength.')
    else:
        pass

    psi4.print_out('Running ROA computation. Subdirectories for each '
                   'required displaced geometry have been created.\n\n')

    ### Initialize database
    db = shelve.open('database', writeback=True)
    if 'inputs_generated' not in db:
        initialize_database(db)

    ### Generate input files
    if not db['inputs_generated']:
        generate_inputs(name, db)
        db['inputs_generated'] = True

    ### If 'serial' calculation, proceed with subdir execution

    ### Check job status
    if db['inputs_generated'] and not db['jobs_complete']:
        print('Checking status')
        roa_stat(db)
        for job, status in db['job_status'].items():
            print("{} --> {}".format(job, status))

    ### Compute ROA Scattering
    if db['jobs_complete']:
        #   SAVE this for when multiple wavelengths works
        #        # Get list of omega values
        #        omega = psi4.get_option('CCRESPONSE','OMEGA')
        #        if len(omega) > 1:
        #            units = copy.copy(omega[-1])
        #            omega.pop()
        #        else:
        #            units = 'atomic'
        #        wavelength = copy.copy(omega[0])
        #        # Set up units for scatter.cc
        #        if units == 'NM':
        #            wavelength = (psi_c * psi_h * 1*(10**-9))/(wavelength * psi_hartree2J)
        #        if units == 'HZ':
        #            wavelength = wavelength * psi_h / psi_hartree2J
        #        if units == 'EV':
        #            wavelength = wavelength / psi_hartree2ev
        #        if units == 'atomic':
        #            pass
        # Initialize tensor lists
        dip_polar_list = []
        opt_rot_list = []
        dip_quad_polar_list = []
        gauge_list = []
        make_gauge_list(gauge_list)
        # Gather data
        synthesize_dipole_polar(db, dip_polar_list)
        synthesize_opt_rot(db, opt_rot_list)
        synthesize_dip_quad_polar(db, dip_quad_polar_list)
        # Compute Scattering
        # Run new function (src/bin/ccresponse/scatter.cc)
        psi4.print_out('Running scatter function')
        step = psi4.get_local_option('FINDIF', 'DISP_SIZE')
        for gauge in opt_rot_list:
            g_idx = opt_rot_list.index(gauge)
            #            print('\n\n----------------------------------------------------------------------')
            #            print('\t%%%%%%%%%% {} %%%%%%%%%%'.format(gauge_list[g_idx]))
            #            print('----------------------------------------------------------------------\n\n')
            psi4.print_out(
                '\n\n----------------------------------------------------------------------\n'
            )
            psi4.print_out('\t%%%%%%%%%% {} %%%%%%%%%%\n'.format(
                gauge_list[g_idx]))
            psi4.print_out(
                '----------------------------------------------------------------------\n\n'
            )
            psi4.scatter(step, dip_polar_list, gauge, dip_quad_polar_list)

    db.close()
Пример #30
0
def anharmonicity(rvals, energies, mol = None):
    """Generates spectroscopic constants for a diatomic molecules.
       Fits a diatomic potential energy curve using either a 5 or 9 point Legendre fit, locates the minimum
       energy point, and then applies second order vibrational perturbation theory to obtain spectroscopic
       constants.  The r values provided must bracket the minimum energy point, or an error will result.

       A dictionary with the following keys, which correspond to spectroscopic constants, is returned:

       :type rvals: list
       :param rvals: The bond lengths (in Angstrom) for which energies are
           provided of length either 5 or 9 but must be the same length as
           the energies array

       :type energies: list
       :param energies: The energies (Eh) computed at the bond lengths in the rvals list

       :returns: (*dict*) Keys: "re", "r0", "we", "wexe", "nu", "ZPVE(harmonic)", "ZPVE(anharmonic)", "Be", "B0", "ae", "De"
                 corresponding to the spectroscopic constants in cm-1
    """

    angstrom_to_bohr = 1.0 / p4const.psi_bohr2angstroms
    angstrom_to_meter = 10e-10;

    if len(rvals) != len(energies):
        raise Exception("The number of energies must match the number of distances")

    npoints = len(rvals)

    if npoints != 5 and npoints != 9:
        raise Exception("Only 5- or 9-point fits are implemented right now")

    psi4.print_out("\n\nPerforming a %d-point fit\n" % npoints)

    psi4.print_out("\nOptimizing geometry based on current surface:\n\n");
    if (npoints == 5):
        optx = rvals[2]
    elif (npoints == 9):
        optx = rvals[4]

    # Molecule can be passed in be user. Look at the function definition above.
    if mol == None:
        mol = psi4.get_active_molecule()
    natoms = mol.natom()
    if natoms != 2:
        raise Exception("The current molecule must be a diatomic for this code to work!")
    m1 = mol.mass(0)
    m2 = mol.mass(1)

    maxit = 30
    thres = 1.0e-9
    for i in range(maxit):
        if (npoints == 5):
            grad= first_deriv_5pt(rvals, energies, optx)
            secd = second_deriv_5pt(rvals, energies, optx)
            energy = function_5pt(rvals, energies, optx)
        elif (npoints == 9):
            grad = first_deriv_9pt(rvals, energies, optx)
            secd = second_deriv_9pt(rvals, energies, optx)
            energy = function_9pt(rvals, energies, optx)
        psi4.print_out("       E = %20.14f, x = %14.7f, grad = %20.14f\n" % (energy, optx, grad))
        if abs(grad) < thres:
            break
        optx -= grad / secd;
    psi4.print_out(" Final E = %20.14f, x = %14.7f, grad = %20.14f\n" % (function_5pt(rvals, energies, optx), optx, grad));

    if optx < min(rvals):
        raise Exception("Minimum energy point is outside range of points provided.  Use a lower range of r values.")
    if optx > max(rvals):
        raise Exception("Minimum energy point is outside range of points provided.  Use a higher range of r values.")

    if (npoints == 5):
        energy = function_5pt(rvals, energies, optx)
        first = first_deriv_5pt(rvals, energies, optx)
        secd = second_deriv_5pt(rvals, energies, optx) * p4const.psi_hartree2aJ
        third = third_deriv_5pt(rvals, energies, optx) * p4const.psi_hartree2aJ
        fourth = fourth_deriv_5pt(rvals, energies, optx) * p4const.psi_hartree2aJ
    elif (npoints == 9):
        energy = function_9pt(rvals, energies, optx)
        first = first_deriv_9pt(rvals, energies, optx)
        secd = second_deriv_9pt(rvals, energies, optx) * p4const.psi_hartree2aJ
        third = third_deriv_9pt(rvals, energies, optx) * p4const.psi_hartree2aJ
        fourth = fourth_deriv_9pt(rvals, energies, optx) * p4const.psi_hartree2aJ

    psi4.print_out("\nEquilibrium Energy %20.14f Hartrees\n" % energy)
    psi4.print_out("Gradient           %20.14f\n" % first)
    psi4.print_out("Quadratic Force Constant %14.7f MDYNE/A\n" % secd)
    psi4.print_out("Cubic Force Constant     %14.7f MDYNE/A**2\n" % third)
    psi4.print_out("Quartic Force Constant   %14.7f MDYNE/A**3\n" % fourth)

    hbar = p4const.psi_h / (2.0 * pi)
    mu = ((m1*m2)/(m1+m2))*p4const.psi_amu2kg
    we = 5.3088375e-11*sqrt(secd/mu)
    wexe = (1.2415491e-6)*(we/secd)**2 * ((5.0*third*third)/(3.0*secd)-fourth)

    # Rotational constant: Be
    I = ((m1*m2)/(m1+m2)) * p4const.psi_amu2kg * (optx * angstrom_to_meter)**2
    B = p4const.psi_h / (8.0 * pi**2 * p4const.psi_c * I)

    # alpha_e and quartic centrifugal distortion constant
    ae = -(6.0 * B**2 / we) * ((1.05052209e-3*we*third)/(sqrt(B * secd**3))+1.0)
    de = 4.0*B**3 / we**2

    # B0 and r0 (plus re check using Be)
    B0 = B - ae / 2.0
    r0 = sqrt(p4const.psi_h / (8.0 * pi**2 * mu * p4const.psi_c * B0))
    recheck = sqrt(p4const.psi_h / (8.0 * pi**2 * mu * p4const.psi_c * B))
    r0 /= angstrom_to_meter;
    recheck /= angstrom_to_meter;

    # Fundamental frequency nu
    nu = we - 2.0 * wexe;
    zpve_nu = 0.5 * we - 0.25 * wexe;

    psi4.print_out("\nre     = %10.6f A  check: %10.6f\n" % (optx, recheck))
    psi4.print_out("r0       = %10.6f A\n" % r0)
    psi4.print_out("we       = %10.4f cm-1\n" % we)
    psi4.print_out("wexe     = %10.4f cm-1\n" % wexe)
    psi4.print_out("nu       = %10.4f cm-1\n" % nu)
    psi4.print_out("ZPVE(nu) = %10.4f cm-1\n" % zpve_nu)
    psi4.print_out("Be       = %10.4f cm-1\n" % B)
    psi4.print_out("B0       = %10.4f cm-1\n" % B0)
    psi4.print_out("ae       = %10.4f cm-1\n" % ae)
    psi4.print_out("De       = %10.7f cm-1\n" % de)
    results = {
               "re"               :  optx,
               "r0"               :  r0,
               "we"               :  we,
               "wexe"             :  wexe,
               "nu"               :  nu,
               "ZPVE(harmonic)"   :  zpve_nu,
               "ZPVE(anharmonic)" :  zpve_nu,
               "Be"               :  B,
               "B0"               :  B0,
               "ae"               :  ae,
               "De"               :  de
              }
    return results
Пример #31
0
def auto_fragments(**kwargs):
    r"""Detects fragments if the user does not supply them.
    Currently only used for the WebMO implementation of SAPT.

    :returns: :ref:`Molecule<sec:psimod_Molecule>`) |w--w| fragmented molecule.

    :type molecule: :ref:`molecule <op_py_molecule>`
    :param molecule: ``h2o`` || etc.

        The target molecule, if not the last molecule defined.

    :examples:

    >>> # [1] replicates with cbs() the simple model chemistry scf/cc-pVDZ: set basis cc-pVDZ energy('scf')
    >>> molecule mol {\nH 0.0 0.0 0.0\nH 2.0 0.0 0.0\nF 0.0 1.0 0.0\nF 2.0 1.0 0.0\n}
    >>> print mol.nfragments()  # 1
    >>> fragmol = auto_fragments()
    >>> print fragmol.nfragments()  # 2

    """
    # Make sure the molecule the user provided is the active one
    molecule = kwargs.pop('molecule', psi4.get_active_molecule())
    molecule.update_geometry()
    molname = molecule.name()

    geom = molecule.save_string_xyz()

    numatoms = molecule.natom()
    VdW = [1.2, 1.7, 1.5, 1.55, 1.52, 1.9, 1.85, 1.8]

    symbol = list(range(numatoms))
    X = [0.0] * numatoms
    Y = [0.0] * numatoms
    Z = [0.0] * numatoms

    Queue = []
    White = []
    Black = []
    F = geom.split('\n')
    for f in range(numatoms):
        A = F[f + 1].split()
        symbol[f] = A[0]
        X[f] = float(A[1])
        Y[f] = float(A[2])
        Z[f] = float(A[3])
        White.append(f)
    Fragment = [[] for i in range(numatoms)]  # stores fragments

    start = 0  # starts with the first atom in the list
    Queue.append(start)
    White.remove(start)

    frag = 0

    while ((len(White) > 0)
           or (len(Queue) > 0)):  # Iterates to the next fragment
        while (len(Queue) > 0):  # BFS within a fragment
            for u in Queue:  # find all nearest Neighbors
                #   (still coloured white) to vertex u
                for i in White:
                    Distance = math.sqrt((X[i] - X[u]) * (X[i] - X[u]) +
                                         (Y[i] - Y[u]) * (Y[i] - Y[u]) +
                                         (Z[i] - Z[u]) * (Z[i] - Z[u]))
                    if Distance < _autofragment_convert(
                            u, symbol) + _autofragment_convert(i, symbol):
                        Queue.append(i)  # if you find you, put it in the que
                        White.remove(
                            i)  # and remove it from the untouched list
            Queue.remove(u)  # remove focus from Queue
            Black.append(u)
            Fragment[frag].append(int(u +
                                      1))  # add to group (adding 1 to start
            #   list at one instead of zero)

        if (len(White) != 0):  # cant move White->Queue if no more exist
            Queue.append(White[0])
            White.remove(White[0])
        frag += 1

    new_geom = """\n"""
    for i in Fragment[0]:
        new_geom = new_geom + F[i].lstrip() + """\n"""
    new_geom = new_geom + """--\n"""
    for j in Fragment[1]:
        new_geom = new_geom + F[j].lstrip() + """\n"""
    new_geom = new_geom + """units angstrom\n"""

    moleculenew = psi4.Molecule.create_molecule_from_string(new_geom)
    moleculenew.set_name(molname)
    moleculenew.update_geometry()
    moleculenew.print_cluster()
    psi4.print_out("""  Exiting auto_fragments\n""")

    return moleculenew
Пример #32
0
def run_roa(name, **kwargs):
    """
        Main driver for managing Raman Optical activity computations with
        CC response theory.

        Uses distributed finite differences approach -->
            1. Sets up a database to keep track of running/finished/waiting
                computations.
            2. Generates separate input files for displaced geometries.
            3. When all displacements are run, collects the necessary information
                from each displaced computation, and computes final result.
    """

    # Get list of omega values -> Make sure we only have one wavelength
    # Catch this now before any real work gets done
    omega = psi4.get_option('CCRESPONSE', 'OMEGA')
    if len(omega) > 2:
        raise Exception('ROA scattering can only be performed for one wavelength.')
    else:
        pass

    psi4.print_out(
        'Running ROA computation. Subdirectories for each '
        'required displaced geometry have been created.\n\n')

    dbno = 0
    # Initialize database
    db = shelve.open('database', writeback=True)
    # Check if final result is in here
    # ->if we have already computed roa, back up the dict
    # ->copy it setting this flag to false and continue
    if ('roa_computed' in db) and ( db['roa_computed'] ):
        db2 = shelve.open('.database.bak{}'.format(dbno), writeback=True)
        dbno += 1
        for key,value in db.iteritems():
            db2[key]=value

        db2.close()
        db['roa_computed'] = False
    else:
        db['roa_computed'] = False

    if 'inputs_generated' not in db:
        findif_response_utils.initialize_database(db,name,"roa", ["roa_tensor"])

    # Generate input files
    if not db['inputs_generated']:
        findif_response_utils.generate_inputs(db,name)
        # handled by helper db['inputs_generated'] = True

    # Check job status
    if db['inputs_generated'] and not db['jobs_complete']:
        print('Checking status')
        findif_response_utils.stat(db)
        for job, status in db['job_status'].items():
            print("{} --> {}".format(job, status))

    # Compute ROA Scattering
    if db['jobs_complete']:
        mygauge = psi4.get_option('CCRESPONSE', 'GAUGE')
        consider_gauge = {
            'LENGTH': ['Length Gauge'],
            'VELOCITY': ['Modified Velocity Gauge'],
            'BOTH': ['Length Gauge', 'Modified Velocity Gauge']
        }
        gauge_list = ["{} Results".format(x) for x in consider_gauge[mygauge]]
        # Gather data
        dip_polar_list = findif_response_utils.collect_displaced_matrix_data(
            db, 'Dipole Polarizability', 3)
        opt_rot_list = [
            x for x in (
                findif_response_utils.collect_displaced_matrix_data(
                    db,
                    "Optical Rotation Tensor ({})".format(gauge),
                    3
                )
                for gauge in consider_gauge[mygauge]
            )
        ]
        dip_quad_polar_list = findif_response_utils.collect_displaced_matrix_data(
            db, "Electric-Dipole/Quadrupole Polarizability", 9)
        # Compute Scattering
        # Run new function (src/bin/ccresponse/scatter.cc)
        psi4.print_out('Running scatter function')
        step = psi4.get_local_option('FINDIF', 'DISP_SIZE')
        for g_idx, gauge in enumerate(opt_rot_list):
            print('\n\n----------------------------------------------------------------------')
            print('\t%%%%%%%%%% {} %%%%%%%%%%'.format(gauge_list[g_idx]))
            print('----------------------------------------------------------------------\n\n')
            psi4.print_out('\n\n----------------------------------------------------------------------\n')
            psi4.print_out('\t%%%%%%%%%% {} %%%%%%%%%%\n'.format(gauge_list[g_idx]))
            psi4.print_out('----------------------------------------------------------------------\n\n')
            print('roa.py:85 I am not being passed a molecule, grabbing from global :(')
            psi4.scatter(psi4.get_active_molecule(), step, dip_polar_list, gauge, dip_quad_polar_list)

        db['roa_computed'] = True

    db.close()
Пример #33
0
 def __init__(self, msg):
     PsiException.__init__(self, msg)
     self.message = msg
     psi4.print_out('\nCSXException: %s\n\n' % (msg))
Пример #34
0
def run_dftd3(self, func=None, dashlvl=None, dashparam=None, dertype=None, verbose=False):
    """Function to call Grimme's dftd3 program (http://toc.uni-muenster.de/DFTD3/)
    to compute the -D correction of level *dashlvl* using parameters for
    the functional *func*. The dictionary *dashparam* can be used to supply
    a full set of dispersion parameters in the absense of *func* or to supply
    individual overrides in the presence of *func*. Returns energy if *dertype* is 0,
    gradient if *dertype* is 1, else tuple of energy and gradient if *dertype*
    unspecified. The dftd3 executable must be independently compiled and found in
    :envvar:`PATH` or :envvar:`PSIPATH`.
    *self* may be either a qcdb.Molecule (sensibly) or a psi4.Molecule
    (works b/c psi4.Molecule has been extended by this method py-side and
    only public interface fns used) or a string that can be instantiated
    into a qcdb.Molecule.

    """
    # Create (if necessary) and update qcdb.Molecule
    if isinstance(self, Molecule):
        # called on a qcdb.Molecule
        pass
    elif isinstance(self, psi4.Molecule):
        # called on a python export of a psi4.Molecule (py-side through Psi4's driver)
        self.create_psi4_string_from_molecule()
    elif isinstance(self, basestring):
        # called on a string representation of a psi4.Molecule (c-side through psi4.Dispersion)
        self = Molecule(self)
    else:
        raise ValidationError("""Argument mol must be psi4string or qcdb.Molecule""")
    self.update_geometry()

    # Validate arguments
    dashlvl = dashlvl.lower()
    dashlvl = dash_alias['-' + dashlvl][1:] if ('-' + dashlvl) in dash_alias.keys() else dashlvl
    if dashlvl not in dashcoeff.keys():
        raise ValidationError("""-D correction level %s is not available. Choose among %s.""" % (dashlvl, dashcoeff.keys()))

    if dertype is None:
        dertype = -1
    elif der0th.match(str(dertype)):
        dertype = 0
    elif der1st.match(str(dertype)):
        dertype = 1
    elif der2nd.match(str(dertype)):
        raise ValidationError('Requested derivative level \'dertype\' %s not valid for run_dftd3.' % (dertype))
    else:
        raise ValidationError('Requested derivative level \'dertype\' %s not valid for run_dftd3.' % (dertype))

    if func is None:
        if dashparam is None:
            # defunct case
            raise ValidationError("""Parameters for -D correction missing. Provide a func or a dashparam kwarg.""")
        else:
            # case where all param read from dashparam dict (which must have all correct keys)
            func = 'custom'
            dashcoeff[dashlvl][func] = {}
            dashparam = dict((k.lower(), v) for k, v in dashparam.iteritems())
            for key in dashcoeff[dashlvl]['b3lyp'].keys():
                if key in dashparam.keys():
                    dashcoeff[dashlvl][func][key] = dashparam[key]
                else:
                    raise ValidationError("""Parameter %s is missing from dashparam dict %s.""" % (key, dashparam))
    else:
        func = func.lower()
        if func not in dashcoeff[dashlvl].keys():
            raise ValidationError("""Functional %s is not available for -D level %s.""" % (func, dashlvl))
        if dashparam is None:
            # (normal) case where all param taken from dashcoeff above
            pass
        else:
            # case where items in dashparam dict can override param taken from dashcoeff above
            dashparam = dict((k.lower(), v) for k, v in dashparam.iteritems())
            for key in dashcoeff[dashlvl]['b3lyp'].keys():
                if key in dashparam.keys():
                    dashcoeff[dashlvl][func][key] = dashparam[key]

    # Move ~/.dftd3par.<hostname> out of the way so it won't interfere
    defaultfile = os.path.expanduser('~') + '/.dftd3par.' + socket.gethostname()
    defmoved = False
    if os.path.isfile(defaultfile):
        os.rename(defaultfile, defaultfile + '_hide')
        defmoved = True

    # Find environment by merging PSIPATH and PATH environment variables
    lenv = {
        'PATH': ':'.join([os.path.abspath(x) for x in os.environ.get('PSIPATH', '').split(':') if x != '']) + \
                ':' + os.environ.get('PATH'),
        'LD_LIBRARY_PATH': os.environ.get('LD_LIBRARY_PATH')
        }

    # Find out if running from Psi4 for scratch details and such
    try:
        psi4.version()
    except NameError:
        isP4regime = False
    else:
        isP4regime = True

    # Setup unique scratch directory and move in
    current_directory = os.getcwd()
    if isP4regime:
        psioh = psi4.IOManager.shared_object()
        psio = psi4.IO.shared_object()
        os.chdir(psioh.get_default_path())
        dftd3_tmpdir = 'psi.' + str(os.getpid()) + '.' + psio.get_default_namespace() + \
            '.dftd3.' + str(random.randint(0, 99999))
    else:
        dftd3_tmpdir = os.environ['HOME'] + os.sep + 'dftd3_' + str(random.randint(0, 99999))
    if os.path.exists(dftd3_tmpdir) is False:
        os.mkdir(dftd3_tmpdir)
    os.chdir(dftd3_tmpdir)

    # Write dftd3_parameters file that governs dispersion calc
    paramcontents = dash_server(func, dashlvl, 'dftd3')
    paramfile1 = 'dftd3_parameters'  # older patched name
    with open(paramfile1, 'w') as handle:
        handle.write(paramcontents)
    paramfile2 = '.dftd3par.local'  # new mainline name
    with open(paramfile2, 'w') as handle:
        handle.write(paramcontents)

    # Write dftd3_geometry file that supplies geometry to dispersion calc
    numAtoms = self.natom()
    geom = self.save_string_xyz()
    reals = []
    for line in geom.splitlines():
        lline = line.split()
        if len(lline) != 4:
            continue
        if lline[0] == 'Gh':
            numAtoms -= 1
        else:
            reals.append(line)

    geomtext = str(numAtoms) + '\n\n'
    for line in reals:
        geomtext += line.strip() + '\n'
    geomfile = './dftd3_geometry.xyz'
    with open(geomfile, 'w') as handle:
        handle.write(geomtext)
    # TODO somehow the variations on save_string_xyz and
    #   whether natom and chgmult does or doesn't get written
    #   have gotten all tangled. I fear this doesn't work
    #   the same btwn libmints and qcdb or for ghosts

    # Call dftd3 program
    command = ['dftd3', geomfile]
    if dertype != 0:
        command.append('-grad')
    try:
        dashout = subprocess.Popen(command, stdout=subprocess.PIPE, env=lenv)
    except OSError as e:
        raise ValidationError('Program dftd3 not found in path. %s' % e)
    out, err = dashout.communicate()

    # Parse output (could go further and break into E6, E8, E10 and Cn coeff)
    success = False
    for line in out.splitlines():
        if re.match(' Edisp /kcal,au', line):
            sline = line.split()
            dashd = float(sline[3])
        if re.match(' normal termination of dftd3', line):
            success = True

    if not success:
        os.chdir(current_directory)
        raise Dftd3Error("""Unsuccessful run. Possibly -D variant not available in dftd3 version.""")

    # Parse grad output
    if dertype != 0:
        derivfile = './dftd3_gradient'
        dfile = open(derivfile, 'r')
        dashdderiv = []
        for line in geom.splitlines():
            lline = line.split()
            if len(lline) != 4:
                continue
            if lline[0] == 'Gh':
                dashdderiv.append([0.0, 0.0, 0.0])
            else:
                dashdderiv.append([float(x.replace('D', 'E')) for x in dfile.readline().split()])
        dfile.close()

        if len(dashdderiv) != self.natom():
            raise ValidationError('Program dftd3 gradient file has %d atoms- %d expected.' % \
                (len(dashdderiv), self.natom()))

    # Prepare results for Psi4
    if isP4regime and dertype != 0:
        psi4.set_variable('DISPERSION CORRECTION ENERGY', dashd)
        psi_dashdderiv = psi4.Matrix(self.natom(), 3)
        psi_dashdderiv.set(dashdderiv)

    # Print program output to file if verbose
    if isP4regime:
        verbose = True if psi4.get_option('SCF', 'PRINT') >= 3 else False
    if verbose:

        text = '\n  ==> DFTD3 Output <==\n'
        text += out
        if dertype != 0:
            with open(derivfile, 'r') as handle:
                text += handle.read().replace('D', 'E')
            text += '\n'
        if isP4regime:
            psi4.print_out(text)
        else:
            print(text)

    # Clean up files and remove scratch directory
    os.unlink(paramfile1)
    os.unlink(paramfile2)
    os.unlink(geomfile)
    if dertype != 0:
        os.unlink(derivfile)
    if defmoved is True:
        os.rename(defaultfile + '_hide', defaultfile)

    os.chdir('..')
    try:
        shutil.rmtree(dftd3_tmpdir)
    except OSError as e:
        ValidationError('Unable to remove dftd3 temporary directory %s' % e)
    os.chdir(current_directory)

    # return -D & d(-D)/dx
    if dertype == -1:
        return dashd, dashdderiv
    elif dertype == 0:
        return dashd
    elif dertype == 1:
        return psi_dashdderiv
Пример #35
0
def run_dftd3(self,
              func=None,
              dashlvl=None,
              dashparam=None,
              dertype=None,
              verbose=False):
    """Function to call Grimme's dftd3 program (http://toc.uni-muenster.de/DFTD3/)
    to compute the -D correction of level *dashlvl* using parameters for
    the functional *func*. The dictionary *dashparam* can be used to supply
    a full set of dispersion parameters in the absense of *func* or to supply
    individual overrides in the presence of *func*. Returns energy if *dertype* is 0,
    gradient if *dertype* is 1, else tuple of energy and gradient if *dertype*
    unspecified. The dftd3 executable must be independently compiled and found in
    :envvar:`PATH` or :envvar:`PSIPATH`.
    *self* may be either a qcdb.Molecule (sensibly) or a psi4.Molecule
    (works b/c psi4.Molecule has been extended by this method py-side and
    only public interface fns used) or a string that can be instantiated
    into a qcdb.Molecule.

    """
    # Create (if necessary) and update qcdb.Molecule
    if isinstance(self, Molecule):
        # called on a qcdb.Molecule
        pass
    elif isinstance(self, psi4.Molecule):
        # called on a python export of a psi4.Molecule (py-side through Psi4's driver)
        self.create_psi4_string_from_molecule()
    elif isinstance(self, basestring):
        # called on a string representation of a psi4.Molecule (c-side through psi4.Dispersion)
        self = Molecule(self)
    else:
        raise ValidationError(
            """Argument mol must be psi4string or qcdb.Molecule""")
    self.update_geometry()

    # Validate arguments
    dashlvl = dashlvl.lower()
    dashlvl = dash_alias['-' + dashlvl][1:] if (
        '-' + dashlvl) in dash_alias.keys() else dashlvl
    if dashlvl not in dashcoeff.keys():
        raise ValidationError(
            """-D correction level %s is not available. Choose among %s.""" %
            (dashlvl, dashcoeff.keys()))

    if dertype is None:
        dertype = -1
    elif der0th.match(str(dertype)):
        dertype = 0
    elif der1st.match(str(dertype)):
        dertype = 1
    elif der2nd.match(str(dertype)):
        raise ValidationError(
            'Requested derivative level \'dertype\' %s not valid for run_dftd3.'
            % (dertype))
    else:
        raise ValidationError(
            'Requested derivative level \'dertype\' %s not valid for run_dftd3.'
            % (dertype))

    if func is None:
        if dashparam is None:
            # defunct case
            raise ValidationError(
                """Parameters for -D correction missing. Provide a func or a dashparam kwarg."""
            )
        else:
            # case where all param read from dashparam dict (which must have all correct keys)
            func = 'custom'
            dashcoeff[dashlvl][func] = {}
            dashparam = dict((k.lower(), v) for k, v in dashparam.iteritems())
            for key in dashcoeff[dashlvl]['b3lyp'].keys():
                if key in dashparam.keys():
                    dashcoeff[dashlvl][func][key] = dashparam[key]
                else:
                    raise ValidationError(
                        """Parameter %s is missing from dashparam dict %s.""" %
                        (key, dashparam))
    else:
        func = func.lower()
        if func not in dashcoeff[dashlvl].keys():
            raise ValidationError(
                """Functional %s is not available for -D level %s.""" %
                (func, dashlvl))
        if dashparam is None:
            # (normal) case where all param taken from dashcoeff above
            pass
        else:
            # case where items in dashparam dict can override param taken from dashcoeff above
            dashparam = dict((k.lower(), v) for k, v in dashparam.iteritems())
            for key in dashcoeff[dashlvl]['b3lyp'].keys():
                if key in dashparam.keys():
                    dashcoeff[dashlvl][func][key] = dashparam[key]

    # Move ~/.dftd3par.<hostname> out of the way so it won't interfere
    defaultfile = os.path.expanduser(
        '~') + '/.dftd3par.' + socket.gethostname()
    defmoved = False
    if os.path.isfile(defaultfile):
        os.rename(defaultfile, defaultfile + '_hide')
        defmoved = True

    # Find environment by merging PSIPATH and PATH environment variables
    lenv = {
        'PATH': ':'.join([os.path.abspath(x) for x in os.environ.get('PSIPATH', '').split(':') if x != '']) + \
                ':' + os.environ.get('PATH'),
        'LD_LIBRARY_PATH': os.environ.get('LD_LIBRARY_PATH')
        }
    #   Filter out None values as subprocess will fault on them
    lenv = {k: v for k, v in lenv.items() if v is not None}

    # Find out if running from Psi4 for scratch details and such
    try:
        psi4.version()
    except NameError:
        isP4regime = False
    else:
        isP4regime = True

    # Setup unique scratch directory and move in
    current_directory = os.getcwd()
    if isP4regime:
        psioh = psi4.IOManager.shared_object()
        psio = psi4.IO.shared_object()
        os.chdir(psioh.get_default_path())
        dftd3_tmpdir = 'psi.' + str(os.getpid()) + '.' + psio.get_default_namespace() + \
            '.dftd3.' + str(random.randint(0, 99999))
    else:
        dftd3_tmpdir = os.environ['HOME'] + os.sep + 'dftd3_' + str(
            random.randint(0, 99999))
    if os.path.exists(dftd3_tmpdir) is False:
        os.mkdir(dftd3_tmpdir)
    os.chdir(dftd3_tmpdir)

    # Write dftd3_parameters file that governs dispersion calc
    paramcontents = dash_server(func, dashlvl, 'dftd3')
    paramfile1 = 'dftd3_parameters'  # older patched name
    with open(paramfile1, 'w') as handle:
        handle.write(paramcontents)
    paramfile2 = '.dftd3par.local'  # new mainline name
    with open(paramfile2, 'w') as handle:
        handle.write(paramcontents)

    # Write dftd3_geometry file that supplies geometry to dispersion calc
    numAtoms = self.natom()
    geom = self.save_string_xyz()
    reals = []
    for line in geom.splitlines():
        lline = line.split()
        if len(lline) != 4:
            continue
        if lline[0] == 'Gh':
            numAtoms -= 1
        else:
            reals.append(line)

    geomtext = str(numAtoms) + '\n\n'
    for line in reals:
        geomtext += line.strip() + '\n'
    geomfile = './dftd3_geometry.xyz'
    with open(geomfile, 'w') as handle:
        handle.write(geomtext)
    # TODO somehow the variations on save_string_xyz and
    #   whether natom and chgmult does or doesn't get written
    #   have gotten all tangled. I fear this doesn't work
    #   the same btwn libmints and qcdb or for ghosts

    # Call dftd3 program
    command = ['dftd3', geomfile]
    if dertype != 0:
        command.append('-grad')
    try:
        dashout = subprocess.Popen(command, stdout=subprocess.PIPE, env=lenv)
    except OSError as e:
        raise ValidationError('Program dftd3 not found in path. %s' % e)
    out, err = dashout.communicate()

    # Parse output (could go further and break into E6, E8, E10 and Cn coeff)
    success = False
    for line in out.splitlines():
        if re.match(' Edisp /kcal,au', line):
            sline = line.split()
            dashd = float(sline[3])
        if re.match(' normal termination of dftd3', line):
            success = True

    if not success:
        os.chdir(current_directory)
        raise Dftd3Error(
            """Unsuccessful run. Possibly -D variant not available in dftd3 version."""
        )

    # Parse grad output
    if dertype != 0:
        derivfile = './dftd3_gradient'
        dfile = open(derivfile, 'r')
        dashdderiv = []
        for line in geom.splitlines():
            lline = line.split()
            if len(lline) != 4:
                continue
            if lline[0] == 'Gh':
                dashdderiv.append([0.0, 0.0, 0.0])
            else:
                dashdderiv.append([
                    float(x.replace('D', 'E'))
                    for x in dfile.readline().split()
                ])
        dfile.close()

        if len(dashdderiv) != self.natom():
            raise ValidationError('Program dftd3 gradient file has %d atoms- %d expected.' % \
                (len(dashdderiv), self.natom()))

    # Prepare results for Psi4
    if isP4regime and dertype != 0:
        psi4.set_variable('DISPERSION CORRECTION ENERGY', dashd)
        psi_dashdderiv = psi4.Matrix(self.natom(), 3)
        psi_dashdderiv.set(dashdderiv)

    # Print program output to file if verbose
    if isP4regime:
        verbose = True if psi4.get_option('SCF', 'PRINT') >= 3 else False
    if verbose:

        text = '\n  ==> DFTD3 Output <==\n'
        text += out
        if dertype != 0:
            with open(derivfile, 'r') as handle:
                text += handle.read().replace('D', 'E')
            text += '\n'
        if isP4regime:
            psi4.print_out(text)
        else:
            print(text)

    # Clean up files and remove scratch directory
    os.unlink(paramfile1)
    os.unlink(paramfile2)
    os.unlink(geomfile)
    if dertype != 0:
        os.unlink(derivfile)
    if defmoved is True:
        os.rename(defaultfile + '_hide', defaultfile)

    os.chdir('..')
    try:
        shutil.rmtree(dftd3_tmpdir)
    except OSError as e:
        ValidationError('Unable to remove dftd3 temporary directory %s' % e)
    os.chdir(current_directory)

    # return -D & d(-D)/dx
    if dertype == -1:
        return dashd, dashdderiv
    elif dertype == 0:
        return dashd
    elif dertype == 1:
        return psi_dashdderiv
Пример #36
0
def run_dftd3(self, func=None, dashlvl=None, dashparam=None, dertype=None):
    """Function to call Grimme's dftd3 program (http://toc.uni-muenster.de/DFTD3/)
    to compute the -D correction of level *dashlvl* using parameters for
    the functional *func*. The dictionary *dashparam* can be used to supply
    a full set of dispersion parameters in the absense of *func* or to supply
    individual overrides in the presence of *func*. Returns energy if *dertype* is 0,
    gradient if *dertype* is 1, else tuple of energy and gradient if *dertype*
    unspecified. The dftd3 executable must be independently compiled and found in
    :envvar:`PATH`.

    """
    # Validate arguments
    if self is None:
        self = psi4.get_active_molecule()

    dashlvl = dashlvl.lower()
    dashlvl = dash_alias['-' + dashlvl][1:] if ('-' + dashlvl) in dash_alias.keys() else dashlvl
    if dashlvl not in dashcoeff.keys():
        raise ValidationError("""-D correction level %s is not available. Choose among %s.""" % (dashlvl, dashcoeff.keys()))

    if dertype is None:
        dertype = -1
    elif der0th.match(str(dertype)):
        dertype = 0
    elif der1st.match(str(dertype)):
        dertype = 1
    elif der2nd.match(str(dertype)):
        raise ValidationError('Requested derivative level \'dertype\' %s not valid for run_dftd3.' % (dertype))
    else:
        raise ValidationError('Requested derivative level \'dertype\' %s not valid for run_dftd3.' % (dertype))

    if func is None:
        if dashparam is None:
            # defunct case
            raise ValidationError("""Parameters for -D correction missing. Provide a func or a dashparam kwarg.""")
        else:
            # case where all param read from dashparam dict (which must have all correct keys)
            func = 'custom'
            dashcoeff[dashlvl][func] = {}
            dashparam = dict((k.lower(), v) for k, v in dashparam.items())
            for key in dashcoeff[dashlvl]['b3lyp'].keys():
                if key in dashparam.keys():
                    dashcoeff[dashlvl][func][key] = dashparam[key]
                else:
                    raise ValidationError("""Parameter %s is missing from dashparam dict %s.""" % (key, dashparam))
    else:
        func = func.lower()
        if func not in dashcoeff[dashlvl].keys():
            raise ValidationError("""Functional %s is not available for -D level %s.""" % (func, dashlvl))
        if dashparam is None:
            # (normal) case where all param taken from dashcoeff above
            pass
        else:
            # case where items in dashparam dict can override param taken from dashcoeff above
            dashparam = dict((k.lower(), v) for k, v in dashparam.items())
            for key in dashcoeff[dashlvl]['b3lyp'].keys():
                if key in dashparam.keys():
                    dashcoeff[dashlvl][func][key] = dashparam[key]

    # Move ~/.dftd3par.<hostname> out of the way so it won't interfere
    defaultfile = os.path.expanduser('~') + '/.dftd3par.' + socket.gethostname()
    defmoved = False
    if os.path.isfile(defaultfile):
        os.rename(defaultfile, defaultfile + '_hide')
        defmoved = True

    # Setup unique scratch directory and move in
    current_directory = os.getcwd()
    psioh = psi4.IOManager.shared_object()
    psio = psi4.IO.shared_object()
    os.chdir(psioh.get_default_path())
    dftd3_tmpdir = 'psi.' + str(os.getpid()) + '.' + psio.get_default_namespace() + \
        '.dftd3.' + str(random.randint(0, 99999))
    if os.path.exists(dftd3_tmpdir) is False:
        os.mkdir(dftd3_tmpdir)
    os.chdir(dftd3_tmpdir)

    # Write dftd3_parameters file that governs dispersion calc
    paramfile = './dftd3_parameters'
    pfile = open(paramfile, 'w')
    pfile.write(dash_server(func, dashlvl, 'dftd3'))
    pfile.close()

    # Write dftd3_geometry file that supplies geometry to dispersion calc
    geomfile = './dftd3_geometry.xyz'
    gfile = open(geomfile, 'w')
    numAtoms = self.natom()
    geom = self.save_string_xyz()
    reals = []
    for line in geom.splitlines():
      if line.split()[0] == 'Gh':
        numAtoms -= 1
      else:
        reals.append(line)
        
    gfile.write(str(numAtoms)+'\n')
    for line in reals:
      gfile.write(line.strip()+'\n')
    gfile.close()

    # Call dftd3 program
    try:
        dashout = subprocess.Popen(['dftd3', geomfile, '-grad'], stdout=subprocess.PIPE)
    except OSError:
        raise ValidationError('Program dftd3 not found in path.')
    out, err = dashout.communicate()

    # Parse output (could go further and break into E6, E8, E10 and Cn coeff)
    success = False
    for line in out.splitlines():
        # communicate in python 3 returns a byte array rather than a string.
        # Convert to string--only need a simple encoding for comparison.
        line = line.decode('utf-8')        
        if re.match(' Edisp /kcal,au', line):
            sline = line.split()
            dashd = float(sline[3])
        if re.match(' normal termination of dftd3', line):
            success = True

    if not success:
        raise ValidationError('Program dftd3 did not complete successfully.')

    # Parse grad output
    derivfile = './dftd3_gradient'
    dfile = open(derivfile, 'r')
    dashdderiv = []
    i = 0
    for line in geom.splitlines():
      if i == 0:
        i += 1
      else:
        if line.split()[0] == 'Gh':
          dashdderiv.append([0.0, 0.0, 0.0])
        else:
          temp = dfile.readline()
          dashdderiv.append([float(x.replace('D', 'E')) for x in temp.split()])
    dfile.close()

    if len(dashdderiv) != self.natom():
        raise ValidationError('Program dftd3 gradient file has %d atoms- %d expected.' % \
            (len(dashdderiv), self.natom()))
    psi_dashdderiv = psi4.Matrix(self.natom(), 3)
    psi_dashdderiv.set(dashdderiv)

    # Print program output to file if verbose
    verbose = psi4.get_option('SCF', 'PRINT')
    if verbose >= 3:
        psi4.print_out('\n  ==> DFTD3 Output <==\n')
        psi4.print_out(out)
        dfile = open(derivfile, 'r')
        psi4.print_out(dfile.read().replace('D', 'E'))
        dfile.close()
        psi4.print_out('\n')

    # Clean up files and remove scratch directory
    os.unlink(paramfile)
    os.unlink(geomfile)
    os.unlink(derivfile)
    if defmoved is True:
        os.rename(defaultfile + '_hide', defaultfile)

    os.chdir('..')
    try:
        shutil.rmtree(dftd3_tmpdir)
    except OSError as e:
        ValidationError('Unable to remove dftd3 temporary directory %s' % e, file=sys.stderr)
    os.chdir(current_directory)

    # return -D & d(-D)/dx
    psi4.set_variable('DISPERSION CORRECTION ENERGY', dashd)
    if dertype == -1:
        return dashd, dashdderiv
    elif dertype == 0:
        return dashd
    elif dertype == 1:
        return psi_dashdderiv
Пример #37
0
def frac_nuke(molecule, **kwargs):
    kwargs = p4util.kwargs_lower(kwargs)

    # The molecule is required, and should be the neutral species
    molecule.update_geometry()
    charge0 = molecule.molecular_charge()
    mult0 = molecule.multiplicity()

    # By default, we start the frac procedure on the 25th iteration
    # when not reading a previous guess
    frac_start = kwargs.get('frac_start', 25)

    # By default, we occupy by tenths of electrons
    foccs = kwargs.get('foccs', [1.0, 0.9, 0.8, 0.7, 0.6, 0.5, 0.4, 0.3, 0.2, 0.1, 0.0])

    # By default, H**O and LUMO are both in alpha
    N = 0;
    for A in range(molecule.natom()):
        N += molecule.Z(A)
    N -= charge0
    N = int(N)
    Nb = int((N - mult0 + 1) / 2)
    Na = int(N - Nb)

    charge = charge0
    mult = mult0

    # By default, nuke all the electrons
    Nmin = 0;
    if ('nmax' in kwargs):
        Nmin = N - int(kwargs['nmax'])

    # By default, DIIS in FRAC (1.0 occupation is always DIIS'd)
    frac_diis = kwargs.get('frac_diis', True)

    # By default, drop the files to the molecule's name
    root = kwargs.get('filename', molecule.name())
    traverse_filename = root + '.traverse.dat'
    stats_filename = root + '.stats.dat'

    # => Traverse <= #
    psi4.set_global_option("DF_INTS_IO", "SAVE")

    Ns = []
    energies = []
    potentials = []
    convs = []
    stats = []

    # Run one SCF to burn things in
    E, wfn= energy('scf', return_wfn=True, molecule=molecule, **kwargs)

    # Determine H**O
    eps_a = wfn.epsilon_a()
    eps_b = wfn.epsilon_b()
    if Na == Nb:
        H**O = -Nb
    elif Nb == 0:
        H**O = Na
    else:
        E_a = eps_a[int(Na - 1)]
        E_b = eps_b[int(Nb - 1)]
        if E_a >= E_b:
            H**O = Na
        else:
            H**O = -Nb

    stats.append("""\t%6d %6d %6d %6d %6d %6d\n""" % (N, Na, Nb, charge, mult, H**O))

    if H**O > 0:
        Na = Na - 1
    else:
        Nb = Nb - 1
    charge = charge + 1
    mult = Na - Nb + 1

    psi4.set_global_option("DF_INTS_IO", "LOAD")
    psi4.set_global_option("FRAC_START", frac_start)
    psi4.set_global_option("FRAC_RENORMALIZE", True)

    # Nuke 'em Rico!
    for Nintegral in range(N, Nmin, -1):

        # Nuke the current H**O
        for occ in foccs:

            psi4.set_global_option("FRAC_OCC", [H**O])
            psi4.set_global_option("FRAC_VAL", [occ])

            E, wfn = energy('scf', return_wfn=True, molecule=molecule, **kwargs)
            C = 1
            if E == 0.0:
                E = psi4.get_variable('SCF ITERATION ENERGY')
                C = 0

            if H**O > 0:
                eps = wfn.epsilon_a()
                potentials.append(eps[H**O - 1])
            else:
                eps = wfn.epsilon_b()
                potentials.append(eps[-H**O - 1])

            Ns.append(Nintegral + occ - 1.0)
            energies.append(E)
            convs.append(C)

            psi4.set_global_option("FRAC_START", 2)
            psi4.set_global_option("FRAC_LOAD", True)
            psi4.set_global_option("FRAC_DIIS", frac_diis)
            psi4.set_global_option("GUESS", "READ")

        # Set the next charge/mult
        molecule.set_molecular_charge(charge)
        molecule.set_multiplicity(mult)

        # Determine H**O
        print('DGAS: What ref should this point to?')
        #ref = psi4.legacy_wavefunction()
        eps_a = wfn.epsilon_a()
        eps_b = wfn.epsilon_b()
        if Na == Nb:
            H**O = -Nb
        elif Nb == 0:
            H**O = Na
        else:
            E_a = eps_a[int(Na - 1)]
            E_b = eps_b[int(Nb - 1)]
            if E_a >= E_b:
                H**O = Na
            else:
                H**O = -Nb

        stats.append("""\t%6d %6d %6d %6d %6d %6d\n""" % (Nintegral-1, Na, Nb, charge, mult, H**O))

        if H**O > 0:
            Na = Na - 1
        else:
            Nb = Nb - 1
        charge = charge + 1
        mult = Na - Nb + 1

    psi4.set_global_option("DF_INTS_IO", "NONE")

    # => Print the results out <= #
    E = {}
    psi4.print_out("""\n    ==> Fractional Occupation Nuke Results <==\n\n""")
    psi4.print_out("""\t%-11s %-24s %-24s %11s\n""" % ('N', 'Energy', 'H**O Energy', 'Converged'))
    for k in range(len(Ns)):
        psi4.print_out("""\t%11.3E %24.16E %24.16E %11d\n""" % (Ns[k], energies[k], potentials[k], convs[k]))
        E[Ns[k]] = energies[k]

    psi4.print_out('\n')
    psi4.print_out("""\t%6s %6s %6s %6s %6s %6s\n""" % ('N', 'Na', 'Nb', 'Charge', 'Mult', 'H**O'))
    for line in stats:
        psi4.print_out(line)

    psi4.print_out('\n\t"You shoot a nuke down a bug hole, you got a lot of dead bugs"\n')
    psi4.print_out('\t\t\t-Starship Troopers\n')

    # Drop the files out
    fh = open(traverse_filename, 'w')
    fh.write("""\t%-11s %-24s %-24s %11s\n""" % ('N', 'Energy', 'H**O Energy', 'Converged'))
    for k in range(len(Ns)):
        fh.write("""\t%11.3E %24.16E %24.16E %11d\n""" % (Ns[k], energies[k], potentials[k], convs[k]))
    fh.close()

    fh = open(stats_filename, 'w')
    fh.write("""\t%6s %6s %6s %6s %6s %6s\n""" % ('N', 'Na', 'Nb', 'Charge', 'Mult', 'H**O'))
    for line in stats:
        fh.write(line)
    fh.close()

    # Properly, should clone molecule but since not returned and easy to unblemish,
    molecule.set_molecular_charge(charge0)
    molecule.set_multiplicity(mult0)

    return E
Пример #38
0
def _nbody_gufunc(func, method_string, **kwargs):
    """
    Computes the nbody interaction energy, gradient, or Hessian depending on input.

    Parameters
    ----------
    func : python function
        Python function that accepts method_string and a molecule and returns a energy, gradient, or Hessian.
    method_string : str
        Lowername to be passed to function
    molecule : psi4.Molecule (default: Global Molecule)
        Molecule to use in all computations
    return_wfn : bool (default: False)
        Return a wavefunction or not
    bsse_type : str or list (default: None, this function is not called)
        Type of BSSE correction to compute: CP, NoCP, or VMFC. The first in this list is returned by this function.
    max_nbody : int
        Maximum n-body to compute, cannot exceede the number of fragments in the moleucle
    ptype : str
        Type of the procedure passed in
    return_total_data : bool (default: False)
        If True returns the total data (energy/gradient/etc) of the system otherwise returns interaction data

    Returns
    -------
    data : return type of func
        The interaction data
    wfn : psi4.Wavefunction (optional)
        A wavefunction with energy/gradient/hessian set appropriotely. This wavefunction also contains 

    Notes
    -----
    This is a generalized univeral function for compute interaction quantities.

    Examples
    --------
    """

    ### ==> Parse some kwargs <==
    kwargs = p4util.kwargs_lower(kwargs)
    return_wfn = kwargs.pop('return_wfn', False)
    ptype = kwargs.pop('ptype', None)
    return_total_data = kwargs.pop('return_total_data', False)
    molecule = kwargs.pop('molecule', psi4.get_active_molecule())
    molecule.update_geometry()
    psi4.clean_variables()

    if ptype not in ['energy', 'gradient', 'hessian']:
        raise ValidationError(
            """N-Body driver: The ptype '%s' is not regonized.""" % ptype)

    # Figure out BSSE types
    do_cp = False
    do_nocp = False
    do_vmfc = False
    return_method = False

    # Must be passed bsse_type
    bsse_type_list = kwargs.pop('bsse_type')
    if bsse_type_list is None:
        raise ValidationError("N-Body GUFunc: Must pass a bsse_type")
    if not isinstance(bsse_type_list, list):
        bsse_type_list = [bsse_type_list]

    for num, btype in enumerate(bsse_type_list):
        if btype.lower() == 'cp':
            do_cp = True
            if (num == 0): return_method = 'cp'
        elif btype.lower() == 'nocp':
            do_nocp = True
            if (num == 0): return_method = 'nocp'
        elif btype.lower() == 'vmfc':
            do_vmfc = True
            if (num == 0): return_method = 'vmfc'
        else:
            raise ValidationError(
                "N-Body GUFunc: bsse_type '%s' is not recognized" %
                btype.lower())

    max_nbody = kwargs.get('max_nbody', -1)
    max_frag = molecule.nfragments()
    if max_nbody == -1:
        max_nbody = molecule.nfragments()
    else:
        max_nbody = min(max_nbody, max_frag)

    # What levels do we need?
    nbody_range = range(1, max_nbody + 1)
    fragment_range = range(1, max_frag + 1)

    # Flip this off for now, needs more testing
    # If we are doing CP lets save them integrals
    #if 'cp' in bsse_type_list and (len(bsse_type_list) == 1):
    #    # Set to save RI integrals for repeated full-basis computations
    #    ri_ints_io = psi4.get_global_option('DF_INTS_IO')

    #    # inquire if above at all applies to dfmp2 or just scf
    #    psi4.set_global_option('DF_INTS_IO', 'SAVE')
    #    psioh = psi4.IOManager.shared_object()
    #    psioh.set_specific_retention(97, True)

    bsse_str = bsse_type_list[0]
    if len(bsse_type_list) > 1:
        bsse_str = str(bsse_type_list)
    psi4.print_out("\n\n")
    psi4.print_out("   ===> N-Body Interaction Abacus <===\n")
    psi4.print_out("        BSSE Treatment:                     %s\n" %
                   bsse_str)

    cp_compute_list = {x: set() for x in nbody_range}
    nocp_compute_list = {x: set() for x in nbody_range}
    vmfc_compute_list = {x: set() for x in nbody_range}
    vmfc_level_list = {x: set()
                       for x in nbody_range
                       }  # Need to sum something slightly different

    # Build up compute sets
    if do_cp:
        # Everything is in dimer basis
        basis_tuple = tuple(fragment_range)
        for nbody in nbody_range:
            for x in it.combinations(fragment_range, nbody):
                cp_compute_list[nbody].add((x, basis_tuple))

    if do_nocp:
        # Everything in monomer basis
        for nbody in nbody_range:
            for x in it.combinations(fragment_range, nbody):
                nocp_compute_list[nbody].add((x, x))

    if do_vmfc:
        # Like a CP for all combinations of pairs or greater
        for nbody in nbody_range:
            for cp_combos in it.combinations(fragment_range, nbody):
                basis_tuple = tuple(cp_combos)
                for interior_nbody in nbody_range:
                    for x in it.combinations(cp_combos, interior_nbody):
                        combo_tuple = (x, basis_tuple)
                        vmfc_compute_list[interior_nbody].add(combo_tuple)
                        vmfc_level_list[len(basis_tuple)].add(combo_tuple)

    # Build a comprehensive compute_range
    compute_list = {x: set() for x in nbody_range}
    for n in nbody_range:
        compute_list[n] |= cp_compute_list[n]
        compute_list[n] |= nocp_compute_list[n]
        compute_list[n] |= vmfc_compute_list[n]
        psi4.print_out("        Number of %d-body computations:     %d\n" %
                       (n, len(compute_list[n])))

    # Build size and slices dictionaries
    fragment_size_dict = {
        frag: molecule.extract_subsets(frag).natom()
        for frag in range(1, max_frag + 1)
    }

    start = 0
    fragment_slice_dict = {}
    for k, v in fragment_size_dict.items():
        fragment_slice_dict[k] = slice(start, start + v)
        start += v

    molecule_total_atoms = sum(fragment_size_dict.values())

    # Now compute the energies
    energies_dict = {}
    ptype_dict = {}
    for n in compute_list.keys():
        psi4.print_out(
            "\n   ==> N-Body: Now computing %d-body complexes <==\n\n" % n)
        print("\n   ==> N-Body: Now computing %d-body complexes <==\n" % n)
        total = len(compute_list[n])
        for num, pair in enumerate(compute_list[n]):
            psi4.print_out(
                "\n       N-Body: Computing complex (%d/%d) with fragments %s in the basis of fragments %s.\n\n"
                % (num + 1, total, str(pair[0]), str(pair[1])))
            ghost = list(set(pair[1]) - set(pair[0]))

            current_mol = molecule.extract_subsets(list(pair[0]), ghost)
            ptype_dict[pair] = func(method_string,
                                    molecule=current_mol,
                                    **kwargs)
            energies_dict[pair] = psi4.get_variable("CURRENT ENERGY")
            psi4.print_out(
                "\n       N-Body: Complex Energy (fragments = %s, basis = %s: %20.14f)\n"
                % (str(pair[0]), str(pair[1]), energies_dict[pair]))

            # Flip this off for now, needs more testing
            #if 'cp' in bsse_type_list and (len(bsse_type_list) == 1):
            #    psi4.set_global_option('DF_INTS_IO', 'LOAD')

            psi4.clean()

    # Final dictionaries
    cp_energy_by_level = {n: 0.0 for n in nbody_range}
    nocp_energy_by_level = {n: 0.0 for n in nbody_range}

    cp_energy_body_dict = {n: 0.0 for n in nbody_range}
    nocp_energy_body_dict = {n: 0.0 for n in nbody_range}
    vmfc_energy_body_dict = {n: 0.0 for n in nbody_range}

    # Build out ptype dictionaries if needed
    if ptype != 'energy':
        if ptype == 'gradient':
            arr_shape = (molecule_total_atoms, 3)
        elif ptype == 'hessian':
            arr_shape = (molecule_total_atoms * 3, molecule_total_atoms * 3)
        else:
            raise KeyError("N-Body: ptype '%s' not recognized" % ptype)

        cp_ptype_by_level = {n: np.zeros(arr_shape) for n in nbody_range}
        nocp_ptype_by_level = {n: np.zeros(arr_shape) for n in nbody_range}

        cp_ptype_body_dict = {n: np.zeros(arr_shape) for n in nbody_range}
        nocp_ptype_body_dict = {n: np.zeros(arr_shape) for n in nbody_range}
        vmfc_ptype_body_dict = {n: np.zeros(arr_shape) for n in nbody_range}
    else:
        cp_ptype_by_level, cp_ptype_body_dict = None, None
        nocp_ptype_by_level, nocp_ptype_body_dict = None, None
        vmfc_ptype_body_dict = None

    # Sum up all of the levels
    for n in nbody_range:

        # Energy
        cp_energy_by_level[n] = sum(energies_dict[v]
                                    for v in cp_compute_list[n])
        nocp_energy_by_level[n] = sum(energies_dict[v]
                                      for v in nocp_compute_list[n])

        # Special vmfc case
        if n > 1:
            vmfc_energy_body_dict[n] = vmfc_energy_body_dict[n - 1]
        for tup in vmfc_level_list[n]:
            vmfc_energy_body_dict[n] += (
                (-1)**(n - len(tup[0]))) * energies_dict[tup]

        # Do ptype
        if ptype != 'energy':
            _sum_cluster_ptype_data(ptype, ptype_dict, cp_compute_list[n],
                                    fragment_slice_dict, fragment_size_dict,
                                    cp_ptype_by_level[n])
            _sum_cluster_ptype_data(ptype, ptype_dict, nocp_compute_list[n],
                                    fragment_slice_dict, fragment_size_dict,
                                    nocp_ptype_by_level[n])
            _sum_cluster_ptype_data(ptype,
                                    ptype_dict,
                                    vmfc_level_list[n],
                                    fragment_slice_dict,
                                    fragment_size_dict,
                                    vmfc_ptype_by_level[n],
                                    vmfc=True)
    # Compute cp energy and ptype
    if do_cp:
        for n in nbody_range:
            if n == max_frag:
                cp_energy_body_dict[n] = cp_energy_by_level[n]
                if ptype != 'energy':
                    cp_ptype_body_dict[n][:] = cp_ptype_by_level[n]
                continue

            for k in range(1, n + 1):
                take_nk = nCr(max_frag - k - 1, n - k)
                sign = ((-1)**(n - k))
                value = cp_energy_by_level[k]
                cp_energy_body_dict[n] += take_nk * sign * value

                if ptype != 'energy':
                    value = cp_ptype_by_level[k]
                    cp_ptype_body_dict[n] += take_nk * sign * value

        _print_nbody_energy(cp_energy_body_dict, "Counterpoise Corrected (CP)")
        cp_interaction_energy = cp_energy_body_dict[
            max_nbody] - cp_energy_body_dict[1]
        psi4.set_variable('Counterpoise Corrected Total Energy',
                          cp_energy_body_dict[max_nbody])
        psi4.set_variable('Counterpoise Corrected Interaction Energy',
                          cp_interaction_energy)

        for n in nbody_range[1:]:
            var_key = 'CP-CORRECTED %d-BODY INTERACTION ENERGY' % n
            psi4.set_variable(var_key,
                              cp_energy_body_dict[n] - cp_energy_body_dict[1])

    # Compute nocp energy and ptype
    if do_nocp:
        for n in nbody_range:
            if n == max_frag:
                nocp_energy_body_dict[n] = nocp_energy_by_level[n]
                if ptype != 'energy':
                    nocp_ptype_body_dict[n][:] = nocp_ptype_by_level[n]
                continue

            for k in range(1, n + 1):
                take_nk = nCr(max_frag - k - 1, n - k)
                sign = ((-1)**(n - k))
                value = nocp_energy_by_level[k]
                nocp_energy_body_dict[n] += take_nk * sign * value

                if ptype != 'energy':
                    value = nocp_ptype_by_level[k]
                    nocp_ptype_body_dict[n] += take_nk * sign * value

        _print_nbody_energy(nocp_energy_body_dict,
                            "Non-Counterpoise Corrected (NoCP)")
        nocp_interaction_energy = nocp_energy_body_dict[
            max_nbody] - nocp_energy_body_dict[1]
        psi4.set_variable('Non-Counterpoise Corrected Total Energy',
                          nocp_energy_body_dict[max_nbody])
        psi4.set_variable('Non-Counterpoise Corrected Interaction Energy',
                          nocp_interaction_energy)

        for n in nbody_range[1:]:
            var_key = 'NOCP-CORRECTED %d-BODY INTERACTION ENERGY' % n
            psi4.set_variable(
                var_key, nocp_energy_body_dict[n] - nocp_energy_body_dict[1])

    # Compute vmfc energy and ptype
    if do_vmfc:
        _print_nbody_energy(vmfc_energy_body_dict,
                            "Valiron-Mayer Function Couterpoise (VMFC)")
        vmfc_interaction_energy = vmfc_energy_body_dict[
            max_nbody] - vmfc_energy_body_dict[1]
        psi4.set_variable('Valiron-Mayer Function Couterpoise Total Energy',
                          vmfc_energy_body_dict[max_nbody])
        psi4.set_variable(
            'Valiron-Mayer Function Couterpoise Interaction Energy',
            vmfc_interaction_energy)

        for n in nbody_range[1:]:
            var_key = 'VMFC-CORRECTED %d-BODY INTERACTION ENERGY' % n
            psi4.set_variable(
                var_key, vmfc_energy_body_dict[n] - vmfc_energy_body_dict[1])

    if return_method == 'cp':
        ptype_body_dict = cp_ptype_body_dict
        energy_body_dict = cp_energy_body_dict
    elif return_method == 'nocp':
        ptype_body_dict = nocp_ptype_body_dict
        energy_body_dict = nocp_energy_body_dict
    elif return_method == 'vmfc':
        ptype_body_dict = vmfc_ptype_body_dict
        energy_body_dict = vmfc_energy_body_dict
    else:
        raise ValidationError(
            "N-Body Wrapper: Invalid return type. Should never be here, please post this error on github."
        )

    # Figure out and build return types
    if return_total_data:
        ret_energy = energy_body_dict[max_nbody]
    else:
        ret_energy = energy_body_dict[max_nbody]
        ret_energy -= energy_body_dict[1]

    if ptype != 'energy':
        if return_total_data:
            np_final_ptype = ptype_body_dict[max_nbody].copy()
        else:
            np_final_ptype = ptype_body_dict[max_nbody].copy()
            np_final_ptype -= ptype_body_dict[1]

            ret_ptype = psi4.Matrix(*np_cp_final_ptype.shape)
            ret_ptype_view = np.asarray(final_ptype)
            ret_ptype_view[:] = np_final_ptype
    else:
        ret_ptype = ret_energy

    # Build and set a wavefunction
    wfn = psi4.new_wavefunction(molecule, 'sto-3g')
    wfn.nbody_energy = energies_dict
    wfn.nbody_ptype = ptype_dict
    wfn.nbody_body_energy = energy_body_dict
    wfn.nbody_body_ptype = ptype_body_dict

    if ptype == 'gradient':
        wfn.set_gradient(ret_ptype)
    elif ptype == 'hessian':
        wfn.set_hessian(ret_ptype)

    psi4.set_variable("CURRENT ENERGY", ret_energy)

    if return_wfn:
        return (ret_ptype, wfn)
    else:
        return ret_ptype
Пример #39
0
def frac_traverse(molecule, **kwargs):
    kwargs = p4util.kwargs_lower(kwargs)

    # The molecule is required, and should be the neutral species
    molecule.update_geometry()
    charge0 = molecule.molecular_charge()
    mult0 = molecule.multiplicity()

    chargep = charge0 + 1
    chargem = charge0 - 1

    # By default, the multiplicity of the cation/anion are mult0 + 1
    # These are overridden with the cation_mult and anion_mult kwargs
    multp = kwargs.get('cation_mult', mult0 + 1)
    multm = kwargs.get('anion_mult', mult0 + 1)

    # By default, we start the frac procedure on the 25th iteration
    # when not reading a previous guess
    frac_start = kwargs.get('frac_start', 25)

    # By default, we occupy by tenths of electrons
    HOMO_occs = kwargs.get('HOMO_occs', [1.0, 0.9, 0.8, 0.7, 0.6, 0.5, 0.4, 0.3, 0.2, 0.1, 0.0])
    LUMO_occs = kwargs.get('LUMO_occs', [1.0, 0.9, 0.8, 0.7, 0.6, 0.5, 0.4, 0.3, 0.2, 0.1, 0.0])

    # By default, H**O and LUMO are both in alpha
    Z = 0;
    for A in range(molecule.natom()):
        Z += molecule.Z(A)
    Z -= charge0
    H**O = kwargs.get('H**O', (Z / 2 + 1 if (Z % 2) else Z / 2))
    LUMO = kwargs.get('LUMO', H**O + 1)

    # By default, DIIS in FRAC (1.0 occupation is always DIIS'd)
    frac_diis = kwargs.get('frac_diis', True)

    # By default, use the neutral orbitals as a guess for the anion
    neutral_guess = kwargs.get('neutral_guess', True)

    # By default, burn-in with UHF first, if UKS
    hf_guess = False
    if psi4.get_global_option('REFERENCE') == 'UKS':
        hf_guess = kwargs.get('hf_guess', True)

    # By default, re-guess at each N
    continuous_guess = kwargs.get('continuous_guess', False)

    # By default, drop the files to the molecule's name
    root = kwargs.get('filename', molecule.name())
    traverse_filename = root + '.traverse.dat'
    # => Traverse <= #
    occs = []
    energies = []
    potentials = []
    convs = []

    # => Run the neutral for its orbitals, if requested <= #

    old_df_ints_io = psi4.get_global_option("DF_INTS_IO")
    psi4.set_global_option("DF_INTS_IO", "SAVE")

    old_guess = psi4.get_global_option("GUESS")
    if (neutral_guess):
        if (hf_guess):
            psi4.set_global_option("REFERENCE","UHF")
        energy('scf')
        psi4.set_global_option("GUESS", "READ")
        psi4.set_global_option("DF_INTS_IO", "LOAD")

    # => Run the anion first <= #

    molecule.set_molecular_charge(chargem)
    molecule.set_multiplicity(multm)

    # => Burn the anion in with hf, if requested <= #
    if hf_guess:
        psi4.set_global_option("REFERENCE","UHF")
        energy('scf', molecule=molecule, **kwargs)
        psi4.set_global_option("REFERENCE","UKS")
        psi4.set_global_option("GUESS", "READ")
        psi4.set_global_option("DF_INTS_IO", "SAVE")

    psi4.set_global_option("FRAC_START", frac_start)
    psi4.set_global_option("FRAC_RENORMALIZE", True)
    psi4.set_global_option("FRAC_LOAD", False)

    for occ in LUMO_occs:

        psi4.set_global_option("FRAC_OCC", [LUMO])
        psi4.set_global_option("FRAC_VAL", [occ])

        E, wfn = energy('scf', return_wfn=True, molecule=molecule, **kwargs)
        C = 1
        if E == 0.0:
            E = psi4.get_variable('SCF ITERATION ENERGY')
            C = 0

        if LUMO > 0:
            eps = wfn.epsilon_a()
            potentials.append(eps[int(LUMO) - 1])
        else:
            eps = wfn.epsilon_b()
            potentials.append(eps[-int(LUMO) - 1])

        occs.append(occ)
        energies.append(E)
        convs.append(C)

        psi4.set_global_option("FRAC_START", 2)
        psi4.set_global_option("FRAC_LOAD", True)
        psi4.set_global_option("GUESS", "READ")
        psi4.set_global_option("FRAC_DIIS", frac_diis)
        psi4.set_global_option("DF_INTS_IO", "LOAD")


    # => Run the neutral next <= #

    molecule.set_molecular_charge(charge0)
    molecule.set_multiplicity(mult0)

    # Burn the neutral in with hf, if requested <= #

    if not continuous_guess:
        psi4.set_global_option("GUESS", old_guess)
        if hf_guess:
            psi4.set_global_option("FRAC_START", 0)
            psi4.set_global_option("REFERENCE", "UHF")
            energy('scf', molecule=molecule, **kwargs)
            psi4.set_global_option("REFERENCE", "UKS")
            psi4.set_global_option("GUESS", "READ")
        psi4.set_global_option("FRAC_LOAD", False)

    psi4.set_global_option("FRAC_START", frac_start)
    psi4.set_global_option("FRAC_RENORMALIZE", True)

    for occ in HOMO_occs:

        psi4.set_global_option("FRAC_OCC", [H**O])
        psi4.set_global_option("FRAC_VAL", [occ])

        E, wfn = energy('scf', return_wfn=True, molecule=molecule, **kwargs)
        C = 1
        if E == 0.0:
            E = psi4.get_variable('SCF ITERATION ENERGY')
            C = 0

        if LUMO > 0:
            eps = wfn.epsilon_a()
            potentials.append(eps[int(H**O) - 1])
        else:
            eps = wfn.epsilon_b()
            potentials.append(eps[-int(H**O) - 1])

        occs.append(occ - 1.0)
        energies.append(E)
        convs.append(C)

        psi4.set_global_option("FRAC_START", 2)
        psi4.set_global_option("FRAC_LOAD", True)
        psi4.set_global_option("GUESS", "READ")
        psi4.set_global_option("FRAC_DIIS", frac_diis)
        psi4.set_global_option("DF_INTS_IO", "LOAD")

    psi4.set_global_option("DF_INTS_IO", old_df_ints_io)

    # => Print the results out <= #
    E = {}
    psi4.print_out("""\n    ==> Fractional Occupation Traverse Results <==\n\n""")
    psi4.print_out("""\t%-11s %-24s %-24s %11s\n""" % ('N', 'Energy', 'H**O Energy', 'Converged'))
    for k in range(len(occs)):
        psi4.print_out("""\t%11.3E %24.16E %24.16E %11d\n""" % (occs[k], energies[k], potentials[k], convs[k]))
        E[occs[k]] = energies[k]

    psi4.print_out('\n\t"You trying to be a hero Watkins?"\n')
    psi4.print_out('\t"Just trying to kill some bugs sir!"\n')
    psi4.print_out('\t\t\t-Starship Troopers\n')

    # Drop the files out
    fh = open(traverse_filename, 'w')
    fh.write("""\t%-11s %-24s %-24s %11s\n""" % ('N', 'Energy', 'H**O Energy', 'Converged'))
    for k in range(len(occs)):
        fh.write("""\t%11.3E %24.16E %24.16E %11d\n""" % (occs[k], energies[k], potentials[k], convs[k]))
    fh.close()

    # Properly, should clone molecule but since not returned and easy to unblemish,
    molecule.set_molecular_charge(charge0)
    molecule.set_multiplicity(mult0)

    return E
Пример #40
0
def run_gaussian_2(name, **kwargs):

    # throw an exception for open-shells
    if (psi4.get_option('SCF','REFERENCE') != 'RHF' ):
        raise ValidationError("""g2 computations require "reference rhf".""")

    # stash user options:
    optstash = p4util.OptionsState(
        ['FNOCC','COMPUTE_TRIPLES'],
        ['FNOCC','COMPUTE_MP4_TRIPLES'],
        ['FREEZE_CORE'],
        ['MP2_TYPE'],
        ['SCF','SCF_TYPE'])

    # override default scf_type
    psi4.set_local_option('SCF','SCF_TYPE','PK')

    # optimize geometry at scf level
    psi4.clean()
    psi4.set_global_option('BASIS',"6-31G(D)")
    driver.optimize('scf')
    psi4.clean()

    # scf frequencies for zpe
    # NOTE This line should not be needed, but without it there's a seg fault
    scf_e, ref = driver.frequency('scf', return_wfn=True)

    # thermodynamic properties
    du = psi4.get_variable('INTERNAL ENERGY CORRECTION')
    dh = psi4.get_variable('ENTHALPY CORRECTION')
    dg = psi4.get_variable('GIBBS FREE ENERGY CORRECTION')

    freqs   = ref.frequencies()
    nfreq   = freqs.dim(0)
    freqsum = 0.0
    for i in range(0, nfreq):
        freqsum += freqs.get(i)
    zpe = freqsum / p4const.psi_hartree2wavenumbers * 0.8929 * 0.5
    psi4.clean()

    # optimize geometry at mp2 (no frozen core) level
    # note: freeze_core isn't an option in MP2
    psi4.set_global_option('FREEZE_CORE',"FALSE")
    psi4.set_global_option('MP2_TYPE', 'CONV')
    driver.optimize('mp2')
    psi4.clean()

    # qcisd(t)
    psi4.set_local_option('FNOCC','COMPUTE_MP4_TRIPLES',"TRUE")
    psi4.set_global_option('FREEZE_CORE',"TRUE")
    psi4.set_global_option('BASIS',"6-311G(D_P)")
    ref = driver.proc.run_fnocc('qcisd(t)', return_wfn=True, **kwargs)

    # HLC: high-level correction based on number of valence electrons
    nirrep = ref.nirrep()
    frzcpi = ref.frzcpi()
    nfzc = 0
    for i in range (0,nirrep):
        nfzc += frzcpi[i]
    nalpha = ref.nalpha() - nfzc
    nbeta  = ref.nbeta() - nfzc
    # hlc of gaussian-2
    hlc = -0.00481 * nalpha -0.00019 * nbeta
    # hlc of gaussian-1
    hlc1 = -0.00614 * nalpha

    eqci_6311gdp = psi4.get_variable("QCISD(T) TOTAL ENERGY")
    emp4_6311gd  = psi4.get_variable("MP4 TOTAL ENERGY")
    emp2_6311gd  = psi4.get_variable("MP2 TOTAL ENERGY")
    psi4.clean()

    # correction for diffuse functions
    psi4.set_global_option('BASIS',"6-311+G(D_P)")
    driver.energy('mp4')
    emp4_6311pg_dp = psi4.get_variable("MP4 TOTAL ENERGY")
    emp2_6311pg_dp = psi4.get_variable("MP2 TOTAL ENERGY")
    psi4.clean()

    # correction for polarization functions
    psi4.set_global_option('BASIS',"6-311G(2DF_P)")
    driver.energy('mp4')
    emp4_6311g2dfp = psi4.get_variable("MP4 TOTAL ENERGY")
    emp2_6311g2dfp = psi4.get_variable("MP2 TOTAL ENERGY")
    psi4.clean()

    # big basis mp2
    psi4.set_global_option('BASIS',"6-311+G(3DF_2P)")
    #run_fnocc('_mp2',**kwargs)
    driver.energy('mp2')
    emp2_big = psi4.get_variable("MP2 TOTAL ENERGY")
    psi4.clean()
    eqci       = eqci_6311gdp
    e_delta_g2 = emp2_big + emp2_6311gd - emp2_6311g2dfp - emp2_6311pg_dp
    e_plus     = emp4_6311pg_dp - emp4_6311gd
    e_2df      = emp4_6311g2dfp - emp4_6311gd

    eg2 = eqci + e_delta_g2 + e_plus + e_2df
    eg2_mp2_0k = eqci + (emp2_big - emp2_6311gd) + hlc + zpe

    psi4.print_out('\n')
    psi4.print_out('  ==>  G1/G2 Energy Components  <==\n')
    psi4.print_out('\n')
    psi4.print_out('        QCISD(T):            %20.12lf\n' % eqci)
    psi4.print_out('        E(Delta):            %20.12lf\n' % e_delta_g2)
    psi4.print_out('        E(2DF):              %20.12lf\n' % e_2df)
    psi4.print_out('        E(+):                %20.12lf\n' % e_plus)
    psi4.print_out('        E(G1 HLC):           %20.12lf\n' % hlc1)
    psi4.print_out('        E(G2 HLC):           %20.12lf\n' % hlc)
    psi4.print_out('        E(ZPE):              %20.12lf\n' % zpe)
    psi4.print_out('\n')
    psi4.print_out('  ==>  0 Kelvin Results  <==\n')
    psi4.print_out('\n')
    eg2_0k = eg2 + zpe + hlc
    psi4.print_out('        G1:                  %20.12lf\n' % (eqci + e_plus + e_2df + hlc1 + zpe))
    psi4.print_out('        G2(MP2):             %20.12lf\n' % eg2_mp2_0k)
    psi4.print_out('        G2:                  %20.12lf\n' % eg2_0k)

    psi4.set_variable("G1 TOTAL ENERGY",eqci + e_plus + e_2df + hlc1 + zpe)
    psi4.set_variable("G2 TOTAL ENERGY",eg2_0k)
    psi4.set_variable("G2(MP2) TOTAL ENERGY",eg2_mp2_0k)

    psi4.print_out('\n')
    T = psi4.get_global_option('T')
    psi4.print_out('  ==>  %3.0lf Kelvin Results  <==\n'% T)
    psi4.print_out('\n')

    internal_energy = eg2_mp2_0k + du - zpe / 0.8929
    enthalpy        = eg2_mp2_0k + dh - zpe / 0.8929
    gibbs           = eg2_mp2_0k + dg - zpe / 0.8929

    psi4.print_out('        G2(MP2) energy:      %20.12lf\n' % internal_energy )
    psi4.print_out('        G2(MP2) enthalpy:    %20.12lf\n' % enthalpy)
    psi4.print_out('        G2(MP2) free energy: %20.12lf\n' % gibbs)
    psi4.print_out('\n')

    psi4.set_variable("G2(MP2) INTERNAL ENERGY",internal_energy)
    psi4.set_variable("G2(MP2) ENTHALPY",enthalpy)
    psi4.set_variable("G2(MP2) FREE ENERGY",gibbs)

    internal_energy = eg2_0k + du - zpe / 0.8929
    enthalpy        = eg2_0k + dh - zpe / 0.8929
    gibbs           = eg2_0k + dg - zpe / 0.8929

    psi4.print_out('        G2 energy:           %20.12lf\n' % internal_energy )
    psi4.print_out('        G2 enthalpy:         %20.12lf\n' % enthalpy)
    psi4.print_out('        G2 free energy:      %20.12lf\n' % gibbs)

    psi4.set_variable("CURRENT ENERGY",eg2_0k)

    psi4.set_variable("G2 INTERNAL ENERGY",internal_energy)
    psi4.set_variable("G2 ENTHALPY",enthalpy)
    psi4.set_variable("G2 FREE ENERGY",gibbs)

    psi4.clean()

    optstash.restore()

    # return 0K g2 results
    return eg2_0k
Пример #41
0
def ip_fitting(molecule, omega_l, omega_r, **kwargs):
    kwargs = p4util.kwargs_lower(kwargs)

    # By default, zero the omega to 3 digits
    omega_tol = kwargs.get('omega_tolerance', 1.0E-3)

    # By default, do up to twenty iterations
    maxiter = kwargs.get('maxiter', 20)

    # By default, do not read previous 180 orbitals file
    read = False
    read180 = ''
    if 'read' in kwargs:
        read = True
        read180 = kwargs['read']

    # The molecule is required, and should be the neutral species
    molecule.update_geometry()
    charge0 = molecule.molecular_charge()
    mult0 = molecule.multiplicity()

    # How many electrons are there?
    N = 0
    for A in range(molecule.natom()):
        N += molecule.Z(A)
    N -= charge0
    N = int(N)
    Nb = int((N - mult0 + 1) / 2)
    Na = int(N - Nb)

    # Work in the ot namespace for this procedure
    psi4.IO.set_default_namespace("ot")

    # Burn in to determine orbital eigenvalues
    if read:
        psi4.set_global_option("GUESS", "READ")
        copy_file_to_scratch(read180, 'psi', 'ot', 180)
    old_guess = psi4.get_global_option("GUESS")
    psi4.set_global_option("DF_INTS_IO", "SAVE")
    psi4.print_out("""\n\t==> IP Fitting SCF: Burn-in <==\n""")
    E, wfn = energy('scf', return_wfn=True, molecule=molecule, **kwargs)
    psi4.set_global_option("DF_INTS_IO", "LOAD")

    # Determine H**O, to determine mult1
    eps_a = wfn.epsilon_a()
    eps_b = wfn.epsilon_b()
    if Na == Nb:
        H**O = -Nb
    elif Nb == 0:
        H**O = Na
    else:
        E_a = eps_a[int(Na - 1)]
        E_b = eps_b[int(Nb - 1)]
        if E_a >= E_b:
            H**O = Na
        else:
            H**O = -Nb

    Na1 = Na;
    Nb1 = Nb;
    if H**O > 0:
        Na1 = Na1 - 1;
    else:
        Nb1 = Nb1 - 1;

    charge1 = charge0 + 1;
    mult1 = Na1 - Nb1 + 1

    omegas = []
    E0s = []
    E1s = []
    kIPs = []
    IPs = []
    types = []

    # Right endpoint
    psi4.set_global_option('DFT_OMEGA', omega_r)

    # Neutral
    if read:
        psi4.set_global_option("GUESS", "READ")
        p4util.copy_file_to_scratch(read180, 'psi', 'ot', 180)

    molecule.set_molecular_charge(charge0)
    molecule.set_multiplicity(mult0)
    psi4.print_out("""\n\t==> IP Fitting SCF: Neutral, Right Endpoint <==\n""")
    E0r, wfn = energy('scf', return_wfn=True, molecule=molecule, **kwargs)
    eps_a = wfn.epsilon_a()
    eps_b = wfn.epsilon_b()
    E_HOMO = 0.0;
    if Nb == 0:
        E_HOMO = eps_a[int(Na - 1)]
    else:
        E_a = eps_a[int(Na - 1)]
        E_b = eps_b[int(Nb - 1)]
        if E_a >= E_b:
            E_HOMO = E_a
        else:
            E_HOMO = E_b
    E_HOMOr = E_HOMO
    psi4.IO.change_file_namespace(180, "ot", "neutral")

    # Cation
    if read:
        psi4.set_global_option("GUESS", "READ")
        p4util.copy_file_to_scratch(read180, 'psi', 'ot', 180)

    molecule.set_molecular_charge(charge1)
    molecule.set_multiplicity(mult1)
    psi4.print_out("""\n\t==> IP Fitting SCF: Cation, Right Endpoint <==\n""")
    E1r = energy('scf', molecule=molecule, **kwargs)
    psi4.IO.change_file_namespace(180, "ot", "cation")

    IPr = E1r - E0r;
    kIPr = -E_HOMOr;
    delta_r = IPr - kIPr;

    if IPr > kIPr:
        message = ("""\n***IP Fitting Error: Right Omega limit should have kIP > IP""")
        raise ValidationError(message)

    omegas.append(omega_r)
    types.append('Right Limit')
    E0s.append(E0r)
    E1s.append(E1r)
    IPs.append(IPr)
    kIPs.append(kIPr)

    # Use previous orbitals from here out
    psi4.set_global_option("GUESS", "READ")

    # Left endpoint
    psi4.set_global_option('DFT_OMEGA', omega_l)

    # Neutral
    psi4.IO.change_file_namespace(180, "neutral", "ot")
    molecule.set_molecular_charge(charge0)
    molecule.set_multiplicity(mult0)
    psi4.print_out("""\n\t==> IP Fitting SCF: Neutral, Left Endpoint <==\n""")
    E0l, wfn = energy('scf', return_wfn=True, molecule=molecule, **kwargs)
    eps_a = wfn.epsilon_a()
    eps_b = wfn.epsilon_b()
    E_HOMO = 0.0
    if Nb == 0:
        E_HOMO = eps_a[int(Na - 1)]
    else:
        E_a = eps_a[int(Na - 1)]
        E_b = eps_b[int(Nb - 1)]
        if E_a >= E_b:
            E_HOMO = E_a
        else:
            E_HOMO = E_b
    E_HOMOl = E_HOMO
    psi4.IO.change_file_namespace(180, "ot", "neutral")

    # Cation
    psi4.IO.change_file_namespace(180, "cation", "ot")
    molecule.set_molecular_charge(charge1)
    molecule.set_multiplicity(mult1)
    psi4.print_out("""\n\t==> IP Fitting SCF: Cation, Left Endpoint <==\n""")
    E1l = energy('scf', molecule=molecule, **kwargs)
    psi4.IO.change_file_namespace(180, "ot", "cation")

    IPl = E1l - E0l
    kIPl = -E_HOMOl
    delta_l = IPl - kIPl

    if IPl < kIPl:
        message = ("""\n***IP Fitting Error: Left Omega limit should have kIP < IP""")
        raise ValidationError(message)

    omegas.append(omega_l)
    types.append('Left Limit')
    E0s.append(E0l)
    E1s.append(E1l)
    IPs.append(IPl)
    kIPs.append(kIPl)

    converged = False
    repeat_l = 0
    repeat_r = 0
    step = 0
    while True:

        step = step + 1

        # Regula Falsi (modified)
        if repeat_l > 1:
            delta_l = delta_l / 2.0
        if repeat_r > 1:
            delta_r = delta_r / 2.0
        omega = - (omega_r - omega_l) / (delta_r - delta_l) * delta_l + omega_l
        psi4.set_global_option('DFT_OMEGA', omega)

        # Neutral
        psi4.IO.change_file_namespace(180, "neutral", "ot")
        molecule.set_molecular_charge(charge0)
        molecule.set_multiplicity(mult0)
        psi4.print_out("""\n\t==> IP Fitting SCF: Neutral, Omega = %11.3E <==\n""" % omega)
        E0, wfn = energy('scf', return_wfn=True, molecule=molecule, **kwargs)
        eps_a = wfn.epsilon_a()
        eps_b = wfn.epsilon_b()
        E_HOMO = 0.0
        if Nb == 0:
            E_HOMO = eps_a[int(Na - 1)]
        else:
            E_a = eps_a[int(Na - 1)]
            E_b = eps_b[int(Nb - 1)]
            if E_a >= E_b:
                E_HOMO = E_a
            else:
                E_HOMO = E_b
        psi4.IO.change_file_namespace(180, "ot", "neutral")

        # Cation
        psi4.IO.change_file_namespace(180, "cation", "ot")
        molecule.set_molecular_charge(charge1)
        molecule.set_multiplicity(mult1)
        psi4.print_out("""\n\t==> IP Fitting SCF: Cation, Omega = %11.3E <==\n""" % omega)
        E1 = energy('scf', molecule=molecule, **kwargs)
        psi4.IO.change_file_namespace(180, "ot", "cation")

        IP = E1 - E0
        kIP = -E_HOMO
        delta = IP - kIP

        if kIP > IP:
            omega_r = omega
            E0r = E0
            E1r = E1
            IPr = IP
            kIPr = kIP
            delta_r = delta
            repeat_r = 0
            repeat_l = repeat_l + 1
        else:
            omega_l = omega
            E0l = E0
            E1l = E1
            IPl = IP
            kIPl = kIP
            delta_l = delta
            repeat_l = 0;
            repeat_r = repeat_r + 1

        omegas.append(omega)
        types.append('Regula-Falsi')
        E0s.append(E0)
        E1s.append(E1)
        IPs.append(IP)
        kIPs.append(kIP)

        # Termination
        if (abs(omega_l - omega_r) < omega_tol or step > maxiter):
            converged = True
            break

    # Properly, should clone molecule but since not returned and easy to unblemish,
    molecule.set_molecular_charge(charge0)
    molecule.set_multiplicity(mult0)
    psi4.IO.set_default_namespace("")

    psi4.print_out("""\n\t==> IP Fitting Results <==\n\n""")

    psi4.print_out("""\t => Occupation Determination <= \n\n""")
    psi4.print_out("""\t          %6s %6s %6s %6s %6s %6s\n""" % ('N', 'Na', 'Nb', 'Charge', 'Mult', 'H**O'))
    psi4.print_out("""\t Neutral: %6d %6d %6d %6d %6d %6d\n""" % (N, Na, Nb, charge0, mult0, H**O))
    psi4.print_out("""\t Cation:  %6d %6d %6d %6d %6d\n\n""" % (N - 1, Na1, Nb1, charge1, mult1))

    psi4.print_out("""\t => Regula Falsi Iterations <=\n\n""")
    psi4.print_out("""\t%3s %11s %14s %14s %14s %s\n""" % ('N','Omega','IP','kIP','Delta','Type'))
    for k in range(len(omegas)):
        psi4.print_out("""\t%3d %11.3E %14.6E %14.6E %14.6E %s\n""" % 
                       (k + 1, omegas[k], IPs[k], kIPs[k], IPs[k] - kIPs[k], types[k]))
    if converged:
        psi4.print_out("""\n\tIP Fitting Converged\n""")
        psi4.print_out("""\tFinal omega = %14.6E\n""" % ((omega_l + omega_r) / 2))
        psi4.print_out("""\n\t"M,I. does the dying. Fleet just does the flying."\n""")
        psi4.print_out("""\t\t\t-Starship Troopers\n""")

    else:
        psi4.print_out("""\n\tIP Fitting did not converge!\n""")

    psi4.set_global_option("DF_INTS_IO", "NONE")
    psi4.set_global_option("GUESS", old_guess)
Пример #42
0
def frac_nuke(molecule, **kwargs):
    kwargs = p4util.kwargs_lower(kwargs)

    # The molecule is required, and should be the neutral species
    molecule.update_geometry()
    charge0 = molecule.molecular_charge()
    mult0 = molecule.multiplicity()

    # By default, we start the frac procedure on the 25th iteration
    # when not reading a previous guess
    frac_start = kwargs.get('frac_start', 25)

    # By default, we occupy by tenths of electrons
    foccs = kwargs.get('foccs',
                       [1.0, 0.9, 0.8, 0.7, 0.6, 0.5, 0.4, 0.3, 0.2, 0.1, 0.0])

    # By default, H**O and LUMO are both in alpha
    N = 0
    for A in range(molecule.natom()):
        N += molecule.Z(A)
    N -= charge0
    N = int(N)
    Nb = int((N - mult0 + 1) / 2)
    Na = int(N - Nb)

    charge = charge0
    mult = mult0

    # By default, nuke all the electrons
    Nmin = 0
    if ('nmax' in kwargs):
        Nmin = N - int(kwargs['nmax'])

    # By default, DIIS in FRAC (1.0 occupation is always DIIS'd)
    frac_diis = kwargs.get('frac_diis', True)

    # By default, drop the files to the molecule's name
    root = kwargs.get('filename', molecule.name())
    traverse_filename = root + '.traverse.dat'
    stats_filename = root + '.stats.dat'

    # => Traverse <= #
    psi4.set_global_option("DF_INTS_IO", "SAVE")

    Ns = []
    energies = []
    potentials = []
    convs = []
    stats = []

    # Run one SCF to burn things in
    E, wfn = energy('scf', return_wfn=True, molecule=molecule, **kwargs)

    # Determine H**O
    eps_a = wfn.epsilon_a()
    eps_b = wfn.epsilon_b()
    if Na == Nb:
        H**O = -Nb
    elif Nb == 0:
        H**O = Na
    else:
        E_a = eps_a[int(Na - 1)]
        E_b = eps_b[int(Nb - 1)]
        if E_a >= E_b:
            H**O = Na
        else:
            H**O = -Nb

    stats.append("""\t%6d %6d %6d %6d %6d %6d\n""" %
                 (N, Na, Nb, charge, mult, H**O))

    if H**O > 0:
        Na = Na - 1
    else:
        Nb = Nb - 1
    charge = charge + 1
    mult = Na - Nb + 1

    psi4.set_global_option("DF_INTS_IO", "LOAD")
    psi4.set_global_option("FRAC_START", frac_start)
    psi4.set_global_option("FRAC_RENORMALIZE", True)

    # Nuke 'em Rico!
    for Nintegral in range(N, Nmin, -1):

        # Nuke the current H**O
        for occ in foccs:

            psi4.set_global_option("FRAC_OCC", [H**O])
            psi4.set_global_option("FRAC_VAL", [occ])

            E, wfn = energy('scf',
                            return_wfn=True,
                            molecule=molecule,
                            **kwargs)
            C = 1
            if E == 0.0:
                E = psi4.get_variable('SCF ITERATION ENERGY')
                C = 0

            if H**O > 0:
                eps = wfn.epsilon_a()
                potentials.append(eps[H**O - 1])
            else:
                eps = wfn.epsilon_b()
                potentials.append(eps[-H**O - 1])

            Ns.append(Nintegral + occ - 1.0)
            energies.append(E)
            convs.append(C)

            psi4.set_global_option("FRAC_START", 2)
            psi4.set_global_option("FRAC_LOAD", True)
            psi4.set_global_option("FRAC_DIIS", frac_diis)
            psi4.set_global_option("GUESS", "READ")

        # Set the next charge/mult
        molecule.set_molecular_charge(charge)
        molecule.set_multiplicity(mult)

        # Determine H**O
        print('DGAS: What ref should this point to?')
        #ref = psi4.legacy_wavefunction()
        eps_a = wfn.epsilon_a()
        eps_b = wfn.epsilon_b()
        if Na == Nb:
            H**O = -Nb
        elif Nb == 0:
            H**O = Na
        else:
            E_a = eps_a[int(Na - 1)]
            E_b = eps_b[int(Nb - 1)]
            if E_a >= E_b:
                H**O = Na
            else:
                H**O = -Nb

        stats.append("""\t%6d %6d %6d %6d %6d %6d\n""" %
                     (Nintegral - 1, Na, Nb, charge, mult, H**O))

        if H**O > 0:
            Na = Na - 1
        else:
            Nb = Nb - 1
        charge = charge + 1
        mult = Na - Nb + 1

    psi4.set_global_option("DF_INTS_IO", "NONE")

    # => Print the results out <= #
    E = {}
    psi4.print_out("""\n    ==> Fractional Occupation Nuke Results <==\n\n""")
    psi4.print_out("""\t%-11s %-24s %-24s %11s\n""" %
                   ('N', 'Energy', 'H**O Energy', 'Converged'))
    for k in range(len(Ns)):
        psi4.print_out("""\t%11.3E %24.16E %24.16E %11d\n""" %
                       (Ns[k], energies[k], potentials[k], convs[k]))
        E[Ns[k]] = energies[k]

    psi4.print_out('\n')
    psi4.print_out("""\t%6s %6s %6s %6s %6s %6s\n""" %
                   ('N', 'Na', 'Nb', 'Charge', 'Mult', 'H**O'))
    for line in stats:
        psi4.print_out(line)

    psi4.print_out(
        '\n\t"You shoot a nuke down a bug hole, you got a lot of dead bugs"\n')
    psi4.print_out('\t\t\t-Starship Troopers\n')

    # Drop the files out
    fh = open(traverse_filename, 'w')
    fh.write("""\t%-11s %-24s %-24s %11s\n""" %
             ('N', 'Energy', 'H**O Energy', 'Converged'))
    for k in range(len(Ns)):
        fh.write("""\t%11.3E %24.16E %24.16E %11d\n""" %
                 (Ns[k], energies[k], potentials[k], convs[k]))
    fh.close()

    fh = open(stats_filename, 'w')
    fh.write("""\t%6s %6s %6s %6s %6s %6s\n""" %
             ('N', 'Na', 'Nb', 'Charge', 'Mult', 'H**O'))
    for line in stats:
        fh.write(line)
    fh.close()

    # Properly, should clone molecule but since not returned and easy to unblemish,
    molecule.set_molecular_charge(charge0)
    molecule.set_multiplicity(mult0)

    return E
Пример #43
0
def run_gaussian_2(name, **kwargs):

    # throw an exception for open-shells
    if (psi4.get_option('SCF', 'REFERENCE') != 'RHF'):
        raise ValidationError("""g2 computations require "reference rhf".""")

    # stash user options:
    optstash = p4util.OptionsState(['FNOCC', 'COMPUTE_TRIPLES'],
                                   ['FNOCC', 'COMPUTE_MP4_TRIPLES'],
                                   ['FREEZE_CORE'], ['MP2_TYPE'],
                                   ['SCF', 'SCF_TYPE'])

    # override default scf_type
    psi4.set_local_option('SCF', 'SCF_TYPE', 'PK')

    # optimize geometry at scf level
    psi4.clean()
    psi4.set_global_option('BASIS', "6-31G(D)")
    driver.optimize('scf')
    psi4.clean()

    # scf frequencies for zpe
    # NOTE This line should not be needed, but without it there's a seg fault
    scf_e, ref = driver.frequency('scf', return_wfn=True)

    # thermodynamic properties
    du = psi4.get_variable('INTERNAL ENERGY CORRECTION')
    dh = psi4.get_variable('ENTHALPY CORRECTION')
    dg = psi4.get_variable('GIBBS FREE ENERGY CORRECTION')

    freqs = ref.frequencies()
    nfreq = freqs.dim(0)
    freqsum = 0.0
    for i in range(0, nfreq):
        freqsum += freqs.get(i)
    zpe = freqsum / p4const.psi_hartree2wavenumbers * 0.8929 * 0.5
    psi4.clean()

    # optimize geometry at mp2 (no frozen core) level
    # note: freeze_core isn't an option in MP2
    psi4.set_global_option('FREEZE_CORE', "FALSE")
    psi4.set_global_option('MP2_TYPE', 'CONV')
    driver.optimize('mp2')
    psi4.clean()

    # qcisd(t)
    psi4.set_local_option('FNOCC', 'COMPUTE_MP4_TRIPLES', "TRUE")
    psi4.set_global_option('FREEZE_CORE', "TRUE")
    psi4.set_global_option('BASIS', "6-311G(D_P)")
    ref = driver.proc.run_fnocc('qcisd(t)', return_wfn=True, **kwargs)

    # HLC: high-level correction based on number of valence electrons
    nirrep = ref.nirrep()
    frzcpi = ref.frzcpi()
    nfzc = 0
    for i in range(0, nirrep):
        nfzc += frzcpi[i]
    nalpha = ref.nalpha() - nfzc
    nbeta = ref.nbeta() - nfzc
    # hlc of gaussian-2
    hlc = -0.00481 * nalpha - 0.00019 * nbeta
    # hlc of gaussian-1
    hlc1 = -0.00614 * nalpha

    eqci_6311gdp = psi4.get_variable("QCISD(T) TOTAL ENERGY")
    emp4_6311gd = psi4.get_variable("MP4 TOTAL ENERGY")
    emp2_6311gd = psi4.get_variable("MP2 TOTAL ENERGY")
    psi4.clean()

    # correction for diffuse functions
    psi4.set_global_option('BASIS', "6-311+G(D_P)")
    driver.energy('mp4')
    emp4_6311pg_dp = psi4.get_variable("MP4 TOTAL ENERGY")
    emp2_6311pg_dp = psi4.get_variable("MP2 TOTAL ENERGY")
    psi4.clean()

    # correction for polarization functions
    psi4.set_global_option('BASIS', "6-311G(2DF_P)")
    driver.energy('mp4')
    emp4_6311g2dfp = psi4.get_variable("MP4 TOTAL ENERGY")
    emp2_6311g2dfp = psi4.get_variable("MP2 TOTAL ENERGY")
    psi4.clean()

    # big basis mp2
    psi4.set_global_option('BASIS', "6-311+G(3DF_2P)")
    #run_fnocc('_mp2',**kwargs)
    driver.energy('mp2')
    emp2_big = psi4.get_variable("MP2 TOTAL ENERGY")
    psi4.clean()
    eqci = eqci_6311gdp
    e_delta_g2 = emp2_big + emp2_6311gd - emp2_6311g2dfp - emp2_6311pg_dp
    e_plus = emp4_6311pg_dp - emp4_6311gd
    e_2df = emp4_6311g2dfp - emp4_6311gd

    eg2 = eqci + e_delta_g2 + e_plus + e_2df
    eg2_mp2_0k = eqci + (emp2_big - emp2_6311gd) + hlc + zpe

    psi4.print_out('\n')
    psi4.print_out('  ==>  G1/G2 Energy Components  <==\n')
    psi4.print_out('\n')
    psi4.print_out('        QCISD(T):            %20.12lf\n' % eqci)
    psi4.print_out('        E(Delta):            %20.12lf\n' % e_delta_g2)
    psi4.print_out('        E(2DF):              %20.12lf\n' % e_2df)
    psi4.print_out('        E(+):                %20.12lf\n' % e_plus)
    psi4.print_out('        E(G1 HLC):           %20.12lf\n' % hlc1)
    psi4.print_out('        E(G2 HLC):           %20.12lf\n' % hlc)
    psi4.print_out('        E(ZPE):              %20.12lf\n' % zpe)
    psi4.print_out('\n')
    psi4.print_out('  ==>  0 Kelvin Results  <==\n')
    psi4.print_out('\n')
    eg2_0k = eg2 + zpe + hlc
    psi4.print_out('        G1:                  %20.12lf\n' %
                   (eqci + e_plus + e_2df + hlc1 + zpe))
    psi4.print_out('        G2(MP2):             %20.12lf\n' % eg2_mp2_0k)
    psi4.print_out('        G2:                  %20.12lf\n' % eg2_0k)

    psi4.set_variable("G1 TOTAL ENERGY", eqci + e_plus + e_2df + hlc1 + zpe)
    psi4.set_variable("G2 TOTAL ENERGY", eg2_0k)
    psi4.set_variable("G2(MP2) TOTAL ENERGY", eg2_mp2_0k)

    psi4.print_out('\n')
    T = psi4.get_global_option('T')
    psi4.print_out('  ==>  %3.0lf Kelvin Results  <==\n' % T)
    psi4.print_out('\n')

    internal_energy = eg2_mp2_0k + du - zpe / 0.8929
    enthalpy = eg2_mp2_0k + dh - zpe / 0.8929
    gibbs = eg2_mp2_0k + dg - zpe / 0.8929

    psi4.print_out('        G2(MP2) energy:      %20.12lf\n' % internal_energy)
    psi4.print_out('        G2(MP2) enthalpy:    %20.12lf\n' % enthalpy)
    psi4.print_out('        G2(MP2) free energy: %20.12lf\n' % gibbs)
    psi4.print_out('\n')

    psi4.set_variable("G2(MP2) INTERNAL ENERGY", internal_energy)
    psi4.set_variable("G2(MP2) ENTHALPY", enthalpy)
    psi4.set_variable("G2(MP2) FREE ENERGY", gibbs)

    internal_energy = eg2_0k + du - zpe / 0.8929
    enthalpy = eg2_0k + dh - zpe / 0.8929
    gibbs = eg2_0k + dg - zpe / 0.8929

    psi4.print_out('        G2 energy:           %20.12lf\n' % internal_energy)
    psi4.print_out('        G2 enthalpy:         %20.12lf\n' % enthalpy)
    psi4.print_out('        G2 free energy:      %20.12lf\n' % gibbs)

    psi4.set_variable("CURRENT ENERGY", eg2_0k)

    psi4.set_variable("G2 INTERNAL ENERGY", internal_energy)
    psi4.set_variable("G2 ENTHALPY", enthalpy)
    psi4.set_variable("G2 FREE ENERGY", gibbs)

    psi4.clean()

    optstash.restore()

    # return 0K g2 results
    return eg2_0k