コード例 #1
0
def _cumulene_chains(rgr):
    atm_hyb_dct = resonance_dominant_atom_hybridizations(rgr)
    sp1_atm_keys = dict_.keys_by_value(atm_hyb_dct, lambda x: x == 1)
    sp2_atm_keys = dict_.keys_by_value(atm_hyb_dct, lambda x: x == 2)

    atm_ngb_keys_dct = atoms_neighbor_atom_keys(rgr)

    def _cumulene_chain(chain):
        ret = None
        atm_key = chain[-1]
        next_atm_keys = atm_ngb_keys_dct[atm_key] - {chain[-2]}
        if next_atm_keys:
            assert len(next_atm_keys) == 1
            next_atm_key, = next_atm_keys
            if next_atm_key in sp1_atm_keys:
                chain.append(next_atm_key)
                ret = _cumulene_chain(chain)
            elif next_atm_key in sp2_atm_keys:
                chain.append(next_atm_key)
                ret = chain
        return ret

    cum_chains = []
    for atm_key in sp2_atm_keys:
        sp1_atm_ngb_keys = atm_ngb_keys_dct[atm_key] & sp1_atm_keys
        chains = [[atm_key, atm_ngb_key] for atm_ngb_key in sp1_atm_ngb_keys]
        for chain in chains:
            cum_chain = _cumulene_chain(chain)
            if cum_chain is not None:
                cum_chains.append(cum_chain)

    cum_chains = tuple(map(tuple, cum_chains))
    return cum_chains
コード例 #2
0
def sp2_bond_keys(gra):
    """ determine the sp2 bonds in this graph
    """
    gra = without_bond_orders(gra)
    bnd_keys = dict_.keys_by_value(resonance_dominant_bond_orders(gra),
                                   lambda x: 2 in x)

    # make sure both ends are sp^2 (excludes cumulenes)
    atm_hyb_dct = resonance_dominant_atom_hybridizations(gra)
    sp2_atm_keys = dict_.keys_by_value(atm_hyb_dct, lambda x: x == 2)
    bnd_keys = frozenset(
        {bnd_key
         for bnd_key in bnd_keys if bnd_key <= sp2_atm_keys})
    return bnd_keys
コード例 #3
0
def stereogenic_atom_keys(gra, assigned=False):
    """ Find stereogenic atoms in this graph.

    If the `assigned` flag is set to `False`, only  unassigned stereogenic
    atoms will be detected.

    :param gra: the graph
    :param assigned: Include atoms that already have stereo assignments?
    :param assigned: bool
    :returns: the stereogenic atom keys
    :rtype: frozenset
    """
    gra = without_bond_orders(gra)
    gra = explicit(gra)  # for simplicity, add the explicit hydrogens back in
    atm_keys = dict_.keys_by_value(atom_bond_valences(gra), lambda x: x == 4)
    if not assigned:
        # Remove assigned stereo keys
        atm_keys -= atom_stereo_keys(gra)

    atm_ngb_keys_dct = atoms_neighbor_atom_keys(gra)

    def _is_stereogenic(atm_key):
        atm_ngb_keys = list(atm_ngb_keys_dct[atm_key])
        pri_vecs = [
            stereo_priority_vector(gra, atm_key, atm_ngb_key)
            for atm_ngb_key in atm_ngb_keys
        ]
        ret = not any(pv1 == pv2
                      for pv1, pv2 in itertools.combinations(pri_vecs, r=2))
        return ret

    ste_gen_atm_keys = frozenset(filter(_is_stereogenic, atm_keys))
    return ste_gen_atm_keys
コード例 #4
0
def homolytic_scissions(rct_gras, viable_only=False):
    """ find all possible homolytic scission 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]

    Homolytic scissions are enumerated by identifying all pure single bonds
    (single bonds with no resonances), and looping over the results of
    breaking each of them. If this gives rise to two distinct
    fragments, the reaction is added to the list.
    """
    assert_is_valid_reagent_graph_list(rct_gras)

    rxns = []

    if len(rct_gras) == 1:
        rct_gra, = rct_gras

        # Identify all pure single bonds involving radical site neighbor
        avg_bnd_ord_dct = resonance_avg_bond_orders(rct_gra)
        brk_bnd_keys = dict_.keys_by_value(avg_bnd_ord_dct, lambda x: x == 1)

        for brk_bnd_key in brk_bnd_keys:
            prds_gra = remove_bonds(rct_gra, [brk_bnd_key])
            prd_gras = connected_components(prds_gra)

            if len(prd_gras) == 2:
                prd_gras = sort_reagents(prd_gras)

                forw_tsg = ts.graph(rct_gra,
                                    frm_bnd_keys=[],
                                    brk_bnd_keys=[brk_bnd_key])
                back_tsg = ts.graph(prds_gra,
                                    frm_bnd_keys=[brk_bnd_key],
                                    brk_bnd_keys=[])

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

    # Dummy line to fix linting checks
    assert viable_only or not viable_only
    # filter removes all reactions
    # if viable_only:
    #    rxns = filter_viable_reactions(rxns)

    return ts_unique(rxns)
コード例 #5
0
ファイル: _core.py プロジェクト: snelliott/automol
def explicit_hydrogen_keys(gra):
    """ explicit hydrogen keys (H types: explicit, implicit, backbone)
    """
    hyd_keys = dict_.keys_by_value(atom_symbols(gra), lambda x: x == 'H')
    atm_ngb_keys_dct = atoms_neighbor_atom_keys(gra)

    def _is_backbone(hyd_key):
        is_h2 = all(ngb_key in hyd_keys and hyd_key < ngb_key
                    for ngb_key in atm_ngb_keys_dct[hyd_key])
        is_multivalent = len(atm_ngb_keys_dct[hyd_key]) > 1
        return is_h2 or is_multivalent

    exp_hyd_keys = frozenset(fmit.filterfalse(_is_backbone, hyd_keys))
    return exp_hyd_keys
コード例 #6
0
def linear_atom_keys(rgr, dummy=True):
    """ atoms forming linear bonds, based on their hybridization

    :param rgr: the graph
    :param dummy: whether or not to consider atoms connected to dummy atoms as
        linear, if different from what would be predicted based on their
        hybridization
    :returns: the linear atom keys
    :rtype: tuple[int]
    """
    rgr = without_fractional_bonds(rgr)
    atm_hyb_dct = resonance_dominant_atom_hybridizations(implicit(rgr))
    lin_atm_keys = set(dict_.keys_by_value(atm_hyb_dct, lambda x: x == 1))

    if dummy:
        dum_ngb_key_dct = dummy_atoms_neighbor_atom_key(rgr)
        lin_atm_keys |= set(dum_ngb_key_dct.values())

    lin_atm_keys = tuple(sorted(lin_atm_keys))
    return lin_atm_keys
コード例 #7
0
ファイル: _graph.py プロジェクト: sjklipp/autochem
def unsaturated_atom_keys(gra):
    """ keys of unsaturated (radical or pi-bonded) atoms
    """
    atm_unsat_vlc_dct = atom_unsaturated_valences(gra, bond_order=False)
    unsat_atm_keys = frozenset(dict_.keys_by_value(atm_unsat_vlc_dct, bool))
    return unsat_atm_keys
コード例 #8
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)
コード例 #9
0
def beta_scissions(rct_gras, viable_only=True):
    """ find all possible beta scission 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]

    FIX DESCRIPTION:
    Beta scissions are enumerated by identifying all pure single bonds (single
    bonds with no resonances), and looping over the results of breaking each of
    them. If this gives rise to two distinct fragments, the reaction is added
    to the list.
    """
    assert_is_valid_reagent_graph_list(rct_gras)

    rxns = []

    if len(rct_gras) == 1:
        rct_gra, = rct_gras

        # Identify all atom keys that neighbor radical sites
        rad_neighs = frozenset({})
        neigh_dct = atoms_neighbor_atom_keys(rct_gra)
        for rad_key in radical_atom_keys(rct_gra):
            rad_neighs = rad_neighs | neigh_dct[rad_key]

        # Identify all pure single bonds involving radical site neighbor
        avg_bnd_ord_dct = resonance_avg_bond_orders(rct_gra)
        brk_bnd_keys = dict_.keys_by_value(avg_bnd_ord_dct, lambda x: x == 1)

        beta_bnd_keys = ()
        for brk_bnd_key in brk_bnd_keys:
            if brk_bnd_key & rad_neighs:
                beta_bnd_keys += (brk_bnd_key, )

        for brk_bnd_key in beta_bnd_keys:
            prds_gra = remove_bonds(rct_gra, [brk_bnd_key])
            prd_gras = connected_components(prds_gra)

            if len(prd_gras) == 2:
                prd_gras = sort_reagents(prd_gras)

                forw_tsg = ts.graph(rct_gra,
                                    frm_bnd_keys=[],
                                    brk_bnd_keys=[brk_bnd_key])
                back_tsg = ts.graph(prds_gra,
                                    frm_bnd_keys=[brk_bnd_key],
                                    brk_bnd_keys=[])

                # Create the reaction object
                rxns.append(
                    Reaction(
                        rxn_cls=par.ReactionClass.Typ.BETA_SCISSION,
                        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)
コード例 #10
0
ファイル: _core.py プロジェクト: snelliott/automol
def bond_stereo_keys(sgr):
    """ keys to bond stereo-centers
    """
    bnd_ste_keys = dict_.keys_by_value(bond_stereo_parities(sgr),
                                       lambda x: x in [True, False])
    return bnd_ste_keys
コード例 #11
0
ファイル: _core.py プロジェクト: snelliott/automol
def atom_stereo_keys(sgr):
    """ keys to atom stereo-centers
    """
    atm_ste_keys = dict_.keys_by_value(atom_stereo_parities(sgr),
                                       lambda x: x in [True, False])
    return atm_ste_keys