def main(): # Get user input. args = parse_user_input() _exec("rm -f ts-analyze.tar.bz2 irc_transition.xyz irc_transition.vib", print_command=False) # Standardize base name to "irc_transition". shutil.copy2(args.ts, 'irc_transition.xyz') # Run Q-Chem calculations.. QCT = QChem("irc_transition.xyz", charge=args.charge, mult=args.mult, method=args.method, basis=args.basis) # Ensure stability. QCT.make_stable() # Single point calculation for bond order matrix. QCT.jobtype = 'sp' QCT.remextra = OrderedDict([('scf_final_print', '1')]) QCT.calculate() np.savetxt("irc_transition.bnd", QCT.load_qcout().qm_bondorder, fmt="%8.3f") # Frequency calculation. QCT.jobtype = 'freq' QCT.calculate() QCT.write_vdata('irc_transition.vib') tarexit()
def QCOpt(initial, charge, mult, method, basis, cycles=100, gtol=600, dxtol=2400, etol=200, cart=False): """ Run a Q-Chem geometry optimization. Default tolerances for gradient, displacement and energy are higher than usual because we don't want significant nonbonded conformational changes in the pathway. Parameters ---------- initial : str Initial XYZ file for optimization charge : int Net charge mult : int Spin multiplicity method : str Electronic structure method basis : str Basis set cycles : int Number of optimization cycles gtol : int Gradient tolerance for Q-Chem dxtol : int Displacement tolerance for Q-Chem etol : int Energy tolerance for Q-Chem cart : bool Perform the optimization in Cartesian coordinates """ # Create Q-Chem object. QC = QChem(initial, charge=charge, mult=mult, method=method, basis=basis, qcin='optimize.in') # Run a stability analysis first to ensure we're in the ground state. QC.make_stable() # Set geometry optimization options. QC.jobtype = 'opt' QC.remextra = OrderedDict() if cart: QC.remextra['geom_opt_coords'] = 0 QC.remextra['thresh'] = 14 QC.remextra['geom_opt_tol_gradient'] = gtol QC.remextra['geom_opt_tol_displacement'] = dxtol QC.remextra['geom_opt_tol_energy'] = etol QC.remextra['geom_opt_max_cycles'] = cycles # Run Q-Chem. QC.calculate() # Create Molecule object from running Q-Chem. M = QC.load_qcout() return M
def main(): # Get user input. args = parse_user_input() # Start timer. click() # Run single point calculation to determine bond order matrix. QCSP = QChem(args.initial, charge=args.charge, mult=args.mult, method=args.method, basis=args.basis) QCSP.make_stable() QCSP.jobtype = 'sp' QCSP.remextra = OrderedDict([('scf_final_print', '1')]) QCSP.calculate() # Rebuild bond list using the bond order matrix. M = QCSP.load_qcout() InitE = M.qm_energies[0] M.bonds = [] # Determined from an incredibly small # of data points. # In example_1.xyz, an O-H distance of 1.89 Angstrom had a BO of 0.094 (so it should be > 0.1) # In example_1.xyz, a C-H distance of 1.39 Angstrom had a BO of 0.305 (so it should be < 0.3) bo_thresh = 0.2 numbonds = 0 bondfactor = 0.0 print("Atoms QM-BO Distance") for i in range(M.na): for j in range(i + 1, M.na): # Print out the ones that are "almost" bonds. if M.qm_bondorder[i, j] > 0.1: print("%s%i%s%s%i % .3f % .3f" % (M.elem[i], i, '-' if M.qm_bondorder[i, j] > bo_thresh else ' ', M.elem[j], j, M.qm_bondorder[i, j], np.linalg.norm(M.xyzs[-1][i] - M.xyzs[-1][j]))) if M.qm_bondorder[i, j] > bo_thresh: M.bonds.append((i, j)) numbonds += 1 if M.qm_bondorder[i, j] <= 1: bondfactor += M.qm_bondorder[i, j] else: # Count double bonds as 1 bondfactor += 1 bondfactor /= numbonds M.build_topology() subxyz = [] subef = [] subna = [] subchg = [] submult = [] subvalid = [] SumFrags = [] # Divide calculation into subsystems. for subg in M.molecules: matoms = subg.nodes() frag = M.atom_select(matoms) # Determine output file name. fout = os.path.splitext( args.initial)[0] + '.sub_%i' % len(subxyz) + '.xyz' # Assume we are getting the Mulliken charges from the last frame, it's safer. # Write the output .xyz file. Chg = sum(M.qm_mulliken_charges[-1][matoms]) SpnZ = sum(M.qm_mulliken_spins[-1][matoms]) Spn2 = sum([i**2 for i in M.qm_mulliken_spins[-1][matoms]]) frag.comms = [ "Molecular formula %s atoms %s from %s charge %+.3f sz %+.3f sz^2 %.3f" % (subg.ef(), commadash(subg.nodes()), args.initial, Chg, SpnZ, Spn2) ] frag.write(fout) subxyz.append(fout) subef.append(subg.ef()) subna.append(frag.na) # Determine integer charge and multiplicity. ichg, chgpass = extract_int(np.array([Chg]), 0.5, 1.0, label="charge") ispn, spnpass = extract_int(np.array([abs(SpnZ)]), 0.5, 1.0, label="spin-z") nproton = sum([Elements.index(i) for i in frag.elem]) nelectron = nproton + ichg # If calculation is valid, append to the list of xyz/chg/mult to be calculated. if (not chgpass or not spnpass): print("Cannot determine charge and spin for fragment %s\n" % subg.ef()) subchg.append(None) submult.append(None) subvalid.append(False) elif ((nelectron - ispn) / 2) * 2 != (nelectron - ispn): print("Inconsistent charge and spin-z for fragment %s\n" % subg.ef()) subchg.append(None) submult.append(None) subvalid.append(False) else: subchg.append(ichg) submult.append(ispn + 1) subvalid.append(True) print("%i/%i subcalculations are valid" % (len(subvalid), sum(subvalid))) for i in range(len(subxyz)): print("%s formula %-12s charge %i mult %i %s" % (subxyz[i], subef[i], subchg[i], submult[i], "valid" if subvalid[i] else "invalid")) fragid = open('fragmentid.txt', 'w') for formula in subef: fragid.write(formula + " ") fragid.write("\nBondfactor: " + str(bondfactor)) if not all(subvalid): fragid.write("\ninvalid") fragid.close() # Archive and exit tarexit()
def main(): # Get user input. args = parse_user_input() # Start timer. click() subxyz = [] subna = [] subchg = [] submult = [] subvalid = [] subefstart = [] subeffinal = [] SumFrags = [] fragfiles = [] # Pick out the files in the tarfile that have the structure "example*.sub_*.xyz" idhome = os.path.abspath('..') tar = tarfile.open(os.path.join(idhome, 'fragmentid.tar.bz2'), 'r') for tarinfo in tar: splitlist = tarinfo.name.split(".") if len(splitlist) > 2: if splitlist[2] == "xyz": subxyz.append(tarinfo.name) fragfiles.append(tarinfo) # Extract these files from the tarfile tar.extractall(members=fragfiles) tar.close() # Load files as molecules for frag in subxyz: M = Molecule(frag) M.read_comm_charge_mult() subchg.append(M.charge) submult.append(M.mult) subna.append(M.na) efstart = re.search('(?<=Molecular formula )\w+', M.comms[0]).group(0) subefstart.append(efstart) print("Running individual optimizations.") # Run individual geometry optimizations. FragE = 0.0 FragZPE = 0.0 FragEntr = 0.0 FragEnth = 0.0 for i in range(len(subxyz)): if subna[i] > 1: M = QCOptIC(subxyz[i], subchg[i], submult[i], args.method, args.basis, cycles=args.cycles, qcin='%s.opt.in' % os.path.splitext(subxyz[i])[0]) # Select frames where the energy is monotonically decreasing. M = M[monotonic_decreasing(M.qm_energies)] else: # Special case of a single atom QCSP = QChem(subxyz[i], charge=subchg[i], mult=submult[i], method=args.method, basis=args.basis, qcin='%s.sp.in' % os.path.splitext(subxyz[i])[0]) QCSP.make_stable() QCSP.jobtype = 'sp' QCSP.calculate() M = QCSP.load_qcout() # Write optimization final result to file. M = M[-1] fragoptfile = os.path.splitext(subxyz[i])[0] + ".opt.xyz" M.write(fragoptfile) QCFR = QChem(fragoptfile, charge=subchg[i], mult=submult[i], method=args.method, basis=args.basis, qcin='%s.freq.in' % os.path.splitext(fragoptfile)[0]) QCFR.freq() M = QCFR.load_qcout() # Print out new molecular formulas. # This time we should be able to use covalent radii. M.build_topology(force_bonds=True) optformula = ' '.join([m.ef() for m in M.molecules]) subeffinal.append(optformula) print(("%s.opt.xyz : formula %s; charge %i; mult %i; energy %f Ha;" "ZPE %f kcal/mol; entropy %f cal/mol.K; enthalpy %f kcal/mol" % (os.path.splitext(subxyz[i])[0], optformula, subchg[i], submult[i], M.qm_energies[0], M.qm_zpe[0], M.qm_entropy[0], M.qm_enthalpy[0]))) FragE += M.qm_energies[0] FragZPE += M.qm_zpe[0] FragEntr += M.qm_entropy[0] FragEnth += M.qm_enthalpy[0] SumFrags.append(M[0]) for fragment in SumFrags: fragment.write('fragmentopt.xyz', append=True) if subefstart != subeffinal: print("Fragments changed during optimization, calculation invalid") print("Final electronic energy (Ha) of optimized frags: % 18.10f" % FragE) print("Final ZPE (kcal/mol) of optimized frags: % 18.10f" % FragZPE) print("Final entropy (cal/mol.K) of optimized frags: % 18.10f" % FragEntr) print("Final enthalpy (kcal/mol) of optimized frags: % 18.10f" % FragEnth) nrg = open('fragmentopt.nrg', 'w') for subef in subeffinal: nrg.write(subef + " ") nrg.write("\nTotal electronic energy: %f Ha\n" % FragE) nrg.write("Total ZPE: %f kcal/mol\n" % FragZPE) nrg.write("Total entropy (STP): %f cal/mol.K\n" % FragEntr) nrg.write("Total enthalpy (STP): %f kcal/mol\n" % FragEnth) if subefstart != subeffinal: nrg.write("invalid") nrg.close() # Archive and exit. tarexit()
QC = QChem(sys.argv[1], qcout=sys.argv[2], qcdir=sys.argv[3], qcsave=True, readsave=True) # File that records how many calculations were done # for this image. calcfnm = os.path.splitext(sys.argv[1])[0] + ".num" calcnum = -1 if os.path.exists(calcfnm): calcnum = int(open(calcfnm).readlines()[0].strip()) calcnum += 1 with open(calcfnm, 'w') as f: print(calcnum, file=f) # File that records how many iterations ago we had to do a stability # analysis. "# of days since last accident" kind of thang. stabfnm = "qchem.nsb" stablast = int(open(stabfnm).readlines()[0].strip()) if os.path.exists(stabfnm) else 0 # Do stability analysis every 5 string iterations or if any calculation # needed stability corrections in the previous 30 iterations. QC.nstab = 1 if os.path.exists('Do_Stability_Analysis'): if calcnum % 10 == 0 or stablast < 30: QC.make_stable() QC.force() # If unstable, then reset accident counter to zero. with open(stabfnm, 'w') as f: if QC.nstab > 1: print(0, file=f) else: print(stablast + 1, file=f)