Example #1
0
 def buildSugar(self, baseAtoms, pucker):
     """Build a sugar of the specified pucker onto a base
     
     ARGUMENTS:
         baseAtoms - a dictionary of base atoms in the form atomName:[x, y, z]
                     Note that this dictionary MUST contain the C1' atom
         pucker    - the pucker of the sugar to be built (passed as an integer, either 2 or 3)
     RETURNS:
         coordinates for a sugar of the specified pucker in anti configuration with the base
     """
     
     #fetch the appropriate sugar structure
     if pucker == 3:
         sugarAtoms = self.__c3pAtoms
     elif pucker == 2:
         sugarAtoms = self.__c2pAtoms
     else:
         raise "BuildInitSugar called with unrecognized pucker: " + str(pucker)
     #I don't have to worry about accidentally modifying the original atom dictionaries, since
     #rotateAtoms effectively makes a deep copy
     
     #figure out which base atoms to use for alignment
     if baseAtoms.has_key("N9"):
         Natom = "N9"
         Catom = "C4"
     else:
         Natom = "N1"
         Catom = "C2"
     
     
     #rotate the sugar so the glycosidic bond is at the appropriate angle
     #first, calculate an axis for this rotation
     translatedBaseN = minus(baseAtoms[Natom], baseAtoms["C1'"])
     sugarN = sugarAtoms[Natom]
     
     axis = crossProd(sugarN, translatedBaseN)
     angle = torsion(translatedBaseN, axis, (0,0,0), sugarN)
     
     #if either angle or magnitude(axis) is 0, then the glycosidic bond is already oriented appropriately
     if not(angle == 0 or magnitude(axis) == 0):
         sugarAtoms = rotateAtoms(sugarAtoms, axis, angle)
     
     
     #next, rotate the sugar so that chi is appropriate
     translatedBaseC = minus(baseAtoms[Catom], baseAtoms["C1'"])
     curChi = torsion(translatedBaseC, translatedBaseN, [0,0,0], sugarAtoms["O4'"])
     sugarAtoms = rotateAtoms(sugarAtoms, translatedBaseN, curChi - STARTING_CHI)
     
     #remove the unnecessary atoms from the sugarAtoms dict
     del sugarAtoms["N1"]
     del sugarAtoms["N9"]
     
     #translate the sugar to the C1' atom of the base
     sugarAtoms = dict([(atom, plus(coords, baseAtoms["C1'"])) for (atom, coords) in sugarAtoms.iteritems()])
     
     return sugarAtoms
Example #2
0
 def theta(self):
     """Calculate the theta pseudotorsion for the current nucleotide
     
     ARGUMENTS:
         None
     RETURNS:
         The value of theta if it is defined, None otherwise.
     NOTE:
         Calculating theta requires the phosphate and sugar atom of the next nucleotide.
         As a result, behaviour of this function is undefined if this nucleotide
         is not part of a chain.  (Currently, it raises an error.)
     """
     
     if (self.connectedToNext()
           and self.hasAtom("P")
           and self.hasAtom(SUGARATOM)
           and self.nextNuc().hasAtom("P")
           and self.nextNuc().hasAtom(SUGARATOM)):
         
         return torsion(self.atoms["P"],
                            self.atoms[SUGARATOM],
                            self.nextNuc().atoms["P"],
                            self.nextNuc().atoms[SUGARATOM])
     else:
         return None
Example #3
0
 def theta(self):
     """Calculate the theta pseudotorsion for the current nucleotide
     
     ARGUMENTS:
         None
     RETURNS:
         The value of theta if it is defined, None otherwise.
     NOTE:
         Calculating theta requires the phosphate and sugar atom of the next nucleotide.
         As a result, behaviour of this function is undefined if this nucleotide
         is not part of a chain.  (Currently, it raises an error.)
     """
     
     if (self.connectedToNext()
           and self.hasAtom("P")
           and self.hasAtom(SUGARATOM)
           and self.nextNuc().hasAtom("P")
           and self.nextNuc().hasAtom(SUGARATOM)):
         
         return torsion(self.atoms["P"],
                            self.atoms[SUGARATOM],
                            self.nextNuc().atoms["P"],
                            self.nextNuc().atoms[SUGARATOM])
     else:
         return None
Example #4
0
    def delta(self):
        """Calculate the delta torsion
        
        ARGUMENTS:
            None
        RETURNS:
            The value of delta if it is defined, None otherwise.
        """

        if (self.hasAtom("C5'") and self.hasAtom("C4'") and self.hasAtom("C3'")
                and self.hasAtom("O3'")):

            return torsion(self.atoms["C5'"], self.atoms["C4'"],
                           self.atoms["C3'"], self.atoms["O3'"])

        else:
            return None
Example #5
0
    def zeta(self):
        """Calculate the zeta torsion
        
        ARGUMENTS:
            None
        RETURNS:
            The value of zeta if it is defined, None otherwise.
        """

        if (self.connectedToNext() and self.hasAtom("C3'")
                and self.hasAtom("O3'") and self.nextNuc().hasAtom("P")
                and self.nextNuc().hasAtom("O5'")):

            return torsion(self.atoms["C3'"], self.atoms["O3'"],
                           self.nextNuc().atoms["P"],
                           self.nextNuc().atoms["O5'"])

        else:
            return None
Example #6
0
    def alpha(self):
        """Calculate the alpha torsion
        
        ARGUMENTS:
            None
        RETURNS:
            The value of alpha if it is defined, None otherwise.
        """

        if (self.connectedToPrev() and self.prevNuc().hasAtom("O3'")
                and self.hasAtom("P") and self.hasAtom("O5'")
                and self.hasAtom("C5'")):

            return torsion(self.atoms["C5'"], self.atoms["O5'"],
                           self.atoms["P"],
                           self.prevNuc().atoms["O3'"])

        else:
            return None
Example #7
0
 def delta(self):
     """Calculate the delta torsion
     
     ARGUMENTS:
         None
     RETURNS:
         The value of delta if it is defined, None otherwise.
     """
     
     if   (self.hasAtom("C5'")
       and self.hasAtom("C4'")
       and self.hasAtom("C3'")
       and self.hasAtom("O3'")):
         
         return torsion(self.atoms["C5'"],
                        self.atoms["C4'"],
                        self.atoms["C3'"],
                        self.atoms["O3'"])
             
     else:
         return None
Example #8
0
 def zeta(self):
     """Calculate the zeta torsion
     
     ARGUMENTS:
         None
     RETURNS:
         The value of zeta if it is defined, None otherwise.
     """
     
     if (self.connectedToNext()
           and self.hasAtom("C3'")
           and self.hasAtom("O3'")
           and self.nextNuc().hasAtom("P")
           and self.nextNuc().hasAtom("O5'")):
         
         return torsion(self.atoms["C3'"],
                        self.atoms["O3'"],
                        self.nextNuc().atoms["P"],
                        self.nextNuc().atoms["O5'"])
             
     else:
         return None
Example #9
0
 def alpha(self):
     """Calculate the alpha torsion
     
     ARGUMENTS:
         None
     RETURNS:
         The value of alpha if it is defined, None otherwise.
     """
     
     if (self.connectedToPrev()
           and self.prevNuc().hasAtom("O3'")
           and self.hasAtom("P")
           and self.hasAtom("O5'")
           and self.hasAtom("C5'")):
         
         return torsion(self.atoms["C5'"],
                        self.atoms["O5'"],
                        self.atoms["P"],
                        self.prevNuc().atoms["O3'"])
             
     else:
         return None
Example #10
0
 def findBase(self, mapNum, sugar, phos5, phos3, baseType, direction = 3):
     """Rotate the sugar center by 360 degrees in ROTATE_SUGAR_INTERVAL increments
     
     ARGUMENTS:
         mapNum   - the molecule number of the Coot map to use
         sugar    - the coordinates of the C1' atom
         phos5    - the coordinates of the 5' phosphate
         phos3    - the coordinates of the 3' phosphate
         baseType - the base type (A, C, G, or U)
     OPTIONAL ARGUMENTS:
         direction - which direction are we tracing the chain
                     if it is 5 (i.e. 3'->5'), then phos5 and phos3 will be flipped
                     all other values will be ignored
                     defaults to 3 (i.e. 5'->3')
     RETURNS:
         baseObj  - a list of [baseType, baseCoordinates]
     """
     
     if direction == 5:
         (phos5, phos3) = (phos3, phos5)
     
     #calculate the bisector of the phos-sugar-phos angle
     #first, calculate a normal to the phos-sugar-phos plane
     sugarPhos5Vec = minus(phos5, sugar)
     sugarPhos3Vec = minus(phos3, sugar)
     normal = crossProd(sugarPhos5Vec, sugarPhos3Vec)
     normal = scalarProd(normal, 1.0/magnitude(normal))
     
     phosSugarPhosAngle = angle(phos5, sugar, phos3)
     
     bisector = rotate(sugarPhos5Vec, normal, phosSugarPhosAngle/2.0)
     
     
     #flip the bisector around (so it points away from the phosphates) and scale its length to 5 A
     startingBasePos = scalarProd(bisector, -1/magnitude(bisector))
     
     #rotate the base baton by 10 degree increments about half of a sphere
     rotations = [startingBasePos] #a list of coordinates for all of the rotations
     for curTheta in range(-90, -1, 10) + range(10, 91, 10):
         curRotation = rotate(startingBasePos, normal, curTheta)
         rotations.append(curRotation) #here's where the phi=0 rotation is accounted for
         
         for curPhi in range(-90, -1, 10) + range(10, 91, 10):
             rotations.append(rotate(curRotation, startingBasePos, curPhi))
             
     #test electron density along all base batons
     for curBaton in rotations:
         curDensityTotal = 0
         densityList = []
         for i in range(1, 9):
             (x, y, z) = plus(sugar, scalarProd(i/2.0, curBaton))
             curPointDensity = density_at_point(mapNum, x, y, z)
             curDensityTotal += curPointDensity
             densityList.append(curPointDensity)
         curBaton.append(curDensityTotal)        #the sum of the density (equivalent to the mean for ordering purposes)
         curBaton.append(median(densityList))    #the median of the density
         curBaton.append(min(densityList))       #the minimum of the density
     
     #find the baton with the max density (as measured using the median)
     #Note that we ignore the sum and minimum of the density.  Those calculations could be commented out,
     #   but they may be useful at some point in the future.  When we look at higher resolutions maybe?
     #   Besides, they're fast calculations.)
     baseDir = max(rotations, key = lambda x: x[4])
     
     #rotate the stock base+sugar structure to align with the base baton
     rotationAngle = angle(self.__baseStrucs["C"]["C4"], [0,0,0], baseDir)
     axis = crossProd(self.__baseStrucs["C"]["C4"], baseDir[0:3])
     
     orientedBase = rotateAtoms(self.__baseStrucs["C"], axis, rotationAngle)
     
     #rotate the base about chi to find the best fit to density
     bestFitBase = None
     maxDensity = -999999
     for curAngle in range(0,360,5):
         rotatedBase = rotateAtoms(orientedBase, orientedBase["C4"], curAngle, sugar)
         curDensity = 0
         for curAtom in ["N1", "C2", "N3", "C4", "C5", "C6"]:
             curDensity += density_at_point(mapNum, rotatedBase[curAtom][0], rotatedBase[curAtom][1], rotatedBase[curAtom][2])
         
         #this is "pseudoChi" because it uses the 5' phosphate in place of the O4' atom
         pseudoChi = torsion(phos5, sugar, rotatedBase["N1"], rotatedBase["N3"])
         curDensity *= self.__pseudoChiInterp.interp(pseudoChi)
         
         if curDensity > maxDensity:
             maxDensity = curDensity
             bestFitBase = rotatedBase
     
     baseObj = ["C", bestFitBase]
     
     #mutate the base to the appropriate type
     if baseType != "C":
         baseObj = self.mutateBase(baseObj, baseType)
     
     return baseObj
Example #11
0
 def findBase(self, mapNum, sugar, phos5, phos3, baseType, direction = 3):
     """Rotate the sugar center by 360 degrees in ROTATE_SUGAR_INTERVAL increments
     
     ARGUMENTS:
         mapNum   - the molecule number of the Coot map to use
         sugar    - the coordinates of the C1' atom
         phos5    - the coordinates of the 5' phosphate
         phos3    - the coordinates of the 3' phosphate
         baseType - the base type (A, C, G, or U)
     OPTIONAL ARGUMENTS:
         direction - which direction are we tracing the chain
                     if it is 5 (i.e. 3'->5'), then phos5 and phos3 will be flipped
                     all other values will be ignored
                     defaults to 3 (i.e. 5'->3')
     RETURNS:
         baseObj  - a list of [baseType, baseCoordinates]
     """
     
     if direction == 5:
         (phos5, phos3) = (phos3, phos5)
     
     #calculate the bisector of the phos-sugar-phos angle
     #first, calculate a normal to the phos-sugar-phos plane
     sugarPhos5Vec = minus(phos5, sugar)
     sugarPhos3Vec = minus(phos3, sugar)
     normal = crossProd(sugarPhos5Vec, sugarPhos3Vec)
     normal = scalarProd(normal, 1.0/magnitude(normal))
     
     phosSugarPhosAngle = angle(phos5, sugar, phos3)
     
     bisector = rotate(sugarPhos5Vec, normal, phosSugarPhosAngle/2.0)
     
     
     #flip the bisector around (so it points away from the phosphates) and scale its length to 5 A
     startingBasePos = scalarProd(bisector, -1/magnitude(bisector))
     
     #rotate the base baton by 10 degree increments about half of a sphere
     rotations = [startingBasePos] #a list of coordinates for all of the rotations
     for curTheta in range(-90, -1, 10) + range(10, 91, 10):
         curRotation = rotate(startingBasePos, normal, curTheta)
         rotations.append(curRotation) #here's where the phi=0 rotation is accounted for
         
         for curPhi in range(-90, -1, 10) + range(10, 91, 10):
             rotations.append(rotate(curRotation, startingBasePos, curPhi))
             
     #test electron density along all base batons
     for curBaton in rotations:
         curDensityTotal = 0
         densityList = []
         for i in range(1, 9):
             (x, y, z) = plus(sugar, scalarProd(i/2.0, curBaton))
             curPointDensity = density_at_point(mapNum, x, y, z)
             curDensityTotal += curPointDensity
             densityList.append(curPointDensity)
         curBaton.append(curDensityTotal)        #the sum of the density (equivalent to the mean for ordering purposes)
         curBaton.append(median(densityList))    #the median of the density
         curBaton.append(min(densityList))       #the minimum of the density
     
     #find the baton with the max density (as measured using the median)
     #Note that we ignore the sum and minimum of the density.  Those calculations could be commented out,
     #   but they may be useful at some point in the future.  When we look at higher resolutions maybe?
     #   Besides, they're fast calculations.)
     baseDir = max(rotations, key = lambda x: x[4])
     
     #rotate the stock base+sugar structure to align with the base baton
     rotationAngle = angle(self.__baseStrucs["C"]["C4"], [0,0,0], baseDir)
     axis = crossProd(self.__baseStrucs["C"]["C4"], baseDir[0:3])
     
     orientedBase = rotateAtoms(self.__baseStrucs["C"], axis, rotationAngle)
     
     #rotate the base about chi to find the best fit to density
     bestFitBase = None
     maxDensity = -999999
     for curAngle in range(0,360,5):
         rotatedBase = rotateAtoms(orientedBase, orientedBase["C4"], curAngle, sugar)
         curDensity = 0
         for curAtom in ["N1", "C2", "N3", "C4", "C5", "C6"]:
             curDensity += density_at_point(mapNum, rotatedBase[curAtom][0], rotatedBase[curAtom][1], rotatedBase[curAtom][2])
         
         #this is "pseudoChi" because it uses the 5' phosphate in place of the O4' atom
         pseudoChi = torsion(phos5, sugar, rotatedBase["N1"], rotatedBase["N3"])
         curDensity *= self.__pseudoChiInterp.interp(pseudoChi)
         
         if curDensity > maxDensity:
             maxDensity = curDensity
             bestFitBase = rotatedBase
     
     baseObj = ["C", bestFitBase]
     
     #mutate the base to the appropriate type
     if baseType != "C":
         baseObj = self.mutateBase(baseObj, baseType)
     
     return baseObj