Beispiel #1
0
def _save_unique_conformer(ret,
                           thy_info,
                           cnf_save_fs,
                           locs,
                           saddle=False,
                           zma_locs=(0, )):
    """ Save the conformer in the filesystem
    """

    # Set the path to the conformer save filesystem
    cnf_save_path = cnf_save_fs[-1].path(locs)

    # Unpack the ret object and obtain the prog and method
    inf_obj, inp_str, out_str = ret
    prog = inf_obj.prog
    method = inf_obj.method

    # Read the energy and geom from the output
    ene = elstruct.reader.energy(prog, method, out_str)
    geo = elstruct.reader.opt_geometry(prog, out_str)
    zma = elstruct.reader.opt_zmatrix(prog, out_str)

    # Read the tra and graph
    if saddle:
        ts_min_cnf_locs, ts_min_path = filesys.mincnf.min_energy_conformer_locators(
            cnf_save_fs, thy_info)
        ts_min_zma_fs = fs.manager(ts_min_path, 'ZMATRIX')
        print('ts_min_path test:', ts_min_path)
        tra = ts_min_zma_fs[-1].file.transformation.read(zma_locs)
        print('zma_locs test:', zma_locs)
        rct_gra = ts_min_zma_fs[-1].file.reactant_graph.read(zma_locs)

    # Build the conformer filesystem and save the structural info
    print(" - Geometry is unique. Saving...")
    print(" - Save path: {}".format(cnf_save_path))
    cnf_save_fs[-1].create(locs)
    cnf_save_fs[-1].file.geometry_info.write(inf_obj, locs)
    cnf_save_fs[-1].file.geometry_input.write(inp_str, locs)
    cnf_save_fs[-1].file.energy.write(ene, locs)
    cnf_save_fs[-1].file.geometry.write(geo, locs)

    # Build the zma filesystem and save the z-matrix
    zma_save_fs = fs.manager(cnf_save_path, 'ZMATRIX')
    zma_save_fs[-1].create(zma_locs)
    zma_save_fs[-1].file.geometry_info.write(inf_obj, zma_locs)
    zma_save_fs[-1].file.geometry_input.write(inp_str, zma_locs)
    zma_save_fs[-1].file.zmatrix.write(zma, zma_locs)

    # Save the tra and gra for a saddle
    if saddle:
        zma_save_fs[-1].file.transformation.write(tra, zma_locs)
        zma_save_fs[-1].file.reactant_graph.write(rct_gra, zma_locs)

    # Saving the energy to a SP filesystem
    print(" - Saving energy of unique geometry...")
    sp_save_fs = autofile.fs.single_point(cnf_save_path)
    sp_save_fs[-1].create(thy_info[1:4])
    sp_save_fs[-1].file.input.write(inp_str, thy_info[1:4])
    sp_save_fs[-1].file.info.write(inf_obj, thy_info[1:4])
    sp_save_fs[-1].file.energy.write(ene, thy_info[1:4])
Beispiel #2
0
def add_zma_inp():
    """ Add the zma input files using geo inputs
    """
    cnf_managers = fs.iterate_managers(PFX, ['REACTION', 'THEORY', 'TRANSITION STATE'],
                                             'CONFORMER')
    for cnf_fs in cnf_managers:
        if cnf_fs is not None:
            print()
            for locs in cnf_fs[-1].existing():
                cnf_path = cnf_fs[-1].path(locs)
                # zma_fs = fs.manager(cnf_path, 'ZMATRIX')
                if cnf_fs[-1].file.geometry_input.exists(locs):
                    inp_str = cnf_fs[-1].file.geometry_input.read(locs)
                    print('FOUND INPUT')
                    print(cnf_fs[-1].path(locs))
                    break
            for locs in cnf_fs[-1].existing():
                cnf_path = cnf_fs[-1].path(locs)
                zma_fs = fs.manager(cnf_path, 'ZMATRIX')
                zma_path = zma_fs[-1].path([0])
                if not zma_fs[-1].file.geometry_input.exists([0]):
                    print('WRITING INPUT')
                    print(zma_path)
                    # zma_fs = fs.manager(cnf_path, 'ZMATRIX')
                    zma_fs[-1].file.geometry_input.write(inp_str, [0])
                else:
                    print('INPUT GOOD')
                    print(zma_path)
Beispiel #3
0
def symmetry_factor(pf_filesystems, pf_models, spc_dct_i, rotors,
                    frm_bnd_keys=(), brk_bnd_keys=()):
    """ Calculate the symmetry factor for a species
        Note: ignoring for saddle pts the possibility that two configurations
        differ only in their torsional values.
        As a result, the symmetry factor is a lower bound of the true value
    """

    if 'sym_factor' in spc_dct_i:
        sym_factor = spc_dct_i['sym_factor']
        print(' - Reading symmetry number input by user:'******'sym']

        # Obtain geometry, energy, and symmetry filesystem
        [cnf_fs, cnf_path, min_cnf_locs, _, _] = pf_filesystems['sym']
        geo = cnf_fs[-1].file.geometry.read(min_cnf_locs)

        # Obtain the external symssetry number
        ext_sym = automol.geom.external_symmetry_factor(geo)

        # Obtain the internal symmetry number using some routine
        if sym_model == 'sampling':

            # Set up the symmetry filesystem
            sym_fs = fs.manager(cnf_path, 'SYMMETRY')
            sym_geos = [geo]
            sym_geos += [sym_fs[-1].file.geometry.read(locs)
                         for locs in sym_fs[-1].existing()]

            # Obtain the internal
            if rotors:
                print(' - Determining internal sym number ',
                      'using sampling routine.')
                int_sym = int_sym_num_from_sampling(
                    sym_geos,
                    frm_bnd_keys=frm_bnd_keys,
                    brk_bnd_keys=brk_bnd_keys)
            else:
                print(' - No torsions, internal sym is 1.0')
                int_sym = 1.0

        else:
            print('No symmetry model requested, ',
                  'setting internal sym factor to 1.0')
            int_sym = 1.0

        # Obtain overall number
        sym_factor = ext_sym * int_sym

        # Reduce sym factor using rotor symmetries
        sym_factor = tors_reduced_sym_factor(sym_factor, rotors)

        # print('sym_factor test:', sym_factor)

    return sym_factor
Beispiel #4
0
def zma_fs_from_prefix(prefix, zma_idxs=(0, )):
    """ Build a zma filesys object
    """

    zma_fs = fs.manager(prefix, 'ZMATRIX')
    zma_fs[-1].create(zma_idxs)
    zma_path = zma_fs[-1].path(zma_idxs)

    return zma_fs, zma_path
Beispiel #5
0
def example2():
    """
    Example 2: Get the manager for a specific part of the file system

    """
    cnf_fs = fs.manager(PFX, [('SPECIES', ['InChI=1S/HO2/c1-2/h1H', 0, 2]),
                              ('THEORY', ['wb97xd', '6-31g*', 'U'])],
                        'CONFORMER')

    print(cnf_fs[0].path())
Beispiel #6
0
def all_rxn_bnd_keys(cnf_fs, cnf_locs, zma_locs=(0, )):
    """ get bond broken and formed keys for a transition state
    """

    cnf_path = cnf_fs[-1].path(cnf_locs)
    zma_fs = fs.manager(cnf_path, 'ZMATRIX')
    tra = zma_fs[-1].file.transformation.read(zma_locs)
    frm_bnd_keys, brk_bnd_keys = tra
    print('rxn keys')
    print(frm_bnd_keys)
    print(brk_bnd_keys)

    return frm_bnd_keys, brk_bnd_keys
Beispiel #7
0
def add_zma_trans():
    """ Add the zma input files using geo inputs
    """
    cnf_managers = fs.iterate_managers(PFX, ['REACTION', 'THEORY', 'TRANSITION STATE'],
                                             'CONFORMER')
    for cnf_fs in cnf_managers:
        if cnf_fs is not None:
            print()
            gra = None
            for locs in cnf_fs[-1].existing():
                cnf_path = cnf_fs[-1].path(locs)
                zma_fs = fs.manager(cnf_path, 'ZMATRIX')
                zma_path = zma_fs[-1].path([0])
                # if zma_fs[-1].file.transformation.exists([0]):
                #     tra = zma_fs[-1].file.transformation.read([0])
                #     print('FOUND TRA')
                #     print(zma_path)
                #     break
                if zma_fs[-1].file.reactant_graph.exists([0]):
                    gra = zma_fs[-1].file.reactant_graph.read([0])
                    print('FOUND GRAPH')
                    print(zma_fs[-1].path([0]))
                    break
            print('---')
            print()
            for locs in cnf_fs[-1].existing():
                cnf_path = cnf_fs[-1].path(locs)
                zma_fs = fs.manager(cnf_path, 'ZMATRIX')
                zma_path = zma_fs[-1].path([0])
                # if not zma_fs[-1].file.transformation.exists([0]):
                if not zma_fs[-1].file.reactant_graph.exists([0]):
                    print('WRITING GRA AT CONF')
                    print(zma_path)
                    zma_fs = fs.manager(cnf_path, 'ZMATRIX')
                    # zma_fs[-1].file.transformation.write(tra, [0])
                    zma_fs[-1].file.reactant_graph.write(gra, [0])
                else:
                    print('GRA GOOD')
                    print(zma_path)
Beispiel #8
0
def rxn_bnd_keys2(path, zma_locs=(0, )):
    """ get bond broken and formed keys for a transition state
    """

    print('zma path', path)
    zma_fs = fs.manager(path, 'ZMATRIX')
    tra = zma_fs[-1].file.transformation.read(zma_locs)
    frm_bnd_keys, brk_bnd_keys = tra
    if frm_bnd_keys:
        frm_bnd_keys = next(iter(frm_bnd_keys))
    if brk_bnd_keys:
        brk_bnd_keys = next(iter(brk_bnd_keys))

    return frm_bnd_keys, brk_bnd_keys
Beispiel #9
0
def _save_sym_indistinct_conformer(geo, cnf_save_fs, cnf_tosave_locs,
                                   cnf_saved_locs):
    """ Save a structure into the SYM directory of a conformer
    """

    # Set the path to the previously saved conformer under which
    # we will save the new conformer that shares a structure
    cnf_save_path = cnf_save_fs[-1].path(cnf_saved_locs)

    # Build the sym file sys
    sym_save_fs = fs.manager(cnf_save_path, 'SYMMETRY')
    sym_save_path = cnf_save_fs[-1].path(cnf_saved_locs)
    print(" - Saving structure in a sym directory at path {}".format(
        sym_save_path))
    sym_save_fs[-1].create(cnf_tosave_locs)
    sym_save_fs[-1].file.geometry.write(geo, cnf_tosave_locs)
#             zma_path = zma_fs[-1].path([0])
#
#             # # Now that we've written the z-matrix to the new location, we can
#             # # remove the old one
#             # zma_df.removable = True
#             # zma_df.remove(cnf_locs)

# Lastly, write the zmatrix files for the z-matrix guess
for zma_fs in itertools.chain(
        fs.iterate_managers(SAVE_PFX, ['REACTION', 'THEORY'], 'ZMATRIX')):

    if zma_fs[-1].exists([0]):
        path = zma_fs[-1].path([0])
        print(path)

        scan_fs = fs.manager(path, 'SCAN')

        scan_locs_lst = sorted(scan_fs[-1].existing())

        if scan_locs_lst:
            scan_locs = scan_locs_lst[0]
            scan_path = scan_fs[-1].path(scan_locs)
            print(scan_locs)

            zma = scan_fs[-1].file.zmatrix.read(scan_locs)

            zma_fs[-1].file.zmatrix.write(zma, [0])
            print('zmatrix written!')
        else:
            zma_fs[0].removable = True
            zma_fs[0].remove()
Beispiel #11
0
def save_saddle_point(opt_ret,
                      hess_ret,
                      freqs,
                      imags,
                      mod_thy_info,
                      cnf_save_fs,
                      ts_save_fs,
                      ts_save_path,
                      frm_bnd_keys,
                      brk_bnd_keys,
                      rcts_gra,
                      zma_locs=(0, )):
    """ Optimize the transition state structure obtained from the grid search
    """

    # Read the geom, energy, and Hessian from output
    opt_inf_obj, opt_inp_str, opt_out_str = opt_ret
    opt_prog = opt_inf_obj.prog
    opt_method = opt_inf_obj.method
    ene = elstruct.reader.energy(opt_prog, opt_method, opt_out_str)
    geo = elstruct.reader.opt_geometry(opt_prog, opt_out_str)
    zma = elstruct.reader.opt_zmatrix(opt_prog, opt_out_str)
    print('TS Geometry:')
    print(automol.geom.string(geo))
    print()

    # Build new zma using x2z and new torsion coordinates
    # zma = automol.geometry.zmatrix(
    #     geo, ts_bnd=(frm_bnd_keys, brk_bnd_keys))

    print(" - Reading hessian from output...")
    hess_inf_obj, hess_inp_str, hess_out_str = hess_ret
    hess_prog = hess_inf_obj.prog
    hess = elstruct.reader.hessian(hess_prog, hess_out_str)
    freqs = sorted([-1.0 * val for val in imags] + freqs)
    print('TS freqs: {}'.format(' '.join(str(freq) for freq in freqs)))

    # Save the information into the filesystem
    print(" - Saving...")
    print(" - Save path: {}".format(ts_save_path))

    # Save geom in the upper theory/TS layer
    ts_save_fs[0].file.geometry.write(geo)

    # Save this structure as first conformer
    locs = [autofile.schema.generate_new_conformer_id()]
    cnf_save_fs[-1].create(locs)
    cnf_save_fs[-1].file.geometry_info.write(opt_inf_obj, locs)
    cnf_save_fs[-1].file.geometry_input.write(opt_inp_str, locs)
    cnf_save_fs[-1].file.hessian_info.write(hess_inf_obj, locs)
    cnf_save_fs[-1].file.hessian_input.write(hess_inp_str, locs)
    cnf_save_fs[-1].file.energy.write(ene, locs)
    cnf_save_fs[-1].file.geometry.write(geo, locs)
    cnf_save_fs[-1].file.hessian.write(hess, locs)
    cnf_save_fs[-1].file.harmonic_frequencies.write(freqs, locs)
    cnf_save_path = cnf_save_fs[-1].path(locs)

    # Save the zmatrix information in a zma filesystem
    cnf_save_path = cnf_save_fs[-1].path(locs)
    zma_save_fs = fs.manager(cnf_save_path, 'ZMATRIX')
    zma_save_fs[-1].create(zma_locs)
    zma_save_fs[-1].file.geometry_info.write(opt_inf_obj, zma_locs)
    zma_save_fs[-1].file.geometry_input.write(opt_inp_str, zma_locs)
    zma_save_fs[-1].file.zmatrix.write(zma, zma_locs)

    # Save the form and break keys in the filesystem
    tra = (frozenset({frm_bnd_keys}), frozenset({brk_bnd_keys}))
    zma_save_fs[-1].file.transformation.write(tra, zma_locs)
    zma_save_fs[-1].file.reactant_graph.write(rcts_gra, zma_locs)

    # Save the energy in a single-point filesystem
    print(" - Saving energy...")
    sp_save_fs = autofile.fs.single_point(cnf_save_path)
    sp_save_fs[-1].create(mod_thy_info[1:4])
    sp_save_fs[-1].file.input.write(opt_inp_str, mod_thy_info[1:4])
    sp_save_fs[-1].file.info.write(opt_inf_obj, mod_thy_info[1:4])
    sp_save_fs[-1].file.energy.write(ene, mod_thy_info[1:4])
Beispiel #12
0
    enes = [cnf_fs[-1].file.energy.read(locs) for locs in locs_lst]
    geo_ene_lst = list(zip(geos, enes))

    cls_idxs_lst = (
        equivalence_class_indices(geo_ene_lst, equivalent_geometry_and_energy))

    cls_locs_lsts = [
        list(map(locs_lst.__getitem__, cls_idxs)) for cls_idxs in cls_idxs_lst]

    rep_locs_lst = list(map(conformer_rep_selector(cnf_fs), cls_locs_lsts))

    for rep_locs, cls_locs_lst in zip(rep_locs_lst, cls_locs_lsts):
        rep_path = cnf_fs[-1].path(rep_locs)
        print(rep_path)

        sym_fs = fs.manager(rep_path, 'SYMMETRY')
        print(sym_fs[0].path())

        for locs in cls_locs_lst:
            print(locs)
            geo = cnf_fs[-1].file.geometry.read(locs)

            sym_fs[-1].create(locs)
            sym_fs[-1].file.geometry.write(geo, locs)

            # WARNING!! THIS PART IS REMOVING STUFF!!
            # (Removes conformer directories that are now redundant)
            if locs != rep_locs:
                print('removing ...')
                cnf_fs[-1].removable = True
                cnf_fs[-1].remove(locs)
Beispiel #13
0
def read_hr_pot(tors_names,
                tors_grids,
                cnf_save_path,
                mod_tors_ene_info,
                ref_ene,
                constraint_dct,
                read_geom=False,
                read_grad=False,
                read_hess=False,
                read_zma=False):
    """ Get the potential for a hindered rotor
    """

    # Build initial lists for storing potential energies and Hessians
    grid_points, grid_vals = set_scan_dims(tors_grids)
    pot, geoms, grads, hessians, zmas, paths = {}, {}, {}, {}, {}, {}

    # Set up filesystem information
    zma_fs = fs.manager(cnf_save_path, 'ZMATRIX')
    zma_path = zma_fs[-1].path([0])
    if constraint_dct is None:
        scn_fs = autofile.fs.scan(zma_path)
    else:
        scn_fs = autofile.fs.cscan(zma_path)

    # Read the energies and Hessians from the filesystem
    for point, vals in zip(grid_points, grid_vals):

        locs = [tors_names, vals]
        if constraint_dct is not None:
            locs = [constraint_dct] + locs

        ene = read_tors_ene(scn_fs, locs, mod_tors_ene_info)
        if ene is not None:
            pot[point] = (ene - ref_ene) * phycon.EH2KCAL
        else:
            pot[point] = -10.0

        # print('path test in read_hr_pot:', scn_fs[-1].path(locs))
        if read_geom:
            if scn_fs[-1].file.geometry.exists(locs):
                geoms[point] = scn_fs[-1].file.geometry.read(locs)
            else:
                geoms[point] = None

        if read_grad:
            if scn_fs[-1].file.gradient.exists(locs):
                grads[point] = scn_fs[-1].file.gradient.read(locs)
            else:
                grads[point] = None

        if read_hess:
            if scn_fs[-1].file.hessian.exists(locs):
                hessians[point] = scn_fs[-1].file.hessian.read(locs)
            else:
                hessians[point] = None

        if read_zma:
            if scn_fs[-1].file.zmatrix.exists(locs):
                zmas[point] = scn_fs[-1].file.zmatrix.read(locs)
            else:
                zmas[point] = None

        paths[point] = scn_fs[-1].path(locs)

    return pot, geoms, grads, hessians, zmas, paths
Beispiel #14
0
""" Script for cycling through reactions and testing Yuri's z-matrix code on
them
"""
import automol
from autofile import fs

# PFX = './TMP/'
PFX = '/lcrc/project/PACC/AutoMech/data/save/'

RXN_FS = fs.manager(PFX, 'REACTION')

FORWARD_COUNT = 0
BACKWARD_COUNT = 0
OVERLAP_COUNT = 0
FAIL_COUNT = 0

fails = []
for rxn_locs, in fs.iterate_locators(PFX, ['REACTION']):
    # print('HERE')
    (rct_ichs, prd_ichs), _, _, _ = rxn_locs

    rct_gras = list(map(automol.inchi.graph, rct_ichs))
    prd_gras = list(map(automol.inchi.graph, prd_ichs))

    rct_gras = list(map(automol.graph.without_stereo_parities, rct_gras))
    prd_gras = list(map(automol.graph.without_stereo_parities, prd_gras))

    rct_gras = list(map(automol.graph.explicit, rct_gras))
    prd_gras = list(map(automol.graph.explicit, prd_gras))

    rct_smis = list((automol.inchi.smiles(ich) for ich in rct_ichs))
Beispiel #15
0
def _ts_geo_viable(zma, cnf_save_fs, rxn_class, mod_thy_info, zma_locs=(0, )):
    """ Perform a series of checks to assess the viability
        of a transition state geometry prior to saving
    """

    # Initialize viable
    viable = True

    # Obtain the min-ene zma and bond keys
    min_cnf_locs, cnf_save_path = filesys.mincnf.min_energy_conformer_locators(
        cnf_save_fs, mod_thy_info)
    zma_save_fs = fs.manager(cnf_save_path, 'ZMATRIX')
    ref_zma = zma_save_fs[-1].file.zmatrix.read(zma_locs)

    # Read the form and broken keys from the min conf
    # frm_bnd_keys, brk_bnd_keys = tsprep.rxn_bnd_keys(
    frm_bnd_keys, brk_bnd_keys = tsprep.all_rxn_bnd_keys(cnf_save_fs,
                                                         min_cnf_locs,
                                                         zma_locs=zma_locs)

    # Use the idxs to set the forming and breaking bond names
    #    if frm_bnd_keys:
    #      frm_name = automol.zmatrix.bond_key_from_idxs(
    #           zma, frm_bnd_keys)
    #        ts_bnd1, ts_bnd2 = min(frm_bnd_keys), max(frm_bnd_keys)
    #    else:
    #      frm_name = ''
    #        ts_bnd1, ts_bnd2 = None, None

    # if brk_bnd_keys:
    #  brk_name = automol.zmatrix.bond_key_from_idxs(
    #      zma, brk_bnd_keys)
    # else:
    #  brk_name = ''
    # print('frm_name', frm_name)
    # print('brk_name', brk_name)

    # Calculate the distance of bond being formed
    # cnf_dct = automol.zmatrix.values(zma)
    # ref_dct = automol.zmatrix.values(ref_zma)
    cnf_geo = automol.zmatrix.geometry(zma)
    ref_geo = automol.zmatrix.geometry(ref_zma)

    cnf_dist_lst = []
    ref_dist_lst = []
    bnd_key_lst = []
    cnf_ang_lst = []
    ref_ang_lst = []
    for frm_bnd_key in frm_bnd_keys:
        print('frm_bnd_key test:', frm_bnd_key)
        frm_idx1, frm_idx2 = list(frm_bnd_key)
        cnf_dist = automol.geom.distance(cnf_geo, frm_idx1, frm_idx2)
        ref_dist = automol.geom.distance(ref_geo, frm_idx1, frm_idx2)
        cnf_dist_lst.append(cnf_dist)
        ref_dist_lst.append(ref_dist)
        bnd_key_lst.append(frm_bnd_key)

    for brk_bnd_key in brk_bnd_keys:
        brk_idx1, brk_idx2 = list(brk_bnd_key)
        cnf_dist = automol.geom.distance(cnf_geo, brk_idx1, brk_idx2)
        ref_dist = automol.geom.distance(ref_geo, brk_idx1, brk_idx2)
        cnf_dist_lst.append(cnf_dist)
        ref_dist_lst.append(ref_dist)
        bnd_key_lst.append(brk_bnd_key)

    for frm_bnd_key in frm_bnd_keys:
        for brk_bnd_key in brk_bnd_keys:
            for frm_idx in frm_bnd_key:
                for brk_idx in brk_bnd_key:
                    if frm_idx == brk_idx:
                        idx2 = frm_idx
                        idx1 = list(frm_bnd_key - frozenset({idx2}))[0]
                        idx3 = list(brk_bnd_key - frozenset({idx2}))[0]
                        cnf_ang = automol.geom.central_angle(
                            cnf_geo, idx1, idx2, idx3)
                        ref_ang = automol.geom.central_angle(
                            ref_geo, idx1, idx2, idx3)
                        cnf_ang_lst.append(cnf_ang)
                        ref_ang_lst.append(ref_ang)

    #      cnf_dist = cnf_dct.get(frm_name, None)
    #      ref_dist = ref_dct.get(frm_name, None)
    #  if cnf_dist is None:
    #      cnf_dist = cnf_dct.get(brk_name, None)
    #  if ref_dist is None:
    #      ref_dist = ref_dct.get(brk_name, None)
    print('bnd_key_list', bnd_key_lst)
    print('conf_dist', cnf_dist_lst)
    print('ref_dist', ref_dist_lst)
    print('conf_angle', cnf_ang_lst)
    print('ref_angle', ref_ang_lst)

    #  # Calculate the central angle of reacting moiety of zma
    #  cnf_angle = geomprep.calc_rxn_angle(
    #      zma, frm_bnd_keys, brk_bnd_keys, rxn_class)
    #  ref_angle = geomprep.calc_rxn_angle(
    #      ref_zma, frm_bnd_keys, brk_bnd_keys, rxn_class)
    #  print('conf_angle', cnf_angle)
    #  print('ref_angle', ref_angle)

    # Set the maximum allowed displacement for a TS conformer
    max_disp = 0.6
    # would be better to check for bond forming length in bond scission with ring forming
    if 'addition' in rxn_class:
        max_disp = 0.8
    if 'abstraction' in rxn_class:
        # this was 1.4 - SJK reduced it to work for some OH abstractions
        max_disp = 1.0

    # Check forming bond angle similar to ini config
    if 'elimination' not in rxn_class:
        for ref_angle, cnf_angle in zip(ref_ang_lst, cnf_ang_lst):
            if abs(cnf_angle - ref_angle) > .44:
                print(
                    " - Transition State conformer has",
                    "diverged from original structure of",
                    "angle {:.3f} with angle {:.3f}".format(
                        ref_angle, cnf_angle))
                viable = False

    symbols = automol.geom.symbols(cnf_geo)
    lst_info = zip(ref_dist_lst, cnf_dist_lst, bnd_key_lst)
    for ref_dist, cnf_dist, bnd_key in lst_info:
        if 'add' in rxn_class or 'abst' in rxn_class:
            bnd_key1, bnd_key2 = min(list(bnd_key)), max(list(bnd_key))
            symb1 = symbols[bnd_key1]
            symb2 = symbols[bnd_key2]

            if bnd_key in frm_bnd_keys:
                # Check if radical atom is closer to some atom
                # other than the bonding atom
                cls = geomprep.is_atom_closest_to_bond_atom(
                    zma, bnd_key2, cnf_dist)
                if not cls:
                    print(
                        " - Transition State conformer has",
                        "diverged from original structure of",
                        "dist {:.3f} with dist {:.3f}".format(
                            ref_dist, cnf_dist))
                    print(' - Radical atom now has a new nearest neighbor')
                    viable = False
                # check forming bond distance
                if abs(cnf_dist - ref_dist) > max_disp:
                    print(
                        " - Transition State conformer has",
                        "diverged from original structure of",
                        "dist {:.3f} with dist {:.3f}".format(
                            ref_dist, cnf_dist))
                    viable = False

            # Check distance relative to equi. bond
            if (symb1, symb2) in bnd.LEN_DCT:
                equi_bnd = bnd.LEN_DCT[(symb1, symb2)]
            elif (symb2, symb1) in bnd.LEN_DCT:
                equi_bnd = bnd.LEN_DCT[(symb2, symb1)]
            else:
                equi_bnd = 0.0
            displace_from_equi = cnf_dist - equi_bnd
            dchk1 = abs(cnf_dist - ref_dist) > 0.1
            dchk2 = displace_from_equi < 0.2
            if dchk1 and dchk2:
                print(
                    " - Transition State conformer has", "converged to an",
                    "equilibrium structure with dist",
                    " {:.3f} comp with equil {:.3f}".format(
                        cnf_dist, equi_bnd))
                viable = False
        else:
            # check forming/breaking bond distance
            # if abs(cnf_dist - ref_dist) > 0.4:
            # max disp of 0.4 causes problems for bond scission with ring forming
            # not sure if setting it to 0.3 will cause problems for other cases
            if abs(cnf_dist - ref_dist) > 0.3:
                print(
                    " - Transition State conformer has",
                    "diverged from original structure of",
                    "dist {:.3f} with dist {:.3f}".format(ref_dist, cnf_dist))
                viable = False

    return viable