示例#1
0
文件: inchi.py 项目: Robot-Will/OASA
  def read_double_bond_stereo_layer( self):
    def get_lowest_numbered_neighbor( atom, verbotten_atom):
      neighs = [(n.properties_.get('inchi_number',1000000), n)
                for n in atom.neighbors
                if n is not verbotten_atom and "inchi_number" in n.properties_]
      if neighs:
        neighs.sort( reverse=True)
        return neighs[0][1]
      else:
        # we take the only one that is there (if any)
        neighs = [n for n in atom.neighbors if n is not verbotten_atom]
        if neighs:
          return neighs[0]
        else:
          raise oasa_inchi_error( "No neigbors on atom with stereo information!")
        

    
    layer = self.get_layer( "b")
    if not layer:
      return
    for a1,a2,sign in re.findall( "(\d+)-(\d+)([-+?u])", layer):
      atom1 = self.get_atom_with_inchi_number( int( a1))
      atom2 = self.get_atom_with_inchi_number( int( a2))
      bond = self.structure.get_edge_between( atom1, atom2)
      # we need neighbors with lowest inchi_number
      neigh1 = get_lowest_numbered_neighbor( atom1, atom2)
      neigh2 = get_lowest_numbered_neighbor( atom2, atom1)
      st = cis_trans_stereochemistry( references=[neigh1,atom1,atom2,neigh2],
                                      value=self.stereo_remap[sign])
      self.structure.add_stereochemistry( st)
示例#2
0
文件: inchi.py 项目: caiyingchun/OASA
    def read_double_bond_stereo_layer(self):
        def get_lowest_numbered_neighbor(atom, verbotten_atom):
            neighs = [
                (n.properties_.get('inchi_number', 1000000), n)
                for n in atom.neighbors
                if n is not verbotten_atom and "inchi_number" in n.properties_
            ]
            if neighs:
                neighs.sort(reverse=True)
                return neighs[0][1]
            else:
                # we take the only one that is there (if any)
                neighs = [n for n in atom.neighbors if n is not verbotten_atom]
                if neighs:
                    return neighs[0]
                else:
                    raise oasa_inchi_error(
                        "No neigbors on atom with stereo information!")

        layer = self.get_layer("b")
        if not layer:
            return
        for a1, a2, sign in re.findall("(\d+)-(\d+)([-+?u])", layer):
            atom1 = self.get_atom_with_inchi_number(int(a1))
            atom2 = self.get_atom_with_inchi_number(int(a2))
            bond = self.structure.get_edge_between(atom1, atom2)
            # we need neighbors with lowest inchi_number
            neigh1 = get_lowest_numbered_neighbor(atom1, atom2)
            neigh2 = get_lowest_numbered_neighbor(atom2, atom1)
            st = cis_trans_stereochemistry(
                references=[neigh1, atom1, atom2, neigh2],
                value=self.stereo_remap[sign])
            self.structure.add_stereochemistry(st)
示例#3
0
    def detect_stereochemistry_from_coords(self, omit_rings=True):
        import stereochemistry, geometry

        def add_neighbor_double_bonds(bond, path):
            for _e in bond.get_neighbor_edges():
                if _e.order == 2 and _e not in path:
                    path.append(_e)
                    add_neighbor_double_bonds(_e, path)

        # double bonds
        # detect clusters of double bonds
        double_paths = []
        processed = set()
        for e in self.edges:
            if e.order == 2 and e not in processed:
                if omit_rings and not self.is_edge_a_bridge(e):
                    continue
                path = [e]
                add_neighbor_double_bonds(e, path)
                if len(path) % 2:
                    double_paths.append(path)
                    processed |= set(path)
        # detect config on these paths
        for path in double_paths:
            vertices = []
            for bond in path:
                vertices.extend(bond.vertices)
            ends = [v for v in vertices if vertices.count(v) == 1]
            if len(
                    ends
            ) != 2:  # two ends is the only thing we are prepared to handle
                continue
            end1, end2 = ends
            # set stereochemistry for all neighbors of both ends
            for e1, n1 in end1.get_neighbor_edge_pairs():
                plane1 = geometry.plane_normal_from_3_points(
                    (n1.x, n1.y, n1.z), (end1.x, end1.y, end1.z),
                    (end2.x, end2.y, end2.z))
                if plane1 == None:
                    continue  # some coords were missing
                if not e1 in path:
                    for e2, n2 in end2.get_neighbor_edge_pairs():
                        if not e2 in path:
                            plane2 = geometry.plane_normal_from_3_points(
                                (end1.x, end1.y, end1.z),
                                (end2.x, end2.y, end2.z), (n2.x, n2.y, n2.z))
                            #cos_angle = geometry.same_or_oposite_side( plane1, plane2)
                            cos_angle = geometry.angle_between_planes(
                                plane1, plane2)
                            if cos_angle < 0:
                                value = stereochemistry.cis_trans_stereochemistry.OPPOSITE_SIDE
                            else:
                                value = stereochemistry.cis_trans_stereochemistry.SAME_SIDE
                            if len(path) == 1:
                                center = path[0]
                            else:
                                center = None
                            refs = [n1, end1, end2, n2]
                            st = stereochemistry.cis_trans_stereochemistry(
                                center=center, value=value, references=refs)
                            to_remove = None
                            to_add = None
                            for st1 in self.stereochemistry:
                                if set(st1.references) == set(st.references):
                                    if st.value == st1.value:
                                        break
                                    else:
                                        to_remove = st1
                                        break
                            else:
                                self.add_stereochemistry(st)
                            if to_remove:
                                self.remove_stereochemistry(to_remove)
示例#4
0
  def _process_stereochemistry( self, mol):
    ## process stereochemistry
    ## double bonds
    def get_stereobond_direction( end_atom, inside_atom, bond, init):
      position = mol.vertices.index( end_atom) - mol.vertices.index( inside_atom)
      char = bond.properties_['stereo'] == "\\" and 1 or -1
      direction = (position * char * init) < 0 and "up" or "down"
      return direction
    def get_end_and_inside_vertex_from_edge_path( edge, path):
      a1,a2 = edge.vertices
      if len( [e for e in a1.neighbor_edges if e in path]) == 1:
        return a1, a2
      return a2, a1
    
    stereo_edges = [e for e in mol.edges if "stereo" in e.properties_]
    paths = []
    for i,e1 in enumerate( stereo_edges):
      for e2 in stereo_edges[i+1:]:
        path = mol.get_path_between_edges( e1, e2)
        path2 = path[1:-1]
        if len( path2)%2 and not [_e for _e in path2 if _e.order != 2]:
          # only odd number of double bonds, double bonds only
          for _e in path[1:-1]:
            if not mol.is_edge_a_bridge_fast_and_dangerous( _e):
              break
          else:
            # only stereo related to non-cyclic bonds
            paths.append( path)
    
    for path in paths:
      bond1 = path[0]
      end_atom1,inside_atom1 = get_end_and_inside_vertex_from_edge_path( bond1, path)
      bond2 = path[-1]
      end_atom2,inside_atom2 = get_end_and_inside_vertex_from_edge_path( bond2, path)
      d1 = get_stereobond_direction( end_atom1, inside_atom1, bond1, -1)
      d2 = get_stereobond_direction( end_atom2, inside_atom2, bond2, -1)
      if d1 == d2:
        value = stereochemistry.cis_trans_stereochemistry.SAME_SIDE
      else:
        value = stereochemistry.cis_trans_stereochemistry.OPPOSITE_SIDE
      if len( path) == 3:
        center = path[1]
      else:
        center = None
      refs = [end_atom1,inside_atom1,inside_atom2,end_atom2]
      st = stereochemistry.cis_trans_stereochemistry( center=center, value=value, references=refs)
      mol.add_stereochemistry( st)

    # tetrahedral stereochemistry
    for v in mol.vertices:
      refs = None
      if 'stereo' in v.properties_:
        idx = [mol.vertices.index( n) for n in v.neighbors]
        idx.sort()
        if len( idx) < 3:
          pass # no stereochemistry with less then 3 neighbors
        elif len( idx) == 3:
          if v.explicit_hydrogens == 0:
            pass # no stereochemistry without adding hydrogen here
          else:
            if self.explicit_hydrogens_to_real_atoms:
              hs = mol.explicit_hydrogens_to_real_atoms( v)
              h = hs.pop()
            else:
              h = stereochemistry.explicit_hydrogen()
            v_idx = mol.vertices.index( v)
            idx1 = [i for i in idx if i < v_idx]
            idx2 = [i for i in idx if i > v_idx]
            refs = [mol.vertices[i] for i in idx1] + [h] + [mol.vertices[i] for i in idx2]
        elif len( idx) == 4:
          refs = [mol.vertices[i] for i in idx]
        else:
          pass # unhandled stereochemistry
      if refs:
        if v.properties_["stereo"] == "@":
          direction = stereochemistry.tetrahedral_stereochemistry.ANTICLOCKWISE
        elif v.properties_['stereo'] == "@@":
          direction = stereochemistry.tetrahedral_stereochemistry.CLOCKWISE
        else:
          continue # no meaning
        st = stereochemistry.tetrahedral_stereochemistry( center=v, value=direction, references=refs)
        mol.add_stereochemistry( st)

    # delete the data after processing
    for e in mol.edges:
      if 'stereo' in e.properties_:
        del e.properties_['stereo']
    for v in mol.vertices:
      if 'stereo' in v.properties_:
        del v.properties_['stereo']
示例#5
0
 def detect_stereochemistry_from_coords( self, omit_rings=True):
   import stereochemistry,geometry
   def add_neighbor_double_bonds( bond, path):
     for _e in bond.get_neighbor_edges():
       if _e.order == 2 and _e not in path:
         path.append( _e)
         add_neighbor_double_bonds( _e, path)
   # double bonds
   # detect clusters of double bonds
   double_paths = []
   processed = set()
   for e in self.edges:
     if e.order == 2 and e not in processed:
       if omit_rings and not self.is_edge_a_bridge( e):
         continue
       path = [e]
       add_neighbor_double_bonds( e, path)
       if len( path) % 2:
         double_paths.append( path)
         processed |= set( path)
   # detect config on these paths
   for path in double_paths:
       vertices = []
       for bond in path:
         vertices.extend( bond.vertices)
       ends = [v for v in vertices if vertices.count(v) == 1]
       if len( ends) != 2: # two ends is the only thing we are prepared to handle
         continue
       end1, end2 = ends
       # set stereochemistry for all neighbors of both ends
       for e1,n1 in end1.get_neighbor_edge_pairs():
         plane1 = geometry.plane_normal_from_3_points( (n1.x,n1.y,n1.z),(end1.x,end1.y,end1.z),(end2.x,end2.y,end2.z))
         if plane1 == None:
           continue # some coords were missing
         if not e1 in path:
           for e2,n2 in end2.get_neighbor_edge_pairs():
             if not e2 in path:
               plane2 = geometry.plane_normal_from_3_points( (end1.x,end1.y,end1.z),(end2.x,end2.y,end2.z),(n2.x,n2.y,n2.z))
               #cos_angle = geometry.same_or_oposite_side( plane1, plane2)
               cos_angle = geometry.angle_between_planes( plane1, plane2)
               if cos_angle < 0:
                 value = stereochemistry.cis_trans_stereochemistry.OPPOSITE_SIDE
               else:
                 value = stereochemistry.cis_trans_stereochemistry.SAME_SIDE
               if len( path) == 1:
                 center = path[0]
               else:
                 center = None
               refs = [n1,end1,end2,n2]
               st = stereochemistry.cis_trans_stereochemistry( center=center, value=value, references=refs)
               to_remove = None
               to_add = None
               for st1 in self.stereochemistry:
                 if set( st1.references) == set( st.references):
                   if st.value == st1.value:
                     break
                   else:
                     to_remove = st1
                     break
               else:
                 self.add_stereochemistry( st)
               if to_remove:
                 self.remove_stereochemistry( to_remove)