示例#1
0
def is_stereo_compatible(tra, sgr1, sgr2):
    """ is this transformation compatible with the reactant/product stereo
    assignments?
    """
    cgr1 = without_stereo_parities(sgr1)
    cgr2 = without_stereo_parities(sgr2)
    atm_key_dct = _full_isomorphism(apply(tra, cgr1), cgr2)

    # determine the stereo centers which are preserved in the transformation
    sgr1 = _relabel(sgr1, atm_key_dct)
    atm_keys = sorted(atom_stereo_keys(sgr1) & atom_stereo_keys(sgr2))
    bnd_keys = sorted(bond_stereo_keys(sgr1) & bond_stereo_keys(sgr2))

    atm_pars1 = dict_.values_by_key(atom_stereo_parities(sgr1), atm_keys)
    atm_pars2 = dict_.values_by_key(atom_stereo_parities(sgr2), atm_keys)
    bnd_pars1 = dict_.values_by_key(bond_stereo_parities(sgr1), bnd_keys)
    bnd_pars2 = dict_.values_by_key(bond_stereo_parities(sgr2), bnd_keys)

    atm_ngb_keys_dct1 = atom_neighbor_keys(sgr1)
    atm_ngb_keys_dct2 = atom_neighbor_keys(sgr2)

    ret = True

    for atm_key, par1, par2 in zip(atm_keys, atm_pars1, atm_pars2):
        atm_ngb_keys1 = stereo_sorted_atom_neighbor_keys(
            sgr1, atm_key, atm_ngb_keys_dct1[atm_key])
        atm_ngb_keys2 = stereo_sorted_atom_neighbor_keys(
            sgr2, atm_key, atm_ngb_keys_dct2[atm_key])

        if _permutation_parity(atm_ngb_keys1, atm_ngb_keys2):
            ret &= (par1 == par2)
        else:
            ret &= (par1 != par2)

    for bnd_key, par1, par2 in zip(bnd_keys, bnd_pars1, bnd_pars2):
        atm1_key, atm2_key = bnd_key

        atm1_ngb_key1 = stereo_sorted_atom_neighbor_keys(
            sgr1, atm1_key, atm_ngb_keys_dct1[atm1_key] - {atm2_key})[0]
        atm2_ngb_key1 = stereo_sorted_atom_neighbor_keys(
            sgr1, atm2_key, atm_ngb_keys_dct1[atm2_key] - {atm1_key})[0]
        atm1_ngb_key2 = stereo_sorted_atom_neighbor_keys(
            sgr2, atm1_key, atm_ngb_keys_dct2[atm1_key] - {atm2_key})[0]
        atm2_ngb_key2 = stereo_sorted_atom_neighbor_keys(
            sgr2, atm2_key, atm_ngb_keys_dct2[atm2_key] - {atm1_key})[0]

        if not ((atm1_ngb_key1 != atm1_ngb_key2) ^
                (atm2_ngb_key1 != atm2_ngb_key2)):
            ret &= (par1 == par2)
        else:
            ret &= (par1 != par2)

    return ret
示例#2
0
def from_data(fml_str,
              main_lyr_dct=None,
              char_lyr_dct=None,
              ste_lyr_dct=None,
              iso_lyr_dct=None):
    """ Build a ChI string from each of the various layers.

        :param fml_str: formula string, in Hill-sort order
        :type fml_str: str
        :param main_lyr_dct: main layers, specifying connectivity and implicit
            hydrogens, by key ('c' and 'h')
        :type main_lyr_dct: dict[str: str]
        :param char_lyr_dct: charge layers, by key ('q' and 'p')
        :type char_lyr_dct: dict[str: str]
        :param ste_lyr_dct: stero layers, by key ('b', 't', 'm', and 's')
        :type ste_lyr_dct: dict[str: str]
        :param iso_lyr_dct: isotope layers, by key ('i', 'h', 'b', 't', 'm',
            and 's')
        :type iso_lyr_dct: dict[str: str]
        :rtype: str
    """

    main_dct = dict_.empty_if_none(main_lyr_dct)
    char_dct = dict_.empty_if_none(char_lyr_dct)
    ste_dct = dict_.empty_if_none(ste_lyr_dct)
    iso_dct = dict_.empty_if_none(iso_lyr_dct)

    main_lyrs = [
        pfx + lyr for pfx, lyr in zip(MAIN_PFXS,
                                      dict_.values_by_key(main_dct, MAIN_PFXS))
        if lyr
    ]
    char_lyrs = [
        pfx + lyr for pfx, lyr in zip(CHAR_PFXS,
                                      dict_.values_by_key(char_dct, CHAR_PFXS))
        if lyr
    ]
    ste_lyrs = [
        pfx + lyr
        for pfx, lyr in zip(STE_PFXS, dict_.values_by_key(ste_dct, STE_PFXS))
        if lyr
    ]
    iso_lyrs = [
        pfx + lyr
        for pfx, lyr in zip(ISO_PFXS, dict_.values_by_key(iso_dct, ISO_PFXS))
        if lyr
    ]

    chi = '/'.join(['AMChI=1', fml_str] + main_lyrs + char_lyrs + ste_lyrs +
                   iso_lyrs)

    return chi
示例#3
0
def add_atom_implicit_hydrogen_valences(gra, inc_atm_imp_hyd_vlc_dct):
    """ add atom imlicit hydrogen valences

    (increments can be positive or negative)
    """
    atm_keys = list(inc_atm_imp_hyd_vlc_dct.keys())
    atm_imp_hyd_vlcs = numpy.add(
        dict_.values_by_key(atom_implicit_hydrogen_valences(gra), atm_keys),
        dict_.values_by_key(inc_atm_imp_hyd_vlc_dct, atm_keys))
    assert all(atm_imp_hyd_vlc >= 0 for atm_imp_hyd_vlc in atm_imp_hyd_vlcs)
    atm_imp_hyd_vlc_dct = dict_.transform_values(
        dict(zip(atm_keys, atm_imp_hyd_vlcs)), int)
    return set_atom_implicit_hydrogen_valences(gra, atm_imp_hyd_vlc_dct)
示例#4
0
def _add_pi_bonds(rgr, bnd_ord_inc_dct):
    """ add pi bonds to this graph
    """
    bnd_keys = bond_keys(rgr)
    assert set(bnd_ord_inc_dct.keys()) <= bnd_keys

    bnd_keys = list(bnd_keys)
    bnd_ords = dict_.values_by_key(bond_orders(rgr), bnd_keys)
    bnd_ord_incs = dict_.values_by_key(bnd_ord_inc_dct, bnd_keys, fill_val=0)
    new_bnd_ords = numpy.add(bnd_ords, bnd_ord_incs)
    bnd_ord_dct = dict(zip(bnd_keys, new_bnd_ords))
    rgr = set_bond_orders(rgr, bnd_ord_dct)
    return rgr
示例#5
0
def atom_hybridizations(rgr):
    """ atom hybridizations, by atom
    """
    rgr = without_fractional_bonds(rgr)
    atm_keys = list(atom_keys(rgr))
    atm_unsat_vlc_dct = atom_unsaturated_valences(rgr, bond_order=True)
    atm_bnd_vlc_dct = atom_bond_valences(rgr, bond_order=False)  # note!!
    atm_unsat_vlcs = numpy.array(
        dict_.values_by_key(atm_unsat_vlc_dct, atm_keys))
    atm_bnd_vlcs = numpy.array(dict_.values_by_key(atm_bnd_vlc_dct, atm_keys))
    atm_lpcs = numpy.array(
        dict_.values_by_key(atom_lone_pair_counts(rgr), atm_keys))
    atm_hybs = atm_unsat_vlcs + atm_bnd_vlcs + atm_lpcs - 1
    atm_hyb_dct = dict_.transform_values(dict(zip(atm_keys, atm_hybs)), int)
    return atm_hyb_dct
示例#6
0
def atom_unsaturated_valences(gra, bond_order=True):
    """ unsaturated valences, by atom

    element valences minus bonding valences = pi sites and radical electrons
    """
    atm_keys = list(atom_keys(gra))
    if not bond_order:
        gra = without_bond_orders(gra)

    atm_bnd_vlcs = dict_.values_by_key(atom_bond_valences(gra), atm_keys)
    atm_tot_vlcs = dict_.values_by_key(atom_element_valences(gra), atm_keys)
    atm_rad_vlcs = numpy.subtract(atm_tot_vlcs, atm_bnd_vlcs)
    atm_unsat_vlc_dct = dict_.transform_values(
        dict(zip(atm_keys, atm_rad_vlcs)), int)
    return atm_unsat_vlc_dct
示例#7
0
def from_data(fml_slyr,
              main_lyr_dct=None,
              char_lyr_dct=None,
              ste_lyr_dct=None,
              iso_lyr_dct=None):
    """ Build an InChI string from each of the various layers.

        :param fml_slyr: sublayer of InChI string containing molecular formula
        :type fml_slyr: str
        :param main_lyr_dct: information for connectivity layer of InChI
        :type main_lyr_dct: dict[str: str]
        :param char_lyr_dct: information for charge layer of InChI
        :type char_lyr_dct: dict[str: str]
        :param ste_lyr_dct: information for stereochemistry layer of InChI
        :type ste_lyr_dct: dict[str: str]
        :param iso_lyr_dct: information for isotope layer of InChI
        :type iso_lyr_dct: dict[str: str]
        :rtype: str
    """

    main_dct = dict_.empty_if_none(main_lyr_dct)
    char_dct = dict_.empty_if_none(char_lyr_dct)
    ste_dct = dict_.empty_if_none(ste_lyr_dct)
    iso_dct = dict_.empty_if_none(iso_lyr_dct)

    main_slyrs = [
        pfx + slyr for pfx, slyr in zip(
            MAIN_PFXS, dict_.values_by_key(main_dct, MAIN_PFXS)) if slyr
    ]
    char_slyrs = [
        pfx + slyr for pfx, slyr in zip(
            CHAR_PFXS, dict_.values_by_key(char_dct, CHAR_PFXS)) if slyr
    ]
    ste_slyrs = [
        pfx + slyr
        for pfx, slyr in zip(STE_PFXS, dict_.values_by_key(ste_dct, STE_PFXS))
        if slyr
    ]
    iso_slyrs = [
        pfx + slyr
        for pfx, slyr in zip(ISO_PFXS, dict_.values_by_key(iso_dct, ISO_PFXS))
        if slyr
    ]

    ich = '/'.join(['InChI=1', fml_slyr] + main_slyrs + char_slyrs +
                   ste_slyrs + iso_slyrs)

    return ich
示例#8
0
def branch_bond_keys(gra, atm_key, bnd_key):
    """ bond keys for branch extending along `bnd_key` away from `atm_key`
    """

    # bnd_key is the set of atom indices for the bond of interest
    # atm_bnd_keys_dct is a dictionary of atoms that are connected to each atom
    bnd_key = frozenset(bnd_key)
    assert atm_key in bnd_key

    atm_bnd_keys_dct = atoms_bond_keys(gra)

    bnch_bnd_keys = {bnd_key}
    seen_bnd_keys = set()
    excl_bnd_keys = atm_bnd_keys_dct[atm_key] - {bnd_key}

    new_bnd_keys = {bnd_key}

    bnd_ngb_keys_dct = bonds_neighbor_bond_keys(gra)

    while new_bnd_keys:
        new_bnd_ngb_keys = set(
            itertools.chain(
                *dict_.values_by_key(bnd_ngb_keys_dct, new_bnd_keys)))
        bnch_bnd_keys.update(new_bnd_ngb_keys - excl_bnd_keys)
        seen_bnd_keys.update(new_bnd_keys)
        new_bnd_keys = bnch_bnd_keys - seen_bnd_keys

    return frozenset(bnch_bnd_keys)
示例#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 frozen(gra):
    """ hashable, sortable, immutable container of graph data
    """
    atm_keys = sorted(atom_keys(gra))
    bnd_keys = sorted(bond_keys(gra), key=sorted)

    # make it sortable by replacing Nones with -infinity
    atm_vals = numpy.array(dict_.values_by_key(atoms(gra), atm_keys),
                           dtype=numpy.object)
    bnd_vals = numpy.array(dict_.values_by_key(bonds(gra), bnd_keys),
                           dtype=numpy.object)
    atm_vals[numpy.equal(atm_vals, None)] = -numpy.inf
    bnd_vals[numpy.equal(bnd_vals, None)] = -numpy.inf

    frz_atms = tuple(zip(atm_keys, map(tuple, atm_vals)))
    frz_bnds = tuple(zip(bnd_keys, map(tuple, bnd_vals)))
    return (frz_atms, frz_bnds)
示例#11
0
def compatible_reverse_stereomers(ste_tsg):
    """ Given a TS graph with stereo assignments, expand all possible reverse
    graphs compatble with the forward graph.

    :param ste_tsg: The TS graph, with stereo assignments.
    :returns: All possible reverse TS graphs.
    """
    frm_bnd_keys = forming_bond_keys(ste_tsg)
    brk_bnd_keys = breaking_bond_keys(ste_tsg)
    _, des_ste_atm_keys = nonconserved_atom_stereo_keys(ste_tsg)
    _, des_ste_bnd_keys = nonconserved_bond_stereo_keys(ste_tsg)
    cons_atm_keys = sorted(atom_stereo_keys(ste_tsg) - des_ste_atm_keys)
    cons_bnd_keys = sorted(bond_stereo_keys(ste_tsg) - des_ste_bnd_keys)

    # 1. Determine index-based stereo assignments for conserved stereo centers
    idx_tsg = to_index_based_stereo(ste_tsg)
    cons_idx_atm_pars = dict_.values_by_key(atom_stereo_parities(idx_tsg),
                                            cons_atm_keys)
    cons_idx_bnd_pars = dict_.values_by_key(bond_stereo_parities(idx_tsg),
                                            cons_bnd_keys)

    # 2. Determine all possible index-based stereo assignments for the reverse
    #    reaction.
    prds_gra = without_stereo_parities(products_graph(ste_tsg))
    prds_sgrs = _stereomers(prds_gra)
    prds_idx_sgrs = list(map(_to_index_based_stereo, prds_sgrs))
    rev_idx_tsgs_pool = [
        graph(p, brk_bnd_keys, frm_bnd_keys) for p in prds_idx_sgrs
    ]

    # 3. Find possibilities which match the assignments for the conserved
    #    stereo centers.
    rev_idx_tsgs = []
    for rev_idx_tsg in rev_idx_tsgs_pool:
        rev_cons_idx_atm_pars = dict_.values_by_key(
            atom_stereo_parities(rev_idx_tsg), cons_atm_keys)
        rev_cons_idx_bnd_pars = dict_.values_by_key(
            bond_stereo_parities(rev_idx_tsg), cons_bnd_keys)
        if (rev_cons_idx_atm_pars == cons_idx_atm_pars
                and rev_cons_idx_bnd_pars == cons_idx_bnd_pars):
            rev_idx_tsgs.append(rev_idx_tsg)

    # 4. Convert the matching reverse graphs back from index-based stereo
    #    assignments to absolute stereo assignments.
    rev_ste_tsgs = list(map(from_index_based_stereo, rev_idx_tsgs))
    return rev_ste_tsgs
示例#12
0
def inchi_with_sort_from_geometry(gra, geo=None, geo_idx_dct=None):
    """ Generate an InChI string from a molecular graph.
        If coordinates are passed in, they are used to determine stereo.

        :param gra: molecular graph
        :type gra: automol graph data structure
        :param geo: molecular geometry
        :type geo: automol geometry data structure
        :param geo_idx_dct:
        :type geo_idx_dct: dict[:]
        :rtype: (str, tuple(int))
    """
    gra = without_dummy_atoms(gra)
    gra = dominant_resonance(gra)
    atm_keys = sorted(atom_keys(gra))
    bnd_keys = list(bond_keys(gra))
    atm_syms = dict_.values_by_key(atom_symbols(gra), atm_keys)
    atm_bnd_vlcs = dict_.values_by_key(atom_bond_valences(gra), atm_keys)
    atm_rad_vlcs = dict_.values_by_key(atom_unsaturated_valences(gra),
                                       atm_keys)
    bnd_ords = dict_.values_by_key(bond_orders(gra), bnd_keys)

    if geo is not None:
        assert geo_idx_dct is not None
        atm_xyzs = coordinates(geo)
        atm_xyzs = [
            atm_xyzs[geo_idx_dct[atm_key]] if atm_key in geo_idx_dct else
            (0., 0., 0.) for atm_key in atm_keys
        ]
    else:
        atm_xyzs = None

    mlf, key_map_inv = _molfile.from_data(atm_keys,
                                          bnd_keys,
                                          atm_syms,
                                          atm_bnd_vlcs,
                                          atm_rad_vlcs,
                                          bnd_ords,
                                          atm_xyzs=atm_xyzs)
    rdm = _rdkit.from_molfile(mlf)
    ich, aux_info = _rdkit.to_inchi(rdm, with_aux_info=True)
    nums = _parse_sort_order_from_aux_info(aux_info)
    nums = tuple(map(key_map_inv.__getitem__, nums))

    return ich, nums
示例#13
0
def atoms_from_data(atm_symb_dct,
                    atm_imp_hyd_vlc_dct=None,
                    atm_ste_par_dct=None):
    """ Construct an atom dictionary from constituent data.

        format:
            atm_dct := {atm_key: (atm_sym, atm_imp_hyd_vlc, atm_ste_par), ...}

        :param atm_symb_dct: atomic symbols, by atom key
        :type atm_symb_dct: dict
        :param atm_imp_hyd_vlc_dct: the no. of implicit hydrogens associated
            with each atom, by atom key
        :type atm_imp_hyd_vlc_dct: dict
        :param atm_ste_par_dct: atom stereo parities, by atom key
        :type atm_ste_par_dct: dict
    """

    keys = sorted(atm_symb_dct.keys())
    symbs = dict_.values_by_key(atm_symb_dct, keys)
    vlcs = dict_.values_by_key(dict_.empty_if_none(atm_imp_hyd_vlc_dct),
                               keys,
                               fill_val=0)
    pars = dict_.values_by_key(dict_.empty_if_none(atm_ste_par_dct),
                               keys,
                               fill_val=None)

    natms = len(symbs)
    vlcs = [0] * natms if vlcs is None else list(vlcs)
    pars = [None] * natms if pars is None else list(pars)

    assert len(vlcs) == natms
    assert len(pars) == natms

    symbs = list(map(ptab.to_symbol, symbs))
    vlcs = list(map(int, vlcs))

    assert all(par in (None, False, True) for par in pars)
    pars = [bool(par) if par is not None else par for par in pars]

    atm_dct = dict(zip(keys, zip(symbs, vlcs, pars)))

    return atm_dct
示例#14
0
def bonds_from_data(bnd_keys, bnd_ord_dct=None, bnd_ste_par_dct=None):
    """ construct bond dictionary graph from data

        format:
            bnd_dct := {bnd_key: (bnd_ord, bnd_ste_par), ...}
            [where bnd_key := frozenset({atm1_key, atm2_key})]

        :param bnd_keys: bond keys
        :type bnd_keys: set
        :param bnd_ord_dct: bond orders, by bond key
        :type bnd_ord_dct: dict
        :param bnd_ste_par_dct: bond stereo parities, by bond key
        :type bnd_ste_par_dct: dict
        :rtype: dict[frozenset({int}): tuple(str, str))]
    """

    keys = sorted(bnd_keys)
    assert all(len(key) == 2 for key in keys)
    ords = dict_.values_by_key(dict_.empty_if_none(bnd_ord_dct),
                               keys,
                               fill_val=1)
    pars = dict_.values_by_key(dict_.empty_if_none(bnd_ste_par_dct),
                               keys,
                               fill_val=None)

    nbnds = len(keys)

    ords = [1] * nbnds if ords is None else list(ords)
    pars = [None] * nbnds if pars is None else list(pars)

    assert len(ords) == nbnds
    assert len(pars) == nbnds

    keys = list(map(frozenset, keys))
    ords = [int(o) if round(o) == o else float(round(o, 1)) for o in ords]

    assert all(par in (None, False, True) for par in pars)
    pars = [bool(par) if par is not None else par for par in pars]

    bnd_dct = dict(zip(keys, zip(ords, pars)))

    return bnd_dct
示例#15
0
def molfile_with_atom_mapping(gra, geo=None, geo_idx_dct=None):
    """ Generate an MOLFile from a molecular graph.
        If coordinates are passed in, they are used to determine stereo.

        :param gra: molecular graph
        :type gra: automol graph data structure
        :param geo: molecular geometry
        :type geo: automol geometry data structure
        :param geo_idx_dct:
        :type geo_idx_dct: dict[:]
        :returns: the MOLFile string, followed by a mapping from MOLFile atoms
            to atoms in the graph
        :rtype: (str, dict)
    """
    gra = without_dummy_atoms(gra)
    gra = dominant_resonance(gra)
    atm_keys = sorted(atom_keys(gra))
    bnd_keys = list(bond_keys(gra))
    atm_syms = dict_.values_by_key(atom_symbols(gra), atm_keys)
    atm_bnd_vlcs = dict_.values_by_key(atom_bond_valences(gra), atm_keys)
    atm_rad_vlcs = dict_.values_by_key(atom_unsaturated_valences(gra),
                                       atm_keys)
    bnd_ords = dict_.values_by_key(bond_orders(gra), bnd_keys)

    if geo is not None:
        assert geo_idx_dct is not None
        atm_xyzs = automol.geom.base.coordinates(geo)
        atm_xyzs = [
            atm_xyzs[geo_idx_dct[atm_key]] if atm_key in geo_idx_dct else
            (0., 0., 0.) for atm_key in atm_keys
        ]
    else:
        atm_xyzs = None

    mlf, key_map_inv = molfile.from_data(atm_keys,
                                         bnd_keys,
                                         atm_syms,
                                         atm_bnd_vlcs,
                                         atm_rad_vlcs,
                                         bnd_ords,
                                         atm_xyzs=atm_xyzs)
    return mlf, key_map_inv
示例#16
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
示例#17
0
def from_graph(gra):
    """ igraph object from a molecular graph
    """
    atm_keys = sorted(atom_keys(gra))
    bnd_keys = sorted(bond_keys(gra), key=sorted)

    atm_vals = dict_.values_by_key(atoms(gra), atm_keys)
    bnd_vals = dict_.values_by_key(bonds(gra), bnd_keys)

    atm_colors = list(itertools.starmap(_encode_vertex_attributes, atm_vals))
    bnd_colors = list(itertools.starmap(_encode_edge_attributes, bnd_vals))

    atm_idx_dct = dict(map(reversed, enumerate(atm_keys)))
    bnd_idxs = [sorted(map(atm_idx_dct.__getitem__, k)) for k in bnd_keys]
    igr = igraph.Graph(bnd_idxs)

    igr.vs['keys'] = atm_keys
    igr.vs['color'] = atm_colors
    igr.es['color'] = bnd_colors

    return igr
示例#18
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
示例#19
0
def atom_bond_valences(gra, bond_order=True):
    """ bond count (bond valence), by atom
    """
    atm_keys = list(atom_keys(gra))
    gra = explicit(gra)
    if not bond_order:
        gra = without_bond_orders(gra)

    atm_nbhs = dict_.values_by_key(atom_neighborhoods(gra), atm_keys)
    atm_bnd_vlcs = [sum(bond_orders(nbh).values()) for nbh in atm_nbhs]
    atm_bnd_vlc_dct = dict_.transform_values(dict(zip(atm_keys, atm_bnd_vlcs)),
                                             int)
    return atm_bnd_vlc_dct
示例#20
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
示例#21
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
示例#22
0
def sing_res_dom_radical_atom_keys(rgr):
    """ resonance-dominant radical atom keys,for one 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)
    ]
    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
示例#23
0
def terminal_heavy_atom_keys(gra):
    """ terminal heavy atoms, sorted by atom type and hydrogen count
    """
    gra = implicit(gra)
    atm_imp_hyd_vlc_dct = atom_implicit_hydrogen_valences(gra)
    atm_keys = [
        key for key, ngb_keys in atoms_neighbor_atom_keys(gra).items()
        if len(ngb_keys) == 1
    ]
    atm_keys = sorted(atm_keys,
                      key=atm_imp_hyd_vlc_dct.__getitem__,
                      reverse=True)
    atm_symbs = dict_.values_by_key(atom_symbols(gra), atm_keys)
    srt = automol.formula.argsort_symbols(atm_symbs, symbs_first=('C', ))
    atm_keys = tuple(map(atm_keys.__getitem__, srt))
    return atm_keys
示例#24
0
def resonance_dominant_radical_atom_keys(rgr):
    """ resonance-dominant radical atom keys

    (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
示例#25
0
def atom_stereo_parity_from_geometry(gra, atm_key, geo, geo_idx_dct):
    """ get the current stereo parity of an atom from its geometry
    """
    atm_ngb_keys_dct = atoms_neighbor_atom_keys(gra)
    atm_ngb_keys = atm_ngb_keys_dct[atm_key]

    # sort the neighbor keys by stereo priority
    atm_ngb_keys = atom_stereo_sorted_neighbor_atom_keys(
        gra, atm_key, atm_ngb_keys)

    # determine the parity based on the coordinates
    xyzs = automol.geom.base.coordinates(geo)
    atm_ngb_idxs = dict_.values_by_key(geo_idx_dct, atm_ngb_keys)
    atm_ngb_xyzs = [xyzs[idx] for idx in atm_ngb_idxs]
    det_mat = numpy.ones((4, 4))
    det_mat[:, :3] = atm_ngb_xyzs
    det_val = numpy.linalg.det(det_mat)
    assert det_val != 0.  # for now, assume no four-atom planes
    par = det_val > 0.
    return par
示例#26
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
示例#27
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