def run(self): """Run QM calculation.""" psi4.core.set_output_file(os.path.join(self.basedir, "psi4.out"), False) psi4_io = psi4.core.IOManager.shared_object() psi4_io.set_default_path(self.basedir) psi4_io.set_specific_retention(32, True) psi4_io.set_specific_path(32, self.basedir) nproc = self.get_nproc() psi4.core.set_num_threads(nproc, True) oldpwd = os.getcwd() os.chdir(self.basedir) scf_e, self.scf_wfn = psi4.energy('scf', return_wfn=True) if self.calc_forces: psi4.gradient('scf', ref_wfn=self.scf_wfn) self.oeprop = psi4.core.OEProp(self.scf_wfn) self.oeprop.add("MULLIKEN_CHARGES") self.oeprop.add("GRID_ESP") self.oeprop.add("GRID_FIELD") self.oeprop.compute() os.chdir(oldpwd) self.exitcode = 0 return self.exitcode
def test_uhf_fchk(inp2, datadir): """ FCHK UHF """ mol = psi4.geometry(""" no_reorient 0 2 O O 1 1.46 H 2 0.97 1 104.6 """) psi4.set_options({ "BASIS": "pcseg-0", 'reference': 'uhf', 'e_convergence': 1e-12, 'd_convergence': 1e-12, 'r_convergence': 1e-10, 'pcg_convergence': 1e-10, }) FCHK_file = f"uhf-{inp2['name']}.fchk" reference_file = datadir.join(f"uhf-{inp2['name']}.ref") psi4.set_options(inp2['options']) e, wfn = psi4.gradient(inp2['name'], return_wfn=True, molecule=mol) ret = psi4.driver.fchk(wfn, FCHK_file, debug=True) assert psi4.compare_arrays(ret["Total SCF Density"], calcD(wfn), 9, "FCHK UHF Density") assert psi4.compare_fchkfiles(reference_file, FCHK_file, 1.e-8, f" File comparison: {FCHK_file}")
def test_nonstationary_forces_h2o(): mol = psi4.geometry(""" 0 1 O 0.0 -0.00 0.00 H 0.0 -0.75 0.58 H 0.0 0.75 0.58 unit Angstrom """) psi4_options = {"basis": "cc-pvdz", "scf_type": "pk"} psi4.set_options(psi4_options) mol.update_geometry() Natom = mol.natom() xyz = mol.geometry().to_array() coords = [stre.Stre(0, 1), stre.Stre(0, 2), bend.Bend(0, 1, 2)] Z = [mol.Z(i) for i in range(0, Natom)] masses = [mol.mass(i) for i in range(0, Natom)] f1 = optking.frag.Frag(Z, xyz, masses, intcos=coords, frozen=False) OptMol = optking.molsys.Molsys([f1]) grad_x = psi4.gradient("hf").to_array() grad_q = OptMol.gradient_to_internals(grad_x.flatten(), useMasses=False) grad_x2 = OptMol.gradient_to_cartesians(grad_q).reshape(Natom, 3) grad_x2 = psi4.core.Matrix.from_array(grad_x2) assert psi4.compare_values(grad_x, grad_x2, 10, "Diff grad. CART->int->CART") grad_q = OptMol.gradient_to_internals(grad_x.flatten(), useMasses=True) grad_x2 = OptMol.gradient_to_cartesians(grad_q).reshape(Natom, 3) grad_x2 = psi4.core.Matrix.from_array(grad_x2) assert psi4.compare_values(grad_x, grad_x2, 10, "Diff grad. CART->int->CART with u=1/mass")
def test_nonstationary_hessian_hooh(): mol = psi4.geometry(""" 0 1 H 0.90 0.77 0.46 O 0.10 0.68 -0.02 O -0.10 -0.68 -0.02 H -0.90 -0.77 0.46 """) mol.update_geometry() Natom = mol.natom() psi4_options = {"basis": "cc-pvdz", "scf_type": "pk"} psi4.set_options(psi4_options) xyz = mol.geometry().to_array() coords = [ stre.Stre(0, 1), stre.Stre(2, 3), bend.Bend(0, 1, 2), bend.Bend(1, 2, 3), tors.Tors(0, 1, 2, 3) ] Z = [mol.Z(i) for i in range(0, Natom)] masses = [mol.mass(i) for i in range(0, Natom)] f1 = optking.frag.Frag(Z, xyz, masses, intcos=coords, frozen=False) OptMol = optking.molsys.Molsys([f1]) grad_x = psi4.gradient("hf").to_array().flatten() H_xy = psi4.hessian("hf").to_array() grad_q = OptMol.gradient_to_internals(grad_x) H_q = OptMol.hessian_to_internals(H_xy, grad_x) H_xy2 = OptMol.hessian_to_cartesians(H_q, grad_q) H_q2 = OptMol.hessian_to_internals(H_xy2, grad_x) assert psi4.compare_values(H_q, H_q2, 7, "Diff hessian cart->INT->cart->INT")
def run_refgradient(mol, bqfield, options): """The function calculates SCF gradient in addition to MP2 or CCSD gradients and saves it the file en_grad0.dat """ basis = 'aug-cc-pvdz' if 'basis' not in options else options['basis'] theory = 'mp2' if 'theory' not in options else options['theory'] psi4.core.set_global_option('freeze_core', 'True') method_str = theory + '/' + basis ref_str = 'scf/' + basis psi4.core.set_global_option_python('EXTERN', bqfield.extern) psi4.core.set_global_option('BASIS', basis) grad0, wfn0 = pri4.gradient(ref_str, return_wfn=True) E0 = psi4.core.get_variable('CURRENT ENERGY') grad, wfn = psi4.gradient(method_str, return_wfn=True, ref_wfn=wfn0) E = psi4.core.get_variable('CURRENT ENERGY') gradarr0 = psi4.p4util.mat2arr(grad0) gradarr = psi4.p4util.mat2arr(grad) with open('en_grad_ref.dat', 'w') as fp: fp.write("%24.16f\n" % E0) for g in gradarr0: fp.write(("%24.16f" * 3 + "\n") % (g0[0], g0[1], g0[2])) with open('en_grad_correl.dat', 'w') as fp: fp.write("%24.16f\n" % E) for g, g0 in zip(gradarr, gradarr0): fp.write(("%24.16f" * 3 + "\n") % (g[0], g[1], g[2])) bq_list = options['bq_list'] # feed BQ positions into Psi4 as angstrom with open('grid.dat', 'w') as fp: for bq in bq_list: fp.write('%16.10f%16.10f%16.10f\n' % (bq[1], bq[2], bq[3])) psi4.oeprop(wfn, 'GRID_FIELD')
def test_rhf_fchk(inp, datadir): """ FCHK RHF """ mol = psi4.geometry(""" no_reorient 0 1 O H 1 1.01 H 1 1.0 2 104.5 """) psi4.set_options({ "BASIS": "pcseg-0", 'd_convergence': 1e-12, }) FCHK_file = f"rhf-{inp['name']}.fchk" reference_file = datadir.join(f"rhf-{inp['name']}.ref") psi4.set_options(inp['options']) e, wfn = psi4.gradient(inp['name'], return_wfn=True, molecule=mol) ret = psi4.driver.fchk(wfn, FCHK_file, debug=True) if inp['name'] in ['mp2', 'dct', 'omp2']: refwfn = wfn.reference_wavefunction() expected = calcD(refwfn) else: expected = calcD(wfn) assert psi4.compare_arrays(ret["Total SCF Density"], expected, 9, "FCHK RHF Density") assert psi4.compare_fchkfiles(reference_file, FCHK_file, 1.e-8, f" File comparison: {FCHK_file}")
def test_dftd3_dft_grad_lr3(): """modified VV10-less B97 functional gradient wB97X-V -> wB97X-D3BJ""" # stored data from finite differences FD_wb97x_d3 = psi4.core.Matrix.from_list( [[0.03637802044642, 0.06718963272193, 0.00000000000000], [0.04955519892514, -0.06340333481039, 0.00000000000000], [-0.07009043821383, -0.00834477190196, 0.00000000000000], [0.02732425404378, -0.05883094637658, 0.00000000000000], [-0.02158351760075, 0.03169471018350, 0.05342791683461], [-0.02158351760075, 0.03169471018350, -0.05342791683461]]) psi4.geometry(""" 0 1 O -1.65542 -0.12330 0.00000 O 1.24621 0.10269 0.00000 H -0.70409 0.03193 0.00000 H -2.03867 0.75372 0.00000 H 1.57599 -0.38252 -0.75856 H 1.57599 -0.38252 0.75856 """) psi4.set_options({ 'scf_type': 'pk', 'basis': 'minix', 'dft_radial_points': 99, 'dft_spherical_points': 302, 'e_convergence': 8, }) analytic = psi4.gradient('wB97X-D3BJ', dertype=1) assert compare_matrices(analytic, FD_wb97x_d3, 5, "wB97X-D3BJ Analytic vs Store")
def test_dftd3_dft_grad_lr3(): """modified VV10-less B97 functional gradient wB97X-V -> wB97X-D3BJ""" # stored data from finite differences FD_wb97x_d3 = psi4.core.Matrix.from_list([ [ 0.03637802044642, 0.06718963272193, 0.00000000000000], [ 0.04955519892514, -0.06340333481039, 0.00000000000000], [ -0.07009043821383, -0.00834477190196, 0.00000000000000], [ 0.02732425404378, -0.05883094637658, 0.00000000000000], [ -0.02158351760075, 0.03169471018350, 0.05342791683461], [ -0.02158351760075, 0.03169471018350, -0.05342791683461]]) psi4.geometry(""" 0 1 O -1.65542 -0.12330 0.00000 O 1.24621 0.10269 0.00000 H -0.70409 0.03193 0.00000 H -2.03867 0.75372 0.00000 H 1.57599 -0.38252 -0.75856 H 1.57599 -0.38252 0.75856 """) psi4.set_options({ 'scf_type': 'pk', 'basis': 'minix', 'dft_radial_points': 99, 'dft_spherical_points': 302, 'e_convergence': 8, }) analytic = psi4.gradient('wB97X-D3BJ', dertype=1) assert compare_matrices(analytic, FD_wb97x_d3, 5, "wB97X-D3BJ Analytic vs Store")
def test_stationary_forces_h2o(): mol = psi4.geometry(""" 0 1 O 0.0000000000 -0.0000000000 0.0025968676 H 0.0000000000 -0.7487897072 0.5811909492 H -0.0000000000 0.7487897072 0.5811909492 unit Angstrom """) psi4_options = {"basis": "cc-pvdz", "scf_type": "pk"} psi4.set_options(psi4_options) mol.update_geometry() Natom = mol.natom() xyz = mol.geometry().to_array() # Make an optking molecule manually, and you can choose your specific # desired internal coordinates. coords = [ stre.Stre(0, 1), # from-zero indexed atoms in geometry stre.Stre(0, 2), bend.Bend(0, 1, 2), ] Z = [mol.Z(i) for i in range(0, Natom)] masses = [mol.mass(i) for i in range(0, Natom)] f1 = optking.frag.Frag(Z, xyz, masses, intcos=coords, frozen=False) OptMol = optking.molsys.Molsys([f1]) #psi4.core.print_out(str(OptMol)) grad_x = psi4.gradient("hf") # returns an (N,3) psi4 matrix #rms = grad_x.rms() # Print gradient as psi4 matrix. #psi4.core.print_out(f"Cartesian Gradient (RMS={rms:.3e})\n") #grad_x.print_out() # Print gradient as numpy array. #print(f"Cartesian Gradient (RMS={rms:.3e})") #print(grad_x.to_array()) grad_x = grad_x.to_array() grad_q = OptMol.gradient_to_internals(grad_x.flatten(), useMasses=False) # returns ndarray grad_x2 = OptMol.gradient_to_cartesians(grad_q).reshape(Natom, 3) grad_x2 = psi4.core.Matrix.from_array(grad_x2) #psi4.core.print_out("Internal Coordinate Gradient:\n"+str(grad_q)+"\n") #rms = grad_x2.rms() #psi4.core.print_out(f"Cartesian Gradient (RMS={rms:.3e})\n") #grad_x2.print_out() #print(f"Cartesian Gradient (RMS={rms:.3e})") #print(grad_x2.to_array()) #rms_diff = np.sqrt(np.mean((grad_x - grad_x2)**2)) #print(f"RMS diff gradient, cart->int->cart: {rms_diff:8.4e}") assert psi4.compare_values(grad_x, grad_x2, 10, "Diff grad. CART->int->CART") grad_q = OptMol.gradient_to_internals(grad_x.flatten(), useMasses=True) grad_x2 = OptMol.gradient_to_cartesians(grad_q).reshape(Natom, 3) grad_x2 = psi4.core.Matrix.from_array(grad_x2) assert psi4.compare_values(grad_x, grad_x2, 10, "Diff grad. CART->int->CART with u=1/mass")
def doGrad(geom, pars): psi4.geometry(geom) Grad, wfn = psi4.gradient(pars.level_of_theory, return_wfn=True) e = wfn.energy() G = np.array(Grad) print(G.shape) pars.grad = G return G, e
def compute_gradient(self): """ Calls Psi4 to obtain the gradient of the QM region and saves it as a numpy array self.gradient """ self.set_up_psi4() G = psi4.gradient(self.method) self.gradient = np.asarray(G)
def test_gradient(inp): h2o = psi4.geometry(""" O H 1 0.958 H 1 0.958 2 104.5 """) psi4.set_options({'basis': 'aug-cc-pvdz', 'points': 5}) psi4.set_options(inp['options']) analytic_gradient = psi4.gradient(inp['name'], dertype=1) print(analytic_gradient) findif_gradient = psi4.gradient(inp['name'], dertype=0) reference_gradient = inp["ref"] assert compare_values(findif_gradient, analytic_gradient, 5, "analytic vs. findif gradient") assert compare_values(reference_gradient, analytic_gradient.np, 5, "analytic vs. reference gradient")
def calculate_gradient(self, LOT, bypass_scf=False, **kwargs): """Calculate the gradient with @LOT. When bypass_scf=True a hf energy calculation has been done before. """ start = time.time() self.grd = psi4.gradient(LOT, bypass_scf=bypass_scf, **kwargs) time_needed = time.time() - start self.timing[LOT] = self.timing.get(LOT, []) + [time_needed]
def test_mp2_module(inp, clsd_open_pmols, request): tnm = request.node.name subject = clsd_open_pmols[inp['subject']] ref_block = _ref_module[inp['options']['scf_type']][inp['options'] ['reference']] ref_ref = ref_block['HF TOTAL ENERGY'] ref_block = ref_block[inp['options']['freeze_core']][inp['options'] ['mp2_type']] ref_corl = ref_block['MP2 CORRELATION ENERGY'] ref_tot = ref_block['MP2 TOTAL ENERGY'] psi4.set_options({ 'basis': 'cc-pvdz', 'guess': 'sad', 'e_convergence': 8, 'd_convergence': 7, }) psi4.set_options(inp['options']) if inp['driver'] == 'energy': ene, wfn = psi4.energy('mp2', molecule=subject, return_wfn=True) elif inp['driver'] == 'gradient': grad, wfn = psi4.gradient('mp2', molecule=subject, return_wfn=True) ref_tot_grad = ref_block['MP2 TOTAL GRADIENT'] for obj in [psi4.core, wfn]: for pv in [ 'HF TOTAL ENERGY', 'SCF TOTAL ENERGY', 'CURRENT REFERENCE ENERGY' ]: assert compare_values(ref_ref, obj.variable(pv), 6, tnm + ' ' + pv) for pv in [ 'MP2 CORRELATION ENERGY', 'CURRENT CORRELATION ENERGY', ]: assert compare_values(ref_corl, obj.variable(pv), 6, tnm + ' ' + pv) for pv in [ 'MP2 TOTAL ENERGY', 'CURRENT ENERGY', ]: assert compare_values(ref_tot, obj.variable(pv), 6, tnm + ' ' + pv) assert compare_values(ref_tot, wfn.energy(), 6, tnm + ' wfn') if inp['driver'] == 'energy': assert compare_values(ref_tot, ene, 6, tnm + ' return') elif inp['driver'] == 'gradient': assert compare_matrices(ref_tot_grad, wfn.gradient(), 6, tnm + ' grad wfn') assert compare_matrices(ref_tot_grad, grad, 6, tnm + ' grad return')
def get_forces(self, atoms, coords): xyz = make_xyz_str(atoms, coords.reshape(-1, 3) * BOHR2ANG) mol = psi4.geometry(xyz) energy, wfn = psi4.energy(self.meth_bas, return_wfn=True) gradient = psi4.gradient(self.meth_bas, molecule=mol, ref_wfn=wfn) results = { "energy": energy, "forces": -np.asarray(gradient).flatten(), } return results
def compute_info(self): """ Calls Psi4 to obtain the energy, Psi4 wavefunction object, and gradient of the QM region and saves as self.energy, self.wavefuction, and self.gradient """ try: self.set_up_psi4() self.energy, self.wavefunction = psi4.energy(self.method, return_wfn=True) G = psi4.gradient(self.method) self.gradient = np.asarray(G) except: self.set_up_psi4(be_quiet=False) self.energy, self.wavefunction = psi4.energy(self.method, return_wfn=True) G = psi4.gradient(self.method) self.gradient = np.asarray(G)
def test_mp2_module(inp, clsd_open_pmols, request): tnm = request.node.name subject = clsd_open_pmols[inp['subject']] ref_block = _ref_module[inp['options']['scf_type']][inp['options']['reference']] ref_ref = ref_block['HF TOTAL ENERGY'] ref_block = ref_block[inp['options']['freeze_core']][inp['options']['mp2_type']] ref_corl = ref_block['MP2 CORRELATION ENERGY'] ref_tot = ref_block['MP2 TOTAL ENERGY'] psi4.set_options({ 'basis': 'cc-pvdz', 'guess': 'sad', 'e_convergence': 8, 'd_convergence': 7, }) psi4.set_options(inp['options']) if inp['driver'] == 'energy': ene, wfn = psi4.energy('mp2', molecule=subject, return_wfn=True) elif inp['driver'] == 'gradient': grad, wfn = psi4.gradient('mp2', molecule=subject, return_wfn=True) ref_tot_grad = ref_block['MP2 TOTAL GRADIENT'] for obj in [psi4.core, wfn]: for pv in ['HF TOTAL ENERGY', 'SCF TOTAL ENERGY', 'CURRENT REFERENCE ENERGY']: assert compare_values(ref_ref, obj.variable(pv), 6, tnm + ' ' + pv) for pv in [ 'MP2 CORRELATION ENERGY', 'CURRENT CORRELATION ENERGY', ]: assert compare_values(ref_corl, obj.variable(pv), 6, tnm + ' ' + pv) for pv in [ 'MP2 TOTAL ENERGY', 'CURRENT ENERGY', ]: assert compare_values(ref_tot, obj.variable(pv), 6, tnm + ' ' + pv) assert compare_values(ref_tot, wfn.energy(), 6, tnm + ' wfn') if inp['driver'] == 'energy': assert compare_values(ref_tot, ene, 6, tnm + ' return') elif inp['driver'] == 'gradient': assert compare_matrices(ref_tot_grad, wfn.gradient(), 6, tnm + ' grad wfn') assert compare_matrices(ref_tot_grad, grad, 6, tnm + ' grad return')
def calculate(inp, calc, save): '''Run nwchem on input, return data in results dict Args inp: Psi4 input object (geometry, bq_pos, bq_charges) calc: calculation type save: save calculation results Returns results: dictionary ''' options = params.options mol, bqfield, bqs = inp psi4.core.set_global_option_python('EXTERN', bqfield.extern) psi4.core.set_global_option('BASIS', options['basis']) psi4.set_memory(int(options['mem_mb'] * 1e6)) if options['correlation'] and calc not in ['esp', 'energy_hf']: theory = options['correlation'] psi4.core.set_global_option('freeze_core', 'True') else: theory = 'scf' method_str = theory + '/' + options['basis'] results = {} if calc == 'energy' or calc == 'energy_hf': results['E_tot'] = psi4.energy(method_str) elif calc == 'esp': raise RuntimeError("Not implemented") elif calc == 'gradient': grad, wfn = psi4.gradient(method_str, return_wfn=True) E = psi4.core.get_variable('CURRENT ENERGY') results['E'] = E results['gradient'] = psi4.p4util.mat2arr(grad) with open('grid.dat', 'w') as fp: for bq in bqs: fp.write('%16.10f%16.10f%16.10f\n' % (bq[0], bq[1], bq[2])) psi4.oeprop(wfn, 'GRID_FIELD') bq_field = np.loadtxt('grid_field.dat') assert bq_field.shape == (len(bqs), 3) bqgrad = [] for chg, field_vec in zip(bqs, bq_field): bqgrad.append(-1.0 * chg[3] * field_vec) results['bq_gradient'] = np.array(bqgrad) elif calc == 'hessian': hess = psi4.hessian(theory) hessarr = np.array(psi4.p4util.mat2arr(hess)) results['hess'] = hessarr return results
def test_ccsd_t_gradient(method='ccsd(t)'): psi_deriv = np.round(np.asarray(psi4.gradient(method + '/' + basis_name)), 10) quax_deriv = np.asarray( quax.core.derivative(molecule, basis_name, method, deriv_order=1, options=options)).reshape(-1, 3) quax_partial0 = quax.core.partial_derivative(molecule, basis_name, method, deriv_order=1, partial=(0, )) assert np.allclose(psi_deriv, quax_deriv) assert np.allclose(psi_deriv[0, 0], quax_partial0)
def get_forces(grad_method): """ Selects the method (QC or FF) to be used to calculate energies and forces for the system Only Psi4 supported methods implemented (date: 05/23/17 - LAC) Parameters: ---------- string grad_method -- Method to be used to calculate forces and energies Returns: ------- float E -- Energy of the system array force -- Numpy array (natoms,3) containing the forces acting on each atom of the system """ E,wfn = psi4.energy(grad_method,return_wfn=True) force = -np.asarray(psi4.gradient(grad_method,ref_wfn=wfn)) return E,force
def G_Thread(cml_file): np.set_printoptions(threshold = 10000000000000) tree = ET.parse(cml_file) root = tree.getroot() method = root[2].attrib['name'] basis = root[3].attrib['name'] sign = int(root[4].attrib['name']) import psi4 order = Get_Order(cml_file) geom = Get_Geom_String(cml_file) psi4.set_options({'FAIL_ON_MAXITER': False}) psi4.geometry(geom) psi4.core.be_quiet() psi4.set_memory('1 GB') grad, wfn = psi4.gradient(method+'/'+basis, return_wfn=True) energy = wfn.energy()*order grad = np.asarray(grad) true_grad = Interpret(grad, cml_file)*order return tuple([sign*true_grad, sign*energy])
def run_gradient(mol, bqfield, options): basis = 'aug-cc-pvdz' if 'basis' not in options else options['basis'] theory = 'mp2' if 'theory' not in options else options['theory'] psi4.core.set_global_option('freeze_core', 'True') method_str = theory + '/' + basis psi4.core.set_global_option_python('EXTERN', bqfield.extern) psi4.core.set_global_option('BASIS', basis) grad, wfn = psi4.gradient(method_str, return_wfn=True) E = psi4.core.get_variable('CURRENT ENERGY') gradarr = psi4.p4util.mat2arr(grad) with open('en_grad.dat', 'w') as fp: fp.write("%24.16f\n" % E) for g in gradarr: fp.write(("%24.16f" * 3 + "\n") % (g[0], g[1], g[2])) bq_list = options['bq_list'] # feed BQ positions into Psi4 as angstrom with open('grid.dat', 'w') as fp: for bq in bq_list: fp.write('%16.10f%16.10f%16.10f\n' % (bq[1], bq[2], bq[3])) psi4.oeprop(wfn, 'GRID_FIELD')
def get_grad(self, mol): self.update_coor(mol) g, wfn = psi4.gradient(self.met, return_wfn=True) mol.func += psi4.variable('CURRENT ENERGY') * self._ce g = sum(g.to_array().tolist(), []) qm3.engines.LA_gradient(self.vla, g) for i in range(len(self.sel)): i3 = i * 3 for j in [0, 1, 2]: mol.grad[3 * self.sel[i] + j] += g[i3 + j] * self._cg if (len(self.nbn) > 0): ef = psi4.core.OEProp(wfn) ef.add("GRID_FIELD") ef.compute() efx = ef.Exvals() efy = ef.Eyvals() efz = ef.Ezvals() for i in range(len(self.nbn)): mol.grad[3 * self.nbn[i]] -= self._cg * mol.chrg[ self.nbn[i]] * efx[i] mol.grad[3 * self.nbn[i] + 1] -= self._cg * mol.chrg[self.nbn[i]] * efy[i] mol.grad[3 * self.nbn[i] + 2] -= self._cg * mol.chrg[self.nbn[i]] * efz[i]
def test_stationary_forces_hooh(): mol = psi4.geometry(""" 0 1 H 0.9047154509 0.7748902860 0.4679224940 O 0.1020360382 0.6887430144 -0.0294829672 O -0.1020360382 -0.6887430144 -0.0294829672 H -0.9047154509 -0.7748902860 0.4679224940 """) mol.update_geometry() psi4_options = {"basis": "cc-pvdz", "scf_type": "pk"} psi4.set_options(psi4_options) xyz = mol.geometry().to_array() Natom = mol.natom() coords = [ stre.Stre(0, 1), stre.Stre(2, 3), bend.Bend(0, 1, 2), bend.Bend(1, 2, 3), tors.Tors(0, 1, 2, 3) ] Z = [mol.Z(i) for i in range(0, Natom)] masses = [mol.mass(i) for i in range(0, Natom)] f1 = optking.frag.Frag(Z, xyz, masses, intcos=coords, frozen=False) OptMol = optking.molsys.Molsys([f1]) grad_x = psi4.gradient("hf").to_array() grad_q = OptMol.gradient_to_internals(grad_x.flatten(), useMasses=False) grad_x2 = OptMol.gradient_to_cartesians(grad_q).reshape(Natom, 3) assert psi4.compare_values(grad_x, grad_x2, 8, "Diff grad. CART->int->CART") grad_q = OptMol.gradient_to_internals(grad_x.flatten(), useMasses=True) grad_x2 = OptMol.gradient_to_cartesians(grad_q).reshape(Natom, 3) assert psi4.compare_values(grad_x, grad_x2, 8, "Diff grad. CART->int->CART with u=1/mass")
def grad_calc(params, current_geom, mol): """ Uses Psi4/pySCF to calculate the energy gradient and returns the gradient and energy. Here any of the keywords the user provides in the .json input are used to set the options for the energy calculation. Parameters: ---------- params(self) -- contains initialized shared parameters. current_geom(np array) -- Matrix of size natoms x 3 containing the geometry. mol(psi4.Molecule) -- Psi4 molecule object containing the current molecule. Returns: ------- grad_mw(np array) -- Mass weighted gradient matrix of size natoms x 3. E(float) -- single-point energy from Psi4 calculation. """ if (params.qm_program == 'pyscf'): pymol = gto.Mole() pymol.verbose = 0 geom_vec = [] for i in range(params.natoms): atom = [ params.symbols[i], ] atom_coords = [] for j in range(3): atom_coords.append(current_geom[i][j]) atom_coords = tuple(atom_coords) atom.append(atom_coords) geom_vec.append(atom) #print(geom_vec) pymol.atom = geom_vec pymol.unit = 'Bohr' pymol.basis = params.basis pymol.charge = params.molecular_charge pymol.spin = params.molecular_multiplicity - 1 pymol.build() #TODO: PySCF 1.6.2 changes the way solvent is called for gradients, change this here # they also added support for ddPCM, YAY! Let's add it in! if (params.method == "scf"): scf_obj = scf.RHF(pymol) if (params.method == "dft"): scf_obj = dft.RKS(pymol) scf_obj.xc = params.xc_functional if (params.do_solvent): solv_obj = scf_obj.DDCOSMO() solv_obj.with_solvent.eps = params.eps lib.num_threads(params.nthreads) E = solv_obj.scf() grad = solv_obj.nuc_grad_method().kernel() else: lib.num_threads(params.nthreads) E = scf_obj.scf() grad = scf_obj.nuc_grad_method().kernel() if (params.qm_program == 'psi4'): mol.set_geometry(psi4.core.Matrix.from_array(current_geom)) mol.fix_orientation(True) mol.fix_com(True) mol.reset_point_group('c1') grad_method = "%s/%s" % (params.method, params.basis) psi4.core.set_output_file("psi4_out.dat", False) psi4.set_options(params.keywords) psi4.set_num_threads(params.nthreads) E, wfn = psi4.energy(grad_method, return_wfn=True) psi4.set_num_threads(params.nthreads) grad = np.asarray(psi4.gradient(grad_method, ref_wfn=wfn)) #print(grad) return grad
}) print("Testing Energies") for method in ['scf', 'mp2', 'ccsd(t)']: psi_e = psi4.energy(method + '/' + basis_name) quax_e = quax.core.energy(molecule, basis_name, method) print("\n{} energies match: ".format(method), onp.allclose(psi_e, quax_e, rtol=0.0, atol=1e-6), '\n') print('Error:', np.abs(quax_e - psi_e)) print("\n") print("\n") print("Testing Gradients") for method in ['scf', 'mp2', 'ccsd(t)']: psi_deriv = onp.round( onp.asarray(psi4.gradient(method + '/' + basis_name)), 10) quax_deriv = onp.asarray( quax.core.derivative(molecule, basis_name, method, order=1)).reshape(-1, 3) print("\n{} gradients match: ".format(method), onp.allclose(quax_deriv, psi_deriv, rtol=0.0, atol=1e-6), '\n') print('Error:', np.abs(quax_deriv - psi_deriv)) print("\n") print("\n") print("Testing Hessians") for method in ['scf', 'mp2', 'ccsd(t)']: psi_deriv = onp.round( onp.asarray(psi4.hessian(method + '/' + basis_name, dertype='gradient')), 10) quax_deriv = onp.asarray(
basis_set = results.basis_set functional = results.functional charge = int(results.charge) if results.charge is not None else 0 multiplicity = int( results.multiplicity) if results.multiplicity is not None else 1 sys.argv = [sys.argv[0]] # ----------------------- # Psi4 # ----------------------- psi4.set_memory(os.environ.get('PSI4_MAX_MEMORY') + " MB") psi4.core.set_num_threads(int(os.environ.get('OMP_NUM_THREADS'))) molecule = psi4.geometry(""" {charge} {multiplicity} {atomic_coords} """.format( charge=charge, multiplicity=multiplicity, atomic_coords=atomic_coords)) gradient, wfn = psi4.gradient( 'hf/{}'.format(basis_set), molecule=molecule, return_wfn=True) energy = wfn.energy() force = gradient.to_array().tolist() properties = {"energy": energy, "force": force} stringified_properties = json.dumps(properties) print('atoms+bits properties:\n~{}~'.format(stringified_properties))
def en_gr_fun(coords,*args): """ en_gr_fun - calcs energy and gradient for mol coords = coords to calculate the energy - initially set to zero mol_coords = init_coords + coords args = (mol, eg_opts, init_coords, init_com, inv_sqrt_mass, coord_type) where: mol = molecule class name eg_opts = options for energy and grad calcs init_coords such that coords are zero initially init_com = initial center of mass when coords = zero inv_sqrt_mass = 1/sqrt(atmas[iat]) - used when coord_type = 'masswt' coord_type posibilities so far: 'cart' function returns scf_e and grad """ #print("<<<<<<<< en_gr_fun coords: ",coords) #print("no of args in *args = %d" % len(args)) if len(args) == 6: (mol,eg_opts,init_coords,init_com,inv_sqrt_mass,coord_type) = args #print("mol =",mol) print("in en_gr_fun: mol =",mol) #print("dir(mol): ->\n",dir(mol)) #print("init_coords =",init_coords) #print("inv_sqrt_mass =",inv_sqrt_mass) #print("coord_type = %s"% coord_type) nat = mol.natom() if coord_type == 'cart': # coords equal linear array len 3*mol.natom() #debug -- print("cart disp coords: ",coords) pass elif coord_type == 'masswt': # coords are mass weighted - convert to cartessian coords = coords * inv_sqrt_mass # cartesian displacment #debug -- print("masswt disp coords as cart: ",coords) else: print("*** Error not set up for coord_type = %s" % coord_type) sys.exit() geom = np.reshape(coords,(nat,3)) + init_coords mol.set_full_geometry(psi4.core.Matrix.from_array(geom)) #mol.update_geometry mol.update_geometry() #psi4.core.print_out("new mol geom: \n") print_mol_coord_sum(mol,opt_stage="New CART") #for iat in range(mol.natom()): #print("atom %d %3s %9.5f xyz coord = " % (iat,mol.symbol(iat),mol.mass(iat)),mol.xyz(iat)) #print("\n===== co bond distance = %10.5f a.u." % (mol.z(1)-mol.z(0))) cxcom = mol.center_of_mass()[0] cycom = mol.center_of_mass()[1] czcom = mol.center_of_mass()[2] #print("cxcom,cycom,czcom: ",cxcom,cycom,czcom) current_com = np.array([cxcom,cycom,czcom],dtype=float) com_dif = current_com - init_com psi4.core.print_out("\n ++++ current com = %18.10f %18.10f %18.10f" % (current_com[0],current_com[1],current_com[2])) psi4.core.print_out("\n ++++ diff = curr - init = %18.10f %18.10f %18.10f a.u.\n" % (com_dif[0],com_dif[1],com_dif[2])) # get inertia tensor and rotational consts inert_ten = np.array(mol.inertia_tensor()) cur_rotc = np.array(mol.rotational_constants()) psi4.core.print_out("\ncurrent rot consts: %15.9f %15.9f %15.9f" % (cur_rotc[0],cur_rotc[1],cur_rotc[2])) psi4.core.print_out("\ninert_ten -->\n") psi4.core.print_out(str(inert_ten)) # calc evals and evecs for inertia_tensor teval,tevec = np.linalg.eigh(inert_ten) psi4.core.print_out("\n Eigen vals and vecs from inertia tensor") for ivec in range(3): psi4.core.print_out("\neval[%d] = %12.8f vec = (%11.8f, %11.8f, %11.8f)" % (ivec,teval[ivec],tevec[ivec,0],tevec[ivec,1],tevec[ivec,2])) scf_e,wavefn = psi4.energy(eg_opts,return_wfn=True) psi4.core.print_out("++++++++ scf_e in en_fun = %18.9f" % scf_e) #print("++++++++ scf_e in en_fun = %18.9f" % scf_e) G0 = psi4.gradient(eg_opts,ref_wfn=wavefn) gvec = np.array(G0) #jdhd - usually comment out this line 21-dec-2019 #print("+=+=+=+=+ Cart gradient vector: \n", gvec) grad = np.reshape(gvec,(len(coords),)) if coord_type == "masswt": grad *= inv_sqrt_mass #print("=+=+=+=+ Mass wt grad vector: \n",grad) #print("+=+=+=+ grad as a linear array -->",grad) #print(">>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>") return scf_e, grad
def test_dft_mp2(inp): """Adapted from dfmp2-2""" h2 = psi4.geometry(""" 0 1 H H 1 1.7007535129120455 units bohr """) basisset = "cc-pVDZ" psi4.set_options({ 'scf_type': 'df', 'guess': 'sad', 'd_convergence': 12, 'e_convergence': 12, 'points': 5, 'basis': basisset, }) psi4.set_options(inp['options']) if inp['driver'] == 'energy': ene, wfn = psi4.energy(inp['name'], return_wfn=True) elif inp['driver'] == 'gradient': grad, wfn = psi4.gradient(inp['name'], return_wfn=True) #, dertype=0) ene = wfn.energy() # simplifies testing logic #for pv, pvv in psi4.core.variables().items(): # print('CORE -- ', pv, pvv) #for pv, pvv in wfn.variables().items(): # print('WFN -- ', pv, pvv) assert compare_values(ref['nobas']['NUCLEAR REPULSION ENERGY'], h2.nuclear_repulsion_energy(), 10, "Nuclear Repulsion Energy") for obj in [psi4.core, wfn]: for qcvar in ['MP2 TOTAL ENERGY', 'MP2 CORRELATION ENERGY']: assert compare_values(ref[basisset][qcvar], obj.variable(qcvar), 10, basisset + " " + qcvar) for qcvar in [inp['pv'] + ' TOTAL ENERGY', 'CURRENT ENERGY']: assert compare_values(ref[basisset][inp['pv'] + ' TOTAL ENERGY'], obj.variable(qcvar), 10, basisset + " " + qcvar) for qcvar in ['HF TOTAL ENERGY', 'SCF TOTAL ENERGY', 'SCF ITERATION ENERGY', 'CURRENT REFERENCE ENERGY']: assert compare_values(ref[basisset]['HF TOTAL ENERGY'], obj.variable(qcvar), 10, basisset + " " + qcvar) for qcvar in ['DISPERSION CORRECTION ENERGY']: #, #'MP2D DISPERSION CORRECTION ENERGY']: if inp['pv'] == 'MP2D': assert compare_values(ref['nobas']['MP2-D DISPERSION CORRECTION ENERGY'], obj.variable(qcvar), 10, basisset + " " + qcvar) if inp['pv'] == 'MP2D': assert compare_values(ref['nobas']['MP2-D DISPERSION CORRECTION ENERGY'], obj.variable('DISPERSION CORRECTION ENERGY'), 10, basisset + " disp ene") if inp['driver'] == 'gradient': #print(ref['nobas']['MP2-D DISPERSION CORRECTION GRADIENT'].shape) #print(np.asarray(obj.variable('DISPERSION CORRECTION GRADIENT')).shape) assert compare_arrays(ref['nobas']['MP2-D DISPERSION CORRECTION GRADIENT'], np.asarray(obj.variable('DISPERSION CORRECTION GRADIENT')), 10, basisset + " disp grad") pass for retrn in [ene, wfn.energy()]: assert compare_values(ref[basisset][inp['pv'] + ' TOTAL ENERGY'], retrn, 10, basisset + " tot ene") if inp['driver'] == 'gradient': for retrn in [grad, wfn.gradient()]: assert compare_arrays(ref[basisset][inp['pv'] + ' TOTAL GRADIENT'], np.asarray(retrn), 10, basisset + " tot grad")
def compute(self, elements, positions, rvec=None, charge=0, multiplicity=1, field_type='dipole', dipole_strength=[0, 0, 0], forces=False, optimize=False, opt_cartesian=False, uhf=False, max_iters=None): if not rvec is None: print( 'Warning: psi4 does not work with periodic boundary conditions. Ignoring them.' ) self.molecule_string = MoleculeString(elements, positions, charge=charge, multiplicity=multiplicity, reorient=False, no_symmetry=True, no_com=True, verbose=False) self.mol = psi4.geometry( self.molecule_string.geometry) # De input moet in angstrom staan if field_type == 'dipole': #print('Perturbing with a constant electric field') options = { 'basis': self.basis, 'PERTURB_H': True, 'PERTURB_WITH': 'DIPOLE', 'PERTURB_DIPOLE': list(dipole_strength) } if opt_cartesian: options['OPT_COORDINATES'] = 'cartesian' if uhf: options['reference'] = 'uhf' if not max_iters is None: options['GEOM_MAXITER'] = max_iters psi4.set_options(options) if optimize: self.energy, self.wavefunction = psi4.optimize(self.method, return_wfn=True) if forces: self.gradient = self.wavefunction.gradient() return self.energy, mol.geometry( ).np / angstrom, self.gradient.np else: return self.energy, self.mol.geometry().np / angstrom if forces: self.gradient, self.wavefunction = psi4.gradient(self.method, return_wfn=True) self.energy = self.wavefunction.energy() return self.energy, self.gradient.np else: self.energy, self.wavefunction = psi4.energy(self.method, return_wfn=True) return self.energy
def compute_dipole_derivatives(self, wfn, prog='psi4', geom=None, disp_points=3, disp_size=0.001, c4kw={}): Natom = self.mol.natom() if prog.upper() == 'PSI4': # Lacking analytic derivatives, we will do fd of applied electric fields. We # alternately apply + and - electric fields in the x, y, and z directions, and # then take finite differences to get the dipole moment derivatives. self.pr( "(ROA) Computing dipole moment derivatives with Psi4 by f.d...\n" ) #Prepare geometry if geom is None: geom = self.analysis_geom_2D self.mol.set_geometry(core.Matrix.from_array(geom)) self.mol.fix_com(True) self.mol.fix_orientation(True) self.mol.reset_point_group('c1') N = self.mol.natom() if disp_points == 3: lambdas = [-1.0 * disp_size, 1.0 * disp_size] elif disp_points == 5: lambdas = [ -2.0 * disp_size, -1.0 * disp_size, 1.0 * disp_size, +2.0 * disp_size ] DmuxDx = psi4.core.Matrix("Dipole derivatives mu_x", N, 3) DmuyDx = psi4.core.Matrix("Dipole derivatives mu_y", N, 3) DmuzDx = psi4.core.Matrix("Dipole derivatives mu_z", N, 3) for dipole_xyz, dipole_vector in enumerate([[1, 0, 0], [0, 1, 0], [0, 0, 1]]): dx = [] for l in lambdas: core.set_global_option('perturb_h', True) core.set_global_option('perturb_with', 'dipole') scaled_dipole_vector = [] for x in dipole_vector: scaled_dipole_vector.append(x * l) core.set_global_option('perturb_dipole', scaled_dipole_vector) dx.append(psi4.gradient(wfn)) for A in range(N): for xyz in range(3): if disp_points == 3: val = (dx[1].get(A, xyz) - dx[0].get(A, xyz)) / (2.0 * disp_size) elif disp_points == 5: val = (dx[0].get(A,xyz) - 8.0*dx[1].get(A,xyz) \ + 8.0*dx[2].get(A,xyz) - dx[3].get(A,xyz)) / (12.0*disp_size) if dipole_xyz == 0: DmuxDx.set(A, xyz, val) elif dipole_xyz == 1: DmuyDx.set(A, xyz, val) elif dipole_xyz == 2: DmuzDx.set(A, xyz, val) core.set_global_option('PERTURB_H', 0) core.set_global_option('PERTURB_DIPOLE', '') # write out a file17 with the dipole moment derivatives f = open('file17.dat', 'w') for i in range(N): f.write('{0:20.10f}{1:20.10f}{2:20.10f}\n'.format( DmuxDx.get(i, 0), DmuxDx.get(i, 1), DmuxDx.get(i, 2))) for i in range(N): f.write('{0:20.10f}{1:20.10f}{2:20.10f}\n'.format( DmuyDx.get(i, 0), DmuyDx.get(i, 1), DmuyDx.get(i, 2))) for i in range(N): f.write('{0:20.10f}{1:20.10f}{2:20.10f}\n'.format( DmuzDx.get(i, 0), DmuzDx.get(i, 1), DmuzDx.get(i, 2))) f.close() elif prog.upper() == 'CFOUR': self.pr( "(ROA) Reading dipole moment derivatives from CFOUR's DIPDER.\n" ) kw = { 'CALC': wfn.upper(), 'BASIS': core.get_global_option('BASIS'), 'VIB': 'EXACT', 'UNITS': 'BOHR', 'VIB': 'EXACT', 'UNITS': 'BOHR', 'SCF_CONV': 9, 'MEM_UNIT': 'GB', 'MEMORY_SIZE': round(core.get_memory() // 1e9), 'SCF_DAMP': 600, # CFOUR's SCF is really poor at converging. 'SCF_EXPSTART': 300, 'SCF_MAXCYC': 600, } kw.update(c4kw) atom_symbols = [ self.mol.symbol(at) for at in range(self.mol.natom()) ] c4 = CFOUR(self.analysis_geom_2D, atom_symbols, kw, "input for DIPDIR read") (c4dipx, c4dipy, c4dipz) = c4.parseDIPDER() # Now rotate to input orientation c4coord = c4.parseGeometry() rmsd, mill = qcel.molutil.B787(c4coord, self.analysis_geom_2D, None, None, atoms_map=True, verbose=False) RotMat = mill.rotation # For each atom for field direction by nuclear direction 3x3 and transform it. for at in range(Natom): DIPDERatom = np.zeros((3, 3)) DIPDERatom[0, :] = c4dipx[at, :] DIPDERatom[1, :] = c4dipy[at, :] DIPDERatom[2, :] = c4dipz[at, :] DIPDERatom[:] = np.dot(RotMat.T, np.dot(DIPDERatom, RotMat)) c4dipx[at][:] = DIPDERatom[0, :] c4dipy[at][:] = DIPDERatom[1, :] c4dipz[at][:] = DIPDERatom[2, :] c4.writeFile17(c4dipx, c4dipy, c4dipz) else: raise Exception('Other muder prog not yet implemented') return
def test_dft_mp2(inp): """Adapted from dfmp2-2""" h2 = psi4.geometry(""" 0 1 H H 1 1.7007535129120455 units bohr """) basisset = "cc-pVDZ" psi4.set_options({ 'scf_type': 'df', 'guess': 'sad', 'd_convergence': 12, 'e_convergence': 12, 'points': 5, 'basis': basisset, }) psi4.set_options(inp['options']) kwargs = {'return_wfn': True} if inp.get('dertype') is not None: kwargs.update({'dertype': inp['dertype']}) if inp['driver'] == 'energy': ene, wfn = psi4.energy(inp['name'], **kwargs) elif inp['driver'] == 'gradient': grad, wfn = psi4.gradient(inp['name'], **kwargs) ene = wfn.energy() # simplifies testing logic #for pv, pvv in psi4.core.variables().items(): # print('CORE -- ', pv, pvv) #for pv, pvv in wfn.variables().items(): # print('WFN -- ', pv, pvv) assert compare_values(ref['nobas']['NUCLEAR REPULSION ENERGY'], h2.nuclear_repulsion_energy(), 10, "Nuclear Repulsion Energy") for obj in [psi4.core, wfn]: for qcvar in ['MP2 TOTAL ENERGY', 'MP2 CORRELATION ENERGY']: assert compare_values(ref[basisset][qcvar], obj.variable(qcvar), 10, basisset + " " + qcvar) for qcvar in [inp['pv'] + ' TOTAL ENERGY', 'CURRENT ENERGY']: assert compare_values(ref[basisset][inp['pv'] + ' TOTAL ENERGY'], obj.variable(qcvar), 10, basisset + " " + qcvar) ## apparently not widespread #if inp['driver'] == 'gradient': # for qcvar in [inp['pv'] + ' TOTAL GRADIENT', # 'CURRENT GRADIENT']: # assert compare_values(ref[basisset][inp['pv'] + ' TOTAL GRADIENT'], obj.variable(qcvar), 10, basisset + " " + qcvar) for qcvar in [ 'HF TOTAL ENERGY', 'SCF TOTAL ENERGY', 'SCF ITERATION ENERGY', 'CURRENT REFERENCE ENERGY' ]: assert compare_values(ref[basisset]['HF TOTAL ENERGY'], obj.variable(qcvar), 10, basisset + " " + qcvar) if inp['pv'] == 'MP2D': for qcvar in [ 'DISPERSION CORRECTION ENERGY', 'MP2D DISPERSION CORRECTION ENERGY' ]: assert compare_values( ref['nobas']['MP2-D DISPERSION CORRECTION ENERGY'], obj.variable(qcvar), 10, basisset + " " + qcvar) if inp['driver'] == 'gradient' and 'dertype' not in inp: for qcvar in [ 'DISPERSION CORRECTION GRADIENT', 'MP2D DISPERSION CORRECTION GRADIENT' ]: assert compare_arrays( ref['nobas']['MP2-D DISPERSION CORRECTION GRADIENT'], np.asarray(obj.variable(qcvar)), 10, basisset + " disp grad") for retrn in [ene, wfn.energy()]: assert compare_values(ref[basisset][inp['pv'] + ' TOTAL ENERGY'], retrn, 10, basisset + " tot ene") if inp['driver'] == 'gradient': for retrn in [grad, wfn.gradient()]: atol = 2.e-8 if 'dertype' in inp else 1.e-10 assert compare_values(ref[basisset][inp['pv'] + ' TOTAL GRADIENT'], np.asarray(retrn), basisset + " tot grad", atol=atol)
def _compute_forces(self): g = -psi4.gradient("SCF", molecule=self.molecule).to_array(dense=True) return numpy.array([g])