def main(): # Get user input. args = parse_user_input() if len(args.methods) > 2: logger.error("Unsure what to do with >2 electronic structure methods") raise RuntimeError # Delete the result from previous jobs _exec("rm -rf ts_result.tar.bz2", print_command=False) # Perform transition state search. # First run the TS-calculation with the smaller basis set QCTS1 = QChemTS(args.tsest, charge=args.charge, mult=args.mult, method=args.methods[0], basis=args.bases[0], finalize=(len(args.methods) == 1), qcin='qcts1.in', vout='irc_transition.vib') QCTS1.write('ts1.xyz') if len(args.methods) == 2: print(' --== \x1b[1;92mUpgrading\x1b[0m ==--') QCTS2 = QChemTS("ts1.xyz", charge=args.charge, mult=args.mult, method=args.methods[1], basis=args.bases[1], finalize=True, qcin='qcts2.in', vout='irc_transition.vib') QCTS2.write('ts2.xyz') qcdir = QCTS2.qcdir shutil.copy2('ts2.xyz', 'ts.xyz') else: qcdir = QCTS1.qcdir shutil.copy2('ts1.xyz', 'ts.xyz') # Intrinsic reaction coordinate calculation. print("Intrinsic reaction coordinate..") # Process and save IRC results. M_IRC, E_IRC = QChemIRC("ts.xyz", charge=args.charge, mult=args.mult, method=args.methods[-1], basis=args.bases[-1], qcdir=qcdir, xyz0=args.initpath) M_IRC.write("irc.xyz") M_IRC.get_populations().write('irc.pop', ftype='xyz') # Save the IRC energy as a function of arc length. ArcMol = arc(M_IRC, RMSD=True) ArcMolCumul = np.insert(np.cumsum(ArcMol), 0, 0.0) np.savetxt("irc.nrg", np.hstack((ArcMolCumul.reshape(-1, 1), E_IRC.reshape(-1, 1))), fmt="% 14.6f", header="Arclength(Ang) Energy(kcal/mol)") # Create IRC with equally spaced structures. M_IRC_EV = SpaceIRC(M_IRC, E_IRC, RMSD=True) M_IRC_EV.write("irc_spaced.xyz") # Run two final single point calculations with SCF_FINAL_PRINT set to 1 M_IRC[0].write("irc_reactant.xyz") M_IRC[-1].write("irc_product.xyz") QCR = QChem("irc_reactant.xyz", charge=args.charge, mult=args.mult, method=args.methods[-1], basis=args.bases[-1]) QCP = QChem("irc_product.xyz", charge=args.charge, mult=args.mult, method=args.methods[-1], basis=args.bases[-1]) shutil.copy2("ts.xyz", "irc_transition.xyz") QCT = QChem("irc_transition.xyz", charge=args.charge, mult=args.mult, method=args.methods[-1], basis=args.bases[-1]) def FinalSCF(SP): SP.make_stable() SP.jobtype = 'sp' SP.remextra = OrderedDict([('scf_final_print', '1')]) SP.calculate() FinalSCF(QCR) FinalSCF(QCP) FinalSCF(QCT) np.savetxt("irc_reactant.bnd", QCR.load_qcout().qm_bondorder, fmt="%8.3f") np.savetxt("irc_product.bnd", QCP.load_qcout().qm_bondorder, fmt="%8.3f") np.savetxt("irc_transition.bnd", QCT.load_qcout().qm_bondorder, fmt="%8.3f") # Calculate ZPEs, entropy, enthalpy for Delta-G calcs # Should be able to take out freq calcs of R and P once we get can confidently get rid of this section. QCR.remextra = OrderedDict() QCP.remextra = OrderedDict() QCT.remextra = OrderedDict() QCR.freq() R = QCR.load_qcout() QCP.freq() P = QCP.load_qcout() QCT.freq() T = QCT.load_qcout() nrgfile = open('deltaG.nrg', 'w') deltaH = P.qm_energies[0] * Ha_to_kcalmol + P.qm_zpe[ 0] - R.qm_energies[0] * Ha_to_kcalmol - R.qm_zpe[0] deltaG = deltaH - P.qm_entropy[0] * 0.29815 + P.qm_enthalpy[ 0] + R.qm_entropy[0] * 0.29815 - R.qm_enthalpy[0] Ha = T.qm_energies[0] * Ha_to_kcalmol + T.qm_zpe[ 0] - R.qm_energies[0] * Ha_to_kcalmol - R.qm_zpe[0] Ga = Ha - T.qm_entropy[0] * 0.29815 + T.qm_enthalpy[ 0] + R.qm_entropy[0] * 0.29815 - R.qm_enthalpy[0] nrgfile.write( "=> ** The following data is referenced to reactant and product complexes **\n" ) nrgfile.write( "=> ** WARNING! Data may not be accurate in cases with >1 molecule **\n" ) nrgfile.write( "=> ** Activation enthalpy H_a (0K) = %.4f kcal/mol **\n" % Ha) nrgfile.write( "=> ** Activation Gibbs energy G_a (STP) = %.4f kcal/mol **\n" % Ga) nrgfile.write( "=> ** Delta-H(0K) = %.4f kcal/mol **\n" % deltaH) nrgfile.write( "=> ** Delta-G(STP) = %.4f kcal/mol **\n" % deltaG) # Calculate Delta-G's based on fragment information from reactant and product # Get data from fragment nrg files if args.fragpath == None: fragpath = os.path.abspath('../../../../../fragments') else: fragpath = args.fragpath formulas = [] nrg = [] zpe = [] entr = [] enth = [] validity = [] for frm in os.listdir(fragpath): optdir = os.path.join(fragpath, frm, "opt") if os.path.exists(os.path.join(optdir, 'fragmentopt.nrg')): fragnrgfile = open(os.path.join(optdir, 'fragmentopt.nrg')) formulas.append(fragnrgfile.readline().strip()) nrg.append(float(fragnrgfile.readline().split()[3])) zpe.append(float(fragnrgfile.readline().split()[2])) entr.append(float(fragnrgfile.readline().split()[3])) enth.append(float(fragnrgfile.readline().split()[3])) validity.append(fragnrgfile.readline().strip()) fragnrgfile.close() # Compare list of molecules to choose right energy formulasR = [] formulasP = [] nrgR = 0.0 nrgP = 0.0 R.build_topology() for subg in R.molecules: formulasR.append(subg.ef()) formulasR = sorted(formulasR) P.build_topology() for subg in P.molecules: formulasP.append(subg.ef()) formulasP = sorted(formulasP) for i in range(len(formulas)): formlist = sorted(formulas[i].split()) if formlist == formulasR and validity[i] != "invalid": nrgR = nrg[i] zpeR = zpe[i] entrR = entr[i] enthR = enth[i] if formlist == formulasP and validity[i] != "invalid": nrgP = nrg[i] zpeP = zpe[i] entrP = entr[i] enthP = enth[i] # Calculate energetics if nrgR != 0.0: Ha = T.qm_energies[0] * Ha_to_kcalmol + T.qm_zpe[ 0] - nrgR * Ha_to_kcalmol - zpeR Ga = Ha - T.qm_entropy[0] * 0.29815 + T.qm_enthalpy[ 0] + entrR * 0.29815 - enthR nrgfile.write( "=> ## The following data is calculated referenced to isolated reactant and product molecules:\n" ) nrgfile.write( "=> ## Activation enthalpy H_a (0K) = %.4f kcal/mol ##\n" % Ha) nrgfile.write( "=> ## Activation Gibbs energy G_a (STP) = %.4f kcal/mol ##\n" % Ga) else: nrgfile.write( "=> Reactant state could not be identified among fragment calculations\n" ) nrgfile.write( "=> No energetics referenced to isolated molecules will be calculated for this pathway\n" ) if nrgR != 0.0 and nrgP != 0.0: deltaH = nrgP * Ha_to_kcalmol + zpeP - nrgR * Ha_to_kcalmol - zpeR deltaG = deltaH - entrP * 0.29815 + enthP + entrR * 0.29815 - enthR nrgfile.write( "=> ## Delta-H(0K) = %.4f kcal/mol **\n" % deltaH) nrgfile.write( "=> ## Delta-G(STP) = %.4f kcal/mol **\n" % deltaG) elif nrgP == 0.0: nrgfile.write( "=> Product state could not be identified among fragment calculations\n" ) nrgfile.write( "=> No reaction energies referenced to isolated molecules will be calculated for this pathway\n" ) nrgfile.close() print("\x1b[1;92mIRC Success!\x1b[0m") 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()