def ccsd(cls, hfwavefunction, hamiltonian, maxiter=100, cutoff=1e-6): occ = hfwavefunction.occ Nelec = occ['alpha'] + occ['beta'] C = hfwavefunction.coefficient dim = hamiltonian.dim * 2 #Transfer Fock integral from spatial to spin basis fs = spinfock(hfwavefunction.eorbitals) #Transfer electron repulsion integral from atomic basis #to molecular basis hamiltonian.operators['electron_repulsion'].basis_transformation(C) #build double bar integral <ij||kl> spinints = hamiltonian.operators['electron_repulsion'].double_bar ts, td, Dai, Dabij = initialize(fs, spinints, Nelec, dim) ECCSD = 0 DECC = 1.0 Iter = 0 log.hline() log('{0:2s} {1:3s} {2:4s}'.format('Iter', 'ECC', 'Delta')) log.hline() while DECC > cutoff or Iter > maxiter: # arbitrary convergence criteria Iter += 1 OLDCC = ECCSD Fae, Fmi, Fme, Wmnij, Wabef, Wmbej = updateintermediates( True, Nelec, dim, fs, spinints, ts, td) ts = makeT1(True, Nelec, dim, fs, spinints, ts, td, Dai, Fae, Fmi, Fme) td = makeT2(True, Nelec, dim, fs, spinints, ts, td, Dabij, Fae, Fmi, Fme, Wmnij, Wabef, Wmbej) ECCSD = ccsdenergy(Nelec, dim, fs, spinints, ts, td) DECC = abs(ECCSD - OLDCC) log('{0:2d} {1:3f} {2:4f}'.format(Iter, ECCSD, DECC)) print('CC iterations converged') print("E(corr,CCSD) = ", ECCSD)
def hf(cls,hamiltonian,occ,maxiter=100,cutoff=1e-6): Norb = hamiltonian.dim #Form the core Hamiltonian Hcore = hamiltonian.operators['kinetic'].value + hamiltonian.operators['nuclear_attraction'].value #Build the orthogonalization matrix X = orthogonalization_matrix(hamiltonian.operators['overlap'].value) #Initial guess of density matrix if occ['alpha']==occ['beta']: D = np.zeros((Norb,Norb)) else: D = {'alpha':np.zeros((Norb,Norb)),'beta':np.zeros((Norb,Norb))} #iteration section Iter = 0 RMS = 1.0 log.hline() log('{0:2s} {1:3s} {2:4s} {3:5s}'.format('Iter', 'E(elec)', 'E(tot)','RMS')) log.hline() while RMS > cutoff and Iter < maxiter: Iter += 1 G = G_matrix(D,hamiltonian.operators['electron_repulsion'].value,Norb) F = F_matrix(Hcore,G,Norb) eorbitals,C = C_matrix(F,X,Norb) OLDD = D D = D_matrix(C,Norb,occ) RMS = deltap(D,OLDD,Norb) Eelec = energy(D,Hcore,F,Norb) Etot = Eelec + hamiltonian.operators['nuclear_repulsion'].value log('{0:2d} {1:3f} {2:4f} {3:5f}'.format(Iter, Eelec, Etot, RMS)) return HFWaveFunction(Norb,occ,C,D,F,eorbitals,Eelec,Etot)
def kernel(self): """Kernel of the solver. Returns ------- results : dict CCSD calculation results. """ log.hline() log('CCSD Section'.format()) log.hline() ham = copy.deepcopy(self.ham) wfn = copy.deepcopy(self.wfn) hf_results = self.hf_results occ = wfn.occ Nelec = occ['alpha'] + occ['beta'] C = wfn.coefficients nspin = ham.nspin #Transfer Fock integral from spatial to spin basis fs = spinfock(hf_results['orbital_energies']) #Transfer electron repulsion integral from atomic basis #to molecular basis ham.operators['electron_repulsion'].basis_transformation(C) #build double bar integral <ij||kl> spinints = ham.operators['electron_repulsion'].double_bar ts, td, Dai, Dabij = initialize(fs, spinints, Nelec, nspin) ECCSD = 0 DECC = 1.0 Iter = 0 log.hline() log('{0:2s} {1:3s} {2:4s}'.format('Iter', 'ECC', 'Delta')) log.hline() while DECC > self.E_conv or Iter > self.maxiter: # arbitrary convergence criteria Iter += 1 OLDCC = ECCSD Fae, Fmi, Fme, Wmnij, Wabef, Wmbej = updateintermediates( True, Nelec, nspin, fs, spinints, ts, td) ts = makeT1(True, Nelec, nspin, fs, spinints, ts, td, Dai, Fae, Fmi, Fme) td = makeT2(True, Nelec, nspin, fs, spinints, ts, td, Dabij, Fae, Fmi, Fme, Wmnij, Wabef, Wmbej) ECCSD = ccsdenergy(Nelec, nspin, fs, spinints, ts, td) DECC = abs(ECCSD - OLDCC) log('{0:2d} {1:3f} {2:4f}'.format(Iter, ECCSD, DECC)) log.hline() log('CCSD Energy = {}'.format(ECCSD)) log('Total Energy = {}'.format(hf_results['total_energy'] + ECCSD)) log.hline() results = { "success": True, "CCSD_energy": ECCSD, "total_energy": hf_results['total_energy'] + ECCSD } return results
def kernel(self): """Kernel of the solver. Returns ------- results : dict MP2 calculation results. """ log.hline() log('MP2 calculation section'.format()) log.hline() ham = copy.deepcopy(self.ham) wfn = copy.deepcopy(self.wfn) hf_results = self.hf_results nspatial = ham.nspatial occ = wfn.occ C = wfn.coefficients eorbitals = hf_results['orbital_energies'] Emp2 = 0.0 if isinstance(ham, RestrictedChemicalHamiltonian): ham.operators['electron_repulsion'].basis_transformation(C) Eri = ham.operators['electron_repulsion'].integral for i in range(occ['alpha']): for j in range(occ['alpha']): for a in range(occ['alpha'], nspatial): for b in range(occ['alpha'], nspatial): Emp2 += Eri[i,a,j,b]*(2*Eri[i,a,j,b]-Eri[i,b,j,a])\ /(eorbitals[i] + eorbitals[j] -eorbitals[a] - eorbitals[b]) log.hline() log('MP2 Results'.format()) log.hline() log('{0:2s} {1:3f}'.format('Escf', hf_results['total_energy'])) log('{0:2s} {1:3f}'.format('Emp2', Emp2)) log('{0:2s} {1:3f}'.format('Etot', hf_results['total_energy'] + Emp2)) log.hline() results = { "success": True, "MP2_energy": Emp2, "total_energy": hf_results['total_energy'] + Emp2 } return results
def mp2(cls,hfwavefunction,hamiltonian): occ = hfwavefunction.occ C = hfwavefunction.coefficient eorbitals = hfwavefunction.eorbitals Emp2 = 0.0 if occ['alpha'] == occ['beta']: Eri = hamiltonian.operators['electron_repulsion'].basis_transformation(C) for i in range(occ['alpha']): for j in range(occ['alpha']): for a in range(occ['alpha'],hamiltonian.dim): for b in range(occ['alpha'],hamiltonian.dim): Emp2 += Eri[i,a,j,b]*(2*Eri[i,a,j,b]-Eri[i,b,j,a])/(eorbitals[i] + eorbitals[j] -eorbitals[a] - eorbitals[b]) elif occ['alpha'] != occ['beta']: for spin in C: Eri = hamiltonian.operators['electron_repulsion'].basis_transformation(C[spin]) for i in range(occ[spin]): for j in range(occ[spin]): for a in range(occ[spin],hamiltonian.dim): for b in range(occ[spin],hamiltonian.dim): Emp2 += Eri[i,a,j,b]*(Eri[i,a,j,b]-0.5*Eri[i,b,j,a])/(eorbitals[spin][i] + eorbitals[spin][j] -eorbitals[spin][a] - eorbitals[spin][b]) log.hline() log('{0:2s} {1:3f}'.format('Escf', hfwavefunction.Etot)) log('{0:2s} {1:3f}'.format('Emp2', Emp2)) log('{0:2s} {1:3f}'.format('Etot', hfwavefunction.Etot+Emp2)) log.hline() return Emp2
def kernel(self): """Kernel of the solver. Returns ------- results : dict CISD calculation results. """ log.hline() log('CISD Section'.format()) log.hline() ham = copy.deepcopy(self.ham) wfn = copy.deepcopy(self.wfn) hf_results = self.hf_results nelec = wfn.nelec nspatial = wfn.nspatial ci_basis = copy.deepcopy(CIBasisSet(wfn, [0, 1, 2])) H = RestrictedCIHamiltonian(ham, wfn, ci_basis) ci_matrix = H.generate_matrix(ci_basis) e_ci, vec_ci = np.linalg.eigh(ci_matrix) E_ci_elec = e_ci[0] E_hf_elec = hf_results['electronic_energy'] E_corr = E_ci_elec - E_hf_elec E_ci_tot = E_ci_elec + ham.operators['nuclear_repulsion'].integral #Build the ci wavefunction. ci_wfn = CIWaveFunction(nelec, nspatial, {}, ci_basis, vec_ci[0]) log.hline() log('CISD Results') log.hline() log('CISD Correlation energy = {}'.format(E_corr)) log('Total energy = {}'.format(E_ci_tot)) log.hline() results = {"total_energy": E_ci_tot} return results, ci_wfn
def kernel(self): """Kernel of the solver. Returns ------- results : dict Full CI calculation results. """ log.hline() log('Full CI Section'.format()) log.hline() ham = copy.deepcopy(self.ham) wfn = copy.deepcopy(self.wfn) hf_results = self.hf_results occ = wfn.occ['alpha'] + wfn.occ['beta'] vir = wfn.nspin - occ excitation_level = list(range(min(occ, vir) + 1)) ci_basis = CIBasisSet(wfn, excitation_level) H = RestrictedCIHamiltonian(ham, wfn, ci_basis) ci_matrix = H.generate_matrix(ci_basis) e_ci, vec_ci = np.linalg.eigh(ci_matrix) E_ci_elec = e_ci[0] E_hf_elec = hf_results['electronic_energy'] E_corr = E_ci_elec - E_hf_elec E_ci_tot = E_ci_elec + ham.operators['nuclear_repulsion'].integral log.hline() log('Results'.format()) log.hline() log('Full CI Correlation energy = {}'.format(E_corr)) log('Total energy = {}'.format(E_ci_tot)) log.hline() results = {"total_energy": E_ci_tot} return results
def kernel(self): """Kernel of the solver. Returns ------- results : dict MP3 calculation results. """ log.hline() log('MP3 Calculation Section'.format()) log.hline() ham = copy.deepcopy(self.ham) wfn = copy.deepcopy(self.wfn) hf_results = self.hf_results nspatial = ham.nspatial occ = wfn.occ C = wfn.coefficients eorbitals = hf_results['orbital_energies'] Emp2 = 0.0 ham.operators['electron_repulsion'].basis_transformation(C) Eri = ham.operators['electron_repulsion'].integral for i in range(occ['alpha']): for j in range(occ['alpha']): for a in range(occ['alpha'], nspatial): for b in range(occ['alpha'], nspatial): Emp2 += Eri[i,a,j,b]*(2*Eri[i,a,j,b]-Eri[i,b,j,a])\ /(eorbitals[i] + eorbitals[j] -eorbitals[a] - eorbitals[b]) Emp3 = 0.0 Eri = ham.operators['electron_repulsion'].double_bar for i in range(occ['alpha']): for j in range(occ['alpha']): for k in range(occ['alpha']): for l in range(occ['alpha']): for a in range(occ['alpha'], nspatial): for b in range(occ['alpha'], nspatial): Emp3 += (1/8.0)*Eri[i,j,a,b]*Eri[k,l,i,j]*Eri[a,b,k,l]\ /((eorbitals[i] + eorbitals[j] -eorbitals[a] - eorbitals[b])\ *(eorbitals[k] + eorbitals[l] -eorbitals[a] - eorbitals[b])) for i in range(occ['alpha']): for j in range(occ['alpha']): for a in range(occ['alpha'], nspatial): for b in range(occ['alpha'], nspatial): for c in range(occ['alpha'], nspatial): for d in range(occ['alpha'], nspatial): Emp3 += (1/8.0)*Eri[i,j,a,b]*Eri[a,b,c,d]*Eri[c,d,i,j]\ /((eorbitals[i] + eorbitals[j] -eorbitals[a] - eorbitals[b])\ *(eorbitals[i] + eorbitals[j] -eorbitals[c] - eorbitals[d])) for i in range(occ['alpha']): for j in range(occ['alpha']): for k in range(occ['alpha']): for a in range(occ['alpha'], nspatial): for b in range(occ['alpha'], nspatial): for c in range(occ['alpha'], nspatial): Emp3 += Eri[i,j,a,b]*Eri[k,b,c,j]*Eri[a,c,i,k]\ /((eorbitals[i] + eorbitals[j] -eorbitals[a] - eorbitals[b])\ *(eorbitals[i] + eorbitals[k] -eorbitals[c] - eorbitals[c])) log.hline() log('MP3 Results'.format()) log.hline() log('{0:2s} {1:3f}'.format('Escf', hf_results['total_energy'])) log('{0:2s} {1:3f}'.format('Emp2', Emp2)) log('{0:2s} {1:3f}'.format('Emp3', Emp3)) log('{0:2s} {1:3f}'.format('Etot', hf_results['total_energy'] + Emp2 + Emp3)) log.hline() results = { "success": True, "MP2_energy": Emp2, "MP3_energy": Emp3, "total_energy": hf_results['total_energy'] + Emp2 + Emp3 } return results
def kernel(self): """Kernel of the solver. Returns ------- results : dict Hartree Fock calculation results. """ log.hline() log('SCF Calculation Section'.format()) log.hline() # Set defaults ham = self.ham occ = self.wfn.occ Norb = ham.nspatial maxiter = self.maxiter E_conv = self.E_conv D_conv = self.D_conv #Form the core Hamiltonian Hcore = ham.operators['kinetic'].integral + ham.operators[ 'nuclear_attraction'].integral #Build the orthogonalization matrix X = orthogonalization_matrix(ham.operators['overlap'].integral) #Initial guess of density matrix D = np.zeros((Norb, Norb)) #iteration section Enuc = ham.operators['nuclear_repulsion'].integral RMS = 1.0 Eold = 0.0 log.hline() log('{0:2s}\t {1:3s}\t {2:4s}\t\t {3:5s}'.format( 'Iter', 'E(elec)', 'dE', 'dRMS')) log.hline() for Iter in range(1, maxiter + 1): Iter += 1 G = G_matrix(D, ham.operators['electron_repulsion'].integral, Norb) F = F_matrix(Hcore, G, Norb) Eorbs, C = C_matrix(F, X, Norb) OLDD = D D = D_matrix(C, Norb, occ) dRMS = deltap(D, OLDD, Norb) Eelec = energy(D, Hcore, F, Norb) log('{0:2d}\t {1:3f}\t {2:4f}\t {3:5f}'.format( Iter, Eelec, Eelec - Eold, dRMS)) if (abs(Eelec - Eold) < E_conv) and (dRMS < D_conv): break Eold = Eelec if Iter == maxiter: raise Exception("Maximum number of SCF cycles exceeded.") log.hline() log('SCF Results'.format()) log.hline() log('Electronic Energy = {}'.format(Eelec)) log('Nuclear Energy = {}'.format(Enuc)) log('Total Energy = {}'.format(Eelec + Enuc)) log.hline() self.wfn.assign_coefficients(C) results = { "success": True, "electronic_energy": Eelec, "nuclear_energy": Enuc, "total_energy": Eelec + Enuc, "orbital_energies": Eorbs } return results
def kernel(self): """Kernel of the solver. Returns ------- results : dict Hartree Fock calculation results. """ log.hline() log('SCF DIIS Calculation Section'.format()) log.hline() # Set defaults ham = self.ham wfn = self.wfn maxiter = self.maxiter E_conv = self.E_conv D_conv = self.D_conv # Overlap Integral S = ham.operators['overlap'].integral # Get occ nbf and ndocc for closed shell molecules occ = wfn.occ nspatial = ham.nspatial ndocc = wfn.occ['alpha'] # Compute required quantities for SCF V = ham.operators['nuclear_attraction'].integral T = ham.operators['kinetic'].integral I = ham.operators['electron_repulsion'].integral # Build H_core H = T + V # Orthogonalizer A = S^(-1/2) A = np.array(ham.operators['overlap'].integral) A = orthogonalization_matrix(A, type='symmetric') # Calculate initial core guess: [Szabo:1996] pp. 145 Hp = A.dot(H).dot(A) # Eqn. 3.177 e, C2 = np.linalg.eigh(Hp) # Solving Eqn. 1.178 C = A.dot(C2) # Back transform, Eqn. 3.174 Cocc = C[:, :ndocc] D = D_matrix(C, nspatial, occ) E = 0.0 Enuc = ham.operators['nuclear_repulsion'].integral Eold = 0.0 Fock_list = [] DIIS_error = [] log.hline() log('{0:2s}\t {1:3s}\t {2:4s}\t\t {3:5s}'.format( 'Iter', 'E(elec)', 'dE', 'dRMS')) log.hline() for Iter in range(1, maxiter + 1): # Build fock matrix J = np.einsum('pqrs,rs->pq', I, D) K = np.einsum('prqs,rs->pq', I, D) F = H + J * 2 - K # DIIS error build w/ HF analytic gradient ([Pulay:1969:197]) diis_e = np.einsum('ij,jk,kl->il', F, D, S) - np.einsum( 'ij,jk,kl->il', S, D, F) diis_e = A.dot(diis_e).dot(A) Fock_list.append(F) DIIS_error.append(diis_e) dRMS = np.mean(diis_e**2)**0.5 # SCF energy and update: [Szabo:1996], Eqn. 3.184, pp. 150 Eelec = np.einsum('pq,pq->', F + H, D) log('{0:2d}\t {1:3f}\t {2:4f}\t {3:5f}'.format( Iter, Eelec, Eelec - Eold, dRMS)) if (abs(Eelec - Eold) < E_conv) and (dRMS < D_conv): break Eold = Eelec if Iter >= 2: # Limit size of DIIS vector diis_count = len(Fock_list) if diis_count > 6: # Remove oldest vector del Fock_list[0] del DIIS_error[0] diis_count -= 1 # Build error matrix B, [Pulay:1980:393], Eqn. 6, LHS B = np.empty((diis_count + 1, diis_count + 1)) B[-1, :] = -1 B[:, -1] = -1 B[-1, -1] = 0 for num1, e1 in enumerate(DIIS_error): for num2, e2 in enumerate(DIIS_error): if num2 > num1: continue val = np.einsum('ij,ij->', e1, e2) B[num1, num2] = val B[num2, num1] = val # normalize B[:-1, :-1] /= np.abs(B[:-1, :-1]).max() # Build residual vector, [Pulay:1980:393], Eqn. 6, RHS resid = np.zeros(diis_count + 1) resid[-1] = -1 # Solve Pulay equations, [Pulay:1980:393], Eqn. 6 ci = np.linalg.solve(B, resid) # Calculate new fock matrix as linear # combination of previous fock matrices F = np.zeros_like(F) for num, c in enumerate(ci[:-1]): F += c * Fock_list[num] # Diagonalize Fock matrix Fp = A.dot(F).dot(A) Eorbs, C2 = np.linalg.eigh(Fp) C = A.dot(C2) Cocc = C[:, :ndocc] D = np.einsum('pi,qi->pq', Cocc, Cocc) if Iter == maxiter: raise Exception("Maximum number of SCF cycles exceeded.") log.hline() log('SCF Results'.format()) log.hline() log('Electronic Energy = {}'.format(Eelec)) log('Nuclear Energy = {}'.format(Enuc)) log('Total Energy = {}'.format(Eelec + Enuc)) log.hline() self.wfn.assign_coefficients(C) results = { "success": True, "electronic_energy": Eelec, "nuclear_energy": Enuc, "total_energy": Eelec + Enuc, "orbital_energies": Eorbs } return results