Example #1
0
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
Example #3
0
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()
    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()