def getAromaticRes(receptor):
    # TODO add acids and amides?
    aromatic_res = { "PHE": ["A"],
                 "TYR": ["A"],
                 "HIS": ["A", "N", "NA"],
                 "TRP": ["A", "N", "NA"],
                 "ARG": ["N", "C" , "NA"],
                 "DA" : ["A", "NA", "N"],  # DNA
                 "DC" : ["A", "N", "NA"],
                 "DT" : ["A", "N", "NA"],
                 "DG" : ["A", "N", "NA"],                 
                 "A" : ["A", "NA", "N"],   # DNA/RNA
                 "C" : ["A", "N", "NA"],
                 "G" : ["A", "N", "NA"],                 
                 "T" : ["A", "N", "NA"],
                 "U" : ["A", "N", "NA"],
                 }
    residues = {}
    special = [] # must be treated as a ligand part
    for a in receptor:
        a = a.strip()
        rtype = a[16:21].strip().upper() # NOTE: we can recognize only all caps!
        if a.startswith("HETATM"):
            special.append(a)
        elif a.startswith('ATOM') and rtype in aromatic_res.keys():
            if hf.getAtype(a) in aromatic_res[rtype]:
                res_id = hf.pmvAtomStrip(a).rsplit(":",1)[0] # A:GLY48:N -> A:GLY48
                if not res_id in residues.keys():
                    residues[res_id] = []
                residues[res_id].append(a)
    if special and DEBUG:
        print "found potential co-factor: %d"  % len(special)
        for a in special: print a
    return residues, special # residues = { "A:GLY48" : [ atom, atom, atom..]}
def findLigandRings(atoms):
    matrix = hf.getDistMatrix(atoms)
    bdist = 2.0 # angstrom of bond dinstance
    graph = hf.makeGraph(nodes_list = range(len(matrix)), distance_matrix = matrix, cutoff = bdist**2)
    rings5,rings6 = findRings(graph)
    RING = rings5+rings6
    ligand_rings = {}
    for r in range(len(RING)):
        # res name first...
        
        # get the first atom PDB string in the ring
        atstring = atoms[RING[r][0]][2]
        ringname = hf.pmvAtomStrip(atstring) 
        ringname_short = ringname.rsplit(":",1)[0].strip()
        if ringname_short:
            c = 0
            while ringname_short+":"+str(c) in ligand_rings.keys():
                c+=1
                if c > 20:
                    ringname_short = None
                    break
        if ringname_short:
            lnam = ringname_short+":"+str(c) 
        else:
            lnam = "rng:"+str(r)

        ligand_rings[lnam] = []
        for a in RING[r]:
            ligand_rings[lnam].append(atoms[a][2])
    return ligand_rings
Example #3
0
    def normalizeWaterScore(self):  #pose,entropyPenalty=False):

        # keep track of the original energy values
        if self.debug:
            old_e = self.pose['energy']
            old_leff = self.pose['leff']

        # rec_displaced waters
        rec_displaced = 0
        for p in self.pose['water_over_rec_penalty']:
            rec_displaced += p
        #    print p # XXX
        #print "RECDISP", rec_displaced  # XXX

        # lig_displaced waters
        lig_displaced = 0
        for p in self.pose['water_over_lig_penalty']:
            lig_displaced += p

        # clustering-displaced
        clust_displaced = 0
        for p in self.pose['water_cluster_penalty']:
            clust_displaced += p

        # count heavy at for lig.efficiency
        heavy_atoms = 0
        for a in self.pose['text']:
            if hf.isAtom(a) and (not hf.getAtype(a) in ['HD', 'W']):
                heavy_atoms += 1

        # energy correction
        if self.conservedwaterentropy:
            # XXX read the penalty from a variable!
            entropy = (0.2) * len(self.pose['water_bridge'])
            #print " ENTROPY PENALTY = ", entropy
        else:
            entropy = 0
        self.pose[
            'energy'] += lig_displaced + rec_displaced + clust_displaced + entropy

        # lig.efficiency correction
        self.pose['leff'] = self.pose['energy'] / float(heavy_atoms)

        if self.debug:
            #print "\n# PENALTY:\t +%2.3f [rec: %2.3f, lig: %2.3f, clust: %2.3f ]" % (rec_displaced+lig_displaced+clust_displaced,
            #        rec_displaced, lig_displaced, clust_displaced)
            print "  Penalties:"
            print "   - lig overlap     : %2.3f" % lig_displaced
            print "   - rec overlap     : %2.3f" % rec_displaced
            print "   - cluster penalty : %2.3f" % clust_displaced
            print "   - extra entropy   : %2.3f" % entropy

            print "   ENERGY:\t %2.3f [ old: %2.3f ]" % (self.pose['energy'],
                                                         old_e)
            print "   L.EFF.:\t %2.3f [ old: %2.3f ]\n" % (self.pose['leff'],
                                                           old_leff)
Example #4
0
    def weakWaterCleanup(self): #
        #pose, cutoff_weak = -0.35, cutoff_strong=-0.5, interact_dist=3.5 ):
        """ clean-up extra_weak waters (increment ['water_rec_over_penalty'], if necessary"""
        org_waters = len(self.pose['water_bridge'])
        #ignore_types = ['HD']

        lone_water = []
        interact_dist = self.interact_dist**2
        hb_types = ['OA', 'NA', 'SA', 'N', 'O', 'OA', 'NA', 'SA']
        hb_types += hf.METALS 
        for idx in range(len(self.pose['water_bridge'])):
            water = self.pose['water_bridge'][idx]
            score = self.pose['water_bridge_scores'][idx]
            # analyze only waters that are not ranked strong
            if score >= self.cutoff_strong: 
                atom_pool = [ a for a in self.pose['water_bridge_contacts'][idx] if hf.getAtype(a) in hb_types] 
                if self.debug:
                    hf.writeList('ATOM_POOL_%d_HB_%d.pdb' % (idx, sess), atom_pool, addNewLine=True)
                lone_water.append(water)
                try:
                    for a in atom_pool:
                        if (dist(water, a, sq=0)<= interact_dist):
                            #print "FOUND MATE",
                            #print dist(water, a, sq=True)
                            #print a.strip()
                            #print "------------------"
                            raise self.qs
                    #print "NO MATE FOR THIS", score
                    #print water.strip()
                except:
                    lone_water.remove(water)
                            
        for w in lone_water:
            idx = self.pose['water_bridge'].index(w)
            del self.pose['water_bridge'][idx]
            del self.pose['water_bridge_contacts'][idx]
        
            # EXPERIMENTAL
            #w_score = self.pose['water_bridge_scores'][idx]
            #if w_score > 
            # XXX THIS shouldn't happen:
            # a weakly bound water could be hanging in the bulk, but it should be accounted for
            # ...? 
            # how to describe the bulk solvent?
            # combine desolv map + discrete waters?
            # 

            self.pose['water_over_rec_penalty'].append( -self.pose['water_bridge_scores'].pop(idx) )
            # update PDBQT text
            #print pose['water_over_rec_penalty'] # XXX
            text_idx = self.pose['text'].index(w)
            del self.pose['text'][text_idx]


        if self.debug:
            print "LONE WATERS # REMOVED: ", (org_waters- len(self.pose['water_bridge']) )
Example #5
0
    def weakWaterCleanup(self): #
        #pose, cutoff_weak = -0.35, cutoff_strong=-0.5, interact_dist=3.5 ):
        """ clean-up extra_weak waters (increment ['water_rec_over_penalty'], if necessary"""
        org_waters = len(self.pose['water_bridge'])
        #ignore_types = ['HD']

        lone_water = []
        interact_dist = self.interact_dist**2
        hb_types = ['OA', 'NA', 'SA', 'N', 'O', 'OA', 'NA', 'SA']
        hb_types += hf.METALS 
        for idx in range(len(self.pose['water_bridge'])):
            water = self.pose['water_bridge'][idx]
            score = self.pose['water_bridge_scores'][idx]
            # analyze only waters that are not ranked strong
            if score >= self.cutoff_strong: 
                atom_pool = [ a for a in self.pose['water_bridge_contacts'][idx] if hf.getAtype(a) in hb_types] 
                if self.debug:
                    hf.writeList('ATOM_POOL_%d_HB_%d.pdb' % (idx, sess), atom_pool, addNewLine=True)
                lone_water.append(water)
                try:
                    for a in atom_pool:
                        if (dist(water, a, sq=0)<= interact_dist):
                            #print "FOUND MATE",
                            #print dist(water, a, sq=True)
                            #print a.strip()
                            #print "------------------"
                            raise self.qs
                    #print "NO MATE FOR THIS", score
                    #print water.strip()
                except:
                    lone_water.remove(water)
                            
        for w in lone_water:
            idx = self.pose['water_bridge'].index(w)
            del self.pose['water_bridge'][idx]
            del self.pose['water_bridge_contacts'][idx]
        
            # EXPERIMENTAL
            #w_score = self.pose['water_bridge_scores'][idx]
            #if w_score > 
            # XXX THIS shouldn't happen:
            # a weakly bound water could be hanging in the bulk, but it should be accounted for
            # ...? 
            # how to describe the bulk solvent?
            # combine desolv map + discrete waters?
            # 

            self.pose['water_over_rec_penalty'].append( -self.pose['water_bridge_scores'].pop(idx) )
            # update PDBQT text
            #print pose['water_over_rec_penalty'] # XXX
            text_idx = self.pose['text'].index(w)
            del self.pose['text'][text_idx]


        if self.debug:
            print "LONE WATERS # REMOVED: ", (org_waters- len(self.pose['water_bridge']) )
Example #6
0
    def normalizeWaterScore(self): #pose,entropyPenalty=False):

        # keep track of the original energy values
        if self.debug:
            old_e =  self.pose['energy']
            old_leff = self.pose['leff']

        # rec_displaced waters
        rec_displaced = 0
        for p in self.pose['water_over_rec_penalty']:
            rec_displaced += p
        #    print p # XXX
        #print "RECDISP", rec_displaced  # XXX 
        
        # lig_displaced waters
        lig_displaced = 0
        for p in self.pose['water_over_lig_penalty']:
            lig_displaced += p

        # clustering-displaced
        clust_displaced = 0
        for p in self.pose['water_cluster_penalty']:
            clust_displaced += p

        # count heavy at for lig.efficiency
        heavy_atoms = 0
        for a in self.pose['text']:
            if hf.isAtom(a) and ( not hf.getAtype(a) in ['HD', 'W'] ):
                heavy_atoms += 1

        # energy correction
        if self.conservedwaterentropy:
            # XXX read the penalty from a variable!
            entropy = (0.2)*len(self.pose['water_bridge'])
            #print " ENTROPY PENALTY = ", entropy
        else:
            entropy = 0
        self.pose['energy'] += lig_displaced + rec_displaced + clust_displaced + entropy

        # lig.efficiency correction
        self.pose['leff'] = self.pose['energy'] / float( heavy_atoms )


        if self.debug:
            #print "\n# PENALTY:\t +%2.3f [rec: %2.3f, lig: %2.3f, clust: %2.3f ]" % (rec_displaced+lig_displaced+clust_displaced,
            #        rec_displaced, lig_displaced, clust_displaced)
            print "  Penalties:"
            print "   - lig overlap     : %2.3f" % lig_displaced
            print "   - rec overlap     : %2.3f" % rec_displaced
            print "   - cluster penalty : %2.3f" % clust_displaced
            print "   - extra entropy   : %2.3f" % entropy

            print "   ENERGY:\t %2.3f [ old: %2.3f ]" %  (self.pose['energy'], old_e)
            print "   L.EFF.:\t %2.3f [ old: %2.3f ]\n" %  (self.pose['leff'], old_leff)
Example #7
0
    def getWaterGridEnergy(self): 

        #                    cutoff_weak = -0.35,   # weak water e.cutoff
        #                    cutoff_strong = -0.5,  # strong water e.cutoff
        #                    desolvEntropy=-0.2,    # desolvation entropy
        #                    mapdistrange = 0.5):   

        # TODO  to be used to 'minimize' the water position too?
        #       looking for the best spot for a water
        #       and increase the energy accordingly?
        # calculate the score for bridging waters;
        self.pose['water_bridge_scores'] = []
        for w in self.pose['water_bridge']:
            points, best_point = self.getMapPoints( coords = hf.atomCoord(w),
                                         distance = self.mapdistrange)
            self.pose['water_bridge_scores'].append(best_point)
        # calculate ligand-overlapping penalties
        self.pose['water_over_lig_penalty'] = []
        for w in self.pose['water_over_lig']:
            points, best_point = self.getMapPoints( coords = atomCoord(w),
                                        distance = self.mapdistrange)
            self.pose['water_over_lig_penalty'].append( -best_point)
        # calculate rec-overlapping penalties
        self.pose['water_over_rec_penalty'] = []
        for w in self.pose['water_over_rec']:
            self.pose['water_over_rec_penalty'].append(-self.desolvEntropy)
Example #8
0
    def getWaterGridEnergy(self):

        #                    cutoff_weak = -0.35,   # weak water e.cutoff
        #                    cutoff_strong = -0.5,  # strong water e.cutoff
        #                    desolvEntropy=-0.2,    # desolvation entropy
        #                    mapdistrange = 0.5):

        # TODO  to be used to 'minimize' the water position too?
        #       looking for the best spot for a water
        #       and increase the energy accordingly?
        # calculate the score for bridging waters;
        self.pose['water_bridge_scores'] = []
        for w in self.pose['water_bridge']:
            points, best_point = self.getMapPoints(coords=hf.atomCoord(w),
                                                   distance=self.mapdistrange)
            self.pose['water_bridge_scores'].append(best_point)
        # calculate ligand-overlapping penalties
        self.pose['water_over_lig_penalty'] = []
        for w in self.pose['water_over_lig']:
            points, best_point = self.getMapPoints(coords=atomCoord(w),
                                                   distance=self.mapdistrange)
            self.pose['water_over_lig_penalty'].append(-best_point)
        # calculate rec-overlapping penalties
        self.pose['water_over_rec_penalty'] = []
        for w in self.pose['water_over_rec']:
            self.pose['water_over_rec_penalty'].append(-self.desolvEntropy)
Example #9
0
 def recOverlapWaters(self):  # pose, cutoff = CLASH,
     #ignore_types = ['HD', 'H', 'W'] ):
     """ INPUT : pdb lig (multi)model and pdb target model
         OUTPUT: cleaned pdb lig model
      """
     #print "WARNING! missing interactions! Line B1"
     overlapping = []
     atom_pool = []
     cutoff = self.clash**2
     #cutoff += 0.5
     #cutoff = 0
     #for a in self.pose['vdw_contacts']: # PDBQT, no-HD   # XXX TODO BUG Line B1
     for aset in self.pose[
             'water_bridge_contacts']:  # PDBQT, no-HD   # XXX TODO BUG Line B1
         for a in aset:
             if not hf.getAtype(a) in self.ignore_types:
                 atom_pool.append(a)
     if self.debug:
         fp = open('DEBUG_rec_overlap.pdb', 'w')
         fp.write("REMARK  WATERS REMOVED BY RECEPTOR CLASHES")
     for w in self.pose['water_bridge']:
         try:  # try/except is faster
             for a in atom_pool:
                 #if hf.dist(w, a, sq=False) < self.clash:
                 if hf.dist(w, a, sq=False) < cutoff:
                     overlapping.append(w)
                     self.pose['text'].remove(w)
                     #print "\n\n\n ####  REMOVED", w
                     if self.debug:
                         fp.write(w + "\n")
                         fp.write(a + "\n")
                     raise self.qs
         except:
             pass
     if self.debug:
         fp.close()
         print "Processed: %d | Rec-overlap %d" % (len(
             self.pose['water_bridge']), len(overlapping))
     for w in overlapping:
         idx = self.pose['water_bridge'].index(w)
         del self.pose['water_bridge_contacts'][idx]
         self.pose['water_bridge'].remove(w)
     self.pose['water_over_rec'] = overlapping
Example #10
0
 def recOverlapWaters(self): # pose, cutoff = CLASH,
     #ignore_types = ['HD', 'H', 'W'] ):
     """ INPUT : pdb lig (multi)model and pdb target model
         OUTPUT: cleaned pdb lig model
      """
     #print "WARNING! missing interactions! Line B1"
     overlapping = []
     atom_pool = []
     cutoff = self.clash**2
     #cutoff += 0.5
     #cutoff = 0
     #for a in self.pose['vdw_contacts']: # PDBQT, no-HD   # XXX TODO BUG Line B1
     for aset in self.pose['water_bridge_contacts']: # PDBQT, no-HD   # XXX TODO BUG Line B1
         for a in aset:
             if not hf.getAtype(a) in self.ignore_types:
                 atom_pool.append(a)
     if self.debug:
         fp = open('DEBUG_rec_overlap.pdb','w')
         fp.write("REMARK  WATERS REMOVED BY RECEPTOR CLASHES")
     for w in self.pose['water_bridge']:
         try: # try/except is faster
             for a in atom_pool:
                 #if hf.dist(w, a, sq=False) < self.clash:
                 if hf.dist(w, a, sq=False) < cutoff:
                     overlapping.append(w)
                     self.pose['text'].remove(w)
                     #print "\n\n\n ####  REMOVED", w
                     if self.debug:
                         fp.write(w+"\n")
                         fp.write(a+"\n")
                     raise self.qs
         except:
             pass 
     if self.debug:
         fp.close()
         print "Processed: %d | Rec-overlap %d" % (len(self.pose['water_bridge']), len(overlapping) )
     for w in overlapping:
         idx = self.pose['water_bridge'].index(w)
         del self.pose['water_bridge_contacts'][idx]
         self.pose['water_bridge'].remove(w)
     self.pose['water_over_rec'] = overlapping
def searchPiGroupsLig(lig):
    # input : ligand atom lines (list)
    atoms = hf.getFlatAtoms(lig, flat_only = True)
    ligand_rings = findLigandRings(atoms)
    if ligand_rings:
        for r in ligand_rings.keys():
            if DEBUG: 
                print "+++"
                for a in ligand_rings[r]: print a[:-1]
                print "+++\n"
            ligand_rings[r] = atomsToVec(ligand_rings[r])
        return ligand_rings
    else:
        return False
Example #12
0
    def __init__(
        self,
        pose=None,  # advanced pose to process [text, coords, water_bridge, ...]
        gridmap=None,  # grid map (file/dictionary)

        # distance parms
        mapdistrange=1.0,  # distance around W coords to look for grid points
        clust_tol=2.0,  # cluster tolerance
        interact_dist=3.5,  # W-RecAtom interaction distance
        clash=2.03,  # min.distance allowed between W/atoms (lig, rec) # XX to remove spurious watre
        loneliness_dist=3.5,  # max distance between W and interacting rec atoms

        # energy parms
        cutoff_weak=-0.35,  # weak water e.cutoff
        cutoff_strong=-0.5,  # strong water e.cutoff
        desolvEntropy=-0.2,  # desolvation entropy
        conservedwaterentropy=0,  # add an entropy penalty also for conserved waters
        ignore_types=['H', 'HD', 'W'],  # atoms ignored for lig_overlap
        debug=False):  # ignore atom types for contacts

        if gridmap == None:
            #raise "No water map provided"
            print "No water map provided"
            return False
        print "WARNING processHydroDocking:_init_> clash distance [%2.3f] is extremely low! Test with some case studies" % clash
        self.gridmap = gridmap
        self.pose = pose
        self.mapdistrange = mapdistrange
        self.clust_tol = clust_tol
        self.interact_dist = interact_dist
        self.clash = clash
        self.loneliness_dist = loneliness_dist

        self.cutoff_weak = cutoff_weak
        self.cutoff_strong = cutoff_strong
        self.desolvEntropy = desolvEntropy
        self.ignore_types = ignore_types
        self.conservedwaterentropy = conservedwaterentropy

        self.qs = hf.QuickStop()

        self.debug = debug

        if not (pose == None) and not (gridmap == None):
            self.process
def atomsToVec(atoms):
    a1 = hf.atomCoord(atoms[1])
    a2 = hf.atomCoord(atoms[2])
    a3 = hf.atomCoord(atoms[3])
    centroid = hf.avgCoord(atoms)
    pvector = hf.calcPlane(a1, a2, a3)
    v1 = hf.vector(centroid, a1)
    v2 = hf.vector(centroid, a2)
    normal1 = hf.normalize(cross(v1 ,v2))
    normal2 = hf.normalize(cross(v2 ,v1))
    centroid_norm1 = hf.normalize(hf.vector(centroid, normal1))
    centroid_norm2 = hf.normalize(hf.vector(centroid, normal2))
    return {"centroid":centroid,"plane":hf.normalize(pvector),"normal":[normal1, normal2],\
                        'cnormal' : [centroid_norm1, centroid_norm2]}
Example #14
0
    def clusterWaters(self): #pose, clust_tolerance=2.0, desolvEntropy=0):
        # cluster waters
        # XXX
        # energy from the cluster?
        # once 3 waters are reclustered (3->1)
        # two desolvEntropy penalties should be issued?
        # XXX
        unclustered_waters = self.pose['water_bridge'][:] # XXX NOT SURE IT"S NECESSARY

        # cluster waters
        water_clusters = hf.clusterAtoms(unclustered_waters, tol=self.clust_tol)

        # calculate clustering energy
        self.pose['water_cluster_penalty'] = []
        remove_from_text = []
        for pop in water_clusters:
            if len(pop)>1:
                this_cluster_centroid = hf.avgCoord(pop)
                this_cluster_penalty = -self.desolvEntropy * (len(pop)-1)
                this_cluster_energy = 0
                this_cluster_contacts = []
                closest_to_centroid = None
                closest_dist = 999999
                for w in pop:
                    # get the w_index + w_score
                    idx = self.pose['water_bridge'].index(w)
                    this_cluster_energy += self.pose['water_bridge_scores'][idx]
                    remove_from_text.append(w)
                    # find water closest to centroid (to be conserved)
                    # get the distance from the cluster average
                    centr_dist =  hf.quickdist( hf.atomCoord(w), this_cluster_centroid, sq = False)
                    a = [ hf.makePdb(coord=this_cluster_centroid) ]
                    #writeList('centroid.pdb', a)
                    if centr_dist <= closest_dist:
                        closest_dist = centr_dist
                        closest_to_centroid = w
                    del self.pose['water_bridge'][idx]
                    del self.pose['water_bridge_scores'][idx]
                    # update contacts
                    for a in self.pose['water_bridge_contacts'][idx]:
                        if not a in this_cluster_contacts:
                            this_cluster_contacts.append(a)
                    del self.pose['water_bridge_contacts'][idx]
                # update PDBQT text
                # XXX DEBUGGINGH
                #print type(remove_from_text), remove_from_text[0]
                #writeList('REMOVING_WATERS.pdb', remove_from_text)
                #writeList('current_ligand.pdbqt', pose['text'])

                for w in remove_from_text:
                    if not w == closest_to_centroid:
                        try:
                            text_idx = self.pose['text'].index(w)

                            del self.pose['text'][text_idx]
                        except:
                            pass
                # use the closest to be updated with clustering coords
                closest_index = self.pose['text'].index(closest_to_centroid)
                water = self.pose['text'][closest_index]
                coord_text = "%8.3f%8.3f%8.3f" % (this_cluster_centroid[0], 
                                                  this_cluster_centroid[1],
                                                  this_cluster_centroid[2])
                cluster_water = water[0:30]+coord_text+water[54:] # XXX ugly, but it works...
                self.pose['text'][closest_index] = cluster_water
                # update water_bridge list+score, water_cluster_penalty list
                self.pose['water_bridge'].append(cluster_water)
                self.pose['water_bridge_scores'].append(this_cluster_energy)
                self.pose['water_cluster_penalty'].append(this_cluster_penalty)
                self.pose['water_bridge_contacts'].append(this_cluster_contacts)
                if self.debug:
                    print "CLUSTER SIZE", len(pop)
                    print "CLUSTER ENRG", this_cluster_energy
                    print "CLUSTER PENL", this_cluster_penalty
                    #print "CLUSTER FINL", clust_energy+clust_penalty
                    print "=============="
def findRings(graph):
    """
    a very simple ring detection algorightm to identify 5, and 6 member aromatic rings

            A    <- head
           / \   
          B   C  <- tier 1
          |   |
          D   E  <- tier 2
           \ /
            F    <- tier 3, ring closure (6 member-ring)

    
            A    <- head 
           / \              
          B   C  <- tier 1
          |   |
          D---E  <- tier 2, ring closure (5-member ring)


            A   <- head 
            |             
            B   <- tier 1
           / \
          C---D <- tier 2  # SPURIOUS, RECOGNIZED BUT NOT COUNTED

              
    """
    # TODO add a planarity check?
    rings5 = []
    rings6 = []
    if DEBUG: print "- starting ring detection..."
    for head in graph.keys():
        tier1 = graph[head]
        tier2 = []
        tier3 = []
        # populate tier2 
        for node1 in tier1:
            for tmp in graph[node1]:
                if not tmp == head and not tmp in tier2 and (not tmp in tier1) :
                    tier2.append(tmp)
        # populate tier3
        for node2 in tier2:
            for tmp in graph[node2]:
                if (not tmp == head) and (not tmp in tier2) and (not tmp in tier1) and (not tmp in tier3):
                    tier3.append(tmp)
        # 6 member rings
        for x in tier3:
            candidate  = []
            for c in tier2:
                if x in graph[c]:
                    if not c in candidate:
                        candidate.append(c)
            if len(candidate) >1:
                r6 = [ head ] 
                r6.append(x)
                r6 += candidate
                for c in candidate:
                    r6 += hf.intersect( graph[head], graph[c])
                r6.sort()
                if not r6 in rings6:
                    rings6.append( r6 )
                    if DEBUG: print "    6member!", r6
                break
        # 5 member rings
        for c1 in tier2:
            for c2 in tier2:
                if not c1 == c2:
                    if (c2 in graph[c1]) and (c1 in graph[c2]):
                        is_3_ring = False
                        for k in graph[c1]:
                            if k in graph[c2]: 
                                is_3_ring =True
                                if DEBUG: print "       [ ...catched a cycle_3... ]"
                                break
                        if not is_3_ring :
                            r5 = [ head ] 
                            r5.append(c1)
                            r5.append(c2)
                            r5 += hf.intersect( graph[head], graph[c1])
                            r5 += hf.intersect( graph[head], graph[c2])
                            r5.sort()
                            if not r5 in rings5:
                                if DEBUG: print "    5member ring!",r5
                                rings5.append(r5)
                        break
    return rings5, rings6
def findStacking(set1, set2 = None):
    """
    INPUT(set1, set2): scan the sets to find p- and t-stackings
    INPUT(set1): scan the set to find self-stackings (p-, t-)


    P-STACKING

        ---c---
           |
       A   V
       |
    ---c---       




    """
    DEBUG = 0

    MAXDIST_TSTACK = 5.0 # centroids distance (T-stacking)Angstroms 
    MAXDIST_PSTACK = 4.2 # centroids distance (P-stacking) Angstroms
    
    MAXDIST_PSTACK = MAXDIST_PSTACK**2
    MAXDIST_TSTACK = MAXDIST_TSTACK**2

    #MAXDIST = 5.0 # Angstroms
    #MAXDIST = MAXDIST**2

    PTOL = 29.9 # P-stacking plane angle tolerance (degr) TODO test values on a wide set!
    TTOL = 14.9 # T-stacking plane angle tolerance (degr) TODO test values on a wide set!
    PLANE_DIST_TSTACK = 2.5
    t_accepted = []
    p_accepted = []
    if not set2:
        set2 = set1
    for g1 in set1.keys():
        R1 = set1[g1]
        for g2 in set2.keys():
            if not g1 == g2: # this is for intramolecular stackings (set1 = set2)
                R2 = set2[g2]
                if not ([g1,g2] in p_accepted) and not ([g2,g1] in p_accepted):
                    if (not [g1,g2] in t_accepted) and not ([g2,g1] in t_accepted):
                        d = hf.quickdist(R1['centroid'], R2['centroid'])
                        if d <= MAXDIST_TSTACK:
                            #print "GOOD DIST: %2.3f" % sqrt(d),
                            pdist = abs(hf.dot( R1['normal'][0], (R1['centroid']-R2['centroid']) ))
                            pangle = abs(hf.vecAngle( R1['plane'], R2['plane']))
                            #print "DISTANCE: %2.2f <"% math.sqrt(d), math.sqrt(MAXDIST_TSTACK)
                            #print "PTOL", PTOL
                            #print "PDIST:", pdist 
                            #print "PANGLE:", pangle
                            #print "======"
                            #print "PANGLE-180", pangle-180
                            #print abs(pangle-180)<=PTOL or (pangle-PTOL)<=0
                            #print "PAANGLE-180 < PTOL", abs(pangle-180)<=PTOL
                            #print "PANGLE-PTOL", pangle-PTOL
                            #print "PANGLE-PTOL < 0", (pangle-PTOL)<=0
                            #print "\n\n"
                            if d <= MAXDIST_PSTACK and ((abs(pangle-180)<=PTOL) or ((pangle-PTOL)<=0)):
                                p_accepted.append([ g1, g2])
                                if DEBUG: 
                                    print " ==> P-stacking",
                                    print "%s--%s  plane angle: %2.1f | pdist: %2.2f\n\n" % (g1, g2, pangle, pdist), 
                            elif (( abs(pangle-90) <= TTOL) or ( abs(pangle-270)<=TTOL) ) and pdist < PLANE_DIST_TSTACK:
                                t_accepted.append([ g1, g2])
                                print "XXX"
                                if DEBUG:
                                    print "== > T-stacking",
                                    print "%s--%s  plane angle: %2.1f " % (g1, g2, pangle), 
                                    if ( abs(pangle-90) <= TTOL):
                                        print "ANGLE:",abs(pangle-90), "<", TTOL
                                    if ( abs(pangle-270)<=TTOL):
                                        print "ANGLE:", abs(pangle-270), "<", TTOL
                                    print "PLANE:",pdist, "<", PLANE_DIST_TSTACK
    return p_accepted, t_accepted 
        if lts:
            for p in lts:
                res =  p[0]
                rec_centroid = rec_vectors[p[0]]['centroid']
                lig_centroid = lig_vectors[p[1]]['centroid'] 
                tstack.append([res, rec_centroid, lig_centroid]) 
    return pstack, tstack

##################################################################
if __name__ == "__main__":
    from sys import argv
    import os
    
    # input must be PDBQT

    ligand = hf.getLines(argv[1])
    name = os.path.basename(argv[1])
    name = os.path.splitext(name)[0]

    try:
        if argv[2] =='-d':
            DEBUG=True
    except:
        pass

    lig_atoms = hf.getAtoms(ligand)
    ligand_rings = searchPiGroupsLig(lig_atoms)
    if not ligand_rings:
        print "No rings in the ligand"
        exit()
    else:
Example #18
0
    def clusterWaters(self):  #pose, clust_tolerance=2.0, desolvEntropy=0):
        # cluster waters
        # XXX
        # energy from the cluster?
        # once 3 waters are reclustered (3->1)
        # two desolvEntropy penalties should be issued?
        # XXX
        unclustered_waters = self.pose[
            'water_bridge'][:]  # XXX NOT SURE IT"S NECESSARY

        # cluster waters
        water_clusters = hf.clusterAtoms(unclustered_waters,
                                         tol=self.clust_tol)

        # calculate clustering energy
        self.pose['water_cluster_penalty'] = []
        remove_from_text = []
        for pop in water_clusters:
            if len(pop) > 1:
                this_cluster_centroid = hf.avgCoord(pop)
                this_cluster_penalty = -self.desolvEntropy * (len(pop) - 1)
                this_cluster_energy = 0
                this_cluster_contacts = []
                closest_to_centroid = None
                closest_dist = 999999
                for w in pop:
                    # get the w_index + w_score
                    idx = self.pose['water_bridge'].index(w)
                    this_cluster_energy += self.pose['water_bridge_scores'][
                        idx]
                    remove_from_text.append(w)
                    # find water closest to centroid (to be conserved)
                    # get the distance from the cluster average
                    centr_dist = hf.quickdist(hf.atomCoord(w),
                                              this_cluster_centroid,
                                              sq=False)
                    a = [hf.makePdb(coord=this_cluster_centroid)]
                    #writeList('centroid.pdb', a)
                    if centr_dist <= closest_dist:
                        closest_dist = centr_dist
                        closest_to_centroid = w
                    del self.pose['water_bridge'][idx]
                    del self.pose['water_bridge_scores'][idx]
                    # update contacts
                    for a in self.pose['water_bridge_contacts'][idx]:
                        if not a in this_cluster_contacts:
                            this_cluster_contacts.append(a)
                    del self.pose['water_bridge_contacts'][idx]
                # update PDBQT text
                # XXX DEBUGGINGH
                #print type(remove_from_text), remove_from_text[0]
                #writeList('REMOVING_WATERS.pdb', remove_from_text)
                #writeList('current_ligand.pdbqt', pose['text'])

                for w in remove_from_text:
                    if not w == closest_to_centroid:
                        try:
                            text_idx = self.pose['text'].index(w)

                            del self.pose['text'][text_idx]
                        except:
                            pass
                # use the closest to be updated with clustering coords
                closest_index = self.pose['text'].index(closest_to_centroid)
                water = self.pose['text'][closest_index]
                coord_text = "%8.3f%8.3f%8.3f" % (this_cluster_centroid[0],
                                                  this_cluster_centroid[1],
                                                  this_cluster_centroid[2])
                cluster_water = water[0:30] + coord_text + water[
                    54:]  # XXX ugly, but it works...
                self.pose['text'][closest_index] = cluster_water
                # update water_bridge list+score, water_cluster_penalty list
                self.pose['water_bridge'].append(cluster_water)
                self.pose['water_bridge_scores'].append(this_cluster_energy)
                self.pose['water_cluster_penalty'].append(this_cluster_penalty)
                self.pose['water_bridge_contacts'].append(
                    this_cluster_contacts)
                if self.debug:
                    print "CLUSTER SIZE", len(pop)
                    print "CLUSTER ENRG", this_cluster_energy
                    print "CLUSTER PENL", this_cluster_penalty
                    #print "CLUSTER FINL", clust_energy+clust_penalty
                    print "=============="