def hydrogen_migrations(rct_gras, viable_only=True): """ find all possible hydrogen migration reactions for these reactants :param rct_gras: graphs for the reactants, without stereo and without overlapping keys :param viable_only: Filter out reactions with non-viable products? :type viable_only: bool :returns: a list of Reaction objects :rtype: tuple[Reaction] Hydrogen migrations are enumerated looping over unsaturated sites, adding hydrogens to them, and looping over non-equivalent heavy atoms and removing hydrgens from them. """ assert_is_valid_reagent_graph_list(rct_gras) rxns = [] if len(rct_gras) == 1: rct_gra, = rct_gras # Identify unsaturated sites rct_add_key = max(atom_keys(rct_gra)) + 1 rct_rad_keys = unsaturated_atom_keys(rct_gra) rct_hyd_keys = atom_keys(rct_gra, sym='H') for rct_rad_key in rct_rad_keys: # Add a hydrogen to the radical/unsaturated site rct_h_gra = add_bonded_atom(rct_gra, 'H', rct_rad_key, bnd_atm_key=rct_add_key) # Identify donor sites rct_don_keys = backbone_keys(rct_h_gra) - {rct_rad_key} for rct_don_key in rct_don_keys: rct_hyd_key = atom_neighbor_atom_key(rct_gra, rct_don_key, symbs_first=['H'], symbs_last=[]) if rct_hyd_key in rct_hyd_keys: prd_gra = remove_atoms(rct_h_gra, {rct_hyd_key}) prd_gra = relabel(prd_gra, {rct_add_key: rct_hyd_key}) forw_tsg = ts.graph(rct_gra, frm_bnd_keys=[(rct_rad_key, rct_hyd_key)], brk_bnd_keys=[(rct_don_key, rct_hyd_key)]) back_tsg = ts.graph(prd_gra, frm_bnd_keys=[(rct_don_key, rct_hyd_key)], brk_bnd_keys=[(rct_rad_key, rct_hyd_key)]) rxns.append( Reaction( rxn_cls=par.ReactionClass.Typ.HYDROGEN_MIGRATION, forw_tsg=forw_tsg, back_tsg=back_tsg, rcts_keys=[atom_keys(rct_gra)], prds_keys=[atom_keys(prd_gra)], )) if viable_only: rxns = filter_viable_reactions(rxns) return ts_unique(rxns)
def hydrogen_abstractions(rct_gras, viable_only=True): """ find hydrogen abstraction reactions for these reactants :param rct_gras: graphs for the reactants, without stereo and without overlapping keys :param viable_only: Filter out reactions with non-viable products? :type viable_only: bool :returns: a list of Reaction objects :rtype: tuple[Reaction] Hydrogen abstractions are enumerated by looping over unique unsaturated atoms on one molecule and abstracting from unique atoms on the other. """ assert_is_valid_reagent_graph_list(rct_gras) rxns = [] if len(rct_gras) == 2: for q1h_gra, q2_gra in itertools.permutations(rct_gras): hyd_keys = atom_keys(q1h_gra, sym='H') # Identify unique heavy atoms as potential donors don_keys = atom_keys(q1h_gra, excl_syms=('H', )) don_keys = atom_equivalence_class_reps(q1h_gra, don_keys) # Identify unique unsaturated atoms as potential attackers att_keys = unsaturated_atom_keys(q2_gra) att_keys = atom_equivalence_class_reps(q2_gra, att_keys) for don_key, att_key in itertools.product(don_keys, att_keys): hyd_key = atom_neighbor_atom_key(q1h_gra, don_key, symbs_first=['H'], symbs_last=[]) if hyd_key in hyd_keys: # Remove a hydrogen from the donor site q1_gra = remove_atoms(q1h_gra, {hyd_key}) # Add a hydrogen atom to the attacker site q2h_gra = add_bonded_atom(q2_gra, 'H', att_key, bnd_atm_key=hyd_key) rcts_gra = union(q1h_gra, q2_gra) prds_gra = union(q2h_gra, q1_gra) forw_tsg = ts.graph(rcts_gra, frm_bnd_keys=[(att_key, hyd_key)], brk_bnd_keys=[(don_key, hyd_key)]) back_tsg = ts.graph(prds_gra, frm_bnd_keys=[(don_key, hyd_key)], brk_bnd_keys=[(att_key, hyd_key)]) rcts_atm_keys = list(map(atom_keys, [q1h_gra, q2_gra])) prds_atm_keys = list(map(atom_keys, [q2h_gra, q1_gra])) # Create the reaction object rxns.append( Reaction( rxn_cls=par.ReactionClass.Typ.HYDROGEN_ABSTRACTION, forw_tsg=forw_tsg, back_tsg=back_tsg, rcts_keys=rcts_atm_keys, prds_keys=prds_atm_keys, )) if viable_only: rxns = filter_viable_reactions(rxns) return ts_unique(rxns)
def hydrogen_migrations(rct_gras, prd_gras): """ find hydrogen migrations consistent with these reactants and products :param rct_gras: reactant graphs (must have non-overlapping keys) :param prd_gras: product graphs (must have non-overlapping keys) Hydrogen migrations are identified by adding a hydrogen to an unsaturated site of the reactant and adding a hydrogen to an unsaturated site of the product and seeing if they match up. If so, we have a hydrogen migration between these two sites. """ _assert_is_valid_reagent_graph_list(rct_gras) _assert_is_valid_reagent_graph_list(prd_gras) rxns = [] if len(rct_gras) == 1 and len(prd_gras) == 1: rct_gra, = rct_gras prd_gra, = prd_gras # Find keys for reactant graph rct_h_key = max(atom_keys(rct_gra)) + 1 rct_rad_keys = unsaturated_atom_keys(rct_gra) # Find keys for product graph prd_h_key = max(atom_keys(prd_gra)) + 1 prd_rad_keys = unsaturated_atom_keys(prd_gra) for rct_rad_key, prd_rad_key in (itertools.product( rct_rad_keys, prd_rad_keys)): # Add hydrogens to each radical site and see if the result matches rct_h_gra = add_bonded_atom(rct_gra, 'H', rct_rad_key, bnd_atm_key=rct_h_key) prd_h_gra = add_bonded_atom(prd_gra, 'H', prd_rad_key, bnd_atm_key=prd_h_key) iso_dct = isomorphism(rct_h_gra, prd_h_gra) if iso_dct: inv_dct = dict(map(reversed, iso_dct.items())) rct_don_key = inv_dct[prd_rad_key] prd_don_key = iso_dct[rct_rad_key] # Check equivalent donor atoms for other possible TSs rct_don_keys = equivalent_atoms(rct_h_gra, rct_don_key) prd_don_keys = equivalent_atoms(prd_h_gra, prd_don_key) for rct_don_key, prd_don_key in (itertools.product( rct_don_keys, prd_don_keys)): rct_hyd_key = atom_neighbor_atom_key(rct_gra, rct_don_key, symbs_first=('H', ), symbs_last=()) prd_hyd_key = atom_neighbor_atom_key(prd_gra, prd_don_key, symbs_first=('H', ), symbs_last=()) forw_tsg = ts.graph(rct_gra, frm_bnd_keys=[(rct_rad_key, rct_hyd_key)], brk_bnd_keys=[(rct_don_key, rct_hyd_key)]) back_tsg = ts.graph(prd_gra, frm_bnd_keys=[(prd_rad_key, prd_hyd_key)], brk_bnd_keys=[(prd_don_key, prd_hyd_key)]) if isomorphism(forw_tsg, ts.reverse(back_tsg)): rxns.append( Reaction( rxn_cls=par.ReactionClass.HYDROGEN_MIGRATION, forw_tsg=forw_tsg, back_tsg=back_tsg, rcts_keys=[atom_keys(rct_gra)], prds_keys=[atom_keys(prd_gra)], )) return ts_unique(rxns)