Beispiel #1
0
def test__connected_components():
    """ test graph.connected_components
    """
    gra1 = C3H3_CGR
    gra2 = C2_CGR
    gra1_natms = automol.formula.atom_count(graph.formula(C3H3_CGR))
    gra2 = graph.transform_keys(gra2, lambda x: x + gra1_natms)

    gra = graph.union(gra1, gra2)
    cmp_gras = graph.connected_components(gra)
    assert cmp_gras in [(gra1, gra2), (gra2, gra1)]
Beispiel #2
0
def additions(rct_gras, prd_gras):
    """ find additions 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)

    Additions are identified by joining an unsaturated site on one reactant to
    an unsaturated site on the other. If the result matches the products, this
    is an addition reaction.
    """
    _assert_is_valid_reagent_graph_list(rct_gras)
    _assert_is_valid_reagent_graph_list(prd_gras)

    rxns = []

    if len(rct_gras) == 2 and len(prd_gras) == 1:
        x_gra, y_gra = rct_gras
        prd_gra, = prd_gras
        x_atm_keys = unsaturated_atom_keys(x_gra)
        y_atm_keys = unsaturated_atom_keys(y_gra)

        for x_atm_key, y_atm_key in itertools.product(x_atm_keys, y_atm_keys):
            xy_gra = add_bonds(union(x_gra, y_gra), [{x_atm_key, y_atm_key}])

            iso_dct = isomorphism(xy_gra, prd_gra)
            if iso_dct:
                rcts_gra = union_from_sequence(rct_gras)
                prds_gra = prd_gra
                f_frm_bnd_key = (x_atm_key, y_atm_key)
                b_brk_bnd_key = (iso_dct[x_atm_key], iso_dct[y_atm_key])
                forw_tsg = ts.graph(rcts_gra,
                                    frm_bnd_keys=[f_frm_bnd_key],
                                    brk_bnd_keys=[])
                back_tsg = ts.graph(prds_gra,
                                    frm_bnd_keys=[],
                                    brk_bnd_keys=[b_brk_bnd_key])

                # sort the reactants so that the largest species is first
                rct_idxs = _argsort_reactants(rct_gras)
                rct_gras = list(map(rct_gras.__getitem__, rct_idxs))

                # Create the reaction object
                rxns.append(
                    Reaction(
                        rxn_cls=par.ReactionClass.ADDITION,
                        forw_tsg=forw_tsg,
                        back_tsg=back_tsg,
                        rcts_keys=list(map(atom_keys, rct_gras)),
                        prds_keys=list(map(atom_keys, prd_gras)),
                    ))

    return ts_unique(rxns)
Beispiel #3
0
def additions(rct_gras, viable_only=True):
    """ find all possible addition 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]

    Additions are enumerated by joining an unsaturated site on one reactant to
    an unsaturated site on the other.
    """
    assert_is_valid_reagent_graph_list(rct_gras)

    rxns = []

    if len(rct_gras) == 2:
        rct_gras = sort_reagents(rct_gras)
        rct1_gra, rct2_gra = rct_gras

        rct1_atm_keys = unsaturated_atom_keys(rct1_gra)
        rct2_atm_keys = unsaturated_atom_keys(rct2_gra)

        for frm_bnd_key in itertools.product(rct1_atm_keys, rct2_atm_keys):
            rcts_gra = union(rct1_gra, rct2_gra)
            prd_gra = add_bonds(rcts_gra, [frm_bnd_key])
            prd_gras = [prd_gra]

            forw_tsg = ts.graph(rcts_gra,
                                frm_bnd_keys=[frm_bnd_key],
                                brk_bnd_keys=[])
            back_tsg = ts.graph(prd_gra,
                                frm_bnd_keys=[],
                                brk_bnd_keys=[frm_bnd_key])

            # Create the reaction object
            rxns.append(
                Reaction(
                    rxn_cls=par.ReactionClass.Typ.ADDITION,
                    forw_tsg=forw_tsg,
                    back_tsg=back_tsg,
                    rcts_keys=list(map(atom_keys, rct_gras)),
                    prds_keys=list(map(atom_keys, prd_gras)),
                ))

    if viable_only:
        rxns = filter_viable_reactions(rxns)

    return ts_unique(rxns)
Beispiel #4
0
def insertions(rct_gras, viable_only=True):
    """ find all possible insertion 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]

    Insertions are enumerated by looping over carbenes and multiple bonds on
    one reactant, which serve as a source of potential "attacking" atoms for
    the insertion, and looping over single bonds that could be inserted into on
    the other reactant. For lack of a better term, we can call these "donating
    atoms". The insertion then looks as follows:

        A1=A2         A1
        .  .    or    .
        .  .         .  .
        D1-D2        D1-D2

    where two bonds are formed between the A and D atoms and the bond between
    the two D atoms is broken.
    """
    assert_is_valid_reagent_graph_list(rct_gras)

    rxns = []

    if len(rct_gras) == 2:
        for rct1_gra, rct2_gra in itertools.permutations(rct_gras):
            rcts_gra = union(rct1_gra, rct2_gra)

            # Carbenes on R1 are potential attacking atoms
            atm_keys = radical_atom_keys(rct1_gra, min_valence=2.)
            atm_keys = tuple(atm_keys)
            # So are atoms on either side of a multiple bond
            bnd_keys = dict_.keys_by_value(resonance_avg_bond_orders(rct1_gra),
                                           lambda x: x > 1.)
            bnd_keys = bond_equivalence_class_reps(rct1_gra, bnd_keys)
            # Use this to form a list of attacking atom pairs for R1
            att_pairs = list(map(tuple, map(sorted, bnd_keys)))
            att_pairs += list(zip(atm_keys, atm_keys))

            # As donor pairs, consider single bonds on R2
            don_bnd_keys = dict_.keys_by_value(
                resonance_avg_bond_orders(rct2_gra), lambda x: x == 1.)
            don_bnd_keys = bond_equivalence_class_reps(rct2_gra, don_bnd_keys)
            don_pairs = list(map(tuple, map(sorted, don_bnd_keys)))

            for att_pair, don_pair in itertools.product(att_pairs, don_pairs):
                if not (are_equivalent_atoms(rct1_gra, *att_pair)
                        or are_equivalent_atoms(rct2_gra, *don_pair)):
                    don_pairs_ = list(itertools.permutations(don_pair))
                else:
                    don_pairs_ = [don_pair]

                for don_pair_ in don_pairs_:
                    att1_key, att2_key = att_pair
                    don1_key, don2_key = don_pair_

                    prds_gra = rcts_gra
                    prds_gra = add_bonds(prds_gra, [(att1_key, don1_key),
                                                    (att2_key, don2_key)])
                    prds_gra = remove_bonds(prds_gra, [(don1_key, don2_key)])

                    prd_gras = connected_components(prds_gra)

                    if len(prd_gras) == 1:
                        forw_tsg = ts.graph(rcts_gra,
                                            frm_bnd_keys=[(att1_key, don1_key),
                                                          (att2_key, don2_key)
                                                          ],
                                            brk_bnd_keys=[(don1_key, don2_key)
                                                          ])
                        back_tsg = ts.graph(prds_gra,
                                            frm_bnd_keys=[(don1_key, don2_key)
                                                          ],
                                            brk_bnd_keys=[(att1_key, don1_key),
                                                          (att2_key, don2_key)
                                                          ])

                        # Create the reaction object
                        rcts_keys = list(map(atom_keys, [rct1_gra, rct2_gra]))
                        prds_keys = list(map(atom_keys, prd_gras))
                        rxns.append(
                            Reaction(
                                rxn_cls=par.ReactionClass.Typ.INSERTION,
                                forw_tsg=forw_tsg,
                                back_tsg=back_tsg,
                                rcts_keys=rcts_keys,
                                prds_keys=prds_keys,
                            ))

    if viable_only:
        rxns = filter_viable_reactions(rxns)

    return ts_unique(rxns)
Beispiel #5
0
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)
Beispiel #6
0
def two_bond_additions(rct_gras, prd_gras):
    """ two bond additions
    """
    assert_is_valid_reagent_graph_list(rct_gras)
    assert_is_valid_reagent_graph_list(prd_gras)

    rxns = []

    if len(rct_gras) == 2 and len(prd_gras) == 1:
        rct_gras = sort_reagents(rct_gras)
        x_gra, y_gra = rct_gras
        prd_gra, = prd_gras
        x_atm_keys = frozenset().union(unsaturated_atom_keys(x_gra),
                                       lone_pair_atom_keys(x_gra))
        y_atm_keys = frozenset().union(unsaturated_atom_keys(y_gra),
                                       lone_pair_atom_keys(y_gra))
        print('x,y keys', x_atm_keys, y_atm_keys)

        # Generate pairs of forming bonds, where each is a pair of idxs
        # describing the atoms making up the forming bond:
        # (frm1, frm2) = ((idx1, idx2), (idx1, idx2))
        frm_bnd_pairs = tuple(itertools.product(x_atm_keys, y_atm_keys))
        frm_bnds_lst = ()
        for pair in itertools.product(frm_bnd_pairs, frm_bnd_pairs):
            # Preclude pairs with same idxs (formind same bond twice)
            if pair[0] != pair[1]:
                # Preclude multiple bonds formed to same atom X---A---Y
                if pair[0][0] != pair[1][0] and pair[0][1] != pair[1][1]:
                    # Preclude the reverse
                    if pair[::-1] not in frm_bnds_lst:
                        frm_bnds_lst += (pair, )

        for frm_bnd_keys in frm_bnds_lst:
            xy_gra = add_bonds(union(x_gra, y_gra),
                               [set(frm_bnd_keys[0]),
                                set(frm_bnd_keys[1])])

            iso_dct = isomorphism(xy_gra, prd_gra)
            if iso_dct:
                rcts_gra = union_from_sequence(rct_gras)
                prds_gra = prd_gra
                b_brk_bnd_keys = [[
                    iso_dct[frm_bnd_keys[0][0]], iso_dct[frm_bnd_keys[0][1]]
                ], [iso_dct[frm_bnd_keys[1][0]], iso_dct[frm_bnd_keys[1][1]]]]
                forw_tsg = ts.graph(rcts_gra,
                                    frm_bnd_keys=frm_bnd_keys,
                                    brk_bnd_keys=[])
                back_tsg = ts.graph(prds_gra,
                                    frm_bnd_keys=[],
                                    brk_bnd_keys=b_brk_bnd_keys)

                # Create the reaction object
                rxns.append(
                    Reaction(
                        rxn_cls=ReactionClass.Typ.ADDITION,
                        forw_tsg=forw_tsg,
                        back_tsg=back_tsg,
                        rcts_keys=list(map(atom_keys, rct_gras)),
                        prds_keys=list(map(atom_keys, prd_gras)),
                    ))

    return ts_unique(rxns)