예제 #1
0
def dominant_resonances(rgr):
    """ all dominant (minimum spin/maximum pi) resonance graphs
    """
    rgr = without_fractional_bonds(rgr)
    rgrs = resonances(rgr)
    mult_min = min(map(maximum_spin_multiplicity, rgrs))
    dom_rgrs = tuple(rgr for rgr in rgrs
                     if maximum_spin_multiplicity(rgr) == mult_min)
    return dom_rgrs
예제 #2
0
def radical_groups(gra):
    """ returns a list of lists of groups attached each radical
    """
    gra = without_fractional_bonds(gra)

    groups = []
    rads = sing_res_dom_radical_atom_keys(gra)
    for rad in rads:
        groups.append(atom_groups(gra, rad))
    return groups
예제 #3
0
def resonance_dominant_atom_hybridizations(rgr):
    """ resonance-dominant atom hybridizations, by atom
    """
    rgr = without_fractional_bonds(rgr)
    atm_keys = list(atom_keys(rgr))
    atm_hybs_by_res = [
        dict_.values_by_key(atom_hybridizations(dom_rgr), atm_keys)
        for dom_rgr in dominant_resonances(rgr)
    ]
    atm_hybs = [min(hybs) for hybs in zip(*atm_hybs_by_res)]
    atm_hyb_dct = dict(zip(atm_keys, atm_hybs))
    return atm_hyb_dct
예제 #4
0
def resonance_dominant_bond_orders(rgr):
    """ resonance-dominant bond orders, by bond
    """
    rgr = without_fractional_bonds(rgr)
    bnd_keys = list(bond_keys(rgr))
    bnd_ords_by_res = [
        dict_.values_by_key(bond_orders(dom_rgr), bnd_keys)
        for dom_rgr in dominant_resonances(rgr)
    ]
    bnd_ords_lst = list(map(frozenset, zip(*bnd_ords_by_res)))
    bnd_dom_res_ords_dct = dict(zip(bnd_keys, bnd_ords_lst))
    return bnd_dom_res_ords_dct
예제 #5
0
def nonresonant_radical_atom_keys(rgr):
    """ keys for radical atoms that are not in resonance
    """
    rgr = without_fractional_bonds(rgr)
    atm_keys = list(atom_keys(rgr))
    atm_rad_vlcs_by_res = [
        dict_.values_by_key(atom_unsaturated_valences(dom_rgr), atm_keys)
        for dom_rgr in dominant_resonances(rgr)
    ]
    atm_rad_vlcs = [min(rad_vlcs) for rad_vlcs in zip(*atm_rad_vlcs_by_res)]
    atm_rad_keys = frozenset(
        atm_key for atm_key, atm_rad_vlc in zip(atm_keys, atm_rad_vlcs)
        if atm_rad_vlc)
    return atm_rad_keys
예제 #6
0
def resonance_avg_bond_orders(rgr):
    """ resonance-dominant bond orders, by bond
    """
    rgr = without_fractional_bonds(rgr)
    bnd_keys = list(bond_keys(rgr))
    bnd_ords_by_res = [
        dict_.values_by_key(bond_orders(dom_rgr), bnd_keys)
        for dom_rgr in dominant_resonances(rgr)
    ]
    nres = len(bnd_ords_by_res)
    bnd_ords_lst = zip(*bnd_ords_by_res)
    avg_bnd_ord_lst = [sum(bnd_ords) / nres for bnd_ords in bnd_ords_lst]
    avg_bnd_ord_dct = dict(zip(bnd_keys, avg_bnd_ord_lst))
    return avg_bnd_ord_dct
예제 #7
0
def sigma_radical_atom_keys(rgr):
    """ keys for sigma radical atoms
    """
    rgr = without_fractional_bonds(rgr)
    atm_rad_keys = nonresonant_radical_atom_keys(rgr)
    bnd_ords_dct = resonance_dominant_bond_orders(rgr)
    atm_bnd_keys_dct = atoms_bond_keys(rgr)
    atm_sig_keys = []
    for atm_key in atm_rad_keys:
        for bnd_key in atm_bnd_keys_dct[atm_key]:
            if 3 in bnd_ords_dct[bnd_key]:
                atm_sig_keys.append(atm_key)
                break
    atm_sig_keys = frozenset(atm_sig_keys)
    return atm_sig_keys
예제 #8
0
def radical_group_dct(gra):
    """ return a dictionary of lists of groups attached each radical
    """
    gra = without_fractional_bonds(gra)

    groups = {}
    rads = list(sing_res_dom_radical_atom_keys(gra))
    atms = atoms(gra)
    for rad in rads:
        key = atms[rad][0]
        if key in groups:
            groups[atms[rad][0]] += atom_groups(gra, rad)
        else:
            groups[atms[rad][0]] = atom_groups(gra, rad)

    return groups
예제 #9
0
def radical_atom_keys(gra, single_res=False, min_valence=1.):
    """ Radical atom keys for this molecular graph

    Radical atoms are based on the lowest-spin resonance structures for this
    graph. If the `single_res` flag is set, a single low-spin resonance
    structure will be chosen when there are multiple such structures.

    This function should eventually replace both
    `resonance_dominant_radical_atom_keys` and
    `sing_res_dom_radical_atom_keys` for a more user-friendly interface.

    Note that this function ignores the bond orders in `gra`. If you wish to
    identify radical atom keys based on the bond orders in `gra`, this can be
    done by using the `atom_unsaturated_valences` function.

    :param gra: the molecular graph
    :param single_res: only include radical keys for a single (arbitrary)
        resonance structure, or include all atoms that are radicals in any of
        the low-spin resonance structures?
    :type single_res: bool
    :param min_valence: optionally, specify that only sites with at least a
        certain number of radical electrons be included
    :type min_valence: int
    :returns: the radical atom keys
    :rtype: frozenset[int]

    """
    gra = without_fractional_bonds(gra)
    atm_keys = list(atom_keys(gra))

    if single_res:
        atm_rad_vlcs = dict_.values_by_key(
            atom_unsaturated_valences(dominant_resonance(gra)), atm_keys)
    else:
        atm_rad_vlcs_by_res = [
            dict_.values_by_key(atom_unsaturated_valences(dom_gra), atm_keys)
            for dom_gra in dominant_resonances(gra)
        ]
        atm_rad_vlcs = [
            max(rad_vlcs) for rad_vlcs in zip(*atm_rad_vlcs_by_res)
        ]

    atm_rad_keys = frozenset(
        atm_key for atm_key, atm_rad_vlc in zip(atm_keys, atm_rad_vlcs)
        if atm_rad_vlc >= min_valence)
    return atm_rad_keys
예제 #10
0
def sing_res_dom_radical_atom_keys(rgr):
    """ resonance-dominant radical atom keys,for one resonance

    TODO: DEPRECATE
    """
    rgr = without_fractional_bonds(rgr)
    atm_keys = list(atom_keys(rgr))
    atm_rad_vlcs_by_res = [
        dict_.values_by_key(atom_unsaturated_valences(dom_rgr), atm_keys)
        for dom_rgr in dominant_resonances(rgr)
    ]
    first_atm_rad_val = [atm_rad_vlcs_by_res[0]]
    atm_rad_vlcs = [max(rad_vlcs) for rad_vlcs in zip(*first_atm_rad_val)]
    atm_rad_keys = frozenset(
        atm_key for atm_key, atm_rad_vlc in zip(atm_keys, atm_rad_vlcs)
        if atm_rad_vlc)
    return atm_rad_keys
예제 #11
0
def resonance_dominant_atom_centered_cumulene_keys(rgr):
    """ resonance dominant keys for atom-centered cumulenes

    the bond-centered cumulenes are described by
        (frozenset({end_atm_key1, end_atm_key2}), cent_atm_key)
    where the first pair contains the sp2 atoms at the cumulene ends and
    `cent_atm_key` is the key of the central atom
    """
    rgr = without_fractional_bonds(rgr)
    cum_chains = _cumulene_chains(rgr)
    cum_keys = set()
    for cum_chain in cum_chains:
        size = len(cum_chain)
        if size % 2 == 1:
            cum_keys.add((frozenset({cum_chain[0],
                                     cum_chain[-1]}), cum_chain[size // 2]))
    cum_keys = frozenset(cum_keys)
    return cum_keys
예제 #12
0
def radical_dissociation_prods(gra, pgra1):
    """ given a dissociation product, determine the other product
    """
    gra = without_fractional_bonds(gra)

    pgra2 = None
    rads = sing_res_dom_radical_atom_keys(gra)
    adj_atms = atoms_neighbor_atom_keys(gra)
    # adj_idxs = tuple(adj_atms[rad] for rad in rads)
    for rad in rads:
        for adj in adj_atms[rad]:
            for group in atom_groups(gra, adj, stereo=False):
                if isomorphism(group, pgra1, backbone_only=True):
                    pgra2 = remove_atoms(gra, atom_keys(group))
                    # pgra2 = remove_bonds(pgra2, bond_keys(group))
                    if bond_keys(group) in pgra2:
                        pgra2 = remove_bonds(pgra2, bond_keys(group))
    return (pgra1, pgra2)
예제 #13
0
def resonance_dominant_radical_atom_keys(rgr):
    """ resonance-dominant radical atom keys

    TODO: DEPRECATE

    (keys of resonance-dominant radical sites)
    """
    rgr = without_fractional_bonds(rgr)
    atm_keys = list(atom_keys(rgr))
    atm_rad_vlcs_by_res = [
        dict_.values_by_key(atom_unsaturated_valences(dom_rgr), atm_keys)
        for dom_rgr in dominant_resonances(rgr)
    ]
    atm_rad_vlcs = [max(rad_vlcs) for rad_vlcs in zip(*atm_rad_vlcs_by_res)]
    atm_rad_keys = frozenset(
        atm_key for atm_key, atm_rad_vlc in zip(atm_keys, atm_rad_vlcs)
        if atm_rad_vlc)
    return atm_rad_keys
예제 #14
0
def sigma_radical_atom_keys(rgr):
    """ keys for sigma radical atoms

    :param rgr: the molecular graph
    :returns: the sigma radical atom keys
    :rtype: frozenset[int]
    """
    rgr = without_fractional_bonds(rgr)
    atm_rad_keys = nonresonant_radical_atom_keys(rgr)
    bnd_ords_dct = resonance_dominant_bond_orders(rgr)
    atm_bnd_keys_dct = atoms_bond_keys(rgr)
    atm_sig_keys = []
    for atm_key in atm_rad_keys:
        for bnd_key in atm_bnd_keys_dct[atm_key]:
            if 3 in bnd_ords_dct[bnd_key]:
                atm_sig_keys.append(atm_key)
                break
    atm_sig_keys = frozenset(atm_sig_keys)
    return atm_sig_keys
예제 #15
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
예제 #16
0
def subresonances(rgr):
    """ this connected graph and its lower-spin (more pi-bonded) resonances
    """
    rgr = without_fractional_bonds(rgr)
    # get the bond capacities (room for increasing bond order), filtering out
    # the negative ones to avoid complications with hypervalent atoms in TSs
    bnd_cap_dct = dict_.by_value(_bond_capacities(rgr), lambda x: x > 0)

    ret_rgrs = []
    if bnd_cap_dct:
        bnd_keys, bnd_caps = zip(*bnd_cap_dct.items())
        atm_keys = list(functools.reduce(frozenset.union, bnd_keys))

        # Loop over all possible combinations of bond order increments (amounts
        # by which to increase the bond order), filtering out combinations that
        # exceed the valences of the atoms involved.
        # (Note that we are only testing the bonds with available pi electrons,
        # so this is compatible with having hypervalent atoms elsewhere in the
        # molecule)
        bnd_ord_inc_ranges = [range(bnd_cap + 1) for bnd_cap in bnd_caps]
        for bnd_ord_incs in itertools.product(*bnd_ord_inc_ranges):
            bnd_ord_inc_dct = dict(zip(bnd_keys, bnd_ord_incs))
            ret_rgr = _add_pi_bonds(rgr, bnd_ord_inc_dct)

            max_bnd_ord = max(bond_orders(ret_rgr).values())

            atm_unsat_vlcs = dict_.values_by_key(
                atom_unsaturated_valences(ret_rgr), atm_keys)

            if not any(atm_unsat_vlc < 0 for atm_unsat_vlc in atm_unsat_vlcs):
                if max_bnd_ord < 4:
                    ret_rgrs.append(ret_rgr)

    if not ret_rgrs:
        ret_rgrs = (rgr, )
    else:
        ret_rgrs = tuple(ret_rgrs)

    return ret_rgrs
예제 #17
0
def radical_atom_keys_from_resonance(rgr, min_valence=1.):
    """ Radical atom keys for a resonance molecular graph

    Assumes the graph has already been assinged to a resonance structure.

    :param rgr: a resonance-structure molecular graph
    :param min_valence: optionally, specify that only sites with at least a
        certain number of radical electrons be included
    :type min_valence: int
    :returns: the radical atom keys
    :rtype: frozenset[int]

    """
    rgr = without_fractional_bonds(rgr)
    atm_keys = list(atom_keys(rgr))

    atm_rad_vlcs = dict_.values_by_key(atom_unsaturated_valences(rgr),
                                       atm_keys)

    atm_rad_keys = frozenset(
        atm_key for atm_key, atm_rad_vlc in zip(atm_keys, atm_rad_vlcs)
        if atm_rad_vlc >= min_valence)
    return atm_rad_keys
예제 #18
0
def radical_dissociation_products(gra, pgra1):
    """ For a given species, determine the products of a dissociation
        occuring around a radical site. We assume one of the
        dissociation products is known, and we attempt to find the
        corresponding product.

        Currently, we assume that the input pgra1 is appropriately
        stereolabeled.

        :param gra: species undergoing dissociation
        :type gra: automol.graph object
        :param pgra1: one of the known products of dissociation
        :type pgra1: automol.graph object
        :rtype: tuple(automol.graph.object)
    """

    # Remove gractional bonds for functions to work
    gra = without_fractional_bonds(gra)

    # Attempt to find a graph of product corresponding to pgra1
    pgra2 = None
    for rad in sing_res_dom_radical_atom_keys(gra):
        for adj in atoms_neighbor_atom_keys(gra)[rad]:
            for group in atom_groups(gra, adj, stereo=False):
                if isomorphism(group, pgra1, backbone_only=True):
                    pgra2 = remove_atoms(gra, atom_keys(group))
                    if bond_keys(group) in pgra2:
                        pgra2 = remove_bonds(pgra2, bond_keys(group))

    # If pgra2 is ID'd, rebuild the two product graphs with stereo labels
    if pgra2 is not None:
        keys2 = atom_keys(pgra2)
        idx_gra = to_index_based_stereo(gra)
        idx_pgra2 = subgraph(idx_gra, keys2, stereo=True)
        pgra2 = from_index_based_stereo(idx_pgra2)

    return pgra1, pgra2