def psi4_esp(method, basis, molecule): """ Computes QM electrostatic potential Parameters ---------- method : str QM method basis : str basis set molecule : psi4.Molecule instance Returns ------- np.array QM electrostatic potential. Note ----- Psi4 read grid information from grid.dat file """ import psi4 mol = psi4.geometry(molecule.create_psi4_string_from_molecule()) psi4.set_options({'basis': basis}) e, wfn = psi4.prop(method, properties=['GRID_ESP'], return_wfn=True) psi4.core.clean() return np.loadtxt('grid_esp.dat')
def compute_energy_and_charges(self, charge_method='MULLIKEN_CHARGES'): """ Calls Psi4 to obtain the self.energy, self.wavefunction, and self.charges on each atom. This method for correlated methods. Note ---- Think about passing in wavefunction instead of calling for energy and wavefunction """ self.set_up_psi4() self.energy, self.wavefunction = psi4.prop(self.method, properties=[charge_method], return_wfn=True) self.charges = np.asarray(self.wavefunction.atomic_point_charges())
def get_elpot(xs,ys,zs,Dnew=None,wfn=None,update=False): if (update): Dreal = Dnew.real wfn.oeprop.set_Da_ao(psi4.core.Matrix.from_array(Dreal)) wfn.oeprop.compute() Vvals = wfn.oeprop.Vvals() else: with open('grid.dat', 'w') as fout: for i in range(xs.np.shape[0]): fout.write("{: 21.18e} {: 21.18e} {: 21.18e}\n".format(xs.np[i], ys.np[i], zs.np[i])) fout.close() ene,wfn = psi4.prop('blyp', properties=['GRID_ESP'], return_wfn=True) #ene,wfn = psi4.energy('blyp',return_wfn=True) Vvals = wfn.oeprop.Vvals() return Vvals, wfn
def CALC_ESP_PSI4(dir, params): os.chdir(dir) psi4.core.be_quiet() properties_origin = ["COM"] #psi4.core.set_output_file(dir, False) ang_au = CONSTANTS.angstrom_to_au xS = 0.0 * ang_au yS = 0.0 * ang_au zS = 0.0 * ang_au xH1 = 0.0 * ang_au yH1 = 0.1 * ang_au zH1 = 1.2 * ang_au xH2 = 0.1 * ang_au yH2 = 1.4 * ang_au zH2 = -0.1 * ang_au mol = psi4.geometry(""" 1 2 noreorient units au S {0} {1} {2} H1 {3} {4} {5} H2 {6} {7} {8} """.format(xS, yS, zS, xH1, yH1, zH1, xH2, yH2, zH2)) psi4.set_options({ 'basis': params['scf_basis'], 'e_convergence': params['scf_enr_conv'], 'reference': params['scf_method'] }) E, wfn = psi4.prop('scf', properties=["GRID_ESP"], return_wfn=True) Vvals = wfn.oeprop.Vvals() os.chdir("../") return Vvals
def CALC_ESP_PSI4_ROT(dir, params, mol_xyz): os.chdir(dir) psi4.core.be_quiet() properties_origin = [ "COM" ] #[“NUCLEAR_CHARGE”] or ["COM"] #here might be the shift! ang_au = CONSTANTS.angstrom_to_au if params['molec_name'] == "d2s": mol = psi4.geometry(""" 1 2 noreorient units au nocom S {0} {1} {2} H {3} {4} {5} H {6} {7} {8} """.format( mol_xyz[0, 0], mol_xyz[1, 0], mol_xyz[2, 0], mol_xyz[0, 1], mol_xyz[1, 1], mol_xyz[2, 1], mol_xyz[0, 2], mol_xyz[1, 2], mol_xyz[2, 2], )) if params['molec_name'] == "cmethane": mol = psi4.geometry(""" 1 2 units au C H 1 CH1 H 1 CH2 2 HCH H 1 CH3 2 HCH 3 120.0 H 1 CH4 2 HCH 3 240.0 CH1 = {0} CH2 = {1} CH3 = {2} CH4 = {3} HCH = 109.471209 """.format(params['mol_geometry']['r1'], params['mol_geometry']['r2'], params['mol_geometry']['r3'], params['mol_geometry']['r4'])) elif params['molec_name'] == "n2": mol = psi4.geometry(""" 1 2 noreorient units au nocom N {0} {1} {2} N {3} {4} {5} """.format(mol_xyz[0, 0], mol_xyz[1, 0], mol_xyz[2, 0], mol_xyz[0, 1], mol_xyz[1, 1], mol_xyz[2, 1])) elif params['molec_name'] == "co": mol = psi4.geometry(""" 1 2 noreorient units au nocom C {0} {1} {2} O {3} {4} {5} """.format(mol_xyz[0, 0], mol_xyz[1, 0], mol_xyz[2, 0], mol_xyz[0, 1], mol_xyz[1, 1], mol_xyz[2, 1])) elif params['molec_name'] == "ocs": mol = psi4.geometry(""" 1 2 noreorient units au O {0} {1} {2} C {3} {4} {5} S {6} {7} {8} """.format( mol_xyz[0, 0], mol_xyz[1, 0], mol_xyz[2, 0], mol_xyz[0, 1], mol_xyz[1, 1], mol_xyz[2, 1], mol_xyz[0, 2], mol_xyz[1, 2], mol_xyz[2, 2], )) elif params['molec_name'] == "h2o": mol = psi4.geometry(""" 1 2 noreorient units au O {0} {1} {2} H {3} {4} {5} H {6} {7} {8} """.format( 0.0, 0.0, 0.0, 0.0, 1.0, 1.0, 0.0, -2.0, 2.0, )) elif params['molec_name'] == "h": mol = psi4.geometry(""" 1 1 noreorient units au nocom H {0} {1} {2} """.format(0.0, 0.0, 1.0)) elif params['molec_name'] == "c": mol = psi4.geometry(""" 1 2 noreorient units au C {0} {1} {2} """.format(0.0, 0.0, 0.0)) psi4.set_options({ 'basis': params['scf_basis'], 'e_convergence': params['scf_enr_conv'], 'reference': params['scf_method'] }) E, wfn = psi4.prop('scf', properties=["GRID_ESP"], return_wfn=True) Vvals = wfn.oeprop.Vvals() os.chdir("../") return Vvals #h2o = psi4.geometry(""" #1 2 #noreorient #O 0.0 0.0 0.000000000000 #H 0.757 0.586 0.000000000000 #H -0.757 0.586 0.000000000000 #""") #D2S geometry (NIST) # r(S-D) = 1.336 ang #angle = 92.06 """
def resp(molecules, options_list=None, intermol_constraints=None): """RESP code driver. Parameters ---------- molecules : list list of psi4.Molecule instances options_list : list, optional list of dictionaries of user's defined options intermol_constraints : dict, optional dictionary of options for multi-molecules fitting Returns ------- charges : list list of charges Note ---- output files : mol_results.dat: fitting results mol_grid.dat: grid points in molecule.units mol_grid_esp.dat: QM esp valuese in a.u. """ if intermol_constraints is None: intermol_constraints = {} if options_list is None: options_list = [] # Check options # Large case keys: resp options # Small case key: internal data intermol_constraints = { k.upper(): v for k, v in intermol_constraints.items() } if 'CHARGE' not in intermol_constraints: intermol_constraints['CHARGE'] = [] if 'EQUAL' not in intermol_constraints: intermol_constraints['EQUAL'] = [] # Check options for first molecule options = {k.upper(): v for k, v in sorted(options_list[0].items())} # VDW surface options if 'ESP' not in options: options['ESP'] = [] if 'GRID' not in options: options['GRID'] = [] if 'N_VDW_LAYERS' not in options: options['N_VDW_LAYERS'] = 4 if 'VDW_SCALE_FACTOR' not in options: options['VDW_SCALE_FACTOR'] = 1.4 if 'VDW_INCREMENT' not in options: options['VDW_INCREMENT'] = 0.2 if 'VDW_POINT_DENSITY' not in options: options['VDW_POINT_DENSITY'] = 1.0 # Hyperbolic restraint options if 'WEIGHT' not in options: options['WEIGHT'] = 1 if 'RESTRAINT' not in options: options['RESTRAINT'] = True if options['RESTRAINT']: if 'RESP_A' not in options: options['RESP_A'] = 0.0005 if 'RESP_B' not in options: options['RESP_B'] = 0.1 if 'IHFREE' not in options: options['IHFREE'] = True if 'TOLER' not in options: options['TOLER'] = 1e-5 if 'MAX_IT' not in options: options['MAX_IT'] = 25 # QM options if 'METHOD_ESP' not in options: options['METHOD_ESP'] = 'scf' if 'BASIS_ESP' not in options: options['BASIS_ESP'] = '6-31g*' options_list[0] = options final_options_list = [] n_atoms = [] symbols_list = [] for imol in range(len(molecules)): options = {k.upper(): v for k, v in options_list[imol].items()} # VDW surface options if 'RADIUS' not in options: options['RADIUS'] = {} radii = {} for i in options['RADIUS']: radii[i.upper()] = options['RADIUS'][i] options['RADIUS'] = radii # Constraint options if 'CONSTRAINT_CHARGE' not in options: options['CONSTRAINT_CHARGE'] = [] if 'CONSTRAINT_GROUP' not in options: options['CONSTRAINT_GROUP'] = [] if 'CONSTRAINT_EQUAL' not in options: options['CONSTRAINT_EQUAL'] = [] if imol > 0: for i in final_options_list[0]: if i not in options and i.isupper(): options[i] = final_options_list[0][i] options['mol_charge'] = molecules[imol].molecular_charge() n_atoms.append(molecules[imol].natom()) coordinates = molecules[imol].geometry() coordinates = coordinates.np.astype('float') * bohr_to_angstrom options['coordinates'] = coordinates symbols = [] for i in range(n_atoms[-1]): symbols.append(molecules[imol].symbol(i)) options['symbols'] = symbols symbols_list.append(symbols) if options['GRID']: # Read grid points points = np.loadtxt(options['GRID']) np.savetxt('grid.dat', points, fmt='%15.10f') if 'Bohr' in str(molecules[imol].units): points *= bohr_to_angstrom else: # Get the points at which we're going to calculate the ESP surface points = [] surface = vdw_surface_helper.vdw_surface_helper() for i in range(options['N_VDW_LAYERS']): scale_factor = options[ 'VDW_SCALE_FACTOR'] + i * options['VDW_INCREMENT'] surface.vdw_surface(coordinates, symbols, scale_factor, options['VDW_POINT_DENSITY'], options['RADIUS']) points.append(surface.shell) radii = surface.radii points = np.concatenate(points) if 'Bohr' in str(molecules[imol].units): points /= bohr_to_angstrom np.savetxt('grid.dat', points, fmt='%15.10f') points *= bohr_to_angstrom else: np.savetxt('grid.dat', points, fmt='%15.10f') # Calculate ESP values at the grid if options['ESP']: # Read electrostatic potential values options['esp_values'] = np.loadtxt(options['ESP']) np.savetxt('grid_esp.dat', options['esp_values'], fmt='%15.10f') else: import psi4 psi4.core.set_active_molecule(molecules[imol]) psi4.set_options({'basis': options['BASIS_ESP']}) psi4.set_options(options.get('PSI4_OPTIONS', {})) psi4.prop(options['METHOD_ESP'], properties=['GRID_ESP']) options['esp_values'] = np.loadtxt('grid_esp.dat') psi4.core.clean() os.system("mv grid.dat %i_%s_grid.dat" % (imol + 1, molecules[imol].name())) os.system("mv grid_esp.dat %i_%s_grid_esp.dat" % (imol + 1, molecules[imol].name())) # Build a matrix of the inverse distance from each ESP point to each nucleus invr = np.zeros((len(points), len(coordinates))) for i in range(invr.shape[0]): for j in range(invr.shape[1]): invr[i, j] = 1 / np.linalg.norm(points[i] - coordinates[j]) options['invr'] = invr * bohr_to_angstrom # convert to atomic units options['coordinates'] /= bohr_to_angstrom # convert to angstroms final_options_list.append(options) # Calculate charges qf, labelf, notes = espfit.fit(final_options_list, intermol_constraints) index = 0 charges = [] # Extract the charges for imol in range(len(molecules)): q = [i[index:index + n_atoms[imol]] for i in qf] index += n_atoms[imol] charges.append(q) for imol in range(len(molecules)): options = final_options_list[imol] # Write the results to disk with open( str(imol + 1) + '_' + molecules[imol].name() + "_results.out", "w") as f: f.write("\n Electrostatic potential parameters\n") f.write("\n Grid information (see %i_%s_grid.dat in %s)\n" % (imol + 1, molecules[imol].name(), str(molecules[imol].units).split('.')[1])) f.write(" van der Waals radii (Angstrom):\n") for i, j in radii.items(): f.write(" %8s%8.3f\n" % (i, j / scale_factor)) f.write(" Number of VDW layers: %d\n" % (options["N_VDW_LAYERS"])) f.write(" VDW scale facotr: %.3f\n" % (options["VDW_SCALE_FACTOR"])) f.write(" VDW increment: %.3f\n" % (options["VDW_INCREMENT"])) f.write(" VDW point density: %.3f\n" % (options["VDW_POINT_DENSITY"])) f.write(" Number of grid points: %d\n" % len(options['esp_values'])) f.write( "\n Quantum electrostatic potential (see %i_%s_grid_esp.dat)\n" % (imol + 1, molecules[imol].name())) f.write(" ESP method: %s\n" % options['METHOD_ESP']) f.write(" ESP basis set: %s\n" % options['BASIS_ESP']) f.write("\n Constraints\n") if options['CONSTRAINT_CHARGE']: f.write(" Charge constraints\n") for i in options['CONSTRAINT_CHARGE']: f.write(" Total charge of %8.5f on the set" % i[0]) for j in i[1]: f.write("%4d" % j) f.write("\n") if options['CONSTRAINT_GROUP'] or options['CONSTRAINT_EQUAL']: f.write(" Equality constraints\n") f.write(" Equal charges on atoms\n") for i in options['CONSTRAINT_GROUP']: f.write(" ") for j in i: f.write("%4d" % j) f.write("\n") for i in options['CONSTRAINT_EQUAL']: for j in range(len(i)): f.write(" ") f.write("%4d%4d" % (i[0][j], i[1][j])) f.write("\n") if intermol_constraints['CHARGE'] or intermol_constraints['EQUAL']: f.write('\n Intermolecular constraints\n') if intermol_constraints['CHARGE']: f.write(' Charge constraints\n') for i in intermol_constraints['CHARGE']: f.write( ' Total charge of %8.5f on the set:' % i[0]) for j in i[1]: f.write('\n molecule %4d, atoms' % j[0]) for k in j[1]: f.write('%4d' % k) f.write('\n') if intermol_constraints['EQUAL']: f.write(' Equality constraints\n') f.write(' Equal charges on\n') for i in intermol_constraints['EQUAL']: f.write(' ') f.write('molecule %4d, atoms' % i[0][0]) for j in i[0][1]: f.write('%4d' % j) f.write('\n molecule %4d, atoms' % i[1][0]) for j in i[1][1]: f.write('%4d' % j) f.write('\n\n') f.write("\n Restraint\n") if options['RESTRAINT']: f.write(" Hyperbolic restraint to a charge of zero\n") if options['IHFREE']: f.write(" Hydrogen atoms are not restrained\n") f.write(" resp_a: %.4f\n" % (options["RESP_A"])) f.write(" resp_b: %.4f\n" % (options["RESP_B"])) f.write("\n Fit\n") for i in notes: if i: f.write(i + '\n') f.write("\n Electrostatic Potential Charges\n") f.write(" Center Symbol") for i in labelf: f.write("%10s" % i) f.write("\n") for i in range(n_atoms[imol]): f.write(" %5d %s " % (i + 1, symbols_list[imol][i])) for j in charges[imol]: f.write("%10.5f" % j[i]) f.write("\n") f.write(" Total Charge: ") for i in charges[imol]: f.write("%10.5f" % np.sum(i)) f.write('\n') return charges
def resp(wfn, options={}): mol = wfn.molecule() n_atoms = mol.natom() # Check options check_options = {} for i in options.keys(): check_options[i.upper()] = options[i] options = check_options if not ('N_VDW_LAYERS' in options.keys()): options['N_VDW_LAYERS'] = 4 if not ('VDW_SCALE_FACTOR' in options.keys()): options['VDW_SCALE_FACTOR'] = 1.4 if not ('VDW_INCREMENT' in options.keys()): options['VDW_INCREMENT'] = 0.2 if not ('VDW_POINT_DENSITY' in options.keys()): options['VDW_POINT_DENSITY'] = 1.0 if not ('RESP_A' in options.keys()): options['RESP_A'] = 0.0005 if not ('RESP_B' in options.keys()): options['RESP_B'] = 0.1 if not ('METHOD' in options.keys()): options['METHOD'] = 'scf' if not ('CHARGE_GROUPS' in options.keys()): options['CHARGE_GROUPS'] = range(n_atoms) if not ('TWO_STAGE_FIT' in options.keys()): options['TWO_STAGE_FIT'] = False if options['TWO_STAGE_FIT']: if not ('RESP_A2' in options.keys()): options['RESP_A2'] = 0.001 if not ('FIT2' in options.keys()): options['FIT2'] = range(n_atoms) if not ('CHARGE_GROUPS2' in options.keys()): options['CHARGE_GROUPS2'] = range(n_atoms) options['mol_charge'] = mol.molecular_charge() # Get the coordinates of the nuclei in Angstroms symbols = [] coordinates = np.asarray(mol.geometry()) # the vdwsurface code expects coordinates in angstroms coordinates *= bohr_to_angstrom for i in range(n_atoms): symbols.append(mol.symbol(i)) # Get the points at which we're going to calculate the ESP surface points = [] for i in range(options['N_VDW_LAYERS']): scale_factor = options[ 'VDW_SCALE_FACTOR'] + i * options['VDW_INCREMENT'] this_shell = vdw_surface(coordinates, symbols, scale_factor, options['VDW_POINT_DENSITY']) points.append(this_shell) points = np.concatenate(points) if 'Bohr' in str(mol.units): points /= bohr_to_angstrom np.savetxt('grid.dat', points, fmt='%.9f', delimiter='\t') points *= bohr_to_angstrom else: np.savetxt('grid.dat', points, fmt='%.9f', delimiter='\t') # Calculate ESP values at the grid e, wfn = psi4.prop(options['METHOD'], properties=['GRID_ESP', 'MULLIKEN_CHARGES'], molecule=wfn.molecule(), return_wfn=True) options['esp_values'] = wfn.oeprop.Vvals() options['charges'] = np.asarray(wfn.atomic_point_charges()) # Build a matrix of the inverse distance from each ESP point to each nucleus options['invr'] = 1.0 / scipy.spatial.distance_matrix(points, coordinates) options['invr'] *= bohr_to_angstrom # Run the optimization using SciPy charges = scipy.optimize.minimize( resp_objective, options['charges'], args=(options), jac=True, method='SLSQP', tol=1e-8, options={'ftol': 1e-8}, constraints={ 'type': 'eq', 'fun': resp_constraint, 'args': [options['mol_charge'], options['CHARGE_GROUPS'], False] }) charges = charges.x if options['TWO_STAGE_FIT']: a = options['RESP_A'] options['RESP_A'] = options['RESP_A2'] options['charges'] = charges charges2 = scipy.optimize.minimize(resp_objective, charges[options['FIT2']], args=(options, True), jac=True, method='SLSQP', tol=1e-8, options={'ftol': 1e-8}, constraints={ 'type': 'eq', 'fun': resp_constraint, 'args': [ options['mol_charge'], options['CHARGE_GROUPS2'], True, options['charges'], options['FIT2'] ] }) charges[options['FIT2']] = charges2.x options['RESP_A'] = a np.savetxt('charges', charges) # Print the parameters to disk psi4.core.print_out( "\n ---------------------------------------------------\n") psi4.core.print_out(" RESTRAINED ELECTROSTATIC POTENTIAL PARAMETERS\n") psi4.core.print_out( " ---------------------------------------------------\n") psi4.core.print_out(" N_VDW_LAYERS: %d\n" % (options["N_VDW_LAYERS"])) psi4.core.print_out(" VDW_SCALE_FACTOR: %.3f\n" % (options["VDW_SCALE_FACTOR"])) psi4.core.print_out(" VDW_INCREMENT: %.3f\n" % (options["VDW_INCREMENT"])) psi4.core.print_out(" VDW_POINT_DENSITY: %.3f\n" % (options["VDW_POINT_DENSITY"])) psi4.core.print_out(" RESP_A: %.4f\n" % (options["RESP_A"])) psi4.core.print_out(" RESP_B: %.4f\n" % (options["RESP_B"])) psi4.core.print_out(" CHARGE_GROUPS: [") for i in options['CHARGE_GROUPS'][:-1]: psi4.core.print_out('%d, ' % i) psi4.core.print_out('%d]\n' % options['CHARGE_GROUPS'][-1]) psi4.core.print_out(" TWO_STAGE_FIT: %s\n" % (options["TWO_STAGE_FIT"])) if options["TWO_STAGE_FIT"]: psi4.core.print_out(" RESP_A2: %.4f\n" % (options["RESP_A2"])) psi4.core.print_out(" FIT2: [") for i in options["FIT2"][:-1]: psi4.core.print_out('%d, ' % i) psi4.core.print_out('%d]\n' % options["FIT2"][-1]) psi4.core.print_out(" CHARGE_GROUPS2: [") for i in options['CHARGE_GROUPS2'][:-1]: psi4.core.print_out('%d, ' % i) psi4.core.print_out('%d]\n' % options['CHARGE_GROUPS2'][-1]) psi4.core.print_out(" METHOD: %s\n" % (options["METHOD"])) psi4.core.print_out( " ---------------------------------------------------\n") # Print the results to disk psi4.core.print_out("\n ----------------------------------------------\n") psi4.core.print_out(" RESTRAINED ELECTROSTATIC POTENTIAL CHARGES\n") psi4.core.print_out(" Center Symbol RESP Charge (a.u.)\n") psi4.core.print_out(" ----------------------------------------------\n") for i in range(len(charges)): psi4.core.print_out(" %5d %s %8.5f\n" % (i, symbols[i], charges[i]))
def resp(molecules, options=None): """RESP code driver. Parameters ---------- molecules : list list of psi4.Molecule instances options_list : dict, optional a dictionary of user's defined options Returns ------- charges : list list of charges Note ---- output files : mol_results.dat: fitting results mol_grid.dat: grid points in molecule.units mol_grid_esp.dat: QM esp valuese in a.u. """ if options is None: options = {} # Check options # RESP options have large case keys options = {k.upper(): v for k, v in sorted(options.items())} # VDW surface options if 'ESP' not in options: options['ESP'] = [] if 'GRID' not in options: options['GRID'] = [] if 'VDW_SCALE_FACTORS' not in options: options['VDW_SCALE_FACTORS'] = [1.4, 1.6, 1.8, 2.0] if 'VDW_POINT_DENSITY' not in options: options['VDW_POINT_DENSITY'] = 1.0 # Hyperbolic restraint options if 'WEIGHT' not in options: options['WEIGHT'] = [1] * len(molecules) if 'RESTRAINT' not in options: options['RESTRAINT'] = True if options['RESTRAINT']: if 'RESP_A' not in options: options['RESP_A'] = 0.0005 if 'RESP_B' not in options: options['RESP_B'] = 0.1 if 'IHFREE' not in options: options['IHFREE'] = True if 'TOLER' not in options: options['TOLER'] = 1e-5 if 'MAX_IT' not in options: options['MAX_IT'] = 25 # QM options if 'METHOD_ESP' not in options: options['METHOD_ESP'] = 'scf' if 'BASIS_ESP' not in options: options['BASIS_ESP'] = '6-31g*' # VDW surface options if 'VDW_RADII' not in options: options['VDW_RADII'] = {} radii = {} for i in options['VDW_RADII']: radii[i.upper()] = options['VDW_RADII'][i] options['VDW_RADII'] = radii # Constraint options if 'CONSTRAINT_CHARGE' not in options: options['CONSTRAINT_CHARGE'] = [] if 'CONSTRAINT_GROUP' not in options: options['CONSTRAINT_GROUP'] = [] data = {} # Same data for all conformer data['natoms'] = molecules[0].natom() data['symbols'] = [] for i in range(data['natoms']): data['symbols'].append(molecules[0].symbol(i)) data['mol_charge'] = molecules[0].molecular_charge() # Data for each conformer data['coordinates'] = [] data['esp_values'] = [] data['invr'] = [] for imol in range(len(molecules)): coordinates = molecules[imol].geometry() coordinates = coordinates.np.astype('float') * bohr_to_angstrom data['coordinates'].append(coordinates) if options['GRID']: # Read grid points points = np.loadtxt(options['GRID'][imol]) np.savetxt('grid.dat', points, fmt='%15.10f') if 'Bohr' in str(molecules[imol].units()): points *= bohr_to_angstrom else: # Get the points at which we're going to calculate the ESP points = [] for scale_factor in options['VDW_SCALE_FACTORS']: shell, radii = vdw_surface.vdw_surface( coordinates, data['symbols'], scale_factor, options['VDW_POINT_DENSITY'], options['VDW_RADII']) points.append(shell) points = np.concatenate(points) if 'Bohr' in str(molecules[imol].units()): points /= bohr_to_angstrom np.savetxt('grid.dat', points, fmt='%15.10f') points *= bohr_to_angstrom else: np.savetxt('grid.dat', points, fmt='%15.10f') # Calculate ESP values at the grid if options['ESP']: # Read electrostatic potential values data['esp_values'].append(np.loadtxt(options['ESP'][imol])) np.savetxt('grid_esp.dat', data['esp_values'][-1], fmt='%15.10f') else: import psi4 psi4.core.set_active_molecule(molecules[imol]) psi4.set_options({'basis': options['BASIS_ESP']}) psi4.set_options(options.get('PSI4_OPTIONS', {})) psi4.prop(options['METHOD_ESP'], properties=['GRID_ESP']) data['esp_values'].append(np.loadtxt('grid_esp.dat')) psi4.core.clean() os.system("mv grid.dat %i_%s_grid.dat" % (imol + 1, molecules[imol].name())) os.system("mv grid_esp.dat %i_%s_grid_esp.dat" % (imol + 1, molecules[imol].name())) # Build a matrix of the inverse distance from each ESP point to each nucleus invr = np.zeros((len(points), len(coordinates))) for i in range(invr.shape[0]): for j in range(invr.shape[1]): invr[i, j] = 1 / np.linalg.norm(points[i] - coordinates[j]) data['invr'].append(invr * bohr_to_angstrom) # convert to atomic units data['coordinates'][-1] /= bohr_to_angstrom # convert to angstroms # Calculate charges qf, labelf, notes = espfit.fit(options, data) # Write the results to disk with open("results.out", "w") as f: f.write("Electrostatic potential parameters\n") if not options['GRID']: f.write(" van der Waals radii (Angstrom):\n") for i, j in radii.items(): f.write(" %8s%8.3f\n" % (i, j / scale_factor)) f.write(" VDW scale factors: ") for i in options["VDW_SCALE_FACTORS"]: f.write('%6.2f' % i) f.write('\n') f.write(" VDW point density: %.3f\n" % (options["VDW_POINT_DENSITY"])) if not options['ESP']: f.write(" ESP method: %s\n" % options['METHOD_ESP']) f.write(" ESP basis set: %s\n" % options['BASIS_ESP']) for imol in range(len(molecules)): f.write( "\nGrid information (see %i_%s_grid.dat in %s)\n" % (imol + 1, molecules[imol].name(), molecules[imol].units())) f.write(" Number of grid points: %d\n" % len(data['esp_values'][imol])) f.write( "\nQuantum electrostatic potential (see %i_%s_grid_esp.dat)\n" % (imol + 1, molecules[imol].name())) f.write("\nConstraints\n") if options['CONSTRAINT_CHARGE']: f.write(" Charge constraints\n") for i in options['CONSTRAINT_CHARGE']: f.write(" Total charge of %12.8f on the set" % i[0]) for j in i[1]: f.write("%4d" % j) f.write("\n") if options['CONSTRAINT_GROUP']: f.write(" Equality constraints\n") f.write(" Equal charges on atoms\n") for i in options['CONSTRAINT_GROUP']: f.write(" ") for j in i: f.write("%4d" % j) f.write("\n") f.write("\nRestraint\n") if options['RESTRAINT']: f.write(" Hyperbolic restraint to a charge of zero\n") if options['IHFREE']: f.write(" Hydrogen atoms are not restrained\n") f.write(" resp_a: %.4f\n" % (options["RESP_A"])) f.write(" resp_b: %.4f\n" % (options["RESP_B"])) f.write("\nFit\n") f.write(notes) f.write("\nElectrostatic Potential Charges\n") f.write(" Center Symbol") for i in labelf: f.write("%10s" % i) f.write("\n") for i in range(data['natoms']): f.write(" %5d %s " % (i + 1, data['symbols'][i])) for j in qf: f.write("%12.8f" % j[i]) f.write("\n") f.write("Total Charge: ") for i in qf: f.write("%12.8f" % np.sum(i)) f.write('\n') return qf