Source code for besmarts.assign.hierarchy_assign_native

"""
besmarts.assign.hierarchy_assign_native

Assign molecule structures to a SMARTS hierarchy using pure BESMARTS matching
"""

from typing import List

from besmarts.core import (
    codecs,
    topology,
    graphs,
    hierarchies,
    assignments,
    trees,
    tree_iterators,
    configs,
    mapper,
)
from besmarts.cluster import cluster_assignment


[docs] class smarts_hierarchy_assignment_native( assignments.smarts_hierarchy_assignment ): """ The BESMARTS labeler. Note that this is much slower than the more developed toolkits. Using this labeler only has the advantage that it is possible to search a single structure (set of indices) in a molecule, rather than searching the entire molecule for all possible matches. This can be useful when you are interested in specific environments in large molecules, like proteins. Note that this still requires a SMILES graph codec, which is not provided by BESMARTS. Decode the SMILES first, then load in the serialized file """ __slots__ = tuple()
[docs] def assign( self, shier: hierarchies.smarts_hierarchy, gcd: codecs.graph_codec, smi: List[str], topo: topology.structure_topology ) -> assignments.smiles_assignment_group: return smarts_hierarchy_assign(shier, gcd, smi, topo)
[docs] def assign_atoms( self, shier: hierarchies.smarts_hierarchy, gcd: codecs.graph_codec, smi: List[str], ) -> assignments.smiles_assignment_group: return smarts_hierarchy_assign_atoms(shier, gcd, smi)
[docs] def assign_bonds( self, shier: hierarchies.smarts_hierarchy, gcd: codecs.graph_codec, smi: List[str], ) -> assignments.smiles_assignment_group: return smarts_hierarchy_assign_bonds(shier, gcd, smi)
[docs] def assign_angles( self, shier: hierarchies.smarts_hierarchy, gcd: codecs.graph_codec, smi: List[str], ) -> assignments.smiles_assignment_group: return smarts_hierarchy_assign_angles(shier, gcd, smi)
[docs] def assign_torsions( self, shier: hierarchies.smarts_hierarchy, gcd: codecs.graph_codec, smi: List[str], ) -> assignments.smiles_assignment_group: return smarts_hierarchy_assign_torsions(shier, gcd, smi)
[docs] def assign_impropers( self, shier: hierarchies.smarts_hierarchy, gcd: codecs.graph_codec, smi: List[str], ) -> assignments.smiles_assignment_group: return smarts_hierarchy_assign_impropers(shier, gcd, smi)
[docs] def smarts_hierarchy_assign_structures( sh: hierarchies.smarts_hierarchy, gcd, topo, ics: List[graphs.structure] ): sh = hierarchies.smarts_hierarchy_to_structure_hierarchy(sh, gcd, topo) roots = trees.tree_index_roots(sh.index) selections = structure_hierarchy_assign(sh, roots, ics) return selections
[docs] def smarts_hierarchy_assign_bonds( sh: hierarchies.smarts_hierarchy, gcd: codecs.graph_codec, smiles: List[str], ): topo = topology.bond_topology() sag = smarts_hierarchy_assign(sh, gcd, smiles, topology.bond) return sag
[docs] def smarts_hierarchy_assign( sh: hierarchies.smarts_hierarchy, gcd: codecs.graph_codec, smiles: List[str], topo: topology.structure_topology ): sh = hierarchies.smarts_hierarchy_to_structure_hierarchy(sh, gcd, topo) sag = [] roots = trees.tree_index_roots(sh.index) for smi in smiles: g = gcd.smiles_decode(smi) ics = graphs.graph_to_structure_topology(g, topo) selections = structure_hierarchy_assign(sh, roots, ics) sa = cluster_assignment.smiles_assignment_str(smi, selections) sag.append(sa) return assignments.smiles_assignment_group(sag, topo) for root in roots: new_matches = assign( shier, root, mol, indices, lambda x: tuple(sorter(x)) ) if not match: match = new_matches else: for x,y in new_matches.items(): if y is not None: match[x] = y
[docs] def smarts_hierarchy_assign_atoms( sh: hierarchies.smarts_hierarchy, gcd: codecs.graph_codec, smiles: List[str], ): sag = smarts_hierarchy_assign(sh, gcd, smiles, topology.atom) return sag
[docs] def smarts_hierarchy_assign_angles( sh: hierarchies.smarts_hierarchy, gcd: codecs.graph_codec, smiles: str ): sag = smarts_hierarchy_assign(sh, gcd, smiles, topology.angle) return sag
[docs] def smarts_hierarchy_assign_torsions( sh: hierarchies.smarts_hierarchy, gcd: codecs.graph_codec, smiles: str ): sag = smarts_hierarchy_assign(sh, gcd, smiles, topology.torsion) return sag
[docs] def smarts_hierarchy_assign_outofplanes( sh: hierarchies.smarts_hierarchy, gcd: codecs.graph_codec, smiles: str ): sag = smarts_hierarchy_assign(sh, gcd, smiles, topology.outofplane) return sag
[docs] def structure_hierarchy_assign( sh: hierarchies.structure_hierarchy, roots, structs ): if len(structs) == 0: return {} topo = sh.topology matches = { tuple(g.select[i] for i in g.topology.primary): None for g in structs } ordering = {} for root in roots: ordering.update({ h.name: i for i, h in enumerate( (tree_iterators.tree_iter_dive(sh.index, root)), len(ordering) ) }) for root in reversed(roots): for cur in tree_iterators.tree_iter_dive_reverse(sh.index, root): sg = sh.subgraphs.get(cur.index) if sg is None: continue if type(sg) is str: print(f"Warning, cannot parse {sg} : skipping") continue S0 = graphs.subgraph_to_structure(sg, topo) unmatched = sum([0] + [int(lbl is None) for lbl in matches.values()]) if unmatched == 0: break lbl = cur.name d = graphs.structure_max_depth(S0) config = configs.smarts_extender_config(d, d, True) for g in structs: assert S0.topology == g.topology g = graphs.structure_copy(g) mapper.mapper_smarts_extend(config, [g]) if not mapper.mapper_match(g, S0): continue ic = tuple(g.select[i] for i in g.topology.primary) if matches[ic] is None: matches[ic] = lbl elif ordering[lbl] > ordering[matches[ic]]: matches[ic] = lbl return matches