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()
Example #4
0
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()
Example #5
0
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)