def __init__(self, scfwfn, mints):
     nocc = scfwfn.nalpha() + scfwfn.nbeta()
     dim = mints.basisset().nbf() * 2
     Vnu = psi4.get_active_molecule().nuclear_repulsion_energy()
     indx = Index(dim, 'pqrsPQRS')
     indx.add_index_range(0, nocc, 'ijkl')
     indx.add_index_range(nocc, dim, 'abcd')
     # grab integrals and project out symmetry
     C1 = mints.petite_list().sotoao()  # Sym -> C1 projection matrix
     Fa = psi4.Matrix(dim / 2, dim / 2)
     Fb = psi4.Matrix(dim / 2, dim / 2)
     Fa.remove_symmetry(scfwfn.Fa(), C1)
     Fb.remove_symmetry(scfwfn.Fb(), C1)
     Sa = mints.ao_overlap()
     Ta = mints.ao_kinetic()
     Va = mints.ao_potential()
     Ga = mints.ao_eri()
     # build and diagonalize spin-orbital Fock matrix
     F = block_matrix_ab(Fa, Fb)
     S = block_matrix_aa(Sa)
     s, U = la.eigh(S)
     U = np.matrix(U)
     x = 1. / np.sqrt(s).real
     X = U * np.diag(x) * U.T
     tF = X * F * X
     e, tC = la.eigh(tF)
     C = X * tC
     # compute integrals
     H = block_matrix_aa(Ta) + block_matrix_aa(Va)
     G = block_4darray(Ga).swapaxes(1,
                                    2)  # < mu nu | rh si >, phys. notation
     self.nocc, self.dim, self.Vnu, self.indx = nocc, dim, Vnu, indx
     self.e, self.C, self.S, self.H, self.G, self.F = e, C, S, H, G, F
Esempio n. 2
0
def run_gpu_dfcc(name, **kwargs):
    """Function encoding sequence of PSI module calls for
    a GPU-accelerated DF-CCSD(T) computation.

    >>> energy('df-ccsd(t)')

    """
    lowername = name.lower()
    kwargs = kwargs_lower(kwargs)

    # stash user options
    optstash = OptionsState(
        ['GPU_DFCC','COMPUTE_TRIPLES'],
        ['GPU_DFCC','DFCC'],
        ['GPU_DFCC','NAT_ORBS'],
        ['SCF','DF_INTS_IO'],
        ['SCF','SCF_TYPE'])

    psi4.set_local_option('SCF','DF_INTS_IO', 'SAVE')
    psi4.set_local_option('GPU_DFCC','DFCC', True)

    # throw an exception for open-shells
    if (psi4.get_option('SCF','REFERENCE') != 'RHF' ):
        raise ValidationError("Error: %s requires \"reference rhf\"." % lowername)

    # override symmetry:
    molecule = psi4.get_active_molecule()
    molecule.update_geometry()
    molecule.reset_point_group('c1')
    molecule.fix_orientation(1)
    molecule.update_geometry()

    # triples?
    if (lowername == 'gpu-df-ccsd'):
        psi4.set_local_option('GPU_DFCC','COMPUTE_TRIPLES', False)
    if (lowername == 'gpu-df-ccsd(t)'):
        psi4.set_local_option('GPU_DFCC','COMPUTE_TRIPLES', True)
    #if (lowername == 'fno-df-ccsd'):
    #    psi4.set_local_option('GPU_DFCC','COMPUTE_TRIPLES', False)
    #    psi4.set_local_option('GPU_DFCC','NAT_ORBS', True)
    #if (lowername == 'fno-df-ccsd(t)'):
    #    psi4.set_local_option('GPU_DFCC','COMPUTE_TRIPLES', True)
    #    psi4.set_local_option('GPU_DFCC','NAT_ORBS', True)

    # set scf-type to df unless the user wants something else
    if psi4.has_option_changed('SCF','SCF_TYPE') == False:
       psi4.set_local_option('SCF','SCF_TYPE', 'DF')

    if psi4.get_option('GPU_DFCC','DF_BASIS_CC') == '':
       basis   = psi4.get_global_option('BASIS')
       dfbasis = corresponding_rifit(basis)
       psi4.set_local_option('GPU_DFCC','DF_BASIS_CC',dfbasis)

    scf_helper(name,**kwargs)
    psi4.plugin('gpu_dfcc.so')

    # restore options
    optstash.restore()

    return psi4.get_variable("CURRENT ENERGY")
Esempio n. 3
0
def generate_inputs(db,name):
    """
        Generates the input files in each sub-directory of the
        distributed finite differences property calculation.

    name: ( string ) method name passed to calling driver,
    db:   (database) The database object associated with this property
          calculation. On exit this db['inputs_generated'] has been set True

    Returns: nothing
    Throws: Exception if the number of atomic displacements is not correct.
    """
    molecule = psi4.get_active_molecule()
    natom = molecule.natom()

    # get list of displacements
    displacement_geoms = psi4.atomic_displacements(molecule)

    # Sanity Check
    # there should be 3 cords * natoms *2 directions (+/-)
    if not (6 * natom) == len(displacement_geoms):
        raise Exception('The number of atomic displacements should be 6 times'
                        ' the number of atoms!')

    displacement_names = db['job_status'].keys()

    for n, entry in enumerate(displacement_names):
        if not os.path.exists(entry):
            os.makedirs(entry)

        # Setup up input file string
        inp_template = 'molecule {molname}_{disp}'
        inp_template += ' {{\n{molecule_info}\n}}\n{options}\n{jobspec}\n'
        molecule.set_geometry(displacement_geoms[n])
        molecule.fix_orientation(True)
        molecule.fix_com(True)
        inputfile = open('{0}/input.dat'.format(entry), 'w')
        inputfile.write("# This is a psi4 input file auto-generated for"
            "computing properties by finite differences.\n\n")
        inputfile.write(
            inp_template.format(
                molname=molecule.name(),
                disp=entry,
                molecule_info=molecule.create_psi4_string_from_molecule(),
                options=p4util.format_options_for_input(),
                jobspec=db['prop_cmd']))
        inputfile.close()
    db['inputs_generated'] = True
Esempio n. 4
0
File: roa.py Progetto: xwang862/psi4
def initialize_database(database):
    database['inputs_generated'] = False
    database['jobs_complete'] = False
    database['roa_computed'] = False
    database['job_status'] = collections.OrderedDict()
    # Populate job_status
    molecule = psi4.get_active_molecule()
    natom = molecule.natom()
    coordinates = ['x', 'y', 'z']
    step_direction = ['p', 'm']

    for atom in range(1, natom + 1):
        for coord in coordinates:
            for step in step_direction:
                job_name = '{}_{}_{}'.format(atom, coord, step)
                database['job_status'].update({job_name: 'not_started'})
 def __init__(self, scfwfn, mints):
     spinorb = SpinOrbital(scfwfn, mints)
     Ep2 = spinorb.build_Ep2()  # Ep2 = 1/(fii+fjj-faa-fbb)
     K = spinorb.build_mo_K(
     )  # K   = <p|Phi><Phi|q> single-det density matrix
     h = spinorb.build_mo_H()  # h   = <p|T+V|q>      one-electron integrals
     g = spinorb.build_mo_antisymmetrized_G(
     )  # g   = <pq||rs>       two-electron integrals
     nocc, dim = spinorb.nocc, spinorb.dim
     indx = Index(dim, 'pqrst')
     indx.add_index_range(0, nocc, 'ijklm')
     indx.add_index_range(nocc, dim, 'abcde')
     # save what we need to object
     self.spinorb, self.indx, self.Ep2, self.K, self.h, self.g = spinorb, indx, Ep2, K, h, g
     self.E, self.Vnu = 0.0, psi4.get_active_molecule(
     ).nuclear_repulsion_energy()
Esempio n. 6
0
def initialize_database(database):
    database['inputs_generated'] = False
    database['jobs_complete']    = False
    database['roa_computed']     = False
    database['job_status'] = collections.OrderedDict()
    # Populate job_status 
    molecule = psi4.get_active_molecule()
    natom    = molecule.natom()
    coordinates    = ['x','y','z']
    step_direction = ['p','m']

    for atom in range(1, natom+1): 
        for coord in coordinates:
            for step in step_direction:
                job_name = '{}_{}_{}'.format(atom,coord,step)
                database['job_status'].update({job_name: 'not_started'})
Esempio n. 7
0
def initialize_database(database, name, prop, properties_array, additional_kwargs=None):
    """
        Initialize the database for computation of some property
        using distributed finite differences driver

    database: (database) the database object passed from the caller
    name:  (string) name as passed to calling driver
    prop: (string) the property being computed, used to add xxx_computed flag
        to database
    prop_array: (list of strings) properties to go in
        properties kwarg of the property() cmd in each sub-dir
    additional_kwargs: (list of strings) *optional*
        any additional kwargs that should go in the call to the
        property() driver method in each subdir


    Returns: nothing
    Throws: nothing
    """
    database['inputs_generated'] = False
    database['jobs_complete'] = False
    prop_cmd ="property('{0}',".format(name)
    prop_cmd += "properties=[ '{}' ".format(properties_array[0])
    if len(properties_array) > 1:
        for element in properties_array[1:]:
            prop_cmd += ",'{}'".format(element)
    prop_cmd += "]"
    if additional_kwargs is not None:
        for arg in additional_kwargs:
            prop_cmd += ", {}".format(arg)
    prop_cmd += ")"
    database['prop_cmd'] = prop_cmd
    database['job_status'] = collections.OrderedDict()
    # Populate the job_status dict
    molecule = psi4.get_active_molecule()
    natom = molecule.natom()
    coordinates = ['x', 'y', 'z']
    step_direction = ['p', 'm']

    for atom in range(1, natom + 1):
        for coord in coordinates:
            for step in step_direction:
                job_name = '{}_{}_{}'.format(atom, coord, step)
                database['job_status'].update({job_name: 'not_started'})
    database['{}_computed'.format(prop)] = False
Esempio n. 8
0
File: roa.py Progetto: xwang862/psi4
def generate_inputs(name, db):
    molecule = psi4.get_active_molecule()
    natom = molecule.natom()

    # Get list of displacements
    displacement_geoms = psi4.atomic_displacements()

    # Sanity check!
    # Until we append the original geometry
    if not (6 * natom) == len(displacement_geoms):
        raise Exception('The number displacements should be 6 times the number'
                        'of atoms!')

    # List of displacements for iterating
    displacement_names = db['job_status'].keys()

    for n, entry in enumerate(displacement_names):
        if not os.path.exists(entry):
            os.makedirs(entry)
        # Set up
        mol_open = 'molecule ' + molecule.name() + '_' + entry + ' {\n'
        mol_close = '}'
        molecule.set_geometry(displacement_geoms[n])
        molecule.fix_orientation(True)
        molecule.fix_com(True)

        # Write input file
        inputfile = open('{0}/input.dat'.format(entry), 'w')
        inputfile.write("# This is a psi4 input file auto-generated for "
                        "computing Raman Optical Activity.\n\n")
        #inputfile.write(basic_molecule_for_input(molecule))
        inputfile.write("{}{}{}".format(
            mol_open, molecule.create_psi4_string_from_molecule(), mol_close))
        #.format(mol_open,molecule.save_string_xyz(),mol_close))
        inputfile.write('\n')
        inputfile.write(p4util.format_options_for_input())
        inputfile.write('\n')
        inputfile.write(
            "property('{0}', properties=['roa_tensor'])".format(name))
        inputfile.close()
Esempio n. 9
0
def generate_inputs(name,db):
    molecule = psi4.get_active_molecule()
    natom = molecule.natom()

    # Get list of displacements
    displacement_geoms = psi4.atomic_displacements(molecule)

    # Sanity check!
    # Until we append the original geometry
    if not (6*natom) == len(displacement_geoms):
        raise Exception('The number displacements should be 6 times the number'
                        'of atoms!')

    # List of displacements for iterating
    displacement_names = db['job_status'].keys()

    for n,entry in enumerate(displacement_names):
        if not os.path.exists(entry):
            os.makedirs(entry)
        # Set up 
        mol_open = 'molecule ' + molecule.name() + '_' + entry + ' {\n'
        mol_close = '}'
        molecule.set_geometry(displacement_geoms[n])
        molecule.fix_orientation(True)
        molecule.fix_com(True)

        # Write input file
        inputfile = open('{0}/input.dat'.format(entry), 'w')
        inputfile.write("# This is a psi4 input file auto-generated for "
                        "computing Raman Optical Activity.\n\n")
		#inputfile.write(basic_molecule_for_input(molecule))
        inputfile.write("{}{}{}"
						.format(mol_open,molecule.create_psi4_string_from_molecule(),mol_close))
                        #.format(mol_open,molecule.save_string_xyz(),mol_close))
        inputfile.write('\n')
        inputfile.write(p4util.format_options_for_input())
        inputfile.write('\n')
        inputfile.write("property('{0}', properties=['roa_tensor'])".format(name))
        inputfile.close()
Esempio n. 10
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()
Esempio n. 11
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.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

    # 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():
        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
Esempio n. 12
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
Esempio n. 13
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()
Esempio n. 14
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
Esempio n. 15
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
Esempio n. 16
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
Esempio n. 17
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
Esempio n. 18
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()
Esempio n. 19
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
Esempio n. 20
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()
Esempio n. 21
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
Esempio n. 22
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()