def from_data(formula_sublayer, main_sublayer_dct=None, charge_sublayer_dct=None, stereo_sublayer_dct=None, isotope_sublayer_dct=None): """ calculate an inchi string from layers """ main_dct = dict_.empty_if_none(main_sublayer_dct) char_dct = dict_.empty_if_none(charge_sublayer_dct) ste_dct = dict_.empty_if_none(stereo_sublayer_dct) iso_dct = dict_.empty_if_none(isotope_sublayer_dct) fml_slyr = formula_sublayer 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
def inchi_with_sort_from_coordinates(gra, atm_xyz_dct=None): """ connectivity graph => inchi conversion (if coordinates are passed in, they are used to determine stereo) """ gra = automol.graph.without_dummy_atoms(gra) gra = automol.graph.dominant_resonance(gra) atm_keys = list(automol.graph.atom_keys(gra)) bnd_keys = list(automol.graph.bond_keys(gra)) atm_syms = dict_.values_by_key(automol.graph.atom_symbols(gra), atm_keys) atm_bnd_vlcs = dict_.values_by_key( automol.graph.atom_bond_valences(gra), atm_keys) atm_rad_vlcs = dict_.values_by_key( automol.graph.atom_unsaturated_valences(gra), atm_keys) bnd_ords = dict_.values_by_key(automol.graph.bond_orders(gra), bnd_keys) atm_xyzs = (None if atm_xyz_dct is None else dict_.values_by_key(atm_xyz_dct, atm_keys)) 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 heuristic_geometry(xgr): """ heuristic geometry for this molecular graph """ xgr = _explicit(xgr) atm_keys = sorted(_atom_keys(xgr)) syms = dict_.values_by_key(_atom_symbols(xgr), atm_keys) xyzs = dict_.values_by_key(atom_stereo_coordinates(xgr), atm_keys) geo = automol.create.geom.from_data(syms, xyzs) return geo
def geometry(gra): """ graph => geometry """ gra = automol.graph.explicit(gra) atm_keys = sorted(automol.graph.atom_keys(gra)) atm_syms = dict_.values_by_key(automol.graph.atom_symbols(gra), atm_keys) atm_xyzs = dict_.values_by_key( automol.graph.atom_stereo_coordinates(gra), atm_keys) geo = automol.create.geom.from_data(atm_syms, atm_xyzs) return geo
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
def add_atom_implicit_hydrogen_valences(xgr, 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(xgr), 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(xgr, atm_imp_hyd_vlc_dct)
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
def _is_valid(bnd_ord_inc_dct): # check if pi bonds exceed unsaturated valences def __tally(atm_bnd_keys): return sum(dict_.values_by_key(bnd_ord_inc_dct, atm_bnd_keys)) atm_unsat_vlc_decs = tuple(map(__tally, atm_bnd_keys_lst)) enough_elecs = numpy.all( numpy.less_equal(atm_unsat_vlc_decs, atm_unsat_vlcs)) # check if all bond orders are less than 4 (should only affect C2) bnd_inc_keys = bnd_ord_inc_dct.keys() bnd_incs = dict_.values_by_key(bnd_ord_inc_dct, bnd_inc_keys) bnd_ords = dict_.values_by_key(bnd_ord_dct, bnd_inc_keys) new_bnd_ords = numpy.add(bnd_ords, bnd_incs) not_too_many = numpy.all(numpy.less(new_bnd_ords, 4)) return enough_elecs and not_too_many
def atom_unsaturated_valences(xgr, bond_order=True): """ unsaturated valences, by atom (element valences minus bonding valences -- pi sites and radical electrons) """ atm_keys = list(atom_keys(xgr)) if not bond_order: xgr = without_bond_orders(xgr) atm_bnd_vlcs = dict_.values_by_key(atom_bond_valences(xgr), atm_keys) atm_tot_vlcs = dict_.values_by_key(atom_element_valences(xgr), 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
def frozen(xgr): """ hashable, sortable, immutable container of graph data """ atm_keys = sorted(atom_keys(xgr)) bnd_keys = sorted(bond_keys(xgr), key=sorted) # make it sortable by replacing Nones with -infinity atm_vals = numpy.array(dict_.values_by_key(atoms(xgr), atm_keys)) bnd_vals = numpy.array(dict_.values_by_key(bonds(xgr), 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 atom_hybridizations(rgr): """ atom hybridizations, by atom """ 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
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 = atom_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 = bond_neighbor_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)
def resonance_dominant_bond_orders(rgr): """ resonance-dominant bond orders, by bond """ 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
def resonance_dominant_atom_hybridizations(rgr): """ resonance-dominant atom hybridizations, by atom """ 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
def sing_res_dom_radical_atom_keys(rgr): """ resonance-dominant radical atom keys,for one resonance """ 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
def resonance_avg_bond_orders(rgr): """ resonance-dominant bond orders, by bond """ 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
def subresonances(rgr): """ this connected graph and its lower-spin (more pi-bonded) resonances """ def _inc_range(bnd_cap): return tuple(range(0, bnd_cap+1)) add_pi_bonds_ = functools.partial(_add_pi_bonds, rgr) atm_keys = list(_atom_keys(rgr)) bnd_keys = list(_bond_keys(rgr)) atm_unsat_vlcs = dict_.values_by_key( _atom_unsaturated_valences(rgr), atm_keys) atm_bnd_keys_lst = dict_.values_by_key(_atom_bond_keys(rgr), atm_keys) bnd_caps = dict_.values_by_key(_bond_capacities(rgr), bnd_keys) bnd_ord_dct = _bond_orders(rgr) def _is_valid(bnd_ord_inc_dct): # check if pi bonds exceed unsaturated valences def __tally(atm_bnd_keys): return sum(dict_.values_by_key(bnd_ord_inc_dct, atm_bnd_keys)) atm_unsat_vlc_decs = tuple(map(__tally, atm_bnd_keys_lst)) enough_elecs = numpy.all( numpy.less_equal(atm_unsat_vlc_decs, atm_unsat_vlcs)) # check if all bond orders are less than 4 (should only affect C2) bnd_inc_keys = bnd_ord_inc_dct.keys() bnd_incs = dict_.values_by_key(bnd_ord_inc_dct, bnd_inc_keys) bnd_ords = dict_.values_by_key(bnd_ord_dct, bnd_inc_keys) new_bnd_ords = numpy.add(bnd_ords, bnd_incs) not_too_many = numpy.all(numpy.less(new_bnd_ords, 4)) return enough_elecs and not_too_many def _bond_value_dictionary(bnd_vals): return dict(zip(bnd_keys, bnd_vals)) bnd_ord_incs_itr = itertools.product(*map(_inc_range, bnd_caps)) bnd_ord_inc_dct_itr = map(_bond_value_dictionary, bnd_ord_incs_itr) bnd_ord_inc_dct_itr = filter(_is_valid, bnd_ord_inc_dct_itr) rgrs = tuple(sorted(map(add_pi_bonds_, bnd_ord_inc_dct_itr), key=_frozen)) return rgrs
def bonds_from_data(bond_keys, bond_orders=None, bond_stereo_parities=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 bond_keys: bond keys :type bond_keys: set :param bond_orders: bond orders, by bond key :type bond_orders: dict :param bond_stereo_parities: bond stereo parities, by bond key :type bond_stereo_parities: dict """ keys = sorted(bond_keys) assert all(len(key) == 2 for key in keys) ords = dict_.values_by_key(dict_.empty_if_none(bond_orders), keys, fill_val=1) pars = dict_.values_by_key(dict_.empty_if_none(bond_stereo_parities), 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 = list(map(int, 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
def resonance_dominant_radical_atom_keys(rgr): """ resonance-dominant radical atom keys (keys of resonance-dominant radical sites) """ 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
def atom_bond_valences(xgr, bond_order=True): """ bond count (bond valence), by atom """ atm_keys = list(atom_keys(xgr)) xgr = explicit(xgr) if not bond_order: xgr = without_bond_orders(xgr) atm_nbhs = dict_.values_by_key(atom_neighborhoods(xgr), 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
def atoms_from_data(atom_symbols, atom_implicit_hydrogen_valences=None, atom_stereo_parities=None): """ construct atom dictionary from data format: atm_dct := {atm_key: (atm_sym, atm_imp_hyd_vlc, atm_ste_par), ...} :param atom_symbols: atomic symbols, by atom key :type atom_symbols: dict :param atom_implicit_hydrogen_valences: the number of implicit hydrogens associated with each atom, by atom key :type atom_implicit_hydrogen_valences: dict :param atom_stereo_parities: atom stereo parities, by atom key :type atom_stereo_parities: dict """ keys = sorted(atom_symbols.keys()) syms = dict_.values_by_key(atom_symbols, keys) vlcs = dict_.values_by_key( dict_.empty_if_none(atom_implicit_hydrogen_valences), keys, fill_val=0) pars = dict_.values_by_key(dict_.empty_if_none(atom_stereo_parities), keys, fill_val=None) natms = len(syms) 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 syms = list(map(pt.to_E, syms)) 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(syms, vlcs, pars))) return atm_dct
def inchi_with_sort_from_geometry(gra, geo=None, geo_idx_dct=None): """ connectivity graph => inchi conversion (if coordinates are passed in, they are used to determine stereo) """ gra = automol.graph.without_dummy_atoms(gra) gra = automol.graph.dominant_resonance(gra) atm_keys = sorted(automol.graph.atom_keys(gra)) bnd_keys = list(automol.graph.bond_keys(gra)) atm_syms = dict_.values_by_key(automol.graph.atom_symbols(gra), atm_keys) atm_bnd_vlcs = dict_.values_by_key(automol.graph.atom_bond_valences(gra), atm_keys) atm_rad_vlcs = dict_.values_by_key( automol.graph.atom_unsaturated_valences(gra), atm_keys) bnd_ords = dict_.values_by_key(automol.graph.bond_orders(gra), bnd_keys) #print('geo test print:', automol.geom.string(automol.graph.geometry(gra))) if geo is not None: assert geo_idx_dct is not None atm_xyzs = automol.geom.coordinates(geo) atm_xyzs = [atm_xyzs[geo_idx_dct[atm_key]] 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 _connected_heuristic_geometry(gra): """ stereo-specific coordinates for a connected molecular geometry """ assert gra == explicit(gra) atm_keys = sorted(atom_keys(gra)) zma, zma_key_dct = connected_heuristic_zmatrix(gra) geo = automol.zmatrix.geometry(zma) idxs = dict_.values_by_key(zma_key_dct, atm_keys) geo = automol.geom.from_subset(geo, idxs) geo_idx_dct = {atm_key: idx for idx, atm_key in enumerate(atm_keys)} return geo, geo_idx_dct
def from_graph(gra): """ igraph object from a molecular graph """ atm_labels = sorted(automol.graph.atom_keys(gra)) bnd_labels = list(sorted(map(sorted, automol.graph.bond_keys(gra)))) atm_keys = atm_labels bnd_keys = list(map(frozenset, bnd_labels)) atm_vals = dict_.values_by_key(automol.graph.atoms(gra), atm_keys) bnd_vals = dict_.values_by_key(automol.graph.bonds(gra), bnd_keys) atm_colors = list(itertools.starmap(_encode_vertex_attributes, atm_vals)) bnd_colors = list(itertools.starmap(_encode_edge_attributes, bnd_vals)) igr = igraph.Graph(bnd_labels) igr.vs['label'] = atm_labels igr.es['label'] = bnd_labels igr.vs['color'] = atm_colors igr.es['color'] = bnd_colors return igr
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 = atom_neighbor_keys(gra) atm_ngb_keys = atm_ngb_keys_dct[atm_key] # sort the neighbor keys by stereo priority atm_ngb_keys = stereo_sorted_atom_neighbor_keys(gra, atm_key, atm_ngb_keys) # determine the parity based on the coordinates xyzs = automol.geom.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
def _start_zmatrix_from_ring(gra, rng_atm_keys): """ generates a z-matrix for a ring """ # the key dictionary can be constructed immediately zma_key_dct = { atm_key: zma_key for zma_key, atm_key in enumerate(rng_atm_keys) } # now, build the z-matrix natms = len(rng_atm_keys) atm_sym_dct = atom_symbols(gra) dist_val = 1.5 * qcc.conversion_factor('angstrom', 'bohr') ang_val = (natms - 2.) * numpy.pi / natms dih_val = 0. # 1. construct the z-matrix for a 3-atom system key_mat = [[None, None, None], [0, None, None], [1, 0, None]] name_mat = [[None, None, None], ['R1', None, None], ['R2', 'A2', None]] syms = dict_.values_by_key(atm_sym_dct, rng_atm_keys[:3]) val_dct = {'R1': dist_val, 'R2': dist_val, 'A2': ang_val} zma = automol.zmatrix.from_data(syms, key_mat, name_mat, val_dct) # 2. append z-matrix rows for the remaining atoms for row, rng_atm_key in enumerate(rng_atm_keys): if row > 2: sym = atm_sym_dct[rng_atm_key] dist_name = automol.zmatrix.new_distance_name(zma) ang_name = automol.zmatrix.new_central_angle_name(zma) dih_name = automol.zmatrix.new_dihedral_angle_name(zma) zma = automol.zmatrix.append(zma, sym, [row - 1, row - 2, row - 3], [dist_name, ang_name, dih_name], [dist_val, ang_val, dih_val]) return zma, zma_key_dct
def branch_bond_keys(xgr, atm_key, bnd_key, saddle=False, ts_bnd=None): """ 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 # atm_bnd_keys_dct = atom_bond_keys(xgr) # print('atm_bnd_keys_dct:', atm_bnd_keys_dct) # bnch_bnd_keys = {bnd_key} # seen_bnd_keys = set() # form set of keys of atoms connected to atm_key # excl_bnd_keys = atm_bnd_keys_dct[atm_key] # if bnd_key in excl_bnd_keys: # excl_bnd_keys = excl_bnd_keys - {bnd_key} # print('excl_bnd_keys:', excl_bnd_keys) # new_bnd_keys = {bnd_key} # bnd_ngb_keys_dct = bond_neighbor_keys(xgr) # print('bnd_ngb_keys_dct:', bnd_ngb_keys_dct) # if bnd_key not in bnd_ngb_keys_dct: # for bnd in bnd_ngb_keys_dct: # atmi, atmj = list(bnd) # if atmi in list(ts_bnd) or atmj in list(ts_bnd): # bnds = list(bnd_ngb_keys_dct[bnd]) # bnds.append(ts_bnd) # bnd_ngb_keys_dct[bnd] = frozenset(bnds) # bnd_ngb_keys_dct[bnd_key] = bond_neighbor_bonds(bnd_key, xgr) # if saddle and bnd_key != ts_bnd: # for bnd in bnd_ngb_keys_dct: # atmi, atmj = list(bnd) # if atmi in list(ts_bnd) or atmj in list(ts_bnd): # bnds = list(bnd_ngb_keys_dct[bnd]) # bnds.append(ts_bnd) # bnd_ngb_keys_dct[bnd] = frozenset(bnds) # bnd_ngb_keys_dct[ts_bnd] = bond_neighbor_bonds(ts_bnd, xgr) bnd_key = frozenset(bnd_key) assert atm_key in bnd_key if not saddle: assert bnd_key in bond_keys(xgr) #print('xgr test:', xgr) #print('atm_key:', atm_key) #print('bnd_key:', bnd_key) #print('saddle:', saddle) #print('ts_bnd:', ts_bnd) atm_bnd_keys_dct = atom_bond_keys(xgr) 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} #print('new_bnd_keys:', new_bnd_keys) bnd_ngb_keys_dct = bond_neighbor_keys(xgr) #print('bnd_ngb_keys_dct:', bnd_ngb_keys_dct) if ts_bnd: bnd_ngb_keys_dct[ts_bnd] = bond_neighbor_bonds(ts_bnd, xgr) #print('updated bnd_ngb_keys_dct:', bnd_ngb_keys_dct) 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 #print('branch bond keys:', bnch_bnd_keys) return frozenset(bnch_bnd_keys)
def __tally(atm_bnd_keys): return sum(dict_.values_by_key(bnd_ord_inc_dct, atm_bnd_keys))