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 = atom_neighbor_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_sym_num_dct = {} bnd_sym_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_sym_nums.append(bnd_sym) bnd_sym_num_dct = dict(zip(bnd_keys, bnd_sym_nums)) # fill in the rest of the bonds for completeness bnd_sym_num_dct = dict_.by_key(bnd_sym_num_dct, bond_keys(gra), fill_val=1) return bnd_sym_num_dct
def add_bonds(gra, keys, ord_dct=None, ste_par_dct=None, check=True): """ add bonds to this molecular graph """ bnd_keys = set(bond_keys(gra)) bnd_ord_dct = bond_orders(gra) bnd_ste_par_dct = bond_stereo_parities(gra) keys = set(map(frozenset, keys)) ord_dct = {} if ord_dct is None else ord_dct ste_par_dct = {} if ste_par_dct is None else ste_par_dct if check: assert not keys & bnd_keys, ( '{} and {} have a non-empty intersection'.format(keys, bnd_keys)) assert set(ord_dct.keys()) <= keys assert set(ste_par_dct.keys()) <= keys bnd_keys.update(keys) bnd_ord_dct.update(ord_dct) bnd_ste_par_dct.update(ste_par_dct) atm_dct = atoms(gra) bnd_dct = _create.bonds_from_data(bond_keys=bnd_keys, bond_orders=bnd_ord_dct, bond_stereo_parities=bnd_ste_par_dct) gra = _create.from_atoms_and_bonds(atoms=atm_dct, bonds=bnd_dct) return gra
def without_stereo_parities(gra): """ graph with stereo assignments wiped out """ atm_ste_par_dct = dict_.by_key({}, atom_keys(gra), fill_val=None) bnd_ste_par_dct = dict_.by_key({}, bond_keys(gra), fill_val=None) gra = set_atom_stereo_parities(gra, atm_ste_par_dct) gra = set_bond_stereo_parities(gra, bnd_ste_par_dct) return gra
def subgraph(gra, atm_keys): """ the subgraph induced by a subset of the atoms """ atm_keys = set(atm_keys) assert atm_keys <= atom_keys(gra) bnd_keys = set(filter(lambda x: x <= atm_keys, bond_keys(gra))) atm_dct = dict_.by_key(atoms(gra), atm_keys) bnd_dct = dict_.by_key(bonds(gra), bnd_keys) return _create.from_atoms_and_bonds(atm_dct, bnd_dct)
def without_bond_orders(gra): """ resonance graph with maximum spin (i.e. no pi bonds) """ bnd_keys = list(bond_keys(gra)) # don't set dummy bonds to one! bnd_ord_dct = bond_orders(gra) bnd_vals = [ 1 if v != 0 else 0 for v in map(bnd_ord_dct.__getitem__, bnd_keys) ] bnd_ord_dct = dict(zip(bnd_keys, bnd_vals)) return set_bond_orders(gra, bnd_ord_dct)
def bond_neighborhoods(gra): """ neighborhood subgraphs, by bond """ bnd_keys = list(bond_keys(gra)) def _neighborhood(bnd_key): nbh_bnd_keys = set(filter(lambda x: bnd_key & x, bnd_keys)) return bond_induced_subgraph(gra, nbh_bnd_keys) bnd_nbh_dct = dict(zip(bnd_keys, map(_neighborhood, bnd_keys))) return bnd_nbh_dct
def atom_neighborhoods(gra): """ neighborhood subgraphs, by atom """ bnd_keys = bond_keys(gra) def _neighborhood(atm_key): nbh_bnd_keys = set(filter(lambda x: atm_key in x, bnd_keys)) return bond_induced_subgraph(gra, nbh_bnd_keys) atm_keys = list(atom_keys(gra)) atm_nbh_dct = dict(zip(atm_keys, map(_neighborhood, atm_keys))) return atm_nbh_dct
def remove_bonds(gra, bnd_keys, check=True): """ remove bonds from the molecular graph """ all_bnd_keys = bond_keys(gra) bnd_keys = set(map(frozenset, bnd_keys)) if check: assert bnd_keys <= all_bnd_keys bnd_keys = all_bnd_keys - bnd_keys atm_dct = atoms(gra) bnd_dct = dict_.by_key(bonds(gra), bnd_keys) return _create.from_atoms_and_bonds(atm_dct, bnd_dct)
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)) bnd_vals = numpy.array(dict_.values_by_key(bonds(gra), bnd_keys)) 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)
def from_graph(gra): """ networkx graph object from a molecular graph """ nxg = networkx.Graph() nxg.add_nodes_from(atom_keys(gra)) nxg.add_edges_from(bond_keys(gra)) networkx.set_node_attributes(nxg, atom_symbols(gra), 'symbol') networkx.set_node_attributes(nxg, atom_implicit_hydrogen_valences(gra), 'implicit_hydrogen_valence') networkx.set_node_attributes(nxg, atom_stereo_parities(gra), 'stereo_parity') networkx.set_edge_attributes(nxg, bond_orders(gra), 'order') networkx.set_edge_attributes(nxg, bond_stereo_parities(gra), 'stereo_parity') return nxg
def _neighbor_keys(bnd_key, bnd_nbh): return frozenset(bond_keys(bnd_nbh) - {bnd_key})