Example #1
0
    def fitScf(self):
        """Function to run scf and fit a system of diffuse charges to
        resulting density.

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

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

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

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

        self.fitGeneral()

        psi4.clean()

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

        if not basisChanged:
            psi4.revoke_option_changed("BASIS")
        if not ribasisChanged:
            psi4.revoke_option_changed("DF_BASIS_SCF")
        if not scftypeChanged:
            psi4.revoke_option_changed("SCF_TYPE")
Example #2
0
    def fitScf(self):
        """Function to run scf and fit a system of diffuse charges to
        resulting density.

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

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

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

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

        self.fitGeneral()

        psi4.clean()

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

        if not basisChanged:
            psi4.revoke_option_changed("BASIS")
        if not ribasisChanged:
            psi4.revoke_option_changed("DF_BASIS_SCF")
        if not scftypeChanged:
            psi4.revoke_option_changed("SCF_TYPE")
Example #3
0
    # SCF energy and update
    FH = F.clone()
    FH.add(H)
    SCF_E = FH.vector_dot(D) + Enuc

    dRMS = diis_e.rms()

    psi4.core.print_out('SCF Iteration %3d: Energy = %4.16f   dE = % 1.5E   dRMS = %1.5E\n'
          % (SCF_ITER, SCF_E, (SCF_E - Eold), dRMS))
    if (abs(SCF_E - Eold) < E_conv) and (dRMS < D_conv):
        break

    Eold = SCF_E

    # DIIS extrapolate
    F = diis_obj.extrapolate()

    # Diagonalize Fock matrix
    C, Cocc, D = build_orbitals(F)

    if SCF_ITER == maxiter:
        psi4.clean()
        raise Exception("Maximum number of SCF cycles exceeded.\n")

psi4.core.print_out('Total time for SCF iterations: %.3f seconds \n\n' % (time.time() - t))
#print(psi4.energy("SCF"))

psi4.core.print_out('Final SCF energy: %.8f hartree\n' % SCF_E)
psi4.compare_values(-76.0033389840197202, SCF_E, 6, 'SCF Energy')
Example #4
0
def run_gaussian_2(name, **kwargs):

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

    psi4.set_variable("CURRENT ENERGY",eg2_0k)

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

    psi4.clean()

    optstash.restore()

    # return 0K g2 results
    return eg2_0k
Example #5
0
    diis.add(F, diis_e)

    # SCF energy and update
    FH = F.clone()
    FH.add(H)
    SCF_E = FH.vector_dot(D) + Enuc

    dRMS = diis_e.rms()

    print('SCF Iteration %3d: Energy = %4.16f   dE = % 1.5E   dRMS = %1.5E' %
          (SCF_ITER, SCF_E, (SCF_E - Eold), dRMS))
    if (abs(SCF_E - Eold) < E_conv) and (dRMS < D_conv):
        break

    Eold = SCF_E
    Dold = D

    F = psi4.core.Matrix.from_array(diis.extrapolate())

    # Diagonalize Fock matrix
    C, Cocc, D = build_orbitals(F)

    if SCF_ITER == maxiter:
        psi4.clean()
        raise Exception("Maximum number of SCF cycles exceeded.\n")

print('Total time for SCF iterations: %.3f seconds \n\n' % (time.time() - t))

print('Final SCF energy: %.8f hartree\n' % SCF_E)
psi4.compare_values(-230.7277181465556453, SCF_E, 6, 'SCF Energy')
Example #6
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
    def __init__(self, mol, rhf_e, rhf_wfn, numpy_memory=2):
        print("\nInitalizing CCSD object...\n")
        time_init = time.time()
        # RHF from Psi4
        self.rhf_e = rhf_e
        self.wfn = rhf_wfn

        self.mints = psi4.core.MintsHelper(self.wfn.basisset())
        self.H = np.asarray(self.mints.ao_kinetic()) + np.asarray(
            self.mints.ao_potential())

        self.ndocc = self.wfn.doccpi()[0]
        self.nmo = self.wfn.nmo()
        self.nmo = self.H.shape[0]
        self.memory = numpy_memory
        self.C = self.wfn.Ca()
        self.npC = np.asarray(self.C)

        self.SCF_E = self.wfn.energy()

        # Update H, transform to MO basis
        self.H = np.einsum('uj,vi,uv', self.npC, self.npC, self.H)

        print('Starting AO ->  MO transformation...')

        ERI_Size = (self.nmo**4) * 8 / (1024**3)
        memory_footprint = ERI_Size * 5
        if memory_footprint > self.memory:
            psi4.clean()
            raise Exception(
                "Estimated memory utilization (%4.2f GB) exceeds numpy_memory \
                            limit of %4.2f GB." %
                (memory_footprint, self.memory))

        # Integral generation from Psi4's MintsHelper
        self.MO = np.asarray(self.mints.mo_eri(self.C, self.C, self.C, self.C))
        # Physicist notation
        self.MO = self.MO.swapaxes(1, 2)
        print("Size of the ERI tensor is %4.2f GB, %d basis functions." %
              (ERI_Size, self.nmo))
        # single-precision MO integrals
        self.MOsp = np.float32(self.MO)

        # Update nocc and nvirt
        self.nocc = self.ndocc
        self.nvirt = self.nmo - self.nocc

        # Make slices
        self.slice_o = slice(0, self.nocc)
        self.slice_v = slice(self.nocc, self.nmo)
        self.slice_a = slice(0, self.nmo)
        self.slice_dict = {
            'o': self.slice_o,
            'v': self.slice_v,
            'a': self.slice_a
        }

        # Compute Fock matrix
        self.F = self.H + 2.0 * np.einsum(
            'pmqm->pq', self.MO[:, self.slice_o, :, self.slice_o])
        self.F -= np.einsum('pmmq->pq', self.MO[:, self.slice_o,
                                                self.slice_o, :])
        # Single-precision F
        self.Fsp = np.float32(self.F)

        # Compute AO density
        self.P = self.get_P()

        # Occupied and Virtual orbital energies for the denominators
        Focc = np.diag(self.Fsp)[self.slice_o]
        Fvir = np.diag(self.Fsp)[self.slice_v]

        # Denominator
        self.Dia = Focc.reshape(-1, 1) - Fvir
        self.Dijab = Focc.reshape(-1, 1, 1, 1) + Focc.reshape(
            -1, 1, 1) - Fvir.reshape(-1, 1) - Fvir

        # Construct initial guess of t1, t2 (t1, t2 at t=0)
        print('Building initial guess...')
        # t^a_i
        self.t1 = np.zeros((self.nocc, self.nvirt))
        # t^{ab}_{ij}
        self.t2 = self.MO[self.slice_o, self.slice_o, self.slice_v,
                          self.slice_v] / self.Dijab
        # single-precision t1, t2
        self.t1_sp = np.float32(self.t1)
        self.t2_sp = np.float32(self.t2)

        print('\n..initialized CCSD in %.3f seconds.\n' %
              (time.time() - time_init))
Example #8
0
def run_gaussian_2(name, **kwargs):

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

    psi4.set_variable("CURRENT ENERGY", eg2_0k)

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

    psi4.clean()

    optstash.restore()

    # return 0K g2 results
    return eg2_0k
Example #9
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