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 _compare(gra1, gra2): """ Compare the backbone structure of two moleculare graphs. :param gra1: molecular graph 1 :type gra1: automol graph data structure :param gra2: molecular graph 2 :type gra2: automol graph data structure :rtype: bool """ gra1 = without_dummy_atoms(gra1) gra2 = without_dummy_atoms(gra2) return backbone_isomorphic(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 linear_segments_atom_keys(gra, lin_keys=None): """ atom keys for linear segments in the graph """ ngb_keys_dct = atoms_neighbor_atom_keys(without_dummy_atoms(gra)) lin_keys = (dummy_atoms_neighbor_atom_key(gra).values() if lin_keys is None else lin_keys) lin_keys = [k for k in lin_keys if len(ngb_keys_dct[k]) <= 2] lin_segs = connected_components(subgraph(gra, lin_keys)) lin_keys_lst = [] for lin_seg in lin_segs: lin_seg_keys = atom_keys(lin_seg) if len(lin_seg_keys) == 1: key, = lin_seg_keys lin_keys_lst.append([key]) else: end_key1, end_key2 = sorted([ key for key, ngb_keys in atoms_neighbor_atom_keys(lin_seg).items() if len(ngb_keys) == 1 ]) ngb_keys_dct = atoms_neighbor_atom_keys(lin_seg) key = None keys = [end_key1] while key != end_key2: key, = ngb_keys_dct[keys[-1]] - set(keys) keys.append(key) lin_keys_lst.append(keys) lin_keys_lst = tuple(map(tuple, lin_keys_lst)) return lin_keys_lst
def heavy_atom_count(gra, dummy=False): """ the number of heavy atoms """ if not dummy: gra = without_dummy_atoms(gra) atm_symb_dct = atom_symbols(gra) nhvy_atms = sum(ptab.to_number(sym) != 1 for sym in atm_symb_dct.values()) return nhvy_atms
def reverse(tsg, dummies=True): """ reverse a transition state graph """ if not dummies: tsg = without_dummy_atoms(tsg) return graph(gra=tsg, frm_bnd_keys=breaking_bond_keys(tsg), brk_bnd_keys=forming_bond_keys(tsg))
def atom_count(gra, dummy=False, with_implicit=True): """ count the number of atoms in this molecule by default, this includes implicit hydrogens and excludes dummy atoms """ if not dummy: gra = without_dummy_atoms(gra) natms = len(atoms(gra)) if with_implicit: atm_imp_hyd_vlc_dct = atom_implicit_hydrogen_valences(gra) natms += sum(atm_imp_hyd_vlc_dct.values()) return natms
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
def rotational_groups(gra, key1, key2, dummy=False): """ get the rotational groups for a given rotational axis :param gra: the graph :param key1: the first atom key :param key2: the second atom key """ if not dummy: gra = without_dummy_atoms(gra) bnd_key = frozenset({key1, key2}) assert bnd_key in bond_keys(gra) grp1 = branch_atom_keys(gra, key2, bnd_key) - {key1} grp2 = branch_atom_keys(gra, key1, bnd_key) - {key2} grp1 = tuple(sorted(grp1)) grp2 = tuple(sorted(grp2)) return grp1, grp2