def inchi(gra, stereo=False): """ Generate an InChI string from a molecular graph. :param gra: molecular graph :type gra: automol graph data structure :param stereo: parameter to include stereochemistry information :type stereo: bool :rtype: str """ ich = automol.inchi.base.hardcoded_object_to_inchi_by_key('graph', gra, comp=_compare) if ich is None: if not stereo or not has_stereo(gra): ich, _ = inchi_with_sort_from_geometry(gra) ich = automol.inchi.base.standard_form(ich, stereo=stereo) else: gra = explicit(gra) geo, geo_idx_dct = automol.graph.embed.fake_stereo_geometry(gra) ich, _ = inchi_with_sort_from_geometry(gra, geo=geo, geo_idx_dct=geo_idx_dct) return ich
def _connected_inchi_with_graph_stereo(ich, gra, nums): """ For a connected inchi/graph, check if the inchi is missing stereo; If so, add stereo based on the graph. Currently only checks for missing bond stereo, since this is all we have seen so far, but could be generalized. :param ich: the inchi string :param gra: the graph :param nums: graph indices to backbone atoms in canonical inchi order :type nums: tuple[int] """ # First, do a check to see if the InChI is missing bond stereo # relative to the graph. ich_ste_keys = automol.inchi.stereo_bonds(ich) our_ste_keys = bond_stereo_keys(gra) miss_ich_ste_keys = automol.inchi.unassigned_stereo_bonds(ich) if len(ich_ste_keys) > len(our_ste_keys): raise Exception("Our code is missing stereo bonds") if len(ich_ste_keys) < len(our_ste_keys) or miss_ich_ste_keys: # Convert to implicit graph and relabel based on InChI sort atm_key_dct = dict(map(reversed, enumerate(nums))) gra = relabel(gra, atm_key_dct) gra = explicit(gra) exp_h_keys = explicit_hydrogen_keys(gra) exp_h_key_dct = {k: -k for k in exp_h_keys} gra = relabel(gra, exp_h_key_dct) # Translate internal stereo parities into InChI stereo parities # and generate the appropriate b-layer string for the InChI ste_dct = bond_stereo_parities(gra) ste_keys = tuple( sorted(tuple(reversed(sorted(k))) for k in bond_stereo_keys(gra))) blyr_strs = [] for atm1_key, atm2_key in ste_keys: our_par = ste_dct[frozenset({atm1_key, atm2_key})] our_srt1, our_srt2 = bond_stereo_sorted_neighbor_atom_keys( gra, atm1_key, atm2_key) ich_srt1 = tuple(reversed(sorted(our_srt1))) ich_srt2 = tuple(reversed(sorted(our_srt2))) if not ((our_srt1 != ich_srt1) ^ (our_srt2 != ich_srt2)): ich_par = our_par else: ich_par = not our_par blyr_strs.append( f"{atm1_key+1}-{atm2_key+1}{'-' if ich_par else '+'}") # After forming the b-layer string, generate the new InChI blyr_str = ','.join(blyr_strs) ste_dct = {'b': blyr_str} # print(ste_dct) ich = automol.inchi.standard_form(ich, ste_dct=ste_dct) # print('out:', ich) return ich
def geometry(gra, keys=None, ntries=5, max_dist_err=0.2): """ sample a qualitatively-correct stereo geometry :param gra: the graph, which may or may not have stereo :param keys: graph keys, in the order in which they should appear in the geometry :param ntries: number of tries for finding a valid geometry :param max_dist_err: maximum distance error convergence threshold Qualitatively-correct means it has the right connectivity and the right stero parities, but its bond lengths and bond angles may not be quantitatively realistic """ assert gra == explicit(gra), ( "Graph => geometry conversion requires explicit hydrogens!\n" "Use automol.graph.explicit() to convert to an explicit graph.") # 0. Get keys and symbols symb_dct = atom_symbols(gra) keys = sorted(atom_keys(gra)) if keys is None else keys symbs = tuple(map(symb_dct.__getitem__, keys)) # 1. Generate bounds matrices lmat, umat = distance_bounds_matrices(gra, keys) chi_dct = chirality_constraint_bounds(gra, keys) pla_dct = planarity_constraint_bounds(gra, keys) conv1_ = qualitative_convergence_checker_(gra, keys) conv2_ = embed.distance_convergence_checker_(lmat, umat, max_dist_err) def conv_(xmat, err, grad): return conv1_(xmat, err, grad) & conv2_(xmat, err, grad) # 2. Generate coordinates with correct stereo, trying a few times for _ in range(ntries): xmat = embed.sample_raw_distance_coordinates(lmat, umat, dim4=True) xmat, conv = embed.cleaned_up_coordinates(xmat, lmat, umat, pla_dct=pla_dct, chi_dct=chi_dct, conv_=conv_) if conv: break if not conv: raise error.FailedGeometryGenerationError(f'Bad gra {string(gra)}') # 3. Generate a geometry data structure from the coordinates xyzs = xmat[:, :3] geo = automol.geom.base.from_data(symbs, xyzs, angstrom=True) return geo
def geometry(gra): """ Convert a molecular graph to a molecular geometry. :param gra: molecular graph :type gra: automol graph data structure :rtype: automol molecular geometry data structure """ symbs = atom_symbols(gra) if len(symbs) != 1: gra = explicit(gra) geo = automol.graph.embed.geometry(gra) else: symb = list(symbs.values())[0] # symb = list(symbs.keys())[0] geo = ((symb, (0.00, 0.00, 0.00)),) return geo