def run_scf_qmmm(mol, fname_pqr): from pyscf import scf, qmmm mm_atm_list, mm_xyz_list, mm_q_list = parmed_load_pqr(fname_pqr) mf = scf.RHF(mol) mf_qmmm = qmmm.mm_charge(mf, mm_xyz_list, mm_q_list) mf_qmmm.run() #print('DONE RHF/MM', mf_qmmm.e_tot) return mf_qmmm
def run(self, mol, point_charges=None): steps = self.multisteps[self.method] self.log(f"Running steps '{steps}' for method {self.method}") for i, step in enumerate(steps): if i == 0: mf = self.get_driver(step, mol=mol) assert step in ("scf", "dft") if self.chkfile: # Copy old chkfile to new chkfile new_chkfile = self.make_fn("chkfile", return_str=True) shutil.copy(self.chkfile, new_chkfile) self.chkfile = new_chkfile mf.chkfile = self.chkfile mf.init_guess = "chkfile" self.log( f"Using '{self.chkfile}' as initial guess for {step} calculation." ) if self.auxbasis: mf.density_fit(auxbasis=self.auxbasis) self.log( f"Using density fitting with auxbasis {self.auxbasis}." ) if point_charges is not None: mf = qmmm.mm_charge(mf, point_charges[:, :3], point_charges[:, 3]) self.log(f"Added {len(point_charges)} point charges with " f"sum(q)={sum(point_charges[:,3]):.4f}.") else: mf = self.get_driver(step, mf=prev_mf) # noqa: F821 if self.keep_chk and (self.chkfile is None) and (step in ("dft", "scf")): self.chkfile = self.make_fn("chkfile", return_str=True) try: os.remove(self.chkfile) except FileNotFoundError: self.log( f"Tried to remove '{self.chkfile}'. It doesn't exist.") self.log(f"Created chkfile '{self.chkfile}'") mf.chkfile = self.chkfile mf.kernel() self.log(f"Completed {step} step") prev_mf = mf # Keep mf and dump mol # save_mol(mol, self.make_fn("mol.chk")) self.mf = mf self.calc_counter += 1 return mf
H -0.0227 1.1812 0.8852 H -0.0227 1.1812 -0.8852 ''', basis='3-21g') numpy.random.seed(1) coords = numpy.random.random((5, 3)) * 10 charges = (numpy.arange(5) + 1.) * -.1 # # The order to apply X2C and QMMM matters. X2C has to be called first then the # QMMM charges. In this case, the non-relativistic QMMM charges is added to # the system, i.e., picture change was not applied to the QMMM charges. # mf = scf.RHF(mol).x2c() mf = qmmm.mm_charge(mf, coords, charges).run() # # If the other order was called, picture change is supposed to applied to QMMM # charges as well. However, the current implementation does not support this # feature. This order only counts the interactions between nucleus and QMMM # charges. The interactions between electrons and QMMM charges are excluded. # mf = scf.RHF(mol) mf = qmmm.mm_charge(mf, coords, charges) mf = mf.x2c().run() print(mf.energy_elec()) # In the current implementation, the electronic part of the code above is # equivalent to mf = scf.RHF(mol)
A simple example to run CCSD with background charges. ''' import numpy from pyscf import gto, scf, cc, qmmm mol = gto.M(atom=''' C 1.1879 -0.3829 0.0000 C 0.0000 0.5526 0.0000 O -1.1867 -0.2472 0.0000 H -1.9237 0.3850 0.0000 H 2.0985 0.2306 0.0000 H 1.1184 -1.0093 0.8869 H 1.1184 -1.0093 -0.8869 H -0.0227 1.1812 0.8852 H -0.0227 1.1812 -0.8852 ''', basis='3-21g', verbose=4) numpy.random.seed(1) coords = numpy.random.random((5, 3)) * 10 charges = (numpy.arange(5) + 1.) * -.1 # # Background charges have to be patched to the underlying SCF calculaitons. # mf = qmmm.mm_charge(scf.RHF(mol), coords, charges).run() cc.CCSD(mf).run()
H 1.1184 -1.0093 -0.8869 H -0.0227 1.1812 0.8852 H -0.0227 1.1812 -0.8852 ''', basis='3-21g') numpy.random.seed(1) coords = numpy.random.random((5,3)) * 10 charges = (numpy.arange(5) + 1.) * -.1 # # The order to apply X2C and QMMM matters. X2C has to be called first then the # QMMM charges. # mf = scf.RHF(mol).x2c() mf = qmmm.mm_charge(mf, coords, charges).run() # # If the other order was called, only the interactions between nucleus and # QMMM charges are included. The interactions between electrons and QMMM # charges are excluded. # mf = scf.RHF(mol) mf = qmmm.mm_charge(mf, coords, charges) mf = mf.x2c().run() print(mf.energy_elec()) # The electronic part of the code above is equivalent to mf = scf.RHF(mol) mf = mf.x2c().run() print(mf.energy_elec())
"Where 1 is the root you want to target.") target_state = int(sys.argv[-1]) # # Load MF orbitals # chkname = "_chk/pp_anion_pt_chg_dz_b3lyp.chk" mol = chkfile.load_mol(chkname) mol.max_memory = int(1e5) mf = dft.RKS(mol) mf.__dict__.update(chkfile.load(chkname, "scf")) # Need to add this back in bc it's not loaded from chkfile # Old O location from -COO- group chg_coords = np.array([[-5.7124, -3.6452, 0.1326]]) mf = qmmm.mm_charge(mf, chg_coords, [-1.0]) # # Load SA-MCSCF # nelecas, ncas = (4, 4) n_states = 3 weights = np.ones(n_states) / n_states mc0 = mcscf.CASSCF(mf, ncas, nelecas).state_average_(weights) mc0.fix_spin(ss=0) mc0.chkfile = "_chk/pp_anion_pt_chg_dz_cas_4e_4o.chk" mc0.__dict__.update(chkfile.load(mc0.chkfile, "mcscf")) # # NEVPT2
import numpy from pyscf import gto, scf, cc, qmmm mol = gto.M(atom=''' C 1.1879 -0.3829 0.0000 C 0.0000 0.5526 0.0000 O -1.1867 -0.2472 0.0000 H -1.9237 0.3850 0.0000 H 2.0985 0.2306 0.0000 H 1.1184 -1.0093 0.8869 H 1.1184 -1.0093 -0.8869 H -0.0227 1.1812 0.8852 H -0.0227 1.1812 -0.8852 ''', basis='3-21g', verbose=4) numpy.random.seed(1) coords = numpy.random.random((5,3)) * 10 charges = (numpy.arange(5) + 1.) * -.1 # # Background charges have to be patched to the underlying SCF calculaitons. # mf = qmmm.mm_charge(scf.RHF(mol), coords, charges).run() cc.CCSD(mf).run()
# Author: Qiming Sun <*****@*****.**> # ''' A simple example to run HF with background charges. ''' import numpy from pyscf import gto, scf, qmmm mol = gto.M(atom=''' C 1.1879 -0.3829 0.0000 C 0.0000 0.5526 0.0000 O -1.1867 -0.2472 0.0000 H -1.9237 0.3850 0.0000 H 2.0985 0.2306 0.0000 H 1.1184 -1.0093 0.8869 H 1.1184 -1.0093 -0.8869 H -0.0227 1.1812 0.8852 H -0.0227 1.1812 -0.8852 ''', basis='3-21g', verbose=4) numpy.random.seed(1) coords = numpy.random.random((5, 3)) * 10 charges = (numpy.arange(5) + 1.) * -.1 mf = scf.UHF(mol) mf = qmmm.mm_charge(mf, coords, charges) mf.run()
# ''' A simple example to run HF with background charges. ''' import numpy from pyscf import gto, scf, qmmm mol = gto.M(atom=''' C 1.1879 -0.3829 0.0000 C 0.0000 0.5526 0.0000 O -1.1867 -0.2472 0.0000 H -1.9237 0.3850 0.0000 H 2.0985 0.2306 0.0000 H 1.1184 -1.0093 0.8869 H 1.1184 -1.0093 -0.8869 H -0.0227 1.1812 0.8852 H -0.0227 1.1812 -0.8852 ''', basis='3-21g', verbose=4) numpy.random.seed(1) coords = numpy.random.random((5,3)) * 10 charges = (numpy.arange(5) + 1.) * -.1 mf = scf.UHF(mol) mf = qmmm.mm_charge(mf, coords, charges) mf.run()
mol.unit = "Angstrom" mol.max_memory = 40000 mol.spin = 0 mol.charge = 0 mol.output = "_logs/_sa_mcscf.out" mol.basis = "ccpvdz" mol.build() # # Mean Field Calculation # # places the charge close to where the hydrogen in COO--H--OOC used to be # (-7.0947 ± 0.1190, -3.0432 ± 0.0676, 0.1083 ± 0.6237) chg_coords = np.array([[-7.0947, -3.0432, 0.1083]]) mf = qmmm.mm_charge(dft.RKS(mol), chg_coords, [-1.0]) mf.xc = "b3lyp" mf.chkfile = "_chk/pp_anion_pt_chg_dz_b3lyp.chk" mf.kernel() # mf.analyze() # # Dump orbitals # molden.dump_scf(mf, "_molden/pp_anion_pt_chg_dz_b3lyp.molden") # # SA-MCSCF # nelecas, ncas = (4, 4) n_states = 3
# # Load MF orbitals # chkname = "_chk/pp_dianion_pt_chg_dz_b3lyp.chk" mol = chkfile.load_mol(chkname) mol.max_memory = int(1e5) mf = dft.RKS(mol) mf.__dict__.update(chkfile.load(chkname, "scf")) # Need to add this back in bc it's not loaded from chkfile # Average the coordinates of the two oxygens on the first carboxylate group chg1_coords = np.array([-2.9263, -7.4737, -0.3309]) # Average the coordinates of the two oxygens on the second carboxylate group chg2_coords = np.array([-8.1490, 1.2438, 0.4364]) mf = qmmm.mm_charge(mf, [chg1_coords, chg2_coords], [-1.0, -1.0]) # # Load SA-MCSCF # nelecas, ncas = (4, 4) n_states = 3 weights = np.ones(n_states) / n_states mc0 = mcscf.CASSCF(mf, ncas, nelecas).state_average_(weights) mc0.fix_spin(ss=0) mc0.chkfile = "_chk/pp_dianion_pt_chg_dz_cas_4e_4o.chk" mc0.__dict__.update(chkfile.load(mc0.chkfile, "mcscf")) # # NEVPT2
mol.spin = 0 mol.charge = 0 mol.output = "_logs/_sa_mcscf.out" mol.basis = "ccpvdz" mol.build() # # Mean Field Calculation # # Average the coordinates of the two oxygens on the first carboxylate group chg1_coords = np.array([-2.9263, -7.4737, -0.3309]) # Average the coordinates of the two oxygens on the second carboxylate group chg2_coords = np.array([-8.1490, 1.2438, 0.4364]) mf = qmmm.mm_charge(dft.RKS(mol), [chg1_coords, chg2_coords], [-1.0, -1.0]) mf.xc = "b3lyp" mf.chkfile = "_chk/pp_dianion_pt_chg_dz_b3lyp.chk" mf.kernel() mf.analyze() # # Dump orbitals # molden.dump_scf(mf, "_molden/pp_dianion_pt_chg_dz_b3lyp.molden") # exit(0) # # SA-MCSCF # nelecas, ncas = (4, 4)
target_state = int(sys.argv[-1]) # # Load MF orbitals # chkname = "_chk/pp_anion_pt_chg_dz_b3lyp.chk" mol = chkfile.load_mol(chkname) mol.max_memory = int(1e5) mf = dft.RKS(mol) mf.__dict__.update(chkfile.load(chkname, "scf")) # Need to add this back in bc it's not loaded from chkfile # places two -0.5 charges where the single bonded oxygens are on the carboxylate species chg1_coords = np.array([-5.7124, -3.6452, 0.1326]) chg2_coords = np.array([-8.0172, -2.5559, 0.0854]) mf = qmmm.mm_charge(dft.RKS(mol), [chg1_coords, chg2_coords], [-0.5, -0.5]) # # Load SA-MCSCF # nelecas, ncas = (4, 4) n_states = 3 weights = np.ones(n_states) / n_states mc0 = mcscf.CASSCF(mf, ncas, nelecas).state_average_(weights) mc0.fix_spin(ss=0) mc0.chkfile = "_chk/pp_anion_pt_chg_dz_cas_4e_4o.chk" mc0.__dict__.update(chkfile.load(mc0.chkfile, "mcscf")) # # NEVPT2
from pyscf.tools import cubegen from pyscf.data.nist import BOHR import numpy as np ang2bohr = 1.0 / BOHR mol = gto.M(atom=''' O 0.0000000000000000 0.0000000000000000 0.000 H -0.26312631683261728 0.92177640310981912 0.000 H 0.9645910938303689 4.0006988432649347E-002 0.000 ''', basis='aug-cc-pVDZ') mm_crd = np.array( [[2.9125407227330018, 0.0000000000000000, 0.000], [3.3354011353264896, -0.41314678971687741, -0.75710308103585677], [3.3354011558614673, -0.41314667699843621, 0.75710313896414105]]) mm_crd *= ang2bohr mm_chgs = np.array([-0.68, 0.34, 0.34]) mf = qmmm.mm_charge(scf.RHF(mol), mm_crd, mm_chgs).run() # electron density cubegen.density(mol, 'h2o_den_qmmm.cube', mf.make_rdm1()) # molecular electrostatic potential cubegen.mep(mol, 'h2o_pot_qmmm.cube', mf.make_rdm1()) # 1st MO nhomo = mf.mol.nelec[0] cubegen.orbital(mol, 'h2o_homo_qmmm.cube', mf.mo_coeff[:, nhomo - 1])
# = <d/dr i| (1/|r-R|) |j> + <i| (1/|r-R|) |d/dr j> for i, q in enumerate(charges): with mol.with_rinv_origin(coords[i]): v = mol.intor('int1e_iprinv') f = (numpy.einsum('ij,xji->x', dm, v) + numpy.einsum('ij,xij->x', dm, v.conj())) * -q g[i] += f # Force = -d/dR return -g # The force from HF electron density # Be careful with the unit of the MM particle coordinates. The gradients are # computed in the atomic unit. mf = qmmm.mm_charge(scf.RHF(mol), coords, charges, unit='Bohr').run() e1_mf = mf.e_tot dm = mf.make_rdm1() mm_force_mf = force(dm) print('HF force:') print(mm_force_mf) # Verify HF force coords[0, 0] += 1e-3 mf = qmmm.mm_charge(scf.RHF(mol), coords, charges, unit='Bohr').run() e2_mf = mf.e_tot print(-(e2_mf - e1_mf) / 1e-3, '==', mm_force_mf[0, 0]) # # For post-HF methods, the response of HF orbitals needs to be considered in # the analytical gradients. It is similar to the gradients code implemented in
def build(eda, gjf, method): starttime = time.time() #xyznam = sys.argv[1] mol = gto.Mole() ##with open(xyznam) as f: # geom = f.read() mol.atom, coords, charges, mol.charge, mol.spin = gjf_kit.gjf_parser(gjf) if 'charge' in method: eda.bgchgs = (coords, charges) if eda.molchgs is None: logger.slog(eda.stdout, "Warning: center frag has no atomic charges") if 'qmmm' in method: eda.bgchgs = (coords, charges) mol.cart = ('cart' in method) mol.basis = method[1] #mol.symmetry = 1 mol.output = eda.output + '-pyscf.log' mol.verbose = eda.verbose mol.build() eda.mol = mol if method[0] == 'hf': mf = scf.RHF(mol) elif dft_kit.is_dft(method[0]): mf = dft.RKS(mol) mf.xc = method[0] if 'ultrafine' in method: mf.grids.atom_grid = (99, 590) if ('charge' in method) or ('qmmm' in method): mf = qmmm.mm_charge(mf, coords, charges, unit='au') mf.kernel() eda.mf = mf if 'force' in method: g = mf.Gradients() eda.force = g.grad() pyscf_time = time.time() #print("pyscf_time=",pyscf_time-starttime) eda.dm = mf.make_rdm1() eda.nao = len(eda.dm) eda.cart = mol.cart os.system("echo '' > " + eda.output + '-eda.log') eda.stdout = open(eda.output + '-eda.log', 'a') if eda.showinter: os.system("echo '' > " + eda.output + '-inter.log') eda.stdout_inter = open(eda.output + '-inter.log', 'a') #with open(self.output+'-eda.log','a') as f: logger.mlog(eda.stdout, "method,basis: ", eda.method) eda.atm2bas_f, eda.atm2bas_p = get_atm2bas(eda.mol) # _p: bas starts from 0 # _f: bas starts from 1 eda.bas2atm, eda.bas2atm_f = get_bas2atm(eda.atm2bas_f, eda.nao, eda.mol.natm) # atm starts from 0 # _f: atm starts from 1 if eda.showinter: if eda.frag_list is None: eda.get_frags() eda.bas2frg = get_bas2frg(eda.bas2atm, eda.frag_list) # frg starts from 1 eda.atm2frg = get_atm2frg(mol.natm, eda.frag_list) eda.nfrag = len(eda.frag_list) eda.ncap = 0 eda.capatoms = [] eda.frag2layer = {} for f in eda.frag_list: eda.frag2layer[f.label] = f.layer if f.layer == 'cap': eda.ncap += 1 eda.capatoms.append(f.atm_insub[0]) eda.capbas_p = [] eda.capbas_f = [] for i in eda.capatoms: eda.capbas_p.append(eda.atm2bas_p[i - 1]) eda.capbas_f.append(eda.atm2bas_f[i - 1]) if eda.verbose >= 6: logger.mlog(eda.stdout, "atm2bas_f", eda.atm2bas_f) logger.mlog(eda.stdout, "atm2bas_p", eda.atm2bas_p) #print(eda.bas2atm) logger.mlog(eda.stdout, "bas2atm", eda.bas2atm) if eda.showinter: logger.mlog(eda.stdout, "bas2frg", eda.bas2frg) logger.mlog(eda.stdout, "atm2frg", eda.atm2frg) logger.mlog(eda.stdout, "cap atoms", eda.capatoms) logger.mlog(eda.stdout, "cap basis_p", eda.capbas_p) eda.built = True return eda