def insertion(rct_zmas, prd_zmas, tras): """ z-matrix for an insertion reaction """ ret = {} dist_name = 'rts' dist_val = 3. tra = tras[0] frm_bnd_keys, _ = automol.graph.trans.formed_bond_keys(tra) # get the atom on react 1 that is being attacked (bond is forming) rct1_atm1_key = list(frm_bnd_keys)[0] # figure out atoms in the chain to define the dummy atom _, rct2_gra = map(rct_gras.__getitem__, rct_idxs) rct1_zma, rct2_zma = map(rct_zmas.__getitem__, rct_idxs) rct1_natms = automol.zmatrix.count(rct1_zma) rct2_natms = automol.zmatrix.count(rct2_zma) rct1_atm2_key, rct1_atm3_key, _ = join_atom_keys(rct1_zma, rct1_atm1_key) # Join the reactant zmas to build the TS zma x_atm_key = rct1_natms rct1_x_zma = rct1_x_join(rct1_zma, rct1_atm1_key, rct1_atm2_key, rct1_atm3_key) ts_zma = rct1x_rct2_join(rct1_x_zma, rct2_zma, dist_name, dist_val, rct1_atm1_key, x_atm_key, rct1_atm2_key, join_vals=(85., 85., 170., 85., 170.)) ts_name_dct = automol.zmatrix.standard_names(ts_zma) dist_name = ts_name_dct[dist_name] ts_zma = automol.zmatrix.standard_form(ts_zma) # Generate constraints # tors_keys = constbuild.bimol() # CHECK IF THE INSERTION MESSES WITH THE TORSION ASSIGNMENTS # Shift the TS bond keys frm_bnd_keys = shift_vals_from_dummy(frm_bnd_keys, ts_zma) brk_bnd_keys = shift_vals_from_dummy(brk_bnd_keys, ts_zma) ret = { 'ts_zma': ts_zma, 'bnd_keys': (frm_bnd_keys, brk_bnd_keys), 'const_keys': (frozenset({}), frozenset({}), frozenset({})) } return ret
def beta_scission(rct_zmas, prd_zmas, tras): """ z-matrix for a beta-scission reaction """ # Obtain frm and brk keys from arbtrary tras tra = tras[0] brk_bnd_keys, = automol.graph.trans.broken_bond_keys(tra) _ = prd_zmas # Unneeded # Obtain the TS ZMA ts_zma, = rct_zmas # wrong since rct_zmas is a lst ts_zma = automol.zmatrix.standard_form(ts_zma) brk_bnd_keys = shift_vals_from_dummy(brk_bnd_keys, ts_zma) ret = { 'ts_zma': ts_zma, 'bnd_keys': (frozenset({}), brk_bnd_keys), 'const_keys': (frozenset({}), frozenset({}), frozenset({})) } return ret
def substitution(rct_zmas, prd_zmas, tras): """ z-matrix for a substitution reaction Presume that radical substitutions at a pi bond occur instead as a sequence of addition and elimination. Also, for now presume that we are only interested in radical molecule substitutions """ ret = None # Set the name and value for the bond being formed dist_name = 'rts' dist_val = 3. # first determine if this is a radical molecule reaction and then # if the radical is the first species # reorder to put it second rad_cnt = 0 mol_cnt = 0 for idx, rct_zma in enumerate(rct_zmas): rad_keys = automol.graph.resonance_dominant_radical_atom_keys( automol.geom.graph(automol.zmatrix.geometry(rct_zma))) ich = automol.geom.inchi(automol.zmatrix.geometry(rct_zma)) is_co = (ich == 'InChI=1S/CO/c1-2') if rad_keys and not is_co: rad_idx = idx rad_cnt += 1 else: # mol_idx = idx mol_cnt += 1 # prolly should try the rearranging earlier # if rad_cnt == 1 and mol_cnt == 1: # if rad_idx == 0: # rct2_zma, rct1_zma = rct_zmas # rct_zmas = [rct1_zma, rct2_zma] # # Confirm the reaction type and build the appropriate Z-Matrix # rct2_gra = automol.zmatrix.graph(rct_zmas[1], remove_stereo=True) # rad_atm_keys = automol.graph.resonance_dominant_radical_atom_keys( # rct2_gra) # if 0 not in rad_atm_keys: # rct_zmas[1] = reorder_zma_for_radicals( # rct_zmas[1], min(rad_atm_keys)) # rct2_gra = automol.zmatrix.graph(rct_zmas[1], remove_stereo=True) # rad_atm_keys = automol.graph.resonance_dominant_radical_atom_keys( # rct2_gra) # # following assert checks to ensure that # # the first atom in the second reactant is a radical # # this is required for the remainder of the routine # assert 0 in rad_atm_keys # rct_zmas, rct_gras = shifted_standard_zmas_graphs( # rct_zmas, remove_stereo=True) # prd_zmas, prd_gras = shifted_standard_zmas_graphs( # prd_zmas, remove_stereo=True) # rcts_gra = functools.reduce(automol.graph.union, rct_gras) # prds_gra = functools.reduce(automol.graph.union, prd_gras) # tras, rct_idxs, _ = automol.graph.reac.substitution(rcts_gra, prds_gra) tra = tras[0] frm_bnd_keys, = automol.graph.trans.formed_bond_keys(tra) brk_bnd_keys, = automol.graph.trans.broken_bond_keys(tra) rct1_zma, rct2_zma = rct_zmas # get the atom on react 1 that is being attacked (bond is forming) rct1_atm1_key = list(frm_bnd_keys)[0] # rct1_zma, rct2_zma = map(rct_zmas.__getitem__, rct_idxs) # _, rct2_gra = map(rct_gras.__getitem__, rct_idxs) rct1_natms = automol.zmatrix.count(rct1_zma) rct2_natms = automol.zmatrix.count(rct2_zma) # figure out atoms in the chain to define the dummy atom rct1_atm2_key, rct1_atm3_key, _ = join_atom_keys(rct1_zma, rct1_atm1_key) # Join the reactant zmas to build the TS zma x_atm_key = rct1_natms rct1_x_zma = rct1_x_join(rct1_zma, rct1_atm1_key, rct1_atm2_key, rct1_atm3_key) ts_zma = rct1x_rct2_join(rct1_x_zma, rct2_zma, dist_name, dist_val, rct1_atm1_key, x_atm_key, rct1_atm2_key, join_vals=(85., 85., 170., 85., 85.)) # Get the names of the coordinates of the breaking and forming bond ts_name_dct = automol.zmatrix.standard_names(ts_zma) form_dist_name = ts_name_dct[dist_name] # Get the torsional coordinates of the transition state ts_zma = automol.zmatrix.standard_form(ts_zma) # tors_keys = constbuild.bimol() # Shift the TS bond keys frm_bnd_keys = shift_vals_from_dummy(frm_bnd_keys, ts_zma) brk_bnd_keys = shift_vals_from_dummy(brk_bnd_keys, ts_zma) ret = { 'ts_zma': ts_zma, 'bnd_keys': (frm_bnd_keys, brk_bnd_keys), 'const_keys': (frozenset({}), frozenset({}), frozenset({})) } return ret
def _hydrogen_abstraction(rct_zmas, prd_zmas, tras): """ standard hydrogen abstraction """ ret = None dist_name = 'rts' dist_val = 3. # Deal with nasty cases which ruin the ordering rct2_gra = automol.zmatrix.graph(rct_zmas[1], remove_stereo=True) rad_atm_keys = automol.graph.resonance_dominant_radical_atom_keys(rct2_gra) # fix for O2 which is recognized as a radical # in the long run it would be better to put then in the # resonance_dominant_radical_atom_keys function if not rad_atm_keys: ich = automol.graph.inchi(rct2_gra) if ich == 'InChI=1S/O2/c1-2': rad_atm_keys = [0] return None # hno2 hack # rad_atm_keys = [0] if 0 not in rad_atm_keys: rct_zmas[1] = reorder_zma_for_radicals(rct_zmas[1], min(rad_atm_keys)) rct2_gra = automol.zmatrix.graph(rct_zmas[1], remove_stereo=True) rad_atm_keys = automol.graph.resonance_dominant_radical_atom_keys( rct2_gra) # following assert checks to ensure that the first atom # in the second reactant is a radical # this is required for the remainder of the routine assert 0 in rad_atm_keys # Shift Graph now? rct_zmas, rct_gras = shifted_standard_zmas_graphs(rct_zmas, remove_stereo=True) prd_zmas, prd_gras = shifted_standard_zmas_graphs(prd_zmas, remove_stereo=True) # fix to put radical atom first # ultimately need to fix this for multiple radical centers # end of fix tra = tras[0] rct1_gra, rct2_gra = rct_gras rct1_zma, rct2_zma = rct_zmas rct1_natms = automol.zmatrix.count(rct1_zma) frm_bnd_keys, = automol.graph.trans.formed_bond_keys(tra) brk_bnd_keys, = automol.graph.trans.broken_bond_keys(tra) rct2_atm1_key = _xor(frm_bnd_keys, brk_bnd_keys) if not rct2_atm1_key == rct1_natms: rct2_gra = automol.graph.move_idx_to_top(rct2_gra, rct2_atm1_key, rct1_natms) rct2_zma = automol.geom.zmatrix(automol.graph.geometry(rct2_gra)) rct_zmas = [rct1_zma, rct2_zma] rct_zmas, _ = shifted_standard_zmas_graphs(rct_zmas, remove_stereo=True) _, rct2_zma = rct_zmas new_bnd_key = [] for key in frm_bnd_keys: if key == rct2_atm1_key: key = rct1_natms new_bnd_key.append(key) frm_bnd_keys = frozenset(new_bnd_key) rct_gras = (rct1_gra, rct2_gra) rct1_atm1_key = next(iter(frm_bnd_keys & brk_bnd_keys)) # if rct1 and rct2 are isomorphic, we may get an atom key on rct2. # in that case, determine the equivalent atom from rct1 if rct1_atm1_key in automol.graph.atom_keys(rct2_gra): atm_key_dct = automol.graph.full_isomorphism(rct2_gra, rct1_gra) assert atm_key_dct rct1_atm1_key = atm_key_dct[rct1_atm1_key] rct1_atm2_key, rct1_atm3_key, _ = join_atom_keys(rct1_zma, rct1_atm1_key) # Join the reactant zmas to build the TS zma x_atm_key = rct1_natms rct1_x_zma = rct1_x_join(rct1_zma, rct1_atm1_key, rct1_atm2_key, rct1_atm3_key) ts_zma = rct1x_rct2_join(rct1_x_zma, rct2_zma, dist_name, dist_val, rct1_atm1_key, x_atm_key, rct1_atm2_key, join_vals=(85., 85., 170., 85., 170.)) # Standardize the ZMA ts_zma = automol.zmatrix.standard_form(ts_zma) # Generate constraints # tors_keys = constbuild.bimol() # Shift the TS bond keys frm_bnd_keys = shift_vals_from_dummy(frm_bnd_keys, ts_zma) brk_bnd_keys = shift_vals_from_dummy(brk_bnd_keys, ts_zma) ret = { 'ts_zma': ts_zma, 'bnd_keys': (frm_bnd_keys, brk_bnd_keys), 'const_keys': (frozenset({}), frozenset({}), frozenset({})) } return ret
def _sigma_hydrogen_abstraction(rct_zmas, prd_zmas): print('323543534343422') ret = None dist_name = 'rts' dist_val = 3. # in the future, we can get the rxn_idxs directly from # graph.reac.hydrogen_abstraction, because it returns them now rxn_idxs = automol.formula.reac.argsort_hydrogen_abstraction( list(map(automol.convert.zmatrix.formula, rct_zmas)), list(map(automol.convert.zmatrix.formula, prd_zmas))) if rxn_idxs is not None: rct_idxs, prd_idxs = rxn_idxs rct_zmas = list(map(rct_zmas.__getitem__, rct_idxs)) prd_zmas = list(map(prd_zmas.__getitem__, prd_idxs)) rct_zmas, rct_gras = shifted_standard_zmas_graphs(rct_zmas, remove_stereo=True) prd_zmas, prd_gras = shifted_standard_zmas_graphs(prd_zmas, remove_stereo=True) tras, _, _ = automol.graph.reac.hydrogen_abstraction( rct_gras, prd_gras) if tras: tra = tras[0] rct1_gra, rct2_gra = rct_gras rct1_zma, rct2_zma = rct_zmas rct1_natms = automol.zmatrix.count(rct1_zma) rct2_natms = automol.zmatrix.count(rct2_zma) frm_bnd_keys, = automol.graph.trans.formed_bond_keys(tra) brk_bnd_keys, = automol.graph.trans.broken_bond_keys(tra) rct1_atm1_key = next(iter(frm_bnd_keys & brk_bnd_keys)) rct2_atm1_key = next(iter(frm_bnd_keys - brk_bnd_keys)) # if rct1 and rct2 are isomorphic, we may get an atom key on rct2. # in that case, determine the equivalent atom from rct1 if rct1_atm1_key in automol.graph.atom_keys(rct2_gra): atm_key_dct = automol.graph.full_isomorphism( rct2_gra, rct1_gra) assert atm_key_dct rct1_atm1_key = atm_key_dct[rct1_atm1_key] rct1_atm2_key, rct1_atm3_key, _ = join_atom_keys( rct1_zma, rct1_atm1_key) x_zma = ((('X', (None, None, None), (None, None, None)), ), {}) x_join_val_dct = { 'rx': 1. * qcc.conversion_factor('angstrom', 'bohr'), 'ax': 90. * qcc.conversion_factor('degree', 'radian'), 'dx': 180. * qcc.conversion_factor('degree', 'radian'), } x_join_keys = numpy.array( [[rct1_atm1_key, rct1_atm2_key, rct1_atm3_key]]) x_join_names = numpy.array([['rx', 'ax', 'dx']], dtype=numpy.object_) x_join_names[numpy.equal(x_join_keys, None)] = None x_join_name_set = set(numpy.ravel(x_join_names)) - {None} x_join_val_dct = { name: x_join_val_dct[name] for name in x_join_name_set } rct1_x_zma = automol.zmatrix.join(rct1_zma, x_zma, x_join_keys, x_join_names, x_join_val_dct) rct1_x_atm_key = rct1_natms if rct2_atm1_key in automol.graph.atom_keys(rct1_gra): atm_key_dct = automol.graph.full_isomorphism( rct1_gra, rct2_gra) assert atm_key_dct rct2_atm1_key = atm_key_dct[rct2_atm1_key] rct2_atm1_key -= rct1_natms assert rct2_atm1_key == 0 # insert dummy atom as the second atom in reactant 2 insert_keys = numpy.array([[0, None, None], [None, 1, None], [None, None, 2]])[:rct2_natms] insert_names = numpy.array([['rx2', None, None], [None, 'ax2', None], [None, None, 'dx2']])[:rct2_natms] insert_val_dct = { 'rx2': 1. * qcc.conversion_factor('angstrom', 'bohr'), 'ax2': 90. * qcc.conversion_factor('degree', 'radian'), 'dx2': 180. * qcc.conversion_factor('degree', 'radian'), } insert_name_set = set(numpy.ravel(insert_names)) - {None} insert_val_dct = { name: insert_val_dct[name] for name in insert_name_set } rct2_x_zma = automol.zmatrix.insert_dummy_atom( rct2_zma, 1, insert_keys, insert_names, insert_val_dct) join_val_dct = { dist_name: dist_val, 'aabs1': 85. * qcc.conversion_factor('degree', 'radian'), 'aabs2': 85. * qcc.conversion_factor('degree', 'radian'), 'babs1': 170. * qcc.conversion_factor('degree', 'radian'), 'babs2': 85. * qcc.conversion_factor('degree', 'radian'), 'babs3': 170. * qcc.conversion_factor('degree', 'radian'), } join_keys = numpy.array( [[rct1_atm1_key, rct1_x_atm_key, rct1_atm2_key], [None, rct1_atm1_key, rct1_x_atm_key], [None, None, rct1_atm1_key]])[:rct2_natms + 1] join_names = numpy.array([[dist_name, 'aabs1', 'babs1'], [None, 'aabs2', 'babs2'], [None, None, 'babs3']])[:rct2_natms + 1] join_names[numpy.equal(join_keys, None)] = None join_name_set = set(numpy.ravel(join_names)) - {None} join_val_dct = {name: join_val_dct[name] for name in join_name_set} ts_zma = automol.zmatrix.join(rct1_x_zma, rct2_x_zma, join_keys, join_names, join_val_dct) ts_name_dct = automol.zmatrix.standard_names(ts_zma) dist_name = ts_name_dct[dist_name] ts_zma = automol.zmatrix.standard_form(ts_zma) rct1_tors_names = automol.zmatrix.torsion_coordinate_names( rct1_zma) rct2_tors_names = automol.zmatrix.torsion_coordinate_names( rct2_zma) tors_names = ( tuple(map(ts_name_dct.__getitem__, rct1_tors_names)) + tuple(map(ts_name_dct.__getitem__, rct2_tors_names))) if 'babs2' in ts_name_dct: geo1 = automol.convert.zmatrix.geometry(rct1_zma) if not automol.geom.is_linear(geo1): tors_name = ts_name_dct['babs2'] tors_names += (tors_name, ) # babs3 should only be included if there is only group # connected to the radical atom include = include_babs3(frm_bnd_keys, rct2_gra) if 'babs3' in ts_name_dct and include: tors_name = ts_name_dct['babs3'] tors_names += (tors_name, ) frm_bnd_keys = shift_vals_from_dummy(frm_bnd_keys, ts_zma) brk_bnd_keys = shift_vals_from_dummy(brk_bnd_keys, ts_zma) # Build reactants graph atom_keys2 = automol.graph.atom_keys(rct2_gra) natom2 = len(atom_keys2) atm_key_dct = dict( zip( atom_keys2, (key + natom2 for key in atom_keys2), )) new_rct2_gra = automol.graph.relabel(rct2_gra, atm_key_dct) rcts_gra = automol.graph.union_from_sequence( (rct1_gra, new_rct2_gra)) ret = (ts_zma, dist_name, frm_bnd_keys, brk_bnd_keys, tors_names, rcts_gra) return ret
def addition(rct_zmas, prd_zmas, tras): """ z-matrix for an addition reaction """ dist_name = 'rts' dist_val = 3. # Old sort procedure (maybe move?) count1 = automol.zmatrix.count(rct_zmas[0]) if len(rct_zmas) == 2: count2 = automol.zmatrix.count(rct_zmas[1]) if count1 == 1 or count1 < count2: rct2_zma, rct1_zma = rct_zmas rct_zmas = [rct1_zma, rct2_zma] rct1_zma, rct2_zma = rct_zmas rct1_gra = automol.zmatrix.graph(rct1_zma) rct2_gra = automol.zmatrix.graph(rct2_zma) rct2_natms = automol.zmatrix.count(rct2_zma) rct1_natms = automol.zmatrix.count(rct1_zma) tra = tras[0] frm_bnd_keyss, = automol.graph.trans.formed_bond_keys(tra) rct1_atm1_key, rct2_atm_key = sorted(frm_bnd_keyss) # Shift rct2_zma so that it's forming site is the first atom if rct2_atm_key != rct1_natms: rct2_geo = automol.zmatrix.geometry(rct2_zma) rct2_geo = automol.geom.swap_coordinates(rct2_geo, rct2_atm_key - rct1_natms, 0) rct2_zma = automol.geom.zmatrix(rct2_geo) rct_zmas, rct_gras = shifted_standard_zmas_graphs([rct1_zma, rct2_zma], remove_stereo=True) _, rct2_zma = rct_zmas rct2_atm_key = rct1_natms frm_bnd_keys = frozenset({rct1_atm1_key, rct2_atm_key}) # Replace old routine with new one based on unsaturated atoms # Start of new routine rct1_unsat_keys = automol.graph.unsaturated_atom_keys(rct1_gra) # get neighbor keys for rct1_atm1_key neighbor_dct = automol.graph.atom_neighbor_keys(rct1_gra) atm1_nghbr_keys = neighbor_dct[rct1_atm1_key] # shift keys for unsaturated atoms and for atm1_nghbr keys # to include dummy atoms # second atom key # choose rct1_atm2 as first unsaturated neighbor to rct1_atm1 rct1_atm2_key = None for key in atm1_nghbr_keys: if key in rct1_unsat_keys: rct1_atm2_key = key break # if no unsaturated neighbor, choose any atm1_nghbr if rct1_atm2_key is None: for key in atm1_nghbr_keys: rct1_atm2_key = key break # third atom key # if atm1 has two neighbors choose third atom key as second neighbor rct1_atm3_key = [] for key in atm1_nghbr_keys: if key != rct1_atm2_key: rct1_atm3_key = key break # else choose it as second neighbor to atm 2 if not rct1_atm3_key: atm2_nghbr_keys = neighbor_dct[rct1_atm2_key] for key in atm2_nghbr_keys: if key != rct1_atm1_key: rct1_atm3_key = key break # check if rct1_atm1, rct1_atm2, rct1_atm3 are colinear # if they are choose a dummy atom rct1_geo = automol.zmatrix.geometry(rct1_zma) if rct1_atm3_key: rct1_sub_geo = (rct1_geo[rct1_atm1_key], rct1_geo[rct1_atm2_key], rct1_geo[rct1_atm3_key]) else: rct1_sub_geo = (rct1_geo[rct1_atm1_key], rct1_geo[rct1_atm2_key]) if automol.geom.is_linear(rct1_sub_geo) or not rct1_atm3_key: # have to regenerate atm2_nghbr_keys to include dummy atom keys! rct1_key_mat = automol.zmatrix.key_matrix(rct1_zma) rct1_keys = [row[0] for row in rct1_key_mat] if rct1_keys[rct1_atm2_key] is not None: atm2_nghbr_keys = [rct1_keys[rct1_atm2_key]] else: atm2_nghbr_keys = [] for idx, rct1_key in enumerate(rct1_keys): if rct1_key == rct1_atm2_key: atm2_nghbr_keys.append(idx) new_atm3 = False for atm_key in atm2_nghbr_keys: if atm_key not in (rct1_atm3_key, rct1_atm1_key): rct1_atm3_key = atm_key new_atm3 = True break if not new_atm3: # if there are no dummy atoms connected to the rct1_atm2 then # search for dummy atom keys connected to rct1_atm1 # now regenerate atm1_nghbr_keys to include dummy atom keys! if rct1_keys[rct1_atm1_key] is not None: atm1_nghbr_keys = [rct1_keys[rct1_atm1_key]] else: atm1_nghbr_keys = [] for idx, rct1_key in enumerate(rct1_keys): if rct1_key == rct1_atm1_key: atm1_nghbr_keys.append(idx) new_atm3 = False for atm_key in atm1_nghbr_keys: if atm_key not in (rct1_atm3_key, rct1_atm2_key): rct1_atm3_key = atm_key new_atm3 = True break join_val_dct = { dist_name: dist_val, 'aabs1': 85. * qcc.conversion_factor('degree', 'radian'), 'aabs2': 85. * qcc.conversion_factor('degree', 'radian'), 'babs1': 85. * qcc.conversion_factor('degree', 'radian'), 'babs2': 85. * qcc.conversion_factor('degree', 'radian'), 'babs3': 85. * qcc.conversion_factor('degree', 'radian'), } rct1_natom = automol.zmatrix.count(rct1_zma) rct2_natom = automol.zmatrix.count(rct2_zma) if rct1_natom == 1 and rct2_natom == 1: raise NotImplementedError if rct1_natom == 2 and rct2_natom == 1: join_keys = numpy.array([[rct1_atm1_key, rct1_atm2_key, None]]) join_names = numpy.array([[dist_name, 'aabs1', None]]) elif rct1_natom == 2 and rct2_natom == 2: join_keys = numpy.array([[rct1_atm1_key, rct1_atm2_key, rct1_atm3_key], [None, rct1_atm1_key, rct1_atm2_key]]) join_names = numpy.array([[dist_name, 'aabs1', None], [None, 'aabs2', 'babs2']]) else: join_keys = numpy.array([[rct1_atm1_key, rct1_atm2_key, rct1_atm3_key], [None, rct1_atm1_key, rct1_atm2_key], [None, None, rct1_atm1_key]])[:rct2_natms] join_names = numpy.array([[dist_name, 'aabs1', 'babs1'], [None, 'aabs2', 'babs2'], [None, None, 'babs3']])[:rct2_natms] join_name_set = set(numpy.ravel(join_names)) - {None} join_val_dct = {name: join_val_dct[name] for name in join_name_set} ts_zma = automol.zmatrix.join(rct1_zma, rct2_zma, join_keys, join_names, join_val_dct) ts_name_dct = automol.zmatrix.standard_names(ts_zma) dist_name = ts_name_dct[dist_name] ts_zma = automol.zmatrix.standard_form(ts_zma) # bimol_tors_names = constbuild.bimol() frm_bnd_keys = shift_vals_from_dummy(frm_bnd_keyss, ts_zma) # Build return ret = { 'ts_zma': ts_zma, 'bnd_keys': (frm_bnd_keys, frozenset({})), 'const_keys': (frozenset({}), frozenset({}), frozenset({})) } return ret
def hydrogen_migration(rct_zmas_lst, prd_zmas_lst, tras): """ z-matrix for a hydrogen migration reaction tras in the ZMATRIX coordinate system """ # Find the zma and traj pair that has min dist among rxn coord init_zma, min_tra = min_dist(rct_zmas_lst, tras) _ = prd_zmas_lst # unneeded for TS build frm_bnd_keys, = automol.graph.trans.formed_bond_keys(min_tra) brk_bnd_keys, = automol.graph.trans.broken_bond_keys(min_tra) # Build a properly ordered zma count = 0 while True: # figure out which idx in frm_bnd_keys corresponds to the hydrogen symbols = automol.vmatrix.symbols(automol.zmatrix.var_(init_zma)) dist_coo_key = tuple(reversed(sorted(frm_bnd_keys))) for idx in dist_coo_key: if symbols[idx] == 'H': h_idx = idx else: a1_idx = idx brk_dist_coo_key = tuple(reversed(sorted(brk_bnd_keys))) for idx in brk_dist_coo_key: if symbols[idx] != 'H': a2_idx = idx # determine if the zmatrix needs to be rebuilt by x2z # determines if the hydrogen atom is used to define other atoms init_keys = automol.zmatrix.key_matrix(init_zma) rebuild = False for i, _ in enumerate(init_keys): if i > h_idx and any(idx == h_idx for idx in init_keys[i]): rebuild = True break # rebuild zmat and go through while loop again if needed # shifts order of cartesian coords and rerun x2z to get a new zmat # else go to next stage if rebuild: re_zma, frm_bnd_keys, brk_bnd_keys = reorder_zmatrix_for_redef( init_zma, a1_idx, h_idx, frm_bnd_keys, brk_bnd_keys) rct_zma = [re_zma] count += 1 if count == 6: break else: rct_zma = init_zma break if not rct_zma: return None # Determine the backbone atoms to redefine the z-matrix entry _, gras = shifted_standard_zmas_graphs([rct_zma], remove_stereo=True) gra = functools.reduce(automol.graph.union, gras) xgr1, = automol.graph.connected_components(gra) chains_dct = automol.graph.atom_longest_chains(xgr1) idx_found = True a3_idx = chains_dct[a2_idx][1] if a3_idx in (h_idx, a1_idx): idx_found = False a2_neighbors = _atom_neighbor_keys(xgr1)[a2_idx] for idx in a2_neighbors: if idx not in (h_idx, a1_idx): a3_idx = idx idx_found = True if not idx_found: a3_idx = chains_dct[a1_idx][1] if a3_idx in (h_idx, a2_idx): a1_neighbors = _atom_neighbor_keys(xgr1)[a1_idx] for idx in a1_neighbors: if idx not in (h_idx, a2_idx): a3_idx = idx # Set the values of the coordinates of the migrating H atom rct_geo = automol.zmatrix.geometry(rct_zma) distance = automol.geom.distance(rct_geo, h_idx, a1_idx) angle = automol.geom.central_angle(rct_geo, h_idx, a1_idx, a2_idx) dihedral = automol.geom.dihedral_angle(rct_geo, h_idx, a1_idx, a2_idx, a3_idx) dihed_is_180 = numpy.isclose(abs(dihedral), (numpy.pi), rtol=(5.0 * numpy.pi / 180.)) dihed_is_0 = numpy.isclose(dihedral, (0.0), rtol=(5.0 * numpy.pi / 180.)) dihed_is_360 = numpy.isclose(abs(dihedral), (2 * numpy.pi), rtol=(5.0 * numpy.pi / 180.)) if dihed_is_180 or dihed_is_0 or dihed_is_360: dihedral -= (15.0 * numpy.pi / 180.) # Reset the keys for the migrating H atom new_idxs = (a1_idx, a2_idx, a3_idx) key_dct = {h_idx: new_idxs} ts_zma = automol.zmatrix.set_keys(rct_zma, key_dct) h_names = automol.zmatrix.name_matrix(ts_zma)[h_idx] ts_zma = automol.zmatrix.set_values(ts_zma, { h_names[0]: distance, h_names[1]: angle, h_names[2]: dihedral }) # standardize the ts zmat and get tors and dist coords coo_dct = automol.zmatrix.coordinates(ts_zma) for coo_name, coo_key in coo_dct.items(): dist_coo_key_rev = dist_coo_key[::-1] if coo_key[0] in (dist_coo_key, dist_coo_key_rev): dist_name = coo_name break # if migrating H atom is not the final zmat entry, shift it to the end (if # needed) if h_idx != automol.zmatrix.count(ts_zma) - 1: ts_zma, h_idx, frm_bnd_keys, brk_bnd_keys = shift_row_to_end( ts_zma, h_idx, frm_bnd_keys, brk_bnd_keys) ts_name_dct = automol.zmatrix.standard_names(ts_zma) dist_name = ts_name_dct[dist_name] ts_zma = automol.zmatrix.standard_form(ts_zma) # Build the torsional coordinates const_bnd_keys, _, _ = constbuild.hydrogen_migration( ts_zma, rct_zma, h_idx, frm_bnd_keys, brk_bnd_keys) # tors_bnd_keys = [coord_idxs(ts_zma, name) for name in tors_names] # Build the bond coordinates frm_bnd_keys = shift_vals_from_dummy(frm_bnd_keys, ts_zma) brk_bnd_keys = shift_vals_from_dummy(brk_bnd_keys, ts_zma) const_bnd_keys = shift_vals_from_dummy(const_bnd_keys, ts_zma) # Set the return ret = { 'ts_zma': ts_zma, 'bnd_keys': (frm_bnd_keys, brk_bnd_keys), 'const_keys': (const_bnd_keys, frozenset({}), frozenset({})) } return ret
def concerted_unimol_elimination(rct_zmas, prd_zmas, tras): """ z-matrix for a concerted unimolecular elimination reaction """ # Find the zma and traj pair that has min dist among rxn coord _ = prd_zmas # Unneeded rct_zma, min_tra = min_dist(rct_zmas, tras) frm_bnd_keys, = automol.graph.trans.formed_bond_keys(min_tra) brk_bnd_keys = automol.graph.trans.broken_bond_keys(min_tra) brk_bnd_key1, brk_bnd_key2 = brk_bnd_keys count = 1 while True: init_zma = rct_zma print('init_zma\n', automol.zmatrix.string(init_zma)) # print('init_geo\n', automol.geom.string(automol.zmatrix.geometry(init_zma))) # Get index for migrating atom (or bond-form atom in group) brk_bnd_key1, brk_bnd_key2 = brk_bnd_keys for bnd_key in (brk_bnd_key1, brk_bnd_key2): if bnd_key & frm_bnd_keys: mig_key = next(iter(bnd_key & frm_bnd_keys)) for key in frm_bnd_keys: if key != mig_key: a1_idx = key # Get chain for redefining the rc1_atm1_key z-matrix entries _, gras = shifted_standard_zmas_graphs([init_zma], remove_stereo=True) gra = functools.reduce(automol.graph.union, gras) xgr1, = automol.graph.connected_components(gra) atm1_neighbors = _atom_neighbor_keys(xgr1)[a1_idx] for idx in atm1_neighbors: num_keys = len(_atom_neighbor_keys(xgr1)[idx]) if idx != mig_key and num_keys > 1: a2_idx = idx atm2_neighbors = _atom_neighbor_keys(xgr1)[a2_idx] for idx in atm2_neighbors: if idx not in (mig_key, a1_idx): a3_idx = idx mig_redef_keys = (a1_idx, a2_idx, a3_idx) print('mig key', mig_key) print('mig redef keys', mig_redef_keys) print('frm keys', frm_bnd_keys) print('brk keys', brk_bnd_keys) # determine if the zmatrix needs to be rebuilt by x2z # determines if the hydrogen atom is used to define other atoms rebuild = False if any(idx > mig_key for idx in mig_redef_keys): rebuild = True # rebuild zmat and go through while loop again if needed # shift order of cartesian coords & rerun x2z to get a new zmat # else go to next stage if rebuild: # multiple bond keys need to be passed reord_zma, frm_bnd_keys, brk_bnd_keys = reorder_zmatrix_for_redef( init_zma, a1_idx, mig_key, frm_bnd_keys, brk_bnd_keys) rct_zma = reord_zma count += 1 if count == 3: finish_build = False break print('rebuild') else: rct_zma = init_zma finish_build = True print('no rebuild') break # If z-mat with good order not found, exit function if not finish_build: return None # determine the new coordinates rct_geo = automol.zmatrix.geometry(rct_zma) distance = automol.geom.distance(rct_geo, mig_key, a1_idx) angle = automol.geom.central_angle(rct_geo, mig_key, a1_idx, a2_idx) dihedral = automol.geom.dihedral_angle(rct_geo, mig_key, a1_idx, a2_idx, a3_idx) # Reset the keys for the migrating H atom new_idxs = (a1_idx, a2_idx, a3_idx) key_dct = {mig_key: new_idxs} ts_zma = automol.zmatrix.set_keys(rct_zma, key_dct) # Reset the values in the value dict mig_names = automol.zmatrix.name_matrix(ts_zma)[mig_key] ts_zma = automol.zmatrix.set_values(ts_zma, { mig_names[0]: distance, mig_names[1]: angle, mig_names[2]: dihedral }) # standardize the ts zmat and get tors and dist coords coo_dct = automol.zmatrix.coordinates(ts_zma) dist_coo_key = tuple(reversed(sorted(frm_bnd_keys))) dist_name = next(coo_name for coo_name, coo_keys in coo_dct.items() if dist_coo_key in coo_keys) ts_name_dct = automol.zmatrix.standard_names(ts_zma) dist_name = ts_name_dct[dist_name] ts_zma = automol.zmatrix.standard_form(ts_zma) brk_bnd_keys = frozenset({ shift_vals_from_dummy(brk_bnd_key1, ts_zma), shift_vals_from_dummy(brk_bnd_key2, ts_zma) }) frm_bnd_keys = shift_vals_from_dummy(frm_bnd_keys, ts_zma) # Set the return ret = { 'ts_zma': ts_zma, 'bnd_keys': (frm_bnd_keys, brk_bnd_keys), 'const_keys': (frozenset({}), frozenset({}), frozenset({})) } return ret