Esempio n. 1
0
    def compute_hessian(self, molecule):
        """
        #magic (if magic was easy)
        """

        optstash = p4util.OptionsState(['PRINT'])
        core.set_global_option('PRINT', 0)

        core.print_out("\n\n   Analytical Dispersion Hessians are not supported by dftd3 or gcp.\n")
        core.print_out("       Computing the Hessian through finite difference of gradients.\n\n")

        # Setup the molecule
        molclone = molecule.clone()
        molclone.reinterpret_coordentry(False)
        molclone.fix_orientation(True)
        molclone.fix_com(True)

        # Record undisplaced symmetry for projection of diplaced point groups
        core.set_parent_symmetry(molecule.schoenflies_symbol())

        gradients = []
        for geom in core.fd_geoms_freq_1(molecule, -1):
            molclone.set_geometry(geom)
            molclone.update_geometry()
            gradients.append(self.compute_gradient(molclone))

        H = core.fd_freq_1(molecule, gradients, -1)
        # H.print_out()
        optstash.restore()
        return H
Esempio n. 2
0
def cubeprop(wfn, **kwargs):
    """Evaluate properties on a grid and generate cube files.

    .. versionadded:: 0.5
       *wfn* parameter passed explicitly

    :returns: None

    :type wfn: :py:class:`~psi4.core.Wavefunction`
    :param wfn: set of molecule, basis, orbitals from which to generate cube files

    :examples:

    >>> # [1] Cube files for all orbitals
    >>> E, wfn = energy('b3lyp', return_wfn=True)
    >>> cubeprop(wfn)

    >>> # [2] Cube files for density (alpha, beta, total, spin) and four orbitals
    >>> #     (two alpha, two beta)
    >>> set cubeprop_tasks ['orbitals', 'density']
    >>> set cubeprop_orbitals [5, 6, -5, -6]
    >>> E, wfn = energy('scf', return_wfn=True)
    >>> cubeprop(wfn)

    """
    # By default compute the orbitals
    if not core.has_global_option_changed('CUBEPROP_TASKS'):
        core.set_global_option('CUBEPROP_TASKS', ['ORBITALS'])

    if ((core.get_global_option('INTEGRAL_PACKAGE') == 'ERD') and ('ESP' in core.get_global_option('CUBEPROP_TASKS'))):
        raise ValidationError('INTEGRAL_PACKAGE ERD does not play nicely with electrostatic potential, so stopping.')

    cp = core.CubeProperties(wfn)
    cp.compute_properties()
Esempio n. 3
0
    def compute_hessian(self, molecule):
        """
        #magic (if magic was easy)
        """

        optstash = p4util.OptionsState(['PRINT'])
        core.set_global_option('PRINT', 0)

        core.print_out(
            "\n\n   Analytical Dispersion Hessians are not supported by dftd3 or gcp.\n"
        )
        core.print_out(
            "       Computing the Hessian through finite difference of gradients.\n\n"
        )

        # Setup the molecule
        molclone = molecule.clone()
        molclone.reinterpret_coordentry(False)
        molclone.fix_orientation(True)
        molclone.fix_com(True)

        # Record undisplaced symmetry for projection of diplaced point groups
        core.set_parent_symmetry(molecule.schoenflies_symbol())

        gradients = []
        for geom in core.fd_geoms_freq_1(molecule, -1):
            molclone.set_geometry(geom)
            molclone.update_geometry()
            gradients.append(self.compute_gradient(molclone))

        H = core.fd_freq_1(molecule, gradients, -1)
        # H.print_out()
        optstash.restore()
        return H
Esempio n. 4
0
def set_options(options_dict):
    """
    Sets Psi4 global options from an input dictionary.
    """

    for k, v, in options_dict.items():
        core.set_global_option(k.upper(), v)
Esempio n. 5
0
def set_options(options_dict):
    """
    Sets Psi4 global options from an input dictionary.
    """

    for k, v, in options_dict.items():
        core.set_global_option(k.upper(), v)
Esempio n. 6
0
def scf_set_reference_local(name, is_dft=False):
    """
    Figures out the correct SCF reference to set locally
    """

    optstash = p4util.OptionsState(['SCF_TYPE'], ['SCF', 'REFERENCE'])

    # Alter default algorithm
    if not core.has_global_option_changed('SCF_TYPE'):
        core.set_global_option('SCF_TYPE', 'DF')

    # Alter reference name if needed
    user_ref = core.get_option('SCF', 'REFERENCE')

    sup = build_superfunctional_from_dictionary(functionals[name], 1, 1,
                                                True)[0]
    if sup.needs_xc() or is_dft:
        if (user_ref == 'RHF'):
            core.set_local_option('SCF', 'REFERENCE', 'RKS')
        elif (user_ref == 'UHF'):
            core.set_local_option('SCF', 'REFERENCE', 'UKS')
        elif (user_ref == 'ROHF'):
            raise ValidationError('ROHF reference for DFT is not available.')
        elif (user_ref == 'CUHF'):
            raise ValidationError('CUHF reference for DFT is not available.')
    # else we are doing HF and nothing needs to be overloaded

    return optstash
Esempio n. 7
0
def scf_set_reference_local(name, is_dft=False):
    """
    Figures out the correct SCF reference to set locally
    """

    optstash = p4util.OptionsState(
        ['SCF_TYPE'],
        ['SCF', 'REFERENCE'])

    # Alter default algorithm
    if not core.has_global_option_changed('SCF_TYPE'):
        core.set_global_option('SCF_TYPE', 'DF')

    # Alter reference name if needed
    user_ref = core.get_option('SCF', 'REFERENCE')

    sup = build_superfunctional_from_dictionary(functionals[name], 1, 1, True)[0]
    if sup.needs_xc() or is_dft:
        if (user_ref == 'RHF'):
            core.set_local_option('SCF', 'REFERENCE', 'RKS')
        elif (user_ref == 'UHF'):
            core.set_local_option('SCF', 'REFERENCE', 'UKS')
        elif (user_ref == 'ROHF'):
            raise ValidationError('ROHF reference for DFT is not available.')
        elif (user_ref == 'CUHF'):
            raise ValidationError('CUHF reference for DFT is not available.')
    # else we are doing HF and nothing needs to be overloaded

    return optstash
Esempio n. 8
0
 def restore(self):
     core.set_global_option(self.option, self.value_global)
     if not self.haschanged_global:
         core.revoke_global_option_changed(self.option)
     if self.module:
         core.set_local_option(self.module, self.option, self.value_local)
         if not self.haschanged_local:
             core.revoke_local_option_changed(self.module, self.option)
Esempio n. 9
0
 def restore(self):
     core.set_global_option(self.option, self.value_global)
     if not self.haschanged_global:
         core.revoke_global_option_changed(self.option)
     if self.module:
         core.set_local_option(self.module, self.option, self.value_local)
         if not self.haschanged_local:
             core.revoke_local_option_changed(self.module, self.option)
Esempio n. 10
0
def _core_jk_build(orbital_basis: core.BasisSet, aux: core.BasisSet = None, jk_type: str = None, do_wK: bool = None, memory: int = None) -> core.JK:
    """
    Constructs a Psi4 JK object from an input basis.

    Parameters
    ----------
    orbital_basis
        Orbital basis to use in the JK object.
    aux
        Optional auxiliary basis set for density-fitted tensors. Defaults
        to the DF_BASIS_SCF if set, otherwise the correspond JKFIT basis
        to the passed in `orbital_basis`.
    jk_type
        Type of JK object to build (DF, Direct, PK, etc). Defaults to the
        current global SCF_TYPE option.

    Returns
    -------
    JK
        Uninitialized JK object.

    Example
    -------

    jk = psi4.core.JK.build(bas)
    jk.set_memory(int(5e8)) # 4GB of memory
    jk.initialize()

    ...

    jk.C_left_add(matirx)
    jk.compute()
    jk.C_clear()

    ...

    """

    optstash = optproc.OptionsState(["SCF_TYPE"])

    if jk_type is not None:
        core.set_global_option("SCF_TYPE", jk_type)

    if aux is None:
        if core.get_global_option("SCF_TYPE") == "DF":
            aux = core.BasisSet.build(orbital_basis.molecule(), "DF_BASIS_SCF", core.get_option("SCF", "DF_BASIS_SCF"),
                                      "JKFIT", orbital_basis.name(), orbital_basis.has_puream())
        else:
            aux = core.BasisSet.zero_ao_basis_set()

    if (do_wK is None) or (memory is None):
        jk = core.JK.build_JK(orbital_basis, aux)
    else:
        jk = core.JK.build_JK(orbital_basis, aux, bool(do_wK), int(memory))

    optstash.restore()
    return jk
Esempio n. 11
0
 def restore(self):
     """Restore value and has_changed status to saved condition."""
     core.set_global_option(self.option, self.value_global)
     if not self.haschanged_global:
         core.revoke_global_option_changed(self.option)
     if self.module:
         core.set_local_option(self.module, self.option, self.value_local)
         if not self.haschanged_local:
             core.revoke_local_option_changed(self.module, self.option)
Esempio n. 12
0
def _core_jk_build(orbital_basis, aux=None, jk_type=None, do_wK=None, memory=None):
    """
    Constructs a Psi4 JK object from an input basis.

    Parameters
    ----------
    orbital_basis : :py:class:`~psi4.core.BasisSet`
        Orbital basis to use in the JK object.
    aux : :py:class:`~psi4.core.BasisSet`, optional
        Optional auxiliary basis set for density-fitted tensors. Defaults
        to the DF_BASIS_SCF if set, otherwise the correspond JKFIT basis
        to the passed in `orbital_basis`.
    jk_type : str, optional
        Type of JK object to build (DF, Direct, PK, etc). Defaults to the
        current global SCF_TYPE option.

    Returns
    -------
    :py:class:`~psi4.core.JK`
        Uninitialized JK object.

    Example
    -------

    jk = psi4.core.JK.build(bas)
    jk.set_memory(int(5e8)) # 4GB of memory
    jk.initialize()

    ...

    jk.C_left_add(matirx)
    jk.compute()
    jk.C_clear()

    ...

    """

    optstash = optproc.OptionsState(["SCF_TYPE"])

    if jk_type is not None:
        core.set_global_option("SCF_TYPE", jk_type)

    if aux is None:
        if core.get_global_option("SCF_TYPE") == "DF":
            aux = core.BasisSet.build(orbital_basis.molecule(), "DF_BASIS_SCF", core.get_option("SCF", "DF_BASIS_SCF"),
                                      "JKFIT", orbital_basis.name(), orbital_basis.has_puream())
        else:
            aux = core.BasisSet.zero_ao_basis_set()

    if (do_wK is None) or (memory is None):
        jk = core.JK.build_JK(orbital_basis, aux)
    else:
        jk = core.JK.build_JK(orbital_basis, aux, bool(do_wK), int(memory))

    optstash.restore()
    return jk
Esempio n. 13
0
def check_disk_df(name, optstash):

    optstash.add_option(['SCF_TYPE'])

    # Alter default algorithm
    if not core.has_global_option_changed('SCF_TYPE') or core.get_global_option('SCF_TYPE') == "DF":
        core.set_global_option('SCF_TYPE', 'DISK_DF')
        core.print_out(f"""    For method '{name}', SCF Algorithm Type (re)set to DISK_DF.\n""")
    else:
        if core.get_global_option('SCF_TYPE') == "MEM_DF":
            raise ValidationError(f"    Method '{name}' requires SCF_TYPE = DISK_DF, please use SCF_TYPE = DF to automatically choose the correct DFJK implementation.")
Esempio n. 14
0
    def compute_hessian(
            self,
            molecule: 'psi4.core.Molecule',
            wfn: 'psi4.core.Wavefunction' = None) -> 'psi4.core.Matrix':
        """Compute dispersion Hessian based on engine, dispersion level, and parameters in `self`.
        Uses finite difference, as no dispersion engine has analytic second derivatives.

        Parameters
        ----------
        molecule : psi4.core.Molecule
            System for which to compute empirical dispersion correction.
        wfn :
            Location to set QCVariables

        Returns
        -------
        psi4.core.Matrix
            (3*nat, 3*nat) dispersion Hessian [Eh/a0/a0].

        """
        optstash = p4util.OptionsState(['PRINT'], ['PARENT_SYMMETRY'])
        core.set_global_option('PRINT', 0)

        core.print_out(
            "\n\n   Analytical Dispersion Hessians are not supported by dftd3 or gcp.\n"
        )
        core.print_out(
            "       Computing the Hessian through finite difference of gradients.\n\n"
        )

        # Setup the molecule
        molclone = molecule.clone()
        molclone.reinterpret_coordentry(False)
        molclone.fix_orientation(True)
        molclone.fix_com(True)

        # Record undisplaced symmetry for projection of diplaced point groups
        core.set_global_option("PARENT_SYMMETRY",
                               molecule.schoenflies_symbol())

        findif_meta_dict = driver_findif.hessian_from_gradients_geometries(
            molclone, -1)
        for displacement in findif_meta_dict["displacements"].values():
            geom_array = np.reshape(displacement["geometry"], (-1, 3))
            molclone.set_geometry(core.Matrix.from_array(geom_array))
            molclone.update_geometry()
            displacement["gradient"] = self.compute_gradient(
                molclone).np.ravel().tolist()

        H = driver_findif.assemble_hessian_from_gradients(findif_meta_dict, -1)
        if wfn is not None:
            wfn.set_variable('DISPERSION CORRECTION HESSIAN', H)
        optstash.restore()
        return core.Matrix.from_array(H)
Esempio n. 15
0
def set_options(options_dict, verbose=1):
    """Sets Psi4 options from an input dictionary.

    Parameters
    ----------
    options_dict : dict
        Dictionary where keys are "option_name" for global options or
        "module_name__option_name" (double underscore separation) for
        option local to "module_name". Values are the option value. All
        are case insensitive.
    verbose : int, optional
        Control print volume.

    Returns
    -------
    None

    """
    optionre = re.compile(r'\A(?P<module>\w+__)?(?P<option>\w+)\Z',
                          re.IGNORECASE)
    rejected = {}

    for k, v, in options_dict.items():

        mobj = optionre.match(k.strip())
        module = mobj.group('module').upper()[:-2] if mobj.group(
            'module') else None
        option = mobj.group('option').upper()

        if module:
            if ((module, option, v) not in [
                ('SCF', 'GUESS', 'READ')
            ]) and ((module, option) not in [('PCM', 'INPUT')]):
                # TODO guess/read exception is for distributed driver. should be handled differently.
                try:
                    core.set_local_option(module, option, v)
                except RuntimeError as err:
                    rejected[k] = (v, err)
                if verbose > 1:
                    print('Setting: core.set_local_option', module, option, v)

            if (module, option) == ("PCM", "INPUT"):
                pcm_helper(v)

        else:
            try:
                core.set_global_option(option, v)
            except RuntimeError as err:
                rejected[k] = (v, err)
            if verbose > 1:
                print('Setting: core.set_global_option', option, v)

    if rejected:
        raise ValidationError(f'Error setting options: {rejected}')
Esempio n. 16
0
    def __enter__(self):
        self.optstash = p4util.optproc.OptionsState(*self.psikwargs.keys())
        for k, v in self.psikwargs.items():

            # Integer options need to be passed as an integer type,
            # or else it fails to set and doesn't throw an error.
            if re.match('^\d+$', v) is not None:
                v = int(v)

            if len(k) == 1:
                core.set_global_option(k[0], v)
            else:
                core.set_local_option(k[0], k[1], v)
Esempio n. 17
0
def psi4_set_options(my_options,mod_name,wfn):
    for i in my_options.get_keys():
        opt=""
        if mod_name in pulsar_2_psi4 and i in pulsar_2_psi4[mod_name]:
            opt=pulsar_2_psi4[mod_name][i]
        elif i in pulsar_2_psi4["GLOBAL"]:
            opt=pulsar_2_psi4["GLOBAL"][i]
        else: continue
        da_opt=my_options.get(i)
        if i=="BASIS_SET":
            bs_name=wfn.system.as_universe()[0].basis_sets[da_opt].description
            psi4.set_global_option(opt,bs_name)
        else:psi4.set_global_option(opt,da_opt)
Esempio n. 18
0
def check_disk_df(name, optstash):

    optstash.add_option(['SCF_TYPE'])

    # Alter default algorithm
    if not core.has_global_option_changed('SCF_TYPE'):
        core.set_global_option('SCF_TYPE', 'DISK_DF')
        core.print_out("""    Method '%s' requires SCF_TYPE = DISK_DF, setting.\n""" % name)
    elif core.get_global_option('SCF_TYPE') == "DF":
        core.set_global_option('SCF_TYPE', 'DISK_DF')
        core.print_out("""    Method '%s' requires SCF_TYPE = DISK_DF, setting.\n""" % name)
    else:
        if core.get_global_option('SCF_TYPE') != "DISK_DF":
            raise ValidationError("  %s requires SCF_TYPE = DISK_DF, please use SCF_TYPE = DF to automatically choose the correct DFJK implementation." % name)
Esempio n. 19
0
def check_disk_df(name, optstash):

    optstash.add_option(['SCF_TYPE'])

    # Alter default algorithm
    if not core.has_global_option_changed('SCF_TYPE'):
        core.set_global_option('SCF_TYPE', 'DISK_DF')
        core.print_out("""    Method '%s' requires SCF_TYPE = DISK_DF, setting.\n""" % name)
    elif core.get_global_option('SCF_TYPE') == "DF":
        core.set_global_option('SCF_TYPE', 'DISK_DF')
        core.print_out("""    Method '%s' requires SCF_TYPE = DISK_DF, setting.\n""" % name)
    else:
        if core.get_global_option('SCF_TYPE') != "DISK_DF":
            raise ValidationError("  %s requires SCF_TYPE = DISK_DF, please use SCF_TYPE = DF to automatically choose the correct DFJK implementation." % name)
Esempio n. 20
0
def scf_compute_energy(self):
    """Base class Wavefunction requires this function. Here it is
    simply a wrapper around initialize(), iterations(), finalize_energy(). It
    returns the SCF energy computed by finalize_energy().

    """
    if core.get_option('SCF',
                       'DF_SCF_GUESS') and (core.get_global_option('SCF_TYPE')
                                            == 'DIRECT'):
        # speed up DIRECT algorithm (recomputes full (non-DF) integrals
        #   each iter) by first converging via fast DF iterations, then
        #   fully converging in fewer slow DIRECT iterations. aka Andy trick 2.0
        core.print_out("  Starting with a DF guess...\n\n")
        with p4util.OptionsStateCM(['SCF_TYPE']):
            core.set_global_option('SCF_TYPE', 'DF')
            self.initialize()
            try:
                self.iterations()
            except SCFConvergenceError:
                self.finalize()
                raise SCFConvergenceError("""SCF DF preiterations""",
                                          self.iteration_, self, 0, 0)
        core.print_out("\n  DF guess converged.\n\n")

        # reset the DIIS & JK objects in prep for DIRECT
        if self.initialized_diis_manager_:
            self.diis_manager_.reset_subspace()
        self.initialize_jk(self.memory_jk_)
    else:
        self.initialize()

    try:
        self.iterations()
    except SCFConvergenceError as e:
        if core.get_option("SCF", "FAIL_ON_MAXITER"):
            core.print_out("  Failed to converge.\n")
            # energy = 0.0
            # A P::e fn to either throw or protest upon nonconvergence
            # die_if_not_converged()
            raise e
        else:
            core.print_out(
                "  Energy and/or wave function did not converge, but proceeding anyway.\n\n"
            )
    else:
        core.print_out("  Energy and wave function converged.\n\n")

    scf_energy = self.finalize_energy()
    return scf_energy
Esempio n. 21
0
def _core_set_global_option_python(key, EXTERN):
    """
    This is a fairly hacky way to get around EXTERN issues. Effectively we are routing this option Python side through attributes until the general Options overhaul.
    """
    if (key != "EXTERN"):
        raise ValidationError("Options: set_global_option_python does not recognize keyword %s" % key)

    if EXTERN is None:
        core.EXTERN = None
        core.set_global_option("EXTERN", False)
    elif isinstance(EXTERN, core.ExternalPotential):
        # Well this is probably the worst hack I have done, thats saying something
        core.EXTERN = EXTERN
        core.set_global_option("EXTERN", True)
    else:
        raise ValidationError("Options: set_global_option_python can either be a NULL or External Potential object")
Esempio n. 22
0
def _core_set_global_option_python(key, EXTERN):
    """
    This is a fairly hacky way to get around EXTERN issues. Effectively we are routing this option Python side through attributes until the general Options overhaul.
    """
    if (key != "EXTERN"):
        raise ValidationError("Options: set_global_option_python does not recognize keyword %s" % key)

    if EXTERN is None:
        core.EXTERN = None
        core.set_global_option("EXTERN", False)
    elif isinstance(EXTERN, core.ExternalPotential):
        # Well this is probably the worst hack I have done, thats saying something
        core.EXTERN = EXTERN
        core.set_global_option("EXTERN", True)
    else:
        raise ValidationError("Options: set_global_option_python can either be a NULL or External Potential object")
Esempio n. 23
0
    def set_cholesky_from(mtd_type):
        type_val = core.get_global_option(mtd_type)
        if type_val == 'CD':
            core.set_local_option('GPU_DFCC', 'DF_BASIS_CC', 'CHOLESKY')
            # Alter default algorithm
            if not core.has_global_option_changed('SCF_TYPE'):
                optstash.add_option(['SCF_TYPE'])
                core.set_global_option('SCF_TYPE', 'CD')
                core.print_out("""    SCF Algorithm Type (re)set to CD.\n""")

        elif type_val in ['DF', 'DISK_DF']:
            if core.get_option('GPU_DFCC', 'DF_BASIS_CC') == 'CHOLESKY':
                core.set_local_option('GPU_DFCC', 'DF_BASIS_CC', '')

            proc_util.check_disk_df(name.upper(), optstash)
        else:
            raise ValidationError("""Invalid type '%s' for DFCC""" % type_val)
Esempio n. 24
0
    def set_cholesky_from(mtd_type):
        type_val = core.get_global_option(mtd_type)
        if type_val == 'CD':
            core.set_local_option('GPU_DFCC', 'DF_BASIS_CC', 'CHOLESKY')
            # Alter default algorithm
            if not core.has_global_option_changed('SCF_TYPE'):
                optstash.add_option(['SCF_TYPE'])
                core.set_global_option('SCF_TYPE', 'CD')
                core.print_out("""    SCF Algorithm Type (re)set to CD.\n""")

        elif type_val == 'DF':
            if core.get_option('GPU_DFCC', 'DF_BASIS_CC') == 'CHOLESKY':
                core.set_local_option('GPU_DFCC', 'DF_BASIS_CC', '')

            proc_util.check_disk_df(name.upper(), optstash)
        else:
            raise ValidationError("""Invalid type '%s' for DFCC""" % type_val)
Esempio n. 25
0
def set_options(options_dict, verbose=1):
    """Sets Psi4 options from an input dictionary.

    Parameters
    ----------
    options_dict : dict
        Dictionary where keys are "option_name" for global options or
        "module_name__option_name" (double underscore separation) for
        option local to "module_name". Values are the option value. All
        are case insensitive.
    verbose : int, optional
        Control print volume.

    Returns
    -------
    None

    """
    optionre = re.compile(r'\A(?P<module>\w+__)?(?P<option>\w+)\Z', re.IGNORECASE)
    rejected = {}

    for k, v, in options_dict.items():
        mobj = optionre.match(k)
        module = mobj.group('module').upper()[:-2] if mobj.group('module') else None
        option = mobj.group('option').upper()

        if module:
            if (module, option, v) not in [('SCF', 'GUESS', 'READ')]:
                # TODO guess/read exception is for distributed driver. should be handled differently.
                try:
                    core.set_local_option(module, option, v)
                except RuntimeError as err:
                    rejected[k] = (v, err)
                if verbose > 1:
                    print('Setting: core.set_local_option', module, option, v)
        else:
            try:
                core.set_global_option(option, v)
            except RuntimeError as err:
                rejected[k] = (v, err)
            if verbose > 1:
                print('Setting: core.set_global_option', option, v)

    if rejected:
        raise ValidationError(f'Error setting options: {rejected}')
Esempio n. 26
0
def scf_compute_energy(self):
    """Base class Wavefunction requires this function. Here it is
    simply a wrapper around initialize(), iterations(), finalize_energy(). It
    returns the SCF energy computed by finalize_energy().

    """
    if core.get_option('SCF', 'DF_SCF_GUESS') and (core.get_global_option('SCF_TYPE') == 'DIRECT'):
        # speed up DIRECT algorithm (recomputes full (non-DF) integrals
        #   each iter) by first converging via fast DF iterations, then
        #   fully converging in fewer slow DIRECT iterations. aka Andy trick 2.0
        core.print_out("  Starting with a DF guess...\n\n")
        with p4util.OptionsStateCM(['SCF_TYPE']):
            core.set_global_option('SCF_TYPE', 'DF')
            self.initialize()
            try:
                self.iterations()
            except SCFConvergenceError:
                self.finalize()
                raise SCFConvergenceError("""SCF DF preiterations""", self.iteration_, self, 0, 0)
        core.print_out("\n  DF guess converged.\n\n")

        # reset the DIIS & JK objects in prep for DIRECT
        if self.initialized_diis_manager_:
            self.diis_manager().reset_subspace()
        self.initialize_jk(self.memory_jk_)
    else:
        self.initialize()

    try:
        self.iterations()
    except SCFConvergenceError as e:
        if core.get_option("SCF", "FAIL_ON_MAXITER"):
            core.print_out("  Failed to converge.\n")
            # energy = 0.0
            # A P::e fn to either throw or protest upon nonconvergence
            # die_if_not_converged()
            raise e
        else:
            core.print_out("  Energy did not converge, but proceeding anyway.\n\n")
    else:
        core.print_out("  Energy converged.\n\n")

    scf_energy = self.finalize_energy()
    return scf_energy
Esempio n. 27
0
def pcm_helper(block):
    """
    Passes multiline string *block* to PCMSolver parser.

    Parameters
    ----------
    block: multiline string with PCM input in PCMSolver syntax.
    """

    suffix = str(os.getpid()) + '.' + str(uuid.uuid4())[:8]
    pcmsolver_fname = 'pcmsolver.' + suffix + '.inp'
    with open(pcmsolver_fname, 'w') as handle:
        handle.write(block)
    import pcmsolver
    parsed_pcm = pcmsolver.parse_pcm_input(pcmsolver_fname)
    os.remove(pcmsolver_fname)
    pcmsolver_parsed_fname = '@pcmsolver.' + suffix
    with open(pcmsolver_parsed_fname, 'w') as tmp:
        tmp.write(parsed_pcm)
    core.set_global_option('PCMSOLVER_PARSED_FNAME', '{}'.format(pcmsolver_parsed_fname))
Esempio n. 28
0
def pcm_helper(block):
    """
    Passes multiline string *block* to PCMSolver parser.

    Parameters
    ----------
    block: multiline string with PCM input in PCMSolver syntax.
    """

    suffix = str(os.getpid()) + '.' + str(uuid.uuid4())[:8]
    pcmsolver_fname = 'pcmsolver.' + suffix + '.inp'
    with open(pcmsolver_fname, 'w') as handle:
        handle.write(block)
    import pcmsolver
    parsed_pcm = pcmsolver.parse_pcm_input(pcmsolver_fname)
    os.remove(pcmsolver_fname)
    pcmsolver_parsed_fname = '@pcmsolver.' + suffix
    with open(pcmsolver_parsed_fname, 'w') as tmp:
        tmp.write(parsed_pcm)
    core.set_global_option('PCMSOLVER_PARSED_FNAME', '{}'.format(pcmsolver_parsed_fname))
Esempio n. 29
0
def process_option(spaces, module, key, value, line):
    """Function to process a line with set or in a set block
    into global/local domain and keyword/value.

    """
    module = module.upper()
    key = key.upper()
    isbasis = True if 'BASIS' in key else False
    value = quotify(value.strip(), isbasis=isbasis)

    if module == "GLOBALS" or module == "GLOBAL" or module == "" or module.isspace():
        # If it's really a global, we need slightly different syntax
        if runalso:
            core.set_global_option(key, dequotify(value))
        return "%score.set_global_option(\"%s\", %s)\n" % (spaces, key, value)
    else:
        # It's a local option, so we need the module name in there too
        if runalso:
            core.set_local_option(module, key, dequotify(value))
        return "%score.set_local_option(\"%s\", \"%s\", %s)\n" % (spaces, module, key, value)
Esempio n. 30
0
def process_option(spaces, module, key, value, line):
    """Function to process a line with set or in a set block
    into global/local domain and keyword/value.

    """
    module = module.upper()
    key = key.upper()
    isbasis = True if 'BASIS' in key else False
    value = quotify(value.strip(), isbasis=isbasis)

    if module == "GLOBALS" or module == "GLOBAL" or module == "" or module.isspace():
        # If it's really a global, we need slightly different syntax
        if runalso:
            core.set_global_option(key, dequotify(value))
        return "%score.set_global_option(\"%s\", %s)\n" % (spaces, key, value)
    else:
        # It's a local option, so we need the module name in there too
        if runalso:
            core.set_local_option(module, key, dequotify(value))
        return "%score.set_local_option(\"%s\", \"%s\", %s)\n" % (spaces, module, key, value)
Esempio n. 31
0
    def compute_hessian(self, molecule):
        """Compute dispersion Hessian based on engine, dispersion level, and parameters in `self`.
        Uses finite difference, as no dispersion engine has analytic second derivatives.

        Parameters
        ----------
        molecule : psi4.core.Molecule
            System for which to compute empirical dispersion correction.

        Returns
        -------
        psi4.core.Matrix
            (3*nat, 3*nat) dispersion Hessian [Eh/a0/a0].

        """
        optstash = p4util.OptionsState(['PRINT'])
        core.set_global_option('PRINT', 0)

        core.print_out("\n\n   Analytical Dispersion Hessians are not supported by dftd3 or gcp.\n")
        core.print_out("       Computing the Hessian through finite difference of gradients.\n\n")

        # Setup the molecule
        molclone = molecule.clone()
        molclone.reinterpret_coordentry(False)
        molclone.fix_orientation(True)
        molclone.fix_com(True)

        # Record undisplaced symmetry for projection of diplaced point groups
        core.set_parent_symmetry(molecule.schoenflies_symbol())

        findif_meta_dict = driver_findif.hessian_from_gradient_geometries(molclone, -1)
        for displacement in findif_meta_dict["displacements"].values():
            geom_array = np.reshape(displacement["geometry"], (-1, 3))
            molclone.set_geometry(core.Matrix.from_array(geom_array))
            molclone.update_geometry()
            displacement["gradient"] = self.compute_gradient(molclone).np.ravel().tolist()

        H = driver_findif.compute_hessian_from_gradients(findif_meta_dict, -1)
        optstash.restore()
        return core.Matrix.from_array(H)
Esempio n. 32
0
    def compute_hessian(self, molecule):
        """Compute dispersion Hessian based on engine, dispersion level, and parameters in `self`.
        Uses finite difference, as no dispersion engine has analytic second derivatives.

        Parameters
        ----------
        molecule : psi4.core.Molecule
            System for which to compute empirical dispersion correction.

        Returns
        -------
        psi4.core.Matrix
            (3*nat, 3*nat) dispersion Hessian [Eh/a0/a0].

        """
        optstash = p4util.OptionsState(['PRINT'])
        core.set_global_option('PRINT', 0)

        core.print_out("\n\n   Analytical Dispersion Hessians are not supported by dftd3 or gcp.\n")
        core.print_out("       Computing the Hessian through finite difference of gradients.\n\n")

        # Setup the molecule
        molclone = molecule.clone()
        molclone.reinterpret_coordentry(False)
        molclone.fix_orientation(True)
        molclone.fix_com(True)

        # Record undisplaced symmetry for projection of diplaced point groups
        core.set_parent_symmetry(molecule.schoenflies_symbol())

        gradients = []
        for geom in driver_findif.hessian_from_gradient_geometries(molecule, -1):
            molclone.set_geometry(geom)
            molclone.update_geometry()
            gradients.append(self.compute_gradient(molclone))

        H = driver_findif.compute_hessian_from_gradient(molecule, gradients, -1)
        optstash.restore()
        return core.Matrix.from_array(H)
Esempio n. 33
0
def reset_pe_options(pofm):
    """Acts on Process::environment.options to clear it, the set it to state encoded in `pofm`.

    Parameters
    ----------
    pofm : dict
        Result of psi4.driver.p4util.prepare_options_for_modules(changedOnly=True, commandsInsteadDict=False)

    Returns
    -------
    None

    """
    core.clean_options()

    for go, dgo in pofm['GLOBALS'].items():
        if dgo['has_changed']:
            core.set_global_option(go, dgo['value'])

    for module in _modules:
        for lo, dlo in pofm[module].items():
            if dlo['has_changed']:
                core.set_local_option(module, lo, dlo['value'])
Esempio n. 34
0
def _reset_pe_options(pofm: Dict):
    """Acts on ``Process::environment.options`` to clear it, then set it to state encoded in **pofm**.

    Parameters
    ----------
    pofm
        Result of :py:func:`psi4.driver.p4util.prepare_options_for_modules(changedOnly=True, commandsInsteadDict=False, stateInsteadMediated=True)`

    Returns
    -------
    None

    """
    core.clean_options()

    for go, dgo in pofm['GLOBALS'].items():
        if dgo['has_changed']:
            core.set_global_option(go, dgo['value'])

    for module in _modules:
        for lo, dlo in pofm[module].items():
            if dlo['has_changed']:
                core.set_local_option(module, lo, dlo['value'])
Esempio n. 35
0
def reset_pe_options(pofm):
    """Acts on Process::environment.options to clear it, the set it to state encoded in `pofm`.

    Parameters
    ----------
    pofm : dict
        Result of psi4.driver.p4util.prepare_options_for_modules(changedOnly=True, commandsInsteadDict=False)

    Returns
    -------
    None

    """
    core.clean_options()

    for go, dgo in pofm['GLOBALS'].items():
        if dgo['has_changed']:
            core.set_global_option(go, dgo['value'])

    for module in _modules:
        for lo, dlo in pofm[module].items():
            if dlo['has_changed']:
                core.set_local_option(module, lo, dlo['value'])
Esempio n. 36
0
    def _init_df(self, calc):
        if self.no_reuse:
            return

        if calc.B == 'd':
            candidates = [
                calcid('m1', 'd', calc.Z),
                calcid('m2', 'd', calc.Z),
                calcid('d', 'd', calc.Z)
            ]
            core.set_global_option("DF_INTS_IO", "SAVE")
            for c in filter(lambda c: c in self.wfn_cache, candidates):
                oldns = self.fmt_ns(c)
                newns = self.fmt_ns(calc)
                core.IO.change_file_namespace(psif.PSIF_DFSCF_BJ, oldns, newns)
                core.set_global_option("DF_INTS_IO", "LOAD")
        else:
            core.set_global_option("DF_INTS_IO", "NONE")
Esempio n. 37
0
def run_sapt_dft(name, **kwargs):
    optstash = p4util.OptionsState(['SCF_TYPE'], ['SCF', 'REFERENCE'],
                                   ['SCF', 'DFT_GRAC_SHIFT'],
                                   ['SCF', 'SAVE_JK'])

    core.tstart()
    # Alter default algorithm
    if not core.has_global_option_changed('SCF_TYPE'):
        core.set_global_option('SCF_TYPE', 'DF')

    core.prepare_options_for_module("SAPT")

    # Get the molecule of interest
    ref_wfn = kwargs.get('ref_wfn', None)
    if ref_wfn is None:
        sapt_dimer = kwargs.pop('molecule', core.get_active_molecule())
    else:
        core.print_out(
            'Warning! SAPT argument "ref_wfn" is only able to use molecule information.'
        )
        sapt_dimer = ref_wfn.molecule()

    sapt_dimer, monomerA, monomerB = proc_util.prepare_sapt_molecule(
        sapt_dimer, "dimer")

    # Grab overall settings
    mon_a_shift = core.get_option("SAPT", "SAPT_DFT_GRAC_SHIFT_A")
    mon_b_shift = core.get_option("SAPT", "SAPT_DFT_GRAC_SHIFT_B")
    do_delta_hf = core.get_option("SAPT", "SAPT_DFT_DO_DHF")
    sapt_dft_functional = core.get_option("SAPT", "SAPT_DFT_FUNCTIONAL")

    # Print out the title and some information
    core.print_out("\n")
    core.print_out(
        "         ---------------------------------------------------------\n")
    core.print_out("         " + "SAPT(DFT) Procedure".center(58) + "\n")
    core.print_out("\n")
    core.print_out("         " + "by Daniel G. A. Smith".center(58) + "\n")
    core.print_out(
        "         ---------------------------------------------------------\n")
    core.print_out("\n")

    core.print_out(
        "  !!!  WARNING:  SAPT(DFT) capability is in beta. Please use with caution. !!!\n\n"
    )

    core.print_out("  ==> Algorithm <==\n\n")
    core.print_out("   SAPT DFT Functional     %12s\n" %
                   str(sapt_dft_functional))
    core.print_out("   Monomer A GRAC Shift    %12.6f\n" % mon_a_shift)
    core.print_out("   Monomer B GRAC Shift    %12.6f\n" % mon_b_shift)
    core.print_out("   Delta HF                %12s\n" %
                   ("True" if do_delta_hf else "False"))
    core.print_out("   JK Algorithm            %12s\n" %
                   core.get_global_option("SCF_TYPE"))
    core.print_out("\n")
    core.print_out("   Required computations:\n")
    if (do_delta_hf):
        core.print_out("     HF  (Dimer)\n")
        core.print_out("     HF  (Monomer A)\n")
        core.print_out("     HF  (Monomer B)\n")
    core.print_out("     DFT (Monomer A)\n")
    core.print_out("     DFT (Monomer B)\n")
    core.print_out("\n")

    if (sapt_dft_functional != "HF") and ((mon_a_shift == 0.0) or
                                          (mon_b_shift == 0.0)):
        raise ValidationError(
            'SAPT(DFT): must set both "SAPT_DFT_GRAC_SHIFT_A" and "B".')

    if (core.get_option('SCF', 'REFERENCE') != 'RHF'):
        raise ValidationError(
            'SAPT(DFT) currently only supports restricted references.')

    core.IO.set_default_namespace('dimer')
    data = {}

    if (core.get_global_option('SCF_TYPE') == 'DF'):
        # core.set_global_option('DF_INTS_IO', 'LOAD')
        core.set_global_option('DF_INTS_IO', 'SAVE')

    # # Compute dimer wavefunction
    hf_wfn_dimer = None
    if do_delta_hf:
        if (core.get_global_option('SCF_TYPE') == 'DF'):
            core.set_global_option('DF_INTS_IO', 'SAVE')

        core.timer_on("SAPT(DFT): Dimer SCF")
        hf_data = {}
        hf_wfn_dimer = scf_helper("SCF",
                                  molecule=sapt_dimer,
                                  banner="SAPT(DFT): delta HF Dimer",
                                  **kwargs)
        hf_data["HF DIMER"] = core.variable("CURRENT ENERGY")
        core.timer_off("SAPT(DFT): Dimer SCF")

        core.timer_on("SAPT(DFT): Monomer A SCF")
        if (core.get_global_option('SCF_TYPE') == 'DF'):
            core.IO.change_file_namespace(97, 'dimer', 'monomerA')

        hf_wfn_A = scf_helper("SCF",
                              molecule=monomerA,
                              banner="SAPT(DFT): delta HF Monomer A",
                              **kwargs)
        hf_data["HF MONOMER A"] = core.variable("CURRENT ENERGY")
        core.timer_off("SAPT(DFT): Monomer A SCF")

        core.timer_on("SAPT(DFT): Monomer B SCF")
        core.set_global_option("SAVE_JK", True)
        if (core.get_global_option('SCF_TYPE') == 'DF'):
            core.IO.change_file_namespace(97, 'monomerA', 'monomerB')

        hf_wfn_B = scf_helper("SCF",
                              molecule=monomerB,
                              banner="SAPT(DFT): delta HF Monomer B",
                              **kwargs)
        hf_data["HF MONOMER B"] = core.variable("CURRENT ENERGY")
        core.set_global_option("SAVE_JK", False)
        core.timer_off("SAPT(DFT): Monomer B SCF")

        # Grab JK object and set to A (so we do not save many JK objects)
        sapt_jk = hf_wfn_B.jk()
        hf_wfn_A.set_jk(sapt_jk)
        core.set_global_option("SAVE_JK", False)

        # Move it back to monomer A
        if (core.get_global_option('SCF_TYPE') == 'DF'):
            core.IO.change_file_namespace(97, 'monomerB', 'dimer')

        core.print_out("\n")
        core.print_out(
            "         ---------------------------------------------------------\n"
        )
        core.print_out("         " + "SAPT(DFT): delta HF Segment".center(58) +
                       "\n")
        core.print_out("\n")
        core.print_out("         " +
                       "by Daniel G. A. Smith and Rob Parrish".center(58) +
                       "\n")
        core.print_out(
            "         ---------------------------------------------------------\n"
        )
        core.print_out("\n")

        # Build cache
        hf_cache = sapt_jk_terms.build_sapt_jk_cache(hf_wfn_A, hf_wfn_B,
                                                     sapt_jk, True)

        # Electrostatics
        core.timer_on("SAPT(DFT):SAPT:elst")
        elst = sapt_jk_terms.electrostatics(hf_cache, True)
        hf_data.update(elst)
        core.timer_off("SAPT(DFT):SAPT:elst")

        # Exchange
        core.timer_on("SAPT(DFT):SAPT:exch")
        exch = sapt_jk_terms.exchange(hf_cache, sapt_jk, True)
        hf_data.update(exch)
        core.timer_off("SAPT(DFT):SAPT:exch")

        # Induction
        core.timer_on("SAPT(DFT):SAPT:ind")
        ind = sapt_jk_terms.induction(
            hf_cache,
            sapt_jk,
            True,
            maxiter=core.get_option("SAPT", "MAXITER"),
            conv=core.get_option("SAPT", "D_CONVERGENCE"),
            Sinf=core.get_option("SAPT", "DO_IND_EXCH_SINF"))
        hf_data.update(ind)
        core.timer_off("SAPT(DFT):SAPT:ind")

        dhf_value = hf_data["HF DIMER"] - hf_data["HF MONOMER A"] - hf_data[
            "HF MONOMER B"]

        core.print_out("\n")
        core.print_out(
            print_sapt_hf_summary(hf_data, "SAPT(HF)", delta_hf=dhf_value))

        data["Delta HF Correction"] = core.variable("SAPT(DFT) Delta HF")
        sapt_jk.finalize()

        del hf_wfn_A, hf_wfn_B, sapt_jk

    if hf_wfn_dimer is None:
        dimer_wfn = core.Wavefunction.build(sapt_dimer,
                                            core.get_global_option("BASIS"))
    else:
        dimer_wfn = hf_wfn_dimer

    # Set the primary functional
    core.set_local_option('SCF', 'REFERENCE', 'RKS')

    # Compute Monomer A wavefunction
    core.timer_on("SAPT(DFT): Monomer A DFT")
    if (core.get_global_option('SCF_TYPE') == 'DF'):
        core.IO.change_file_namespace(97, 'dimer', 'monomerA')

    if mon_a_shift:
        core.set_global_option("DFT_GRAC_SHIFT", mon_a_shift)

    core.IO.set_default_namespace('monomerA')
    wfn_A = scf_helper(sapt_dft_functional,
                       post_scf=False,
                       molecule=monomerA,
                       banner="SAPT(DFT): DFT Monomer A",
                       **kwargs)
    data["DFT MONOMERA"] = core.variable("CURRENT ENERGY")

    core.set_global_option("DFT_GRAC_SHIFT", 0.0)
    core.timer_off("SAPT(DFT): Monomer A DFT")

    # Compute Monomer B wavefunction
    core.timer_on("SAPT(DFT): Monomer B DFT")
    if (core.get_global_option('SCF_TYPE') == 'DF'):
        core.IO.change_file_namespace(97, 'monomerA', 'monomerB')

    if mon_b_shift:
        core.set_global_option("DFT_GRAC_SHIFT", mon_b_shift)

    core.set_global_option("SAVE_JK", True)
    core.IO.set_default_namespace('monomerB')
    wfn_B = scf_helper(sapt_dft_functional,
                       post_scf=False,
                       molecule=monomerB,
                       banner="SAPT(DFT): DFT Monomer B",
                       **kwargs)
    data["DFT MONOMERB"] = core.variable("CURRENT ENERGY")

    # Save JK object
    sapt_jk = wfn_B.jk()
    wfn_A.set_jk(sapt_jk)
    core.set_global_option("SAVE_JK", False)

    core.set_global_option("DFT_GRAC_SHIFT", 0.0)
    core.timer_off("SAPT(DFT): Monomer B DFT")

    # Write out header
    scf_alg = core.get_global_option("SCF_TYPE")
    sapt_dft_header(sapt_dft_functional, mon_a_shift, mon_b_shift,
                    bool(do_delta_hf), scf_alg)

    # Call SAPT(DFT)
    sapt_jk = wfn_B.jk()
    sapt_dft(dimer_wfn,
             wfn_A,
             wfn_B,
             sapt_jk=sapt_jk,
             data=data,
             print_header=False)

    # Copy data back into globals
    for k, v in data.items():
        core.set_variable(k, v)

    core.tstop()

    return dimer_wfn
Esempio n. 38
0
def run_json_qcschema(json_data, clean, json_serialization, keep_wfn=False):
    """
    An implementation of the QC JSON Schema (molssi-qc-schema.readthedocs.io/en/latest/index.html#) implementation in Psi4.


    Parameters
    ----------
    json_data : JSON
        Please see molssi-qc-schema.readthedocs.io/en/latest/spec_components.html for further details.

    Notes
    -----
    !Warning! This function is experimental and likely to change in the future.
    Please report any suggestions or uses of this function on github.com/MolSSI/QC_JSON_Schema.

    Examples
    --------

    """

    # Clean a few things
    _clean_psi_environ(clean)

    # This is currently a forced override
    if json_data["schema_name"] in ["qc_schema_input", "qcschema_input"]:
        json_data["schema_name"] = "qcschema_input"
    else:
        raise KeyError("Schema name of '{}' not understood".format(
            json_data["schema_name"]))

    if json_data["schema_version"] != 1:
        raise KeyError("Schema version of '{}' not understood".format(
            json_data["schema_version"]))

    if json_data.get("nthreads", False) is not False:
        core.set_num_threads(json_data["nthreads"], quiet=True)

    # Build molecule
    if "schema_name" in json_data["molecule"]:
        molschemus = json_data["molecule"]  # dtype >=2
    else:
        molschemus = json_data  # dtype =1
    mol = core.Molecule.from_schema(molschemus)

    # Update molecule geometry as we orient and fix_com
    json_data["molecule"]["geometry"] = mol.geometry().np.ravel().tolist()

    # Set options
    kwargs = json_data["keywords"].pop("function_kwargs", {})
    p4util.set_options(json_data["keywords"])

    # Setup the computation
    method = json_data["model"]["method"]
    core.set_global_option("BASIS", json_data["model"]["basis"])
    kwargs.update({"return_wfn": True, "molecule": mol})

    # Handle special properties case
    if json_data["driver"] == "properties":
        if "properties" not in kwargs:
            kwargs["properties"] = list(default_properties_)

    # Actual driver run
    val, wfn = methods_dict_[json_data["driver"]](method, **kwargs)

    # Pull out a standard set of SCF properties
    if "extras" not in json_data:
        json_data["extras"] = {}
    json_data["extras"]["qcvars"] = {}

    current_qcvars_only = json_data["extras"].get("current_qcvars_only", False)
    if json_data["extras"].get("wfn_qcvars_only", False):
        psi_props = wfn.variables(
            include_deprecated_keys=(not current_qcvars_only))
    else:
        psi_props = core.variables(
            include_deprecated_keys=(not current_qcvars_only))
        for k, v in psi_props.items():
            if k not in json_data["extras"]["qcvars"]:
                json_data["extras"]["qcvars"][k] = _serial_translation(
                    v, json=json_serialization)

    # Still a bit of a mess at the moment add in local vars as well.
    for k, v in wfn.variables().items():
        if k not in json_data["extras"]["qcvars"]:
            # interpreting wfn_qcvars_only as no deprecated qcvars either
            if not (json_data["extras"].get("wfn_qcvars_only", False) and
                    (any([
                        k.upper().endswith(" DIPOLE " + cart)
                        for cart in ["X", "Y", "Z"]
                    ]) or any([
                        k.upper().endswith(" QUADRUPOLE " + cart)
                        for cart in ["XX", "YY", "ZZ", "XY", "XZ", "YZ"]
                    ]) or k.upper() in [
                        "SOS-MP2 CORRELATION ENERGY",
                        "SOS-MP2 TOTAL ENERGY",
                        "SOS-PI-MP2 CORRELATION ENERGY",
                        "SOS-PI-MP2 TOTAL ENERGY",
                        "SCS-MP3 CORRELATION ENERGY",
                        "SCS-MP3 TOTAL ENERGY",
                    ])):
                json_data["extras"]["qcvars"][k] = _serial_translation(
                    v, json=json_serialization)

    # Handle the return result
    if json_data["driver"] == "energy":
        json_data["return_result"] = val
    elif json_data["driver"] in ["gradient", "hessian"]:
        json_data["return_result"] = _serial_translation(
            val, json=json_serialization)
    elif json_data["driver"] == "properties":
        ret = {}
        mtd = json_data["model"]["method"].upper()

        # Dipole/quadrupole still special case
        if "dipole" in kwargs["properties"]:
            ret["dipole"] = _serial_translation(psi_props[mtd + " DIPOLE"],
                                                json=json_serialization)
        if "quadrupole" in kwargs["properties"]:
            ret["quadrupole"] = _serial_translation(psi_props[mtd +
                                                              " QUADRUPOLE"],
                                                    json=json_serialization)
        ret.update(
            _convert_variables(wfn.variables(),
                               context="properties",
                               json=json_serialization))

        json_data["return_result"] = ret
    else:
        raise KeyError("Did not understand Driver key %s." %
                       json_data["driver"])

    props = {
        "calcinfo_nbasis": wfn.nso(),
        "calcinfo_nmo": wfn.nmo(),
        "calcinfo_nalpha": wfn.nalpha(),
        "calcinfo_nbeta": wfn.nbeta(),
        "calcinfo_natom": mol.geometry().shape[0],
        "nuclear_repulsion_energy": mol.nuclear_repulsion_energy(
        ),  # use this b/c psivar is monomer for SAPT
    }
    props.update(
        _convert_variables(psi_props,
                           context="generics",
                           json=json_serialization))
    if not list(
            set(['CBS NUMBER', 'NBODY NUMBER', 'FINDIF NUMBER'])
            & set(json_data["extras"]["qcvars"].keys())):
        props.update(
            _convert_variables(psi_props,
                               context="scf",
                               json=json_serialization))

    # Write out post-SCF keywords
    if "MP2 CORRELATION ENERGY" in psi_props:
        props.update(
            _convert_variables(psi_props,
                               context="mp2",
                               json=json_serialization))

    if "CCSD CORRELATION ENERGY" in psi_props:
        props.update(
            _convert_variables(psi_props,
                               context="ccsd",
                               json=json_serialization))

    if "CCSD(T) CORRELATION ENERGY" in psi_props:
        props.update(
            _convert_variables(psi_props,
                               context="ccsd(t)",
                               json=json_serialization))

    json_data["properties"] = props
    json_data["success"] = True
    json_data["provenance"]["module"] = wfn.module()

    if keep_wfn:
        json_data["wavefunction"] = _convert_wavefunction(wfn)

    files = {
        "psi4.grad":
        Path(core.get_writer_file_prefix(wfn.molecule().name()) + ".grad"),
        "psi4.hess":
        Path(core.get_writer_file_prefix(wfn.molecule().name()) + ".hess"),
        # binary "psi4.180.npy": Path(core.get_writer_file_prefix(wfn.molecule().name()) + ".180.npy"),
        "timer.dat":
        Path(
            "timer.dat"
        ),  # ok for `psi4 --qcschema` but no file collected for `qcengine.run_program(..., "psi4")`
    }
    json_data["native_files"] = {
        fl: flpath.read_text()
        for fl, flpath in files.items() if flpath.exists()
    }

    # Reset state
    _clean_psi_environ(clean)

    json_data["schema_name"] = "qcschema_output"

    return json_data
Esempio n. 39
0
def run_json_qc_schema(json_data, clean):
    """
    An implementation of the QC JSON Schema (molssi-qc-schema.readthedocs.io/en/latest/index.html#) implementation in Psi4.


    Parameters
    ----------
    json_data : JSON
        Please see molssi-qc-schema.readthedocs.io/en/latest/spec_components.html for further details.

    Notes
    -----
    !Warning! This function is experimental and likely to change in the future.
    Please report any suggestions or uses of this function on github.com/MolSSI/QC_JSON_Schema.

    Examples
    --------

    """

    # Clean a few things
    _clean_psi_environ(clean)

    # This is currently a forced override
    if json_data["schema_name"] != "qc_schema_input":
        raise KeyError("Schema name of '{}' not understood".format(json_data["schema_name"]))

    if json_data["schema_version"] != 1:
        raise KeyError("Schema version of '{}' not understood".format(json_data["schema_version"]))

    if json_data.get("nthreads", False) is not False:
        psi4.set_num_threads(json_data["nthreads"], quiet=True)

    json_data["provenance"] = {"creator": "Psi4", "version": psi4.__version__, "routine": "psi4.json.run_json"}

    # Build molecule
    mol = core.Molecule.from_schema(json_data)

    # Update molecule geometry as we orient and fix_com
    json_data["molecule"]["geometry"] = mol.geometry().np.ravel().tolist()


    # Set options
    for k, v in json_data["keywords"].items():
        core.set_global_option(k, v)

    # Setup the computation
    method = json_data["model"]["method"]
    core.set_global_option("BASIS", json_data["model"]["basis"])
    kwargs = {"return_wfn": True, "molecule": mol}

    # Handle special properties case
    if json_data["driver"] == "properties":
        if "properties" in json_data["model"]:
            kwargs["properties"] = [x.lower() for x in json_data["model"]["properties"]]

            extra = set(kwargs["properties"]) - can_do_properties_
            if len(extra):
                raise KeyError("Did not understand property key %s." % kwargs["properties"])
        else:
            kwargs["properties"] = list(can_do_properties_)


    # Actual driver run
    val, wfn = methods_dict_[json_data["driver"]](method, **kwargs)

    # Pull out a standard set of SCF properties
    psi_props = psi4.core.get_variables()
    json_data["psi4:qcvars"] = psi_props

    # Handle the return result
    if json_data["driver"] == "energy":
        json_data["return_result"] = val
    elif json_data["driver"] in ["gradient", "hessian"]:
        json_data["return_result"] = val.np.ravel().tolist()
    elif json_data["driver"] == "properties":
        ret = {}
        mtd = json_data["model"]["method"].upper()
        if "dipole" in kwargs["properties"]:
            ret["dipole"] = [psi_props[mtd + " DIPOLE " + x] for x in ["X", "Y", "Z"]]
        if "quadrupole" in kwargs["properties"]:
            ret["quadrupole"] = [psi_props[mtd + " QUADRUPOLE " + x] for x in ["XX", "XY", "XZ", "YY", "YZ", "ZZ"]]
        if "mulliken_charges" in kwargs["properties"]:
            ret["mulliken_charges"] = wfn.get_array("MULLIKEN_CHARGES").np.ravel().tolist()
        if "lowdin_charges" in kwargs["properties"]:
            ret["lowdin_charges"] = wfn.get_array("LOWDIN_CHARGES").np.ravel().tolist()
        if "wiberg_lowdin_indices" in kwargs["properties"]:
            ret["wiberg_lowdin_indices"] = wfn.get_array("WIBERG_LOWDIN_INDICES").np.ravel().tolist()
        if "mayer_indices" in kwargs["properties"]:
            ret["mayer_indices"] = wfn.get_array("MAYER_INDICES").np.ravel().tolist()

        json_data["return_result"] = ret
    else:
        raise KeyError("Did not understand Driver key %s." % json_data["driver"])


    props = {
        "calcinfo_nbasis": wfn.nso(),
        "calcinfo_nmo": wfn.nmo(),
        "calcinfo_nalpha": wfn.nalpha(),
        "calcinfo_nbeta": wfn.nbeta(),
        "calcinfo_natom": mol.geometry().shape[0],
        "scf_one_electron_energy": psi_props["ONE-ELECTRON ENERGY"],
        "scf_two_electron_energy": psi_props["TWO-ELECTRON ENERGY"],
        "nuclear_repulsion_energy": psi_props["NUCLEAR REPULSION ENERGY"],
        "scf_dipole_moment": [psi_props[x] for x in ["SCF DIPOLE X", "SCF DIPOLE Y", "SCF DIPOLE Z"]],
        "scf_iterations": int(psi_props["SCF ITERATIONS"]),
        "scf_total_energy": psi_props["SCF TOTAL ENERGY"],
        "return_energy": psi_props["CURRENT ENERGY"],
    }

    # Pull out optional SCF keywords
    other_scf = [("DFT VV10 ENERGY", "scf_vv10_energy"), ("DFT XC ENERGY", "scf_xc_energy"),
                 ("DISPERSION CORRECTION ENERGY", "scf_dispersion_correction_energy")]
    for pkey, skey in other_scf:
        if (pkey in psi_props) and (psi_props[pkey] != 0):
            props[skey] = psi_props[pkey]

    # Write out MP2 keywords
    if "MP2 CORRELATION ENERGY" in psi_props:
        props["mp2_same_spin_correlation_energy"] = psi_props["MP2 SAME-SPIN CORRELATION ENERGY"]
        props["mp2_opposite_spin_correlation_energy"] = psi_props["MP2 OPPOSITE-SPIN CORRELATION ENERGY"]
        props["mp2_singles_energy"] = 0.0
        props["mp2_doubles_energy"] = psi_props["MP2 CORRELATION ENERGY"]
        props["mp2_total_correlation_energy"] = psi_props["MP2 CORRELATION ENERGY"]
        props["mp2_total_energy"] = psi_props["MP2 TOTAL ENERGY"]

    json_data["properties"] = props
    json_data["success"] = True

    # Reset state
    _clean_psi_environ(clean)

    json_data["schema_name"] = "qc_schema_output"

    return json_data
Esempio n. 40
0
def run_json_original_v1_1(json_data, clean):
    """
    Runs and updates the input JSON data.

    This was a trial specification introduced in Psi4 v1.1. This will be deprecated in Psi4 v1.3 in favour of the QC JSON format
    found here: http://molssi-qc-schema.readthedocs.io/en/latest/index.html#

    Parameters
    ----------
    json_data : JSON input
        Required input fields:
            - molecule : str
                A string representation of the molecule. Any valid psi4 synatx is valid.
            - driver : str
                The driver method to use valid arguments are "energy", "gradient", "property"
            - args : str
                Input arguments to the driver function
            - kwargs : dict
                Input dictionary to the driver function

        Optional input fields:
            - kwargs : dict
                Additional kwargs to be passed to the driver.
            - options : dict
                Global options to set in the Psi4 run.
            - scratch_location : str
                Overide the default scratch location.
            - return_output : bool
                Return the full string reprsentation of the output or not.

        Output fields:
            - return_value : float, psi4.core.Vector, psi4.core.Matrix
                The return value of the input function.
            - variables : dict
                The list of Psi4 variables generated from the run.
            - success : bool
                Indicates if the run was successful or not.
            - error : str
                If an error is raised the result is returned here.
            - raw_output : str
                The full Psi4 output if requested.


    Notes
    -----
    !Warning! This function is experimental and likely to change in the future.
    Please report any suggestions or uses of this function on github.com/psi4/psi4.

    Examples
    --------

    # CP corrected Helium dimer energy in the STO-3G basis.
    >>> json_data = {}

    >>> json_data["molecule"] = "He 0 0 0\n--\nHe 0 0 1"
    >>> json_data["driver"] = "energy"
    >>> json_data["method"] = 'SCF'
    >>> json_data["kwargs"] = {"bsse_type": "cp"}
    >>> json_data["options"] = {"BASIS": "STO-3G"}

    >>> run_json(json_data)
    {
        "raw_output": "Output storing was not requested.",
        "options": {
            "BASIS": "STO-3G"
        },
        "driver": "energy",
        "molecule": "He 0 0 0\n--\nHe 0 0 1",
        "method": "SCF",
        "variables": {
            "SCF N ITERS": 2.0,
            "SCF DIPOLE Y": 0.0,
            "CURRENT DIPOLE Y": 0.0,
            "CP-CORRECTED 2-BODY INTERACTION ENERGY": 0.1839360538612116,
            "HF TOTAL ENERGY": -5.433191881443323,
            "SCF TOTAL ENERGY": -5.433191881443323,
            "TWO-ELECTRON ENERGY": 4.124089347186247,
            "SCF ITERATION ENERGY": -5.433191881443323,
            "CURRENT DIPOLE X": 0.0,
            "CURRENT DIPOLE Z": 0.0,
            "CURRENT REFERENCE ENERGY": -5.433191881443323,
            "CURRENT ENERGY": 0.1839360538612116,
            "COUNTERPOISE CORRECTED TOTAL ENERGY": -5.433191881443323,
            "SCF DIPOLE Z": 0.0,
            "COUNTERPOISE CORRECTED INTERACTION ENERGY": 0.1839360538612116,
            "NUCLEAR REPULSION ENERGY": 2.11670883436,
            "SCF DIPOLE X": 0.0,
            "ONE-ELECTRON ENERGY": -11.67399006298957
        },
        "return_value": 0.1839360538612116,
        "error": "",
        "success": true,
        "provenance": {
            "creator": "Psi4",
            "routine": "psi4.run_json",
            "version": "1.1a1"
        },
        "kwargs": {
            "bsse_type": "cp"
        }
    }
    """

    # Clean a few things
    _clean_psi_environ(clean)

    # Set a few variables
    json_data["error"] = ""
    json_data["success"] = False
    json_data["raw_output"] = None
    json_data[
        "warning"] = "Warning! This format will be deprecated in Psi4 v1.3. Please switch the standard QC JSON format."

    # Add the provenance data
    prov = {}
    prov["version"] = psi4.__version__
    prov["routine"] = "psi4.run_json"
    prov["creator"] = "Psi4"
    json_data["provenance"] = prov

    # Check input
    for check in ["driver", "method", "molecule"]:
        if check not in list(json_data):
            json_data["error"] = "Minimum input requires the %s field." % check
            return json_data

    # Check driver call
    if json_data["driver"] not in list(methods_dict_):
        json_data["error"] = "Driver parameters '%s' not recognized" % str(json_data["driver"])
        return json_data

    # Set options
    if "options" in json_data.keys() and (json_data["options"] is not None):
        for k, v in json_data["options"].items():
            core.set_global_option(k, v)

    # Rework args
    args = json_data["method"]
    if not isinstance(args, (list, tuple)):
        args = [args]

    # Deep copy kwargs
    if "kwargs" in list(json_data):
        kwargs = copy.deepcopy(json_data["kwargs"])
    else:
        kwargs = {}

    kwargs["molecule"] = molutil.geometry(json_data["molecule"])

    # Full driver call
    kwargs["return_wfn"] = True

    if json_data["driver"] not in methods_dict_:
        raise KeyError("Driver type '%s' not recognized." % str(json_data["driver"]))

    val, wfn = methods_dict_[json_data["driver"]](*args, **kwargs)

    if isinstance(val, (float, int)):
        json_data["return_value"] = val
    elif isinstance(val, (core.Matrix, core.Vector)):
        json_data["return_value"] = val.to_serial()
    else:
        raise TypeError("Unrecognized return value of type %s\n" % type(val))

    json_data["variables"] = core.get_variables()
    json_data["success"] = True

    # Reset state
    _clean_psi_environ(clean)

    return json_data
Esempio n. 41
0
File: frac.py Progetto: yxie326/psi4
def ip_fitting(name,
               omega_l=0.05,
               omega_r=2.5,
               omega_convergence=1.0e-3,
               maxiter=20,
               **kwargs):
    """Optimize DFT omega parameter for molecular system.

    Parameters
    ----------
    name : string or function
        DFT functional string name or function defining functional
        whose omega is to be optimized.
    omega_l : float, optional
        Minimum omega to be considered during fitting.
    omega_r : float, optional
        Maximum omega to be considered during fitting.
    molecule : :ref:`molecule <op_py_molecule>`, optional
        Target molecule (neutral) for which omega is to be tuned, if not last defined.
    omega_convergence : float, optional
        Threshold below which to consider omega converged. (formerly omega_tolerance)
    maxiter : int, optional
        Maximum number of iterations towards omega convergence.

    Returns
    -------
    float
        Optimal omega parameter.

    """
    optstash = p4util.OptionsState(['SCF', 'REFERENCE'], ['SCF', 'GUESS'],
                                   ['SCF', 'DF_INTS_IO'], ['SCF', 'DFT_OMEGA'],
                                   ['DOCC'], ['SOCC'])

    kwargs = p4util.kwargs_lower(kwargs)

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

    if core.get_option('SCF', 'REFERENCE') != 'UKS':
        core.print_out(
            """  Requested procedure `ip_fitting` runs further calculations with UKS reference.\n"""
        )
        core.set_local_option('SCF', 'REFERENCE', 'UKS')

    # Make sure the molecule the user provided is the active one, and neutral
    molecule = kwargs.pop('molecule', core.get_active_molecule())
    molecule.update_geometry()

    if molecule.molecular_charge() != 0:
        raise ValidationError(
            """IP Fitting requires neutral molecule to start.""")
    if molecule.schoenflies_symbol() != 'c1':
        core.print_out(
            """  Requested procedure `ip_fitting` does not make use of molecular symmetry: """
            """further calculations in C1 point group.\n""")
    molecule = molecule.clone()
    molecule.reset_point_group('c1')
    molecule.update_geometry()

    charge0 = molecule.molecular_charge()
    mult0 = molecule.multiplicity()

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

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

    # Burn in to determine orbital eigenvalues
    if read:
        core.set_local_option("SCF", "GUESS", "READ")
        copy_file_to_scratch(read180, 'psi', 'ot', 180)
    core.set_local_option("SCF", "DF_INTS_IO", "SAVE")
    E, wfn = driver.energy('scf',
                           dft_functional=name,
                           return_wfn=True,
                           molecule=molecule,
                           banner='IP Fitting SCF: Burn-in',
                           **kwargs)
    core.set_local_option("SCF", "DF_INTS_IO", "LOAD")

    if not wfn.functional().is_x_lrc():
        raise ValidationError(
            """Not sensible to optimize omega for non-long-range-correction functional."""
        )

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

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

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

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

    # Right endpoint
    core.set_local_option('SCF', 'DFT_OMEGA', omega_r)

    # Neutral
    if read:
        core.set_local_option("SCF", "GUESS", "READ")
        p4util.copy_file_to_scratch(read180, 'psi', 'ot', 180)

    molecule.set_molecular_charge(charge0)
    molecule.set_multiplicity(mult0)
    E0r, wfn = driver.energy('scf',
                             dft_functional=name,
                             return_wfn=True,
                             molecule=molecule,
                             banner='IP Fitting SCF: Neutral, Right Endpoint',
                             **kwargs)
    eps_a = wfn.epsilon_a()
    eps_b = wfn.epsilon_b()
    if Nb == 0:
        E_HOMO = eps_a.np[int(Na - 1)]
    else:
        E_a = eps_a.np[int(Na - 1)]
        E_b = eps_b.np[int(Nb - 1)]
        E_HOMO = max(E_a, E_b)
    E_HOMOr = E_HOMO
    core.IO.change_file_namespace(180, "ot", "neutral")

    # Cation
    if read:
        core.set_local_option("SCF", "GUESS", "READ")
        p4util.copy_file_to_scratch(read180, 'psi', 'ot', 180)

    molecule.set_molecular_charge(charge1)
    molecule.set_multiplicity(mult1)
    E1r = driver.energy('scf',
                        dft_functional=name,
                        molecule=molecule,
                        banner='IP Fitting SCF: Cation, Right Endpoint',
                        **kwargs)
    core.IO.change_file_namespace(180, "ot", "cation")

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

    if IPr > kIPr:
        raise ValidationError(
            """\n***IP Fitting Error: Right Omega limit should have kIP > IP: {} !> {}"""
            .format(kIPr, IPr))

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

    # Use previous orbitals from here out
    core.set_local_option("SCF", "GUESS", "READ")

    # Left endpoint
    core.set_local_option('SCF', 'DFT_OMEGA', omega_l)

    # Neutral
    core.IO.change_file_namespace(180, "neutral", "ot")
    molecule.set_molecular_charge(charge0)
    molecule.set_multiplicity(mult0)
    core.set_global_option("DOCC", [Nb])
    core.set_global_option("SOCC", [Na - Nb])
    E0l, wfn = driver.energy('scf',
                             dft_functional=name,
                             return_wfn=True,
                             molecule=molecule,
                             banner='IP Fitting SCF: Neutral, Left Endpoint',
                             **kwargs)
    eps_a = wfn.epsilon_a()
    eps_b = wfn.epsilon_b()
    if Nb == 0:
        E_HOMO = eps_a.np[int(Na - 1)]
    else:
        E_a = eps_a.np[int(Na - 1)]
        E_b = eps_b.np[int(Nb - 1)]
        E_HOMO = max(E_a, E_b)
    E_HOMOl = E_HOMO
    core.IO.change_file_namespace(180, "ot", "neutral")

    # Cation
    core.IO.change_file_namespace(180, "cation", "ot")
    molecule.set_molecular_charge(charge1)
    molecule.set_multiplicity(mult1)
    core.set_global_option("DOCC", [Nb1])
    core.set_global_option("SOCC", [Na1 - Nb1])
    E1l = driver.energy('scf',
                        dft_functional=name,
                        molecule=molecule,
                        banner='IP Fitting SCF: Cation, Left Endpoint',
                        **kwargs)
    core.IO.change_file_namespace(180, "ot", "cation")

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

    if IPl < kIPl:
        raise ValidationError(
            """\n***IP Fitting Error: Left Omega limit should have kIP < IP: {} !< {}"""
            .format(kIPl, IPl))

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

    converged = False
    repeat_l = 0
    repeat_r = 0
    for step in range(maxiter):

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

        # Neutral
        core.IO.change_file_namespace(180, "neutral", "ot")
        molecule.set_molecular_charge(charge0)
        molecule.set_multiplicity(mult0)
        core.set_global_option("DOCC", [Nb])
        core.set_global_option("SOCC", [Na - Nb])
        E0, wfn = driver.energy(
            'scf',
            dft_functional=name,
            return_wfn=True,
            molecule=molecule,
            banner='IP Fitting SCF: Neutral, Omega = {:11.3E}'.format(omega),
            **kwargs)
        eps_a = wfn.epsilon_a()
        eps_b = wfn.epsilon_b()
        if Nb == 0:
            E_HOMO = eps_a.np[int(Na - 1)]
        else:
            E_a = eps_a.np[int(Na - 1)]
            E_b = eps_b.np[int(Nb - 1)]
            E_HOMO = max(E_a, E_b)
        core.IO.change_file_namespace(180, "ot", "neutral")

        # Cation
        core.IO.change_file_namespace(180, "cation", "ot")
        molecule.set_molecular_charge(charge1)
        molecule.set_multiplicity(mult1)
        core.set_global_option("DOCC", [Nb1])
        core.set_global_option("SOCC", [Na1 - Nb1])
        E1 = driver.energy(
            'scf',
            dft_functional=name,
            molecule=molecule,
            banner='IP Fitting SCF: Cation, Omega = {:11.3E}'.format(omega),
            **kwargs)
        core.IO.change_file_namespace(180, "ot", "cation")

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

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

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

        # Termination
        if abs(omega_l - omega_r) < omega_convergence:
            converged = True
            break

    core.IO.set_default_namespace("")
    core.print_out("""\n    ==> IP Fitting Results <==\n\n""")

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

    core.print_out("""     => Regula Falsi Iterations <=\n\n""")
    core.print_out("""    %3s %11s %14s %14s %14s %s\n""" %
                   ('N', 'Omega', 'IP', 'kIP', 'Delta', 'Type'))
    for k in range(len(omegas)):
        core.print_out(
            """    %3d %11.3E %14.6E %14.6E %14.6E %s\n""" %
            (k + 1, omegas[k], IPs[k], kIPs[k], IPs[k] - kIPs[k], types[k]))

    optstash.restore()
    if converged:
        core.print_out("""\n    IP Fitting Converged\n""")
        core.print_out("""    Final omega = %14.6E\n""" %
                       ((omega_l + omega_r) / 2))
        core.print_out(
            """\n    "M,I. does the dying. Fleet just does the flying."\n""")
        core.print_out("""            -Starship Troopers\n""")

    else:
        raise ConvergenceError("""IP Fitting """, step + 1)

    return ((omega_l + omega_r) / 2)
Esempio n. 42
0
def run_json_qcschema(json_data, clean):
    """
    An implementation of the QC JSON Schema (molssi-qc-schema.readthedocs.io/en/latest/index.html#) implementation in Psi4.


    Parameters
    ----------
    json_data : JSON
        Please see molssi-qc-schema.readthedocs.io/en/latest/spec_components.html for further details.

    Notes
    -----
    !Warning! This function is experimental and likely to change in the future.
    Please report any suggestions or uses of this function on github.com/MolSSI/QC_JSON_Schema.

    Examples
    --------

    """

    # Clean a few things
    _clean_psi_environ(clean)

    # This is currently a forced override
    if json_data["schema_name"] in ["qc_schema_input", "qcschema_input"]:
        json_data["schema_name"] = "qcschema_input"
    else:
        raise KeyError("Schema name of '{}' not understood".format(json_data["schema_name"]))

    if json_data["schema_version"] != 1:
        raise KeyError("Schema version of '{}' not understood".format(json_data["schema_version"]))

    if json_data.get("nthreads", False) is not False:
        psi4.set_num_threads(json_data["nthreads"], quiet=True)

    json_data["provenance"] = {"creator": "Psi4", "version": psi4.__version__, "routine": "psi4.json.run_json"}

    # Build molecule
    if "schema_name" in json_data["molecule"]:
        molschemus = json_data["molecule"]  # dtype >=2
    else:
        molschemus = json_data  # dtype =1
    mol = core.Molecule.from_schema(molschemus)

    # Update molecule geometry as we orient and fix_com
    json_data["molecule"]["geometry"] = mol.geometry().np.ravel().tolist()

    # Set options
    kwargs = json_data["keywords"].pop("function_kwargs", {})
    psi4.set_options(json_data["keywords"])

    # Setup the computation
    method = json_data["model"]["method"]
    core.set_global_option("BASIS", json_data["model"]["basis"])
    kwargs.update({"return_wfn": True, "molecule": mol})

    # Handle special properties case
    if json_data["driver"] == "properties":
        if "properties" in json_data["model"]:
            kwargs["properties"] = [x.lower() for x in json_data["model"]["properties"]]

            extra = set(kwargs["properties"]) - can_do_properties_
            if len(extra):
                raise KeyError("Did not understand property key %s." % kwargs["properties"])
        else:
            kwargs["properties"] = list(can_do_properties_)

    # Actual driver run
    val, wfn = methods_dict_[json_data["driver"]](method, **kwargs)

    # Pull out a standard set of SCF properties
    if "extras" not in json_data:
        json_data["extras"] = {}
    json_data["extras"]["qcvars"] = {}

    if json_data["extras"].get("wfn_qcvars_only", False):
        psi_props = wfn.variables()
    else:
        psi_props = psi4.core.variables()
        for k, v in psi_props.items():
            if k not in json_data["extras"]["qcvars"]:
                json_data["extras"]["qcvars"][k] = _json_translation(v)

    # Still a bit of a mess at the moment add in local vars as well.
    for k, v in wfn.variables().items():
        if k not in json_data["extras"]["qcvars"]:
            json_data["extras"]["qcvars"][k] = _json_translation(v)

    # Handle the return result
    if json_data["driver"] == "energy":
        json_data["return_result"] = val
    elif json_data["driver"] in ["gradient", "hessian"]:
        json_data["return_result"] = val.np.ravel().tolist()
    elif json_data["driver"] == "properties":
        ret = {}
        mtd = json_data["model"]["method"].upper()

        # Dipole/quadrupole still special case
        if "dipole" in kwargs["properties"]:
            ret["dipole"] = [psi_props[mtd + " DIPOLE " + x] for x in ["X", "Y", "Z"]]
        if "quadrupole" in kwargs["properties"]:
            ret["quadrupole"] = [psi_props[mtd + " QUADRUPOLE " + x] for x in ["XX", "XY", "XZ", "YY", "YZ", "ZZ"]]
        ret.update(_convert_variables(wfn.variables(), context="properties"))

        json_data["return_result"] = ret
    else:
        raise KeyError("Did not understand Driver key %s." % json_data["driver"])

    props = {
        "calcinfo_nbasis": wfn.nso(),
        "calcinfo_nmo": wfn.nmo(),
        "calcinfo_nalpha": wfn.nalpha(),
        "calcinfo_nbeta": wfn.nbeta(),
        "calcinfo_natom": mol.geometry().shape[0],
    }
    props.update(_convert_variables(psi_props, context="generics"))
    if not list(set(['CBS NUMBER', 'NBODY NUMBER', 'FINDIF NUMBER']) & set(json_data["extras"]["qcvars"].keys())):
        props.update(_convert_variables(psi_props, context="scf"))

    # Write out MP2 keywords
    if "MP2 CORRELATION ENERGY" in psi_props:
        props.update(_convert_variables(psi_props, context="mp2"))

    json_data["properties"] = props
    json_data["success"] = True

    # Reset state
    _clean_psi_environ(clean)

    json_data["schema_name"] = "qcschema_output"

    return json_data
Esempio n. 43
0
def basis_helper(block, name='', key='BASIS', set_option=True):
    """For PsiAPI mode, forms a basis specification function from *block*
    and associates it with keyword *key* under handle *name*. Registers
    the basis spec with Psi4 so that it can be applied again to future
    molecules. For usage, see mints2, mints9, and cc54 test cases. Unless
    *set_option* is False, *name* will be set as current active *key*,
    equivalent to `set key name` or `set_option({key: name})`.

    """
    key = key.upper()
    name = ('anonymous' + str(uuid.uuid4())[:8]) if name == '' else name
    cleanbas = basname(name).replace('-', '')  # further remove hyphens so can be function name
    block = qcel.util.filter_comments(block)
    command_lines = re.split('\n', block)

    symbol_re = re.compile(r'^\s*assign\s+(?P<symbol>[A-Z]{1,3})\s+(?P<basis>[-+*\(\)\w]+)\s*$', re.IGNORECASE)
    label_re = re.compile(
        r'^\s*assign\s+(?P<label>(?P<symbol>[A-Z]{1,3})(?:(_\w+)|(\d+))?)\s+(?P<basis>[-+*\(\)\w]+)\s*$',
        re.IGNORECASE)
    all_re = re.compile(r'^\s*assign\s+(?P<basis>[-+*\(\)\w]+)\s*$', re.IGNORECASE)
    basislabel = re.compile(r'\s*\[\s*([-*\(\)\w]+)\s*\]\s*')

    def anon(mol, role):
        basstrings = {}

        # Start by looking for assign lines, and remove them
        leftover_lines = []
        assignments = False
        for line in command_lines:
            if symbol_re.match(line):
                m = symbol_re.match(line)
                mol.set_basis_by_symbol(m.group('symbol'), m.group('basis'), role=role)
                assignments = True

            elif label_re.match(line):
                m = label_re.match(line)
                mol.set_basis_by_label(m.group('label'), m.group('basis'), role=role)
                assignments = True

            elif all_re.match(line):
                m = all_re.match(line)
                mol.set_basis_all_atoms(m.group('basis'), role=role)
                assignments = True

            else:
                # Ignore blank lines and accumulate remainder
                if line and not line.isspace():
                    leftover_lines.append(line.strip())

        # Now look for regular basis set definitions
        basblock = list(filter(None, basislabel.split('\n'.join(leftover_lines))))
        if len(basblock) == 1:
            if not assignments:
                # case with no [basname] markers where whole block is contents of gbs file
                mol.set_basis_all_atoms(name, role=role)
                basstrings[basname(name)] = basblock[0]
            else:
                message = (
                    "Conflicting basis set specification: assign lines present but shells have no [basname] label."
                    "")
                raise TestComparisonError(message)
        else:
            # case with specs separated by [basname] markers
            for idx in range(0, len(basblock), 2):
                basstrings[basname(basblock[idx])] = basblock[idx + 1]

        return basstrings

    anon.__name__ = 'basisspec_psi4_yo__' + cleanbas
    qcdb.libmintsbasisset.basishorde[name.upper()] = anon
    if set_option:
        core.set_global_option(key, name)
Esempio n. 44
0
def run_sf_sapt(name, **kwargs):
    optstash = p4util.OptionsState(['SCF_TYPE'], ['SCF', 'REFERENCE'],
                                   ['SCF', 'DFT_GRAC_SHIFT'],
                                   ['SCF', 'SAVE_JK'])

    core.tstart()

    # Alter default algorithm
    if not core.has_global_option_changed('SCF_TYPE'):
        core.set_global_option('SCF_TYPE', 'DF')

    core.prepare_options_for_module("SAPT")

    # Get the molecule of interest
    ref_wfn = kwargs.get('ref_wfn', None)
    if ref_wfn is None:
        sapt_dimer = kwargs.pop('molecule', core.get_active_molecule())
    else:
        core.print_out(
            'Warning! SAPT argument "ref_wfn" is only able to use molecule information.'
        )
        sapt_dimer = ref_wfn.molecule()

    sapt_dimer, monomerA, monomerB = proc_util.prepare_sapt_molecule(
        sapt_dimer, "dimer")

    # Print out the title and some information
    core.print_out("\n")
    core.print_out(
        "         ---------------------------------------------------------\n")
    core.print_out("         " + "Spin-Flip SAPT Procedure".center(58) + "\n")
    core.print_out("\n")
    core.print_out("         " +
                   "by Daniel G. A. Smith and Konrad Patkowski".center(58) +
                   "\n")
    core.print_out(
        "         ---------------------------------------------------------\n")
    core.print_out("\n")

    core.print_out("  ==> Algorithm <==\n\n")
    core.print_out("   JK Algorithm            %12s\n" %
                   core.get_option("SCF", "SCF_TYPE"))
    core.print_out("\n")
    core.print_out("   Required computations:\n")
    core.print_out("     HF  (Monomer A)\n")
    core.print_out("     HF  (Monomer B)\n")
    core.print_out("\n")

    if (core.get_option('SCF', 'REFERENCE') != 'ROHF'):
        raise ValidationError(
            'Spin-Flip SAPT currently only supports restricted open-shell references.'
        )

    # Run the two monomer computations
    core.IO.set_default_namespace('dimer')
    data = {}

    if (core.get_global_option('SCF_TYPE') == 'DF'):
        core.set_global_option('DF_INTS_IO', 'SAVE')

    # Compute dimer wavefunction
    wfn_A = scf_helper("SCF",
                       molecule=monomerA,
                       banner="SF-SAPT: HF Monomer A",
                       **kwargs)

    core.set_global_option("SAVE_JK", True)
    wfn_B = scf_helper("SCF",
                       molecule=monomerB,
                       banner="SF-SAPT: HF Monomer B",
                       **kwargs)
    sapt_jk = wfn_B.jk()
    core.set_global_option("SAVE_JK", False)
    core.print_out("\n")
    core.print_out(
        "         ---------------------------------------------------------\n")
    core.print_out("         " +
                   "Spin-Flip SAPT Exchange and Electrostatics".center(58) +
                   "\n")
    core.print_out("\n")
    core.print_out("         " +
                   "by Daniel G. A. Smith and Konrad Patkowski".center(58) +
                   "\n")
    core.print_out(
        "         ---------------------------------------------------------\n")
    core.print_out("\n")

    sf_data = sapt_sf_terms.compute_sapt_sf(sapt_dimer, sapt_jk, wfn_A, wfn_B)

    # Print the results
    core.print_out("   Spin-Flip SAPT Results\n")
    core.print_out("  " + "-" * 103 + "\n")

    for key, value in sf_data.items():
        value = sf_data[key]
        print_vals = (key, value * 1000, value * constants.hartree2kcalmol,
                      value * constants.hartree2kJmol)
        string = "    %-26s % 15.8f [mEh] % 15.8f [kcal/mol] % 15.8f [kJ/mol]\n" % print_vals
        core.print_out(string)
    core.print_out("  " + "-" * 103 + "\n\n")

    dimer_wfn = core.Wavefunction.build(sapt_dimer, wfn_A.basisset())

    # Set variables
    psivar_tanslator = {
        "Elst10": "SAPT ELST ENERGY",
        "Exch10(S^2) [diagonal]": "SAPT EXCH10(S^2),DIAGONAL ENERGY",
        "Exch10(S^2) [off-diagonal]": "SAPT EXCH10(S^2),OFF-DIAGONAL ENERGY",
        "Exch10(S^2) [highspin]": "SAPT EXCH10(S^2),HIGHSPIN ENERGY",
    }

    for k, v in sf_data.items():
        psi_k = psivar_tanslator[k]

        dimer_wfn.set_variable(psi_k, v)
        core.set_variable(psi_k, v)

    # Copy over highspin
    core.set_variable("SAPT EXCH ENERGY", sf_data["Exch10(S^2) [highspin]"])

    core.tstop()

    return dimer_wfn
Esempio n. 45
0
def run_sf_sapt(name, **kwargs):
    optstash = p4util.OptionsState(['SCF_TYPE'],
                                   ['SCF', 'REFERENCE'],
                                   ['SCF', 'DFT_GRAC_SHIFT'],
                                   ['SCF', 'SAVE_JK'])

    core.tstart()

    # Alter default algorithm
    if not core.has_global_option_changed('SCF_TYPE'):
        core.set_global_option('SCF_TYPE', 'DF')

    core.prepare_options_for_module("SAPT")

    # Get the molecule of interest
    ref_wfn = kwargs.get('ref_wfn', None)
    if ref_wfn is None:
        sapt_dimer = kwargs.pop('molecule', core.get_active_molecule())
    else:
        core.print_out('Warning! SAPT argument "ref_wfn" is only able to use molecule information.')
        sapt_dimer = ref_wfn.molecule()

    sapt_dimer, monomerA, monomerB = proc_util.prepare_sapt_molecule(sapt_dimer, "dimer")

    # Print out the title and some information
    core.print_out("\n")
    core.print_out("         ---------------------------------------------------------\n")
    core.print_out("         " + "Spin-Flip SAPT Procedure".center(58) + "\n")
    core.print_out("\n")
    core.print_out("         " + "by Daniel G. A. Smith and Konrad Patkowski".center(58) + "\n")
    core.print_out("         ---------------------------------------------------------\n")
    core.print_out("\n")

    core.print_out("  ==> Algorithm <==\n\n")
    core.print_out("   JK Algorithm            %12s\n" % core.get_option("SCF", "SCF_TYPE"))
    core.print_out("\n")
    core.print_out("   Required computations:\n")
    core.print_out("     HF  (Monomer A)\n")
    core.print_out("     HF  (Monomer B)\n")
    core.print_out("\n")

    if (core.get_option('SCF', 'REFERENCE') != 'ROHF'):
        raise ValidationError('Spin-Flip SAPT currently only supports restricted open-shell references.')

    # Run the two monomer computations
    core.IO.set_default_namespace('dimer')
    data = {}

    if (core.get_global_option('SCF_TYPE') == 'DF'):
        core.set_global_option('DF_INTS_IO', 'SAVE')

    # Compute dimer wavefunction
    wfn_A = scf_helper("SCF", molecule=monomerA, banner="SF-SAPT: HF Monomer A", **kwargs)

    core.set_global_option("SAVE_JK", True)
    wfn_B = scf_helper("SCF", molecule=monomerB, banner="SF-SAPT: HF Monomer B", **kwargs)
    sapt_jk = wfn_B.jk()
    core.set_global_option("SAVE_JK", False)
    core.print_out("\n")
    core.print_out("         ---------------------------------------------------------\n")
    core.print_out("         " + "Spin-Flip SAPT Exchange and Electrostatics".center(58) + "\n")
    core.print_out("\n")
    core.print_out("         " + "by Daniel G. A. Smith and Konrad Patkowski".center(58) + "\n")
    core.print_out("         ---------------------------------------------------------\n")
    core.print_out("\n")

    sf_data = sapt_sf_terms.compute_sapt_sf(sapt_dimer, sapt_jk, wfn_A, wfn_B)

    # Print the results
    core.print_out("   Spin-Flip SAPT Results\n")
    core.print_out("  " + "-" * 103 + "\n")

    for key, value in sf_data.items():
        value = sf_data[key]
        print_vals = (key, value * 1000, value * constants.hartree2kcalmol, value * constants.hartree2kJmol)
        string = "    %-26s % 15.8f [mEh] % 15.8f [kcal/mol] % 15.8f [kJ/mol]\n" % print_vals
        core.print_out(string)
    core.print_out("  " + "-" * 103 + "\n\n")

    dimer_wfn = core.Wavefunction.build(sapt_dimer, wfn_A.basisset())

    # Set variables
    psivar_tanslator = {
        "Elst10": "SAPT ELST ENERGY",
        "Exch10(S^2) [diagonal]": "SAPT EXCH10(S^2),DIAGONAL ENERGY",
        "Exch10(S^2) [off-diagonal]": "SAPT EXCH10(S^2),OFF-DIAGONAL ENERGY",
        "Exch10(S^2) [highspin]": "SAPT EXCH10(S^2),HIGHSPIN ENERGY",
    }

    for k, v in sf_data.items():
        psi_k = psivar_tanslator[k]
        
        dimer_wfn.set_variable(psi_k, v)
        core.set_variable(psi_k, v)

    # Copy over highspin
    core.set_variable("SAPT EXCH ENERGY", sf_data["Exch10(S^2) [highspin]"])

    core.tstop()

    return dimer_wfn
Esempio n. 46
0
def _set_convergence_criterion(ptype,
                               method_name,
                               scf_Ec,
                               pscf_Ec,
                               scf_Dc,
                               pscf_Dc,
                               gen_Ec,
                               verbose=1):
    r"""
    This function will set local SCF and global energy convergence criterion
    to the defaults listed at:
    http://www.psicode.org/psi4manual/master/scf.html#convergence-and-
    algorithm-defaults. SCF will be converged more tightly if a post-SCF
    method is select (pscf_Ec, and pscf_Dc) else the looser (scf_Ec, and
    scf_Dc convergence criterion will be used).

    ptype -         Procedure type (energy, gradient, etc). Nearly always test on
                    procedures['energy'] since that's guaranteed to exist for a method.
    method_name -   Name of the method
    scf_Ec -        E convergence criterion for scf target method
    pscf_Ec -       E convergence criterion for scf of post-scf target method
    scf_Dc -        D convergence criterion for scf target method
    pscf_Dc -       D convergence criterion for scf of post-scf target method
    gen_Ec -        E convergence criterion for post-scf target method

    """
    optstash = p4util.OptionsState(['SCF', 'E_CONVERGENCE'],
                                   ['SCF', 'D_CONVERGENCE'], ['E_CONVERGENCE'])

    # Kind of want to move this out of here
    _method_exists(ptype, method_name)

    if verbose >= 2:
        print('      Setting convergence', end=' ')
    # Set method-dependent scf convergence criteria, check against energy routines
    if not core.has_option_changed('SCF', 'E_CONVERGENCE'):
        if procedures['energy'][method_name] == proc.run_scf:
            core.set_local_option('SCF', 'E_CONVERGENCE', scf_Ec)
            if verbose >= 2:
                print(scf_Ec, end=' ')
        else:
            core.set_local_option('SCF', 'E_CONVERGENCE', pscf_Ec)
            if verbose >= 2:
                print(pscf_Ec, end=' ')
    else:
        if verbose >= 2:
            print('CUSTOM', core.get_option('SCF', 'E_CONVERGENCE'), end=' ')

    if not core.has_option_changed('SCF', 'D_CONVERGENCE'):
        if procedures['energy'][method_name] == proc.run_scf:
            core.set_local_option('SCF', 'D_CONVERGENCE', scf_Dc)
            if verbose >= 2:
                print(scf_Dc, end=' ')
        else:
            core.set_local_option('SCF', 'D_CONVERGENCE', pscf_Dc)
            if verbose >= 2:
                print(pscf_Dc, end=' ')
    else:
        if verbose >= 2:
            print('CUSTOM', core.get_option('SCF', 'D_CONVERGENCE'), end=' ')

    # Set post-scf convergence criteria (global will cover all correlated modules)
    if not core.has_global_option_changed('E_CONVERGENCE'):
        if procedures['energy'][method_name] != proc.run_scf:
            core.set_global_option('E_CONVERGENCE', gen_Ec)
            if verbose >= 2:
                print(gen_Ec, end=' ')
    else:
        if procedures['energy'][method_name] != proc.run_scf:
            if verbose >= 2:
                print('CUSTOM',
                      core.get_global_option('E_CONVERGENCE'),
                      end=' ')

    if verbose >= 2:
        print('')
    return optstash
Esempio n. 47
0
def _set_convergence_criterion(ptype, method_name, scf_Ec, pscf_Ec, scf_Dc, pscf_Dc, gen_Ec, verbose=1):
    r"""
    This function will set local SCF and global energy convergence criterion
    to the defaults listed at:
    http://www.psicode.org/psi4manual/master/scf.html#convergence-and-
    algorithm-defaults. SCF will be converged more tightly if a post-SCF
    method is select (pscf_Ec, and pscf_Dc) else the looser (scf_Ec, and
    scf_Dc convergence criterion will be used).

    ptype -         Procedure type (energy, gradient, etc). Nearly always test on
                    procedures['energy'] since that's guaranteed to exist for a method.
    method_name -   Name of the method
    scf_Ec -        E convergence criterion for scf target method
    pscf_Ec -       E convergence criterion for scf of post-scf target method
    scf_Dc -        D convergence criterion for scf target method
    pscf_Dc -       D convergence criterion for scf of post-scf target method
    gen_Ec -        E convergence criterion for post-scf target method

    """
    optstash = p4util.OptionsState(
        ['SCF', 'E_CONVERGENCE'],
        ['SCF', 'D_CONVERGENCE'],
        ['E_CONVERGENCE'])

    # Kind of want to move this out of here
    _method_exists(ptype, method_name)

    if verbose >= 2:
        print('      Setting convergence', end=' ')
    # Set method-dependent scf convergence criteria, check against energy routines
    if not core.has_option_changed('SCF', 'E_CONVERGENCE'):
        if procedures['energy'][method_name] == proc.run_scf:
            core.set_local_option('SCF', 'E_CONVERGENCE', scf_Ec)
            if verbose >= 2:
                print(scf_Ec, end=' ')
        else:
            core.set_local_option('SCF', 'E_CONVERGENCE', pscf_Ec)
            if verbose >= 2:
                print(pscf_Ec, end=' ')
    else:
        if verbose >= 2:
            print('CUSTOM', core.get_option('SCF', 'E_CONVERGENCE'), end=' ')

    if not core.has_option_changed('SCF', 'D_CONVERGENCE'):
        if procedures['energy'][method_name] == proc.run_scf:
            core.set_local_option('SCF', 'D_CONVERGENCE', scf_Dc)
            if verbose >= 2:
                print(scf_Dc, end=' ')
        else:
            core.set_local_option('SCF', 'D_CONVERGENCE', pscf_Dc)
            if verbose >= 2:
                print(pscf_Dc, end=' ')
    else:
        if verbose >= 2:
            print('CUSTOM', core.get_option('SCF', 'D_CONVERGENCE'), end=' ')

    # Set post-scf convergence criteria (global will cover all correlated modules)
    if not core.has_global_option_changed('E_CONVERGENCE'):
        if procedures['energy'][method_name] != proc.run_scf:
            core.set_global_option('E_CONVERGENCE', gen_Ec)
            if verbose >= 2:
                print(gen_Ec, end=' ')
    else:
        if procedures['energy'][method_name] != proc.run_scf:
            if verbose >= 2:
                print('CUSTOM', core.get_global_option('E_CONVERGENCE'), end=' ')

    if verbose >= 2:
        print('')
    return optstash
Esempio n. 48
0
def basis_helper(block, name='', key='BASIS', set_option=True):
    """For PsiAPI mode, forms a basis specification function from *block*
    and associates it with keyword *key* under handle *name*. Registers
    the basis spec with Psi4 so that it can be applied again to future
    molecules. For usage, see mints2, mints9, and cc54 test cases. Unless
    *set_option* is False, *name* will be set as current active *key*,
    equivalent to `set key name` or `set_option({key: name})`.

    """
    key = key.upper()
    name = ('anonymous' + str(uuid.uuid4())[:8]) if name == '' else name
    cleanbas = basname(name).replace(
        '-', '')  # further remove hyphens so can be function name
    block = qcel.util.filter_comments(block)
    command_lines = re.split('\n', block)

    symbol_re = re.compile(
        r'^\s*assign\s+(?P<symbol>[A-Z]{1,3})\s+(?P<basis>[-+*\(\)\w]+)\s*$',
        re.IGNORECASE)
    label_re = re.compile(
        r'^\s*assign\s+(?P<label>(?P<symbol>[A-Z]{1,3})(?:(_\w+)|(\d+))?)\s+(?P<basis>[-+*\(\)\w]+)\s*$',
        re.IGNORECASE)
    all_re = re.compile(r'^\s*assign\s+(?P<basis>[-+*\(\)\w]+)\s*$',
                        re.IGNORECASE)
    basislabel = re.compile(r'\s*\[\s*([-*\(\)\w]+)\s*\]\s*')

    def anon(mol, role):
        basstrings = {}

        # Start by looking for assign lines, and remove them
        leftover_lines = []
        assignments = False
        for line in command_lines:
            if symbol_re.match(line):
                m = symbol_re.match(line)
                mol.set_basis_by_symbol(m.group('symbol'),
                                        m.group('basis'),
                                        role=role)
                assignments = True

            elif label_re.match(line):
                m = label_re.match(line)
                mol.set_basis_by_label(m.group('label'),
                                       m.group('basis'),
                                       role=role)
                assignments = True

            elif all_re.match(line):
                m = all_re.match(line)
                mol.set_basis_all_atoms(m.group('basis'), role=role)
                assignments = True

            else:
                # Ignore blank lines and accumulate remainder
                if line and not line.isspace():
                    leftover_lines.append(line.strip())

        # Now look for regular basis set definitions
        basblock = list(
            filter(None, basislabel.split('\n'.join(leftover_lines))))
        if len(basblock) == 1:
            if not assignments:
                # case with no [basname] markers where whole block is contents of gbs file
                mol.set_basis_all_atoms(name, role=role)
                basstrings[basname(name)] = basblock[0]
            else:
                message = (
                    "Conflicting basis set specification: assign lines present but shells have no [basname] label."
                    "")
                raise TestComparisonError(message)
        else:
            # case with specs separated by [basname] markers
            for idx in range(0, len(basblock), 2):
                basstrings[basname(basblock[idx])] = basblock[idx + 1]

        return basstrings

    anon.__name__ = 'basisspec_psi4_yo__' + cleanbas
    qcdb.libmintsbasisset.basishorde[name.upper()] = anon
    if set_option:
        core.set_global_option(key, name)
Esempio n. 49
0
def run_json(json_data):
    """
    Runs and updates the input JSON data.

    Parameters
    ----------
    json_data : JSON input
        Required input fields:
            - molecule : str
                A string representation of the molecule. Any valid psi4 synatx is valid.
            - driver : str
                The driver method to use valid arguments are "energy", "gradient", "property"
            - args : str
                Input arguments to the driver function
            - kwargs : dict
                Input dictionary to the driver function

        Optional input fields:
            - kwargs : dict
                Additional kwargs to be passed to the driver.
            - options : dict
                Global options to set in the Psi4 run.
            - scratch_location : str
                Overide the default scratch location.
            - return_output : bool
                Return the full string reprsentation of the output or not.

        Output fields:
            - return_value : float, psi4.core.Vector, psi4.core.Matrix
                The return value of the input function.
            - variables : dict
                The list of Psi4 variables generated from the run.
            - success : bool
                Indicates if the run was successful or not.
            - error : str
                If an error is raised the result is returned here.
            - raw_output : str
                The full Psi4 output if requested.


    Notes
    -----
    !Warning! This function is experimental and likely to change in the future.
    Please report any suggestions or uses of this function on github.com/psi4/psi4.

    Examples
    --------

    # CP corrected Helium dimer energy in the STO-3G basis.
    >>> json_data = {}

    >>> json_data["molecule"] = "He 0 0 0\n--\nHe 0 0 1"
    >>> json_data["driver"] = "energy"
    >>> json_data["method"] = 'SCF'
    >>> json_data["kwargs"] = {"bsse_type": "cp"}
    >>> json_data["options"] = {"BASIS": "STO-3G"}

    >>> run_json(json_data)
    {
        "raw_output": "Output storing was not requested.",
        "options": {
            "BASIS": "STO-3G"
        },
        "driver": "energy",
        "molecule": "He 0 0 0\n--\nHe 0 0 1",
        "method": "SCF",
        "variables": {
            "SCF N ITERS": 2.0,
            "SCF DIPOLE Y": 0.0,
            "CURRENT DIPOLE Y": 0.0,
            "CP-CORRECTED 2-BODY INTERACTION ENERGY": 0.1839360538612116,
            "HF TOTAL ENERGY": -5.433191881443323,
            "SCF TOTAL ENERGY": -5.433191881443323,
            "TWO-ELECTRON ENERGY": 4.124089347186247,
            "SCF ITERATION ENERGY": -5.433191881443323,
            "CURRENT DIPOLE X": 0.0,
            "CURRENT DIPOLE Z": 0.0,
            "CURRENT REFERENCE ENERGY": -5.433191881443323,
            "CURRENT ENERGY": 0.1839360538612116,
            "COUNTERPOISE CORRECTED TOTAL ENERGY": -5.433191881443323,
            "SCF DIPOLE Z": 0.0,
            "COUNTERPOISE CORRECTED INTERACTION ENERGY": 0.1839360538612116,
            "NUCLEAR REPULSION ENERGY": 2.11670883436,
            "SCF DIPOLE X": 0.0,
            "ONE-ELECTRON ENERGY": -11.67399006298957
        },
        "return_value": 0.1839360538612116,
        "error": "",
        "success": true,
        "provenance": {
            "creator": "Psi4",
            "routine": "psi4.run_json",
            "version": "1.1a1"
        },
        "kwargs": {
            "bsse_type": "cp"
        }
    }
    """

    # Set a few variables
    json_data["error"] = ""
    json_data["raw_output"] = "Output storing was not requested."
    json_data["success"] = False
    json_data["raw_output"] = None

    # Check input
    for check in ["driver", "method", "molecule"]:
        if check not in list(json_data):
            json_data["error"] = "Minimum input requires the %s field." % check
            return json_data

    # Check driver call
    if json_data["driver"] not in list(methods_dict):
        json_data["error"] = "Driver parameters '%s' not recognized" % str(json_data["driver"])
        return json_data


    # Set scratch
    if "scratch_location" in list(json_data):
        psi4_io = core.IOManager.shared_object()
        psi4_io.set_default_path(json_data["scratch_location"])

    # Set memory
    if "memory" in list(json_data):
        psi4.core.set_memory(int(json_data["memory"]))

    # Do we return the output?
    return_output = json_data.pop("return_output", False)
    if return_output:
        outfile = str(uuid.uuid4()) + ".json_out"
        core.set_output_file(outfile, False)
        json_data["raw_output"] = "Not yet run."

    try:
        # Set options
        if "options" in json_data.keys() and (json_data["options"] is not None):
            for k, v in json_data["options"].items():
                core.set_global_option(k, v)

        # Rework args
        args = json_data["method"]
        if not isinstance(args, (list, tuple)):
            args = [args]

        # Deep copy kwargs
        if "kwargs" in list(json_data):
            kwargs = copy.deepcopy(json_data["kwargs"])
        else:
            kwargs = {}

        kwargs["molecule"] = molutil.geometry(json_data["molecule"])

        # Full driver call
        kwargs["return_wfn"] = True

        val, wfn = methods_dict[json_data["driver"]](*args, **kwargs)

        if isinstance(val, (float)):
            json_data["return_value"] = val
        elif isinstance(val, (core.Matrix, core.Vector)):
            json_data["return_value"] = val.to_serial()
        else:
            json_data["error"] += "Unrecognized return value of type %s\n" % type(val)
            json_data["return_value"] = val

        json_data["variables"] = core.get_variables()
        json_data["success"] = True

        prov = {}
        prov["version"] = psi4.__version__
        prov["routine"] = "psi4.run_json"
        prov["creator"] = "Psi4"
        json_data["provenance"] = prov

    except Exception as error:
        json_data["error"] += repr(error)
        json_data["success"] = False

    if return_output:
        with open(outfile, 'r') as f:
            json_data["raw_output"] = f.read()
        os.unlink(outfile)

    return json_data
Esempio n. 50
0
def run_json_original_v1_1(json_data, clean):
    """
    Runs and updates the input JSON data.

    This was a trial specification introduced in Psi4 v1.1. This will be deprecated in Psi4 v1.3 in favour of the QC JSON format
    found here: http://molssi-qc-schema.readthedocs.io/en/latest/index.html#

    Parameters
    ----------
    json_data : JSON input
        Required input fields:
            - molecule : str
                A string representation of the molecule. Any valid psi4 synatx is valid.
            - driver : str
                The driver method to use valid arguments are "energy", "gradient", "property"
            - args : str
                Input arguments to the driver function
            - kwargs : dict
                Input dictionary to the driver function

        Optional input fields:
            - kwargs : dict
                Additional kwargs to be passed to the driver.
            - options : dict
                Global options to set in the Psi4 run.
            - scratch_location : str
                Overide the default scratch location.
            - return_output : bool
                Return the full string reprsentation of the output or not.

        Output fields:
            - return_value : float, psi4.core.Vector, psi4.core.Matrix
                The return value of the input function.
            - variables : dict
                The list of Psi4 variables generated from the run.
            - success : bool
                Indicates if the run was successful or not.
            - error : str
                If an error is raised the result is returned here.
            - raw_output : str
                The full Psi4 output if requested.


    Notes
    -----
    !Warning! This function is experimental and likely to change in the future.
    Please report any suggestions or uses of this function on github.com/psi4/psi4.

    Examples
    --------

    # CP corrected Helium dimer energy in the STO-3G basis.
    >>> json_data = {}

    >>> json_data["molecule"] = "He 0 0 0\n--\nHe 0 0 1"
    >>> json_data["driver"] = "energy"
    >>> json_data["method"] = 'SCF'
    >>> json_data["kwargs"] = {"bsse_type": "cp"}
    >>> json_data["options"] = {"BASIS": "STO-3G"}

    >>> run_json(json_data)
    {
        "raw_output": "Output storing was not requested.",
        "options": {
            "BASIS": "STO-3G"
        },
        "driver": "energy",
        "molecule": "He 0 0 0\n--\nHe 0 0 1",
        "method": "SCF",
        "variables": {
            "SCF N ITERS": 2.0,
            "SCF DIPOLE Y": 0.0,
            "CURRENT DIPOLE Y": 0.0,
            "CP-CORRECTED 2-BODY INTERACTION ENERGY": 0.1839360538612116,
            "HF TOTAL ENERGY": -5.433191881443323,
            "SCF TOTAL ENERGY": -5.433191881443323,
            "TWO-ELECTRON ENERGY": 4.124089347186247,
            "SCF ITERATION ENERGY": -5.433191881443323,
            "CURRENT DIPOLE X": 0.0,
            "CURRENT DIPOLE Z": 0.0,
            "CURRENT REFERENCE ENERGY": -5.433191881443323,
            "CURRENT ENERGY": 0.1839360538612116,
            "COUNTERPOISE CORRECTED TOTAL ENERGY": -5.433191881443323,
            "SCF DIPOLE Z": 0.0,
            "COUNTERPOISE CORRECTED INTERACTION ENERGY": 0.1839360538612116,
            "NUCLEAR REPULSION ENERGY": 2.11670883436,
            "SCF DIPOLE X": 0.0,
            "ONE-ELECTRON ENERGY": -11.67399006298957
        },
        "return_value": 0.1839360538612116,
        "error": "",
        "success": true,
        "provenance": {
            "creator": "Psi4",
            "routine": "psi4.run_json",
            "version": "1.1a1"
        },
        "kwargs": {
            "bsse_type": "cp"
        }
    }
    """

    # Clean a few things
    _clean_psi_environ(clean)

    # Set a few variables
    json_data["error"] = ""
    json_data["success"] = False
    json_data["raw_output"] = None
    json_data[
        "warning"] = "Warning! This format will be deprecated in Psi4 v1.3. Please switch the standard QC JSON format."

    # Add the provenance data
    prov = {}
    prov["version"] = psi4.__version__
    prov["routine"] = "psi4.run_json"
    prov["creator"] = "Psi4"
    json_data["provenance"] = prov

    # Check input
    for check in ["driver", "method", "molecule"]:
        if check not in list(json_data):
            json_data["error"] = "Minimum input requires the %s field." % check
            return json_data

    # Check driver call
    if json_data["driver"] not in list(methods_dict_):
        json_data["error"] = "Driver parameters '%s' not recognized" % str(json_data["driver"])
        return json_data

    # Set options
    if "options" in json_data.keys() and (json_data["options"] is not None):
        for k, v in json_data["options"].items():
            core.set_global_option(k, v)

    # Rework args
    args = json_data["method"]
    if not isinstance(args, (list, tuple)):
        args = [args]

    # Deep copy kwargs
    if "kwargs" in list(json_data):
        kwargs = copy.deepcopy(json_data["kwargs"])
    else:
        kwargs = {}

    kwargs["molecule"] = molutil.geometry(json_data["molecule"])

    # Full driver call
    kwargs["return_wfn"] = True

    if json_data["driver"] not in methods_dict_:
        raise KeyError("Driver type '%s' not recognized." % str(json_data["driver"]))

    val, wfn = methods_dict_[json_data["driver"]](*args, **kwargs)

    if isinstance(val, (float, int)):
        json_data["return_value"] = val
    elif isinstance(val, (core.Matrix, core.Vector)):
        json_data["return_value"] = val.to_serial()
    else:
        raise TypeError("Unrecognized return value of type %s\n" % type(val))

    json_data["variables"] = core.get_variables()
    json_data["success"] = True

    # Reset state
    _clean_psi_environ(clean)

    return json_data
Esempio n. 51
0
def run_json_qc_schema(json_data, clean):
    """
    An implementation of the QC JSON Schema (molssi-qc-schema.readthedocs.io/en/latest/index.html#) implementation in Psi4.


    Parameters
    ----------
    json_data : JSON
        Please see molssi-qc-schema.readthedocs.io/en/latest/spec_components.html for further details.

    Notes
    -----
    !Warning! This function is experimental and likely to change in the future.
    Please report any suggestions or uses of this function on github.com/MolSSI/QC_JSON_Schema.

    Examples
    --------

    """

    # Clean a few things
    _clean_psi_environ(clean)

    # This is currently a forced override
    if json_data["schema_name"] != "qc_schema_input":
        raise KeyError("Schema name of '{}' not understood".format(json_data["schema_name"]))

    if json_data["schema_version"] != 1:
        raise KeyError("Schema version of '{}' not understood".format(json_data["schema_version"]))

    if json_data.get("nthreads", False) is not False:
        psi4.set_num_threads(json_data["nthreads"], quiet=True)

    json_data["provenance"] = {"creator": "Psi4", "version": psi4.__version__, "routine": "psi4.json.run_json"}

    # Build molecule
    mol = core.Molecule.from_schema(json_data)

    # Update molecule geometry as we orient and fix_com
    json_data["molecule"]["geometry"] = mol.geometry().np.ravel().tolist()


    # Set options
    for k, v in json_data["keywords"].items():
        core.set_global_option(k, v)

    # Setup the computation
    method = json_data["model"]["method"]
    core.set_global_option("BASIS", json_data["model"]["basis"])
    kwargs = {"return_wfn": True, "molecule": mol}

    # Handle special properties case
    if json_data["driver"] == "properties":
        if "properties" in json_data["model"]:
            kwargs["properties"] = [x.lower() for x in json_data["model"]["properties"]]

            extra = set(kwargs["properties"]) - can_do_properties_
            if len(extra):
                raise KeyError("Did not understand property key %s." % kwargs["properties"])
        else:
            kwargs["properties"] = list(can_do_properties_)


    # Actual driver run
    val, wfn = methods_dict_[json_data["driver"]](method, **kwargs)

    # Pull out a standard set of SCF properties
    psi_props = psi4.core.get_variables()
    json_data["psi4:qcvars"] = psi_props

    # Handle the return result
    if json_data["driver"] == "energy":
        json_data["return_result"] = val
    elif json_data["driver"] in ["gradient", "hessian"]:
        json_data["return_result"] = val.np.ravel().tolist()
    elif json_data["driver"] == "properties":
        ret = {}
        mtd = json_data["model"]["method"].upper()
        if "dipole" in kwargs["properties"]:
            ret["dipole"] = [psi_props[mtd + " DIPOLE " + x] for x in ["X", "Y", "Z"]]
        if "quadrupole" in kwargs["properties"]:
            ret["quadrupole"] = [psi_props[mtd + " QUADRUPOLE " + x] for x in ["XX", "XY", "XZ", "YY", "YZ", "ZZ"]]
        if "mulliken_charges" in kwargs["properties"]:
            ret["mulliken_charges"] = wfn.get_array("MULLIKEN_CHARGES").np.ravel().tolist()
        if "lowdin_charges" in kwargs["properties"]:
            ret["lowdin_charges"] = wfn.get_array("LOWDIN_CHARGES").np.ravel().tolist()
        if "wiberg_lowdin_indices" in kwargs["properties"]:
            ret["wiberg_lowdin_indices"] = wfn.get_array("WIBERG_LOWDIN_INDICES").np.ravel().tolist()
        if "mayer_indices" in kwargs["properties"]:
            ret["mayer_indices"] = wfn.get_array("MAYER_INDICES").np.ravel().tolist()

        json_data["return_result"] = ret
    else:
        raise KeyError("Did not understand Driver key %s." % json_data["driver"])


    props = {
        "calcinfo_nbasis": wfn.nso(),
        "calcinfo_nmo": wfn.nmo(),
        "calcinfo_nalpha": wfn.nalpha(),
        "calcinfo_nbeta": wfn.nbeta(),
        "calcinfo_natom": mol.geometry().shape[0],
        "scf_one_electron_energy": psi_props["ONE-ELECTRON ENERGY"],
        "scf_two_electron_energy": psi_props["TWO-ELECTRON ENERGY"],
        "nuclear_repulsion_energy": psi_props["NUCLEAR REPULSION ENERGY"],
        "scf_dipole_moment": [psi_props[x] for x in ["SCF DIPOLE X", "SCF DIPOLE Y", "SCF DIPOLE Z"]],
        "scf_iterations": int(psi_props["SCF ITERATIONS"]),
        "scf_total_energy": psi_props["SCF TOTAL ENERGY"],
        "return_energy": psi_props["CURRENT ENERGY"],
    }

    # Pull out optional SCF keywords
    other_scf = [("DFT VV10 ENERGY", "scf_vv10_energy"), ("DFT XC ENERGY", "scf_xc_energy"),
                 ("DISPERSION CORRECTION ENERGY", "scf_dispersion_correction_energy")]
    for pkey, skey in other_scf:
        if (pkey in psi_props) and (psi_props[pkey] != 0):
            props[skey] = psi_props[pkey]

    # Write out MP2 keywords
    if "MP2 CORRELATION ENERGY" in psi_props:
        props["mp2_same_spin_correlation_energy"] = psi_props["MP2 SAME-SPIN CORRELATION ENERGY"]
        props["mp2_opposite_spin_correlation_energy"] = psi_props["MP2 OPPOSITE-SPIN CORRELATION ENERGY"]
        props["mp2_singles_energy"] = 0.0
        props["mp2_doubles_energy"] = psi_props["MP2 CORRELATION ENERGY"]
        props["mp2_total_correlation_energy"] = psi_props["MP2 CORRELATION ENERGY"]
        props["mp2_total_energy"] = psi_props["MP2 TOTAL ENERGY"]

    json_data["properties"] = props
    json_data["success"] = True

    # Reset state
    _clean_psi_environ(clean)

    json_data["schema_name"] = "qc_schema_output"

    return json_data
Esempio n. 52
0
def run_json_qc_schema(json_data, clean):
    """
    An implementation of the QC JSON Schema (molssi-qc-schema.readthedocs.io/en/latest/index.html#) implementation in Psi4.


    Parameters
    ----------
    json_data : JSON
        Please see molssi-qc-schema.readthedocs.io/en/latest/spec_components.html for further details.

    Notes
    -----
    !Warning! This function is experimental and likely to change in the future.
    Please report any suggestions or uses of this function on github.com/MolSSI/QC_JSON_Schema.

    Examples
    --------

    """

    # Clean a few things
    _clean_psi_environ(clean)

    # This is currently a forced override
    if json_data["schema_name"] in ["qc_schema_input", "qcschema_input"]:
        json_data["schema_name"] = "qc_schema_input"  # humor qcel 0.1.3
    else:
        raise KeyError("Schema name of '{}' not understood".format(json_data["schema_name"]))

    if json_data["schema_version"] != 1:
        raise KeyError("Schema version of '{}' not understood".format(json_data["schema_version"]))

    if json_data.get("nthreads", False) is not False:
        psi4.set_num_threads(json_data["nthreads"], quiet=True)

    json_data["provenance"] = {"creator": "Psi4", "version": psi4.__version__, "routine": "psi4.json.run_json"}

    # Build molecule
    mol = core.Molecule.from_schema(json_data)

    # Update molecule geometry as we orient and fix_com
    json_data["molecule"]["geometry"] = mol.geometry().np.ravel().tolist()

    # Set options
    for k, v in json_data["keywords"].items():
        core.set_global_option(k, v)

    # Setup the computation
    method = json_data["model"]["method"]
    core.set_global_option("BASIS", json_data["model"]["basis"])
    kwargs = {"return_wfn": True, "molecule": mol}

    # Handle special properties case
    if json_data["driver"] == "properties":
        if "properties" in json_data["model"]:
            kwargs["properties"] = [x.lower() for x in json_data["model"]["properties"]]

            extra = set(kwargs["properties"]) - can_do_properties_
            if len(extra):
                raise KeyError("Did not understand property key %s." % kwargs["properties"])
        else:
            kwargs["properties"] = list(can_do_properties_)

    # Actual driver run
    val, wfn = methods_dict_[json_data["driver"]](method, **kwargs)

    # Pull out a standard set of Psi variables
    psi_props = psi4.core.scalar_variables()
    json_data["psi4:qcvars"] = psi_props

    # Still a bit of a mess at the moment add in local vars as well.
    for k, v in wfn.variables().items():
        if k not in json_data["psi4:qcvars"]:
            json_data["psi4:qcvars"][k] = _json_translation(v)

    # Handle the return result
    if json_data["driver"] == "energy":
        json_data["return_result"] = val
    elif json_data["driver"] in ["gradient", "hessian"]:
        json_data["return_result"] = val.np.ravel().tolist()
    elif json_data["driver"] == "properties":
        ret = {}
        mtd = json_data["model"]["method"].upper()

        # Dipole/quadrupole still special case
        if "dipole" in kwargs["properties"]:
            ret["dipole"] = [psi_props[mtd + " DIPOLE " + x] for x in ["X", "Y", "Z"]]
        if "quadrupole" in kwargs["properties"]:
            ret["quadrupole"] = [psi_props[mtd + " QUADRUPOLE " + x] for x in ["XX", "XY", "XZ", "YY", "YZ", "ZZ"]]
        ret.update(_convert_variables(wfn.variables(), context="properties"))

        json_data["return_result"] = ret
    else:
        raise KeyError("Did not understand Driver key %s." % json_data["driver"])

    props = {
        "calcinfo_nbasis": wfn.nso(),
        "calcinfo_nmo": wfn.nmo(),
        "calcinfo_nalpha": wfn.nalpha(),
        "calcinfo_nbeta": wfn.nbeta(),
        "calcinfo_natom": mol.geometry().shape[0],
    }
    props.update(_convert_variables(psi_props, context="generics"))
    props.update(_convert_variables(psi_props, context="scf"))

    # Write out MP2 keywords
    if "MP2 CORRELATION ENERGY" in psi_props:
        props.update(_convert_variables(psi_props, context="mp2"))

    json_data["properties"] = props
    json_data["success"] = True

    # Reset state
    _clean_psi_environ(clean)

    json_data["schema_name"] = "qcschema_output"

    return json_data
Esempio n. 53
0
def ip_fitting(name, omega_l=0.05, omega_r=2.5, omega_convergence=1.0e-3, maxiter=20, **kwargs):
    """Optimize DFT omega parameter for molecular system.

    Parameters
    ----------
    name : string or function
        DFT functional string name or function defining functional
        whose omega is to be optimized.
    omega_l : float, optional
        Minimum omega to be considered during fitting.
    omega_r : float, optional
        Maximum omega to be considered during fitting.
    molecule : :ref:`molecule <op_py_molecule>`, optional
        Target molecule (neutral) for which omega is to be tuned, if not last defined.
    omega_convergence : float, optional
        Threshold below which to consider omega converged. (formerly omega_tolerance)
    maxiter : int, optional
        Maximum number of iterations towards omega convergence.

    Returns
    -------
    float
        Optimal omega parameter.

    """
    optstash = p4util.OptionsState(
        ['SCF', 'REFERENCE'],
        ['SCF', 'GUESS'],
        ['SCF', 'DF_INTS_IO'],
        ['SCF', 'DFT_OMEGA'],
        ['DOCC'],
        ['SOCC'])

    kwargs = p4util.kwargs_lower(kwargs)

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

    if core.get_option('SCF', 'REFERENCE') != 'UKS':
        core.print_out("""  Requested procedure `ip_fitting` runs further calculations with UKS reference.\n""")
        core.set_local_option('SCF', 'REFERENCE', 'UKS')

    # Make sure the molecule the user provided is the active one, and neutral
    molecule = kwargs.pop('molecule', core.get_active_molecule())
    molecule.update_geometry()

    if molecule.molecular_charge() != 0:
        raise ValidationError("""IP Fitting requires neutral molecule to start.""")
    if molecule.schoenflies_symbol() != 'c1':
        core.print_out("""  Requested procedure `ip_fitting` does not make use of molecular symmetry: """
                       """further calculations in C1 point group.\n""")
    molecule = molecule.clone()
    molecule.reset_point_group('c1')
    molecule.update_geometry()

    charge0 = molecule.molecular_charge()
    mult0 = molecule.multiplicity()

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

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

    # Burn in to determine orbital eigenvalues
    if read:
        core.set_local_option("SCF", "GUESS", "READ")
        copy_file_to_scratch(read180, 'psi', 'ot', 180)
    core.set_local_option("SCF", "DF_INTS_IO", "SAVE")
    E, wfn = driver.energy('scf', dft_functional=name, return_wfn=True, molecule=molecule,
                           banner='IP Fitting SCF: Burn-in', **kwargs)
    core.set_local_option("SCF", "DF_INTS_IO", "LOAD")

    if not wfn.functional().is_x_lrc():
        raise ValidationError("""Not sensible to optimize omega for non-long-range-correction functional.""")

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

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

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

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

    # Right endpoint
    core.set_local_option('SCF', 'DFT_OMEGA', omega_r)

    # Neutral
    if read:
        core.set_local_option("SCF", "GUESS", "READ")
        p4util.copy_file_to_scratch(read180, 'psi', 'ot', 180)

    molecule.set_molecular_charge(charge0)
    molecule.set_multiplicity(mult0)
    E0r, wfn = driver.energy('scf', dft_functional=name, return_wfn=True, molecule=molecule,
                             banner='IP Fitting SCF: Neutral, Right Endpoint', **kwargs)
    eps_a = wfn.epsilon_a()
    eps_b = wfn.epsilon_b()
    if Nb == 0:
        E_HOMO = eps_a.np[int(Na - 1)]
    else:
        E_a = eps_a.np[int(Na - 1)]
        E_b = eps_b.np[int(Nb - 1)]
        E_HOMO = max(E_a, E_b)
    E_HOMOr = E_HOMO
    core.IO.change_file_namespace(180, "ot", "neutral")

    # Cation
    if read:
        core.set_local_option("SCF", "GUESS", "READ")
        p4util.copy_file_to_scratch(read180, 'psi', 'ot', 180)

    molecule.set_molecular_charge(charge1)
    molecule.set_multiplicity(mult1)
    E1r = driver.energy('scf', dft_functional=name, molecule=molecule,
                               banner='IP Fitting SCF: Cation, Right Endpoint', **kwargs)
    core.IO.change_file_namespace(180, "ot", "cation")

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

    if IPr > kIPr:
        raise ValidationError("""\n***IP Fitting Error: Right Omega limit should have kIP > IP: {} !> {}""".format(kIPr, IPr))

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

    # Use previous orbitals from here out
    core.set_local_option("SCF", "GUESS", "READ")

    # Left endpoint
    core.set_local_option('SCF', 'DFT_OMEGA', omega_l)

    # Neutral
    core.IO.change_file_namespace(180, "neutral", "ot")
    molecule.set_molecular_charge(charge0)
    molecule.set_multiplicity(mult0)
    core.set_global_option("DOCC", [Nb])
    core.set_global_option("SOCC", [Na - Nb])
    E0l, wfn = driver.energy('scf', dft_functional=name, return_wfn=True, molecule=molecule,
                             banner='IP Fitting SCF: Neutral, Left Endpoint', **kwargs)
    eps_a = wfn.epsilon_a()
    eps_b = wfn.epsilon_b()
    if Nb == 0:
        E_HOMO = eps_a.np[int(Na - 1)]
    else:
        E_a = eps_a.np[int(Na - 1)]
        E_b = eps_b.np[int(Nb - 1)]
        E_HOMO = max(E_a, E_b)
    E_HOMOl = E_HOMO
    core.IO.change_file_namespace(180, "ot", "neutral")

    # Cation
    core.IO.change_file_namespace(180, "cation", "ot")
    molecule.set_molecular_charge(charge1)
    molecule.set_multiplicity(mult1)
    core.set_global_option("DOCC", [Nb1])
    core.set_global_option("SOCC", [Na1 - Nb1])
    E1l = driver.energy('scf', dft_functional=name, molecule=molecule,
                        banner='IP Fitting SCF: Cation, Left Endpoint', **kwargs)
    core.IO.change_file_namespace(180, "ot", "cation")

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

    if IPl < kIPl:
        raise ValidationError("""\n***IP Fitting Error: Left Omega limit should have kIP < IP: {} !< {}""".format(kIPl, IPl))

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

    converged = False
    repeat_l = 0
    repeat_r = 0
    for step in range(maxiter):

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

        # Neutral
        core.IO.change_file_namespace(180, "neutral", "ot")
        molecule.set_molecular_charge(charge0)
        molecule.set_multiplicity(mult0)
        core.set_global_option("DOCC", [Nb])
        core.set_global_option("SOCC", [Na - Nb])
        E0, wfn = driver.energy('scf', dft_functional=name, return_wfn=True, molecule=molecule,
                                banner='IP Fitting SCF: Neutral, Omega = {:11.3E}'.format(omega), **kwargs)
        eps_a = wfn.epsilon_a()
        eps_b = wfn.epsilon_b()
        if Nb == 0:
            E_HOMO = eps_a.np[int(Na - 1)]
        else:
            E_a = eps_a.np[int(Na - 1)]
            E_b = eps_b.np[int(Nb - 1)]
            E_HOMO = max(E_a, E_b)
        core.IO.change_file_namespace(180, "ot", "neutral")

        # Cation
        core.IO.change_file_namespace(180, "cation", "ot")
        molecule.set_molecular_charge(charge1)
        molecule.set_multiplicity(mult1)
        core.set_global_option("DOCC", [Nb1])
        core.set_global_option("SOCC", [Na1 - Nb1])
        E1 = driver.energy('scf', dft_functional=name, molecule=molecule,
                           banner='IP Fitting SCF: Cation, Omega = {:11.3E}'.format(omega), **kwargs)
        core.IO.change_file_namespace(180, "ot", "cation")

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

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

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

        # Termination
        if abs(omega_l - omega_r) < omega_convergence:
            converged = True
            break

    core.IO.set_default_namespace("")
    core.print_out("""\n    ==> IP Fitting Results <==\n\n""")

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

    core.print_out("""     => Regula Falsi Iterations <=\n\n""")
    core.print_out("""    %3s %11s %14s %14s %14s %s\n""" % ('N','Omega','IP','kIP','Delta','Type'))
    for k in range(len(omegas)):
        core.print_out("""    %3d %11.3E %14.6E %14.6E %14.6E %s\n""" %
                       (k + 1, omegas[k], IPs[k], kIPs[k], IPs[k] - kIPs[k], types[k]))

    optstash.restore()
    if converged:
        core.print_out("""\n    IP Fitting Converged\n""")
        core.print_out("""    Final omega = %14.6E\n""" % ((omega_l + omega_r) / 2))
        core.print_out("""\n    "M,I. does the dying. Fleet just does the flying."\n""")
        core.print_out("""            -Starship Troopers\n""")

    else:
        raise ConvergenceError("""IP Fitting """, step + 1)

    return ((omega_l + omega_r) / 2)
Esempio n. 54
0
def run_sapt_dft(name, **kwargs):
    optstash = p4util.OptionsState(['SCF', 'SCF_TYPE'],
                                   ['SCF', 'REFERENCE'],
                                   ['SCF', 'DFT_FUNCTIONAL'],
                                   ['SCF', 'DFT_GRAC_SHIFT'],
                                   ['SCF', 'SAVE_JK'])

    core.tstart()
    # Alter default algorithm
    if not core.has_option_changed('SCF', 'SCF_TYPE'):
        core.set_local_option('SCF', 'SCF_TYPE', 'DF')

    core.prepare_options_for_module("SAPT")

    # Get the molecule of interest
    ref_wfn = kwargs.get('ref_wfn', None)
    if ref_wfn is None:
        sapt_dimer = kwargs.pop('molecule', core.get_active_molecule())
    else:
        core.print_out('Warning! SAPT argument "ref_wfn" is only able to use molecule information.')
        sapt_dimer = ref_wfn.molecule()

    sapt_dimer, monomerA, monomerB = proc_util.prepare_sapt_molecule(sapt_dimer, "dimer")

    # Grab overall settings
    mon_a_shift = core.get_option("SAPT", "SAPT_DFT_GRAC_SHIFT_A")
    mon_b_shift = core.get_option("SAPT", "SAPT_DFT_GRAC_SHIFT_B")
    do_delta_hf = core.get_option("SAPT", "SAPT_DFT_DO_DHF")
    sapt_dft_functional = core.get_option("SAPT", "SAPT_DFT_FUNCTIONAL")

    # Print out the title and some information
    core.print_out("\n")
    core.print_out("         ---------------------------------------------------------\n")
    core.print_out("         " + "SAPT(DFT) Procedure".center(58) + "\n")
    core.print_out("\n")
    core.print_out("         " + "by Daniel G. A. Smith".center(58) + "\n")
    core.print_out("         ---------------------------------------------------------\n")
    core.print_out("\n")

    core.print_out("  ==> Algorithm <==\n\n")
    core.print_out("   SAPT DFT Functional     %12s\n" % str(sapt_dft_functional))
    core.print_out("   Monomer A GRAC Shift    %12.6f\n" % mon_a_shift)
    core.print_out("   Monomer B GRAC Shift    %12.6f\n" % mon_b_shift)
    core.print_out("   Delta HF                %12s\n" % ("True" if do_delta_hf else "False"))
    core.print_out("   JK Algorithm            %12s\n" % core.get_option("SCF", "SCF_TYPE"))
    core.print_out("\n")
    core.print_out("   Required computations:\n")
    if (do_delta_hf):
        core.print_out("     HF  (Dimer)\n")
        core.print_out("     HF  (Monomer A)\n")
        core.print_out("     HF  (Monomer B)\n")
    core.print_out("     DFT (Monomer A)\n")
    core.print_out("     DFT (Monomer B)\n")
    core.print_out("\n")

    if (sapt_dft_functional != "HF") and ((mon_a_shift == 0.0) or (mon_b_shift == 0.0)):
        raise ValidationError('SAPT(DFT): must set both "SAPT_DFT_GRAC_SHIFT_A" and "B".')

    if (core.get_option('SCF', 'REFERENCE') != 'RHF'):
        raise ValidationError('SAPT(DFT) currently only supports restricted references.')


    core.IO.set_default_namespace('dimer')
    data = {}

    core.set_global_option("SAVE_JK", True)
    if (core.get_option('SCF', 'SCF_TYPE') == 'DF'):
        # core.set_global_option('DF_INTS_IO', 'LOAD')
        core.set_global_option('DF_INTS_IO', 'SAVE')

    # # Compute dimer wavefunction
    hf_cache = {}
    hf_wfn_dimer = None
    if do_delta_hf:
        if (core.get_option('SCF', 'SCF_TYPE') == 'DF'):
            core.set_global_option('DF_INTS_IO', 'SAVE')

        hf_data = {}
        hf_wfn_dimer = scf_helper(
            "SCF", molecule=sapt_dimer, banner="SAPT(DFT): delta HF Dimer", **kwargs)
        hf_data["HF DIMER"] = core.get_variable("CURRENT ENERGY")

        if (core.get_option('SCF', 'SCF_TYPE') == 'DF'):
            core.IO.change_file_namespace(97, 'dimer', 'monomerA')
        hf_wfn_A = scf_helper(
            "SCF", molecule=monomerA, banner="SAPT(DFT): delta HF Monomer A", **kwargs)
        hf_data["HF MONOMER A"] = core.get_variable("CURRENT ENERGY")

        if (core.get_option('SCF', 'SCF_TYPE') == 'DF'):
            core.IO.change_file_namespace(97, 'monomerA', 'monomerB')
        hf_wfn_B = scf_helper(
            "SCF", molecule=monomerB, banner="SAPT(DFT): delta HF Monomer B", **kwargs)
        hf_data["HF MONOMER B"] = core.get_variable("CURRENT ENERGY")

        # Move it back to monomer A
        if (core.get_option('SCF', 'SCF_TYPE') == 'DF'):
            core.IO.change_file_namespace(97, 'monomerB', 'dimer')

        core.print_out("\n")
        core.print_out("         ---------------------------------------------------------\n")
        core.print_out("         " + "SAPT(DFT): delta HF Segement".center(58) + "\n")
        core.print_out("\n")
        core.print_out("         " + "by Daniel G. A. Smith and Rob Parrish".center(58) + "\n")
        core.print_out("         ---------------------------------------------------------\n")
        core.print_out("\n")

        # Build cache and JK
        sapt_jk = hf_wfn_B.jk()

        hf_cache = sapt_jk_terms.build_sapt_jk_cache(hf_wfn_A, hf_wfn_B, sapt_jk, True)

        # Electostatics
        elst = sapt_jk_terms.electrostatics(hf_cache, True)
        hf_data.update(elst)

        # Exchange
        exch = sapt_jk_terms.exchange(hf_cache, sapt_jk, True)
        hf_data.update(exch)

        # Induction
        ind = sapt_jk_terms.induction(
            hf_cache,
            sapt_jk,
            True,
            maxiter=core.get_option("SAPT", "MAXITER"),
            conv=core.get_option("SAPT", "D_CONVERGENCE"))
        hf_data.update(ind)

        dhf_value = hf_data["HF DIMER"] - hf_data["HF MONOMER A"] - hf_data["HF MONOMER B"]

        core.print_out("\n")
        core.print_out(print_sapt_hf_summary(hf_data, "SAPT(HF)", delta_hf=dhf_value))

        data["Delta HF Correction"] = core.get_variable("SAPT(DFT) Delta HF")

    if hf_wfn_dimer is None:
        dimer_wfn = core.Wavefunction.build(sapt_dimer, core.get_global_option("BASIS"))
    else:
        dimer_wfn = hf_wfn_dimer

    # Set the primary functional
    core.set_global_option("DFT_FUNCTIONAL", core.get_option("SAPT", "SAPT_DFT_FUNCTIONAL"))
    core.set_local_option('SCF', 'REFERENCE', 'RKS')

    # Compute Monomer A wavefunction
    if (core.get_option('SCF', 'SCF_TYPE') == 'DF'):
        core.IO.change_file_namespace(97, 'dimer', 'monomerA')

    if mon_a_shift:
        core.set_global_option("DFT_GRAC_SHIFT", mon_a_shift)

    # Save the JK object
    core.IO.set_default_namespace('monomerA')
    wfn_A = scf_helper("SCF", molecule=monomerA, banner="SAPT(DFT): DFT Monomer A", **kwargs)
    data["DFT MONOMERA"] = core.get_variable("CURRENT ENERGY")

    core.set_global_option("DFT_GRAC_SHIFT", 0.0)

    # Compute Monomer B wavefunction
    if (core.get_option('SCF', 'SCF_TYPE') == 'DF'):
        core.IO.change_file_namespace(97, 'monomerA', 'monomerB')

    if mon_b_shift:
        core.set_global_option("DFT_GRAC_SHIFT", mon_b_shift)

    core.IO.set_default_namespace('monomerB')
    wfn_B = scf_helper("SCF", molecule=monomerB, banner="SAPT(DFT): DFT Monomer B", **kwargs)
    data["DFT MONOMERB"] = core.get_variable("CURRENT ENERGY")

    core.set_global_option("DFT_GRAC_SHIFT", 0.0)

    # Print out the title and some information
    core.print_out("\n")
    core.print_out("         ---------------------------------------------------------\n")
    core.print_out("         " + "SAPT(DFT): Intermolecular Interaction Segment".center(58) + "\n")
    core.print_out("\n")
    core.print_out("         " + "by Daniel G. A. Smith and Rob Parrish".center(58) + "\n")
    core.print_out("         ---------------------------------------------------------\n")
    core.print_out("\n")

    core.print_out("  ==> Algorithm <==\n\n")
    core.print_out("   SAPT DFT Functional     %12s\n" % str(sapt_dft_functional))
    core.print_out("   Monomer A GRAC Shift    %12.6f\n" % mon_a_shift)
    core.print_out("   Monomer B GRAC Shift    %12.6f\n" % mon_b_shift)
    core.print_out("   Delta HF                %12s\n" % ("True" if do_delta_hf else "False"))
    core.print_out("   JK Algorithm            %12s\n" % core.get_option("SCF", "SCF_TYPE"))

    # Build cache and JK
    sapt_jk = wfn_B.jk()

    cache = sapt_jk_terms.build_sapt_jk_cache(wfn_A, wfn_B, sapt_jk, True)

    # Electostatics
    elst = sapt_jk_terms.electrostatics(cache, True)
    data.update(elst)

    # Exchange
    exch = sapt_jk_terms.exchange(cache, sapt_jk, True)
    data.update(exch)

    # Induction
    ind = sapt_jk_terms.induction(
        cache,
        sapt_jk,
        True,
        maxiter=core.get_option("SAPT", "MAXITER"),
        conv=core.get_option("SAPT", "D_CONVERGENCE"))
    data.update(ind)

    # Dispersion
    primary_basis = wfn_A.basisset()
    core.print_out("\n")
    aux_basis = core.BasisSet.build(sapt_dimer, "DF_BASIS_MP2",
                                    core.get_option("DFMP2", "DF_BASIS_MP2"), "RIFIT",
                                    core.get_global_option('BASIS'))
    fdds_disp = sapt_mp2_terms.df_fdds_dispersion(primary_basis, aux_basis, cache)
    data.update(fdds_disp)

    if core.get_option("SAPT", "SAPT_DFT_MP2_DISP_ALG") == "FISAPT":
        mp2_disp = sapt_mp2_terms.df_mp2_fisapt_dispersion(wfn_A, primary_basis, aux_basis, cache, do_print=True)
    else:
        mp2_disp = sapt_mp2_terms.df_mp2_sapt_dispersion(
            dimer_wfn, wfn_A, wfn_B, primary_basis, aux_basis, cache, do_print=True)
    data.update(mp2_disp)

    # Print out final data
    core.print_out("\n")
    core.print_out(print_sapt_dft_summary(data, "SAPT(DFT)"))

    # Copy data back into globals
    for k, v in data.items():
        core.set_variable(k, v)

    core.tstop()

    return dimer_wfn
Esempio n. 55
0
def run_sapt_dft(name, **kwargs):
    optstash = p4util.OptionsState(['SCF_TYPE'], ['SCF', 'REFERENCE'], ['SCF', 'DFT_GRAC_SHIFT'],
                                   ['SCF', 'SAVE_JK'])

    core.tstart()
    # Alter default algorithm
    if not core.has_global_option_changed('SCF_TYPE'):
        core.set_global_option('SCF_TYPE', 'DF')

    core.prepare_options_for_module("SAPT")

    # Get the molecule of interest
    ref_wfn = kwargs.get('ref_wfn', None)
    if ref_wfn is None:
        sapt_dimer = kwargs.pop('molecule', core.get_active_molecule())
    else:
        core.print_out('Warning! SAPT argument "ref_wfn" is only able to use molecule information.')
        sapt_dimer = ref_wfn.molecule()

    sapt_dimer, monomerA, monomerB = proc_util.prepare_sapt_molecule(sapt_dimer, "dimer")

    # Grab overall settings
    mon_a_shift = core.get_option("SAPT", "SAPT_DFT_GRAC_SHIFT_A")
    mon_b_shift = core.get_option("SAPT", "SAPT_DFT_GRAC_SHIFT_B")
    do_delta_hf = core.get_option("SAPT", "SAPT_DFT_DO_DHF")
    sapt_dft_functional = core.get_option("SAPT", "SAPT_DFT_FUNCTIONAL")

    # Print out the title and some information
    core.print_out("\n")
    core.print_out("         ---------------------------------------------------------\n")
    core.print_out("         " + "SAPT(DFT) Procedure".center(58) + "\n")
    core.print_out("\n")
    core.print_out("         " + "by Daniel G. A. Smith".center(58) + "\n")
    core.print_out("         ---------------------------------------------------------\n")
    core.print_out("\n")

    core.print_out("  !!!  WARNING:  SAPT(DFT) capability is in beta. Please use with caution. !!!\n\n")

    core.print_out("  ==> Algorithm <==\n\n")
    core.print_out("   SAPT DFT Functional     %12s\n" % str(sapt_dft_functional))
    core.print_out("   Monomer A GRAC Shift    %12.6f\n" % mon_a_shift)
    core.print_out("   Monomer B GRAC Shift    %12.6f\n" % mon_b_shift)
    core.print_out("   Delta HF                %12s\n" % ("True" if do_delta_hf else "False"))
    core.print_out("   JK Algorithm            %12s\n" % core.get_global_option("SCF_TYPE"))
    core.print_out("\n")
    core.print_out("   Required computations:\n")
    if (do_delta_hf):
        core.print_out("     HF  (Dimer)\n")
        core.print_out("     HF  (Monomer A)\n")
        core.print_out("     HF  (Monomer B)\n")
    core.print_out("     DFT (Monomer A)\n")
    core.print_out("     DFT (Monomer B)\n")
    core.print_out("\n")

    if (sapt_dft_functional != "HF") and ((mon_a_shift == 0.0) or (mon_b_shift == 0.0)):
        raise ValidationError('SAPT(DFT): must set both "SAPT_DFT_GRAC_SHIFT_A" and "B".')

    if (core.get_option('SCF', 'REFERENCE') != 'RHF'):
        raise ValidationError('SAPT(DFT) currently only supports restricted references.')

    core.IO.set_default_namespace('dimer')
    data = {}

    if (core.get_global_option('SCF_TYPE') == 'DF'):
        # core.set_global_option('DF_INTS_IO', 'LOAD')
        core.set_global_option('DF_INTS_IO', 'SAVE')

    # # Compute dimer wavefunction
    hf_wfn_dimer = None
    if do_delta_hf:
        if (core.get_global_option('SCF_TYPE') == 'DF'):
            core.set_global_option('DF_INTS_IO', 'SAVE')

        hf_data = {}
        hf_wfn_dimer = scf_helper("SCF", molecule=sapt_dimer, banner="SAPT(DFT): delta HF Dimer", **kwargs)
        hf_data["HF DIMER"] = core.get_variable("CURRENT ENERGY")

        if (core.get_global_option('SCF_TYPE') == 'DF'):
            core.IO.change_file_namespace(97, 'dimer', 'monomerA')

        hf_wfn_A = scf_helper("SCF", molecule=monomerA, banner="SAPT(DFT): delta HF Monomer A", **kwargs)
        hf_data["HF MONOMER A"] = core.get_variable("CURRENT ENERGY")

        core.set_global_option("SAVE_JK", True)
        if (core.get_global_option('SCF_TYPE') == 'DF'):
            core.IO.change_file_namespace(97, 'monomerA', 'monomerB')

        hf_wfn_B = scf_helper("SCF", molecule=monomerB, banner="SAPT(DFT): delta HF Monomer B", **kwargs)
        hf_data["HF MONOMER B"] = core.get_variable("CURRENT ENERGY")
        core.set_global_option("SAVE_JK", False)

        # Grab JK object and set to A (so we do not save many JK objects)
        sapt_jk = hf_wfn_B.jk()
        hf_wfn_A.set_jk(sapt_jk)
        core.set_global_option("SAVE_JK", False)

        # Move it back to monomer A
        if (core.get_global_option('SCF_TYPE') == 'DF'):
            core.IO.change_file_namespace(97, 'monomerB', 'dimer')

        core.print_out("\n")
        core.print_out("         ---------------------------------------------------------\n")
        core.print_out("         " + "SAPT(DFT): delta HF Segement".center(58) + "\n")
        core.print_out("\n")
        core.print_out("         " + "by Daniel G. A. Smith and Rob Parrish".center(58) + "\n")
        core.print_out("         ---------------------------------------------------------\n")
        core.print_out("\n")

        # Build cache
        hf_cache = sapt_jk_terms.build_sapt_jk_cache(hf_wfn_A, hf_wfn_B, sapt_jk, True)

        # Electostatics
        elst = sapt_jk_terms.electrostatics(hf_cache, True)
        hf_data.update(elst)

        # Exchange
        exch = sapt_jk_terms.exchange(hf_cache, sapt_jk, True)
        hf_data.update(exch)

        # Induction
        ind = sapt_jk_terms.induction(
            hf_cache,
            sapt_jk,
            True,
            maxiter=core.get_option("SAPT", "MAXITER"),
            conv=core.get_option("SAPT", "D_CONVERGENCE"),
            Sinf=core.get_option("SAPT", "DO_IND_EXCH_SINF"))
        hf_data.update(ind)

        dhf_value = hf_data["HF DIMER"] - hf_data["HF MONOMER A"] - hf_data["HF MONOMER B"]

        core.print_out("\n")
        core.print_out(print_sapt_hf_summary(hf_data, "SAPT(HF)", delta_hf=dhf_value))

        data["Delta HF Correction"] = core.get_variable("SAPT(DFT) Delta HF")
        sapt_jk.finalize()

        del hf_wfn_A, hf_wfn_B, sapt_jk

    if hf_wfn_dimer is None:
        dimer_wfn = core.Wavefunction.build(sapt_dimer, core.get_global_option("BASIS"))
    else:
        dimer_wfn = hf_wfn_dimer

    # Set the primary functional
    core.set_local_option('SCF', 'REFERENCE', 'RKS')

    # Compute Monomer A wavefunction
    if (core.get_global_option('SCF_TYPE') == 'DF'):
        core.IO.change_file_namespace(97, 'dimer', 'monomerA')

    if mon_a_shift:
        core.set_global_option("DFT_GRAC_SHIFT", mon_a_shift)

    # Save the JK object
    core.IO.set_default_namespace('monomerA')
    wfn_A = scf_helper(
        sapt_dft_functional, post_scf=False, molecule=monomerA, banner="SAPT(DFT): DFT Monomer A", **kwargs)
    data["DFT MONOMERA"] = core.get_variable("CURRENT ENERGY")

    core.set_global_option("DFT_GRAC_SHIFT", 0.0)

    # Compute Monomer B wavefunction
    if (core.get_global_option('SCF_TYPE') == 'DF'):
        core.IO.change_file_namespace(97, 'monomerA', 'monomerB')

    if mon_b_shift:
        core.set_global_option("DFT_GRAC_SHIFT", mon_b_shift)

    core.set_global_option("SAVE_JK", True)
    core.IO.set_default_namespace('monomerB')
    wfn_B = scf_helper(
        sapt_dft_functional, post_scf=False, molecule=monomerB, banner="SAPT(DFT): DFT Monomer B", **kwargs)
    data["DFT MONOMERB"] = core.get_variable("CURRENT ENERGY")

    # Save JK object
    sapt_jk = wfn_B.jk()
    wfn_A.set_jk(sapt_jk)
    core.set_global_option("SAVE_JK", False)

    core.set_global_option("DFT_GRAC_SHIFT", 0.0)

    # Write out header
    scf_alg = core.get_global_option("SCF_TYPE")
    sapt_dft_header(sapt_dft_functional, mon_a_shift, mon_b_shift, bool(do_delta_hf), scf_alg)

    # Call SAPT(DFT)
    sapt_jk = wfn_B.jk()
    sapt_dft(dimer_wfn, wfn_A, wfn_B, sapt_jk=sapt_jk, data=data, print_header=False)

    # Copy data back into globals
    for k, v in data.items():
        core.set_variable(k, v)

    core.tstop()

    return dimer_wfn
Esempio n. 56
0
def run_gaussian_2(name, **kwargs):

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

    core.set_variable("CURRENT ENERGY",eg2_0k)

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

    core.clean()

    optstash.restore()

    # return 0K g2 results
    return eg2_0k