def isomorphism(gra1, gra2, backbone_only=False, stereo=True, dummy=True): """ Obtain an isomorphism between two graphs This should eventually replace the other isomorphism functions. :param backbone_only: Compare backbone atoms only? :type backbone_only: bool :param stereo: Consider stereo? :type stereo: bool :param dummy: Consider dummy atoms? :type dummy: bool :returns: The isomorphism mapping `gra1` onto `gra2` :rtype: dict """ if backbone_only: gra1 = implicit(gra1) gra2 = implicit(gra2) if not stereo: gra1 = without_stereo_parities(gra1) gra2 = without_stereo_parities(gra2) if not dummy: gra1 = without_dummy_atoms(gra1) gra2 = without_dummy_atoms(gra2) return _isomorphism(gra1, gra2)
def rotational_symmetry_number(gra, key1, key2, lin_keys=None): """ get the rotational symmetry number along a given rotational axis :param gra: the graph :param key1: the first atom key :param key2: the second atom key """ ngb_keys_dct = atoms_neighbor_atom_keys(without_dummy_atoms(gra)) imp_hyd_vlc_dct = atom_implicit_hydrogen_valences(implicit(gra)) axis_keys = {key1, key2} # If the keys are part of a linear chain, use the ends of that for the # symmetry number calculation lin_keys_lst = linear_segments_atom_keys(gra, lin_keys=lin_keys) for keys in lin_keys_lst: if key1 in keys or key2 in keys: if len(keys) == 1: key1, key2 = sorted(ngb_keys_dct[keys[0]]) else: key1, = ngb_keys_dct[keys[0]] - {keys[1]} key2, = ngb_keys_dct[keys[-1]] - {keys[-2]} axis_keys |= set(keys) break sym_num = 1 for key in (key1, key2): if key in imp_hyd_vlc_dct: ngb_keys = ngb_keys_dct[key] - axis_keys if len(ngb_keys) == imp_hyd_vlc_dct[key] == 3: sym_num = 3 break return sym_num
def bond_symmetry_numbers(gra, frm_bnd_key=None, brk_bnd_key=None): """ symmetry numbers, by bond the (approximate) symmetry number of the torsional potential for this bond, based on the hydrogen counts for each atom It is reduced to 1 if one of the H atoms in the torsional bond is a neighbor to the special bonding atom (the atom that is being transferred) """ imp_gra = implicit(gra) atm_imp_hyd_vlc_dct = atom_implicit_hydrogen_valences(imp_gra) bnd_keys = bond_keys(imp_gra) tfr_atm = None if frm_bnd_key and brk_bnd_key: for atm_f in list(frm_bnd_key): for atm_b in list(brk_bnd_key): if atm_f == atm_b: tfr_atm = atm_f if tfr_atm: neighbor_dct = atoms_neighbor_atom_keys(gra) nei_tfr = neighbor_dct[tfr_atm] atms = gra[0] all_hyds = [] for atm in atms: if atms[atm][0] == 'H': all_hyds.append(atm) else: nei_tfr = {} bnd_symb_num_dct = {} bnd_symb_nums = [] for bnd_key in bnd_keys: bnd_sym = 1 vlc = max(map(atm_imp_hyd_vlc_dct.__getitem__, bnd_key)) if vlc == 3: bnd_sym = 3 if tfr_atm: for atm in nei_tfr: nei_s = neighbor_dct[atm] h_nei = 0 for nei in nei_s: if nei in all_hyds: h_nei += 1 if h_nei == 3: bnd_sym = 1 bnd_symb_nums.append(bnd_sym) bnd_symb_num_dct = dict(zip(bnd_keys, bnd_symb_nums)) # fill in the rest of the bonds for completeness bnd_symb_num_dct = dict_.by_key(bnd_symb_num_dct, bond_keys(gra), fill_val=1) return bnd_symb_num_dct
def backbone_isomorphism(gra1, gra2, igraph=False): """ graph backbone isomorphism for implicit graphs, this is the relabeling of `gra1` to produce `gra2` for other graphs, it gives the correspondences between backbone atoms """ gra1 = implicit(gra1) gra2 = implicit(gra2) if igraph: igr1 = _igraph.from_graph(gra1) igr2 = _igraph.from_graph(gra2) iso_dcts = _igraph.isomorphisms(igr1, igr2) iso_dct = iso_dcts[0] if iso_dcts else None else: nxg1 = _networkx.from_graph(gra1) nxg2 = _networkx.from_graph(gra2) iso_dct = _networkx.isomorphism(nxg1, nxg2) return iso_dct
def is_branched(gra): """ determine is the molecule has a branched chain """ _is_branched = False gra = implicit(gra) chain_length = len(longest_chain(gra)) natoms = atom_count(gra, with_implicit=False) if natoms != chain_length: _is_branched = True return _is_branched
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
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
def _inchi_connected_graph(ich, stereo=True): """ Generate a molecular graph from an InChI string where all all atoms are connected by at least one bond. :param ich: InChI string d :type ich: str :param remove_stereo: parameter to include stereochemistry information :type remove_stereo: bool :rtype: automol molecular graph """ gra = object_from_hardcoded_inchi_by_key('graph', ich) if gra is None: ich = standard_form(ich) if not stereo or not has_stereo(ich): rdm = _rdkit.from_inchi(ich) gra = _rdkit.to_connectivity_graph(rdm) else: geo = geometry(ich) gra = graph(geo, stereo=stereo) gra = implicit(gra) return gra