def pyquante_2_to_1_molecule(old_molecule): from PyQuante.Atom import Atom from PyQuante import Molecule # new_atoms = [] # for old_atom in old_molecule.atoms: # new_atom = Atom(atno=old_atom.Z, # x=old_atom.r[0], # y=old_atom.r[1], # z=old_atom.r[2]) # new_atoms.append(new_atom) # new_molecule = Molecule(name=old_molecule.name, # atomlist=new_atoms, # units=old_molecule.units, # charge=old_molecule.charge, # multiplicity=old_molecule.multiplicity) new_molecule = Molecule(name=old_molecule.name, units=old_molecule.units, charge=old_molecule.charge, multiplicity=old_molecule.multiplicity) for old_atom in old_molecule.atoms: new_atom = Atom(atno=old_atom.Z, x=old_atom.r[0], y=old_atom.r[1], z=old_atom.r[2]) new_molecule.add_atom(new_atom) return new_molecule
def pyq1_dft(atomtuples=[(2, (0, 0, 0))], basis='6-31G**', maxit=10, xcname='SVWN'): from PyQuante import Ints, settings, Molecule from PyQuante.dft import getXC from PyQuante.MG2 import MG2 as MolecularGrid from PyQuante.LA2 import mkdens, geigh, trace2 from PyQuante.Ints import getJ print("PyQ1 DFT run") atoms = Molecule('Pyq1', atomlist=atomtuples) bfs = Ints.getbasis(atoms, basis=basis) S, h, Ints = Ints.getints(bfs, atoms) nclosed, nopen = nel // 2, nel % 2 assert nopen == 0 enuke = atoms.get_enuke() grid_nrad = settings.DFTGridRadii grid_fineness = settings.DFTGridFineness gr = MolecularGrid(atoms, grid_nrad, grid_fineness) gr.set_bf_amps(bfs) orbe, orbs = geigh(h, S) eold = 0 for i in range(maxit): D = mkdens(orbs, 0, nclosed) gr.setdens(D) J = getJ(Ints, D) Exc, Vxc = getXC(gr, nel, functional=xcname) F = h + 2 * J + Vxc orbe, orbs = geigh(F, S) Ej = 2 * trace2(D, J) Eone = 2 * trace2(D, h) energy = Eone + Ej + Exc + enuke print(i, energy, Eone, Ej, Exc, enuke) if np.isclose(energy, eold): break eold = energy return energy
def generate_data(): mol = Molecule.from_file("eth.cml") scf = SCF(mol, basis="sto3g") scf.iterate() shelf = open_shelf() shelf["scf"]=scf shelf.close()
def make_grid(maker = np.ogrid): mol = Molecule.from_file("eth.cml") mc = mass_centre(mol) x,y,z = mc DIM = 5 grid = maker[-DIM + x :DIM +x:32j,-DIM +y:DIM+y:32j,-DIM+z:DIM+z:32j] return grid
def generate_data(): mol = Molecule.from_file("eth.cml") scf = SCF(mol, basis="sto3g") scf.iterate() shelf = open_shelf() shelf["scf"] = scf shelf.close()
def pyq1_dft(atomtuples=[(2,(0,0,0))],basis = '6-31G**',maxit=10, xcname='SVWN'): from PyQuante import Ints,settings,Molecule from PyQuante.dft import getXC from PyQuante.MG2 import MG2 as MolecularGrid from PyQuante.LA2 import mkdens,geigh,trace2 from PyQuante.Ints import getJ print ("PyQ1 DFT run") atoms = Molecule('Pyq1',atomlist=atomtuples) bfs = Ints.getbasis(atoms,basis=basis) S,h,Ints = Ints.getints(bfs,atoms) nclosed,nopen = nel//2,nel%2 assert nopen==0 enuke = atoms.get_enuke() grid_nrad = settings.DFTGridRadii grid_fineness = settings.DFTGridFineness gr = MolecularGrid(atoms,grid_nrad,grid_fineness) gr.set_bf_amps(bfs) orbe,orbs = geigh(h,S) eold = 0 for i in range(maxit): D = mkdens(orbs,0,nclosed) gr.setdens(D) J = getJ(Ints,D) Exc,Vxc = getXC(gr,nel,functional=xcname) F = h+2*J+Vxc orbe,orbs = geigh(F,S) Ej = 2*trace2(D,J) Eone = 2*trace2(D,h) energy = Eone + Ej + Exc + enuke print (i,energy,Eone,Ej,Exc,enuke) if np.isclose(energy,eold): break eold = energy return energy
def make_grid(maker=np.ogrid): mol = Molecule.from_file("eth.cml") mc = mass_centre(mol) x, y, z = mc DIM = 5 grid = maker[-DIM + x:DIM + x:32j, -DIM + y:DIM + y:32j, -DIM + z:DIM + z:32j] return grid
def testLoadFile(self, ): """ """ mol = Molecule.from_file(CML, format="cml") self.assertEqual(mol[0].atno, 1) self.assertRaises(IOError, Molecule.from_file, INEXISTENT, format="cml")
def test(): from PyQuante import Molecule h2 = Molecule('H2', [(1, (0.00000000, 0.00000000, 0.5)), (1, (0.00000000, 0.00000000, -0.5))], units='Angstrom') h2opt = SteepestDescent(h2) print h2opt return
def display_atoms(): mol = Molecule.from_file("eth.cml") cords = [] power = [] mc = mass_centre(mol) for atom in mol: cords.append(atom.r) power.append(atom.atno) x, y, z = zip(*cords) from enthought.mayavi import mlab mlab.points3d(x, y, z, power, scale_mode='none')
def display_atoms(): mol = Molecule.from_file("eth.cml") cords=[] power = [] mc = mass_centre(mol) for atom in mol: cords.append(atom.r ) power.append(atom.atno) x,y,z = zip(*cords) from enthought.mayavi import mlab mlab.points3d(x,y,z,power,scale_mode='none')
def pyquante1(self, name="pyq2 molecule"): """ Make a PyQuante1 Molecule object that can be passed into that program for testing/debugging purposes. """ from PyQuante import Molecule atuples = [(a.atno, tuple(a.r)) for a in self.atoms] return Molecule(name, atuples, charge=self.charge, multiplicity=self.multiplicity)
def test(): import logging h2 = Molecule('H2', atomlist=[(1, (0.35, 0, 0)), (1, (-0.35, 0, 0))], units='Angs') #logging.info("\nRegular eigensolver") h2_normal = HFSolver(h2) h2_normal.iterate() logging.info("\nNormal eigensolver, in subspace of existing orbitals") h2_sub = SubspaceSolver(h2, eigh) h2_sub.iterate() logging.info("\nDavidson eigensolve in subspace of existing orbitals") dav = init_davidson(2) # Have to look for more than 1 root h2_dav = SubspaceSolver(h2, dav) h2_dav.iterate() logging.info("\nJacobi eigensolve in subspace of existing orbitals") jac = init_jacobi() h2_jac = SubspaceSolver(h2, jac) h2_jac.iterate() logging.info("\nDensity Matrix Purification") from PyQuante.DMP import TCP, init_dmat_solver solver = init_dmat_solver(TCP) h2solv = DmatSolver(h2, solver) h2solv.iterate() logging.info("\nCanonical Purification") from PyQuante.DMP import CP, init_dmat_solver solver = init_dmat_solver(CP) h2solv = DmatSolver(h2, solver) h2solv.iterate() logging.info("\nMcWeeny Purification") from PyQuante.DMP import McWeeny, init_dmat_solver solver = init_dmat_solver(McWeeny) h2solv = DmatSolver(h2, solver) h2solv.iterate() logging.info("\nTrace Resetting Purification") from PyQuante.DMP import TRP, init_dmat_solver solver = init_dmat_solver(TRP) h2solv = DmatSolver(h2, solver) h2solv.iterate()
""" Calculates the Boron atom using DFT. """ from PyQuante import SCF, Molecule, dft, Atom B = Molecule('Boron',[(5, (0,0,0))]) B.multiplicity = 2 E, eigs, orbitals = dft.dft(B) print "total energy:", E print "KS energies:", eigs
#!/usr/bin/env python from PyQuante import Molecule from PyQuante.dft import dft h2o = Molecule('h2o', [(1, (0.7570, 0.5860, 0.0)), (1, (-0.757, 0.5860, 0.0)), (8, (0, 0, 0))], units="Bohr") en, orbe, orbs = dft(h2o, functional="LDA", basis="sto-3g")
energy = get_energy(h, F, D, enuke) print "%d %f" % (i, energy) if abs(energy - eold) < 1e-4: break eold = energy print "Final HF energy for system %s is %f" % (atoms.name, energy) return energy, orbe, orbs # Data Li_x1 = -0.200966 H_x1 = 1.399033 Li_x2 = -0.351691 H_x2 = 2.448309 # Construct a molecule: LiH1 = Molecule('LiH1', [('Li', (Li_x1, 0, 0)), ('H', (H_x1, 0, 0))], units='Angs') bfs1 = getbasis(LiH1) S1, h1, Ints1 = getints(bfs1, LiH1) simple_hf(LiH1, S1, h1, Ints1) # Make another molecule LiH2 = Molecule('LiH2', [('Li', (Li_x2, 0, 0)), ('H', (H_x2, 0, 0))], units='Angs') bfs2 = getbasis(LiH2) S2, h2, Ints2 = getints(bfs2, LiH2) simple_hf(LiH2, S2, h2, Ints2) # Make a superset of the two basis sets: bfs_big = bfs1 + bfs2 # and make a basis set with it: S1a, h1a, Ints1a = getints(bfs_big, LiH1)
#2nd iteration of Hartree Fock Python Implementation, with use of Pyquante as an integral library #Each numbered section refers to coressponding step in Szabo QM Textbook on page 161 from PyQuante import Molecule, Ints from PyQuante import LA2 as linalg from PyQuante.NumWrap import eigh, matrixmultiply from PyQuante import hartree_fock as HF #Global Variables############################ convergenceLimit = 1.0 * pow(10, -6) maxCycle = 50 #Section 1############################ #specify a molecule molecule = Molecule("H2", [(1, (0, 0, 0)), (1, (0, 0, 1)), (8, (-1, 0, 0))]) basisSet = Ints.getbasis(molecule, "sto-3g") #Section 2############################ #Overlap Matrix S = Ints.getS(basisSet) #Follwing Two matrices compose the core Hamiltonian #KE Matrix KE = Ints.getT(basisSet) #External Potential, Nuclear - Electron Attraction Vext = Ints.getV(basisSet, molecule) #Form Hcore Hcore = KE + Vext
def main(argv): ############################ # Initialize MPI ############################ comm = MPI.COMM_WORLD rank = comm.rank ############################ parser = argparse.ArgumentParser( description='Hartree Fock Calculation from scratch') # molecule information parser.add_argument('mol', help='xyz file of the molecule', type=str) parser.add_argument('-basis', default='sto-3g', help='basis set to be used in the calculation', type=str) parser.add_argument('-charge', default=0, help='Charge of the system', type=float) parser.add_argument('-units', default='angs', help='Units in the xyz file', type=str) # HF calculations parser.add_argument('-MaxIter', default=100, help='Maximum number of SCF iterations', type=int) parser.add_argument('-eps_SCF', default=1E-4, help='Criterion for SCF termination', type=float) # LR-TDHF arguments parser.add_argument( '-nb_exc', default=10, help='Number of excitations to compute in the Davidson diagonalization', type=int) parser.add_argument('-tda', default=0, help='Perform the Tamm-Dancoff approximation', type=int) parser.add_argument( '-hermitian', default=1, help='Reduce the TDHD equation to their hermitian form', type=int) # export parser.add_argument('-nb_print_mo', default=10, help='Number of orbitals to be written', type=int) parser.add_argument('-export_mo', default=1, help='Export the MO in Gaussian Cube format', type=int) parser.add_argument('-export_blender', default=0, help='Export the MO in bvox format', type=int) ''' Possible basis '3-21g' 'sto3g' 'sto-3g' 'sto-6g' '6-31g' '6-31g**' '6-31g(d,p)' '6-31g**++' '6-31g++**' '6-311g**' '6-311g++(2d,2p)' '6-311g++(3d,3p)' '6-311g++(3df,3pd)' 'lacvp' 'ccpvdz' 'cc-pvdz' 'ccpvtz' 'cc-pvtz' 'ccpvqz' 'cc-pvqz' 'ccpv5z' 'cc-pv5z' 'ccpv6z' 'cc-pv6z' 'augccpvdz' 'aug-cc-pvdz' 'augccpvtz' 'aug-cc-pvtz' 'augccpvqz' 'aug-cc-pvqz' 'augccpv5z' 'aug-cc-pv5z' 'augccpv6z' 'aug-cc-pv6z' 'dzvp':'dzvp', ''' # done args = parser.parse_args() if rank == 0: print '\n\n==================================================' print '== PyQuante - Linear response TDHF calculation ==' print '== MPI version on %02d procs ==' % ( comm.size) print '==================================================\n' #------------------------------------------------------------------------------------------- # # PREPARE SIMULATIONS # #------------------------------------------------------------------------------------------- ########################################################## ## Read Molecule ########################################################## # read the xyz file of the molecule if rank == 0: print '\t Read the position of the molecule\n\t', print '-' * 50 f = open(args.mol, 'r') data = f.readlines() f.close # get the molecule name name_mol = re.split(r'\.|/', args.mol)[-2] # create the molecule object xyz = [] for i in range(2, len(data)): d = data[i].split() xyz.append((d[0], (float(d[1]), float(d[2]), float(d[3])))) natom = len(xyz) mol = Molecule(name=name_mol, units=args.units) mol.add_atuples(xyz) mol.set_charge(args.charge) nelec = mol.get_nel() if np.abs(args.charge) == 1: mol.set_multiplicity(2) if args.charge > 1: print 'charge superior to one are not implemented' # get the basis function bfs = getbasis(mol, args.basis) nbfs = len(bfs) nclosed, nopen = mol.get_closedopen() nocc = nclosed # get the dipole moment in the AO basis mu_at_x, mu_at_y, mu_at_z = compute_dipole_atoms(bfs) mu_tot = mu_at_x + mu_at_y + mu_at_z if rank == 0: print '\t\t Molecule %s' % args.mol print '\t\t Basis %s' % args.basis print '\t\t %d electrons' % nelec print '\t\t %d basis functions' % (nbfs) if _print_basis_: for i in range(nbfs): print bfs[i] # compute all the integrals if rank == 0: print '\n\t Compute the integrals and form the matrices' S, Hcore, Ints = Ints_MPI.getints_mpi(bfs, mol, rank, comm, _debug_=_debug_mpi_) ########################################################## ## ## HF GROUND STATE ## ########################################################## comm.Barrier() ###################################################### # only the master proc computes the HF ground state # That should change somehwow ###################################################### if rank == 0: ################################################ # compute the HF ground state of the system ################################################ print '\n\t Compute the ground state HF Ground State\n\t', print '-' * 50 L, C, P = rhf(mol, bfs, S, Hcore, Ints, MaxIter=args.MaxIter, eps_SCF=args.eps_SCF) print '\t Energy of the HF orbitals\n\t', print '-' * 50 index_homo = nocc - 1 nb_print = int(min(nbfs, args.nb_print_mo) / 2) for ibfs in range(index_homo - nb_print + 1, index_homo + nb_print + 1): print '\t\t orb %02d \t occ %1.1f \t\t Energy %1.3f eV' % ( ibfs, np.abs( 2 * P[ibfs, ibfs].real), L[ibfs].real / hartree2ev) ################################################ ## Export the MO in VMD Format ################################################ if args.export_mo: print '\t Export MO Gaussian Cube format' index_homo = nocc - 1 nb_print = int(min(nbfs, args.nb_print_mo) / 2) fmo_names = [] for ibfs in range(index_homo - nb_print + 1, index_homo + nb_print + 1): if ibfs <= index_homo: motyp = 'occ' else: motyp = 'virt' file_name = mol.name + '_mo' + '_' + motyp + '_%01d.cube' % ( ibfs) xyz_min, nb_pts, spacing = mesh_orb(file_name, mol, bfs, C, ibfs) fmo_names.append(file_name) ########################################################## ## Export the MO in bvox Blender format ########################################################## if args.export_blender: print '\t Export MO volumetric data for Blender' bvox_files_mo = [] for fname in fmo_names: fn = cube2blender(fname) bvox_files_mo.append(fn) ## Create the Blender script to visualize the orbitals path_to_files = os.getcwd() pdb_file = name_mol + '.pdb' create_pdb(pdb_file, args.mol, args.units) # create the blender file blname = name_mol + '_mo_volumetric.py' create_blender_script_mo(blname, xyz_min, nb_pts, spacing, pdb_file, bvox_files_mo, path_to_files) ########################################################## ## ## LR-TDHF Calculations ## ########################################################## comm.Barrier() if rank == 0: print '\n\t Compute the LR-TDHF response of the system\n\t', print '-' * 50 if rank == 0: print '\t\t Transform the 2e integrals in the MO basis' # Rearrange the integrals with MPI # so far it does not work # broadcast the C matrix from 0 to all the procs #if rank != 0: # C = np.zeros((nbfs,nbfs)) #comm.Bcast(C,root=0) # rearrange the INTs #MOInts_mpi = Ints_MPI.TransformInts_mpi(Ints,C,rank,comm,_debug_mpi_) # master proc determine which orbitals to account for if rank == 0: # rearrange the integrals with only 1 proc. MOInts = Ints_MPI.TransformInts(Ints, C) # energies of the occupied/virtual orbitals eocc, evirt = L[:nocc], L[nocc:] nb_hole, nb_elec = len(eocc), len(evirt) # index of the excitations nb_exc = nb_hole * nb_elec ind_hole = range(nocc - 1, -1, -1) ind_elec = range(nocc, nbfs) index_exc = [x for x in itertools.product(ind_hole, ind_elec)] # init the matrices A = np.zeros((nb_exc, nb_exc)) if not args.tda: B = np.zeros((nb_exc, nb_exc)) # form the A and B matrices for e1 in range(nb_exc): for e2 in range(nb_exc): i, j = index_exc[e1][0], index_exc[e2][0] a, b = index_exc[e1][1], index_exc[e2][1] # coulomb/exchange integrals for A j_int = MOInts[intindex(i, a, j, b)] k_int = MOInts[intindex(i, j, a, b)] # diagonal/offdiagonal element of A if e1 == e2: eif = L[a] - L[i] A[e1, e2] = eif + j_int - k_int else: A[e1, e2] = j_int - k_int # B matrix if not args.tda: # coulomb/exchange integrals j_int = MOInts[intindex(i, a, b, j)] k_int = MOInts[intindex(i, b, a, j)] B[e1, e2] = j_int - k_int # for the total matrix # and diagonalize it # in the non-Hermitian case if not args.hermitian: if args.tda: Q = A B = np.zeros((nb_exc, nb_exc)) I = np.eye(nb_exc) else: Q = np.zeros((2 * nb_exc, 2 * nb_exc)) Q[:nb_exc, :nb_exc] = A Q[nb_exc:, nb_exc:] = np.conj(A) Q[:nb_exc, nb_exc:] = B Q[nb_exc:, :nb_exc] = np.conj(B) I = np.eye(2 * nb_exc) I[nb_exc:, nb_exc:] *= -1 # diagonalize the matrix if args.nb_exc < nbfs: w, Cex = scla.eig(Q, b=I, eigvals=[0, args.nb_exc]) else: w, Cex = scla.eig(Q, b=I) # for the total matrix # and diagonalize it # in the Hermitian case else: if args.tda: qm = scla.sqrtm(A) qp = A else: qm = scla.sqrtm(A - B) qp = A + B Q = np.dot(qm, np.dot(qp, qm)) print '\t\t Diagonalize the %02dx%02d response matrix' % (nb_exc, nb_exc) if args.nb_exc < nbfs: w2, Cex = scla.eigh(Q, eigvals=[0, args.nb_exc]) else: w2, Cex = scla.eigh(Q) w = np.sqrt(w2) print '\n\t Energy of HF excitation\n\t', print '-' * 50 for iexc in range(len(w)): # frequency freq = w[iexc].real # print the excitaiton in details if _print_detail_exc_: print_first = 1 for kxc in range(nb_exc): trans = Cex[kxc, iexc]**2 init, final = index_exc[kxc][0], index_exc[kxc][1] osc = 2. / 3 * freq * (np.inner( C[:, init], np.inner(mu_tot, C[:, final]).T))**2 if trans > 0.001: print '\t\t \t \t \t \t \t %02d->%02d (%1.3f %%)\t osc %1.3f' % ( init, final, trans, osc) # print only the max contribution else: # maximum contrbution index_max = np.argmax(Cex[:, iexc]**2) max_trans = Cex[index_max, iexc]**2 init_max, final_max = index_exc[index_max][0], index_exc[ index_max][1] osc = 2. / 3 * freq * (np.inner( C[:, init_max], np.inner(mu_tot, C[:, final_max]).T))**2 print '\t\t exc %02d \t Energy %1.3f eV \t %02d->%02d (%1.3f %%)\t osc %1.3f' \ %(iexc,freq/hartree2ev,init_max,final_max,max_trans,osc) if rank == 0: print '\n\n==================================================' print '== Calculation done ==' print '==================================================\n'
""" Calculates the Radon atom using HF. """ import logging from PyQuante import SCF, Molecule, dft, Atom from basis_rn_ano import basis_data logging.basicConfig(level=logging.DEBUG) R = Molecule('Radon',[(86, (0,0,0))]) R.multiplicity = 1 hf = SCF(R, method="HF", basis="6-31G**", basis_data=basis_data) hf.iterate() # print some info: print "HF Results: energy =", hf.energy print "orbital energies:", hf.solver.orbe
def build_molecule(self, *a, **kw): from PyQuante import Molecule self.molecule = Molecule(*a, **kw)
def test(): from PyQuante import Molecule from mpi4py import MPI ############################ # Initialize MPI ############################ comm = MPI.COMM_WORLD rank = comm.rank ############################ if rank == 0: print '\n' print '#' * 60 print '# Parallel PyQuante' print '# Integral calculation with MPI' print '#' * 60 tinit = time.time() print '\n' ##################################### # Creates the molecule ##################################### mol = 'benzene.xyz' units = 'angs' basis_set = '6-31g' # read the xyz file of the molecule if rank == 0: print '\t Read molecule position' f = open(mol, 'r') data = f.readlines() f.close # create the molecule object xyz = [] for i in range(2, len(data)): d = data[i].split() xyz.append((d[0], (float(d[1]), float(d[2]), float(d[3])))) natom = len(xyz) mol = Molecule(name='molecule', units=units) mol.add_atuples(xyz) nelec = mol.get_nel() ##################################### # get the basis function ##################################### basis = getbasis(mol, basis_set) nbfs = len(basis) nclosed, nopen = mol.get_closedopen() nocc = nclosed ##################################### # Print for debug ##################################### if rank == 0: print '\t Basis %s' % basis_set print '\t %d basis functions' % (nbfs) print '\t %d shells\n ' % (len(basis.shells)) if 0: for i in range(nbfs): print basis[i] comm.barrier() ##################################### # compute all the integrals ##################################### S, h, Ints = getints_mpi(basis, mol, rank, comm, _debug_=True) comm.barrier() if rank == 0: tfinal = time.time() print '\n\t Total computation time %f ' % (tfinal - tinit)
#!/usr/bin/env python from PyQuante import Molecule from PyQuante.dft import dft coord = [(1, (0.0998334, 0.995004, -0.6)), (1, (0.911616, 0.411044, 1.6)), (1, (0.811782, -0.58396, -0.6)), (1, (-0.0998334, -0.995004, 1.6)), (1, (-0.911616, -0.411044, -0.6)), (1, (-0.811782, 0.583961, 1.6)), (6, (0, 0, 0)), (6, (0, 0, 1))] ethane = Molecule('ethane', coord, units="Angstrom") en, orbe, orbs = dft(ethane, functional="LDA", basis="sto-3g")
#!/usr/bin/env python from PyQuante import Molecule from PyQuante.dft import dft n2 = Molecule('n2', [(7, (0, 0, 0)), (7, (0, 0, 1.097600))], units="Angstrom") en, orbe, orbs = dft(n2, functional="LDA", basis="sto-3g")
from PyQuante import Molecule, SCF # Define the atom he = Molecule('he', atomlist=[(2, (0, 0, 0))], charge=0, multiplicity=1) # Run HF solver = SCF(he, method="HF", basis="dzvp") solver.iterate() # Show result print solver print "HF Energy = ", solver.energy print "---With fractional charge---" he = Molecule('he', atomlist=[(2.04, (0, 0, 0))], charge=0, multiplicity=1) # Run HF solver = SCF(he, method="HF", basis="dzvp") solver.iterate() # Show result print solver print "HF Energy = ", solver.energy
#!/usr/bin/env python from PyQuante import Molecule from PyQuante.dft import dft h2 = Molecule('h2', [(1, (0, 0, -.36700000000000000000)), (1, (0, 0, 0.36700000000000000000))], units="Angstrom") en, orbe, orbs = dft(h2, functional="LDA", basis="sto-3g")
#!/usr/bin/env python2 from PyQuante import Molecule from PyQuante.dft import dft he = Molecule('he', [(2, (0, 0, 0))], units="Angstrom") en, orbe, orbs = dft(he, functional="LDA", basis="sto-3g")
""" Calculates the H2 molecule using UHF. And plots the charge density along the x-axis. """ from PyQuante import SCF, Molecule from PyQuante.NumWrap import arange from pylab import plot, savefig # Do the lda calculation: h2 = Molecule('h2', [(1, (-0.7, 0, 0)), (1, (0.7, 0, 0))]) hf = SCF(h2, method="UHF", basis="6-31G**") hf.iterate() # print some info: print "UHF Results: energy =", hf.energy print "orbital energies:", hf.solvera.orbe # Get the items we'll need to compute the density with orbs = hf.solvera.orbs bfs = hf.basis_set.get() nclosed,nopen = h2.get_closedopen() nbf = len(bfs) x,y,z = 0, 0, 0 xs = arange(-1.0, 1.1, 0.1) ds = [] for x in xs: amp_xyz = 0 for i in range(nclosed):
def main(argv): parser = argparse.ArgumentParser( description='Hartree Fock Calculation from scratch') # molecule information parser.add_argument('mol', help='xyz file of the molecule', type=str) parser.add_argument('-basis', default='sto-3g', help='basis set to be used in the calculation', type=str) parser.add_argument('-charge', default=0, help='Charge of the system', type=float) parser.add_argument('-units', default='angs', help='Units in the xyz file', type=str) # HF calculations parser.add_argument('-MaxIter', default=100, help='Maximum number of SCF iterations', type=int) parser.add_argument('-eps_SCF', default=1E-4, help='Criterion for SCF termination', type=float) # field information parser.add_argument('-ffreq', default=0.1, help='Frequency of the field', type=float) parser.add_argument('-fint', default=0.05, help='Intensity of the field', type=float) parser.add_argument('-ft0', default=0.5, help='center of the field for gsin', type=float) parser.add_argument('-fsigma', default=0.25, help='sigma of the field for gsin', type=float) parser.add_argument('-fform', default='sin', help='field form', type=str) parser.add_argument('-fdir', default='x', help='direction of the field', type=str) # Propagation parser.add_argument('-tmax', default=200, help='maximum evolution time', type=float) parser.add_argument('-nT', default=200, help='number of time step', type=int) parser.add_argument('-time_unit', default='au', help='unit of tmax', type=str) # export parser.add_argument('-nb_print_mo', default=10, help='Number of orbitals to be written', type=int) ''' Possible basis '3-21g' 'sto3g' 'sto-3g' 'sto-6g' '6-31g' '6-31g**' '6-31g(d,p)' '6-31g**++' '6-31g++**' '6-311g**' '6-311g++(2d,2p)' '6-311g++(3d,3p)' '6-311g++(3df,3pd)' 'lacvp' 'ccpvdz' 'cc-pvdz' 'ccpvtz' 'cc-pvtz' 'ccpvqz' 'cc-pvqz' 'ccpv5z' 'cc-pv5z' 'ccpv6z' 'cc-pv6z' 'augccpvdz' 'aug-cc-pvdz' 'augccpvtz' 'aug-cc-pvtz' 'augccpvqz' 'aug-cc-pvqz' 'augccpv5z' 'aug-cc-pv5z' 'augccpv6z' 'aug-cc-pv6z' 'dzvp':'dzvp', ''' # done args = parser.parse_args() print '\n\n==================================================' print '== PyQuante - Time-dependent hartree-fock ==' print '==================================================\n' #------------------------------------------------------------------------------------------- # # PREPARE SIMULATIONS # #------------------------------------------------------------------------------------------- ########################################################## ## Read Molecule ########################################################## # read the xyz file of the molecule print '\t Read molecule position' f = open(args.mol, 'r') data = f.readlines() f.close # get the molecule name name_mol = re.split(r'\.|/', args.mol)[-2] # create the molecule object xyz = [] for i in range(2, len(data)): d = data[i].split() xyz.append((d[0], (float(d[1]), float(d[2]), float(d[3])))) natom = len(xyz) mol = Molecule(name=name_mol, units=args.units) mol.add_atuples(xyz) mol.set_charge(args.charge) nelec = mol.get_nel() if np.abs(args.charge) == 1: mol.set_multiplicity(2) if args.charge > 1: print 'charge superior to one are not implemented' # get the basis function bfs = getbasis(mol, args.basis) nbfs = len(bfs) nclosed, nopen = mol.get_closedopen() nocc = nclosed print '\t\t Molecule %s' % args.mol print '\t\t Basis %s' % args.basis print '\t\t %d basis functions' % (nbfs) if _print_basis_: for i in range(nbfs): print bfs[i] # compute all the integrals print '\n\t Compute the integrals and form the matrices' S, Hcore, Ints = getints(bfs, mol) print '\t Compute the transition dipole moments' mu_at = compute_dipole_atoms(bfs, args.fdir) ########################################################## ## Compute the HF GROUND STATE ########################################################## print '\n\t Compute the ground state HF Ground State\n\t', print '-' * 50 L, C, Cp, F0, F0p, D, Dp, P, X = rhf(mol, bfs, S, Hcore, Ints, MaxIter=args.MaxIter, eps_SCF=args.eps_SCF) print '\t Energy of the HF orbitals\n\t', print '-' * 50 index_homo = nocc - 1 nb_print = int(min(nbfs, args.nb_print_mo) / 2) for ibfs in range(index_homo - nb_print + 1, index_homo + nb_print + 1): print '\t\t orb %02d \t occ %1.1f \t\t Energy %1.3f Ha' % ( ibfs, np.abs(2 * P[ibfs, ibfs].real), L[ibfs].real) # store the field free eigenstates C0 = np.copy(C) C0p = np.copy(Cp) # invert of the X matrix Xm1 = np.linalg.inv(X) ########################################################## ## Transform the matrices in the OB ########################################################## # pass the other matrices as well Hcore_p = simx(Hcore, X, 'T') mu_at_p = simx(mu_at, X, 'T') # copy the Fock matrix Fp = np.copy(F0p) # transtion matrix at t=0 mup = mu_at_p # check if everythong is ok if _check_ortho_: w, u = np.linalg.eigh(F0p) if np.sum(np.abs(w - L)) > 1E-3: print '\t == Warning orthonormalisation issue' sys.exit() #------------------------------------------------------------------------------------------- # # TEST IF EVERYTHING IS OF SO FAR # #------------------------------------------------------------------------------------------- # verify the basis transformation between # Atomic Orbitals and Orthonormal orbitals # if _test_: print '\n\t Run Check on the matrices' #print'\n' #print'='*40 print '\t\t Verify the basis transformation from diagonal to AO basis ', x = np.dot(np.diag(L), np.linalg.inv(C)) x = np.dot(C, x) x = np.dot(S, x) if np.abs(np.sum(x - F0)) < 1E-3: print '\t Check' else: print '\t NOT OK' #print'='*40 if _verbose_: print '\t\t reconstructed Fock matrix' print x print '\t\t original Fock matrix' print F0 #print'\n\t' #print'='*40 print '\t\t Verify the basis transformation from AO to diagonal basis ', y = np.dot(F0, C) y = np.dot(np.linalg.inv(S), y) y = np.dot(np.linalg.inv(C), y) if np.abs(np.sum(y - np.diag(L))) < 1E-3: print '\t Check' else: print '\t NOT OK' #print'='*40 if _verbose_: print '\t\t reconstructed eigenvalues' print y print '\t\t original eigenvalues' print L # # verify the basis transformation between # Atomic Orbitals and Orthonormal orbitals # if _test_: #print'\n' #print'='*40 print '\t\t Verify the basis transformation from AO basis to ORTHO basis ', #print'='*40 if np.abs(np.sum(D - np.dot(X, np.dot(Dp, X.T)))) < 1E-3: print '\t Check' else: print '\t NOT OK' if _verbose_: print '\t\t reconstructed density in the AO' print np.dot(X, np.dot(Dp, X.T)) print '\t\t Original density in the AO' print D # # verify the basis transformation between # Atomic Orbitals and Orthonormal orbitals # if _test_: #print'\n' #print'='*40 print '\t\t Verify the basis transformation from AO basis to ORTHO basis ', #print'='*40 if np.abs(np.sum(Dp - np.dot(Xm1, np.dot(D, Xm1.T)))) < 1E-3: print '\t Check' else: print '\t NOT OK' if _verbose_: print '\t\t reconstructed density in the OB' print np.dot(Xm1, np.dot(D, Xm1.T)) print '\t\t original density in the OB' print Dp # test if the Fock matrix and densitu matrix in OB # share the same eigenbasis # due to degeneracies in the density matrix only a few # eigenvectors might be the same if _verbose_: print '\t\t verify that the Fock matrix and the density matrix ' print '\t\t in the ORTHOGONAL BASIS have the same eigenvector', lf, cf = scla.eigh(F0p) r = 1E-6 * np.random.rand(nbfs, nbfs) r += r.T ld, cd = scla.eigh(Dp + r) x1 = simx(Dp, cf, 'N') x2 = simx(F0p, cd, 'N') s1 = np.sum(np.abs(x1 - np.diag(np.diag(x1)))) s2 = np.sum(np.abs(x2 - np.diag(np.diag(x2)))) if s1 < 1E-6 and s2 < 1E-6: print '\t\t Check' else: print '\t\t NOT OK' if _verbose_: print '\t\tDensity matrix in eigenbasis of the Fock matrix' print np.array_str(x1, suppress_small=True) print '\t\t\Fock matrix in eigenbasis of the Density matrix' print np.array_str(x2, suppress_small=True) print '\n' print '\t\t', print '=' * 40 print '\t\teigenvector/eigenvalues of the fock matrix' print lf print cf print '' print '\t\teigenvector/eigenvalues of the density matrix' print ld print cd print '\t\t', print '=' * 40 # # check the initial population of the molecular orbital # if _verbose_: print '\t\t', print '=' * 40 print '\t\t Initial population of the molecular orbitals' print '\t\t ', for i in range(len(P)): print '%1.3f ' % (P[i, i].real), print '' print '\t\t', print '=' * 40 # #------------------------------------------------------------------------------------------- # # SIMUALTIONS # #------------------------------------------------------------------------------------------- ########################################################## ## Define time and outputs ########################################################## if args.time_unit == 'fs': tmax_convert = args.tmax * 1E-15 / au2s elif args.time_unit == 'ps': tmax_convert = args.tmax * 1E-12 / au2s elif args.time_unit == 'au': tmax_convert = args.tmax # a few shortcut ffreq = args.ffreq fint = args.fint ft0 = args.ft0 * tmax_convert fsigma = args.fsigma * tmax_convert fform = args.fform # readjust the frequency in case it is not specified if ffreq < 0: ffreq = L[nocc] - L[nocc - 1] print '\n\t Field frequency adjusted to %f' % (ffreq) T = np.linspace(0, tmax_convert, args.nT) Tplot = np.linspace(0, args.tmax, args.nT) FIELD = np.zeros(args.nT) N = np.zeros((nbfs, args.nT)) Q = np.zeros((natom, args.nT)) mu0 = 0 for i in range(natom): Q[i, :] = mol[i].Z mu0 += mol[i].Z * mol.atoms[i].r[0] MU = mu0 * np.ones(args.nT) dt = T[1] - T[0] ########################################################## ## Loop over time ########################################################## print '\n' print '\t Compute the TDHF dynamics' print '\t Simulation done at %d percent' % (0), for iT in range(0, args.nT): ################################################################ ## TIMER ################################################################ if iT * 10 % int(args.nT) == 0: sys.stdout.write('\r\t Simulation done at %d percent' % (iT * 100 / args.nT)) sys.stdout.flush() ################################################################ ## Compute the observable ################################################################ # compute the Lowdin atomic charges for iorb in range(nbfs): atid = bfs[iorb].atid Q[atid, iT] -= 2 * Dp[iorb, iorb].real # compute the population of the orbitals for iorb in range(nbfs): N[iorb, iT] = (np.dot(C0p[:, iorb], np.dot(Dp.real, C0p[:, iorb].T)) / np.linalg.norm(C0p[:, iorb])**2).real # compute the instantaneous dipole MU[iT] -= np.trace(np.dot(mu_at, D)).real ###################################### ## Propagation ###################################### if _predict_ and iT < args.nT - 1: # predict the density matrix dp = propagate_dm(Dp, Fp, dt, method='relax') #predicted dm in AO basis d = np.dot(X, np.dot(dp, X.T)) # value of the field fp1 = compute_field(T[iT + 1], ffreq=ffreq, fint=fint, t0=ft0, s=fsigma, fform=fform) mup_p1 = mu_at_p * fp1 # predicted fock matrix fp = compute_F(d, Hcore_p, X, Ints, mup_p1) # form the intermediate fock matrix fm = 0.5 * (Fp + fp) # propagte the density matrix with that Dp = propagate_dm(Dp, fm, dt, method='relax') else: # propagte the density matrix with that Dp = propagate_dm(Dp, Fp, dt, method='relax') ###################################### ## New Density Matrix in AO ###################################### # DM in AO basis D = np.dot(X, np.dot(Dp, X.T)) ###################################### ## New Field ###################################### # value of the field FIELD[iT] = compute_field(T[iT], ffreq=ffreq, fint=fint, t0=ft0, s=fsigma, fform=fform) mup = mu_at_p * FIELD[iT] ###################################### ## New Fock Matrix ###################################### # new Fock matrix Fp = compute_F(D, Hcore_p, X, Ints, mup) sys.stdout.write('\r\t Simulation done at 100 percent') # save all the data print '\n\t Save data\n' np.savetxt('time.dat', Tplot) np.savetxt('orb_pops.dat', N) np.savetxt('charges.dat', Q) np.savetxt('dipole.dat', MU) np.savetxt('field.dat', FIELD) #------------------------------------------------------------------------------------------- # # EXPORT THE RESULTS # #------------------------------------------------------------------------------------------- ########################################################## ## PLOT THE DATA WITH MATPLOTLIB ########################################################## if _plot_: plot(Tplot, FIELD, N, Q, MU, cutlow=0.05, cuthigh=0.9) ########################################################## ## Export the MO in VMD Format ########################################################## if _export_mo_: print '\t Export MO Gaussian Cube format' index_homo = nocc - 1 nb_print = int(min(nbfs, args.nb_print_mo) / 2) fmo_names = [] for ibfs in range(index_homo - nb_print + 1, index_homo + nb_print + 1): if ibfs <= index_homo: motyp = 'occ' else: motyp = 'virt' file_name = mol.name + '_mo' + '_' + motyp + '_%01d.cube' % (index) xyz_min, nb_pts, spacing = mesh_orb(file_name, mol, bfs, C0, ibfs) fmo_names.append(file_name) ########################################################## ## Export the MO ## in bvox Blender format ########################################################## if _export_blender_: print '\t Export MO volumetric data for Blender' bvox_files_mo = [] for fname in fmo_names: fn = cube2blender(fname) bvox_files_mo.append(fn) ########################################################## ## Create the ## Blender script to visualize the orbitals ########################################################## path_to_files = os.getcwd() pdb_file = name_mol + '.pdb' create_pdb(pdb_file, args.mol, args.units) # create the blender file blname = name_mol + '_mo_volumetric.py' create_blender_script_mo(blname, xyz_min, nb_pts, spacing, pdb_file, bvox_files_mo, path_to_files) ########################################################## ## Export the MO DYNAMICS in VMD Format ########################################################## if _export_mo_dynamics_: # step increment nstep_mo = 4 # resolution i.e. point per angstrom ppa = 1 # just a test norm = 1 - np.min(N[0, :]) # loop to create all the desired cube files fdyn_elec, fdyn_hole = [], [] for iT in range(0, args.nT, nstep_mo): if iT * 10 % int(args.nT) == 0: sys.stdout.write( '\r\t Export Cube File \t\t\t\t %d percent done' % (iT * 100 / args.nT)) sys.stdout.flush() felec, fhole, xyz_min, nb_pts, spacing = mesh_exc_dens( mol, bfs, N, C0, iT, nocc, resolution=ppa) fdyn_elec.append(felec) fdyn_hole.append(fhole) sys.stdout.write('\r\t Export Cube File \t\t\t\t 100 percent done\n') # create the vmd script to animate the voxel create_vmd_anim(mol.name, args.nT, nstep_mo) ########################################################## ## Export the DYN ## in bvox Blender format ########################################################## if _export_blender_: print '\t Export volumetric data for Blender' # create the bvox files for electron bvox_files_dyn_elec = [] for fname in fdyn_elec: fn = cube2blender(fname) bvox_files_dyn_elec.append(fn) # create the bvox files for holes bvox_files_dyn_hole = [] for fname in fdyn_hole: fn = cube2blender(fname) bvox_files_dyn_hole.append(fn) # create the pdb file pdb_file = name_mol + '.pdb' create_pdb(pdb_file, args.mol, args.units) # path to files path_to_files = os.getcwd() # create the blender script blname = name_mol + '_traj_volumetric.py' create_blender_script_traj(blname, xyz_min, nb_pts, spacing, pdb_file, bvox_files_dyn_elec, bvox_files_dyn_hole, path_to_files) print '\n\n==================================================' print '== Calculation done ==' print '==================================================\n'
#!/usr/bin/env python from PyQuante import Molecule from PyQuante.dft import dft lih = Molecule('LiH', [(1, (0, 0, -1.210905)), (3, (0, 0, 0.403635))], units="Bohr") en, orbe, orbs = dft(lih, functional="LDA", basis="sto-3g")
def Edot(method='ROHF'): O = Molecule('O', atomlist=[('O', (0, 0, 0))], multiplicity=3) job = SCF(O, method=method, basis='6-31G**') job.iterate() return job.energy
def testGuess(self, ): """ """ mol = Molecule.from_file(CML) self.assertRaises(IOError, Molecule.from_file, INEXISTENT)
def pyq1_rohf(atomtuples=[(2,(0,0,0))],basis = '6-31G**',maxit=10,mult=3): from PyQuante import Ints,settings,Molecule from PyQuante.hartree_fock import get_energy from PyQuante.MG2 import MG2 as MolecularGrid from PyQuante.LA2 import mkdens,geigh,trace2,simx from PyQuante.Ints import getJ,getK print ("PyQ1 ROHF run") atoms = Molecule('Pyq1',atomlist=atomtuples,multiplicity=mult) bfs = Ints.getbasis(atoms,basis=basis) S,h,I2e = Ints.getints(bfs,atoms) nbf = norbs = len(bfs) nel = atoms.get_nel() nalpha,nbeta = atoms.get_alphabeta() enuke = atoms.get_enuke() orbe,orbs = geigh(h,S) eold = 0 for i in range(maxit): Da = mkdens(orbs,0,nalpha) Db = mkdens(orbs,0,nbeta) Ja = getJ(I2e,Da) Jb = getJ(I2e,Db) Ka = getK(I2e,Da) Kb = getK(I2e,Db) Fa = h+Ja+Jb-Ka Fb = h+Ja+Jb-Kb energya = get_energy(h,Fa,Da) energyb = get_energy(h,Fb,Db) eone = (trace2(Da,h) + trace2(Db,h))/2 etwo = (trace2(Da,Fa) + trace2(Db,Fb))/2 energy = (energya+energyb)/2 + enuke print (i,energy,eone,etwo,enuke) if abs(energy-eold) < 1e-5: break eold = energy Fa = simx(Fa,orbs) Fb = simx(Fb,orbs) # Building the approximate Fock matrices in the MO basis F = 0.5*(Fa+Fb) K = Fb-Fa # The Fock matrix now looks like # F-K | F + K/2 | F # --------------------------------- # F + K/2 | F | F - K/2 # --------------------------------- # F | F - K/2 | F + K # Make explicit slice objects to simplify this do = slice(0,nbeta) so = slice(nbeta,nalpha) uo = slice(nalpha,norbs) F[do,do] -= K[do,do] F[uo,uo] += K[uo,uo] F[do,so] += 0.5*K[do,so] F[so,do] += 0.5*K[so,do] F[so,uo] -= 0.5*K[so,uo] F[uo,so] -= 0.5*K[uo,so] orbe,mo_orbs = np.linalg.eigh(F) orbs = np.dot(orbs,mo_orbs) return energy,orbe,orbs
def testLoadString(self): mol = Molecule.from_string(open(CML).read(), "cml") self.assertEqual(mol.charge, 0) self.assertEqual(mol.multiplicity, 1)
def testGuess(self,): """ """ mol = Molecule.from_file(CML) self.assertRaises(IOError, Molecule.from_file, INEXISTENT)
from PyQuante import Molecule from PyQuante.Ints import getbasis h2 = Molecule('h2',[('H',(0,0,-0.5)),('H',(0,0,0.5))],units='Angs') basis = getbasis(h2,basis_data='sto-3g') nbf = len(basis) h2.inertial() print "STO-3G z" for i in range(nbf): for j in range(nbf): print i,j,basis[i].multipole(basis[j],0,0,1) # Sheesh! I don't have 6-31g in PyQuante print '6-31G CH4 1' ch4 = Molecule('ch4', [('C',(0.0, 0.0, 0.0)), ('H',(0.0, 0.0, 1.083658)), ('H',(1.021683, 0.0, -0.361219)), ('H',(-0.510841, 0.884804, -0.361219)), ('H',(-0.510841,-0.884804, -0.361219)),], units='Angs') ch4.inertial() # This should give the same results, but without the inertial coordinate # transformation #ch4 = Molecule('ch4', # [(6,( 0.0000000000,-0.0000000781, 0.0000001487)), # (1,( 0.0000000000,-0.6085461813,-1.9553066848)),
def testMultiOptions(self): mol = Molecule.from_file(CML, format="cml") self.assertEqual(mol.charge, 0) self.assertEqual(mol.multiplicity, 1)
def energy(R=1.217, method='UHF'): O2 = Molecule('O2',atomlist=[('O',(0,0,0)),('O',(R,0,0))],\ units='Angstrom',multiplicity=3) O2abinitio = SCF(O2, method=method, basis='6-31G**') O2abinitio.iterate() return O2abinitio.energy
#!/usr/bin/env python2 from PyQuante import Molecule from PyQuante.dft import dft be = Molecule('be', [(4, (0, 0, 0))], units="Angstrom") en, orbe, orbs = dft(be, functional="LDA", basis="sto-3g")
def testLoadFile(self,): """ """ mol = Molecule.from_file(CML, format="cml") self.assertEqual(mol[0].atno, 1) self.assertRaises(IOError, Molecule.from_file, INEXISTENT, format="cml")
def pyq1_rohf(atomtuples=[(2, (0, 0, 0))], basis='6-31G**', maxit=10, mult=3): from PyQuante import Ints, settings, Molecule from PyQuante.hartree_fock import get_energy from PyQuante.MG2 import MG2 as MolecularGrid from PyQuante.LA2 import mkdens, geigh, trace2, simx from PyQuante.Ints import getJ, getK print("PyQ1 ROHF run") atoms = Molecule('Pyq1', atomlist=atomtuples, multiplicity=mult) bfs = Ints.getbasis(atoms, basis=basis) S, h, I2e = Ints.getints(bfs, atoms) nbf = norbs = len(bfs) nel = atoms.get_nel() nalpha, nbeta = atoms.get_alphabeta() enuke = atoms.get_enuke() orbe, orbs = geigh(h, S) eold = 0 for i in range(maxit): Da = mkdens(orbs, 0, nalpha) Db = mkdens(orbs, 0, nbeta) Ja = getJ(I2e, Da) Jb = getJ(I2e, Db) Ka = getK(I2e, Da) Kb = getK(I2e, Db) Fa = h + Ja + Jb - Ka Fb = h + Ja + Jb - Kb energya = get_energy(h, Fa, Da) energyb = get_energy(h, Fb, Db) eone = (trace2(Da, h) + trace2(Db, h)) / 2 etwo = (trace2(Da, Fa) + trace2(Db, Fb)) / 2 energy = (energya + energyb) / 2 + enuke print(i, energy, eone, etwo, enuke) if abs(energy - eold) < 1e-5: break eold = energy Fa = simx(Fa, orbs) Fb = simx(Fb, orbs) # Building the approximate Fock matrices in the MO basis F = 0.5 * (Fa + Fb) K = Fb - Fa # The Fock matrix now looks like # F-K | F + K/2 | F # --------------------------------- # F + K/2 | F | F - K/2 # --------------------------------- # F | F - K/2 | F + K # Make explicit slice objects to simplify this do = slice(0, nbeta) so = slice(nbeta, nalpha) uo = slice(nalpha, norbs) F[do, do] -= K[do, do] F[uo, uo] += K[uo, uo] F[do, so] += 0.5 * K[do, so] F[so, do] += 0.5 * K[so, do] F[so, uo] -= 0.5 * K[so, uo] F[uo, so] -= 0.5 * K[uo, so] orbe, mo_orbs = np.linalg.eigh(F) orbs = np.dot(orbs, mo_orbs) return energy, orbe, orbs