예제 #1
0
def run_cis(name, **kwargs):
    r"""Function encoding sequence of PSI module and plugin calls so that
    cis can be called via :py:func:`~driver.energy`. For post-scf plugins.

    >>> energy('cis')

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

    # Your plugin's psi4 run sequence goes here
    psi4.core.set_local_option('MYPLUGIN', 'PRINT', 1)

    # Compute a SCF reference, a wavefunction is return which holds the molecule used, orbitals
    # Fock matrices, and more
    print('Attention! This SCF may be density-fitted.')
    ref_wfn = kwargs.get('ref_wfn', None)
    if ref_wfn is None:
        ref_wfn = psi4.driver.scf_helper(name, **kwargs)

    # Ensure IWL files have been written when not using DF/CD
    proc_util.check_iwl_file_from_scf_type(
        psi4.core.get_option('SCF', 'SCF_TYPE'), ref_wfn)

    # Call the Psi4 plugin
    # Please note that setting the reference wavefunction in this way is ONLY for plugins
    cis_wfn = psi4.core.plugin('cis.so', ref_wfn)

    return cis_wfn
예제 #2
0
def run_mydft(name, **kwargs):
    r"""Function encoding sequence of PSI module and plugin calls so that
    mydft can be called via :py:func:`~driver.energy`. For post-scf plugins.

    >>> energy('mydft')

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

    # Your plugin's psi4 run sequence goes here

    scf_wfn = kwargs.get('ref_wfn', None)
    if scf_wfn is None:
        func = psi4.core.get_option('MYDFT', 'FUNCTIONAL')
        scf_molecule = kwargs.get('molecule', psi4.core.get_active_molecule())
        base_wfn = psi4.core.Wavefunction.build(
            scf_molecule, psi4.core.get_global_option('BASIS'))
        scf_wfn = proc.scf_wavefunction_factory(
            func, base_wfn, psi4.core.get_option('SCF', 'REFERENCE'))

    # Ensure IWL files have been written when not using DF/CD
    proc_util.check_iwl_file_from_scf_type(
        psi4.core.get_option('SCF', 'SCF_TYPE'), scf_wfn)

    # Call the Psi4 plugin
    # Please note that setting the reference wavefunction in this way is ONLY for plugins
    mydft_wfn = psi4.core.plugin('mydft.so', scf_wfn)

    return mydft_wfn
예제 #3
0
def run_cct3(name, **kwargs):
    r"""Function encoding sequence of PSI module and plugin calls so that
    cct3 can be called via :py:func:`~driver.energy`. For post-scf plugins.

    >>> energy('cct3')

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

    optstash = p4util.OptionsState(['CCT3', 'CALC_TYPE'])

    # Your plugin's psi4 run sequence goes here
    if lowername == "cct3":
        pass
    elif lowername == "ccsd":
        psi4.core.set_local_option("CCT3", "CALC_TYPE", "CCSD")
    elif lowername == "cr-cc(2,3)":
        psi4.core.set_local_option("CCT3", "CALC_TYPE", "CR-CC")
    elif lowername == "ccsd_lct":  # CCSDt
        psi4.core.set_local_option("CCT3", "CALC_TYPE", "CCSD3A")
    elif lowername == "cc(t;3)":
        psi4.core.set_local_option("CCT3", "CALC_TYPE", "CCT3")

    # Compute a SCF reference, a wavefunction is return which holds the molecule used, orbitals
    # Fock matrices, and more
    ref_wfn = kwargs.get('ref_wfn', None)
    if ref_wfn is None:
        ref_wfn = psi4.driver.scf_helper(name, **kwargs)

    # Ensure IWL files have been written when not using DF/CD
    proc_util.check_iwl_file_from_scf_type(
        psi4.core.get_option('SCF', 'SCF_TYPE'), ref_wfn)

    # Call the Psi4 plugin
    # Please note that setting the reference wavefunction in this way is ONLY for plugins
    cct3_wfn = psi4.core.plugin('cct3.so', ref_wfn)

    try:
        cct3_wfn.set_module("cct3")
    except AttributeError:
        pass  # pre-July 2020 psi4

    # Shove variables into global space
    for k, v in cct3_wfn.variables().items():
        psi4.core.set_variable(k, v)

    optstash.restore()

    return cct3_wfn
예제 #4
0
def run_mcpdft(name, **kwargs):
    r"""Function encoding sequence of PSI module and plugin calls so that
    mcpdft can be called via :py:func:`~driver.energy`. For post-scf plugins.

    >>> energy('mcpdft')

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

    psi4.core.set_local_option('SCF', 'DF_INTS_IO', 'SAVE')

    v2rdm_wfn = kwargs.get('ref_wfn', None)
    if v2rdm_wfn is None:
        raise ValidationError(
            """Error: %s requires a reference wave function (v2rdm-casscf)."""
            % name)

    psi4.core.set_variable("V2RDM TOTAL ENERGY", v2rdm_wfn.energy())

    if ((psi4.core.get_option('MCPDFT', 'MCPDFT_METHOD') == '1DH_MCPDFT') or
        (psi4.core.get_option('MCPDFT', 'MCPDFT_METHOD') == 'LS1DH_MCPDFT')):
        proc.run_dfmp2('mp2', **kwargs)

    if ('WBLYP' == psi4.core.get_option('MCPDFT', 'MCPDFT_FUNCTIONAL')):
        func = 'BLYP'
    else:
        func = psi4.core.get_option('MCPDFT', 'MCPDFT_FUNCTIONAL')
    ref_molecule = kwargs.get('molecule', psi4.core.get_active_molecule())
    base_wfn = psi4.core.Wavefunction.build(
        ref_molecule, psi4.core.get_global_option('BASIS'))
    ref_wfn = proc.scf_wavefunction_factory(
        func, base_wfn, psi4.core.get_option('MCPDFT', 'REFERENCE'))

    # push v2rdm-casscf orbitals onto reference
    for irrep in range(0, v2rdm_wfn.Ca().nirrep()):
        ref_wfn.Ca().nph[irrep][:, :] = v2rdm_wfn.Ca().nph[irrep][:, :]
        ref_wfn.Cb().nph[irrep][:, :] = v2rdm_wfn.Cb().nph[irrep][:, :]

    # push v2rdm-casscf energies onto reference
    for irrep in range(0, v2rdm_wfn.epsilon_a().nirrep()):
        ref_wfn.epsilon_a().nph[irrep][:] = v2rdm_wfn.epsilon_a().nph[irrep][:]
        ref_wfn.epsilon_b().nph[irrep][:] = v2rdm_wfn.epsilon_b().nph[irrep][:]

    # Call the Psi4 plugin
    # Please note that setting the reference wavefunction in this way is ONLY for plugins
    mcpdft_wfn = psi4.core.plugin('mcpdft.so', ref_wfn)

    return mcpdft_wfn
예제 #5
0
def run_scf_plug(name, **kwargs):
    r"""Function encoding sequence of PSI module and plugin calls so that
    scf_plug can be called via :py:func:`~driver.energy`. For post-scf plugins.

    >>> energy('scf_plug')

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

    # Your plugin's psi4 run sequence goes here
    psi4.core.set_local_option('MYPLUGIN', 'PRINT', 1)

    # Compute a SCF reference, a wavefunction is return which holds the molecule used, orbitals
    # Fock matrices, and more
    print('Attention! This SCF may be density-fitted.')
    ref_wfn = kwargs.get('ref_wfn', None)
    if ref_wfn is None:
        ref_wfn = psi4.driver.scf_helper(name, **kwargs)


    # Ensure IWL files have been written when not using DF/CD
    # proc_util.check_iwl_file_from_scf_type(psi4.core.get_option('SCF', 'SCF_TYPE'), ref_wfn)

    # analytic derivatives do not work with scf_type df/cd
    scf_type = psi4.core.get_option('SCF', 'SCF_TYPE')
    if ( scf_type == 'CD' or scf_type == 'DF' ):
        raise ValidationError("""Error: analytic gradients not implemented for scf_type %s.""" % scf_type)

    # Call the Psi4 plugin
    # Please note that setting the reference wavefunction in this way is ONLY for plugins

    scf_plug_wfn = psi4.core.plugin('scf_plug.so', ref_wfn)
    print(scf_plug_wfn)
    print(ref_wfn)

    derivobj = psi4.core.Deriv(scf_plug_wfn)
    derivobj.set_deriv_density_backtransformed(True)
    derivobj.set_ignore_reference(True)
    grad = derivobj.compute()


   

   

    scf_plug_wfn.set_gradient(grad)

    return scf_plug_wfn
예제 #6
0
파일: pymodule.py 프로젝트: jH0ward/dlmg2OR
def run_rhf_dlmg2b(name, **kwargs):
    r"""Function encoding sequence of PSI module and plugin calls so that
    rhf_dlmg2b can be called via :py:func:`~driver.energy`. For post-scf plugins.

    >>> energy('rhf_dlmg2b')

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

    # Your plugin's psi4 run sequence goes here
    psi4.core.set_local_option('MYPLUGIN', 'PRINT', 1)

    # Compute a SCF reference, a wavefunction is return which holds the molecule used, orbitals
    # Fock matrices, and more
    print('Attention! This SCF may be density-fitted.')
    ref_wfn = kwargs.get('ref_wfn', None)
    if ref_wfn is None:
        ref_wfn = psi4.driver.scf_helper(name, **kwargs)

    # Ensure IWL files have been written when not using DF/CD
    proc_util.check_iwl_file_from_scf_type(
        psi4.core.get_option('SCF', 'SCF_TYPE'), ref_wfn)

    # Call the Psi4 plugin

    psi4.core.set_global_option('GUESS', 'READ')
    optstash = p4util.OptionsState(['E_CONVERGENCE'])
    psi4.core.set_global_option('E_CONVERGENCE', 1492.)

    # Please note that setting the reference wavefunction in this way is ONLY for plugins
    vac_wfn = psi4.core.plugin('rhf_dlmg2b.so', ref_wfn)
    # Vacuum wfn has been returned. Start solvent calc
    psi4.core.set_local_option('RHF_DLMG2B', 'eps',
                               psi4.core.get_option('RHF_DLMG2B', 'eps_sol'))
    # If eps_sol set to zero, return vacuum wfn
    test_eps = psi4.core.get_option('RHF_DLMG2B', 'eps_sol')
    optstash.restore()
    if (test_eps == 0.0):
        print("Vac_wfn being returned now")
        return vac_wfn

    # Do solvent scf
    sol_wfn = psi4.core.plugin('rhf_dlmg2b.so', vac_wfn)
    kwargs['ref_wfn'] = sol_wfn

    return sol_wfn
예제 #7
0
def run_v2rdm_casscf_gradient(name, **kwargs):
    r"""Function encoding sequence of PSI module and plugin calls so that
    v2rdm_casscf can be called via :py:func:`~driver.energy`. For post-scf plugins.

    >>> gradient('v2rdm_casscf')

    """

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

    optstash = p4util.OptionsState(
        ['GLOBALS', 'DERTYPE'], ['V2RDM_CASSCF', 'OPTIMIZE_ORBITALS'],
        ['V2RDM_CASSCF', 'SEMICANONICALIZE_ORBITALS'],
        ['V2RDM_CASSCF', 'ORBOPT_ACTIVE_ACTIVE_ROTATIONS'],
        ['V2RDM_CASSCF', 'RESTART_FROM_CHECKPOINT_FILE'],
        ['V2RDM_CASSCF', 'WRITE_CHECKPOINT_FILE'])

    psi4.core.set_global_option('DERTYPE', 'FIRST')
    psi4.core.set_local_option("V2RDM_CASSCF", "OPTIMIZE_ORBITALS", True)
    psi4.core.set_local_option("V2RDM_CASSCF",
                               "ORBOPT_ACTIVE_ACTIVE_ROTATIONS", True)
    psi4.core.set_local_option("V2RDM_CASSCF", "SEMICANONICALIZE_ORBITALS",
                               False)
    psi4.core.set_local_option("V2RDM_CASSCF", "RESTART_FROM_CHECKPOINT_FILE",
                               "DUMMY")
    psi4.core.set_local_option("V2RDM_CASSCF", "WRITE_CHECKPOINT_FILE", True)

    # analytic derivatives do not work with scf_type df/cd
    scf_type = psi4.core.get_option('SCF', 'SCF_TYPE')
    if (scf_type == 'CD' or scf_type == 'DF'):
        raise ValidationError(
            """Error: analytic v2RDM-CASSCF gradients not implemented for scf_type %s."""
            % scf_type)

    v2rdm_wfn = run_v2rdm_casscf(name, **kwargs)

    derivobj = psi4.core.Deriv(v2rdm_wfn)
    derivobj.set_deriv_density_backtransformed(True)
    derivobj.set_ignore_reference(True)
    grad = derivobj.compute()

    v2rdm_wfn.set_gradient(grad)

    optstash.restore()

    return v2rdm_wfn
예제 #8
0
def run_mean_field_cqed(name, **kwargs):
    r"""Function encoding sequence of PSI module and plugin calls so that
    mean_field_cqed can be called via :py:func:`~driver.energy`. For post-scf plugins.

    >>> energy('mean_field_cqed')

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

    # Your plugin's psi4 run sequence goes here
    ref_wfn = kwargs.get('ref_wfn', None)
    if ref_wfn is None:
        ref_wfn = psi4.driver.scf_helper(name, **kwargs)

    mean_field_cqed_wfn = psi4.core.plugin('mean_field_cqed.so', ref_wfn)
    return mean_field_cqed_wfn
예제 #9
0
def run_fcidump(name, **kwargs):
    r"""Function encoding sequence of PSI module and plugin calls so that
    fcidump can be called via :py:func:`~driver.energy`.

    >>> energy('fcidump')

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

    # Your plugin's psi4 run sequence goes here
    ref_wfn = kwargs.get('ref_wfn', None)
    if ref_wfn is None:
        ref_wfn = psi4.driver.scf_helper(name, **kwargs)

    proc_util.check_iwl_file_from_scf_type(psi4.core.get_option('SCF', 'SCF_TYPE'), ref_wfn)
    test_wfn = psi4.core.plugin('fcidump.so', ref_wfn)

    return test_wfn
예제 #10
0
def run_v2rdm_casscf(name, **kwargs):
    r"""Function encoding sequence of PSI module and plugin calls so that
    v2rdm_casscf can be called via :py:func:`~driver.energy`. For post-scf plugins.

    >>> energy('v2rdm_casscf')

    """

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

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

    psi4.core.set_local_option('SCF', 'DF_INTS_IO', 'SAVE')

    # Your plugin's psi4 run sequence goes here
    ref_wfn = kwargs.get('ref_wfn', None)
    if ref_wfn is None:
        ref_wfn = psi4.driver.scf_helper(name, **kwargs)

    # if restarting from a checkpoint file, this file
    # needs to be in scratch with the correct name
    filename = psi4.core.get_option("V2RDM_CASSCF",
                                    "RESTART_FROM_CHECKPOINT_FILE")

    # todo PSIF_V2RDM_CHECKPOINT should be definied in psifiles.h
    if (filename != "" and psi4.core.get_global_option('DERTYPE') != 'FIRST'):
        molname = psi4.wavefunction().molecule().name()
        p4util.copy_file_to_scratch(filename, 'psi', molname, 269, False)

    # Ensure IWL files have been written when not using DF/CD
    scf_type = psi4.core.get_option('SCF', 'SCF_TYPE')
    if (scf_type == 'PK' or scf_type == 'DIRECT'):
        proc_util.check_iwl_file_from_scf_type(
            psi4.core.get_option('SCF', 'SCF_TYPE'), ref_wfn)

    returnvalue = psi4.core.plugin('v2rdm_casscf.so', ref_wfn)

    optstash.restore()

    return returnvalue
예제 #11
0
파일: pymodule.py 프로젝트: nhv17/new_erpa
def run_erpa(name, **kwargs):
    r"""Function encoding sequence of PSI module and plugin calls so that
    erpa can be called via :py:func:`~driver.energy`. For post-scf plugins.

    >>> energy('erpa')

    """

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

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

    #    psi4.core.set_local_option('SCF', 'DF_INTS_IO', 'SAVE')
    erpa_corr_global = psi4.core.get_option('ERPA', 'ERPA_CORRELATION')
    erpa_corr_local = psi4.core.get_global_option('ERPA_CORRELATION')
    if not erpa_corr_global and not erpa_corr_local:
        nat_orbs_global = psi4.core.get_option('V2RDM_CASSCF', 'NAT_ORBS')
        nat_orbs_local = psi4.core.get_global_option('NAT_ORBS')
        if not nat_orbs_global and not nat_orbs_local:
            raise psi4.ValidationError(
                """ERPA requires that the V2RDM_CASSCF option "nat_orbs" be set to true."""
            )

    # Your plugin's psi4 run sequence goes here
    ref_wfn = kwargs.get('ref_wfn', None)
    if ref_wfn is None:
        ref_wfn = psi4.driver.scf_helper(name, **kwargs)

    # Ensure IWL files have been written when not using DF/CD
    scf_type = psi4.core.get_option('SCF', 'SCF_TYPE')
    if (scf_type == 'PK' or scf_type == 'DIRECT'):
        proc_util.check_iwl_file_from_scf_type(
            psi4.core.get_option('SCF', 'SCF_TYPE'), ref_wfn)

    returnvalue = psi4.core.plugin('erpa.so', ref_wfn)

    #   optstash.restore()

    return returnvalue
예제 #12
0
파일: pymodule.py 프로젝트: lothian/ugacc
def run_ugacc(name, **kwargs):
    r"""Function encoding sequence of PSI module and plugin calls so that
    ugacc can be called via :py:func:`~driver.energy`. For post-scf plugins.

    >>> energy('ugacc')

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

    # Your plugin's psi4 run sequence goes here
    if ('wfn' in kwargs):
        if (kwargs['wfn'] == 'ccsd'):
            psi4.core.set_global_option('WFN', 'CCSD')
        elif (kwargs['wfn'] == 'ccsd(t)'):
            psi4.core.set_global_option('WFN', 'CCSD_T')
    scf_wfn = kwargs.get('ref_wfn', None)
    if scf_wfn is None:
        scf_wfn = psi4.driver.scf_helper(name, **kwargs)
    proc_util.check_iwl_file_from_scf_type(psi4.core.get_option('SCF', 'SCF_TYPE'), scf_wfn)

    return psi4.core.plugin('ugacc.so', scf_wfn)
예제 #13
0
def run_libresponse_psi4(name, **kwargs):
    r"""Function encoding sequence of PSI module and plugin calls so that
    libresponse_psi4 can be called via :py:func:`~driver.energy`. For post-scf
    plugins.

    >>> energy('libresponse_psi4')
    """

    kwargs = p4util.kwargs_lower(kwargs)

    # Your plugin's psi4 run sequence goes here
    psi4.core.set_local_option("MYPLUGIN", "PRINT", 1)

    # The response density is asymmetric; need to build generalized
    # J/K.
    proc_util.check_non_symmetric_jk_density("libresponse")

    # Disable symmetry, even for passed-in wavefunctions.
    molecule = kwargs.get("molecule", None)
    if molecule is None:
        molecule = psi4.core.get_active_molecule()
    molecule = disable_symmetry(molecule)
    kwargs["molecule"] = molecule

    # Compute a SCF reference, a wavefunction is return which holds the
    # molecule used, orbitals Fock matrices, and more
    ref_wfn = kwargs.get("ref_wfn", None)
    if ref_wfn is None:
        ref_wfn = psi4.driver.scf_helper(name, **kwargs)

    # Ensure IWL files have been written when not using DF/CD
    proc_util.check_iwl_file_from_scf_type(
        psi4.core.get_option("SCF", "SCF_TYPE"), ref_wfn)

    # Call the Psi4 plugin
    # Please note that setting the reference wavefunction in this way is ONLY for plugins
    libresponse_psi4_wfn = psi4.core.plugin("libresponse_psi4.so", ref_wfn)

    return libresponse_psi4_wfn
예제 #14
0
def run_ccreorg(name, **kwargs):
    """Function encoding sequence of PSI module and plugin calls so that
    ccreorg can be called via :py:func:`~driver.energy`. For post-scf plugins.

    >>> energy('ccreorg')

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

    # Your plugin's psi4 run sequence goes here
    if ('wfn' in kwargs):
        if (kwargs['wfn'] == 'ccsd'):
            psi4.core.set_global_option('WFN', 'CCSD')
        elif (kwargs['wfn'] == 'ccsd(t)'):
            psi4.core.set_global_option('WFN', 'CCSD_T')
    scf_wfn = kwargs.get('ref_wfn', None)
    if scf_wfn is None:
        scf_wfn = psi4.driver.scf_helper(name, **kwargs)
    proc_util.check_iwl_file_from_scf_type(
        psi4.core.get_option('SCF', 'SCF_TYPE'), scf_wfn)

    return psi4.core.plugin('ccreorg.so', scf_wfn)
예제 #15
0
def run_forte(name, **kwargs):
    r"""Function encoding sequence of PSI module and plugin calls so that
    forte can be called via :py:func:`~driver.energy`. For post-scf plugins.

    >>> energy('forte')

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

    # Your plugin's psi4 run sequence goes here
    psi4.core.set_local_option('MYPLUGIN', 'PRINT', 1)

    # Compute a SCF reference, a wavefunction is return which holds the molecule used, orbitals
    # Fock matrices, and more
    ref_wfn = kwargs.get('ref_wfn', None)
    if ref_wfn is None:
        ref_wfn = psi4.driver.scf_helper(name, **kwargs)

    if ('DF' in psi4.core.get_option('FORTE', 'INT_TYPE')):
        aux_basis = psi4.core.BasisSet.build(
            ref_wfn.molecule(), 'DF_BASIS_MP2',
            psi4.core.get_global_option('DF_BASIS_MP2'), 'RIFIT',
            psi4.core.get_global_option('BASIS'))
        ref_wfn.set_basisset('DF_BASIS_MP2', aux_basis)

    if (psi4.core.get_option('FORTE', 'MINAO_BASIS')):
        minao_basis = psi4.core.BasisSet.build(
            ref_wfn.molecule(), 'MINAO_BASIS',
            psi4.core.get_option('FORTE', 'MINAO_BASIS'))
        ref_wfn.set_basisset('MINAO_BASIS', minao_basis)

    # Call the Psi4 plugin
    # Please note that setting the reference wavefunction in this way is ONLY for plugins
    forte_wfn = psi4.core.plugin('forte.so', ref_wfn)

    return forte_wfn
예제 #16
0
파일: pymodule.py 프로젝트: loriab/gpu_dfcc
def run_gpu_dfcc(name, **kwargs):
    """Function encoding sequence of PSI module calls for
    a GPU-accelerated DF-CCSD(T) computation.

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

    """

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

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

    psi4.core.set_local_option('GPU_DFCC', 'DFCC', True)
    psi4.core.set_local_option('GPU_DFCC', 'CC_TYPE', 'DF')

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

    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)

    # triples?
    if (lowername == 'gpu-df-ccsd'):
        psi4.core.set_local_option('GPU_DFCC', 'COMPUTE_TRIPLES', False)
        set_cholesky_from('CC_TYPE')

    if (lowername == 'gpu-df-ccsd(t)'):
        psi4.core.set_local_option('GPU_DFCC', 'COMPUTE_TRIPLES', True)
        set_cholesky_from('CC_TYPE')

    if psi4.core.get_global_option('SCF_TYPE') not in ['CD', 'DISK_DF']:
        raise ValidationError("""Invalid scf_type for DFCC.""")

    # save DF or CD ints generated by SCF for use in CC
    psi4.core.set_local_option('SCF', 'DF_INTS_IO', 'SAVE')

    # psi4 run sequence
    ref_wfn = kwargs.get('ref_wfn', None)
    if ref_wfn is None:
        ref_wfn = psi4.driver.scf_helper(name, use_c1=True,
                                         **kwargs)  # C1 certified
    else:
        if ref_wfn.molecule().schoenflies_symbol() != 'c1':
            raise ValidationError(
                """  GPU-DFCC does not make use of molecular symmetry: """
                """  reference wavefunction must be C1.\n""")

    scf_aux_basis = psi4.core.BasisSet.build(
        ref_wfn.molecule(),
        "DF_BASIS_SCF",
        psi4.core.get_option("SCF", "DF_BASIS_SCF"),
        "JKFIT",
        psi4.core.get_global_option('BASIS'),
        puream=ref_wfn.basisset().has_puream())
    ref_wfn.set_basisset("DF_BASIS_SCF", scf_aux_basis)

    aux_basis = psi4.core.BasisSet.build(
        ref_wfn.molecule(), "DF_BASIS_CC",
        psi4.core.get_global_option("DF_BASIS_CC"), "RIFIT",
        psi4.core.get_global_option("BASIS"))
    ref_wfn.set_basisset("DF_BASIS_CC", aux_basis)

    returnvalue = psi4.core.plugin('gpu_dfcc.so', ref_wfn)

    # restore options
    optstash.restore()

    return returnvalue
예제 #17
0
def run_v2rdm_casscf(name, **kwargs):
    r"""Function encoding sequence of PSI module and plugin calls so that
    v2rdm_casscf can be called via :py:func:`~driver.energy`. For post-scf plugins.

    >>> energy('v2rdm_casscf')

    """

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

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

    psi4.core.set_local_option('SCF', 'DF_INTS_IO', 'SAVE')

    # Your plugin's psi4 run sequence goes here
    ref_wfn = kwargs.get('ref_wfn', None)
    if ref_wfn is None:
        ref_wfn = psi4.driver.scf_helper(name, **kwargs)

    # if restarting from a checkpoint file, this file
    # needs to be in scratch with the correct name
    filename = psi4.core.get_option("V2RDM_CASSCF",
                                    "RESTART_FROM_CHECKPOINT_FILE")

    # Ensure IWL files have been written when not using DF/CD
    scf_type = psi4.core.get_option('SCF', 'SCF_TYPE')
    if (scf_type == 'PK' or scf_type == 'DIRECT'):
        proc_util.check_iwl_file_from_scf_type(
            psi4.core.get_option('SCF', 'SCF_TYPE'), ref_wfn)

    # reorder wavefuntions based on user input
    # apply a list of 2x2 rotation matrices to the orbitals in the form of [irrep, orbital1, orbital2, theta]
    # where an angle of 0 would do nothing and an angle of 90 would switch the two orbitals.
    # the indices of irreps and orbitals start from 0
    reorder_orbitals = psi4.core.get_option("V2RDM_CASSCF", "MCSCF_ROTATE")
    for orbord in reorder_orbitals:
        if type(orbord) != list:
            raise psi4.p4util.PsiException(
                "Each element of the orbtial rotate list requires 4 arguements (irrep, orb1, orb2, theta)."
            )
        if len(orbord) != 4:
            raise psi4.p4util.PsiException(
                "Each element of the orbtial rotate list requires 4 arguements (irrep, orb1, orb2, theta)."
            )

        irrep, orb1, orb2, theta = orbord

        if irrep > ref_wfn.Ca().nirrep():
            raise psi4.p4util.PsiException(
                "REORDER_ORBITALS: Expression %s irrep number is larger than the number of irreps"
                % (str(orbord)))

        if max(orb1, orb2) > ref_wfn.Ca().coldim()[irrep]:
            raise psi4.p4util.PsiException(
                "REORDER_ORBITALS: Expression %s orbital number exceeds number of orbitals in irrep"
                % (str(orbord)))

        theta = numpy.deg2rad(theta)

        x_a = ref_wfn.Ca().nph[irrep][:, orb1].copy()
        y_a = ref_wfn.Ca().nph[irrep][:, orb2].copy()

        xp_a = numpy.cos(theta) * x_a - numpy.sin(theta) * y_a
        yp_a = numpy.sin(theta) * x_a + numpy.cos(theta) * y_a

        ref_wfn.Ca().nph[irrep][:, orb1] = xp_a
        ref_wfn.Ca().nph[irrep][:, orb2] = yp_a

        x_b = ref_wfn.Ca().nph[irrep][:, orb1].copy()
        y_b = ref_wfn.Ca().nph[irrep][:, orb2].copy()

        xp_b = numpy.cos(theta) * x_b - numpy.sin(theta) * y_b
        yp_b = numpy.sin(theta) * x_b + numpy.cos(theta) * y_b

        ref_wfn.Ca().nph[irrep][:, orb1] = xp_b
        ref_wfn.Ca().nph[irrep][:, orb2] = yp_b

    returnvalue = psi4.core.plugin('v2rdm_casscf.so', ref_wfn)

    optstash.restore()

    return returnvalue
예제 #18
0
파일: frac.py 프로젝트: 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)
예제 #19
0
파일: frac.py 프로젝트: yxie326/psi4
def frac_nuke(name, **kwargs):
    """Pull all the electrons out, one at a time"""
    optstash = p4util.OptionsState(
        ['SCF', 'GUESS'],
        ['SCF', 'DF_INTS_IO'],
        ["SCF", "FRAC_START"],
        ["SCF", "FRAC_RENORMALIZE"],
        # NYI ["SCF", "FRAC_LOAD"],
        ["SCF", "FRAC_OCC"],
        ["SCF", "FRAC_VAL"],
        ["SCF", "FRAC_DIIS"])

    kwargs = p4util.kwargs_lower(kwargs)

    # 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(
            """frac_nuke requires neutral molecule to start.""")
    if molecule.schoenflies_symbol() != 'c1':
        core.print_out(
            """  Requested procedure `frac_nuke` 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()

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

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

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

    charge = charge0
    mult = mult0

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

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

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

    # => Traverse <= #
    core.set_local_option("SCF", "DF_INTS_IO", "SAVE")

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

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

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

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

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

    core.set_local_option("SCF", "DF_INTS_IO", "LOAD")
    core.set_local_option("SCF", "FRAC_START", frac_start)
    core.set_local_option("SCF", "FRAC_RENORMALIZE", True)

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

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

            core.set_local_option("SCF", "FRAC_OCC", [H**O])
            core.set_local_option("SCF", "FRAC_VAL", [occ])

            E, wfn = driver.energy('scf',
                                   dft_functional=name,
                                   return_wfn=True,
                                   molecule=molecule,
                                   **kwargs)
            C = 1
            if E == 0.0:
                E = core.variable('SCF ITERATION ENERGY')
                C = 0

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

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

            core.set_local_option("SCF", "FRAC_START", 2)
            # NYI core.set_local_option("SCF", "FRAC_LOAD", True)
            core.set_local_option("SCF", "FRAC_DIIS", frac_diis)
            core.set_local_option("SCF", "GUESS", "READ")

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

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

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

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

    core.set_local_option("SCF", "DF_INTS_IO", "NONE")

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

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

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

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

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

    optstash.restore()
    return E
예제 #20
0
def run_forte(name, **kwargs):
    r"""Function encoding sequence of PSI module and plugin calls so that
    forte can be called via :py:func:`~driver.energy`. For post-scf plugins.

    >>> energy('forte')

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

    # Compute a SCF reference, a wavefunction is return which holds the molecule used, orbitals
    # Fock matrices, and more
    ref_wfn = kwargs.get('ref_wfn', None)
    if ref_wfn is None:
        ref_wfn = psi4.driver.scf_helper(name, **kwargs)

    # Get the option object
    options = psi4.core.get_options()
    options.set_current_module('FORTE')
    forte.forte_options.update_psi_options(options)

    if ('DF' in options.get_str('INT_TYPE')):
        aux_basis = psi4.core.BasisSet.build(ref_wfn.molecule(), 'DF_BASIS_MP2',
                                         psi4.core.get_global_option('DF_BASIS_MP2'),
                                         'RIFIT', psi4.core.get_global_option('BASIS'))
        ref_wfn.set_basisset('DF_BASIS_MP2', aux_basis)

    if (options.get_str('MINAO_BASIS')):
        minao_basis = psi4.core.BasisSet.build(ref_wfn.molecule(), 'MINAO_BASIS',
                                               options.get_str('MINAO_BASIS'))
        ref_wfn.set_basisset('MINAO_BASIS', minao_basis)

    # Start Forte, initialize ambit
    my_proc_n_nodes = forte.startup()
    my_proc, n_nodes = my_proc_n_nodes

    # Print the banner
    forte.banner()

    # Create the MOSpaceInfo object
    mo_space_info = forte.make_mo_space_info(ref_wfn, forte.forte_options)

    # Call methods that project the orbitals (AVAS, embedding)
    orbital_projection(ref_wfn, options)

    state = forte.make_state_info_from_psi_wfn(ref_wfn)
    scf_info = forte.SCFInfo(ref_wfn)
    state_weights_map = forte.make_state_weights_map(forte.forte_options,ref_wfn)

    # Run a method
    job_type = options.get_str('JOB_TYPE')

    energy = 0.0

    if job_type == 'NONE':
        forte.cleanup()
        return ref_wfn

    start = timeit.timeit()

    # Make an integral object
    ints = forte.make_forte_integrals(ref_wfn, options, mo_space_info)

    # Rotate orbitals before computation
    orb_type = options.get_str("ORBITAL_TYPE")
    if orb_type != 'CANONICAL':
        orb_t = forte.make_orbital_transformation(orb_type, scf_info, forte.forte_options, ints, mo_space_info)
        orb_t.compute_transformation()
        Ua = orb_t.get_Ua()
        Ub = orb_t.get_Ub()

        ints.rotate_orbitals(Ua,Ub)

    # Run a method
    if (job_type == 'NEWDRIVER'):
        energy = forte_driver(state_weights_map, scf_info, forte.forte_options, ints, mo_space_info)
    else:
        energy = forte.forte_old_methods(ref_wfn, options, ints, mo_space_info)

    end = timeit.timeit()
    #print('\n\n  Your calculation took ', (end - start), ' seconds');

    # Close ambit, etc.
    forte.cleanup()

    psi4.core.set_scalar_variable('CURRENT ENERGY', energy)
    return ref_wfn
예제 #21
0
def run_psi4fockci(name, molecule, **kwargs):
    """
    A method to run a RAS-nSF-IP/EA calculation.

    This runs a RAS-nSF-IP/EA calculation using Psi4's DETCI module. The 
    number of spin-flips and IP/EA is determined based on setting the 
    ``new_charge`` and ``new_multiplicity`` of the desired target state.
    Additional excitations are included by setting the ``conf_space`` 
    keyword; excitations through the CISDT level are currently supported.

    Parameters
    ----------
    name : str
        Name of method (for Psi4 interfacing)
    molecule : psi4.core.Molecule
        Molecule to run the calculation on.
    new_charge : int
        Target charge of the molecule.
    new_multiplicity : int
        Target multiplicity of the molecule.
    conf_space : str ("")
        Option for including additional excitations outside of the CAS space. 
        Defaults to CAS-nSF-IP/EA. Valid options include:
            * ``""`` CAS-nSF-IP/EA
            * ``"h"`` RAS(h)-nSF-IP/EA
            * ``"p"`` RAS(p)-nSF-IP/EA
            * ``"1x"`` RAS(h,p)-nSF-IP/EA
            * ``"S"`` RAS(S)-nSF-IP/EA
            * ``"SD"`` RAS(SD)-nSF-IP/EA
            * ``"SDT"`` RAS(SDT)-nSF-IP/EA
    add_opts : dict ({})
        Additional options to pass into Psi4.
    return_ci_wfn : bool (False)
        Whether to return the CI wavefunction object.
    return_rohf_wfn : bool (False)
        Whether to return the ROHF wavefunction object.
    return_rohf_e : bool (False)
        Whether to return the ROHF energy.
    read_rohf_wfn : bool (False)
        Whether to read a Psi4 ROHF wavefunction.
    rohf_wfn_in : psi4.core.Wavefunction
        The Psi4 ROHF reference wavefunction (pre-computed).
    write_rohf_wfn : str ("")
        Name of file (.npz) to write
    localize : bool (False)
        Perform BOYS localization on the RAS 2 space before DETCI call?
        Can help with visualization and analysis of orbitals.
    frozen_docc : int (0)
        Number of frozen core orbitals.
    frozen_vir : int (0)
        Number of frozen virtual orbitals.

    Returns
    -------
    return_ci_wfn : psi4.core.Wavefunction
        The SF-CAS([conf_space]) wavefunction.
    """
    lowername = name.lower()
    kwargs = p4util.kwargs_lower(kwargs)

    optstash = p4util.OptionsState(['SCF', 'SCF_TYPE'], ['BASIS'],
                                   ['SCF', 'MAXITER'], ['DETCI', 'CI_MAXITER'])

    new_charge = kwargs.get('new_charge')
    new_multiplicity = kwargs.get('new_multiplicity')
    ref_mol = molecule

    if (not 'new_charge' in kwargs):
        print("ERROR: Please designate a target charge!")
        exit()
    if (not 'new_multiplicity' in kwargs):
        print("ERROR: Please designate a target multiplicity!")
        exit()

    conf_space = kwargs.get('conf_space', "")
    add_opts = kwargs.get('add_opts', {})
    read_rohf_wfn = kwargs.get('read_rohf_wfn', False)
    wfn_rohf_in = kwargs.get('wfn_rohf_in', None)
    write_rohf_wfn = kwargs.get('write_rohf_wfn', "")
    write_ci_vects = kwargs.get('write_ci_vects', False)
    localize = kwargs.get('localize', False)
    frozen_docc = kwargs.get('frozen_docc', 0)
    frozen_uocc = kwargs.get('frozen_vir', 0)

    print("Starting Psi4FockCI...\n")
    # default options for Psi4
    opts = {
        'scf_type': 'pk',
        'reference': 'rohf',
        'mixed': False,
        'maxiter': 1000,
        'ci_maxiter': 50
    }
    opts.update(add_opts)  # add additional options from user

    # run ROHF calculation on reference state or read it in
    psi4.core.clean()
    psi4.set_options(opts)
    mol = ref_mol.clone()  # clone molecule so original isn't modified
    # read in ROHF guess wavefunction if provided
    if (read_rohf_wfn):
        # set up options and run
        psi4.set_options(opts)
        print("Using ROHF from reference...")
        wfn_rohf = wfn_rohf_in
        e_rohf = wfn_rohf.energy()
    # else, run ROHF on reference state
    else:
        print("Running reference...")
        # TODO: Change to scf_helper call
        e_rohf, wfn_rohf = psi4.energy('scf',
                                       molecule=mol,
                                       return_wfn=True,
                                       options=opts)
        print("SCF (%i %i): %6.12f" %
              (mol.molecular_charge(), mol.multiplicity(), e_rohf))

    # saving npz file of wavefunction if needed
    if (write_rohf_wfn != ""):
        wfn_rohf.to_file(write_rohf_wfn)

    # update molecular charge and multiplicity
    mol.set_molecular_charge(new_charge)
    mol.set_multiplicity(new_multiplicity)

    # set up reference wfn to pass into detci
    # save orbital values from reference calculation
    doccpi = wfn_rohf.doccpi()[0]
    soccpi = wfn_rohf.soccpi()[0]
    nmo = wfn_rohf.nmo()
    # calculate soccpi and doccpi
    new_soccpi = mol.multiplicity() - 1
    del_electrons = ref_mol.molecular_charge() - mol.molecular_charge()
    n_total = wfn_rohf.nalpha() + wfn_rohf.nbeta() + del_electrons
    # set orbital occupations
    wfn_rohf.force_soccpi(psi4.core.Dimension([new_soccpi]))
    wfn_rohf.force_doccpi(
        psi4.core.Dimension([(int)((n_total - new_soccpi) / 2)]))

    # set up RAS1, RAS2, RAS3 spaces
    ras1 = doccpi
    ras2 = soccpi
    ras3 = nmo - soccpi - doccpi

    # add/remove orbitals to active space
    if ('add_orbs_ras1' in kwargs):
        ras1 = ras1 - kwargs['add_orbs_ras1']
        ras2 = ras2 + kwargs['add_orbs_ras1']
    if ('add_orbs_ras3' in kwargs):
        ras3 = ras3 - kwargs['add_orbs_ras3']
        ras2 = ras2 + kwargs['add_orbs_ras3']

    # if we need to localize...
    if (localize):
        C = psi4.core.Matrix.to_array(wfn_rohf.Ca(), copy=True)
        ras1_C = C[:, :doccpi]
        ras2_C = C[:, doccpi:doccpi + soccpi]
        ras3_C = C[:, doccpi + soccpi:]
        loc = psi4.core.Localizer.build('BOYS', wfn_rohf.basisset(),
                                        psi4.core.Matrix.from_array(ras2_C))
        loc.localize()
        ras2_localized = psi4.core.Matrix.to_array(loc.L, copy=True)
        localized_orbs = np.column_stack((ras1_C, ras2_localized, ras3_C))
        new_Ca = psi4.core.Matrix.from_array(localized_orbs, name="Ca")
        new_Cb = psi4.core.Matrix.from_array(localized_orbs, name="Cb")
        wfn_rohf.Ca().copy(new_Ca)
        wfn_rohf.Cb().copy(new_Cb)

    # change charge and multiplicity to new target values
    n_sf = (ref_mol.multiplicity() - abs(del_electrons) - new_multiplicity) / 2
    print("\nRunning RAS-SF-IP/EA...")
    print("  New Charge/Mult: (%i %i)" % (new_charge, new_multiplicity))
    print("  Spin-Flips: %i" % n_sf)
    print("  Electron Count: %i" % del_electrons)

    # set active space and docc space based on configuration space input
    # Regular CAS configuration space
    # includes only active space configurations
    if (conf_space == "" or conf_space == "CAS"):
        opts.update({'frozen_docc': [doccpi]})
        opts.update({'ras1': [0]})
        opts.update({'ras2': [ras2]})
        opts.update({'ras3': [0]})
        opts.update({'ras4': [0]})
    # just (h) excitations
    elif (conf_space == "h"):
        opts.update({'ex_level': 0})
        opts.update({'val_ex_level': 1})
        opts.update({'ras3_max': 0})
        opts.update({'frozen_docc': [frozen_docc]})
        opts.update({'ras1': [ras1 - frozen_docc]})
        opts.update({'ras2': [ras2]})
        opts.update({'ras3': [0]})
        opts.update({'ras4': [0]})
    # just (p) excitations
    elif (conf_space == "p"):
        opts.update({'ex_level': 0})
        opts.update({'val_ex_level': 0})
        opts.update({'ras3_max': 1})
        opts.update({'frozen_docc': [doccpi]})
        opts.update({'ras1': [0]})
        opts.update({'ras2': [ras2]})
        opts.update({'ras3': [ras3 - frozen_uocc]})
        opts.update({'frozen_uocc': [frozen_uocc]})
        opts.update({'ras4': [0]})
    # 1x configuration space
    # includes (h, p) excitations
    elif (conf_space == "1x" or conf_space == "h,p"):
        opts.update({'frozen_docc': [0]})
        opts.update({'ex_level': 0})
        opts.update({'val_ex_level': 1})
        opts.update({'ras3_max': 1})
        opts.update({'frozen_docc': [frozen_docc]})
        opts.update({'ras1': [ras1 - frozen_docc]})
        opts.update({'ras2': [ras2]})
        opts.update({'ras3': [ras3 - frozen_uocc]})
        opts.update({'frozen_uocc': [frozen_uocc]})
        opts.update({'ras4': [0]})
    # S configuration space
    # includes (h, p, hp) excitations
    elif (conf_space == "s"):
        opts.update({'ex_level': 1})
        opts.update({'frozen_docc': [frozen_docc]})
        opts.update({'ras1': [ras1 - frozen_docc]})
        opts.update({'ras2': [ras2]})
        opts.update({'ras3': [ras3 - frozen_uocc]})
        opts.update({'frozen_uocc': [frozen_uocc]})
        opts.update({'ras4': [0]})
    elif (conf_space == "sd"):
        opts.update({'frozen_docc': [0]})
        opts.update({'ex_level': 2})
        opts.update({'frozen_docc': [frozen_docc]})
        opts.update({'ras1': [ras1 - frozen_docc]})
        opts.update({'ras2': [ras2]})
        opts.update({'ras3': [ras3 - frozen_uocc]})
        opts.update({'frozen_uocc': [frozen_uocc]})
        opts.update({'ras4': [0]})
    elif (conf_space == "sdt"):
        opts.update({'frozen_docc': [0]})
        opts.update({'ex_level': 3})
        opts.update({'frozen_docc': [frozen_docc]})
        opts.update({'ras1': [ras1 - frozen_docc]})
        opts.update({'ras2': [ras2]})
        opts.update({'ras3': [ras3 - frozen_uocc]})
        opts.update({'frozen_uocc': [frozen_uocc]})
        opts.update({'ras4': [0]})
    # Other configuration spaces aren't supported yet
    else:
        print("Configuration space %s not supported. Exiting..." % conf_space)
        exit()

    # run cas
    psi4.set_options(opts)
    e_cas, wfn_cas = psi4.energy('detci',
                                 ref_wfn=wfn_rohf,
                                 return_wfn=True,
                                 molecule=mol)

    # printing useful info
    print("\n Root\tEnergy")
    print("-----------------------------------")
    n = 0
    while (psi4.core.has_variable("CI ROOT %i TOTAL ENERGY" % n)):
        n_str = "CI ROOT %i TOTAL ENERGY" % n
        e_n = psi4.core.variable(n_str)
        print(" %4i\t%6.12f" % (n, e_n))
        n = n + 1
    print("-----------------------------------\n")

    psi4.core.print_variables()  # printing Psi4 variables

    # obtain eigenvectors if needed
    # partly based on Daniel Smith's answer on Psi4 forums
    if (write_ci_vects):
        wfn_cas_2 = psi4.core.CIWavefunction(wfn_rohf)
        C = np.zeros((wfn_cas_2.ndet(), n_roots))
        for i in range(n_roots):
            dvec = wfn_cas_2.new_civector(i + 1, 53, True, True)
            dvec.set_nvec(i + 1)
            dvec.init_io_files(True)
            dvec.read(i, 0)
            C[:, i] = np.array(dvec)
        np.savetxt('ci_vect.txt', C)

    optstash.restore()

    print("Psi4FockCI complete. Have a good day!")

    return wfn_cas
예제 #22
0
def database(name, db_name, **kwargs):
    r"""Function to access the molecule objects and reference energies of
    popular chemical databases.

    :aliases: db()

    :returns: (*float*) Mean absolute deviation of the database in kcal/mol

    :PSI variables:

    .. hlist::
       :columns: 1

       * :psivar:`db_name DATABASE MEAN SIGNED DEVIATION <db_nameDATABASEMEANSIGNEDDEVIATION>`
       * :psivar:`db_name DATABASE MEAN ABSOLUTE DEVIATION <db_nameDATABASEMEANABSOLUTEDEVIATION>`
       * :psivar:`db_name DATABASE ROOT-MEAN-SQUARE DEVIATION <db_nameDATABASEROOT-MEAN-SQUARESIGNEDDEVIATION>`
       * Python dictionaries of results accessible as ``DB_RGT`` and ``DB_RXN``.

    .. note:: It is very easy to make a database from a collection of xyz files
        using the script :source:`share/scripts/ixyz2database.py`.
        See :ref:`sec:createDatabase` for details.

    .. caution:: Some features are not yet implemented. Buy a developer some coffee.

       - In sow/reap mode, use only global options (e.g., the local option set by ``set scf scf_type df`` will not be respected).

    .. note:: To access a database that is not embedded in a |PSIfour|
        distribution, add the path to the directory containing the database
        to the environment variable :envvar:`PYTHONPATH`.

    :type name: string
    :param name: ``'scf'`` || ``'sapt0'`` || ``'ccsd(t)'`` || etc.

        First argument, usually unlabeled. Indicates the computational method
        to be applied to the database. May be any valid argument to
        :py:func:`~driver.energy`.

    :type db_name: string
    :param db_name: ``'BASIC'`` || ``'S22'`` || ``'HTBH'`` || etc.

        Second argument, usually unlabeled. Indicates the requested database
        name, matching (case insensitive) the name of a python file in
        ``psi4/share/databases`` or :envvar:`PYTHONPATH`.  Consult that
        directory for available databases and literature citations.

    :type func: :ref:`function <op_py_function>`
    :param func: |dl| ``energy`` |dr| || ``optimize`` || ``cbs``

        Indicates the type of calculation to be performed on each database
        member. The default performs a single-point ``energy('name')``, while
        ``optimize`` perfoms a geometry optimization on each reagent, and
        ``cbs`` performs a compound single-point energy. If a nested series
        of python functions is intended (see :ref:`sec:intercalls`), use
        keyword ``db_func`` instead of ``func``.

    :type mode: string
    :param mode: |dl| ``'continuous'`` |dr| || ``'sow'`` || ``'reap'``

        Indicates whether the calculations required to complete the
        database are to be run in one file (``'continuous'``) or are to be
        farmed out in an embarrassingly parallel fashion
        (``'sow'``/``'reap'``).  For the latter, run an initial job with
        ``'sow'`` and follow instructions in its output file.

    :type cp: :ref:`boolean <op_py_boolean>`
    :param cp: ``'on'`` || |dl| ``'off'`` |dr|

        Indicates whether counterpoise correction is employed in computing
        interaction energies. Use this option and NOT the :py:func:`~wrappers.cp`
        function for BSSE correction in database().  Option available
        (See :ref:`sec:availableDatabases`) only for databases of bimolecular complexes.

    :type rlxd: :ref:`boolean <op_py_boolean>`
    :param rlxd: ``'on'`` || |dl| ``'off'`` |dr|

        Indicates whether correction for deformation energy is
        employed in computing interaction energies.  Option available
        (See :ref:`sec:availableDatabases`) only for databases of bimolecular complexes
        with non-frozen monomers, e.g., HBC6.

    :type symm: :ref:`boolean <op_py_boolean>`
    :param symm: |dl| ``'on'`` |dr| || ``'off'``

        Indicates whether the native symmetry of the database reagents is
        employed (``'on'``) or whether it is forced to :math:`C_1` symmetry
        (``'off'``). Some computational methods (e.g., SAPT) require no
        symmetry, and this will be set by database().

    :type zpe: :ref:`boolean <op_py_boolean>`
    :param zpe: ``'on'`` || |dl| ``'off'`` |dr|

        Indicates whether zero-point-energy corrections are appended to
        single-point energy values. Option valid only for certain
        thermochemical databases. Disabled until Hessians ready.

    :type benchmark: string
    :param benchmark: |dl| ``'default'`` |dr| || ``'S22A'`` || etc.

        Indicates whether a non-default set of reference energies, if
        available (See :ref:`sec:availableDatabases`), are employed for the
        calculation of error statistics.

    :type tabulate: array of strings
    :param tabulate: |dl| ``[]`` |dr| || ``['scf total energy', 'natom']`` || etc.

        Indicates whether to form tables of variables other than the
        primary requested energy.  Available for any PSI variable.

    :type subset: string or array of strings
    :param subset:

        Indicates a subset of the full database to run. This is a very
        flexible option and can be used in three distinct ways, outlined
        below. Note that two take a string and the last takes an array.
        See `Available Databases`_ for available values.

        * ``'small'`` || ``'large'`` || ``'equilibrium'``
            Calls predefined subsets of the requested database, either
            ``'small'``, a few of the smallest database members,
            ``'large'``, the largest of the database members, or
            ``'equilibrium'``, the equilibrium geometries for a database
            composed of dissociation curves.
        * ``'BzBz_S'`` || ``'FaOOFaON'`` || ``'ArNe'`` ||  ``'HB'`` || etc.
            For databases composed of dissociation curves, or otherwise
            divided into subsets, individual curves and subsets can be
            called by name. Consult the database python files for available
            molecular systems (case insensitive).
        * ``[1,2,5]`` || ``['1','2','5']`` || ``['BzMe-3.5', 'MeMe-5.0']`` || etc.
            Specify a list of database members to run. Consult the
            database python files for available molecular systems.  This
            is the only portion of database input that is case sensitive;
            choices for this keyword must match the database python file.

    :examples:

    >>> # [1] Two-stage SCF calculation on short, equilibrium, and long helium dimer
    >>> db('scf','RGC10',cast_up='sto-3g',subset=['HeHe-0.85','HeHe-1.0','HeHe-1.5'], tabulate=['scf total energy','natom'])

    >>> # [2] Counterpoise-corrected interaction energies for three complexes in S22
    >>> #     Error statistics computed wrt an old benchmark, S22A
    >>> database('mp2','S22',cp=1,subset=[16,17,8],benchmark='S22A')

    >>> # [3] SAPT0 on the neon dimer dissociation curve
    >>> db('sapt0',subset='NeNe',cp=0,symm=0,db_name='RGC10')

    >>> # [4] Optimize system 1 in database S22, producing tables of scf and mp2 energy
    >>> db('mp2','S22',db_func=optimize,subset=[1], tabulate=['mp2 total energy','current energy'])

    >>> # [5] CCSD on the smallest systems of HTBH, a hydrogen-transfer database
    >>> database('ccsd','HTBH',subset='small', tabulate=['ccsd total energy', 'mp2 total energy'])

    """
    lowername = name  #TODO
    kwargs = p4util.kwargs_lower(kwargs)

    # Wrap any positional arguments into kwargs (for intercalls among wrappers)
    if not('name' in kwargs) and name:
        kwargs['name'] = name #.lower()
    if not('db_name' in kwargs) and db_name:
        kwargs['db_name'] = db_name

    # Establish function to call
    func = kwargs.pop('db_func', kwargs.pop('func', energy))
    kwargs['db_func'] = func
    # Bounce to CP if bsse kwarg (someday)
    if kwargs.get('bsse_type', None) is not None:
        raise ValidationError("""Database: Cannot specify bsse_type for database. Use the cp keyword withing database instead.""")

    allowoptexceeded = kwargs.get('allowoptexceeded', False)
    optstash = p4util.OptionsState(
        ['WRITER_FILE_LABEL'],
        ['SCF', 'REFERENCE'])

    # Wrapper wholly defines molecule. discard any passed-in
    kwargs.pop('molecule', None)

    # Paths to search for database files: here + PSIPATH + library + PYTHONPATH
    db_paths = []
    db_paths.append(os.getcwd())
    db_paths.extend(os.environ.get('PSIPATH', '').split(os.path.pathsep))
    db_paths.append(os.path.join(core.get_datadir(), 'databases'))
    db_paths.append(os.path.dirname(__file__))
    db_paths = list(map(os.path.abspath, db_paths))
    sys.path[1:1] = db_paths
    # TODO this should be modernized a la interface_cfour

    # Define path and load module for requested database
    database = p4util.import_ignorecase(db_name)
    if database is None:
        core.print_out('\nPython module for database %s failed to load\n\n' % (db_name))
        core.print_out('\nSearch path that was tried:\n')
        core.print_out(", ".join(map(str, sys.path)))
        raise ValidationError("Python module loading problem for database " + str(db_name))
    else:
        dbse = database.dbse
        HRXN = database.HRXN
        ACTV = database.ACTV
        RXNM = database.RXNM
        BIND = database.BIND
        TAGL = database.TAGL
        GEOS = database.GEOS
        try:
            DATA = database.DATA
        except AttributeError:
            DATA = {}

    user_writer_file_label = core.get_global_option('WRITER_FILE_LABEL')
    user_reference = core.get_global_option('REFERENCE')

    # Configuration based upon e_name & db_name options
    #   Force non-supramolecular if needed
    if not hasattr(lowername, '__call__') and re.match(r'^.*sapt', lowername):
        try:
            database.ACTV_SA
        except AttributeError:
            raise ValidationError('Database %s not suitable for non-supramolecular calculation.' % (db_name))
        else:
            ACTV = database.ACTV_SA
    #   Force open-shell if needed
    openshell_override = 0
    if user_reference in ['RHF', 'RKS']:
        try:
            database.isOS
        except AttributeError:
            pass
        else:
            if p4util.yes.match(str(database.isOS)):
                openshell_override = 1
                core.print_out('\nSome reagents in database %s require an open-shell reference; will be reset to UHF/UKS as needed.\n' % (db_name))

    # Configuration based upon database keyword options
    #   Option symmetry- whether symmetry treated normally or turned off (currently req'd for dfmp2 & dft)
    db_symm = kwargs.get('symm', True)

    symmetry_override = 0
    if db_symm is False:
        symmetry_override = 1
    elif db_symm is True:
        pass
    else:
        raise ValidationError("""Symmetry mode '%s' not valid.""" % (db_symm))

    #   Option mode of operation- whether db run in one job or files farmed out
    db_mode = kwargs.pop('db_mode', kwargs.pop('mode', 'continuous')).lower()
    kwargs['db_mode'] = db_mode

    if db_mode == 'continuous':
        pass
    elif db_mode == 'sow':
        pass
    elif db_mode == 'reap':
        db_linkage = kwargs.get('linkage', None)
        if db_linkage is None:
            raise ValidationError("""Database execution mode 'reap' requires a linkage option.""")
    else:
        raise ValidationError("""Database execution mode '%s' not valid.""" % (db_mode))

    #   Option counterpoise- whether for interaction energy databases run in bsse-corrected or not
    db_cp = kwargs.get('cp', False)

    if db_cp is True:
        try:
            database.ACTV_CP
        except AttributeError:
            raise ValidationError("""Counterpoise correction mode 'yes' invalid for database %s.""" % (db_name))
        else:
            ACTV = database.ACTV_CP
    elif db_cp is False:
        pass
    else:
        raise ValidationError("""Counterpoise correction mode '%s' not valid.""" % (db_cp))

    #   Option relaxed- whether for non-frozen-monomer interaction energy databases include deformation correction or not?
    db_rlxd = kwargs.get('rlxd', False)

    if db_rlxd is True:
        if db_cp is True:
            try:
                database.ACTV_CPRLX
                database.RXNM_CPRLX
            except AttributeError:
                raise ValidationError('Deformation and counterpoise correction mode \'yes\' invalid for database %s.' % (db_name))
            else:
                ACTV = database.ACTV_CPRLX
                RXNM = database.RXNM_CPRLX
        elif db_cp is False:
            try:
                database.ACTV_RLX
            except AttributeError:
                raise ValidationError('Deformation correction mode \'yes\' invalid for database %s.' % (db_name))
            else:
                ACTV = database.ACTV_RLX
    elif db_rlxd is False:
    #elif no.match(str(db_rlxd)):
        pass
    else:
        raise ValidationError('Deformation correction mode \'%s\' not valid.' % (db_rlxd))

    #   Option zero-point-correction- whether for thermochem databases jobs are corrected by zpe
    db_zpe = kwargs.get('zpe', False)

    if db_zpe is True:
        raise ValidationError('Zero-point-correction mode \'yes\' not yet implemented.')
    elif db_zpe is False:
        pass
    else:
        raise ValidationError('Zero-point-correction \'mode\' %s not valid.' % (db_zpe))

    #   Option benchmark- whether error statistics computed wrt alternate reference energies
    db_benchmark = 'default'
    if 'benchmark' in kwargs:
        db_benchmark = kwargs['benchmark']

        if db_benchmark.lower() == 'default':
            pass
        else:
            BIND = p4util.getattr_ignorecase(database, 'BIND_' + db_benchmark)
            if BIND is None:
                raise ValidationError('Special benchmark \'%s\' not available for database %s.' % (db_benchmark, db_name))

    #   Option tabulate- whether tables of variables other than primary energy method are formed
    # TODO db(func=cbs,tabulate=[non-current-energy])  # broken
    db_tabulate = []
    if 'tabulate' in kwargs:
        db_tabulate = kwargs['tabulate']

    #   Option subset- whether all of the database or just a portion is run
    db_subset = HRXN
    if 'subset' in kwargs:
        db_subset = kwargs['subset']

    if isinstance(db_subset, (str, bytes)):
        if db_subset.lower() == 'small':
            try:
                database.HRXN_SM
            except AttributeError:
                raise ValidationError("""Special subset 'small' not available for database %s.""" % (db_name))
            else:
                HRXN = database.HRXN_SM
        elif db_subset.lower() == 'large':
            try:
                database.HRXN_LG
            except AttributeError:
                raise ValidationError("""Special subset 'large' not available for database %s.""" % (db_name))
            else:
                HRXN = database.HRXN_LG
        elif db_subset.lower() == 'equilibrium':
            try:
                database.HRXN_EQ
            except AttributeError:
                raise ValidationError("""Special subset 'equilibrium' not available for database %s.""" % (db_name))
            else:
                HRXN = database.HRXN_EQ
        else:
            HRXN = p4util.getattr_ignorecase(database, db_subset)
            if HRXN is None:
                HRXN = p4util.getattr_ignorecase(database, 'HRXN_' + db_subset)
                if HRXN is None:
                    raise ValidationError("""Special subset '%s' not available for database %s.""" % (db_subset, db_name))
    else:
        temp = []
        for rxn in db_subset:
            if rxn in HRXN:
                temp.append(rxn)
            else:
                raise ValidationError("""Subset element '%s' not a member of database %s.""" % (str(rxn), db_name))
        HRXN = temp

    temp = []
    for rxn in HRXN:
        temp.append(ACTV['%s-%s' % (dbse, rxn)])
    HSYS = p4util.drop_duplicates(sum(temp, []))

    # Sow all the necessary reagent computations
    core.print_out("\n\n")
    p4util.banner(("Database %s Computation" % (db_name)))
    core.print_out("\n")

    #   write index of calcs to output file
    instructions = """\n    The database single-job procedure has been selected through mode='continuous'.\n"""
    instructions += """    Calculations for the reagents will proceed in the order below and will be followed\n"""
    instructions += """    by summary results for the database.\n\n"""
    for rgt in HSYS:
        instructions += """                    %-s\n""" % (rgt)
    core.print_out(instructions)

    #   Loop through chemical systems
    ERGT = {}
    ERXN = {}
    VRGT = {}
    VRXN = {}
    for rgt in HSYS:
        VRGT[rgt] = {}

        core.print_out('\n')
        p4util.banner(' Database {} Computation: Reagent {} \n   {}'.format(db_name, rgt, TAGL[rgt]))
        core.print_out('\n')

        molecule = core.Molecule.from_dict(GEOS[rgt].to_dict())
        molecule.set_name(rgt)
        molecule.update_geometry()

        if symmetry_override:
            molecule.reset_point_group('c1')
            molecule.fix_orientation(True)
            molecule.fix_com(True)
            molecule.update_geometry()

        if (openshell_override) and (molecule.multiplicity() != 1):
            if user_reference == 'RHF':
                core.set_global_option('REFERENCE', 'UHF')
            elif user_reference == 'RKS':
                core.set_global_option('REFERENCE', 'UKS')

        core.set_global_option('WRITER_FILE_LABEL', user_writer_file_label + ('' if user_writer_file_label == '' else '-') + rgt)

        if allowoptexceeded:
            try:
                ERGT[rgt] = func(molecule=molecule, **kwargs)
            except ConvergenceError:
                core.print_out(f"Optimization exceeded cycles for {rgt}")
                ERGT[rgt] = 0.0
        else:
            ERGT[rgt] = func(molecule=molecule, **kwargs)
        core.print_variables()
        core.print_out("   Database Contributions Map:\n   {}\n".format('-' * 75))
        for rxn in HRXN:
            db_rxn = dbse + '-' + str(rxn)
            if rgt in ACTV[db_rxn]:
                core.print_out('   reagent {} contributes by {:.4f} to reaction {}\n'.format(rgt, RXNM[db_rxn][rgt], db_rxn))
        core.print_out('\n')
        for envv in db_tabulate:
            VRGT[rgt][envv.upper()] = core.variable(envv)
        core.set_global_option("REFERENCE", user_reference)
        core.clean()
        #core.opt_clean()
        core.clean_variables()

    # Reap all the necessary reaction computations
    core.print_out("\n")
    p4util.banner(("Database %s Results" % (db_name)))
    core.print_out("\n")

    maxactv = []
    for rxn in HRXN:
        maxactv.append(len(ACTV[dbse + '-' + str(rxn)]))
    maxrgt = max(maxactv)
    table_delimit = '-' * (62 + 20 * maxrgt)
    tables = ''

    #   find any reactions that are incomplete
    FAIL = collections.defaultdict(int)
    for rxn in HRXN:
        db_rxn = dbse + '-' + str(rxn)
        for i in range(len(ACTV[db_rxn])):
            if abs(ERGT[ACTV[db_rxn][i]]) < 1.0e-12:
                if not allowoptexceeded:
                    FAIL[rxn] = 1

    #   tabulate requested process::environment variables
    tables += """   For each VARIABLE requested by tabulate, a 'Reaction Value' will be formed from\n"""
    tables += """   'Reagent' values according to weightings 'Wt', as for the REQUESTED ENERGY below.\n"""
    tables += """   Depending on the nature of the variable, this may or may not make any physical sense.\n"""
    for rxn in HRXN:
        db_rxn = dbse + '-' + str(rxn)
        VRXN[db_rxn] = {}

    for envv in db_tabulate:
        envv = envv.upper()
        tables += """\n   ==> %s <==\n\n""" % (envv.title())
        tables += _tblhead(maxrgt, table_delimit, 2)

        for rxn in HRXN:
            db_rxn = dbse + '-' + str(rxn)

            if FAIL[rxn]:
                tables += """\n%23s   %8s %8s %8s %8s""" % (db_rxn, '', '****', '', '')
                for i in range(len(ACTV[db_rxn])):
                    tables += """ %16.8f %2.0f""" % (VRGT[ACTV[db_rxn][i]][envv], RXNM[db_rxn][ACTV[db_rxn][i]])

            else:
                VRXN[db_rxn][envv] = 0.0
                for i in range(len(ACTV[db_rxn])):
                    VRXN[db_rxn][envv] += VRGT[ACTV[db_rxn][i]][envv] * RXNM[db_rxn][ACTV[db_rxn][i]]

                tables += """\n%23s        %16.8f                  """ % (db_rxn, VRXN[db_rxn][envv])
                for i in range(len(ACTV[db_rxn])):
                    tables += """ %16.8f %2.0f""" % (VRGT[ACTV[db_rxn][i]][envv], RXNM[db_rxn][ACTV[db_rxn][i]])
        tables += """\n   %s\n""" % (table_delimit)

    #   tabulate primary requested energy variable with statistics
    count_rxn = 0
    minDerror = 100000.0
    maxDerror = 0.0
    MSDerror = 0.0
    MADerror = 0.0
    RMSDerror = 0.0

    tables += """\n   ==> %s <==\n\n""" % ('Requested Energy')
    tables += _tblhead(maxrgt, table_delimit, 1)
    for rxn in HRXN:
        db_rxn = dbse + '-' + str(rxn)

        if FAIL[rxn]:
            tables += """\n%23s   %8.4f %8s %10s %10s""" % (db_rxn, BIND[db_rxn], '****', '****', '****')
            for i in range(len(ACTV[db_rxn])):
                tables += """ %16.8f %2.0f""" % (ERGT[ACTV[db_rxn][i]], RXNM[db_rxn][ACTV[db_rxn][i]])

        else:
            ERXN[db_rxn] = 0.0
            for i in range(len(ACTV[db_rxn])):
                ERXN[db_rxn] += ERGT[ACTV[db_rxn][i]] * RXNM[db_rxn][ACTV[db_rxn][i]]
            error = constants.hartree2kcalmol * ERXN[db_rxn] - BIND[db_rxn]

            tables += """\n%23s   %8.4f %8.4f %10.4f %10.4f""" % (db_rxn, BIND[db_rxn], constants.hartree2kcalmol * ERXN[db_rxn],
                error, error * constants.cal2J)
            for i in range(len(ACTV[db_rxn])):
                tables += """ %16.8f %2.0f""" % (ERGT[ACTV[db_rxn][i]], RXNM[db_rxn][ACTV[db_rxn][i]])

            if abs(error) < abs(minDerror):
                minDerror = error
            if abs(error) > abs(maxDerror):
                maxDerror = error
            MSDerror += error
            MADerror += abs(error)
            RMSDerror += error * error
            count_rxn += 1
    tables += """\n   %s\n""" % (table_delimit)

    if count_rxn:

        MSDerror /= float(count_rxn)
        MADerror /= float(count_rxn)
        RMSDerror = math.sqrt(RMSDerror / float(count_rxn))

        tables += """%23s %19s %10.4f %10.4f\n""" % ('Minimal Dev', '', minDerror, minDerror * constants.cal2J)
        tables += """%23s %19s %10.4f %10.4f\n""" % ('Maximal Dev', '', maxDerror, maxDerror * constants.cal2J)
        tables += """%23s %19s %10.4f %10.4f\n""" % ('Mean Signed Dev', '', MSDerror, MSDerror * constants.cal2J)
        tables += """%23s %19s %10.4f %10.4f\n""" % ('Mean Absolute Dev', '', MADerror, MADerror * constants.cal2J)
        tables += """%23s %19s %10.4f %10.4f\n""" % ('RMS Dev', '', RMSDerror, RMSDerror * constants.cal2J)
        tables += """   %s\n""" % (table_delimit)

        core.set_variable('%s DATABASE MEAN SIGNED DEVIATION' % (db_name), MSDerror)
        core.set_variable('%s DATABASE MEAN ABSOLUTE DEVIATION' % (db_name), MADerror)
        core.set_variable('%s DATABASE ROOT-MEAN-SQUARE DEVIATION' % (db_name), RMSDerror)

        core.print_out(tables)
        finalenergy = MADerror

    else:
        finalenergy = 0.0

    optstash.restore()

    DB_RGT.clear()
    DB_RGT.update(VRGT)
    DB_RXN.clear()
    DB_RXN.update(VRXN)
    return finalenergy
예제 #23
0
def run_gpu_dfcc(name, **kwargs):
    """Function encoding sequence of PSI module calls for
    a GPU-accelerated DF-CCSD(T) computation.

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

    """

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

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

    psi4.core.set_local_option('GPU_DFCC','DFCC', True)
    psi4.core.set_local_option('GPU_DFCC','CC_TYPE', 'DF')    

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

    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)


    # triples?
    if (lowername == 'gpu-df-ccsd'):
        psi4.core.set_local_option('GPU_DFCC','COMPUTE_TRIPLES', False)
        set_cholesky_from('CC_TYPE')

    if (lowername == 'gpu-df-ccsd(t)'):
        psi4.core.set_local_option('GPU_DFCC','COMPUTE_TRIPLES', True)
        set_cholesky_from('CC_TYPE')

    if psi4.core.get_global_option('SCF_TYPE') not in ['CD', 'DISK_DF']:
        raise ValidationError("""Invalid scf_type for DFCC.""")

    # save DF or CD ints generated by SCF for use in CC
    psi4.core.set_local_option('SCF', 'DF_INTS_IO', 'SAVE')

    # psi4 run sequence 
    ref_wfn = kwargs.get('ref_wfn', None)
    if ref_wfn is None:
        ref_wfn = psi4.driver.scf_helper(name, use_c1=True, **kwargs)  # C1 certified
    else:
        if ref_wfn.molecule().schoenflies_symbol() != 'c1':
            raise ValidationError("""  GPU-DFCC does not make use of molecular symmetry: """
                                  """  reference wavefunction must be C1.\n""")

    scf_aux_basis = psi4.core.BasisSet.build(ref_wfn.molecule(), "DF_BASIS_SCF",
                                        psi4.core.get_option("SCF", "DF_BASIS_SCF"),
                                        "JKFIT", psi4.core.get_global_option('BASIS'),
                                        puream=ref_wfn.basisset().has_puream())
    ref_wfn.set_basisset("DF_BASIS_SCF", scf_aux_basis)

    aux_basis = psi4.core.BasisSet.build(ref_wfn.molecule(), "DF_BASIS_CC",
                                        psi4.core.get_global_option("DF_BASIS_CC"),
                                        "RIFIT", psi4.core.get_global_option("BASIS"))
    ref_wfn.set_basisset("DF_BASIS_CC", aux_basis)

    returnvalue = psi4.core.plugin('gpu_dfcc.so',ref_wfn)

    # restore options
    optstash.restore()

    return returnvalue 
예제 #24
0
def database(name, db_name, **kwargs):
    r"""Function to access the molecule objects and reference energies of
    popular chemical databases.

    :aliases: db()

    :returns: (*float*) Mean absolute deviation of the database in kcal/mol

    :PSI variables:

    .. hlist::
       :columns: 1

       * :psivar:`db_name DATABASE MEAN SIGNED DEVIATION <db_nameDATABASEMEANSIGNEDDEVIATION>`
       * :psivar:`db_name DATABASE MEAN ABSOLUTE DEVIATION <db_nameDATABASEMEANABSOLUTEDEVIATION>`
       * :psivar:`db_name DATABASE ROOT-MEAN-SQUARE DEVIATION <db_nameDATABASEROOT-MEAN-SQUARESIGNEDDEVIATION>`
       * Python dictionaries of results accessible as ``DB_RGT`` and ``DB_RXN``.

    .. note:: It is very easy to make a database from a collection of xyz files
        using the script :source:`share/scripts/ixyz2database.py`.
        See :ref:`sec:createDatabase` for details.

    .. caution:: Some features are not yet implemented. Buy a developer some coffee.

       - In sow/reap mode, use only global options (e.g., the local option set by ``set scf scf_type df`` will not be respected).

    .. note:: To access a database that is not embedded in a |PSIfour|
        distribution, add the path to the directory containing the database
        to the environment variable :envvar:`PYTHONPATH`.

    :type name: string
    :param name: ``'scf'`` || ``'sapt0'`` || ``'ccsd(t)'`` || etc.

        First argument, usually unlabeled. Indicates the computational method
        to be applied to the database. May be any valid argument to
        :py:func:`~driver.energy`.

    :type db_name: string
    :param db_name: ``'BASIC'`` || ``'S22'`` || ``'HTBH'`` || etc.

        Second argument, usually unlabeled. Indicates the requested database
        name, matching (case insensitive) the name of a python file in
        ``psi4/share/databases`` or :envvar:`PYTHONPATH`.  Consult that
        directory for available databases and literature citations.

    :type func: :ref:`function <op_py_function>`
    :param func: |dl| ``energy`` |dr| || ``optimize`` || ``cbs``

        Indicates the type of calculation to be performed on each database
        member. The default performs a single-point ``energy('name')``, while
        ``optimize`` perfoms a geometry optimization on each reagent, and
        ``cbs`` performs a compound single-point energy. If a nested series
        of python functions is intended (see :ref:`sec:intercalls`), use
        keyword ``db_func`` instead of ``func``.

    :type mode: string
    :param mode: |dl| ``'continuous'`` |dr| || ``'sow'`` || ``'reap'``

        Indicates whether the calculations required to complete the
        database are to be run in one file (``'continuous'``) or are to be
        farmed out in an embarrassingly parallel fashion
        (``'sow'``/``'reap'``).  For the latter, run an initial job with
        ``'sow'`` and follow instructions in its output file.

    :type cp: :ref:`boolean <op_py_boolean>`
    :param cp: ``'on'`` || |dl| ``'off'`` |dr|

        Indicates whether counterpoise correction is employed in computing
        interaction energies. Use this option and NOT the :py:func:`~wrappers.cp`
        function for BSSE correction in database().  Option available
        (See :ref:`sec:availableDatabases`) only for databases of bimolecular complexes.

    :type rlxd: :ref:`boolean <op_py_boolean>`
    :param rlxd: ``'on'`` || |dl| ``'off'`` |dr|

        Indicates whether correction for deformation energy is
        employed in computing interaction energies.  Option available
        (See :ref:`sec:availableDatabases`) only for databases of bimolecular complexes
        with non-frozen monomers, e.g., HBC6.

    :type symm: :ref:`boolean <op_py_boolean>`
    :param symm: |dl| ``'on'`` |dr| || ``'off'``

        Indicates whether the native symmetry of the database reagents is
        employed (``'on'``) or whether it is forced to :math:`C_1` symmetry
        (``'off'``). Some computational methods (e.g., SAPT) require no
        symmetry, and this will be set by database().

    :type zpe: :ref:`boolean <op_py_boolean>`
    :param zpe: ``'on'`` || |dl| ``'off'`` |dr|

        Indicates whether zero-point-energy corrections are appended to
        single-point energy values. Option valid only for certain
        thermochemical databases. Disabled until Hessians ready.

    :type benchmark: string
    :param benchmark: |dl| ``'default'`` |dr| || ``'S22A'`` || etc.

        Indicates whether a non-default set of reference energies, if
        available (See :ref:`sec:availableDatabases`), are employed for the
        calculation of error statistics.

    :type tabulate: array of strings
    :param tabulate: |dl| ``[]`` |dr| || ``['scf total energy', 'natom']`` || etc.

        Indicates whether to form tables of variables other than the
        primary requested energy.  Available for any PSI variable.

    :type subset: string or array of strings
    :param subset:

        Indicates a subset of the full database to run. This is a very
        flexible option and can be used in three distinct ways, outlined
        below. Note that two take a string and the last takes an array.
        See `Available Databases`_ for available values.

        * ``'small'`` || ``'large'`` || ``'equilibrium'``
            Calls predefined subsets of the requested database, either
            ``'small'``, a few of the smallest database members,
            ``'large'``, the largest of the database members, or
            ``'equilibrium'``, the equilibrium geometries for a database
            composed of dissociation curves.
        * ``'BzBz_S'`` || ``'FaOOFaON'`` || ``'ArNe'`` ||  ``'HB'`` || etc.
            For databases composed of dissociation curves, or otherwise
            divided into subsets, individual curves and subsets can be
            called by name. Consult the database python files for available
            molecular systems (case insensitive).
        * ``[1,2,5]`` || ``['1','2','5']`` || ``['BzMe-3.5', 'MeMe-5.0']`` || etc.
            Specify a list of database members to run. Consult the
            database python files for available molecular systems.  This
            is the only portion of database input that is case sensitive;
            choices for this keyword must match the database python file.

    :examples:

    >>> # [1] Two-stage SCF calculation on short, equilibrium, and long helium dimer
    >>> db('scf','RGC10',cast_up='sto-3g',subset=['HeHe-0.85','HeHe-1.0','HeHe-1.5'], tabulate=['scf total energy','natom'])

    >>> # [2] Counterpoise-corrected interaction energies for three complexes in S22
    >>> #     Error statistics computed wrt an old benchmark, S22A
    >>> database('mp2','S22',cp=1,subset=[16,17,8],benchmark='S22A')

    >>> # [3] SAPT0 on the neon dimer dissociation curve
    >>> db('sapt0',subset='NeNe',cp=0,symm=0,db_name='RGC10')

    >>> # [4] Optimize system 1 in database S22, producing tables of scf and mp2 energy
    >>> db('mp2','S22',db_func=optimize,subset=[1], tabulate=['mp2 total energy','current energy'])

    >>> # [5] CCSD on the smallest systems of HTBH, a hydrogen-transfer database
    >>> database('ccsd','HTBH',subset='small', tabulate=['ccsd total energy', 'mp2 total energy'])

    """
    lowername = name  #TODO
    kwargs = p4util.kwargs_lower(kwargs)

    # Wrap any positional arguments into kwargs (for intercalls among wrappers)
    if not ('name' in kwargs) and name:
        kwargs['name'] = name  #.lower()
    if not ('db_name' in kwargs) and db_name:
        kwargs['db_name'] = db_name

    # Establish function to call
    func = kwargs.pop('db_func', kwargs.pop('func', energy))
    kwargs['db_func'] = func
    # Bounce to CP if bsse kwarg (someday)
    if kwargs.get('bsse_type', None) is not None:
        raise ValidationError(
            """Database: Cannot specify bsse_type for database. Use the cp keyword withing database instead."""
        )

    allowoptexceeded = kwargs.get('allowoptexceeded', False)
    optstash = p4util.OptionsState(['WRITER_FILE_LABEL'], ['SCF', 'REFERENCE'])

    # Wrapper wholly defines molecule. discard any passed-in
    kwargs.pop('molecule', None)

    # Paths to search for database files: here + PSIPATH + library + PYTHONPATH
    db_paths = []
    db_paths.append(os.getcwd())
    db_paths.extend(os.environ.get('PSIPATH', '').split(os.path.pathsep))
    db_paths.append(os.path.join(core.get_datadir(), 'databases'))
    db_paths.append(os.path.dirname(__file__))
    db_paths = list(map(os.path.abspath, db_paths))
    sys.path[1:1] = db_paths
    # TODO this should be modernized a la interface_cfour

    # Define path and load module for requested database
    database = p4util.import_ignorecase(db_name)
    if database is None:
        core.print_out('\nPython module for database %s failed to load\n\n' %
                       (db_name))
        core.print_out('\nSearch path that was tried:\n')
        core.print_out(", ".join(map(str, sys.path)))
        raise ValidationError("Python module loading problem for database " +
                              str(db_name))
    else:
        dbse = database.dbse
        HRXN = database.HRXN
        ACTV = database.ACTV
        RXNM = database.RXNM
        BIND = database.BIND
        TAGL = database.TAGL
        GEOS = database.GEOS
        try:
            DATA = database.DATA
        except AttributeError:
            DATA = {}

    user_writer_file_label = core.get_global_option('WRITER_FILE_LABEL')
    user_reference = core.get_global_option('REFERENCE')

    # Configuration based upon e_name & db_name options
    #   Force non-supramolecular if needed
    if not hasattr(lowername, '__call__') and re.match(r'^.*sapt', lowername):
        try:
            database.ACTV_SA
        except AttributeError:
            raise ValidationError(
                'Database %s not suitable for non-supramolecular calculation.'
                % (db_name))
        else:
            ACTV = database.ACTV_SA
    #   Force open-shell if needed
    openshell_override = 0
    if user_reference in ['RHF', 'RKS']:
        try:
            database.isOS
        except AttributeError:
            pass
        else:
            if p4util.yes.match(str(database.isOS)):
                openshell_override = 1
                core.print_out(
                    '\nSome reagents in database %s require an open-shell reference; will be reset to UHF/UKS as needed.\n'
                    % (db_name))

    # Configuration based upon database keyword options
    #   Option symmetry- whether symmetry treated normally or turned off (currently req'd for dfmp2 & dft)
    db_symm = kwargs.get('symm', True)

    symmetry_override = 0
    if db_symm is False:
        symmetry_override = 1
    elif db_symm is True:
        pass
    else:
        raise ValidationError("""Symmetry mode '%s' not valid.""" % (db_symm))

    #   Option mode of operation- whether db run in one job or files farmed out
    db_mode = kwargs.pop('db_mode', kwargs.pop('mode', 'continuous')).lower()
    kwargs['db_mode'] = db_mode

    if db_mode == 'continuous':
        pass
    elif db_mode == 'sow':
        pass
    elif db_mode == 'reap':
        db_linkage = kwargs.get('linkage', None)
        if db_linkage is None:
            raise ValidationError(
                """Database execution mode 'reap' requires a linkage option."""
            )
    else:
        raise ValidationError("""Database execution mode '%s' not valid.""" %
                              (db_mode))

    #   Option counterpoise- whether for interaction energy databases run in bsse-corrected or not
    db_cp = kwargs.get('cp', False)

    if db_cp is True:
        try:
            database.ACTV_CP
        except AttributeError:
            raise ValidationError(
                """Counterpoise correction mode 'yes' invalid for database %s."""
                % (db_name))
        else:
            ACTV = database.ACTV_CP
    elif db_cp is False:
        pass
    else:
        raise ValidationError(
            """Counterpoise correction mode '%s' not valid.""" % (db_cp))

    #   Option relaxed- whether for non-frozen-monomer interaction energy databases include deformation correction or not?
    db_rlxd = kwargs.get('rlxd', False)

    if db_rlxd is True:
        if db_cp is True:
            try:
                database.ACTV_CPRLX
                database.RXNM_CPRLX
            except AttributeError:
                raise ValidationError(
                    'Deformation and counterpoise correction mode \'yes\' invalid for database %s.'
                    % (db_name))
            else:
                ACTV = database.ACTV_CPRLX
                RXNM = database.RXNM_CPRLX
        elif db_cp is False:
            try:
                database.ACTV_RLX
            except AttributeError:
                raise ValidationError(
                    'Deformation correction mode \'yes\' invalid for database %s.'
                    % (db_name))
            else:
                ACTV = database.ACTV_RLX
    elif db_rlxd is False:
        #elif no.match(str(db_rlxd)):
        pass
    else:
        raise ValidationError('Deformation correction mode \'%s\' not valid.' %
                              (db_rlxd))

    #   Option zero-point-correction- whether for thermochem databases jobs are corrected by zpe
    db_zpe = kwargs.get('zpe', False)

    if db_zpe is True:
        raise ValidationError(
            'Zero-point-correction mode \'yes\' not yet implemented.')
    elif db_zpe is False:
        pass
    else:
        raise ValidationError('Zero-point-correction \'mode\' %s not valid.' %
                              (db_zpe))

    #   Option benchmark- whether error statistics computed wrt alternate reference energies
    db_benchmark = 'default'
    if 'benchmark' in kwargs:
        db_benchmark = kwargs['benchmark']

        if db_benchmark.lower() == 'default':
            pass
        else:
            BIND = p4util.getattr_ignorecase(database, 'BIND_' + db_benchmark)
            if BIND is None:
                raise ValidationError(
                    'Special benchmark \'%s\' not available for database %s.' %
                    (db_benchmark, db_name))

    #   Option tabulate- whether tables of variables other than primary energy method are formed
    # TODO db(func=cbs,tabulate=[non-current-energy])  # broken
    db_tabulate = []
    if 'tabulate' in kwargs:
        db_tabulate = kwargs['tabulate']

    #   Option subset- whether all of the database or just a portion is run
    db_subset = HRXN
    if 'subset' in kwargs:
        db_subset = kwargs['subset']

    if isinstance(db_subset, (str, bytes)):
        if db_subset.lower() == 'small':
            try:
                database.HRXN_SM
            except AttributeError:
                raise ValidationError(
                    """Special subset 'small' not available for database %s."""
                    % (db_name))
            else:
                HRXN = database.HRXN_SM
        elif db_subset.lower() == 'large':
            try:
                database.HRXN_LG
            except AttributeError:
                raise ValidationError(
                    """Special subset 'large' not available for database %s."""
                    % (db_name))
            else:
                HRXN = database.HRXN_LG
        elif db_subset.lower() == 'equilibrium':
            try:
                database.HRXN_EQ
            except AttributeError:
                raise ValidationError(
                    """Special subset 'equilibrium' not available for database %s."""
                    % (db_name))
            else:
                HRXN = database.HRXN_EQ
        else:
            HRXN = p4util.getattr_ignorecase(database, db_subset)
            if HRXN is None:
                HRXN = p4util.getattr_ignorecase(database, 'HRXN_' + db_subset)
                if HRXN is None:
                    raise ValidationError(
                        """Special subset '%s' not available for database %s."""
                        % (db_subset, db_name))
    else:
        temp = []
        for rxn in db_subset:
            if rxn in HRXN:
                temp.append(rxn)
            else:
                raise ValidationError(
                    """Subset element '%s' not a member of database %s.""" %
                    (str(rxn), db_name))
        HRXN = temp

    temp = []
    for rxn in HRXN:
        temp.append(ACTV['%s-%s' % (dbse, rxn)])
    HSYS = p4util.drop_duplicates(sum(temp, []))

    # Sow all the necessary reagent computations
    core.print_out("\n\n")
    p4util.banner(("Database %s Computation" % (db_name)))
    core.print_out("\n")

    #   write index of calcs to output file
    instructions = """\n    The database single-job procedure has been selected through mode='continuous'.\n"""
    instructions += """    Calculations for the reagents will proceed in the order below and will be followed\n"""
    instructions += """    by summary results for the database.\n\n"""
    for rgt in HSYS:
        instructions += """                    %-s\n""" % (rgt)
    core.print_out(instructions)

    #   Loop through chemical systems
    ERGT = {}
    ERXN = {}
    VRGT = {}
    VRXN = {}
    for rgt in HSYS:
        VRGT[rgt] = {}

        core.print_out('\n')
        p4util.banner(' Database {} Computation: Reagent {} \n   {}'.format(
            db_name, rgt, TAGL[rgt]))
        core.print_out('\n')

        molecule = core.Molecule.from_dict(GEOS[rgt].to_dict())
        molecule.set_name(rgt)
        molecule.update_geometry()

        if symmetry_override:
            molecule.reset_point_group('c1')
            molecule.fix_orientation(True)
            molecule.fix_com(True)
            molecule.update_geometry()

        if (openshell_override) and (molecule.multiplicity() != 1):
            if user_reference == 'RHF':
                core.set_global_option('REFERENCE', 'UHF')
            elif user_reference == 'RKS':
                core.set_global_option('REFERENCE', 'UKS')

        core.set_global_option(
            'WRITER_FILE_LABEL', user_writer_file_label +
            ('' if user_writer_file_label == '' else '-') + rgt)

        if allowoptexceeded:
            try:
                ERGT[rgt] = func(molecule=molecule, **kwargs)
            except ConvergenceError:
                core.print_out(f"Optimization exceeded cycles for {rgt}")
                ERGT[rgt] = 0.0
        else:
            ERGT[rgt] = func(molecule=molecule, **kwargs)
        core.print_variables()
        core.print_out("   Database Contributions Map:\n   {}\n".format('-' *
                                                                        75))
        for rxn in HRXN:
            db_rxn = dbse + '-' + str(rxn)
            if rgt in ACTV[db_rxn]:
                core.print_out(
                    '   reagent {} contributes by {:.4f} to reaction {}\n'.
                    format(rgt, RXNM[db_rxn][rgt], db_rxn))
        core.print_out('\n')
        for envv in db_tabulate:
            VRGT[rgt][envv.upper()] = core.variable(envv)
        core.set_global_option("REFERENCE", user_reference)
        core.clean()
        #core.opt_clean()
        core.clean_variables()

    # Reap all the necessary reaction computations
    core.print_out("\n")
    p4util.banner(("Database %s Results" % (db_name)))
    core.print_out("\n")

    maxactv = []
    for rxn in HRXN:
        maxactv.append(len(ACTV[dbse + '-' + str(rxn)]))
    maxrgt = max(maxactv)
    table_delimit = '-' * (62 + 20 * maxrgt)
    tables = ''

    #   find any reactions that are incomplete
    FAIL = collections.defaultdict(int)
    for rxn in HRXN:
        db_rxn = dbse + '-' + str(rxn)
        for i in range(len(ACTV[db_rxn])):
            if abs(ERGT[ACTV[db_rxn][i]]) < 1.0e-12:
                if not allowoptexceeded:
                    FAIL[rxn] = 1

    #   tabulate requested process::environment variables
    tables += """   For each VARIABLE requested by tabulate, a 'Reaction Value' will be formed from\n"""
    tables += """   'Reagent' values according to weightings 'Wt', as for the REQUESTED ENERGY below.\n"""
    tables += """   Depending on the nature of the variable, this may or may not make any physical sense.\n"""
    for rxn in HRXN:
        db_rxn = dbse + '-' + str(rxn)
        VRXN[db_rxn] = {}

    for envv in db_tabulate:
        envv = envv.upper()
        tables += """\n   ==> %s <==\n\n""" % (envv.title())
        tables += _tblhead(maxrgt, table_delimit, 2)

        for rxn in HRXN:
            db_rxn = dbse + '-' + str(rxn)

            if FAIL[rxn]:
                tables += """\n%23s   %8s %8s %8s %8s""" % (db_rxn, '', '****',
                                                            '', '')
                for i in range(len(ACTV[db_rxn])):
                    tables += """ %16.8f %2.0f""" % (VRGT[
                        ACTV[db_rxn][i]][envv], RXNM[db_rxn][ACTV[db_rxn][i]])

            else:
                VRXN[db_rxn][envv] = 0.0
                for i in range(len(ACTV[db_rxn])):
                    VRXN[db_rxn][envv] += VRGT[
                        ACTV[db_rxn][i]][envv] * RXNM[db_rxn][ACTV[db_rxn][i]]

                tables += """\n%23s        %16.8f                  """ % (
                    db_rxn, VRXN[db_rxn][envv])
                for i in range(len(ACTV[db_rxn])):
                    tables += """ %16.8f %2.0f""" % (VRGT[
                        ACTV[db_rxn][i]][envv], RXNM[db_rxn][ACTV[db_rxn][i]])
        tables += """\n   %s\n""" % (table_delimit)

    #   tabulate primary requested energy variable with statistics
    count_rxn = 0
    minDerror = 100000.0
    maxDerror = 0.0
    MSDerror = 0.0
    MADerror = 0.0
    RMSDerror = 0.0

    tables += """\n   ==> %s <==\n\n""" % ('Requested Energy')
    tables += _tblhead(maxrgt, table_delimit, 1)
    for rxn in HRXN:
        db_rxn = dbse + '-' + str(rxn)

        if FAIL[rxn]:
            tables += """\n%23s   %8.4f %8s %10s %10s""" % (
                db_rxn, BIND[db_rxn], '****', '****', '****')
            for i in range(len(ACTV[db_rxn])):
                tables += """ %16.8f %2.0f""" % (ERGT[ACTV[db_rxn][i]],
                                                 RXNM[db_rxn][ACTV[db_rxn][i]])

        else:
            ERXN[db_rxn] = 0.0
            for i in range(len(ACTV[db_rxn])):
                ERXN[db_rxn] += ERGT[ACTV[db_rxn][i]] * RXNM[db_rxn][
                    ACTV[db_rxn][i]]
            error = constants.hartree2kcalmol * ERXN[db_rxn] - BIND[db_rxn]

            tables += """\n%23s   %8.4f %8.4f %10.4f %10.4f""" % (
                db_rxn, BIND[db_rxn], constants.hartree2kcalmol * ERXN[db_rxn],
                error, error * constants.cal2J)
            for i in range(len(ACTV[db_rxn])):
                tables += """ %16.8f %2.0f""" % (ERGT[ACTV[db_rxn][i]],
                                                 RXNM[db_rxn][ACTV[db_rxn][i]])

            if abs(error) < abs(minDerror):
                minDerror = error
            if abs(error) > abs(maxDerror):
                maxDerror = error
            MSDerror += error
            MADerror += abs(error)
            RMSDerror += error * error
            count_rxn += 1
    tables += """\n   %s\n""" % (table_delimit)

    if count_rxn:

        MSDerror /= float(count_rxn)
        MADerror /= float(count_rxn)
        RMSDerror = math.sqrt(RMSDerror / float(count_rxn))

        tables += """%23s %19s %10.4f %10.4f\n""" % (
            'Minimal Dev', '', minDerror, minDerror * constants.cal2J)
        tables += """%23s %19s %10.4f %10.4f\n""" % (
            'Maximal Dev', '', maxDerror, maxDerror * constants.cal2J)
        tables += """%23s %19s %10.4f %10.4f\n""" % (
            'Mean Signed Dev', '', MSDerror, MSDerror * constants.cal2J)
        tables += """%23s %19s %10.4f %10.4f\n""" % (
            'Mean Absolute Dev', '', MADerror, MADerror * constants.cal2J)
        tables += """%23s %19s %10.4f %10.4f\n""" % (
            'RMS Dev', '', RMSDerror, RMSDerror * constants.cal2J)
        tables += """   %s\n""" % (table_delimit)

        core.set_variable('%s DATABASE MEAN SIGNED DEVIATION' % (db_name),
                          MSDerror)
        core.set_variable('%s DATABASE MEAN ABSOLUTE DEVIATION' % (db_name),
                          MADerror)
        core.set_variable('%s DATABASE ROOT-MEAN-SQUARE DEVIATION' % (db_name),
                          RMSDerror)

        core.print_out(tables)
        finalenergy = MADerror

    else:
        finalenergy = 0.0

    optstash.restore()

    DB_RGT.clear()
    DB_RGT.update(VRGT)
    DB_RXN.clear()
    DB_RXN.update(VRXN)
    return finalenergy
예제 #25
0
파일: pymodule.py 프로젝트: bgpeyton/n_body
def run_n_body(name, **kwargs):
    r"""Function encoding sequence of PSI module and plugin calls so that
    n_body can be called via :py:func:`~driver.energy`. For post-scf plugins.

    >>> energy('n_body')

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

    #    print("START run_n_body()")

    # Your plugin's psi4 run sequence goes here
    psi4.core.set_local_option('MYPLUGIN', 'PRINT', 1)

    ##### BEGIN TAYLOR'S run_n_body() FUNCTION #####

    # Only energy and properties are implemented for now, not sure others even
    # make sense anyways.

    db = shelve.open('database', writeback=True)
    #    print(db)
    # Initialize database
    if not 'initialized' in db:
        n_body.initialize_database(db, kwargs)
        db['initialized'] = True
    elif not db['initialized']:
        n_body.initialize_database(db, kwargs)
        db['initialized'] = True

    # Remove n_body_func, it's being tracked in the database and we don't want to propagate it
    if 'n_body_func' in kwargs:
        kwargs.pop('n_body_func')

    # Process user requested options
    n_body_options = n_body.process_options(name, db, kwargs.pop('n_body'))

    # Compare database options to n_body_options
    if 'distributed' in n_body_options:
        db['distributed'] = n_body_options['distributed']
        if not db['distributed']:
            raise Exception(
                "Currently n_body jobs must be run in distributed mode"
                " use the n_body wrapper instead.\n")
    if 'cutoff' in n_body_options:
        db['cutoff'] = n_body_options['cutoff']
    if 'num_threads' in n_body_options:
        db['num_threads'] = n_body_options['num_threads']
    if 'bsse' in n_body_options:
        db['bsse'] = n_body_options['bsse']
    if 'pcm' in n_body_options:
        db['pcm'] = n_body_options['pcm']
    if 'solute' in n_body_options:
        db['solute'] = n_body_options['solute']
    if 'timing' in n_body_options:
        db['timing'] = n_body_options['timing']
    if 'harvest' in n_body_options:
        db['harvest'] = n_body_options['harvest']
    if 'cook' in n_body_options:
        db['cook'] = n_body_options['cook']

    # methods consistency check
    if 'methods' in n_body_options:
        for key, val in n_body_options['methods'].items():
            if key in db['methods'].keys():
                # requested n_body_max smaller than previously requested
                if val < db['methods'][key]:
                    raise Exception('n_body_max for {} has '
                                    'decreased.'.format(key))
                # requested n_body_max has increased
                elif val > db['methods'][key]:
                    # save requested n_body_max
                    db['methods'][key] = val
                    # update database entries
                    n_body.extend_database(db, kwargs)
                    # set flag to regenerate inputs
                    db['inputs_generated'] = False
            else:  # method not already in database
                # add method and n_body_max to database
                db['methods'][key] = val
                # update database entries
                n_body.extend_database(db, kwargs)
                # set flag to regenerate inputs
                db['inputs_generated'] = False

    # Get complete system
    molecule = psi4.core.get_active_molecule()

    # Determine interacting fragments
    if db['cutoff']:
        i_pairs = n_body.interacting_pairs(db['cutoff'])
        i_clusters = []

    if not db['inputs_generated']:
        # Create method directories
        for method, n_body_max in db['methods'].items():
            try:
                os.makedirs(method)
            except:
                if os.path.isdir(method):
                    print(method)
                    pass
                else:
                    raise Exception('Attempt to create {} directory '
                                    'failed.'.format(method))
            # Create n_body_level directories
            for n in range(1, n_body_max + 1):
                directory = '{}/{}'.format(method, n_body.n_body_dir(n))
                try:
                    os.makedirs(directory)
                except:
                    if os.path.isdir(directory):
                        print(directory)
                        pass
                    else:
                        raise Exception('Attempt to create {} directory '
                                        'failed.'.format(directory))
                # Create job input files

                # Grab all ghost functions if SSFC
                # Else, get all possible clusters without ghost atoms
                if db['bsse'] == 'ssfc':
                    clusters = psi4.extract_clusters(molecule, True, n)
                else:
                    clusters = psi4.extract_clusters(molecule, False, n)

                # Flip distance-dropoff off for now
                #if db['bsse'] == 'radius'
                #clusters = extract_clusters(molecule, False, n)
                #clusters = n_body.expand_basis(clusters, db['basis_cutoff'])

                # Get list of fragments involved in clusters
                indexes = psi4.extract_cluster_indexing(molecule, n)
                print('Length of index array = {}'.format(len(indexes)))

                # Testing for extension to inclusion of nearby atoms (ghosted)
                #cluster_string = clusters[0].save_string_xyz_g09()
                #print(cluster_string)
                #cluster_string += molecule.extract_subsets(2).save_string_xyz_g09()
                #print(molecule.extract_subsets(2).save_string_xyz_g09())
                #print(clusters[0].save_string_xyz_g09())
                #print(cluster_string)
                #cluster_string = ''

                # Get interacting clusters
                if db['cutoff']:
                    if n == 1:
                        # Generate all inputs
                        pass
                    elif n == 2:
                        # generate inputs for i_pairs only
                        for k in range(len(clusters) - 1, -1, -1):
                            clus = indexes[k]
                            if clus in i_pairs:
                                i_clusters.append(clus)
                            else:
                                # Remove non-interacting clusters from lists
                                clusters.pop(k)
                                indexes.pop(k)

                    elif n > 2:
                        prev_clusters = copy.deepcopy(i_clusters)
                        i_clusters = []

                        for k in range(len(clusters) - 1, -1, -1):
                            # Check if interacting cluster
                            clus = indexes[k]
                            for p_clus in prev_clusters:
                                # previous cluster is contained within current cluster
                                if set(p_clus).issubset(set(clus)):
                                    # Get remaining frag number
                                    if len(set(clus).difference(
                                            set(p_clus))) == 1:
                                        l = set(clus).difference(
                                            set(p_clus)).pop()
                                    else:
                                        raise Exception(
                                            'Length of difference '
                                            'set is greater than 1')
                                    for m in p_clus:
                                        # Is this an interacting pair?
                                        if sorted([l, m],
                                                  reverse=True) in i_pairs:
                                            i_clusters.append(clus)
                                            # Don't check anymore pairs
                                            break
                                    if clus in i_clusters:
                                        break
                            else:
                                # Remove non-interacting clusters from lists
                                clusters.pop(k)
                                indexes.pop(k)

                # Create input files
                db[method][n]['total_num_jobs'] = len(clusters)
                print('n = {}'.format(n))
                print('Number of jobs created = {}'.format(len(clusters)))
                for k in range(len(clusters)):
                    psi4.activate(clusters[k])
                    cluster = psi4.core.get_active_molecule()
                    #                    db[method][n]['MW'][job] = value
                    ### Set-up things for input generation
                    # Get list of combinations to ghost
                    # MBCP
                    if db['bsse'] == 'mbcp' and n > 1:
                        mbcp = list(itertools.combinations(indexes[k], n - 1))
                        for ghost in mbcp:
                            directory = '{}/{}/{}'.format(
                                method, n_body.n_body_dir(n),
                                n_body.ghost_dir(indexes[k], ghost))
                            cluster.set_ghost_fragments(list(ghost))
                            cluster.update_geometry()
                            cluster.set_name('{}_{}'.format(
                                molecule.name(),
                                n_body.ghost_dir(indexes[k], ghost)))
                            n_body.plant(cluster, db, kwargs, method,
                                         directory)
                            # Update job_status dict
                            n_basis = n
                            n_real = n - len(ghost)
                            ghost_jobs = '{}-{}r'.format(n_basis, n_real)
                            #                            db[method][ghost_jobs]['total_num_jobs'] = len(mbcp) * len(clusters)
                            #                            db[method][ghost_jobs]['job_status'].update({n_body.ghost_dir(indexes[k],ghost):
                            #                                                                        'not_started'})
                            db[method][n]['total_num_jobs'] = len(mbcp) * len(
                                clusters)
                            db[method][n]['job_status'].update({
                                n_body.ghost_dir(indexes[k], ghost):
                                'not_started'
                            })
                            # Calculate molecular weight
                            totalmass = sum(
                                mol2.mass(i) for i in range(mol2.natom())
                                if mol2.Z(i))
                            totmass = sum(
                                cluster.mass(i) for i in range(cluster.natom())
                                if cluster.Z(i))
                            db[method][n]['MW'].update(
                                {n_body.ghost_dir(indexes[k], ghost): totmass})
                            # Reactivate fragments for next round
                            cluster.set_active_fragments(list(ghost))
                            cluster.update_geometry()
                    # VMFC
                    elif db['bsse'] == 'vmfc':
                        vmfc = []
                        for n_ghost in range(n - 1, 0, -1):
                            vmfc.extend(
                                list(
                                    itertools.combinations(
                                        indexes[k], n_ghost)))
                        for ghost in vmfc:
                            directory = '{}/{}/{}'.format(
                                method, n_body.n_body_dir(n),
                                n_body.ghost_dir(indexes[k], ghost))
                            cluster.set_ghost_fragments(list(ghost))
                            cluster.update_geometry()
                            cluster.set_name('{}_{}'.format(
                                molecule.name(),
                                n_body.ghost_dir(indexes[k], ghost)))
                            n_body.plant(cluster, db, kwargs, method,
                                         directory)
                            # Update job_status dict
                            n_basis = n
                            n_real = n - len(ghost)
                            ghost_jobs = '{}-{}r'.format(n_basis, n_real)
                            #db[method][ghost_jobs]['total_num_jobs'] = len(vmfc) * len(clusters)
                            #                            db[method][ghost_jobs]['total_num_jobs'] = len(list(itertools.combinations(range(0,n),n_real))) * len(clusters)
                            #                            db[method][ghost_jobs]['job_status'].update({n_body.ghost_dir(indexes[k],ghost):
                            #                                                                        'not_started'})
                            db[method][n]['total_num_jobs'] = len(
                                list(
                                    itertools.combinations(
                                        range(0, n), n_real))) * len(clusters)
                            db[method][n]['job_status'].update({
                                n_body.ghost_dir(indexes[k], ghost):
                                'not_started'
                            })
                            # Calculate molecular weight
                            totmass = sum(
                                cluster.mass(i) for i in range(cluster.natom())
                                if cluster.Z(i))
                            db[method][n]['MW'].update(
                                {n_body.ghost_dir(indexes[k], ghost): totmass})
                            # Reactivate fragments for next round
                            cluster.set_active_fragments(list(ghost))
                            cluster.update_geometry()

                    # SSFC or no BSSE
                    else:
                        cluster.set_name('{}_{}'.format(
                            molecule.name(), n_body.cluster_dir(indexes[k])))
                        #molecule.set_name('{}_{}'.format(molecule.name(),cluster_dir(indexes[k])))
                        directory = '{}/{}/{}'.format(
                            method, n_body.n_body_dir(n),
                            n_body.cluster_dir(indexes[k]))
                        n_body.plant(cluster, db, kwargs, method, directory)

                        # Update database job_status dict
                        db[method][n]['job_status'].update(
                            {n_body.cluster_dir(indexes[k]): 'not_started'})
                        # Calculate molecular weight
                        totmass = sum(
                            cluster.mass(i) for i in range(cluster.natom())
                            if cluster.Z(i))
                        db[method][n]['MW'].update(
                            {n_body.cluster_dir(indexes[k]): totmass})
        # Check for zero jobs (happens occasionally due to cutoff)
        for method in db['methods']:
            for n in range(1, db[method]['n_body_max'] + 1):
                if db[method][n]['total_num_jobs'] == 0:
                    db[method]['n_body_max'] = n - 1
                    break
        # Inputs successfully generated
        db['inputs_generated'] = True

    # For now open and close database frequently, until I figure out atexit
    db.close()
    db = shelve.open('database', writeback=True)

    # Check status of jobs
    if not db['jobs_complete']:
        n_incomplete = 0
        # Check all methods
        for method in db['methods'].keys():
            #### NOTE: dft_methods is defunct #####
            #            if method in n_body.dft_methods:
            #                outname = 'input.log'
            #                complete_message = 'Normal termination of Gaussian'
            #            if (method == 'b3lyp'):
            if method in n_body.dft_methods:
                outname = 'input.log'
                complete_message = 'Normal termination of Gaussian'
                error_message = 'Error termination'
            else:
                outname = 'output.dat'
                complete_message = 'Psi4 exiting successfully'
                error_message = 'Psi4 encountered an error'
            # Check all n_body_levels
            print('Before job checking:')
            for field in db[method]['farm']:
                num_fin = db[method][field]['num_jobs_complete']
                tot_num = db[method][field]['total_num_jobs']
                print('{}/{} {}-body jobs finished'.format(
                    num_fin, tot_num, field))
                n_complete = num_fin
                if num_fin != tot_num:
                    db_stat = db[method][field]['job_status']
                    n_complete = 0
                    for job, status in db_stat.items():
                        if status == 'complete':
                            n_complete += 1
                        elif status in ('not_started', 'running', 'error'):
                            try:
                                outfile = open('{}/{}/{}/{}'.format(
                                    method, n_body.n_body_dir(field), job,
                                    outname))
                                for line in outfile:
                                    if complete_message in line:
                                        # This actually marks the job complete as soon as
                                        # the first route section is complete in the case
                                        # of g09, not when the job is totally finished.
                                        db_stat[job] = 'complete'
                                        n_complete += 1
                                        break
                                    elif error_message in line:
                                        db_stat[job] = 'error'
                                        break
                                else:
                                    db_stat[job] = 'running'
                                    n_incomplete += 1
                            except:
                                # this print statement is super annoying, muting it for now
                                #                                print('Exception: probably could not open file for {}'.format(job))
                                n_incomplete += 1
                db[method][field]['num_jobs_complete'] = n_complete
        if n_incomplete == 0:
            db['jobs_complete'] = True

    db.close()
    db = shelve.open('database', writeback=True)

    # Gather results
    if not db['results_computed']:
        for method in db['methods'].keys():
            print('\nAfter job checking:')
            for field in db[method]['farm']:
                num_fin = db[method][field]['num_jobs_complete']
                tot_num = db[method][field]['total_num_jobs']
                print('{}/{} {}-body jobs finished'.format(
                    num_fin, tot_num, field))
                if (db[method][field]['num_jobs_complete'] == db[method][field]
                    ['total_num_jobs']):
                    if db['harvest']:
                        if method in n_body.dft_methods:
                            n_body.harvest_g09(db, method, field)
                        else:
                            n_body.harvest_data(db, method, field)
            if not db['harvest']:
                print("Data harvesting has been disabled.")
            elif not db['cook']:
                print("Data cooking has been disabled.")
            else:
                for field in db[method]['farm']:
                    if (db[method][field]['num_jobs_complete'] == db[method]
                        [field]['total_num_jobs']):
                        n_body.cook_data(db, method, field)
#                       #if db['bsse'] == 'vmfc' and field > 1:
#                       #    n_body.vmfc_cook(db, method, field)
#                       #    n_body.mbcp_cook(db, method, field)
#                       if db['bsse'] == 'vmfc':
#                           n_body.vmfc_cook(db, method, field)
#                           if field > 1:
#                               n_body.mbcp_cook(db, method, field)
#                       elif db['bsse'] == 'mbcp' and field > 1:
#                           n_body.mbcp_cook(db,method,field)
#                       # Future location of an if check for mass adjust or not
#                       if 'rotation' in db[method]['results']:
#                           n_body.mass_adjust_rotations(db,method,field)

    db.close()
    db = shelve.open('database', writeback=True)

    # Print banner to output file including user options
    n_body.banner(db)

    db.close()

    pass
예제 #26
0
def run_psixas(name, **kwargs):
    r"""Function encoding sequence of PSI module and plugin calls so that
    psixas can be called via :py:func:`~driver.energy`. For post-scf plugins.

    >>> energy('psixas')

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

    #print the banner
    printBanner()

    mol = kwargs["molecule"]
    func = kwargs["functional"]

    tmp = psi4.core.get_local_option("PSIXAS", "MODE")
    mode = tmp.split("+")
    if not (all([x in ["GS", "LOC", "EX", "SPEC"] for x in mode])):
        raise Exception("Wrong mode, possible values are GS, LOC, EX, SPEC.")

    if "GS" in mode:
        DFTGroundState(mol,
                       func,
                       PREFIX=psi4.core.get_local_option("PSIXAS", "PREFIX"))

    if "LOC" in mode:
        loc_sub = np.array(psi4.core.get_local_option("PSIXAS", "LOC_SUB"),
                           dtype=np.int)
        wfn = psi4.core.Wavefunction.build(
            mol, psi4.core.get_global_option('BASIS'))

        nbf = wfn.nso()
        sup = psi4.driver.dft.build_superfunctional(func, False)[0]
        sup.set_deriv(2)
        sup.allocate()

        uhf = psi4.core.UHF(wfn, sup)

        prefix = psi4.core.get_local_option("PSIXAS", "PREFIX")
        Ca = np.load(prefix + "_gsorbs.npz")["Ca"]
        Cb = np.load(prefix + "_gsorbs.npz")["Cb"]
        occa = np.load(prefix + "_gsorbs.npz")["occa"]
        occb = np.load(prefix + "_gsorbs.npz")["occb"]
        epsa = np.load(prefix + "_gsorbs.npz")["epsa"]
        epsb = np.load(prefix + "_gsorbs.npz")["epsb"]

        locCa = psi4.core.Matrix(wfn.nso(), len(loc_sub))
        locCb = psi4.core.Matrix(wfn.nso(), len(loc_sub))

        locCa.np[:] = np.copy(Ca[:, loc_sub])
        locCb.np[:] = np.copy(Cb[:, loc_sub])

        LocalA = psi4.core.Localizer.build("PIPEK_MEZEY", wfn.basisset(),
                                           locCa)
        LocalB = psi4.core.Localizer.build("PIPEK_MEZEY", wfn.basisset(),
                                           locCb)

        LocalA.localize()
        LocalB.localize()

        Ca[:, loc_sub] = LocalA.L
        Cb[:, loc_sub] = LocalB.L

        np.savez(prefix + '_gsorbs', Ca=Ca, Cb=Cb, occa=occa, occb=occb)
        psi4.core.print_out("Localized Orbitals written")

        OCCA = psi4.core.Vector(nbf)
        OCCB = psi4.core.Vector(nbf)
        OCCA.np[:] = occa
        OCCB.np[:] = occb

        uhf.Ca().np[:] = Ca
        uhf.Cb().np[:] = Cb

        uhf.epsilon_a().np[:] = epsa
        uhf.epsilon_b().np[:] = epsb

        uhf.occupation_a().np[:] = occa
        uhf.occupation_b().np[:] = occb

        mw = psi4.core.MoldenWriter(uhf)
        mw.write(prefix + '_loc.molden', uhf.Ca(), uhf.Cb(), uhf.epsilon_a(),
                 uhf.epsilon_b(), OCCA, OCCB, True)
        psi4.core.print_out("Moldenfile written\n")

        print("Localize subset")
        print(loc_sub)

    orbitals = []
    if ("EX" in mode):
        orbs = psi4.core.get_local_option("PSIXAS", "ORBS")
        occs = psi4.core.get_local_option("PSIXAS", "OCCS")
        freeze = psi4.core.get_local_option("PSIXAS", "FREEZE")
        spin = psi4.core.get_local_option("PSIXAS", "SPIN")
        ovl = psi4.core.get_local_option("PSIXAS", "OVL")

        lens = [len(x) for x in [orbs, occs, freeze, spin, ovl]]
        if len(list((set(lens)))) > 1:
            raise Exception("Input arrays have inconsistent length" +
                            " ".join(str(lens)))
        for i in range(len(orbs)):
            orbitals.append({
                "orb": orbs[i],
                "spin": spin[i].lower(),
                "occ": occs[i],
                "frz": freeze[i] == "T",
                "DoOvl": ovl[i] == "T"
            })
        DFTExcitedState(mol, func, orbitals)

    if ("SPEC" in mode):
        CalcSpec(mol, func)

    #psixas_wfn = psi4.core.plugin('psixas.so', wfn)

    return 0  #psixas_wfn
예제 #27
0
def nbody_gufunc(func, method_string, **kwargs):
    """
    Computes the nbody interaction energy, gradient, or Hessian depending on input.
    This is a generalized univeral function for computing interaction quantities.

    :returns: *return type of func* |w--w| The interaction data.

    :returns: (*float*, :py:class:`~psi4.core.Wavefunction`) |w--w| interaction data and wavefunction with energy/gradient/hessian set appropriately when **return_wfn** specified.

    :type func: function
    :param func: ``energy`` || etc.

        Python function that accepts method_string and a molecule. Returns a
        energy, gradient, or Hessian as requested.

    :type method_string: string
    :param method_string: ``'scf'`` || ``'mp2'`` || ``'ci5'`` || etc.

        First argument, lowercase and usually unlabeled. Indicates the computational
        method to be passed to func.

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

        The target molecule, if not the last molecule defined.

    :type return_wfn: :ref:`boolean <op_py_boolean>`
    :param return_wfn: ``'on'`` || |dl| ``'off'`` |dr|

        Indicate to additionally return the :py:class:`~psi4.core.Wavefunction`
        calculation result as the second element of a tuple.

    :type bsse_type: string or list
    :param bsse_type: ``'cp'`` || ``['nocp', 'vmfc']`` || |dl| ``None`` |dr| || etc.

        Type of BSSE correction to compute: CP, NoCP, or VMFC. The first in this
        list is returned by this function. By default, this function is not called.

    :type max_nbody: int
    :param max_nbody: ``3`` || etc.

        Maximum n-body to compute, cannot exceed the number of fragments in the moleucle.

    :type ptype: string
    :param ptype: ``'energy'`` || ``'gradient'`` || ``'hessian'``

        Type of the procedure passed in.

    :type return_total_data: :ref:`boolean <op_py_boolean>`
    :param return_total_data: ``'on'`` || |dl| ``'off'`` |dr|

        If True returns the total data (energy/gradient/etc) of the system,
        otherwise returns interaction data.
    """

    # Initialize dictionaries for easy data passing
    metadata, component_results, nbody_results = {}, {}, {}

    # Parse some kwargs
    kwargs = p4util.kwargs_lower(kwargs)
    metadata['ptype'] = kwargs.pop('ptype', None)
    metadata['return_wfn'] = kwargs.pop('return_wfn', False)
    metadata['return_total_data'] = kwargs.pop('return_total_data', False)
    metadata['molecule'] = kwargs.pop('molecule', core.get_active_molecule())
    metadata['molecule'].update_geometry()
    metadata['kwargs'] = kwargs
    core.clean_variables()

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

    # Parse bsse_type, raise exception if not provided or unrecognized
    metadata['bsse_type_list'] = kwargs.pop('bsse_type')
    if metadata['bsse_type_list'] is None:
        raise ValidationError("N-Body GUFunc: Must pass a bsse_type")
    if not isinstance(metadata['bsse_type_list'], list):
        metadata['bsse_type_list'] = [metadata['bsse_type_list']]

    for num, btype in enumerate(metadata['bsse_type_list']):
        metadata['bsse_type_list'][num] = btype.lower()
        if btype.lower() not in ['cp', 'nocp', 'vmfc']:
            raise ValidationError("N-Body GUFunc: bsse_type '%s' is not recognized" % btype.lower())

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

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

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

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

    # Get compute list
    metadata = build_nbody_compute_list(metadata)

    # Compute N-Body components
    component_results = compute_nbody_components(func, method_string, metadata)

    # Assemble N-Body quantities
    nbody_results = assemble_nbody_components(metadata, component_results)

    # Figure out returns
    if metadata['ptype'] != 'energy':
        if metadata['return_total_data']:
            np_final_ptype = nbody_results['ptype_body_dict'][metadata['max_nbody']].copy()
        else:
            np_final_ptype = nbody_results['ptype_body_dict'][metadata['max_nbody']].copy()
            np_final_ptype -= ptype_body_dict[1]

        nbody_results['ret_ptype'] = core.Matrix.from_array(np_final_ptype)
    else:
        nbody_results['ret_ptype'] = nbody_results['ret_energy']

    # Build wfn and bind variables
    wfn = core.Wavefunction.build(metadata['molecule'], 'def2-svp')
    dicts = ['energies', 'ptype', 'intermediates', 'energy_body_dict', 'ptype_body_dict', 'nbody']
    for r in [component_results, nbody_results]:
        for d in r:
            if d in dicts:
                for var, value in r[d].items():
                    wfn.set_variable(str(var), value)
                    core.set_variable(str(var), value)

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

    core.set_variable("CURRENT ENERGY", nbody_results['ret_energy'])
    wfn.set_variable("CURRENT ENERGY", nbody_results['ret_energy'])

    if metadata['return_wfn']:
        return (nbody_results['ret_ptype'], wfn)
    else:
        return nbody_results['ret_ptype']
예제 #28
0
def run_forte(name, **kwargs):
    r"""Function encoding sequence of PSI module and plugin calls so that
    forte can be called via :py:func:`~driver.energy`. For post-scf plugins.

    >>> energy('forte')

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

    # Compute a SCF reference, a wavefunction is return which holds the molecule used, orbitals
    # Fock matrices, and more
    ref_wfn = kwargs.get('ref_wfn', None)
    if ref_wfn is None:
        ref_wfn = psi4.driver.scf_helper(name, **kwargs)

    # Get the option object
    options = psi4.core.get_options()
    options.set_current_module('FORTE')
    forte.forte_options.update_psi_options(options)

    if ('DF' in options.get_str('INT_TYPE')):
        aux_basis = psi4.core.BasisSet.build(
            ref_wfn.molecule(), 'DF_BASIS_MP2',
            psi4.core.get_global_option('DF_BASIS_MP2'), 'RIFIT',
            psi4.core.get_global_option('BASIS'))
        ref_wfn.set_basisset('DF_BASIS_MP2', aux_basis)

    if (options.get_str('MINAO_BASIS')):
        minao_basis = psi4.core.BasisSet.build(ref_wfn.molecule(),
                                               'MINAO_BASIS',
                                               options.get_str('MINAO_BASIS'))
        ref_wfn.set_basisset('MINAO_BASIS', minao_basis)

    # Start Forte, initialize ambit
    my_proc_n_nodes = forte.startup()
    my_proc, n_nodes = my_proc_n_nodes

    # Print the banner
    forte.banner()

    # Create the MOSpaceInfo object
    mo_space_info = forte.make_mo_space_info(ref_wfn, forte.forte_options)

    # Create the AO subspace projector
    ps = forte.make_aosubspace_projector(ref_wfn, options)

    state = forte.make_state_info_from_psi_wfn(ref_wfn)
    scf_info = forte.SCFInfo(ref_wfn)
    state_weights_map = forte.make_state_weights_map(forte.forte_options,
                                                     ref_wfn)

    # Run a method
    job_type = options.get_str('JOB_TYPE')

    energy = 0.0
    if job_type != 'NONE':
        start = timeit.timeit()

        # Make an integral object
        ints = forte.make_forte_integrals(ref_wfn, options, mo_space_info)

        # Rotate orbitals before computation
        orb_type = options.get_str("ORBITAL_TYPE")
        if orb_type != 'CANONICAL':
            orb_t = forte.make_orbital_transformation(orb_type, scf_info,
                                                      forte.forte_options,
                                                      ints, mo_space_info)
            orb_t.compute_transformation()
            Ua = orb_t.get_Ua()
            Ub = orb_t.get_Ub()

            ints.rotate_orbitals(Ua, Ub)

        # Run a method
        if (job_type == 'NEWDRIVER'):
            energy = forte_driver(state_weights_map, scf_info,
                                  forte.forte_options, ints, mo_space_info)
        else:
            energy = forte.forte_old_methods(ref_wfn, options, ints,
                                             mo_space_info)

        end = timeit.timeit()
        #print('\n\n  Your calculation took ', (end - start), ' seconds');

    # Close ambit, etc.
    forte.cleanup()

    psi4.core.set_scalar_variable('CURRENT ENERGY', energy)
    return ref_wfn
예제 #29
0
def prepare_psi4_ref_wfn(options, **kwargs):
    """
    Prepare a Psi4 Wavefunction as reference for Forte.
    :param options: a ForteOptions object for options
    :param kwargs: named arguments associated with Psi4
    :return: (the processed Psi4 Wavefunction, a Forte MOSpaceInfo object)

    Notes:
        We will create a new Psi4 Wavefunction (wfn_new) if necessary.

        1. For an empty ref_wfn, wfn_new will come from Psi4 SCF or MCSCF.

        2. For a valid ref_wfn, we will test the orbital orthonormality against molecule.
           If the orbitals from ref_wfn are consistent with the active geometry,
           wfn_new will simply be a link to ref_wfn.
           If not, we will rerun a Psi4 SCF and orthogonalize orbitals, where
           wfn_new comes from this new Psi4 SCF computation.
    """
    p4print = psi4.core.print_out

    # grab reference Wavefunction and Molecule from kwargs
    kwargs = p4util.kwargs_lower(kwargs)

    ref_wfn = kwargs.get('ref_wfn', None)

    molecule = kwargs.pop('molecule', psi4.core.get_active_molecule())
    point_group = molecule.point_group().symbol()

    # try to read orbitals from file
    Ca = read_orbitals() if options.get_bool('READ_ORBITALS') else None

    need_orbital_check = True
    fresh_ref_wfn = True if ref_wfn is None else False

    if ref_wfn is None:
        ref_type = options.get_str('REF_TYPE')
        p4print('\n  No reference wave function provided for Forte.'
                f' Computing {ref_type} orbitals using Psi4 ...\n')

        # no warning printing for MCSCF
        job_type = options.get_str('JOB_TYPE')
        do_mcscf = (job_type in ["CASSCF", "MCSCF_TWO_STEP"]
                    or options.get_bool("CASSCF_REFERENCE"))

        # run Psi4 SCF or MCSCF
        ref_wfn = run_psi4_ref(ref_type, molecule, not do_mcscf, **kwargs)

        need_orbital_check = False if Ca is None else True
    else:
        # Ca from file has higher priority than that of ref_wfn
        Ca = ref_wfn.Ca().clone() if Ca is None else Ca

    # build Forte MOSpaceInfo
    nmopi = ref_wfn.nmopi()
    mo_space_info = forte.make_mo_space_info(nmopi, point_group, options)

    # do we need to check MO overlap?
    if not need_orbital_check:
        wfn_new = ref_wfn
    else:
        # test if input Ca has the correct dimension
        if Ca.rowdim() != nmopi or Ca.coldim() != nmopi:
            raise ValueError(
                "Invalid orbitals: different basis set / molecule")

        new_S = psi4.core.Wavefunction.build(molecule,
                                             options.get_str("BASIS")).S()

        if check_MO_orthonormality(new_S, Ca):
            wfn_new = ref_wfn
            wfn_new.Ca().copy(Ca)
        else:
            if fresh_ref_wfn:
                wfn_new = ref_wfn
                wfn_new.Ca().copy(ortho_orbs_forte(wfn_new, mo_space_info, Ca))
            else:
                p4print("\n  Perform new SCF at current geometry ...\n")

                kwargs_copy = {
                    k: v
                    for k, v in kwargs.items() if k != 'ref_wfn'
                }
                wfn_new = run_psi4_ref('scf', molecule, False, **kwargs_copy)

                # orthonormalize orbitals
                wfn_new.Ca().copy(ortho_orbs_forte(wfn_new, mo_space_info, Ca))

                # copy wfn_new to ref_wfn
                ref_wfn.shallow_copy(wfn_new)

    # set DF and MINAO basis
    if 'DF' in options.get_str('INT_TYPE'):
        aux_basis = psi4.core.BasisSet.build(molecule, 'DF_BASIS_MP2',
                                             options.get_str('DF_BASIS_MP2'),
                                             'RIFIT', options.get_str('BASIS'))
        wfn_new.set_basisset('DF_BASIS_MP2', aux_basis)

    if options.get_str('MINAO_BASIS'):
        minao_basis = psi4.core.BasisSet.build(molecule, 'MINAO_BASIS',
                                               options.get_str('MINAO_BASIS'))
        wfn_new.set_basisset('MINAO_BASIS', minao_basis)

    return wfn_new, mo_space_info
예제 #30
0
def gradient_forte(name, **kwargs):
    r"""Function encoding sequence of PSI module and plugin calls so that
    forte can be called via :py:func:`~driver.energy`. For post-scf plugins.

    >>> gradient('forte') 
        available for : CASSCF

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

    # Compute a SCF reference, a wavefunction is return which holds the molecule used, orbitals
    # Fock matrices, and more
    ref_wfn = kwargs.get('ref_wfn', None)
    if ref_wfn is None:
        ref_wfn = psi4.driver.scf_helper(name, **kwargs)

    # Get the psi4 option object
    optstash = p4util.OptionsState(['GLOBALS', 'DERTYPE'])
    psi4_options = psi4.core.get_options()
    psi4_options.set_current_module('FORTE')

    # Get the forte option object
    options = forte.forte_options
    options.get_options_from_psi4(psi4_options)

    if ('DF' in options.get_str('INT_TYPE')):
        raise Exception('analytic gradient is not implemented for density fitting')

    if (options.get_str('MINAO_BASIS')):
        minao_basis = psi4.core.BasisSet.build(ref_wfn.molecule(), 'MINAO_BASIS',
                                               options.get_str('MINAO_BASIS'))
        ref_wfn.set_basisset('MINAO_BASIS', minao_basis)

    # Start Forte, initialize ambit
    my_proc_n_nodes = forte.startup()
    my_proc, n_nodes = my_proc_n_nodes

    # Print the banner
    forte.banner()

    # Create the MOSpaceInfo object
    mo_space_info = forte.make_mo_space_info(ref_wfn, options)

    # Call methods that project the orbitals (AVAS, embedding)
    mo_space_info = orbital_projection(ref_wfn, options, mo_space_info)

    state = forte.make_state_info_from_psi_wfn(ref_wfn)
    scf_info = forte.SCFInfo(ref_wfn)
    state_weights_map = forte.make_state_weights_map(options,ref_wfn)

    # Run a method
    job_type = options.get_str('JOB_TYPE')

    energy = 0.0

    if not job_type == 'CASSCF':
        raise Exception('analytic gradient is only implemented for CASSCF')

    start = time.time()

    # Make an integral object
    ints = forte.make_forte_integrals(ref_wfn, options, mo_space_info)

    # Rotate orbitals before computation
    orb_type = options.get_str("ORBITAL_TYPE")
    if orb_type != 'CANONICAL':
        orb_t = forte.make_orbital_transformation(orb_type, scf_info, options, ints, mo_space_info)
        orb_t.compute_transformation()
        Ua = orb_t.get_Ua()
        Ub = orb_t.get_Ub()

        ints.rotate_orbitals(Ua,Ub)

    # Run gradient computation
    energy = forte.forte_old_methods(ref_wfn, options, ints, mo_space_info)
    derivobj = psi4.core.Deriv(ref_wfn)
    derivobj.set_deriv_density_backtransformed(True)
    derivobj.set_ignore_reference(True)
    grad = derivobj.compute() #psi4.core.DerivCalcType.Correlated
    ref_wfn.set_gradient(grad)    
    optstash.restore()        

    end = time.time()
    #print('\n\n  Your calculation took ', (end - start), ' seconds');

    # Close ambit, etc.
    forte.cleanup()

    return ref_wfn
예제 #31
0
def nbody_gufunc(func, method_string, **kwargs):
    """
    Computes the nbody interaction energy, gradient, or Hessian depending on input.
    This is a generalized univeral function for computing interaction quantities.

    :returns: *return type of func* |w--w| The interaction data.

    :returns: (*float*, :ref:`Wavefunction<sec:psimod_Wavefunction>`) |w--w| interaction data and wavefunction with energy/gradient/hessian set appropriately when **return_wfn** specified.

    :type func: function
    :param func: ``energy`` || etc.

        Python function that accepts method_string and a molecule. Returns a
        energy, gradient, or Hessian as requested.

    :type method_string: string
    :param method_string: ``'scf'`` || ``'mp2'`` || ``'ci5'`` || etc.

        First argument, lowercase and usually unlabeled. Indicates the computational
        method to be passed to func.

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

        The target molecule, if not the last molecule defined.

    :type return_wfn: :ref:`boolean <op_py_boolean>`
    :param return_wfn: ``'on'`` || |dl| ``'off'`` |dr|

        Indicate to additionally return the :ref:`Wavefunction<sec:psimod_Wavefunction>`
        calculation result as the second element of a tuple.

    :type bsse_type: string or list
    :param bsse_type: ``'cp'`` || ``['nocp', 'vmfc']`` || |dl| ``None`` |dr| || etc.

        Type of BSSE correction to compute: CP, NoCP, or VMFC. The first in this
        list is returned by this function. By default, this function is not called.

    :type max_nbody: int
    :param max_nbody: ``3`` || etc.

        Maximum n-body to compute, cannot exceed the number of fragments in the moleucle.

    :type ptype: string
    :param ptype: ``'energy'`` || ``'gradient'`` || ``'hessian'``

        Type of the procedure passed in.

    :type return_total_data: :ref:`boolean <op_py_boolean>`
    :param return_total_data: ``'on'`` || |dl| ``'off'`` |dr|

        If True returns the total data (energy/gradient/etc) of the system,
        otherwise returns interaction data.
    """

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

    molecule_total_atoms = sum(fragment_size_dict.values())

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

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

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

            core.clean()

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

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

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

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

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

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

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

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

        # Do ptype
        if ptype != 'energy':
            _sum_cluster_ptype_data(ptype, ptype_dict, cp_compute_list[n],
                                    fragment_slice_dict, fragment_size_dict,
                                    cp_ptype_by_level[n])
            _sum_cluster_ptype_data(ptype, ptype_dict, nocp_compute_list[n],
                                    fragment_slice_dict, fragment_size_dict,
                                    nocp_ptype_by_level[n])
            _sum_cluster_ptype_data(ptype,
                                    ptype_dict,
                                    vmfc_level_list[n],
                                    fragment_slice_dict,
                                    fragment_size_dict,
                                    vmfc_ptype_by_level[n],
                                    vmfc=True)

    # Compute cp energy and ptype
    if do_cp:
        for n in nbody_range:
            if n == max_frag:
                cp_energy_body_dict[n] = cp_energy_by_level[n]
                if ptype != 'energy':
                    cp_ptype_body_dict[n][:] = cp_ptype_by_level[n]
                continue

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

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

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

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

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

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

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

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

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

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

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

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

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

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

            ret_ptype = core.Matrix.from_array(np_final_ptype)
    else:
        ret_ptype = ret_energy

    # Build and set a wavefunction
    wfn = core.Wavefunction.build(molecule, 'sto-3g')
    wfn.cdict["nbody_energy"] = energies_dict
    wfn.cdict["nbody_ptype"] = ptype_dict
    wfn.cdict["nbody_body_energy"] = energy_body_dict
    wfn.cdict["nbody_body_ptype"] = ptype_body_dict

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

    core.set_variable("CURRENT ENERGY", ret_energy)

    if return_wfn:
        return (ret_ptype, wfn)
    else:
        return ret_ptype
예제 #32
0
def run_efp_gamess(name, **kwargs):
    r"""Function encoding sequence of PSI module and plugin calls so that
    efp_gamess can be called via :py:func:`~driver.energy`. For post-scf plugins.

    >>> energy('efp_gamess')

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

    # Your plugin's psi4 run sequence goes here
    psi4.core.set_local_option('MYPLUGIN', 'PRINT', 1)

    # Compute a SCF reference, a wavefunction is return which holds the molecule used, orbitals
    # Fock matrices, and more
    print('Attention! This SCF may be density-fitted.')
    ref_wfn = kwargs.get('ref_wfn', None)
    if ref_wfn is None:
        ref_wfn = psi4.driver.scf_helper(name, **kwargs)

    # Ensure IWL files have been written when not using DF/CD
    proc_util.check_iwl_file_from_scf_type(
        psi4.core.get_option('SCF', 'SCF_TYPE'), ref_wfn)

    # Call the Psi4 plugin
    # Please note that setting the reference wavefunction in this way is ONLY for plugins
    # This prints a bound python method
    print("\nPrinting ref_wfn.Fa")
    print(ref_wfn.Fa)
    # This defines a psi4.core.Matrix object and prints it
    print("\nPrinting np.asarray(ref_wfn.Fa())")
    print(np.asarray(ref_wfn.Fa()))
    #Farray=np.asarray(ref_wfn.Fa())
    Farray = ref_wfn.Fa().to_array()
    print("\nPrinting Farray, which is np.asarray(ref_wfn.Fa())")
    print(Farray)

    print("\nPrinting Farray asarray")
    print(np.asarray(Farray))
    # I think this does nothing different from the above
    Fa = ref_wfn.Fa()
    print("\nPrinting Fa=ref_wfn.Fa()")
    print(Fa)
    print("\nPrinting np.asarray(Fa)")
    print(np.asarray(Fa))
    # This prints to the output the matrix values
    #Fa.print_out()
    # This actually changes Fa and the ref_wfn Fa value
    #Fa.set(0,0,0.0)
    #Fa.print_out()
    #ref_wfn.Fa=Fa
    # Tests my previous assertion about ref_wfn changes
    #Fa_zeroed=ref_wfn.Fa()
    #Fa_zeroed.print_out()

    # Change return name to the trans matrix I'm trying to send back
    #efp_gamess_wfn = psi4.core.plugin('efp_gamess.so', ref_wfn)

    psi4.core.set_local_option('efp_gamess', 'coleman', 0)

    trans_mat_c = psi4.core.plugin('efp_gamess.so', ref_wfn)
    print("\nPrinting C transformation matrix")
    print(trans_mat_c)
    print("\nPrinting C transformation matrix (as array)")
    print(np.asarray(trans_mat_c))
    trans_mat_c.print_out()

    psi4.core.print_out("\nalright coleman H coming now")
    psi4.core.set_local_option('efp_gamess', 'coleman', 1)

    trans_mat_h = psi4.core.plugin('efp_gamess.so', ref_wfn)
    print("\nPrinting H transformation matrix")
    print(trans_mat_h)
    print("\nPrinting H transformation matrix (as array)")
    print(np.asarray(trans_mat_h))
    trans_mat_h.print_out()

    # Define hdf5 file
    f = h5py.File("form.h5", "r")
    group = f["EFPcalc"]
    print("\nListing dataset in h5 file EFPcalc group")
    print(list(group.keys()))
    fock_dset = group['CONVERGED TOTAL FOCK MATRIX']
    fock_np = np.array(fock_dset)
    print("\nGAMESS Fock matrix as numpy array")
    print(fock_np)
    mo_dset = group['MO_coeff']
    mo_np = np.array(mo_dset)
    print("\nGAMESS MO coeficients")
    print(mo_np)

    print("\nPSI4 MO coefficients")
    print("\nTransforming MO coefficients")
    psi4_C = np.matmul(trans_mat_c, np.transpose(mo_np))
    print("\nTransformed MO coefficients")
    print(psi4_C)

    # Test adding these together
    #print("Adding np.asarray(trans_mat_h)+np.asarray(trans_mat_c)\n")
    #test_sum=np.asarray(trans_mat_h)+np.asarray(trans_mat_c)
    #print(test_sum)

    #test_sum2=np.asarray(Fa)+np.asarray(trans_mat_c)
    #print(test_sum2)
    #test_sum.print_out()
    # Find out what trans_mat is (it's like the others)
    #print(trans_mat)
    # print actual values
    #trans_mat.print_out()

    # Change return to original ref_wfn, hopefully changed
    #return efp_gamess_wfn
    return ref_wfn
예제 #33
0
파일: driver_nbody.py 프로젝트: q2kuhn/psi4
def nbody_gufunc(func: Union[str, Callable], method_string: str, **kwargs):
    """
    Computes the nbody interaction energy, gradient, or Hessian depending on input.
    This is a generalized univeral function for computing interaction and total quantities.

    :returns: *return type of func* |w--w| The data.

    :returns: (*float*, :py:class:`~psi4.core.Wavefunction`) |w--w| data and wavefunction with energy/gradient/hessian set appropriately when **return_wfn** specified.

    :type func: Callable
    :param func: ``energy`` || etc.

        Python function that accepts method_string and a molecule. Returns a
        energy, gradient, or Hessian as requested.

    :type method_string: str
    :param method_string: ``'scf'`` || ``'mp2'`` || ``'ci5'`` || etc.

        First argument, lowercase and usually unlabeled. Indicates the computational
        method to be passed to func.

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

        The target molecule, if not the last molecule defined.

    :type return_wfn: :ref:`boolean <op_py_boolean>`
    :param return_wfn: ``'on'`` || |dl| ``'off'`` |dr|

        Indicate to additionally return the :py:class:`~psi4.core.Wavefunction`
        calculation result as the second element of a tuple.

    :type bsse_type: str or list
    :param bsse_type: ``'cp'`` || ``['nocp', 'vmfc']`` || |dl| ``None`` |dr| || etc.

        Type of BSSE correction to compute: CP, NoCP, or VMFC. The first in this
        list is returned by this function. By default, this function is not called.

    :type max_nbody: int
    :param max_nbody: ``3`` || etc.

        Maximum n-body to compute, cannot exceed the number of fragments in the moleucle.

    :type ptype: str
    :param ptype: ``'energy'`` || ``'gradient'`` || ``'hessian'``

        Type of the procedure passed in.

    :type return_total_data: :ref:`boolean <op_py_boolean>`
    :param return_total_data: ``'on'`` || |dl| ``'off'`` |dr|

        If True returns the total data (energy/gradient/etc) of the system,
        otherwise returns interaction data.

    :type levels: dict
    :param levels: ``{1: 'ccsd(t)', 2: 'mp2', 'supersystem': 'scf'}`` || ``{1: 2, 2: 'ccsd(t)', 3: 'mp2'}`` || etc

        Dictionary of different levels of theory for different levels of expansion
        Note that method_string is not used in this case.
        supersystem computes all higher order n-body effects up to nfragments.

    :type embedding_charges: dict
    :param embedding_charges: ``{1: [-0.834, 0.417, 0.417], ..}``

        Dictionary of atom-centered point charges. keys: 1-based index of fragment, values: list of charges for each fragment.

    :type charge_method: str
    :param charge_method: ``scf/6-31g`` || ``b3lyp/6-31g*`` || etc

        Method to compute point charges for monomers. Overridden by embedding_charges if both are provided.

    :type charge_type: str
    :param charge_type: ``MULLIKEN_CHARGES`` || ``LOWDIN_CHARGES`` 

        Default is ``MULLIKEN_CHARGES``
    """

    # Initialize dictionaries for easy data passing
    metadata, component_results, nbody_results = {}, {}, {}

    # Parse some kwargs
    kwargs = p4util.kwargs_lower(kwargs)
    if kwargs.get('levels', False):
        return driver_nbody_helper.multi_level(func, **kwargs)
    metadata['ptype'] = kwargs.pop('ptype', None)
    metadata['return_wfn'] = kwargs.pop('return_wfn', False)
    metadata['return_total_data'] = kwargs.pop('return_total_data', False)
    metadata['molecule'] = kwargs.pop('molecule', core.get_active_molecule())
    metadata['molecule'].update_geometry()
    metadata['molecule'].fix_com(True)
    metadata['molecule'].fix_orientation(True)
    metadata['embedding_charges'] = kwargs.get('embedding_charges', False)
    metadata['kwargs'] = kwargs
    core.clean_variables()

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

    # Parse bsse_type, raise exception if not provided or unrecognized
    metadata['bsse_type_list'] = kwargs.pop('bsse_type')
    if metadata['bsse_type_list'] is None:
        raise ValidationError("N-Body GUFunc: Must pass a bsse_type")
    if not isinstance(metadata['bsse_type_list'], list):
        metadata['bsse_type_list'] = [metadata['bsse_type_list']]

    for num, btype in enumerate(metadata['bsse_type_list']):
        metadata['bsse_type_list'][num] = btype.lower()
        if btype.lower() not in ['cp', 'nocp', 'vmfc']:
            raise ValidationError(
                "N-Body GUFunc: bsse_type '%s' is not recognized" %
                btype.lower())

    metadata['max_nbody'] = kwargs.get('max_nbody', -1)
    if metadata['molecule'].nfragments() == 1:
        raise ValidationError(
            "N-Body requires active molecule to have more than 1 fragment.")
    metadata['max_frag'] = metadata['molecule'].nfragments()
    if metadata['max_nbody'] == -1:
        metadata['max_nbody'] = metadata['molecule'].nfragments()
    else:
        metadata['max_nbody'] = min(metadata['max_nbody'],
                                    metadata['max_frag'])

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

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

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

    # Get compute list
    metadata = build_nbody_compute_list(metadata)

    # Compute N-Body components
    component_results = compute_nbody_components(func, method_string, metadata)

    # Assemble N-Body quantities
    nbody_results = assemble_nbody_components(metadata, component_results)

    # Build wfn and bind variables
    wfn = core.Wavefunction.build(metadata['molecule'], 'def2-svp')
    dicts = [
        'energies', 'ptype', 'intermediates', 'energy_body_dict',
        'gradient_body_dict', 'hessian_body_dict', 'nbody',
        'cp_energy_body_dict', 'nocp_energy_body_dict', 'vmfc_energy_body_dict'
    ]
    if metadata['ptype'] == 'gradient':
        wfn.set_gradient(nbody_results['ret_ptype'])
        nbody_results['gradient_body_dict'] = nbody_results['ptype_body_dict']
    elif metadata['ptype'] == 'hessian':
        nbody_results['hessian_body_dict'] = nbody_results['ptype_body_dict']
        wfn.set_hessian(nbody_results['ret_ptype'])
        component_results_gradient = component_results.copy()
        component_results_gradient['ptype'] = component_results_gradient[
            'gradients']
        metadata['ptype'] = 'gradient'
        nbody_results_gradient = assemble_nbody_components(
            metadata, component_results_gradient)
        wfn.set_gradient(nbody_results_gradient['ret_ptype'])
        nbody_results['gradient_body_dict'] = nbody_results_gradient[
            'ptype_body_dict']

    for r in [component_results, nbody_results]:
        for d in r:
            if d in dicts:
                for var, value in r[d].items():
                    try:
                        wfn.set_scalar_variable(str(var), value)
                        core.set_scalar_variable(str(var), value)
                    except:
                        wfn.set_array_variable(
                            d.split('_')[0].upper() + ' ' + str(var),
                            core.Matrix.from_array(value))

    core.set_variable("CURRENT ENERGY", nbody_results['ret_energy'])
    wfn.set_variable("CURRENT ENERGY", nbody_results['ret_energy'])
    if metadata['ptype'] == 'gradient':
        core.set_variable("CURRENT GRADIENT", nbody_results['ret_ptype'])
    elif metadata['ptype'] == 'hessian':
        core.set_variable("CURRENT HESSIAN", nbody_results['ret_ptype'])

    if metadata['return_wfn']:
        return (nbody_results['ret_ptype'], wfn)
    else:
        return nbody_results['ret_ptype']
예제 #34
0
def nbody_gufunc(func, method_string, **kwargs):
    """
    Computes the nbody interaction energy, gradient, or Hessian depending on input.
    This is a generalized univeral function for computing interaction quantities.

    :returns: *return type of func* |w--w| The interaction data.

    :returns: (*float*, :py:class:`~psi4.core.Wavefunction`) |w--w| interaction data and wavefunction with energy/gradient/hessian set appropriately when **return_wfn** specified.

    :type func: function
    :param func: ``energy`` || etc.

        Python function that accepts method_string and a molecule. Returns a
        energy, gradient, or Hessian as requested.

    :type method_string: string
    :param method_string: ``'scf'`` || ``'mp2'`` || ``'ci5'`` || etc.

        First argument, lowercase and usually unlabeled. Indicates the computational
        method to be passed to func.

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

        The target molecule, if not the last molecule defined.

    :type return_wfn: :ref:`boolean <op_py_boolean>`
    :param return_wfn: ``'on'`` || |dl| ``'off'`` |dr|

        Indicate to additionally return the :py:class:`~psi4.core.Wavefunction`
        calculation result as the second element of a tuple.

    :type bsse_type: string or list
    :param bsse_type: ``'cp'`` || ``['nocp', 'vmfc']`` || |dl| ``None`` |dr| || etc.

        Type of BSSE correction to compute: CP, NoCP, or VMFC. The first in this
        list is returned by this function. By default, this function is not called.

    :type max_nbody: int
    :param max_nbody: ``3`` || etc.

        Maximum n-body to compute, cannot exceed the number of fragments in the moleucle.

    :type ptype: string
    :param ptype: ``'energy'`` || ``'gradient'`` || ``'hessian'``

        Type of the procedure passed in.

    :type return_total_data: :ref:`boolean <op_py_boolean>`
    :param return_total_data: ``'on'`` || |dl| ``'off'`` |dr|

        If True returns the total data (energy/gradient/etc) of the system,
        otherwise returns interaction data.
    """

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

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

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

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

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

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

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

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

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


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


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

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

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

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

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


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

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

    molecule_total_atoms = sum(fragment_size_dict.values())

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

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

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

            core.clean()

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

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

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

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

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


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

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

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


        # Do ptype
        if ptype != 'energy':
            _sum_cluster_ptype_data(ptype, ptype_dict, cp_compute_list[n],
                                      fragment_slice_dict, fragment_size_dict,
                                      cp_ptype_by_level[n])
            _sum_cluster_ptype_data(ptype, ptype_dict, nocp_compute_list[n],
                                      fragment_slice_dict, fragment_size_dict,
                                      nocp_ptype_by_level[n])
            _sum_cluster_ptype_data(ptype, ptype_dict, vmfc_level_list[n],
                                      fragment_slice_dict, fragment_size_dict,
                                      vmfc_ptype_by_level[n], vmfc=True)

    # Compute cp energy and ptype
    if do_cp:
        for n in nbody_range:
            if n == max_frag:
                cp_energy_body_dict[n] = cp_energy_by_level[n]
                if ptype != 'energy':
                    cp_ptype_body_dict[n][:] = cp_ptype_by_level[n]
                continue

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

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

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

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

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

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

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

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

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


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

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

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


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


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

            ret_ptype = core.Matrix.from_array(np_final_ptype)
    else:
        ret_ptype = ret_energy

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

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

    core.set_variable("CURRENT ENERGY", ret_energy)

    if return_wfn:
        return (ret_ptype, wfn)
    else:
        return ret_ptype
예제 #35
0
def nbody_gufunc(func, method_string, **kwargs):
    """
    Computes the nbody interaction energy, gradient, or Hessian depending on input.
    This is a generalized univeral function for computing interaction and total quantities.

    :returns: *return type of func* |w--w| The data.

    :returns: (*float*, :py:class:`~psi4.core.Wavefunction`) |w--w| data and wavefunction with energy/gradient/hessian set appropriately when **return_wfn** specified.

    :type func: function
    :param func: ``energy`` || etc.

        Python function that accepts method_string and a molecule. Returns a
        energy, gradient, or Hessian as requested.

    :type method_string: string
    :param method_string: ``'scf'`` || ``'mp2'`` || ``'ci5'`` || etc.

        First argument, lowercase and usually unlabeled. Indicates the computational
        method to be passed to func.

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

        The target molecule, if not the last molecule defined.

    :type return_wfn: :ref:`boolean <op_py_boolean>`
    :param return_wfn: ``'on'`` || |dl| ``'off'`` |dr|

        Indicate to additionally return the :py:class:`~psi4.core.Wavefunction`
        calculation result as the second element of a tuple.

    :type bsse_type: string or list
    :param bsse_type: ``'cp'`` || ``['nocp', 'vmfc']`` || |dl| ``None`` |dr| || etc.

        Type of BSSE correction to compute: CP, NoCP, or VMFC. The first in this
        list is returned by this function. By default, this function is not called.

    :type max_nbody: int
    :param max_nbody: ``3`` || etc.

        Maximum n-body to compute, cannot exceed the number of fragments in the moleucle.

    :type ptype: string
    :param ptype: ``'energy'`` || ``'gradient'`` || ``'hessian'``

        Type of the procedure passed in.

    :type return_total_data: :ref:`boolean <op_py_boolean>`
    :param return_total_data: ``'on'`` || |dl| ``'off'`` |dr|

        If True returns the total data (energy/gradient/etc) of the system,
        otherwise returns interaction data.

    :type levels: dict
    :param levels: ``{1: 'ccsd(t)', 2: 'mp2', 'supersystem': 'scf'}`` || ``{1: 2, 2: 'ccsd(t)', 3: 'mp2'}`` || etc

        Dictionary of different levels of theory for different levels of expansion
        Note that method_string is not used in this case.
        supersystem computes all higher order n-body effects up to nfragments.

    :type embedding_charges: dict
    :param embedding_charges: ``{1: [-0.834, 0.417, 0.417], ..}``

        Dictionary of atom-centered point charges. keys: 1-based index of fragment, values: list of charges for each fragment.

    :type charge_method: string
    :param charge_method: ``scf/6-31g`` || ``b3lyp/6-31g*`` || etc

        Method to compute point charges for monomers. Overridden by embedding_charges if both are provided.

    :type charge_type: string
    :param charge_type: ``MULLIKEN_CHARGES`` || ``LOWDIN_CHARGES`` 

        Default is ``MULLIKEN_CHARGES``
    """

    # Initialize dictionaries for easy data passing
    metadata, component_results, nbody_results = {}, {}, {}

    # Parse some kwargs
    kwargs = p4util.kwargs_lower(kwargs)
    if kwargs.get('levels', False):
        return driver_nbody_helper.multi_level(func, **kwargs)
    metadata['ptype'] = kwargs.pop('ptype', None)
    metadata['return_wfn'] = kwargs.pop('return_wfn', False)
    metadata['return_total_data'] = kwargs.pop('return_total_data', False)
    metadata['molecule'] = kwargs.pop('molecule', core.get_active_molecule())
    metadata['molecule'].update_geometry()
    metadata['molecule'].fix_com(True)
    metadata['molecule'].fix_orientation(True)
    metadata['embedding_charges'] = kwargs.get('embedding_charges', False)
    metadata['kwargs'] = kwargs
    core.clean_variables()

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

    # Parse bsse_type, raise exception if not provided or unrecognized
    metadata['bsse_type_list'] = kwargs.pop('bsse_type')
    if metadata['bsse_type_list'] is None:
        raise ValidationError("N-Body GUFunc: Must pass a bsse_type")
    if not isinstance(metadata['bsse_type_list'], list):
        metadata['bsse_type_list'] = [metadata['bsse_type_list']]

    for num, btype in enumerate(metadata['bsse_type_list']):
        metadata['bsse_type_list'][num] = btype.lower()
        if btype.lower() not in ['cp', 'nocp', 'vmfc']:
            raise ValidationError("N-Body GUFunc: bsse_type '%s' is not recognized" % btype.lower())

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

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

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

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

    # Get compute list
    metadata = build_nbody_compute_list(metadata)

    # Compute N-Body components
    component_results = compute_nbody_components(func, method_string, metadata)

    # Assemble N-Body quantities
    nbody_results = assemble_nbody_components(metadata, component_results)

    # Build wfn and bind variables
    wfn = core.Wavefunction.build(metadata['molecule'], 'def2-svp')
    dicts = [
        'energies', 'ptype', 'intermediates', 'energy_body_dict', 'gradient_body_dict', 'hessian_body_dict', 'nbody',
        'cp_energy_body_dict', 'nocp_energy_body_dict', 'vmfc_energy_body_dict'
    ]
    if metadata['ptype'] == 'gradient':
        wfn.set_gradient(nbody_results['ret_ptype'])
        nbody_results['gradient_body_dict'] = nbody_results['ptype_body_dict']
    elif metadata['ptype'] == 'hessian':
        nbody_results['hessian_body_dict'] = nbody_results['ptype_body_dict']
        wfn.set_hessian(nbody_results['ret_ptype'])
        component_results_gradient = component_results.copy()
        component_results_gradient['ptype'] = component_results_gradient['gradients']
        metadata['ptype'] = 'gradient'
        nbody_results_gradient = assemble_nbody_components(metadata, component_results_gradient)
        wfn.set_gradient(nbody_results_gradient['ret_ptype'])
        nbody_results['gradient_body_dict'] = nbody_results_gradient['ptype_body_dict']

    for r in [component_results, nbody_results]:
        for d in r:
            if d in dicts:
                for var, value in r[d].items():
                    try:
                        wfn.set_scalar_variable(str(var), value)
                        core.set_scalar_variable(str(var), value)
                    except:
                        wfn.set_array_variable(d.split('_')[0].upper() + ' ' + str(var), core.Matrix.from_array(value))

    core.set_variable("CURRENT ENERGY", nbody_results['ret_energy'])
    wfn.set_variable("CURRENT ENERGY", nbody_results['ret_energy'])

    if metadata['return_wfn']:
        return (nbody_results['ret_ptype'], wfn)
    else:
        return nbody_results['ret_ptype']
예제 #36
0
파일: frac.py 프로젝트: dsirianni/psi4
def frac_nuke(name, **kwargs):
    """Pull all the electrons out, one at a time"""
    optstash = p4util.OptionsState(
        ['SCF', 'GUESS'],
        ['SCF', 'DF_INTS_IO'],
        ["SCF", "FRAC_START"],
        ["SCF", "FRAC_RENORMALIZE"],
        # NYI ["SCF", "FRAC_LOAD"],
        ["SCF", "FRAC_OCC"],
        ["SCF", "FRAC_VAL"],
        ["SCF", "FRAC_DIIS"])

    kwargs = p4util.kwargs_lower(kwargs)

    # 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("""frac_nuke requires neutral molecule to start.""")
    if molecule.schoenflies_symbol() != 'c1':
        core.print_out("""  Requested procedure `frac_nuke` 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()

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

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

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

    charge = charge0
    mult = mult0

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

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

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

    # => Traverse <= #
    core.set_local_option("SCF", "DF_INTS_IO", "SAVE")

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

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

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

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

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

    core.set_local_option("SCF", "DF_INTS_IO", "LOAD")
    core.set_local_option("SCF", "FRAC_START", frac_start)
    core.set_local_option("SCF", "FRAC_RENORMALIZE", True)

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

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

            core.set_local_option("SCF", "FRAC_OCC", [H**O])
            core.set_local_option("SCF", "FRAC_VAL", [occ])

            E, wfn = driver.energy('scf', dft_functional=name, return_wfn=True, molecule=molecule, **kwargs)
            C = 1
            if E == 0.0:
                E = core.variable('SCF ITERATION ENERGY')
                C = 0

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

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

            core.set_local_option("SCF", "FRAC_START", 2)
            # NYI core.set_local_option("SCF", "FRAC_LOAD", True)
            core.set_local_option("SCF", "FRAC_DIIS", frac_diis)
            core.set_local_option("SCF", "GUESS", "READ")

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

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

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

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

    core.set_local_option("SCF", "DF_INTS_IO", "NONE")

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

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

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

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

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

    optstash.restore()
    return E
예제 #37
0
파일: frac.py 프로젝트: yxie326/psi4
def frac_traverse(name, **kwargs):
    """Scan electron occupancy from +1 electron to -1.

    Parameters
    ----------
    name : string or function
        DFT functional string name or function defining functional
        whose omega is to be optimized.
    molecule : :ref:`molecule <op_py_molecule>`, optional
        Target molecule (neutral) for which omega is to be tuned, if not last defined.
    cation_mult : int, optional
        Multiplicity of cation, if not neutral multiplicity + 1.
    anion_mult : int, optional
        Multiplicity of anion, if not neutral multiplicity + 1.
    frac_start : int, optional
        Iteration at which to start frac procedure when not reading previous
        guess. Defaults to 25.
    HOMO_occs : list, optional
        Occupations to step through for cation, by default `[1 - 0.1 * x for x in range(11)]`.
    LUMO_occs : list, optional
        Occupations to step through for anion, by default `[1 - 0.1 * x for x in range(11)]`.
    H**O : int, optional
        Index of H**O.
    LUMO : int, optional
        Index of LUMO.
    frac_diis : bool, optional
        Do use DIIS for non-1.0-occupied points?
    neutral_guess : bool, optional
        Do use neutral orbitals as guess for the anion?
    hf_guess: bool, optional
        Do use UHF guess before UKS?
    continuous_guess : bool, optional
        Do carry along guess rather than reguessing at each occupation?
    filename : str, optional
        Result filename, if not name of molecule.

    Returns
    -------
    dict
        Dictionary associating SCF energies with occupations.

    """
    optstash = p4util.OptionsState(
        ['SCF', 'GUESS'],
        ['SCF', 'DF_INTS_IO'],
        ['SCF', 'REFERENCE'],
        ["SCF", "FRAC_START"],
        ["SCF", "FRAC_RENORMALIZE"],
        #["SCF", "FRAC_LOAD"],
        ["SCF", "FRAC_OCC"],
        ["SCF", "FRAC_VAL"],
        ["SCF", "FRAC_DIIS"])
    kwargs = p4util.kwargs_lower(kwargs)

    # 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(
            """frac_traverse requires neutral molecule to start.""")
    if molecule.schoenflies_symbol() != 'c1':
        core.print_out(
            """  Requested procedure `frac_traverse` 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()

    chargep = charge0 + 1
    chargem = charge0 - 1

    multp = kwargs.get('cation_mult', mult0 + 1)
    multm = kwargs.get('anion_mult', mult0 + 1)

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

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

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

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

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

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

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

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

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

    core.set_local_option("SCF", "DF_INTS_IO", "SAVE")

    old_guess = core.get_local_option("SCF", "GUESS")
    if (neutral_guess):
        if (hf_guess):
            core.set_local_option("SCF", "REFERENCE", "UHF")
        driver.energy('scf', dft_functional=name, molecule=molecule, **kwargs)
        core.set_local_option("SCF", "GUESS", "READ")
        core.set_local_option("SCF", "DF_INTS_IO", "LOAD")

    # => Run the anion first <= #

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

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

    core.set_local_option("SCF", "FRAC_START", frac_start)
    core.set_local_option("SCF", "FRAC_RENORMALIZE", True)
    # NYI core.set_local_option("SCF", "FRAC_LOAD", False)

    for occ in LUMO_occs:

        core.set_local_option("SCF", "FRAC_OCC", [LUMO])
        core.set_local_option("SCF", "FRAC_VAL", [occ])

        E, wfn = driver.energy('scf',
                               dft_functional=name,
                               return_wfn=True,
                               molecule=molecule,
                               **kwargs)
        C = 1
        if E == 0.0:
            E = core.variable('SCF ITERATION ENERGY')
            C = 0

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

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

        core.set_local_option("SCF", "FRAC_START", 2)
        #core.set_local_option("SCF", "FRAC_LOAD", True)
        core.set_local_option("SCF", "GUESS", "READ")
        core.set_local_option("SCF", "FRAC_DIIS", frac_diis)
        core.set_local_option("SCF", "DF_INTS_IO", "LOAD")

    # => Run the neutral next <= #

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

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

    if not continuous_guess:
        core.set_local_option("SCF", "GUESS", old_guess)
        if hf_guess:
            core.set_local_option("SCF", "FRAC_START", 0)
            core.set_local_option("SCF", "REFERENCE", "UHF")
            driver.energy('scf',
                          dft_functional=name,
                          molecule=molecule,
                          **kwargs)
            core.set_local_option("SCF", "REFERENCE", "UKS")
            core.set_local_option("SCF", "GUESS", "READ")
        # NYI core.set_local_option("SCF", "FRAC_LOAD", False)

    core.set_local_option("SCF", "FRAC_START", frac_start)
    core.set_local_option("SCF", "FRAC_RENORMALIZE", True)

    for occ in HOMO_occs:

        core.set_local_option("SCF", "FRAC_OCC", [H**O])
        core.set_local_option("SCF", "FRAC_VAL", [occ])

        E, wfn = driver.energy('scf',
                               dft_functional=name,
                               return_wfn=True,
                               molecule=molecule,
                               **kwargs)
        C = 1
        if E == 0.0:
            E = core.variable('SCF ITERATION ENERGY')
            C = 0

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

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

        core.set_local_option("SCF", "FRAC_START", 2)
        # NYI core.set_local_option("SCF", "FRAC_LOAD", True)
        core.set_local_option("SCF", "GUESS", "READ")
        core.set_local_option("SCF", "FRAC_DIIS", frac_diis)
        core.set_local_option("SCF", "DF_INTS_IO", "LOAD")

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

    core.print_out("""
    You trying to be a hero Watkins?
    Just trying to kill some bugs sir!
            -Starship Troopers""")

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

    optstash.restore()
    return E
예제 #38
0
파일: frac.py 프로젝트: dsirianni/psi4
def frac_traverse(name, **kwargs):
    """Scan electron occupancy from +1 electron to -1.

    Parameters
    ----------
    name : string or function
        DFT functional string name or function defining functional
        whose omega is to be optimized.
    molecule : :ref:`molecule <op_py_molecule>`, optional
        Target molecule (neutral) for which omega is to be tuned, if not last defined.
    cation_mult : int, optional
        Multiplicity of cation, if not neutral multiplicity + 1.
    anion_mult : int, optional
        Multiplicity of anion, if not neutral multiplicity + 1.
    frac_start : int, optional
        Iteration at which to start frac procedure when not reading previous
        guess. Defaults to 25.
    HOMO_occs : list, optional
        Occupations to step through for cation, by default `[1 - 0.1 * x for x in range(11)]`.
    LUMO_occs : list, optional
        Occupations to step through for anion, by default `[1 - 0.1 * x for x in range(11)]`.
    H**O : int, optional
        Index of H**O.
    LUMO : int, optional
        Index of LUMO.
    frac_diis : bool, optional
        Do use DIIS for non-1.0-occupied points?
    neutral_guess : bool, optional
        Do use neutral orbitals as guess for the anion?
    hf_guess: bool, optional
        Do use UHF guess before UKS?
    continuous_guess : bool, optional
        Do carry along guess rather than reguessing at each occupation?
    filename : str, optional
        Result filename, if not name of molecule.

    Returns
    -------
    dict
        Dictionary associating SCF energies with occupations.

    """
    optstash = p4util.OptionsState(
        ['SCF', 'GUESS'],
        ['SCF', 'DF_INTS_IO'],
        ['SCF', 'REFERENCE'],
        ["SCF", "FRAC_START"],
        ["SCF", "FRAC_RENORMALIZE"],
        #["SCF", "FRAC_LOAD"],
        ["SCF", "FRAC_OCC"],
        ["SCF", "FRAC_VAL"],
        ["SCF", "FRAC_DIIS"])
    kwargs = p4util.kwargs_lower(kwargs)

    # 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("""frac_traverse requires neutral molecule to start.""")
    if molecule.schoenflies_symbol() != 'c1':
        core.print_out("""  Requested procedure `frac_traverse` 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()

    chargep = charge0 + 1
    chargem = charge0 - 1

    multp = kwargs.get('cation_mult', mult0 + 1)
    multm = kwargs.get('anion_mult', mult0 + 1)

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

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

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

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

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

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

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

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

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

    core.set_local_option("SCF", "DF_INTS_IO", "SAVE")

    old_guess = core.get_local_option("SCF", "GUESS")
    if (neutral_guess):
        if (hf_guess):
            core.set_local_option("SCF", "REFERENCE", "UHF")
        driver.energy('scf', dft_functional=name, molecule=molecule, **kwargs)
        core.set_local_option("SCF", "GUESS", "READ")
        core.set_local_option("SCF", "DF_INTS_IO", "LOAD")

    # => Run the anion first <= #

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

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

    core.set_local_option("SCF", "FRAC_START", frac_start)
    core.set_local_option("SCF", "FRAC_RENORMALIZE", True)
    # NYI core.set_local_option("SCF", "FRAC_LOAD", False)

    for occ in LUMO_occs:

        core.set_local_option("SCF", "FRAC_OCC", [LUMO])
        core.set_local_option("SCF", "FRAC_VAL", [occ])

        E, wfn = driver.energy('scf', dft_functional=name, return_wfn=True, molecule=molecule, **kwargs)
        C = 1
        if E == 0.0:
            E = core.variable('SCF ITERATION ENERGY')
            C = 0

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

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

        core.set_local_option("SCF", "FRAC_START", 2)
        #core.set_local_option("SCF", "FRAC_LOAD", True)
        core.set_local_option("SCF", "GUESS", "READ")
        core.set_local_option("SCF", "FRAC_DIIS", frac_diis)
        core.set_local_option("SCF", "DF_INTS_IO", "LOAD")


    # => Run the neutral next <= #

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

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

    if not continuous_guess:
        core.set_local_option("SCF", "GUESS", old_guess)
        if hf_guess:
            core.set_local_option("SCF", "FRAC_START", 0)
            core.set_local_option("SCF", "REFERENCE", "UHF")
            driver.energy('scf', dft_functional=name, molecule=molecule, **kwargs)
            core.set_local_option("SCF", "REFERENCE", "UKS")
            core.set_local_option("SCF", "GUESS", "READ")
        # NYI core.set_local_option("SCF", "FRAC_LOAD", False)

    core.set_local_option("SCF", "FRAC_START", frac_start)
    core.set_local_option("SCF", "FRAC_RENORMALIZE", True)

    for occ in HOMO_occs:

        core.set_local_option("SCF", "FRAC_OCC", [H**O])
        core.set_local_option("SCF", "FRAC_VAL", [occ])

        E, wfn = driver.energy('scf', dft_functional=name, return_wfn=True, molecule=molecule, **kwargs)
        C = 1
        if E == 0.0:
            E = core.variable('SCF ITERATION ENERGY')
            C = 0

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

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

        core.set_local_option("SCF", "FRAC_START", 2)
        # NYI core.set_local_option("SCF", "FRAC_LOAD", True)
        core.set_local_option("SCF", "GUESS", "READ")
        core.set_local_option("SCF", "FRAC_DIIS", frac_diis)
        core.set_local_option("SCF", "DF_INTS_IO", "LOAD")

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

    core.print_out("""
    You trying to be a hero Watkins?
    Just trying to kill some bugs sir!
            -Starship Troopers""")

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

    optstash.restore()
    return E
예제 #39
0
def run_forte(name, **kwargs):
    r"""Function encoding sequence of PSI module and plugin calls so that
    forte can be called via :py:func:`~driver.energy`. For post-scf plugins.

    >>> energy('forte')

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

    # Compute a SCF reference, a wavefunction is return which holds the molecule used, orbitals
    # Fock matrices, and more
    ref_wfn = kwargs.get('ref_wfn', None)
    if ref_wfn is None:
        ref_wfn = psi4.driver.scf_helper(name, **kwargs)

    # Get the option object
    psi4_options = psi4.core.get_options()
    psi4_options.set_current_module('FORTE')

    # Get the forte option object
    options = forte.forte_options
    options.get_options_from_psi4(psi4_options)

    if ('DF' in options.get_str('INT_TYPE')):
        aux_basis = psi4.core.BasisSet.build(ref_wfn.molecule(), 'DF_BASIS_MP2',
                                         options.get_str('DF_BASIS_MP2'),
                                         'RIFIT', options.get_str('BASIS'))
        ref_wfn.set_basisset('DF_BASIS_MP2', aux_basis)

    if (options.get_str('MINAO_BASIS')):
        minao_basis = psi4.core.BasisSet.build(ref_wfn.molecule(), 'MINAO_BASIS',
                                               options.get_str('MINAO_BASIS'))
        ref_wfn.set_basisset('MINAO_BASIS', minao_basis)

    # Start Forte, initialize ambit
    my_proc_n_nodes = forte.startup()
    my_proc, n_nodes = my_proc_n_nodes

    # Print the banner
    forte.banner()

    # Create the MOSpaceInfo object
    mo_space_info = forte.make_mo_space_info(ref_wfn, options)

    # Call methods that project the orbitals (AVAS, embedding)
    mo_space_info = orbital_projection(ref_wfn, options, mo_space_info)

    # Averaging spin multiplets if doing spin-adapted computation
    if options.get_str('CORRELATION_SOLVER') == 'SA-MRDSRG':
        options_dict = options.dict()
        options_dict['SPIN_AVG_DENSITY']['value'] = True
        options.set_dict(options_dict)

    state = forte.make_state_info_from_psi_wfn(ref_wfn)
    scf_info = forte.SCFInfo(ref_wfn)
    state_weights_map = forte.make_state_weights_map(options,ref_wfn)

    # Run a method
    job_type = options.get_str('JOB_TYPE')

    energy = 0.0

    if job_type == 'NONE':
        forte.cleanup()
        return ref_wfn

    start_pre_ints = time.time()

    # Make an integral object
    ints = forte.make_forte_integrals(ref_wfn, options, mo_space_info)

    start = time.time()

    # Rotate orbitals before computation (e.g. localization, MP2 natural orbitals, etc.)
    orb_type = options.get_str("ORBITAL_TYPE")
    if orb_type != 'CANONICAL':
        orb_t = forte.make_orbital_transformation(orb_type, scf_info, options, ints, mo_space_info)
        orb_t.compute_transformation()
        Ua = orb_t.get_Ua()
        Ub = orb_t.get_Ub()
        ints.rotate_orbitals(Ua,Ub)

    # Run a method
    if (job_type == 'NEWDRIVER'):
        energy = forte_driver(state_weights_map, scf_info, options, ints, mo_space_info)
    else:
        energy = forte.forte_old_methods(ref_wfn, options, ints, mo_space_info)

    end = time.time()

    # Close ambit, etc.
    forte.cleanup()

    psi4.core.set_scalar_variable('CURRENT ENERGY', energy)

    psi4.core.print_out(f'\n\n  Time to prepare integrals: {start - start_pre_ints:12.3f} seconds')
    psi4.core.print_out(f'\n  Time to run job          : {end - start:12.3f} seconds')
    psi4.core.print_out(f'\n  Total                    : {end - start:12.3f} seconds')
    return ref_wfn
예제 #40
0
파일: frac.py 프로젝트: dsirianni/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)