Example #1
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.set_local_option('SCF', 'DF_INTS_IO', 'SAVE')

    # Your plugin's psi4 run sequence goes here
    scf_wfn = scf_helper(name, **kwargs)

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

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

    returnvalue = psi4.plugin('v2rdm_casscf.so',scf_wfn)

    #psi4.set_variable('CURRENT ENERGY', returnvalue)

    return psi4.get_variable('CURRENT ENERGY')
Example #2
0
def run_plugin_mp2(name, **kwargs):
    r"""Function encoding sequence of PSI module and plugin calls so that
    mollerplesset2 can be called via :py:func:`~driver.energy`.

    >>> energy('mollerplesset2')

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

    # Your plugin's psi4 run sequence goes here
    psi4.set_local_option('MOLLERPLESSET2', 'PRINT', 1)
    scf_wfn = scf_helper(lowername)

    # Need to semicanonicalize the ROHF orbitals
    if psi4.get_global_option('REFERENCE') == 'ROHF':
        scf_wfn.semicanonicalize()

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

    #psi4.set_legacy_wavefunction(scf_wfn)
    returnvalue = psi4.plugin('mollerplesset2.so', scf_wfn)

    return returnvalue
Example #3
0
def run_plugin_mp2(name, **kwargs):
    r"""Function encoding sequence of PSI module and plugin calls so that
    mollerplesset2 can be called via :py:func:`~driver.energy`.

    >>> energy('mollerplesset2')

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

    # Your plugin's psi4 run sequence goes here
    psi4.set_local_option('MOLLERPLESSET2', 'PRINT', 1)
    scf_wfn = scf_helper(lowername)

    # Need to semicanonicalize the ROHF orbitals
    if psi4.get_global_option('REFERENCE') == 'ROHF':
        scf_wfn.semicanonicalize()

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

    #psi4.set_legacy_wavefunction(scf_wfn)
    returnvalue = psi4.plugin('mollerplesset2.so', scf_wfn)

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

    >>> energy('paralleldf')

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

    # Your plugin's psi4 run sequence goes here
    #psi4.set_global_option('BASIS', 'sto-3g')
    psi4.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 = driver.scf_helper(name, **kwargs)

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

    return paralleldf_wfn
Example #5
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.set_local_option('SCF', 'DF_INTS_IO', 'SAVE')

    # Your plugin's psi4 run sequence goes here
    scf_wfn = scf_helper(name, **kwargs)

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

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

    returnvalue = psi4.plugin('v2rdm_casscf.so', scf_wfn)

    #psi4.set_variable('CURRENT ENERGY', returnvalue)

    return psi4.get_variable('CURRENT ENERGY')
Example #6
0
def run_plugin_fragment(name, **kwargs):
    r"""Function encoding sequence of PSI module and plugin calls so that
    plugin_fragment can be called via :py:func:`~driver.energy`. For post-scf plugins.

    >>> energy('plugin_fragment')

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

    # Your plugin's psi4 run sequence goes here
    psi4.plugin('plugin_fragment.so')
Example #7
0
def run_plugin_fragment(name, **kwargs):
    r"""Function encoding sequence of PSI module and plugin calls so that
    plugin_fragment can be called via :py:func:`~driver.energy`. For post-scf plugins.

    >>> energy('plugin_fragment')

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

    # Your plugin's psi4 run sequence goes here
    psi4.plugin('plugin_fragment.so')
Example #8
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.set_local_option('CIS', 'PRINT', 1)
    scf_helper(name, **kwargs)
    returnvalue = psi4.plugin('cis.so')
    psi4.set_variable('CURRENT ENERGY', returnvalue)
Example #9
0
def run_fasnocis(name, **kwargs):
    r"""Function encoding sequence of PSI module and plugin calls so that
    OCDFT can be called via :py:func:`~driver.energy`.

    >>> energy('fasnocis')

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

    # Run OCDFT
    psi4.set_local_option('CDFT','METHOD','FASNOCIS')
    returnvalue = psi4.plugin('cdft.so')

    return returnvalue
Example #10
0
def run_plugin_mp2(name, **kwargs):
    r"""Function encoding sequence of PSI module and plugin calls so that
    mollerplesset2 can be called via :py:func:`~driver.energy`.

    >>> energy('mollerplesset2')

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

    # Your plugin's psi4 run sequence goes here
    psi4.set_local_option('MOLLERPLESSET2', 'PRINT', 1)
    psi4.scf()
    returnvalue = psi4.plugin('mollerplesset2.so')

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

    >>> energy('dpd_unit_test')

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

    # Your plugin's psi4 run sequence goes here
    psi4.set_global_option('BASIS', 'sto-3g')
    psi4.set_local_option('DPD_UNIT_TEST', 'PRINT', 1)
    scf_helper(name, **kwargs)
    returnvalue = psi4.plugin('dpd_unit_test.so')
    psi4.set_variable('CURRENT ENERGY', returnvalue)
Example #12
0
def run_main(name, **kwargs):
    r"""Function encoding sequence of PSI module and plugin calls so that
    main can be called via :py:func:`~driver.energy`. For post-scf plugins.

    >>> energy('main')

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

    # Your plugin's psi4 run sequence goes here
    #    psi4.set_global_option('BASIS', 'sto-3g')
    #    psi4.set_local_option('MAIN', 'PRINT', 1)
    scf_helper(name, **kwargs)
    returnvalue = psi4.plugin('main.so')
    psi4.set_variable('CURRENT ENERGY', returnvalue)
Example #13
0
def sherrill_gold_standard(name='mp2', **kwargs):
    r"""Function to call the quantum chemical method known as 'Gold Standard'
    in the Sherrill group. Uses :py:func:`~wrappers.complete_basis_set` to evaluate
    the following expression. Two-point extrapolation of the correlation energy
    performed according to :py:func:`~wrappers.corl_xtpl_helgaker_2`.

    .. math:: E_{total}^{\text{Au\_std}} = E_{total,\; \text{SCF}}^{\text{aug-cc-pVQZ}} \; + E_{corl,\; \text{MP2}}^{\text{aug-cc-pV[TQ]Z}} \; + \delta_{\text{MP2}}^{\text{CCSD(T)}}\big\vert_{\text{aug-cc-pVTZ}}

    >>> # [1] single-point energy by this composite method
    >>> energy('sherrill_gold_standard')

    >>> # [2] finite-difference geometry optimization
    >>> optimize('sherrill_gold_standard')

    >>> # [3] finite-difference geometry optimization, overwriting some pre-defined sherrill_gold_standard options
    >>> optimize('sherrill_gold_standard', corl_basis='cc-pV[DT]Z', delta_basis='3-21g')

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

    if not ('func_cbs' in kwargs):
        kwargs['func_cbs'] = energy

    if not ('scf_basis' in kwargs):
        kwargs['scf_basis'] = 'aug-cc-pVQZ'
    if not ('scf_scheme' in kwargs):
        kwargs['scf_scheme'] = highest_1

    if not ('corl_wfn' in kwargs):
        kwargs['corl_wfn'] = 'mp2'
        name = 'mp2'
    if not ('corl_basis' in kwargs):
        kwargs['corl_basis'] = 'aug-cc-pV[TQ]Z'
    if not ('corl_scheme' in kwargs):
        kwargs['corl_scheme'] = corl_xtpl_helgaker_2

    if not ('delta_wfn' in kwargs):
        kwargs['delta_wfn'] = 'ccsd(t)'
    if not ('delta_wfn_lesser' in kwargs):
        kwargs['delta_wfn_lesser'] = 'mp2'
    if not ('delta_basis' in kwargs):
        kwargs['delta_basis'] = 'aug-cc-pVTZ'
    if not ('delta_scheme' in kwargs):
        kwargs['delta_scheme'] = highest_1

    return cbs(name, **kwargs)
Example #14
0
def sherrill_gold_standard(name='mp2', **kwargs):
    r"""Function to call the quantum chemical method known as 'Gold Standard'
    in the Sherrill group. Uses :py:func:`~wrappers.complete_basis_set` to evaluate
    the following expression. Two-point extrapolation of the correlation energy
    performed according to :py:func:`~wrappers.corl_xtpl_helgaker_2`.

    .. math:: E_{total}^{\text{Au\_std}} = E_{total,\; \text{SCF}}^{\text{aug-cc-pVQZ}} \; + E_{corl,\; \text{MP2}}^{\text{aug-cc-pV[TQ]Z}} \; + \delta_{\text{MP2}}^{\text{CCSD(T)}}\big\vert_{\text{aug-cc-pVTZ}}

    >>> # [1] single-point energy by this composite method
    >>> energy('sherrill_gold_standard')

    >>> # [2] finite-difference geometry optimization
    >>> optimize('sherrill_gold_standard')

    >>> # [3] finite-difference geometry optimization, overwriting some pre-defined sherrill_gold_standard options
    >>> optimize('sherrill_gold_standard', corl_basis='cc-pV[DT]Z', delta_basis='3-21g')

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

    if not ('func_cbs' in kwargs):
        kwargs['func_cbs'] = energy

    if not ('scf_basis' in kwargs):
        kwargs['scf_basis'] = 'aug-cc-pVQZ'
    if not ('scf_scheme' in kwargs):
        kwargs['scf_scheme'] = highest_1

    if not ('corl_wfn' in kwargs):
        kwargs['corl_wfn'] = 'mp2'
        name = 'mp2'
    if not ('corl_basis' in kwargs):
        kwargs['corl_basis'] = 'aug-cc-pV[TQ]Z'
    if not ('corl_scheme' in kwargs):
        kwargs['corl_scheme'] = corl_xtpl_helgaker_2

    if not ('delta_wfn' in kwargs):
        kwargs['delta_wfn'] = 'ccsd(t)'
    if not ('delta_wfn_lesser' in kwargs):
        kwargs['delta_wfn_lesser'] = 'mp2'
    if not ('delta_basis' in kwargs):
        kwargs['delta_basis'] = 'aug-cc-pVTZ'
    if not ('delta_scheme' in kwargs):
        kwargs['delta_scheme'] = highest_1

    return cbs(name, **kwargs)
Example #15
0
def run_dfdcft(name, **kwargs):
    r"""Function encoding sequence of PSI module and plugin calls so that
    dfdcft can be called via :py:func:`~driver.energy`. For post-scf plugins.

    >>> energy('dfdcft')

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

#    psi4.set_local_option('SCF', 'REFERENCE', 'UHF')
#    psi4.set_local_option('DFDCFT', 'REFERENCE', 'UHF')

    # Your plugin's psi4 run sequence goes here
    scf_helper(name, **kwargs)
    returnvalue = psi4.plugin('dfdcft.so')
    psi4.set_variable('CURRENT ENERGY', returnvalue)
Example #16
0
def run_fvno(name, **kwargs):
    r"""Function encoding sequence of PSI module and plugin calls so that
    fvno can be called via :py:func:`~driver.energy`. For post-scf plugins.

    >>> energy('fvno')

    """
    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.set_global_option('WFN', 'CCSD')
        elif (kwargs['wfn'] == 'ccsd(t)'):
            psi4.set_global_option('WFN', 'CCSD_T')
    scf_helper(name, **kwargs)
    psi4.transqt2()
    returnvalue = psi4.plugin('fvno.so')
Example #17
0
def run_fvno(name, **kwargs):
    r"""Function encoding sequence of PSI module and plugin calls so that
    fvno can be called via :py:func:`~driver.energy`. For post-scf plugins.

    >>> energy('fvno')

    """
    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.set_global_option('WFN', 'CCSD')
        elif (kwargs['wfn'] == 'ccsd(t)'):
            psi4.set_global_option('WFN', 'CCSD_T')
    scf_helper(name, **kwargs)
    psi4.transqt2()
    returnvalue = psi4.plugin('fvno.so')
Example #18
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.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 = driver.scf_helper(name, **kwargs)

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

    # todo PSIF_V2RDM_CHECKPOINT should be definied in psifiles.h
    if ( filename != "" ):
        molname = ref_wfn.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.get_option('SCF', 'SCF_TYPE')
    if ( scf_type == 'PK' or scf_type == 'DIRECT' ):
        proc_util.check_iwl_file_from_scf_type(psi4.get_option('SCF', 'SCF_TYPE'), ref_wfn)

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

    #psi4.set_variable('CURRENT ENERGY', returnvalue)

    #return psi4.get_variable('CURRENT ENERGY')
    return returnvalue
Example #19
0
def run_aomp2(name, **kwargs):
    r"""Function encoding sequence of PSI module and plugin calls so that
    aomp2 can be called via :py:func:`~driver.energy`. For post-scf plugins.

    >>> energy('aomp2')

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

    ref_wfn = kwargs.get('ref_wfn', None)
    if ref_wfn is None:
        ref_wfn = driver.scf_helper(name, **kwargs)

    # Your plugin's psi4 run sequence goes here
    #psi4.set_local_option('AOMP2', 'PRINT', 1)
    #scf_helper(name, **kwargs)
    returnvalue = psi4.plugin("aomp2.so", ref_wfn)
    #psi4.set_variable('CURRENT ENERGY', returnvalue)

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

    >>> energy('ccambit')

    """
    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.set_global_option('WFN', 'CCSD')
        elif (kwargs['wfn'] == 'ccsd(t)'):
            psi4.set_global_option('WFN', 'CCSD_T')
    scf_wfn = kwargs.get('ref_wfn', None)
    if scf_wfn is None:
        scf_wfn = driver.scf_helper(name, **kwargs)
    check_iwl_file_from_scf_type(psi4.get_option('SCF', 'SCF_TYPE'), scf_wfn)
    return psi4.plugin('ccambit.so', scf_wfn)
Example #21
0
def allen_focal_point(name='mp2', **kwargs):
    r"""Function to call Wes Allen-style Focal
    Point Analysis. JCP 127 014306.  Uses
    :py:func:`~wrappers.complete_basis_set` to evaluate the following
    expression. SCF employs a three-point extrapolation according
    to :py:func:`~wrappers.scf_xtpl_helgaker_3`. MP2, CCSD, and
    CCSD(T) employ two-point extrapolation performed according to
    :py:func:`~wrappers.corl_xtpl_helgaker_2`.  CCSDT and CCSDT(Q)
    are plain deltas. This wrapper requires :ref:`Kallay's MRCC code <sec:mrcc>`.

    .. math:: E_{total}^{\text{FPA}} = E_{total,\; \text{SCF}}^{\text{cc-pV[Q56]Z}} \; + E_{corl,\; \text{MP2}}^{\text{cc-pV[56]Z}} \; + \delta_{\text{MP2}}^{\text{CCSD}}\big\vert_{\text{cc-pV[56]Z}} \; + \delta_{\text{CCSD}}^{\text{CCSD(T)}}\big\vert_{\text{cc-pV[56]Z}} \; + \delta_{\text{CCSD(T)}}^{\text{CCSDT}}\big\vert_{\text{cc-pVTZ}} \; + \delta_{\text{CCSDT}}^{\text{CCSDT(Q)}}\big\vert_{\text{cc-pVDZ}}

    >>> # [1] single-point energy by this composite method
    >>> energy('allen_focal_point')

    >>> # [2] finite-difference geometry optimization embarrasingly parallel
    >>> optimize('allen_focal_point', mode='sow')

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

    if not ('func_cbs' in kwargs):
        kwargs['func_cbs'] = energy

    # SCF
    if not ('scf_basis' in kwargs):
        kwargs['scf_basis'] = 'cc-pV[Q56]Z'
    if not ('scf_scheme' in kwargs):
        kwargs['scf_scheme'] = scf_xtpl_helgaker_3

    # delta MP2 - SCF
    if not ('corl_wfn' in kwargs):
        kwargs['corl_wfn'] = 'mp2'
        name = 'mp2'
    if not ('corl_basis' in kwargs):
        kwargs['corl_basis'] = 'cc-pV[56]Z'
    if not ('corl_scheme' in kwargs):
        kwargs['corl_scheme'] = corl_xtpl_helgaker_2

    # delta CCSD - MP2
    if not ('delta_wfn' in kwargs):
        kwargs['delta_wfn'] = 'mrccsd'
    if not ('delta_wfn_lesser' in kwargs):
        kwargs['delta_wfn_lesser'] = 'mp2'
    if not ('delta_basis' in kwargs):
        kwargs['delta_basis'] = 'cc-pV[56]Z'
    if not ('delta_scheme' in kwargs):
        kwargs['delta_scheme'] = corl_xtpl_helgaker_2

    # delta CCSD(T) - CCSD
    if not ('delta2_wfn' in kwargs):
        kwargs['delta2_wfn'] = 'mrccsd(t)'
    if not ('delta2_wfn_lesser' in kwargs):
        kwargs['delta2_wfn_lesser'] = 'mrccsd'
    if not ('delta2_basis' in kwargs):
        kwargs['delta2_basis'] = 'cc-pV[56]Z'
    if not ('delta2_scheme' in kwargs):
        kwargs['delta2_scheme'] = corl_xtpl_helgaker_2

    # delta CCSDT - CCSD(T)
    if not ('delta3_wfn' in kwargs):
        kwargs['delta3_wfn'] = 'mrccsdt'
    if not ('delta3_wfn_lesser' in kwargs):
        kwargs['delta3_wfn_lesser'] = 'mrccsd(t)'
    if not ('delta3_basis' in kwargs):
        kwargs['delta3_basis'] = 'cc-pVTZ'
    if not ('delta3_scheme' in kwargs):
        kwargs['delta3_scheme'] = highest_1

    # delta CCSDT(Q) - CCSDT
    if not ('delta4_wfn' in kwargs):
        kwargs['delta4_wfn'] = 'mrccsdt(q)'
    if not ('delta4_wfn_lesser' in kwargs):
        kwargs['delta4_wfn_lesser'] = 'mrccsdt'
    if not ('delta4_basis' in kwargs):
        kwargs['delta4_basis'] = 'cc-pVDZ'
    if not ('delta4_scheme' in kwargs):
        kwargs['delta4_scheme'] = highest_1

    return cbs(name, **kwargs)
Example #22
0
def _nbody_gufunc(func, method_string, **kwargs):
    """
    Computes the nbody interaction energy, gradient, or Hessian depending on input.

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

    molecule_total_atoms = sum(fragment_size_dict.values())

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

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

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

            psi4.clean()

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

    psi4.set_variable("CURRENT ENERGY", ret_energy)

    if return_wfn:
        return (ret_ptype, wfn)
    else:
        return ret_ptype
Example #23
0
def _nbody_gufunc(func, method_string, **kwargs):
    """
    Computes the nbody interaction energy, gradient, or Hessian depending on input.

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

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

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

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

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

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

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

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

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

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

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

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

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


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


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

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

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

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

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


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

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

    molecule_total_atoms = sum(fragment_size_dict.values())

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

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

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

            psi4.clean()

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

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

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

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

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


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

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

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


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

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

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

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

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

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

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

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

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

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


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

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

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


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


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

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

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

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

    psi4.set_variable("CURRENT ENERGY", ret_energy)

    if return_wfn:
        return (ret_ptype, wfn)
    else:
        return ret_ptype
Example #24
0
def ip_fitting(molecule, omega_l, omega_r, **kwargs):
    kwargs = p4util.kwargs_lower(kwargs)

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

        step = step + 1

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

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

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

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

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

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

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

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

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

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

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

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

    psi4.set_global_option("DF_INTS_IO", "NONE")
    psi4.set_global_option("GUESS", old_guess)
Example #25
0
def frac_traverse(molecule, **kwargs):
    kwargs = p4util.kwargs_lower(kwargs)

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

    chargep = charge0 + 1
    chargem = charge0 - 1

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

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

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

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

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

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

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

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

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

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

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

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

    # => Run the anion first <= #

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

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

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

    for occ in LUMO_occs:

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

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

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

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

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

    # => Run the neutral next <= #

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

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

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

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

    for occ in HOMO_occs:

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

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

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

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

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

    psi4.set_global_option("DF_INTS_IO", old_df_ints_io)

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

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

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

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

    return E
Example #26
0
def frac_nuke(molecule, **kwargs):
    kwargs = p4util.kwargs_lower(kwargs)

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

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

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

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

    charge = charge0
    mult = mult0

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

    return E
Example #27
0
def ip_fitting(molecule, omega_l, omega_r, **kwargs):
    kwargs = p4util.kwargs_lower(kwargs)

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

        step = step + 1

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

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

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

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

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

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

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

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

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

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

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

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

    psi4.set_global_option("DF_INTS_IO", "NONE")
    psi4.set_global_option("GUESS", old_guess)
Example #28
0
def frac_traverse(molecule, **kwargs):
    kwargs = p4util.kwargs_lower(kwargs)

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

    chargep = charge0 + 1
    chargem = charge0 - 1

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

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

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

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

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

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

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

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

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

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

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

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

    # => Run the anion first <= #

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

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

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

    for occ in LUMO_occs:

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

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

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

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

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


    # => Run the neutral next <= #

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

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

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

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

    for occ in HOMO_occs:

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

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

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

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

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

    psi4.set_global_option("DF_INTS_IO", old_df_ints_io)

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

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

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

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

    return E
Example #29
0
def frac_nuke(molecule, **kwargs):
    kwargs = p4util.kwargs_lower(kwargs)

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

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

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

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

    charge = charge0
    mult = mult0

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

    return E
Example #30
0
def allen_focal_point(name='mp2', **kwargs):
    r"""Function to call Wes Allen-style Focal
    Point Analysis. JCP 127 014306.  Uses
    :py:func:`~wrappers.complete_basis_set` to evaluate the following
    expression. SCF employs a three-point extrapolation according
    to :py:func:`~wrappers.scf_xtpl_helgaker_3`. MP2, CCSD, and
    CCSD(T) employ two-point extrapolation performed according to
    :py:func:`~wrappers.corl_xtpl_helgaker_2`.  CCSDT and CCSDT(Q)
    are plain deltas. This wrapper requires :ref:`Kallay's MRCC code <sec:mrcc>`.

    .. math:: E_{total}^{\text{FPA}} = E_{total,\; \text{SCF}}^{\text{cc-pV[Q56]Z}} \; + E_{corl,\; \text{MP2}}^{\text{cc-pV[56]Z}} \; + \delta_{\text{MP2}}^{\text{CCSD}}\big\vert_{\text{cc-pV[56]Z}} \; + \delta_{\text{CCSD}}^{\text{CCSD(T)}}\big\vert_{\text{cc-pV[56]Z}} \; + \delta_{\text{CCSD(T)}}^{\text{CCSDT}}\big\vert_{\text{cc-pVTZ}} \; + \delta_{\text{CCSDT}}^{\text{CCSDT(Q)}}\big\vert_{\text{cc-pVDZ}}

    >>> # [1] single-point energy by this composite method
    >>> energy('allen_focal_point')

    >>> # [2] finite-difference geometry optimization embarrasingly parallel
    >>> optimize('allen_focal_point', mode='sow')

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

    if not ('func_cbs' in kwargs):
        kwargs['func_cbs'] = energy

    # SCF
    if not ('scf_basis' in kwargs):
        kwargs['scf_basis'] = 'cc-pV[Q56]Z'
    if not ('scf_scheme' in kwargs):
        kwargs['scf_scheme'] = scf_xtpl_helgaker_3

    # delta MP2 - SCF
    if not ('corl_wfn' in kwargs):
        kwargs['corl_wfn'] = 'mp2'
        name = 'mp2'
    if not ('corl_basis' in kwargs):
        kwargs['corl_basis'] = 'cc-pV[56]Z'
    if not ('corl_scheme' in kwargs):
        kwargs['corl_scheme'] = corl_xtpl_helgaker_2

    # delta CCSD - MP2
    if not ('delta_wfn' in kwargs):
        kwargs['delta_wfn'] = 'mrccsd'
    if not ('delta_wfn_lesser' in kwargs):
        kwargs['delta_wfn_lesser'] = 'mp2'
    if not ('delta_basis' in kwargs):
        kwargs['delta_basis'] = 'cc-pV[56]Z'
    if not ('delta_scheme' in kwargs):
        kwargs['delta_scheme'] = corl_xtpl_helgaker_2

    # delta CCSD(T) - CCSD
    if not ('delta2_wfn' in kwargs):
        kwargs['delta2_wfn'] = 'mrccsd(t)'
    if not ('delta2_wfn_lesser' in kwargs):
        kwargs['delta2_wfn_lesser'] = 'mrccsd'
    if not ('delta2_basis' in kwargs):
        kwargs['delta2_basis'] = 'cc-pV[56]Z'
    if not ('delta2_scheme' in kwargs):
        kwargs['delta2_scheme'] = corl_xtpl_helgaker_2

    # delta CCSDT - CCSD(T)
    if not ('delta3_wfn' in kwargs):
        kwargs['delta3_wfn'] = 'mrccsdt'
    if not ('delta3_wfn_lesser' in kwargs):
        kwargs['delta3_wfn_lesser'] = 'mrccsd(t)'
    if not ('delta3_basis' in kwargs):
        kwargs['delta3_basis'] = 'cc-pVTZ'
    if not ('delta3_scheme' in kwargs):
        kwargs['delta3_scheme'] = highest_1

    # delta CCSDT(Q) - CCSDT
    if not ('delta4_wfn' in kwargs):
        kwargs['delta4_wfn'] = 'mrccsdt(q)'
    if not ('delta4_wfn_lesser' in kwargs):
        kwargs['delta4_wfn_lesser'] = 'mrccsdt'
    if not ('delta4_basis' in kwargs):
        kwargs['delta4_basis'] = 'cc-pVDZ'
    if not ('delta4_scheme' in kwargs):
        kwargs['delta4_scheme'] = highest_1

    return cbs(name, **kwargs)
Example #31
0
def ip_fitting(mol, omega_l, omega_r, **kwargs):
    kwargs = p4util.kwargs_lower(kwargs)

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

        step = step + 1;

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

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

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

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

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

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

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

    psi4.IO.set_default_namespace("")

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

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

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

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

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