def compute_charges(charge_method, charge_type, molecule): """ Compute charges for nbody fragments """ from psi4.driver.driver import energy from psi4.driver.p4util.util import oeprop charges = {} molecule = molecule.clone() for i in range(1, molecule.nfragments() + 1): molecule.set_name('charges%i' %i) e, wfn = energy(charge_method, molecule=molecule.extract_subsets([i]), return_wfn=True) oeprop(wfn, charge_type) charges[i] = wfn.atomic_point_charges().np return charges
def compute_charges(charge_method, charge_type, molecule): """ Compute charges for nbody fragments """ from psi4.driver.driver import energy from psi4.driver.p4util.util import oeprop charges = {} molecule = molecule.clone() for i in range(1, molecule.nfragments() + 1): molecule.set_name('charges%i' % i) e, wfn = energy(charge_method, molecule=molecule.extract_subsets([i]), return_wfn=True) oeprop(wfn, charge_type) charges[i] = wfn.atomic_point_charges().np return charges
def ip_fitting(name, omega_l=0.05, omega_r=2.5, omega_convergence=1.0e-3, maxiter=20, **kwargs): """Optimize DFT omega parameter for molecular system. Parameters ---------- name : string or function DFT functional string name or function defining functional whose omega is to be optimized. omega_l : float, optional Minimum omega to be considered during fitting. omega_r : float, optional Maximum omega to be considered during fitting. molecule : :ref:`molecule <op_py_molecule>`, optional Target molecule (neutral) for which omega is to be tuned, if not last defined. omega_convergence : float, optional Threshold below which to consider omega converged. (formerly omega_tolerance) maxiter : int, optional Maximum number of iterations towards omega convergence. Returns ------- float Optimal omega parameter. """ optstash = p4util.OptionsState(['SCF', 'REFERENCE'], ['SCF', 'GUESS'], ['SCF', 'DF_INTS_IO'], ['SCF', 'DFT_OMEGA'], ['DOCC'], ['SOCC']) kwargs = p4util.kwargs_lower(kwargs) # By default, do not read previous 180 orbitals file read = False read180 = '' if 'read' in kwargs: read = True read180 = kwargs['read'] if core.get_option('SCF', 'REFERENCE') != 'UKS': core.print_out( """ Requested procedure `ip_fitting` runs further calculations with UKS reference.\n""" ) core.set_local_option('SCF', 'REFERENCE', 'UKS') # Make sure the molecule the user provided is the active one, and neutral molecule = kwargs.pop('molecule', core.get_active_molecule()) molecule.update_geometry() if molecule.molecular_charge() != 0: raise ValidationError( """IP Fitting requires neutral molecule to start.""") if molecule.schoenflies_symbol() != 'c1': core.print_out( """ Requested procedure `ip_fitting` does not make use of molecular symmetry: """ """further calculations in C1 point group.\n""") molecule = molecule.clone() molecule.reset_point_group('c1') molecule.update_geometry() charge0 = molecule.molecular_charge() mult0 = molecule.multiplicity() # How many electrons are there? N = 0 for A in range(molecule.natom()): N += molecule.Z(A) N -= charge0 N = int(N) Nb = int((N - mult0 + 1) / 2) Na = int(N - Nb) # Work in the ot namespace for this procedure core.IO.set_default_namespace("ot") # Burn in to determine orbital eigenvalues if read: core.set_local_option("SCF", "GUESS", "READ") copy_file_to_scratch(read180, 'psi', 'ot', 180) core.set_local_option("SCF", "DF_INTS_IO", "SAVE") E, wfn = driver.energy('scf', dft_functional=name, return_wfn=True, molecule=molecule, banner='IP Fitting SCF: Burn-in', **kwargs) core.set_local_option("SCF", "DF_INTS_IO", "LOAD") if not wfn.functional().is_x_lrc(): raise ValidationError( """Not sensible to optimize omega for non-long-range-correction functional.""" ) # Determine H**O, to determine mult1 eps_a = wfn.epsilon_a() eps_b = wfn.epsilon_b() if Na == Nb: H**O = -Nb elif Nb == 0: H**O = Na else: E_a = eps_a.np[int(Na - 1)] E_b = eps_b.np[int(Nb - 1)] if E_a >= E_b: H**O = Na else: H**O = -Nb Na1 = Na Nb1 = Nb if H**O > 0: Na1 -= 1 else: Nb1 -= 1 charge1 = charge0 + 1 mult1 = Na1 - Nb1 + 1 omegas = [] E0s = [] E1s = [] kIPs = [] IPs = [] types = [] # Right endpoint core.set_local_option('SCF', 'DFT_OMEGA', omega_r) # Neutral if read: core.set_local_option("SCF", "GUESS", "READ") p4util.copy_file_to_scratch(read180, 'psi', 'ot', 180) molecule.set_molecular_charge(charge0) molecule.set_multiplicity(mult0) E0r, wfn = driver.energy('scf', dft_functional=name, return_wfn=True, molecule=molecule, banner='IP Fitting SCF: Neutral, Right Endpoint', **kwargs) eps_a = wfn.epsilon_a() eps_b = wfn.epsilon_b() if Nb == 0: E_HOMO = eps_a.np[int(Na - 1)] else: E_a = eps_a.np[int(Na - 1)] E_b = eps_b.np[int(Nb - 1)] E_HOMO = max(E_a, E_b) E_HOMOr = E_HOMO core.IO.change_file_namespace(180, "ot", "neutral") # Cation if read: core.set_local_option("SCF", "GUESS", "READ") p4util.copy_file_to_scratch(read180, 'psi', 'ot', 180) molecule.set_molecular_charge(charge1) molecule.set_multiplicity(mult1) E1r = driver.energy('scf', dft_functional=name, molecule=molecule, banner='IP Fitting SCF: Cation, Right Endpoint', **kwargs) core.IO.change_file_namespace(180, "ot", "cation") IPr = E1r - E0r kIPr = -E_HOMOr delta_r = IPr - kIPr if IPr > kIPr: raise ValidationError( """\n***IP Fitting Error: Right Omega limit should have kIP > IP: {} !> {}""" .format(kIPr, IPr)) omegas.append(omega_r) types.append('Right Limit') E0s.append(E0r) E1s.append(E1r) IPs.append(IPr) kIPs.append(kIPr) # Use previous orbitals from here out core.set_local_option("SCF", "GUESS", "READ") # Left endpoint core.set_local_option('SCF', 'DFT_OMEGA', omega_l) # Neutral core.IO.change_file_namespace(180, "neutral", "ot") molecule.set_molecular_charge(charge0) molecule.set_multiplicity(mult0) core.set_global_option("DOCC", [Nb]) core.set_global_option("SOCC", [Na - Nb]) E0l, wfn = driver.energy('scf', dft_functional=name, return_wfn=True, molecule=molecule, banner='IP Fitting SCF: Neutral, Left Endpoint', **kwargs) eps_a = wfn.epsilon_a() eps_b = wfn.epsilon_b() if Nb == 0: E_HOMO = eps_a.np[int(Na - 1)] else: E_a = eps_a.np[int(Na - 1)] E_b = eps_b.np[int(Nb - 1)] E_HOMO = max(E_a, E_b) E_HOMOl = E_HOMO core.IO.change_file_namespace(180, "ot", "neutral") # Cation core.IO.change_file_namespace(180, "cation", "ot") molecule.set_molecular_charge(charge1) molecule.set_multiplicity(mult1) core.set_global_option("DOCC", [Nb1]) core.set_global_option("SOCC", [Na1 - Nb1]) E1l = driver.energy('scf', dft_functional=name, molecule=molecule, banner='IP Fitting SCF: Cation, Left Endpoint', **kwargs) core.IO.change_file_namespace(180, "ot", "cation") IPl = E1l - E0l kIPl = -E_HOMOl delta_l = IPl - kIPl if IPl < kIPl: raise ValidationError( """\n***IP Fitting Error: Left Omega limit should have kIP < IP: {} !< {}""" .format(kIPl, IPl)) omegas.append(omega_l) types.append('Left Limit') E0s.append(E0l) E1s.append(E1l) IPs.append(IPl) kIPs.append(kIPl) converged = False repeat_l = 0 repeat_r = 0 for step in range(maxiter): # Regula Falsi (modified) if repeat_l > 1: delta_l /= 2.0 if repeat_r > 1: delta_r /= 2.0 omega = -(omega_r - omega_l) / (delta_r - delta_l) * delta_l + omega_l core.set_local_option('SCF', 'DFT_OMEGA', omega) # Neutral core.IO.change_file_namespace(180, "neutral", "ot") molecule.set_molecular_charge(charge0) molecule.set_multiplicity(mult0) core.set_global_option("DOCC", [Nb]) core.set_global_option("SOCC", [Na - Nb]) E0, wfn = driver.energy( 'scf', dft_functional=name, return_wfn=True, molecule=molecule, banner='IP Fitting SCF: Neutral, Omega = {:11.3E}'.format(omega), **kwargs) eps_a = wfn.epsilon_a() eps_b = wfn.epsilon_b() if Nb == 0: E_HOMO = eps_a.np[int(Na - 1)] else: E_a = eps_a.np[int(Na - 1)] E_b = eps_b.np[int(Nb - 1)] E_HOMO = max(E_a, E_b) core.IO.change_file_namespace(180, "ot", "neutral") # Cation core.IO.change_file_namespace(180, "cation", "ot") molecule.set_molecular_charge(charge1) molecule.set_multiplicity(mult1) core.set_global_option("DOCC", [Nb1]) core.set_global_option("SOCC", [Na1 - Nb1]) E1 = driver.energy( 'scf', dft_functional=name, molecule=molecule, banner='IP Fitting SCF: Cation, Omega = {:11.3E}'.format(omega), **kwargs) core.IO.change_file_namespace(180, "ot", "cation") IP = E1 - E0 kIP = -E_HOMO delta = IP - kIP if kIP > IP: omega_r = omega E0r = E0 E1r = E1 IPr = IP kIPr = kIP delta_r = delta repeat_r = 0 repeat_l += 1 else: omega_l = omega E0l = E0 E1l = E1 IPl = IP kIPl = kIP delta_l = delta repeat_l = 0 repeat_r += 1 omegas.append(omega) types.append('Regula-Falsi') E0s.append(E0) E1s.append(E1) IPs.append(IP) kIPs.append(kIP) # Termination if abs(omega_l - omega_r) < omega_convergence: converged = True break core.IO.set_default_namespace("") core.print_out("""\n ==> IP Fitting Results <==\n\n""") core.print_out(""" => Occupation Determination <= \n\n""") core.print_out(""" %6s %6s %6s %6s %6s %6s\n""" % ('N', 'Na', 'Nb', 'Charge', 'Mult', 'H**O')) core.print_out(""" Neutral: %6d %6d %6d %6d %6d %6d\n""" % (N, Na, Nb, charge0, mult0, H**O)) core.print_out(""" Cation: %6d %6d %6d %6d %6d\n\n""" % (N - 1, Na1, Nb1, charge1, mult1)) core.print_out(""" => Regula Falsi Iterations <=\n\n""") core.print_out(""" %3s %11s %14s %14s %14s %s\n""" % ('N', 'Omega', 'IP', 'kIP', 'Delta', 'Type')) for k in range(len(omegas)): core.print_out( """ %3d %11.3E %14.6E %14.6E %14.6E %s\n""" % (k + 1, omegas[k], IPs[k], kIPs[k], IPs[k] - kIPs[k], types[k])) optstash.restore() if converged: core.print_out("""\n IP Fitting Converged\n""") core.print_out(""" Final omega = %14.6E\n""" % ((omega_l + omega_r) / 2)) core.print_out( """\n "M,I. does the dying. Fleet just does the flying."\n""") core.print_out(""" -Starship Troopers\n""") else: raise ConvergenceError("""IP Fitting """, step + 1) return ((omega_l + omega_r) / 2)
def frac_traverse(name, **kwargs): """Scan electron occupancy from +1 electron to -1. Parameters ---------- name : string or function DFT functional string name or function defining functional whose omega is to be optimized. molecule : :ref:`molecule <op_py_molecule>`, optional Target molecule (neutral) for which omega is to be tuned, if not last defined. cation_mult : int, optional Multiplicity of cation, if not neutral multiplicity + 1. anion_mult : int, optional Multiplicity of anion, if not neutral multiplicity + 1. frac_start : int, optional Iteration at which to start frac procedure when not reading previous guess. Defaults to 25. HOMO_occs : list, optional Occupations to step through for cation, by default `[1 - 0.1 * x for x in range(11)]`. LUMO_occs : list, optional Occupations to step through for anion, by default `[1 - 0.1 * x for x in range(11)]`. H**O : int, optional Index of H**O. LUMO : int, optional Index of LUMO. frac_diis : bool, optional Do use DIIS for non-1.0-occupied points? neutral_guess : bool, optional Do use neutral orbitals as guess for the anion? hf_guess: bool, optional Do use UHF guess before UKS? continuous_guess : bool, optional Do carry along guess rather than reguessing at each occupation? filename : str, optional Result filename, if not name of molecule. Returns ------- dict Dictionary associating SCF energies with occupations. """ optstash = p4util.OptionsState( ['SCF', 'GUESS'], ['SCF', 'DF_INTS_IO'], ['SCF', 'REFERENCE'], ["SCF", "FRAC_START"], ["SCF", "FRAC_RENORMALIZE"], #["SCF", "FRAC_LOAD"], ["SCF", "FRAC_OCC"], ["SCF", "FRAC_VAL"], ["SCF", "FRAC_DIIS"]) kwargs = p4util.kwargs_lower(kwargs) # Make sure the molecule the user provided is the active one, and neutral molecule = kwargs.pop('molecule', core.get_active_molecule()) molecule.update_geometry() if molecule.molecular_charge() != 0: raise ValidationError( """frac_traverse requires neutral molecule to start.""") if molecule.schoenflies_symbol() != 'c1': core.print_out( """ Requested procedure `frac_traverse` does not make use of molecular symmetry: """ """further calculations in C1 point group.\n""") molecule = molecule.clone() molecule.reset_point_group('c1') molecule.update_geometry() charge0 = molecule.molecular_charge() mult0 = molecule.multiplicity() chargep = charge0 + 1 chargem = charge0 - 1 multp = kwargs.get('cation_mult', mult0 + 1) multm = kwargs.get('anion_mult', mult0 + 1) # By default, we start the frac procedure on the 25th iteration # when not reading a previous guess frac_start = kwargs.get('frac_start', 25) # By default, we occupy by tenths of electrons HOMO_occs = kwargs.get( 'HOMO_occs', [1.0, 0.9, 0.8, 0.7, 0.6, 0.5, 0.4, 0.3, 0.2, 0.1, 0.0]) LUMO_occs = kwargs.get( 'LUMO_occs', [1.0, 0.9, 0.8, 0.7, 0.6, 0.5, 0.4, 0.3, 0.2, 0.1, 0.0]) # By default, H**O and LUMO are both in alpha Z = 0 for A in range(molecule.natom()): Z += molecule.Z(A) Z -= charge0 H**O = kwargs.get('H**O', (Z / 2 + 1 if (Z % 2) else Z / 2)) LUMO = kwargs.get('LUMO', H**O + 1) # By default, DIIS in FRAC (1.0 occupation is always DIIS'd) frac_diis = kwargs.get('frac_diis', True) # By default, use the neutral orbitals as a guess for the anion neutral_guess = kwargs.get('neutral_guess', True) # By default, burn-in with UHF first, if UKS hf_guess = False if core.get_local_option('SCF', 'REFERENCE') == 'UKS': hf_guess = kwargs.get('hf_guess', True) # By default, re-guess at each N continuous_guess = kwargs.get('continuous_guess', False) # By default, drop the files to the molecule's name root = kwargs.get('filename', molecule.name()) traverse_filename = root + '.traverse.dat' # => Traverse <= # occs = [] energies = [] potentials = [] convs = [] # => Run the neutral for its orbitals, if requested <= # core.set_local_option("SCF", "DF_INTS_IO", "SAVE") old_guess = core.get_local_option("SCF", "GUESS") if (neutral_guess): if (hf_guess): core.set_local_option("SCF", "REFERENCE", "UHF") driver.energy('scf', dft_functional=name, molecule=molecule, **kwargs) core.set_local_option("SCF", "GUESS", "READ") core.set_local_option("SCF", "DF_INTS_IO", "LOAD") # => Run the anion first <= # molecule.set_molecular_charge(chargem) molecule.set_multiplicity(multm) # => Burn the anion in with hf, if requested <= # if hf_guess: core.set_local_option("SCF", "REFERENCE", "UHF") driver.energy('scf', dft_functional=name, molecule=molecule, **kwargs) core.set_local_option("SCF", "REFERENCE", "UKS") core.set_local_option("SCF", "GUESS", "READ") core.set_local_option("SCF", "DF_INTS_IO", "SAVE") core.set_local_option("SCF", "FRAC_START", frac_start) core.set_local_option("SCF", "FRAC_RENORMALIZE", True) # NYI core.set_local_option("SCF", "FRAC_LOAD", False) for occ in LUMO_occs: core.set_local_option("SCF", "FRAC_OCC", [LUMO]) core.set_local_option("SCF", "FRAC_VAL", [occ]) E, wfn = driver.energy('scf', dft_functional=name, return_wfn=True, molecule=molecule, **kwargs) C = 1 if E == 0.0: E = core.variable('SCF ITERATION ENERGY') C = 0 if LUMO > 0: eps = wfn.epsilon_a() potentials.append(eps.get(int(LUMO) - 1)) else: eps = wfn.epsilon_b() potentials.append(eps.get(-int(LUMO) - 1)) occs.append(occ) energies.append(E) convs.append(C) core.set_local_option("SCF", "FRAC_START", 2) #core.set_local_option("SCF", "FRAC_LOAD", True) core.set_local_option("SCF", "GUESS", "READ") core.set_local_option("SCF", "FRAC_DIIS", frac_diis) core.set_local_option("SCF", "DF_INTS_IO", "LOAD") # => Run the neutral next <= # molecule.set_molecular_charge(charge0) molecule.set_multiplicity(mult0) # Burn the neutral in with hf, if requested <= # if not continuous_guess: core.set_local_option("SCF", "GUESS", old_guess) if hf_guess: core.set_local_option("SCF", "FRAC_START", 0) core.set_local_option("SCF", "REFERENCE", "UHF") driver.energy('scf', dft_functional=name, molecule=molecule, **kwargs) core.set_local_option("SCF", "REFERENCE", "UKS") core.set_local_option("SCF", "GUESS", "READ") # NYI core.set_local_option("SCF", "FRAC_LOAD", False) core.set_local_option("SCF", "FRAC_START", frac_start) core.set_local_option("SCF", "FRAC_RENORMALIZE", True) for occ in HOMO_occs: core.set_local_option("SCF", "FRAC_OCC", [H**O]) core.set_local_option("SCF", "FRAC_VAL", [occ]) E, wfn = driver.energy('scf', dft_functional=name, return_wfn=True, molecule=molecule, **kwargs) C = 1 if E == 0.0: E = core.variable('SCF ITERATION ENERGY') C = 0 if LUMO > 0: eps = wfn.epsilon_a() potentials.append(eps.get(int(H**O) - 1)) else: eps = wfn.epsilon_b() potentials.append(eps.get(-int(H**O) - 1)) occs.append(occ - 1.0) energies.append(E) convs.append(C) core.set_local_option("SCF", "FRAC_START", 2) # NYI core.set_local_option("SCF", "FRAC_LOAD", True) core.set_local_option("SCF", "GUESS", "READ") core.set_local_option("SCF", "FRAC_DIIS", frac_diis) core.set_local_option("SCF", "DF_INTS_IO", "LOAD") # => Print the results out <= # E = {} core.print_out( """\n ==> Fractional Occupation Traverse Results <==\n\n""") core.print_out(""" %-11s %-24s %-24s %11s\n""" % ('N', 'Energy', 'H**O Energy', 'Converged')) for k in range(len(occs)): core.print_out(""" %11.3E %24.16E %24.16E %11d\n""" % (occs[k], energies[k], potentials[k], convs[k])) E[occs[k]] = energies[k] core.print_out(""" You trying to be a hero Watkins? Just trying to kill some bugs sir! -Starship Troopers""") # Drop the files out with open(traverse_filename, 'w') as fh: fh.write(""" %-11s %-24s %-24s %11s\n""" % ('N', 'Energy', 'H**O Energy', 'Converged')) for k in range(len(occs)): fh.write(""" %11.3E %24.16E %24.16E %11d\n""" % (occs[k], energies[k], potentials[k], convs[k])) optstash.restore() return E
def frac_nuke(name, **kwargs): """Pull all the electrons out, one at a time""" optstash = p4util.OptionsState( ['SCF', 'GUESS'], ['SCF', 'DF_INTS_IO'], ["SCF", "FRAC_START"], ["SCF", "FRAC_RENORMALIZE"], # NYI ["SCF", "FRAC_LOAD"], ["SCF", "FRAC_OCC"], ["SCF", "FRAC_VAL"], ["SCF", "FRAC_DIIS"]) kwargs = p4util.kwargs_lower(kwargs) # Make sure the molecule the user provided is the active one, and neutral molecule = kwargs.pop('molecule', core.get_active_molecule()) molecule.update_geometry() if molecule.molecular_charge() != 0: raise ValidationError( """frac_nuke requires neutral molecule to start.""") if molecule.schoenflies_symbol() != 'c1': core.print_out( """ Requested procedure `frac_nuke` does not make use of molecular symmetry: """ """further calculations in C1 point group.\n""") molecule = molecule.clone() molecule.reset_point_group('c1') molecule.update_geometry() charge0 = molecule.molecular_charge() mult0 = molecule.multiplicity() # By default, we start the frac procedure on the 25th iteration # when not reading a previous guess frac_start = kwargs.get('frac_start', 25) # By default, we occupy by tenths of electrons foccs = kwargs.get('foccs', [1.0, 0.9, 0.8, 0.7, 0.6, 0.5, 0.4, 0.3, 0.2, 0.1, 0.0]) # By default, H**O and LUMO are both in alpha N = 0 for A in range(molecule.natom()): N += molecule.Z(A) N -= charge0 N = int(N) Nb = int((N - mult0 + 1) / 2) Na = int(N - Nb) charge = charge0 mult = mult0 # By default, nuke all the electrons Nmin = 0 if 'nmax' in kwargs: Nmin = N - int(kwargs['nmax']) # By default, DIIS in FRAC (1.0 occupation is always DIIS'd) frac_diis = kwargs.get('frac_diis', True) # By default, drop the files to the molecule's name root = kwargs.get('filename', molecule.name()) traverse_filename = root + '.traverse.dat' stats_filename = root + '.stats.dat' # => Traverse <= # core.set_local_option("SCF", "DF_INTS_IO", "SAVE") Ns = [] energies = [] potentials = [] convs = [] stats = [] # Run one SCF to burn things in E, wfn = driver.energy('scf', dft_functional=name, return_wfn=True, molecule=molecule, **kwargs) # Determine H**O eps_a = wfn.epsilon_a() eps_b = wfn.epsilon_b() eps_a.print_out() if Na == Nb: H**O = -Nb elif Nb == 0: H**O = Na else: E_a = eps_a.get(int(Na - 1)) E_b = eps_b.get(int(Nb - 1)) if E_a >= E_b: H**O = Na else: H**O = -Nb stats.append(""" %6d %6d %6d %6d %6d %6d\n""" % (N, Na, Nb, charge, mult, H**O)) if H**O > 0: Na -= 1 else: Nb -= 1 charge += 1 mult = Na - Nb + 1 core.set_local_option("SCF", "DF_INTS_IO", "LOAD") core.set_local_option("SCF", "FRAC_START", frac_start) core.set_local_option("SCF", "FRAC_RENORMALIZE", True) # Nuke 'em Rico! for Nintegral in range(N, Nmin, -1): # Nuke the current H**O for occ in foccs: core.set_local_option("SCF", "FRAC_OCC", [H**O]) core.set_local_option("SCF", "FRAC_VAL", [occ]) E, wfn = driver.energy('scf', dft_functional=name, return_wfn=True, molecule=molecule, **kwargs) C = 1 if E == 0.0: E = core.variable('SCF ITERATION ENERGY') C = 0 if H**O > 0: eps = wfn.epsilon_a() potentials.append(eps.np[H**O - 1]) else: eps = wfn.epsilon_b() potentials.append(eps.np[-H**O - 1]) Ns.append(Nintegral + occ - 1.0) energies.append(E) convs.append(C) core.set_local_option("SCF", "FRAC_START", 2) # NYI core.set_local_option("SCF", "FRAC_LOAD", True) core.set_local_option("SCF", "FRAC_DIIS", frac_diis) core.set_local_option("SCF", "GUESS", "READ") # Set the next charge/mult molecule.set_molecular_charge(charge) molecule.set_multiplicity(mult) # Determine H**O print('DGAS: What ref should this point to?') #ref = core.legacy_wavefunction() eps_a = wfn.epsilon_a() eps_b = wfn.epsilon_b() if Na == Nb: H**O = -Nb elif Nb == 0: H**O = Na else: E_a = eps_a.np[int(Na - 1)] E_b = eps_b.np[int(Nb - 1)] if E_a >= E_b: H**O = Na else: H**O = -Nb stats.append(""" %6d %6d %6d %6d %6d %6d\n""" % (Nintegral - 1, Na, Nb, charge, mult, H**O)) if H**O > 0: Na -= 1 else: Nb -= 1 charge += 1 mult = Na - Nb + 1 core.set_local_option("SCF", "DF_INTS_IO", "NONE") # => Print the results out <= # E = {} core.print_out("""\n ==> Fractional Occupation Nuke Results <==\n\n""") core.print_out(""" %-11s %-24s %-24s %11s\n""" % ('N', 'Energy', 'H**O Energy', 'Converged')) for k in range(len(Ns)): core.print_out(""" %11.3E %24.16E %24.16E %11d\n""" % (Ns[k], energies[k], potentials[k], convs[k])) E[Ns[k]] = energies[k] core.print_out('\n') core.print_out(""" %6s %6s %6s %6s %6s %6s\n""" % ('N', 'Na', 'Nb', 'Charge', 'Mult', 'H**O')) for line in stats: core.print_out(line) core.print_out( '\n "You shoot a nuke down a bug hole, you got a lot of dead bugs"\n' ) core.print_out(' -Starship Troopers\n') # Drop the files out with open(traverse_filename, 'w') as fh: fh.write(""" %-11s %-24s %-24s %11s\n""" % ('N', 'Energy', 'H**O Energy', 'Converged')) for k in range(len(Ns)): fh.write(""" %11.3E %24.16E %24.16E %11d\n""" % (Ns[k], energies[k], potentials[k], convs[k])) with open(stats_filename, 'w') as fh: fh.write(""" %6s %6s %6s %6s %6s %6s\n""" % ('N', 'Na', 'Nb', 'Charge', 'Mult', 'H**O')) for line in stats: fh.write(line) optstash.restore() return E
def run_gaussian_2(name, **kwargs): # throw an exception for open-shells if (core.get_option('SCF','REFERENCE') != 'RHF' ): raise ValidationError("""g2 computations require "reference rhf".""") # stash user options: optstash = p4util.OptionsState( ['FNOCC','COMPUTE_TRIPLES'], ['FNOCC','COMPUTE_MP4_TRIPLES'], ['FREEZE_CORE'], ['MP2_TYPE'], ['SCF','SCF_TYPE']) # override default scf_type core.set_local_option('SCF','SCF_TYPE','PK') # optimize geometry at scf level core.clean() core.set_global_option('BASIS',"6-31G(D)") driver.optimize('scf') core.clean() # scf frequencies for zpe # NOTE This line should not be needed, but without it there's a seg fault scf_e, ref = driver.frequency('scf', return_wfn=True) # thermodynamic properties du = core.get_variable('INTERNAL ENERGY CORRECTION') dh = core.get_variable('ENTHALPY CORRECTION') dg = core.get_variable('GIBBS FREE ENERGY CORRECTION') freqs = ref.frequencies() nfreq = freqs.dim(0) freqsum = 0.0 for i in range(0, nfreq): freqsum += freqs.get(i) zpe = freqsum / p4const.psi_hartree2wavenumbers * 0.8929 * 0.5 core.clean() # optimize geometry at mp2 (no frozen core) level # note: freeze_core isn't an option in MP2 core.set_global_option('FREEZE_CORE',"FALSE") core.set_global_option('MP2_TYPE', 'CONV') driver.optimize('mp2') core.clean() # qcisd(t) core.set_local_option('FNOCC','COMPUTE_MP4_TRIPLES',"TRUE") core.set_global_option('FREEZE_CORE',"TRUE") core.set_global_option('BASIS',"6-311G(D_P)") ref = driver.proc.run_fnocc('qcisd(t)', return_wfn=True, **kwargs) # HLC: high-level correction based on number of valence electrons nirrep = ref.nirrep() frzcpi = ref.frzcpi() nfzc = 0 for i in range (0,nirrep): nfzc += frzcpi[i] nalpha = ref.nalpha() - nfzc nbeta = ref.nbeta() - nfzc # hlc of gaussian-2 hlc = -0.00481 * nalpha -0.00019 * nbeta # hlc of gaussian-1 hlc1 = -0.00614 * nalpha eqci_6311gdp = core.get_variable("QCISD(T) TOTAL ENERGY") emp4_6311gd = core.get_variable("MP4 TOTAL ENERGY") emp2_6311gd = core.get_variable("MP2 TOTAL ENERGY") core.clean() # correction for diffuse functions core.set_global_option('BASIS',"6-311+G(D_P)") driver.energy('mp4') emp4_6311pg_dp = core.get_variable("MP4 TOTAL ENERGY") emp2_6311pg_dp = core.get_variable("MP2 TOTAL ENERGY") core.clean() # correction for polarization functions core.set_global_option('BASIS',"6-311G(2DF_P)") driver.energy('mp4') emp4_6311g2dfp = core.get_variable("MP4 TOTAL ENERGY") emp2_6311g2dfp = core.get_variable("MP2 TOTAL ENERGY") core.clean() # big basis mp2 core.set_global_option('BASIS',"6-311+G(3DF_2P)") #run_fnocc('_mp2',**kwargs) driver.energy('mp2') emp2_big = core.get_variable("MP2 TOTAL ENERGY") core.clean() eqci = eqci_6311gdp e_delta_g2 = emp2_big + emp2_6311gd - emp2_6311g2dfp - emp2_6311pg_dp e_plus = emp4_6311pg_dp - emp4_6311gd e_2df = emp4_6311g2dfp - emp4_6311gd eg2 = eqci + e_delta_g2 + e_plus + e_2df eg2_mp2_0k = eqci + (emp2_big - emp2_6311gd) + hlc + zpe core.print_out('\n') core.print_out(' ==> G1/G2 Energy Components <==\n') core.print_out('\n') core.print_out(' QCISD(T): %20.12lf\n' % eqci) core.print_out(' E(Delta): %20.12lf\n' % e_delta_g2) core.print_out(' E(2DF): %20.12lf\n' % e_2df) core.print_out(' E(+): %20.12lf\n' % e_plus) core.print_out(' E(G1 HLC): %20.12lf\n' % hlc1) core.print_out(' E(G2 HLC): %20.12lf\n' % hlc) core.print_out(' E(ZPE): %20.12lf\n' % zpe) core.print_out('\n') core.print_out(' ==> 0 Kelvin Results <==\n') core.print_out('\n') eg2_0k = eg2 + zpe + hlc core.print_out(' G1: %20.12lf\n' % (eqci + e_plus + e_2df + hlc1 + zpe)) core.print_out(' G2(MP2): %20.12lf\n' % eg2_mp2_0k) core.print_out(' G2: %20.12lf\n' % eg2_0k) core.set_variable("G1 TOTAL ENERGY",eqci + e_plus + e_2df + hlc1 + zpe) core.set_variable("G2 TOTAL ENERGY",eg2_0k) core.set_variable("G2(MP2) TOTAL ENERGY",eg2_mp2_0k) core.print_out('\n') T = core.get_global_option('T') core.print_out(' ==> %3.0lf Kelvin Results <==\n'% T) core.print_out('\n') internal_energy = eg2_mp2_0k + du - zpe / 0.8929 enthalpy = eg2_mp2_0k + dh - zpe / 0.8929 gibbs = eg2_mp2_0k + dg - zpe / 0.8929 core.print_out(' G2(MP2) energy: %20.12lf\n' % internal_energy ) core.print_out(' G2(MP2) enthalpy: %20.12lf\n' % enthalpy) core.print_out(' G2(MP2) free energy: %20.12lf\n' % gibbs) core.print_out('\n') core.set_variable("G2(MP2) INTERNAL ENERGY",internal_energy) core.set_variable("G2(MP2) ENTHALPY",enthalpy) core.set_variable("G2(MP2) FREE ENERGY",gibbs) internal_energy = eg2_0k + du - zpe / 0.8929 enthalpy = eg2_0k + dh - zpe / 0.8929 gibbs = eg2_0k + dg - zpe / 0.8929 core.print_out(' G2 energy: %20.12lf\n' % internal_energy ) core.print_out(' G2 enthalpy: %20.12lf\n' % enthalpy) core.print_out(' G2 free energy: %20.12lf\n' % gibbs) core.set_variable("CURRENT ENERGY",eg2_0k) core.set_variable("G2 INTERNAL ENERGY",internal_energy) core.set_variable("G2 ENTHALPY",enthalpy) core.set_variable("G2 FREE ENERGY",gibbs) core.clean() optstash.restore() # return 0K g2 results return eg2_0k
def run_gaussian_2(name, **kwargs): # throw an exception for open-shells if (core.get_option('SCF', 'REFERENCE') != 'RHF'): raise ValidationError("""g2 computations require "reference rhf".""") # stash user options: optstash = p4util.OptionsState(['FNOCC', 'COMPUTE_TRIPLES'], ['FNOCC', 'COMPUTE_MP4_TRIPLES'], ['BASIS'], ['FREEZE_CORE'], ['MP2_TYPE'], ['SCF_TYPE']) # override default scf_type core.set_global_option('SCF_TYPE', 'PK') # optimize geometry at scf level core.clean() core.set_global_option('BASIS', "6-31G(D)") driver.optimize('scf') core.clean() # scf frequencies for zpe # NOTE This line should not be needed, but without it there's a seg fault scf_e, ref = driver.frequency('scf', return_wfn=True) # thermodynamic properties du = core.variable('THERMAL ENERGY CORRECTION') dh = core.variable('ENTHALPY CORRECTION') dg = core.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 / constants.hartree2wavenumbers * 0.8929 * 0.5 core.clean() # optimize geometry at mp2 (no frozen core) level # note: freeze_core isn't an option in MP2 core.set_global_option('FREEZE_CORE', "FALSE") core.set_global_option('MP2_TYPE', 'CONV') driver.optimize('mp2') core.clean() # qcisd(t) core.set_local_option('FNOCC', 'COMPUTE_MP4_TRIPLES', "TRUE") core.set_global_option('FREEZE_CORE', "TRUE") core.set_global_option('BASIS', "6-311G(D_P)") ref = driver.proc.run_fnocc('qcisd(t)', return_wfn=True, **kwargs) # HLC: high-level correction based on number of valence electrons nirrep = ref.nirrep() frzcpi = ref.frzcpi() nfzc = 0 for i in range(0, nirrep): nfzc += frzcpi[i] nalpha = ref.nalpha() - nfzc nbeta = ref.nbeta() - nfzc # hlc of gaussian-2 hlc = -0.00481 * nalpha - 0.00019 * nbeta # hlc of gaussian-1 hlc1 = -0.00614 * nalpha eqci_6311gdp = core.variable("QCISD(T) TOTAL ENERGY") emp4_6311gd = core.variable("MP4 TOTAL ENERGY") emp2_6311gd = core.variable("MP2 TOTAL ENERGY") core.clean() # correction for diffuse functions core.set_global_option('BASIS', "6-311+G(D_P)") driver.energy('mp4') emp4_6311pg_dp = core.variable("MP4 TOTAL ENERGY") emp2_6311pg_dp = core.variable("MP2 TOTAL ENERGY") core.clean() # correction for polarization functions core.set_global_option('BASIS', "6-311G(2DF_P)") driver.energy('mp4') emp4_6311g2dfp = core.variable("MP4 TOTAL ENERGY") emp2_6311g2dfp = core.variable("MP2 TOTAL ENERGY") core.clean() # big basis mp2 core.set_global_option('BASIS', "6-311+G(3DF_2P)") #run_fnocc('_mp2',**kwargs) driver.energy('mp2') emp2_big = core.variable("MP2 TOTAL ENERGY") core.clean() eqci = eqci_6311gdp e_delta_g2 = emp2_big + emp2_6311gd - emp2_6311g2dfp - emp2_6311pg_dp e_plus = emp4_6311pg_dp - emp4_6311gd e_2df = emp4_6311g2dfp - emp4_6311gd eg2 = eqci + e_delta_g2 + e_plus + e_2df eg2_mp2_0k = eqci + (emp2_big - emp2_6311gd) + hlc + zpe core.print_out('\n') core.print_out(' ==> G1/G2 Energy Components <==\n') core.print_out('\n') core.print_out(' QCISD(T): %20.12lf\n' % eqci) core.print_out(' E(Delta): %20.12lf\n' % e_delta_g2) core.print_out(' E(2DF): %20.12lf\n' % e_2df) core.print_out(' E(+): %20.12lf\n' % e_plus) core.print_out(' E(G1 HLC): %20.12lf\n' % hlc1) core.print_out(' E(G2 HLC): %20.12lf\n' % hlc) core.print_out(' E(ZPE): %20.12lf\n' % zpe) core.print_out('\n') core.print_out(' ==> 0 Kelvin Results <==\n') core.print_out('\n') eg2_0k = eg2 + zpe + hlc core.print_out(' G1: %20.12lf\n' % (eqci + e_plus + e_2df + hlc1 + zpe)) core.print_out(' G2(MP2): %20.12lf\n' % eg2_mp2_0k) core.print_out(' G2: %20.12lf\n' % eg2_0k) core.set_variable("G1 TOTAL ENERGY", eqci + e_plus + e_2df + hlc1 + zpe) core.set_variable("G2 TOTAL ENERGY", eg2_0k) core.set_variable("G2(MP2) TOTAL ENERGY", eg2_mp2_0k) core.print_out('\n') T = core.get_global_option('T') core.print_out(' ==> %3.0lf Kelvin Results <==\n' % T) core.print_out('\n') internal_energy = eg2_mp2_0k + du - zpe / 0.8929 enthalpy = eg2_mp2_0k + dh - zpe / 0.8929 gibbs = eg2_mp2_0k + dg - zpe / 0.8929 core.print_out(' G2(MP2) energy: %20.12lf\n' % internal_energy) core.print_out(' G2(MP2) enthalpy: %20.12lf\n' % enthalpy) core.print_out(' G2(MP2) free energy: %20.12lf\n' % gibbs) core.print_out('\n') core.set_variable("G2(MP2) INTERNAL ENERGY", internal_energy) core.set_variable("G2(MP2) ENTHALPY", enthalpy) core.set_variable("G2(MP2) FREE ENERGY", gibbs) internal_energy = eg2_0k + du - zpe / 0.8929 enthalpy = eg2_0k + dh - zpe / 0.8929 gibbs = eg2_0k + dg - zpe / 0.8929 core.print_out(' G2 energy: %20.12lf\n' % internal_energy) core.print_out(' G2 enthalpy: %20.12lf\n' % enthalpy) core.print_out(' G2 free energy: %20.12lf\n' % gibbs) core.set_variable("CURRENT ENERGY", eg2_0k) core.set_variable("G2 INTERNAL ENERGY", internal_energy) core.set_variable("G2 ENTHALPY", enthalpy) core.set_variable("G2 FREE ENERGY", gibbs) core.clean() optstash.restore() # return 0K g2 results return eg2_0k
def ip_fitting(name, omega_l=0.05, omega_r=2.5, omega_convergence=1.0e-3, maxiter=20, **kwargs): """Optimize DFT omega parameter for molecular system. Parameters ---------- name : string or function DFT functional string name or function defining functional whose omega is to be optimized. omega_l : float, optional Minimum omega to be considered during fitting. omega_r : float, optional Maximum omega to be considered during fitting. molecule : :ref:`molecule <op_py_molecule>`, optional Target molecule (neutral) for which omega is to be tuned, if not last defined. omega_convergence : float, optional Threshold below which to consider omega converged. (formerly omega_tolerance) maxiter : int, optional Maximum number of iterations towards omega convergence. Returns ------- float Optimal omega parameter. """ optstash = p4util.OptionsState( ['SCF', 'REFERENCE'], ['SCF', 'GUESS'], ['SCF', 'DF_INTS_IO'], ['SCF', 'DFT_OMEGA'], ['DOCC'], ['SOCC']) kwargs = p4util.kwargs_lower(kwargs) # By default, do not read previous 180 orbitals file read = False read180 = '' if 'read' in kwargs: read = True read180 = kwargs['read'] if core.get_option('SCF', 'REFERENCE') != 'UKS': core.print_out(""" Requested procedure `ip_fitting` runs further calculations with UKS reference.\n""") core.set_local_option('SCF', 'REFERENCE', 'UKS') # Make sure the molecule the user provided is the active one, and neutral molecule = kwargs.pop('molecule', core.get_active_molecule()) molecule.update_geometry() if molecule.molecular_charge() != 0: raise ValidationError("""IP Fitting requires neutral molecule to start.""") if molecule.schoenflies_symbol() != 'c1': core.print_out(""" Requested procedure `ip_fitting` does not make use of molecular symmetry: """ """further calculations in C1 point group.\n""") molecule = molecule.clone() molecule.reset_point_group('c1') molecule.update_geometry() charge0 = molecule.molecular_charge() mult0 = molecule.multiplicity() # How many electrons are there? N = 0 for A in range(molecule.natom()): N += molecule.Z(A) N -= charge0 N = int(N) Nb = int((N - mult0 + 1) / 2) Na = int(N - Nb) # Work in the ot namespace for this procedure core.IO.set_default_namespace("ot") # Burn in to determine orbital eigenvalues if read: core.set_local_option("SCF", "GUESS", "READ") copy_file_to_scratch(read180, 'psi', 'ot', 180) core.set_local_option("SCF", "DF_INTS_IO", "SAVE") E, wfn = driver.energy('scf', dft_functional=name, return_wfn=True, molecule=molecule, banner='IP Fitting SCF: Burn-in', **kwargs) core.set_local_option("SCF", "DF_INTS_IO", "LOAD") if not wfn.functional().is_x_lrc(): raise ValidationError("""Not sensible to optimize omega for non-long-range-correction functional.""") # Determine H**O, to determine mult1 eps_a = wfn.epsilon_a() eps_b = wfn.epsilon_b() if Na == Nb: H**O = -Nb elif Nb == 0: H**O = Na else: E_a = eps_a.np[int(Na - 1)] E_b = eps_b.np[int(Nb - 1)] if E_a >= E_b: H**O = Na else: H**O = -Nb Na1 = Na Nb1 = Nb if H**O > 0: Na1 -= 1 else: Nb1 -= 1 charge1 = charge0 + 1 mult1 = Na1 - Nb1 + 1 omegas = [] E0s = [] E1s = [] kIPs = [] IPs = [] types = [] # Right endpoint core.set_local_option('SCF', 'DFT_OMEGA', omega_r) # Neutral if read: core.set_local_option("SCF", "GUESS", "READ") p4util.copy_file_to_scratch(read180, 'psi', 'ot', 180) molecule.set_molecular_charge(charge0) molecule.set_multiplicity(mult0) E0r, wfn = driver.energy('scf', dft_functional=name, return_wfn=True, molecule=molecule, banner='IP Fitting SCF: Neutral, Right Endpoint', **kwargs) eps_a = wfn.epsilon_a() eps_b = wfn.epsilon_b() if Nb == 0: E_HOMO = eps_a.np[int(Na - 1)] else: E_a = eps_a.np[int(Na - 1)] E_b = eps_b.np[int(Nb - 1)] E_HOMO = max(E_a, E_b) E_HOMOr = E_HOMO core.IO.change_file_namespace(180, "ot", "neutral") # Cation if read: core.set_local_option("SCF", "GUESS", "READ") p4util.copy_file_to_scratch(read180, 'psi', 'ot', 180) molecule.set_molecular_charge(charge1) molecule.set_multiplicity(mult1) E1r = driver.energy('scf', dft_functional=name, molecule=molecule, banner='IP Fitting SCF: Cation, Right Endpoint', **kwargs) core.IO.change_file_namespace(180, "ot", "cation") IPr = E1r - E0r kIPr = -E_HOMOr delta_r = IPr - kIPr if IPr > kIPr: raise ValidationError("""\n***IP Fitting Error: Right Omega limit should have kIP > IP: {} !> {}""".format(kIPr, IPr)) omegas.append(omega_r) types.append('Right Limit') E0s.append(E0r) E1s.append(E1r) IPs.append(IPr) kIPs.append(kIPr) # Use previous orbitals from here out core.set_local_option("SCF", "GUESS", "READ") # Left endpoint core.set_local_option('SCF', 'DFT_OMEGA', omega_l) # Neutral core.IO.change_file_namespace(180, "neutral", "ot") molecule.set_molecular_charge(charge0) molecule.set_multiplicity(mult0) core.set_global_option("DOCC", [Nb]) core.set_global_option("SOCC", [Na - Nb]) E0l, wfn = driver.energy('scf', dft_functional=name, return_wfn=True, molecule=molecule, banner='IP Fitting SCF: Neutral, Left Endpoint', **kwargs) eps_a = wfn.epsilon_a() eps_b = wfn.epsilon_b() if Nb == 0: E_HOMO = eps_a.np[int(Na - 1)] else: E_a = eps_a.np[int(Na - 1)] E_b = eps_b.np[int(Nb - 1)] E_HOMO = max(E_a, E_b) E_HOMOl = E_HOMO core.IO.change_file_namespace(180, "ot", "neutral") # Cation core.IO.change_file_namespace(180, "cation", "ot") molecule.set_molecular_charge(charge1) molecule.set_multiplicity(mult1) core.set_global_option("DOCC", [Nb1]) core.set_global_option("SOCC", [Na1 - Nb1]) E1l = driver.energy('scf', dft_functional=name, molecule=molecule, banner='IP Fitting SCF: Cation, Left Endpoint', **kwargs) core.IO.change_file_namespace(180, "ot", "cation") IPl = E1l - E0l kIPl = -E_HOMOl delta_l = IPl - kIPl if IPl < kIPl: raise ValidationError("""\n***IP Fitting Error: Left Omega limit should have kIP < IP: {} !< {}""".format(kIPl, IPl)) omegas.append(omega_l) types.append('Left Limit') E0s.append(E0l) E1s.append(E1l) IPs.append(IPl) kIPs.append(kIPl) converged = False repeat_l = 0 repeat_r = 0 for step in range(maxiter): # Regula Falsi (modified) if repeat_l > 1: delta_l /= 2.0 if repeat_r > 1: delta_r /= 2.0 omega = - (omega_r - omega_l) / (delta_r - delta_l) * delta_l + omega_l core.set_local_option('SCF', 'DFT_OMEGA', omega) # Neutral core.IO.change_file_namespace(180, "neutral", "ot") molecule.set_molecular_charge(charge0) molecule.set_multiplicity(mult0) core.set_global_option("DOCC", [Nb]) core.set_global_option("SOCC", [Na - Nb]) E0, wfn = driver.energy('scf', dft_functional=name, return_wfn=True, molecule=molecule, banner='IP Fitting SCF: Neutral, Omega = {:11.3E}'.format(omega), **kwargs) eps_a = wfn.epsilon_a() eps_b = wfn.epsilon_b() if Nb == 0: E_HOMO = eps_a.np[int(Na - 1)] else: E_a = eps_a.np[int(Na - 1)] E_b = eps_b.np[int(Nb - 1)] E_HOMO = max(E_a, E_b) core.IO.change_file_namespace(180, "ot", "neutral") # Cation core.IO.change_file_namespace(180, "cation", "ot") molecule.set_molecular_charge(charge1) molecule.set_multiplicity(mult1) core.set_global_option("DOCC", [Nb1]) core.set_global_option("SOCC", [Na1 - Nb1]) E1 = driver.energy('scf', dft_functional=name, molecule=molecule, banner='IP Fitting SCF: Cation, Omega = {:11.3E}'.format(omega), **kwargs) core.IO.change_file_namespace(180, "ot", "cation") IP = E1 - E0 kIP = -E_HOMO delta = IP - kIP if kIP > IP: omega_r = omega E0r = E0 E1r = E1 IPr = IP kIPr = kIP delta_r = delta repeat_r = 0 repeat_l += 1 else: omega_l = omega E0l = E0 E1l = E1 IPl = IP kIPl = kIP delta_l = delta repeat_l = 0 repeat_r += 1 omegas.append(omega) types.append('Regula-Falsi') E0s.append(E0) E1s.append(E1) IPs.append(IP) kIPs.append(kIP) # Termination if abs(omega_l - omega_r) < omega_convergence: converged = True break core.IO.set_default_namespace("") core.print_out("""\n ==> IP Fitting Results <==\n\n""") core.print_out(""" => Occupation Determination <= \n\n""") core.print_out(""" %6s %6s %6s %6s %6s %6s\n""" % ('N', 'Na', 'Nb', 'Charge', 'Mult', 'H**O')) core.print_out(""" Neutral: %6d %6d %6d %6d %6d %6d\n""" % (N, Na, Nb, charge0, mult0, H**O)) core.print_out(""" Cation: %6d %6d %6d %6d %6d\n\n""" % (N - 1, Na1, Nb1, charge1, mult1)) core.print_out(""" => Regula Falsi Iterations <=\n\n""") core.print_out(""" %3s %11s %14s %14s %14s %s\n""" % ('N','Omega','IP','kIP','Delta','Type')) for k in range(len(omegas)): core.print_out(""" %3d %11.3E %14.6E %14.6E %14.6E %s\n""" % (k + 1, omegas[k], IPs[k], kIPs[k], IPs[k] - kIPs[k], types[k])) optstash.restore() if converged: core.print_out("""\n IP Fitting Converged\n""") core.print_out(""" Final omega = %14.6E\n""" % ((omega_l + omega_r) / 2)) core.print_out("""\n "M,I. does the dying. Fleet just does the flying."\n""") core.print_out(""" -Starship Troopers\n""") else: raise ConvergenceError("""IP Fitting """, step + 1) return ((omega_l + omega_r) / 2)
def frac_traverse(name, **kwargs): """Scan electron occupancy from +1 electron to -1. Parameters ---------- name : string or function DFT functional string name or function defining functional whose omega is to be optimized. molecule : :ref:`molecule <op_py_molecule>`, optional Target molecule (neutral) for which omega is to be tuned, if not last defined. cation_mult : int, optional Multiplicity of cation, if not neutral multiplicity + 1. anion_mult : int, optional Multiplicity of anion, if not neutral multiplicity + 1. frac_start : int, optional Iteration at which to start frac procedure when not reading previous guess. Defaults to 25. HOMO_occs : list, optional Occupations to step through for cation, by default `[1 - 0.1 * x for x in range(11)]`. LUMO_occs : list, optional Occupations to step through for anion, by default `[1 - 0.1 * x for x in range(11)]`. H**O : int, optional Index of H**O. LUMO : int, optional Index of LUMO. frac_diis : bool, optional Do use DIIS for non-1.0-occupied points? neutral_guess : bool, optional Do use neutral orbitals as guess for the anion? hf_guess: bool, optional Do use UHF guess before UKS? continuous_guess : bool, optional Do carry along guess rather than reguessing at each occupation? filename : str, optional Result filename, if not name of molecule. Returns ------- dict Dictionary associating SCF energies with occupations. """ optstash = p4util.OptionsState( ['SCF', 'GUESS'], ['SCF', 'DF_INTS_IO'], ['SCF', 'REFERENCE'], ["SCF", "FRAC_START"], ["SCF", "FRAC_RENORMALIZE"], #["SCF", "FRAC_LOAD"], ["SCF", "FRAC_OCC"], ["SCF", "FRAC_VAL"], ["SCF", "FRAC_DIIS"]) kwargs = p4util.kwargs_lower(kwargs) # Make sure the molecule the user provided is the active one, and neutral molecule = kwargs.pop('molecule', core.get_active_molecule()) molecule.update_geometry() if molecule.molecular_charge() != 0: raise ValidationError("""frac_traverse requires neutral molecule to start.""") if molecule.schoenflies_symbol() != 'c1': core.print_out(""" Requested procedure `frac_traverse` does not make use of molecular symmetry: """ """further calculations in C1 point group.\n""") molecule = molecule.clone() molecule.reset_point_group('c1') molecule.update_geometry() charge0 = molecule.molecular_charge() mult0 = molecule.multiplicity() chargep = charge0 + 1 chargem = charge0 - 1 multp = kwargs.get('cation_mult', mult0 + 1) multm = kwargs.get('anion_mult', mult0 + 1) # By default, we start the frac procedure on the 25th iteration # when not reading a previous guess frac_start = kwargs.get('frac_start', 25) # By default, we occupy by tenths of electrons HOMO_occs = kwargs.get('HOMO_occs', [1.0, 0.9, 0.8, 0.7, 0.6, 0.5, 0.4, 0.3, 0.2, 0.1, 0.0]) LUMO_occs = kwargs.get('LUMO_occs', [1.0, 0.9, 0.8, 0.7, 0.6, 0.5, 0.4, 0.3, 0.2, 0.1, 0.0]) # By default, H**O and LUMO are both in alpha Z = 0 for A in range(molecule.natom()): Z += molecule.Z(A) Z -= charge0 H**O = kwargs.get('H**O', (Z / 2 + 1 if (Z % 2) else Z / 2)) LUMO = kwargs.get('LUMO', H**O + 1) # By default, DIIS in FRAC (1.0 occupation is always DIIS'd) frac_diis = kwargs.get('frac_diis', True) # By default, use the neutral orbitals as a guess for the anion neutral_guess = kwargs.get('neutral_guess', True) # By default, burn-in with UHF first, if UKS hf_guess = False if core.get_local_option('SCF', 'REFERENCE') == 'UKS': hf_guess = kwargs.get('hf_guess', True) # By default, re-guess at each N continuous_guess = kwargs.get('continuous_guess', False) # By default, drop the files to the molecule's name root = kwargs.get('filename', molecule.name()) traverse_filename = root + '.traverse.dat' # => Traverse <= # occs = [] energies = [] potentials = [] convs = [] # => Run the neutral for its orbitals, if requested <= # core.set_local_option("SCF", "DF_INTS_IO", "SAVE") old_guess = core.get_local_option("SCF", "GUESS") if (neutral_guess): if (hf_guess): core.set_local_option("SCF", "REFERENCE", "UHF") driver.energy('scf', dft_functional=name, molecule=molecule, **kwargs) core.set_local_option("SCF", "GUESS", "READ") core.set_local_option("SCF", "DF_INTS_IO", "LOAD") # => Run the anion first <= # molecule.set_molecular_charge(chargem) molecule.set_multiplicity(multm) # => Burn the anion in with hf, if requested <= # if hf_guess: core.set_local_option("SCF", "REFERENCE","UHF") driver.energy('scf', dft_functional=name, molecule=molecule, **kwargs) core.set_local_option("SCF", "REFERENCE", "UKS") core.set_local_option("SCF", "GUESS", "READ") core.set_local_option("SCF", "DF_INTS_IO", "SAVE") core.set_local_option("SCF", "FRAC_START", frac_start) core.set_local_option("SCF", "FRAC_RENORMALIZE", True) # NYI core.set_local_option("SCF", "FRAC_LOAD", False) for occ in LUMO_occs: core.set_local_option("SCF", "FRAC_OCC", [LUMO]) core.set_local_option("SCF", "FRAC_VAL", [occ]) E, wfn = driver.energy('scf', dft_functional=name, return_wfn=True, molecule=molecule, **kwargs) C = 1 if E == 0.0: E = core.variable('SCF ITERATION ENERGY') C = 0 if LUMO > 0: eps = wfn.epsilon_a() potentials.append(eps.get(int(LUMO) - 1)) else: eps = wfn.epsilon_b() potentials.append(eps.get(-int(LUMO) - 1)) occs.append(occ) energies.append(E) convs.append(C) core.set_local_option("SCF", "FRAC_START", 2) #core.set_local_option("SCF", "FRAC_LOAD", True) core.set_local_option("SCF", "GUESS", "READ") core.set_local_option("SCF", "FRAC_DIIS", frac_diis) core.set_local_option("SCF", "DF_INTS_IO", "LOAD") # => Run the neutral next <= # molecule.set_molecular_charge(charge0) molecule.set_multiplicity(mult0) # Burn the neutral in with hf, if requested <= # if not continuous_guess: core.set_local_option("SCF", "GUESS", old_guess) if hf_guess: core.set_local_option("SCF", "FRAC_START", 0) core.set_local_option("SCF", "REFERENCE", "UHF") driver.energy('scf', dft_functional=name, molecule=molecule, **kwargs) core.set_local_option("SCF", "REFERENCE", "UKS") core.set_local_option("SCF", "GUESS", "READ") # NYI core.set_local_option("SCF", "FRAC_LOAD", False) core.set_local_option("SCF", "FRAC_START", frac_start) core.set_local_option("SCF", "FRAC_RENORMALIZE", True) for occ in HOMO_occs: core.set_local_option("SCF", "FRAC_OCC", [H**O]) core.set_local_option("SCF", "FRAC_VAL", [occ]) E, wfn = driver.energy('scf', dft_functional=name, return_wfn=True, molecule=molecule, **kwargs) C = 1 if E == 0.0: E = core.variable('SCF ITERATION ENERGY') C = 0 if LUMO > 0: eps = wfn.epsilon_a() potentials.append(eps.get(int(H**O) - 1)) else: eps = wfn.epsilon_b() potentials.append(eps.get(-int(H**O) - 1)) occs.append(occ - 1.0) energies.append(E) convs.append(C) core.set_local_option("SCF", "FRAC_START", 2) # NYI core.set_local_option("SCF", "FRAC_LOAD", True) core.set_local_option("SCF", "GUESS", "READ") core.set_local_option("SCF", "FRAC_DIIS", frac_diis) core.set_local_option("SCF", "DF_INTS_IO", "LOAD") # => Print the results out <= # E = {} core.print_out("""\n ==> Fractional Occupation Traverse Results <==\n\n""") core.print_out(""" %-11s %-24s %-24s %11s\n""" % ('N', 'Energy', 'H**O Energy', 'Converged')) for k in range(len(occs)): core.print_out(""" %11.3E %24.16E %24.16E %11d\n""" % (occs[k], energies[k], potentials[k], convs[k])) E[occs[k]] = energies[k] core.print_out(""" You trying to be a hero Watkins? Just trying to kill some bugs sir! -Starship Troopers""") # Drop the files out with open(traverse_filename, 'w') as fh: fh.write(""" %-11s %-24s %-24s %11s\n""" % ('N', 'Energy', 'H**O Energy', 'Converged')) for k in range(len(occs)): fh.write(""" %11.3E %24.16E %24.16E %11d\n""" % (occs[k], energies[k], potentials[k], convs[k])) optstash.restore() return E
def frac_nuke(name, **kwargs): """Pull all the electrons out, one at a time""" optstash = p4util.OptionsState( ['SCF', 'GUESS'], ['SCF', 'DF_INTS_IO'], ["SCF", "FRAC_START"], ["SCF", "FRAC_RENORMALIZE"], # NYI ["SCF", "FRAC_LOAD"], ["SCF", "FRAC_OCC"], ["SCF", "FRAC_VAL"], ["SCF", "FRAC_DIIS"]) kwargs = p4util.kwargs_lower(kwargs) # Make sure the molecule the user provided is the active one, and neutral molecule = kwargs.pop('molecule', core.get_active_molecule()) molecule.update_geometry() if molecule.molecular_charge() != 0: raise ValidationError("""frac_nuke requires neutral molecule to start.""") if molecule.schoenflies_symbol() != 'c1': core.print_out(""" Requested procedure `frac_nuke` does not make use of molecular symmetry: """ """further calculations in C1 point group.\n""") molecule = molecule.clone() molecule.reset_point_group('c1') molecule.update_geometry() charge0 = molecule.molecular_charge() mult0 = molecule.multiplicity() # By default, we start the frac procedure on the 25th iteration # when not reading a previous guess frac_start = kwargs.get('frac_start', 25) # By default, we occupy by tenths of electrons foccs = kwargs.get('foccs', [1.0, 0.9, 0.8, 0.7, 0.6, 0.5, 0.4, 0.3, 0.2, 0.1, 0.0]) # By default, H**O and LUMO are both in alpha N = 0 for A in range(molecule.natom()): N += molecule.Z(A) N -= charge0 N = int(N) Nb = int((N - mult0 + 1) / 2) Na = int(N - Nb) charge = charge0 mult = mult0 # By default, nuke all the electrons Nmin = 0 if 'nmax' in kwargs: Nmin = N - int(kwargs['nmax']) # By default, DIIS in FRAC (1.0 occupation is always DIIS'd) frac_diis = kwargs.get('frac_diis', True) # By default, drop the files to the molecule's name root = kwargs.get('filename', molecule.name()) traverse_filename = root + '.traverse.dat' stats_filename = root + '.stats.dat' # => Traverse <= # core.set_local_option("SCF", "DF_INTS_IO", "SAVE") Ns = [] energies = [] potentials = [] convs = [] stats = [] # Run one SCF to burn things in E, wfn = driver.energy('scf', dft_functional=name, return_wfn=True, molecule=molecule, **kwargs) # Determine H**O eps_a = wfn.epsilon_a() eps_b = wfn.epsilon_b() eps_a.print_out() if Na == Nb: H**O = -Nb elif Nb == 0: H**O = Na else: E_a = eps_a.get(int(Na - 1)) E_b = eps_b.get(int(Nb - 1)) if E_a >= E_b: H**O = Na else: H**O = -Nb stats.append(""" %6d %6d %6d %6d %6d %6d\n""" % (N, Na, Nb, charge, mult, H**O)) if H**O > 0: Na -= 1 else: Nb -= 1 charge += 1 mult = Na - Nb + 1 core.set_local_option("SCF", "DF_INTS_IO", "LOAD") core.set_local_option("SCF", "FRAC_START", frac_start) core.set_local_option("SCF", "FRAC_RENORMALIZE", True) # Nuke 'em Rico! for Nintegral in range(N, Nmin, -1): # Nuke the current H**O for occ in foccs: core.set_local_option("SCF", "FRAC_OCC", [H**O]) core.set_local_option("SCF", "FRAC_VAL", [occ]) E, wfn = driver.energy('scf', dft_functional=name, return_wfn=True, molecule=molecule, **kwargs) C = 1 if E == 0.0: E = core.variable('SCF ITERATION ENERGY') C = 0 if H**O > 0: eps = wfn.epsilon_a() potentials.append(eps.np[H**O - 1]) else: eps = wfn.epsilon_b() potentials.append(eps.np[-H**O - 1]) Ns.append(Nintegral + occ - 1.0) energies.append(E) convs.append(C) core.set_local_option("SCF", "FRAC_START", 2) # NYI core.set_local_option("SCF", "FRAC_LOAD", True) core.set_local_option("SCF", "FRAC_DIIS", frac_diis) core.set_local_option("SCF", "GUESS", "READ") # Set the next charge/mult molecule.set_molecular_charge(charge) molecule.set_multiplicity(mult) # Determine H**O print('DGAS: What ref should this point to?') #ref = core.legacy_wavefunction() eps_a = wfn.epsilon_a() eps_b = wfn.epsilon_b() if Na == Nb: H**O = -Nb elif Nb == 0: H**O = Na else: E_a = eps_a.np[int(Na - 1)] E_b = eps_b.np[int(Nb - 1)] if E_a >= E_b: H**O = Na else: H**O = -Nb stats.append(""" %6d %6d %6d %6d %6d %6d\n""" % (Nintegral-1, Na, Nb, charge, mult, H**O)) if H**O > 0: Na -= 1 else: Nb -= 1 charge += 1 mult = Na - Nb + 1 core.set_local_option("SCF", "DF_INTS_IO", "NONE") # => Print the results out <= # E = {} core.print_out("""\n ==> Fractional Occupation Nuke Results <==\n\n""") core.print_out(""" %-11s %-24s %-24s %11s\n""" % ('N', 'Energy', 'H**O Energy', 'Converged')) for k in range(len(Ns)): core.print_out(""" %11.3E %24.16E %24.16E %11d\n""" % (Ns[k], energies[k], potentials[k], convs[k])) E[Ns[k]] = energies[k] core.print_out('\n') core.print_out(""" %6s %6s %6s %6s %6s %6s\n""" % ('N', 'Na', 'Nb', 'Charge', 'Mult', 'H**O')) for line in stats: core.print_out(line) core.print_out('\n "You shoot a nuke down a bug hole, you got a lot of dead bugs"\n') core.print_out(' -Starship Troopers\n') # Drop the files out with open(traverse_filename, 'w') as fh: fh.write(""" %-11s %-24s %-24s %11s\n""" % ('N', 'Energy', 'H**O Energy', 'Converged')) for k in range(len(Ns)): fh.write(""" %11.3E %24.16E %24.16E %11d\n""" % (Ns[k], energies[k], potentials[k], convs[k])) with open(stats_filename, 'w') as fh: fh.write(""" %6s %6s %6s %6s %6s %6s\n""" % ('N', 'Na', 'Nb', 'Charge', 'Mult', 'H**O')) for line in stats: fh.write(line) optstash.restore() return E
def run_psi4(para: dict): try: if (not para.__contains__("multiplicity")): para["multiplicity"] = 1 if (not para.__contains__("charge")): para["charge"] = 0 if (not para.__contains__("basis")): para["basis"] = 0 if (not para.__contains__("EQ_TOLERANCE")): para["EQ_TOLERANCE"] = 1e-8 str_mol = para["mol"] str_mol = str_mol + "\n symmetry c1" mol = geometry(str_mol, "mol") core.IO.set_default_namespace("mol") mol.set_multiplicity(para["multiplicity"]) mol.set_molecular_charge(para["charge"]) core.set_global_option("BASIS", para["basis"]) core.set_global_option("SCF_TYPE", "pk") core.set_global_option("SOSCF", "false") core.set_global_option("FREEZE_CORE", "false") core.set_global_option("DF_SCF_GUESS", "false") core.set_global_option("OPDM", "true") core.set_global_option("TPDM", "true") core.set_global_option("MAXITER", 1e6) core.set_global_option("NUM_AMPS_PRINT", 1e6) core.set_global_option("R_CONVERGENCE", 1e-6) core.set_global_option("D_CONVERGENCE", 1e-6) core.set_global_option("E_CONVERGENCE", 1e-6) core.set_global_option("DAMPING_PERCENTAGE", 0) if mol.multiplicity == 1: core.set_global_option("REFERENCE", "rhf") core.set_global_option("GUESS", "sad") else: core.set_global_option("REFERENCE", "rohf") core.set_global_option("GUESS", "gwh") hf_energy, hf_wavefunction = energy('scf', return_wfn=True) except Exception as exception: return (-1, traceback.format_exc()) else: nuclear_repulsion = mol.nuclear_repulsion_energy() canonical_orbitals = numpy.asarray(hf_wavefunction.Ca()) mints = core.MintsHelper(hf_wavefunction.basisset()) fermion_str = get_molecular_hamiltonian(mints, canonical_orbitals, nuclear_repulsion, para["EQ_TOLERANCE"]) return (0, fermion_str)