def test__from_data(): """ test getters """ cgr = automol.graph.from_data( atm_symb_dct=graph.atom_symbols(C8H13O_CGR), bnd_keys=graph.bond_keys(C8H13O_CGR), atm_imp_hyd_vlc_dct=( graph.atom_implicit_hydrogen_valences(C8H13O_CGR)), ) assert cgr == C8H13O_CGR rgr = automol.graph.from_data( atm_symb_dct=graph.atom_symbols(C8H13O_RGR), bnd_keys=graph.bond_keys(C8H13O_RGR), atm_imp_hyd_vlc_dct=( graph.atom_implicit_hydrogen_valences(C8H13O_RGR)), bnd_ord_dct=graph.bond_orders(C8H13O_RGR), ) assert rgr == C8H13O_RGR sgr = automol.graph.from_data( atm_symb_dct=graph.atom_symbols(C8H13O_SGR), bnd_keys=graph.bond_keys(C8H13O_SGR), atm_imp_hyd_vlc_dct=( graph.atom_implicit_hydrogen_valences(C8H13O_SGR)), atm_ste_par_dct=graph.atom_stereo_parities(C8H13O_SGR), bnd_ste_par_dct=graph.bond_stereo_parities(C8H13O_SGR)) assert sgr == C8H13O_SGR
def test__set_atom_implicit_hydrogen_valences(): """ test graph.set_atom_implicit_hydrogen_valences """ atm_keys = graph.atom_keys(C8H13O_CGR) cgr = graph.set_atom_implicit_hydrogen_valences( C8H13O_CGR, {atm_key: 0 for atm_key in atm_keys}) assert cgr == automol.graph.from_data(graph.atom_symbols(C8H13O_CGR), graph.bond_keys(C8H13O_CGR))
def test__from_dictionaries(): """ test graph.from_dictionaries """ assert graph.from_dictionaries( graph.atom_symbols(CH2FH2H_CGR_EXP), graph.bond_keys(CH2FH2H_CGR_EXP) ) == CH2FH2H_CGR_EXP assert graph.from_dictionaries( graph.atom_symbols(C8H13O_RGRS[0]), graph.bond_keys(C8H13O_RGRS[0]), atm_imp_hyd_vlc_dct=graph.atom_implicit_hydrogen_valences( C8H13O_RGRS[0]), bnd_ord_dct=graph.bond_orders(C8H13O_RGRS[0]) ) == C8H13O_RGRS[0] assert graph.from_dictionaries( graph.atom_symbols(C8H13O_SGRS[0]), graph.bond_keys(C8H13O_SGRS[0]), atm_imp_hyd_vlc_dct=graph.atom_implicit_hydrogen_valences( C8H13O_SGRS[0]), atm_ste_par_dct=graph.atom_stereo_parities(C8H13O_SGRS[0]), bnd_ste_par_dct=graph.bond_stereo_parities(C8H13O_SGRS[0]) ) == C8H13O_SGRS[0] # a litte ridiculous, but make sure we get the keys right sgr_ref = C8H13O_SGRS[0] natms = len(graph.atoms(sgr_ref)) for _ in range(10): pmt_dct = dict(enumerate(numpy.random.permutation(natms))) sgr = graph.relabel(sgr_ref, pmt_dct) assert graph.from_dictionaries( graph.atom_symbols(sgr), graph.bond_keys(sgr), atm_imp_hyd_vlc_dct=graph.atom_implicit_hydrogen_valences(sgr), atm_ste_par_dct=graph.atom_stereo_parities(sgr), bnd_ste_par_dct=graph.bond_stereo_parities(sgr) ) == sgr
def eliminations(rct_gras, viable_only=True): """ find all possible elimination 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] Eliminations are enumerated by forming a bond between an attacking heavy atom and another atom not initially bonded to it, forming a ring. The bond adjacent to the attacked atom is then broken, along with a second bond in the ring, downstream from the attacking heavy atom, away from the attacked atom. """ assert_is_valid_reagent_graph_list(rct_gras) rxns = [] if len(rct_gras) == 1: rct_gra, = rct_gras ngb_keys_dct = atoms_neighbor_atom_keys(rct_gra) # frm1_keys = atom_keys(rct_gra, excl_syms=('H',)) frm1_keys = unsaturated_atom_keys(rct_gra) rct_symbs = atom_symbols(rct_gra) frm1_keys_o = frozenset(key for key in frm1_keys if rct_symbs[key] == 'O') frm2_keys = atom_keys(rct_gra) bnd_keys = bond_keys(rct_gra) frm_bnd_keys = [(frm1_key, frm2_key) for frm1_key, frm2_key in itertools.product( frm1_keys_o, frm2_keys) if frm1_key != frm2_key and not frozenset({frm1_key, frm2_key}) in bnd_keys] for frm1_key, frm2_key in frm_bnd_keys: # Bond the radical atom to the hydrogen atom prds_gra = add_bonds(rct_gra, [(frm2_key, frm1_key)]) # Get keys to the ring formed by this extra bond rng_keys = next((ks for ks in rings_atom_keys(prds_gra) if frm2_key in ks and frm1_key in ks), None) # Eliminations (as far as I can tell) only happen through TSs with # 3- or 4-membered rings if rng_keys is not None and len(rng_keys) < 5: frm1_ngb_key, = ngb_keys_dct[frm1_key] & set(rng_keys) frm2_ngb_key, = ngb_keys_dct[frm2_key] & set(rng_keys) # Break the bonds on either side of the newly formed bond prds_gra = remove_bonds(prds_gra, [(frm1_key, frm1_ngb_key)]) prds_gra = remove_bonds(prds_gra, [(frm2_key, frm2_ngb_key)]) prd_gras = connected_components(prds_gra) if len(prd_gras) == 2: forw_tsg = ts.graph(rct_gra, frm_bnd_keys=[(frm1_key, frm2_key)], brk_bnd_keys=[(frm1_key, frm1_ngb_key), (frm2_key, frm2_ngb_key) ]) back_tsg = ts.graph(prds_gra, frm_bnd_keys=[(frm1_key, frm1_ngb_key), (frm2_key, frm2_ngb_key) ], brk_bnd_keys=[(frm1_key, frm2_key)]) rcts_atm_keys = list(map(atom_keys, rct_gras)) prds_atm_keys = list(map(atom_keys, prd_gras)) if frm2_key not in prds_atm_keys[1]: prds_atm_keys = list(reversed(prds_atm_keys)) # Create the reaction object rxns.append( Reaction( rxn_cls=par.ReactionClass.Typ.ELIMINATION, 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 eliminations(rct_gras, prd_gras): """ find eliminations 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) Eliminations are identified by forming a bond between an attacking heavy atom and another atom not initially bonded to it, forming a ring. The bond adjacent to the attacked atom is then broken, along with a second bond in the ring, downstream of the attacking heavy atom, away from the attacked atom. """ def _identify(frm1_keys, frm2_keys, bnd_keys): """ Try and identify elmination from some set of keys """ _rxns = [] frm_bnd_keys = [ (frm1_key, frm2_key) for frm1_key, frm2_key in itertools.product(frm1_keys, frm2_keys) if frm1_key != frm2_key and not frozenset({frm1_key, frm2_key}) in bnd_keys ] for frm1_key, frm2_key in frm_bnd_keys: prds_gra_ = add_bonds(rct_gra, [(frm2_key, frm1_key)]) # Get keys of all bonds in the ring formed by this extra bond rng_bnd_keys = next((ks for ks in rings_bond_keys(prds_gra_) if frozenset({frm1_key, frm2_key}) in ks), None) if rng_bnd_keys is not None: # Elims break two bonds of the ring formed by the forming bond # Loop over all ring bond-pairs, break bonds, see if prods form # Ensure to preclude the forming-bond from this set brk_bnds = tuple( bond for bond in itertools.combinations(rng_bnd_keys, 2) if frozenset({frm1_key, frm2_key}) not in bond) for brk_bnd_1, brk_bnd_2 in brk_bnds: prds_gra_2_ = prds_gra_ prds_gra_2_ = remove_bonds(prds_gra_2_, [brk_bnd_1]) prds_gra_2_ = remove_bonds(prds_gra_2_, [brk_bnd_2]) inv_dct = isomorphism(prds_gra_2_, prds_gra) if inv_dct: f_frm_bnd_key = (frm1_key, frm2_key) inv_ = inv_dct.__getitem__ b_frm_bnd_key1 = tuple(map(inv_, brk_bnd_1)) b_frm_bnd_key2 = tuple(map(inv_, brk_bnd_2)) b_brk_bnd_key = tuple(map(inv_, f_frm_bnd_key)) forw_tsg = ts.graph( rct_gra, frm_bnd_keys=[f_frm_bnd_key], brk_bnd_keys=[brk_bnd_1, brk_bnd_2]) back_tsg = ts.graph( prds_gra, frm_bnd_keys=[b_frm_bnd_key1, b_frm_bnd_key2], brk_bnd_keys=[b_brk_bnd_key]) rcts_atm_keys = list(map(atom_keys, rct_gras)) prds_atm_keys = list(map(atom_keys, prd_gras)) if inv_dct[frm1_key] not in prds_atm_keys[1]: prds_atm_keys = list(reversed(prds_atm_keys)) assert inv_dct[frm1_key] in prds_atm_keys[1] assert inv_dct[frm2_key] in prds_atm_keys[1] # Create the reaction object _rxns.append( Reaction( rxn_cls=ReactionClass.Typ.ELIMINATION, forw_tsg=forw_tsg, back_tsg=back_tsg, rcts_keys=rcts_atm_keys, prds_keys=prds_atm_keys, )) return _rxns 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) == 2: rct_gra, = rct_gras prds_gra = union_from_sequence(prd_gras) # ngb_keys_dct = atoms_neighbor_atom_keys(rct_gra) # Generate keys all bonds and 1/2 the forming bond frm1_keys = atom_keys(rct_gra) bnd_keys = bond_keys(rct_gra) frm2_keys = unsaturated_atom_keys(rct_gra) rct_symbs = atom_symbols(rct_gra) frm2_keys_o = frozenset(key for key in frm2_keys if rct_symbs[key] == 'O') rxns.extend(_identify(frm1_keys, frm2_keys_o, bnd_keys)) # OLD WAY. More IDs but more mistakes # To make the function general, try to ID reaction # with different types of keys for the attacking atom # (1) unsaturated atom sites # frm2_keys = unsaturated_atom_keys(rct_gra) # rxns.extend(_identify(frm1_keys, frm2_keys, bnd_keys)) # if not rxns: # # (2) remaining saturated atom sites # frm2_keys = atom_keys(rct_gra, excl_syms=('H',)) - frm2_keys # rxns.extend(_identify(frm1_keys, frm2_keys, bnd_keys)) # # if not rxns: # Ignoring H2 formation for now for speed # # # (3) H atoms # # frm1_keys = atom_keys(rct_gra, sym='H') # # rxns.extend(_identify(frm1_keys, frm2_keys, bnd_keys)) return ts_unique(rxns)