ó
Ń%Tc           @   s(  d  Z  d d l m Z m Z m Z m Z m Z d d l m Z d d l	 m
 Z
 m Z m Z m Z m Z m Z m Z m Z m Z d d l m Z d d l m Z m Z d d l m Z m Z m Z m Z e Z d Z e d	  Z d Z  d
 Z! d Z" d Z# d Z$ d	 Z% d Z& d f  d     YZ' d   Z( d S(   sS   A class to determine the coordinates of the next phosphate atom in electron densityi’’’’(   t   radianst   pit   cost   sint   sqrt(   t   LinearInterp(	   t   distt   anglet	   crossProdt
   scalarProdt   minust   plust	   magnitudet   torsiont   rotateAtoms(   t   ln(   t   mediant   lowerQuartile(   t   map_peaks_pyt!   map_peaks_near_point_from_list_pyt   density_at_pointt   add_molecule_pyi
   i   i   i   g      Š?i   t   NextPhosc           B   s   e  Z d  Z i  Z d   Z d   Z d d  Z d d  Z d   Z d   Z	 d   Z
 d d	  Z d
   Z d   Z e d  Z RS(   sS   A class to determine the coordinates of the next phosphate atom in electron densityc         C   sR   t  |  |  _ t  |  |  _ t  |  |  _ |  j |  |  _ t  |  |  _ d S(   s  Initialize the NextPhos object with distance and angle data
        
        ARGUMENTS:
           phosDistFilename             - the name of a file containing smoothed data about inter-phosphate distances
           phosAngleFilename            - the name of a file containing smoothed data about inter-phosphate angles
           sugarPhosSugarAngleFilename  - the name of a file containing smoothed data about sugar-phosphate-sugar angles
           basesFilename                - the name of a PDB file containing structures of all four bases
           pseudoChiFilename            - the name of a file containing smoothed data about the pseudo-chi torsion (i.e. about base rotation relative to a simple backbone trace)
        RETURNS:
            an initialized NextPhos object
        N(   R   t   _NextPhos__phosDistInterpt   _NextPhos__phosAngleInterpt$   _NextPhos__sugarPhosSugarAngleInterpt   _NextPhos__readBasest   _NextPhos__baseStrucst   _NextPhos__pseudoChiInterp(   t   selft   phosDistFilenamet   phosAngleFilenamet   sugarPhosSugarAngleFilenamet   basesFilenamet   pseudoChiFilename(    (    sV   /public2/ftp/pub/ccp4/6.5/ccp4-6.5/lib/python2.7/site-packages/coot/rcrane/nextPhos.pyt   __init__2   s
    c      	   C   sW  t  | d  } t d t   d t   d t   d t    } xµ | j   D]§ } | d d !d k rh qI n  | d	 d
 !j   } | d d !j   } t | d d ! } t | d d ! } t | d d ! }	 | j d d  } | | |	 g | | | <qI Wx\ | j   D]N }
 | |
 d } x7 | |
 j   D]% } t | |
 | |  | |
 | <q&WqW| S(   s"  Read nucleotide structures from the specified PDB file
        ARGUMENTS:
            filename - the name of a PDB file containing structures of all four bases
        RETURNS:
            struc    - a dictionary of file strucutres in the form base type => atom name => coordinates
        t   rt   At   Ct   Gt   Ui    i   s   ATOM  i   i   i   i   i   i&   i.   i6   t   *t   's   C1'(   t   opent   dictt	   readlinest   stript   floatt   replacet   keysR
   (   R   t   filenamet   inputt   struct   curlinet   atomNamet   resNamet   xt   yt   zt   curRest   c1loct   curAtom(    (    sV   /public2/ftp/pub/ccp4/6.5/ccp4-6.5/lib/python2.7/site-packages/coot/rcrane/nextPhos.pyt   __readBasesF   s"    -'i   c      
   C   s  |  j  | |  } g  } x| D]} t | |  d k r | d k r^ |  j | | |  }	 n |  j | | |  }	 |	 d d | d }
 t t |  j j t | |    t |  j j t | | |    t |  j	 j t | | |	 d d d !   t
 t |
  } | j | | |	 f  q q W| j d d   d d  g  | D] } | d ^ qH} g  | D] } | d ^ qe} | | f S(   sś  Find the next phosphate in a chain using phosphate distance and angle data
        
        ARGUMENTS:
            mapNum    - the molecule number of the Coot map to use
            curPhos   - the coordinates of the current phosphate
            prevPhos  - the coordinates of the previous phosphate
            prevSugar - the coordinates of the previous C1' atom
        OPTIONAL ARGUMENTS:
            direction - which direction to trace the chain: 3 implies 5'->3'
                                                            5 implies 3'->5'
                        defaults to 3 (5'->3')
        RETURNS:
            peakList  - a list of potential phosphate peaks
            sugarList - a list of potential C1' locations for each phosphate peak
        i   i   i    t   keyc         S   s   |  d S(   Ni   (    (   R8   (    (    sV   /public2/ftp/pub/ccp4/6.5/ccp4-6.5/lib/python2.7/site-packages/coot/rcrane/nextPhos.pyt   <lambda>   s    t   reversei   (   t   getPeaksR   t	   findSugart   PHOS_DIST_WEIGHTR   R   t   interpR   R   R   t   DENSITY_WEIGHTt   appendt   sort(   R   t   mapNumt   curPhost   prevPhost	   prevSugart	   directiont   peakst
   peakScorest   curPeakt	   sugarLocst   densityScoret   scoreR8   t   peakListt	   sugarList(    (    sV   /public2/ftp/pub/ccp4/6.5/ccp4-6.5/lib/python2.7/site-packages/coot/rcrane/nextPhos.pyt   nextPhosj   s    	c         C   s2  |  j  | |  } g  } xŗ | D]² } t | |  d k r | d k r^ |  j | | |  } n |  j | | |  } | d d | d } t |  j j t | |    t t |  }	 | j | |	 | f  q q W| j d d   d d  g  | D] }
 |
 d ^ qõ } g  | D] }
 |
 d ^ q} | | f S(   sm  find the second phosphate in a chain using phosphate distance data
        
        ARGUMENTS:
            mapNum    - the molecule number of the Coot map to use
            curPhos   - the coordinates of the first phosphate
        OPTIONAL ARGUMENTS:
            direction - which direction to trace the chain: 3 implies 5'->3'
                                                            5 implies 3'->5'
                        defaults to 3 (5'->3')
        RETURNS:
            peakList  - a list of potential phosphate peaks
            sugarList - a list of potential C1' locations for each phosphate peak
        i   i   i    R?   c         S   s   |  d S(   Ni   (    (   R8   (    (    sV   /public2/ftp/pub/ccp4/6.5/ccp4-6.5/lib/python2.7/site-packages/coot/rcrane/nextPhos.pyR@   Ļ   s    RA   i   (	   RB   R   RC   R   R   RE   t   SECOND_PHOS_DENSITY_WEIGHTRG   RH   (   R   RI   RJ   RM   RN   RO   RP   RQ   RR   RS   R8   RT   RU   (    (    sV   /public2/ftp/pub/ccp4/6.5/ccp4-6.5/lib/python2.7/site-packages/coot/rcrane/nextPhos.pyt
   secondPhos¬   s    /c            s/   |  j  |    } | j d   f d    | S(   s7  find the first phosphate in a chain
        
        ARGUMENTS:
            mapNum    - the molecule number of the Coot map to use
            curPos    - where to start the search (i.e. the current screen center coordinates)
        RETURNS:
            peaks     - a list of potential phosphate peaks
        R?   c            s   t    |   S(   N(   R   (   R8   (   t   curPos(    sV   /public2/ftp/pub/ccp4/6.5/ccp4-6.5/lib/python2.7/site-packages/coot/rcrane/nextPhos.pyR@   å   s    (   RB   RH   (   R   RI   RY   RN   (    (   RY   sV   /public2/ftp/pub/ccp4/6.5/ccp4-6.5/lib/python2.7/site-packages/coot/rcrane/nextPhos.pyt	   firstPhosŲ   s    
c          C   s9  t  | |  } d | d d | d } d | d } t d d d g t | |   } t |  d	 k  r t d d d g t | |   } n  t | | t |   } t | |  }	 t |	 | t |	   }	 t | |	  }
 t |
 |  }
 |  j | | |
  } xd| D]\} | d d
 !} d } t | |  } t | d t d  } x[ t d t d  D]F } t | t | |   \ } } } t	 | | | |  } | | 7} q\W| \ } } } t	 | | | |  } | | 7} t | |  } t | d t d  } x[ t d t d  D]F } t | t | |   \ } } } t	 | | | |  } | | 7} qW| j
 |  q	Wg  } | d d } | d d } | j
 | d  xk t d t |  d  D]P } | } | } | | d d } | | k  r¶| | k r¶| j
 | |  q¶q¶W| j d d   d t  xt d t |   D]ų } | | d d
 !} t | | |  } t | |  } t t | |  |  } t | d t |   } t | | d | d  } t | d t |   } t | | | d  } t | d t |   } t | | d  } t | |  | | d d
 +q9W| S(   s¢  find potential C1' locations between the given 5' and 3' phosphate coordinates
        
        ARGUMENTS:
            mapNum      - the molecule number of the Coot map to use
            phos5       - the coordinates of the 5' phosphate
            phos3       - the coordinates of the 3' phosphate
        RETURNS:
            sugarMaxima - a list of potential C1' locations, each listed as [x, y, z, score]
        gŽ°«ÉĒæi   gdu«ē¤÷ł?gįķAČæ?gĢĪ¢w*Ü?gPżHķ?i
   i    gü©ńŅMbP?i   g      š?i   i’’’’i   R?   c         S   s   |  d S(   Ni   (    (   R8   (    (    sV   /public2/ftp/pub/ccp4/6.5/ccp4-6.5/lib/python2.7/site-packages/coot/rcrane/nextPhos.pyR@   T  s    RA   gÆ°ą~@b@gģų/Äó?g1Šµ/ŚQĄ(   R   R   R
   R   R	   R   t   _NextPhos__rotateSugarCentert   DENSITY_CHECK_POINTSt   rangeR   RG   t   lenRH   t   TrueR   t   rotate(    R   RI   t   phos5t   phos3t   phosPhosDistt   perpDistt   projDistt   normalt
   perpVectort
   projVectort   sugarLoct   sugarRotationPointst   curSugarLocFullt   curSugarLoct   curDensityTotalt   phosSugarVectort   iR8   R9   R:   t   curPointDensityt   sugarPhosVectort   sugarMaximat   curPeakHeightt   nextPeakHeightt   prevPeakHeightt   curSugart	   phosAnglet   phos5vectort   axist   c1vect   phosBisectorAxis(    (    sV   /public2/ftp/pub/ccp4/6.5/ccp4-6.5/lib/python2.7/site-packages/coot/rcrane/nextPhos.pyRC   ź   sn    !$!
! c         C   s  t  | |  } t | d t |   } | \ } } } t  | |  \ } }	 }
 | d g } | g } t } x| d t d t k  rt |  } t |  } | | | |	 | |
 } | | | | | | | |
 | |	 | | d } | | |	 | | | | | | |
 | | d } | | |
 | | | | |	 | | | | d } | j | | | | g  | t 7} qn W| S(   s±  rotate the sugar center by 360 degrees in ROTATE_SUGAR_INTERVAL increments
        
        ARGUMENTS:
            phos5         - the coordinates of the 5' phosphate
            phos3         - the coordinates of the 3' phosphate
            sugarCenter   - the coordinates of the sugar center to be rotated
        RETURNS:
            rotatedPoints - a list of the rotated points, each listed as [x, y, z, rotation angle]
        i   i    i   g      ą?(   R
   R	   R   t   SUGAR_ROTATION_INTERVALR   R   R   RG   (   R   Ra   Rb   t   sugarCenterRy   t   ut   vt   wR8   R9   R:   t   sugarCenterRott   rotatedPointst   curAnglet   cosThetat   sinThetat   at   newXt   newYt   newZ(    (    sV   /public2/ftp/pub/ccp4/6.5/ccp4-6.5/lib/python2.7/site-packages/coot/rcrane/nextPhos.pyt   __rotateSugarCenterm  s"    	666c   %   	   C   s  | d k r | | } } n  t  | |  } t  | |  } t | |  }	 t |	 d t |	   }	 t | | |  }
 t | |	 |
 d  } t | d t |   } | g } x t d d d  t d d d  D]k } t | |	 |  } | j |  xC t d d d  t d d d  D] } | j t | | |   qWqĻ Wxø | D]° } d } g  } xh t d	 d
  D]W } t | t | d |   \ } } } t	 | | | |  } | | 7} | j |  qgW| j |  | j t
 |   | j t |   qEWt | d d   } t |  j d d d d d g |  } t |  j d d | d d ! } t |  j d | |  } d } d } xŪ t d d d  D]Ē } t | | d | |  }  d }! xQ d d d d d d g D]7 }" |! t	 | |  |" d |  |" d	 |  |" d  7}! qĖWt | | |  d |  d  }# |! |  j j |#  9}! |! | k r|! } |  } qqWd | g }$ | d k r|  j |$ |  }$ n  |$ S(   s  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]
        i   g      š?g       @i’’’’i¦’’’i
   i[   i    i   i	   R?   c         S   s   |  d S(   Ni   (    (   R8   (    (    sV   /public2/ftp/pub/ccp4/6.5/ccp4-6.5/lib/python2.7/site-packages/coot/rcrane/nextPhos.pyR@   Ņ  s    R&   t   C4i   iĮ½š’ih  t   N1t   C2t   N3t   C5t   C6i   N(   R
   R   R	   R   R   R`   R]   RG   R   R   R   t   mint   maxR   R   t   NoneR   R   RE   t
   mutateBase(%   R   RI   t   sugarRa   Rb   t   baseTypeRM   t   sugarPhos5Vect   sugarPhos3VecRf   t   phosSugarPhosAnglet   bisectort   startingBasePost	   rotationst   curThetat   curRotationt   curPhit   curBatonRm   t   densityListRo   R8   R9   R:   Rp   t   baseDirt   rotationAngleRy   t   orientedBaset   bestFitBaset
   maxDensityR   t   rotatedBaset
   curDensityR=   t	   pseudoChit   baseObj(    (    sV   /public2/ftp/pub/ccp4/6.5/ccp4-6.5/lib/python2.7/site-packages/coot/rcrane/nextPhos.pyt   findBase  s\    	))!%
&!5c         C   st  | \ } } d } | d k s* | d k rD t | d | d  } n= t | d | d  } t d d |  } t | | d  } |  j | } d } | d k s¬ | d k r¹ | d } n* t | d | d  } t d d |  } t | d d d g |  }	 t | |  }
 t | |
 |	  } d } | d k s>| d k rrt t | d	 | d
  t | d | d
   } n1 t t | d	 | d  t | d | d   } d } | d k sĮ| d k rõt t | d	 | d
  t | d | d
   } n1 t t | d	 | d  t | d | d   } t | d d d g |  } t | |  } t | | | | d  } | | g S(   s  Change the base type.
        
        ARGUMENTS:
            curBase - the current base object in the form [baseType, baseCoordinates]
            newBaseType - the base type to mutate to
        RETURNS:
            baseObj  - a list of [baseType, baseCoordinates]
        R&   R(   R   s   C1'R   g      š?g       @i    R   R   R   t   N9t   N7N(   R   R
   R   R	   R   R   R   R   (   R   t   curBaset   newBaseTypet   curBaseTypet   curBaseCoordst   curAlignmentVectort   curBaseCentert   newBaseCoordst   newAlignmentVectorR£   Ry   t	   curNormalt	   newNormalt   normalAnglet
   normalAxis(    (    sV   /public2/ftp/pub/ccp4/6.5/ccp4-6.5/lib/python2.7/site-packages/coot/rcrane/nextPhos.pyR   ō  s8    
4141c   	      C   sÄ   | \ } } | d } i  } x1 | j    D]# \ } } t | | |  | | <q) Wd	 } | d k sn | d k r{ | d } n* t | d | d  } t d d |  } t | | d |  } | | g S(
   s¶  Flip the base anti/syn
        
        ARGUMENTS:
            curBase - the current base object in the form [baseType, baseCoordinates]
        RETURNS:
            the base object with rotated coordinates
        NOTE:
            This function does not necessarily simply rotate about chi.  When flipping a purine, it also adjusts
            the glycosidic bond position so that it the base a chance of staying in the density
        s   C1'R&   R(   R   R   g      š?g       @i“   N(   t   itemsR
   R   R   R	   R   (	   R   R®   R   R±   t   curC1coordsR“   R6   t   curAtomCoordsRy   (    (    sV   /public2/ftp/pub/ccp4/6.5/ccp4-6.5/lib/python2.7/site-packages/coot/rcrane/nextPhos.pyt   flipBase3  s    
c         C   sĖ  | \ } } } | |  j  k rcg  } t   } t }	 x|	 t k rRt | |	  }
 xń |
 D]é } y  | | d | d | d WqX t k
 r@| j |  | j | d  sĀ t   | | d <n  | | d j | d  sł t   | | d | d <n  | | d | d j | d  sAt | | d | d | d <qAqX XqX W|	 t	 8}	 q6 W| |  j  | <n  t
 | |  j  | | | | |  } x? | D]7 } | \ } } } t | | | |  } | j |  qW| S(   sć  Get a list of peaks in the map near a given position
        
        ARGUMENTS:
            mapNum      - the molecule number of the Coot map to use
            pos         - the coordinates to search near
        OPTIONAL ARGUMENTS:
            radius      - how far from pos should we look for peaks?
                          defaults to RADIUS (defined at the top of this file)
        RETURNS:
            closePeaks  - a list of peaks in the format [x, y, z, density]
        i    i   i   (   t   _NextPhos__peakListR,   t   GET_PEAKS_STARTING_SIGMAt   GET_PEAKS_ENDING_SIGMAR   t   KeyErrorRG   t   has_keyR_   t   GET_PEAKS_SIGMA_STEPR   R   (   R   RI   t   post   radiusR8   R9   R:   RT   t   peakHasht   curSigmat   curPeakst   peakt
   closePeaksRP   t   density(    (    sV   /public2/ftp/pub/ccp4/6.5/ccp4-6.5/lib/python2.7/site-packages/coot/rcrane/nextPhos.pyRB   X  s4    	 #)"(   t   __name__t
   __module__t   __doc__R¾   R#   R   RV   RX   RZ   RC   R[   R«   R   R½   t   RADIUSRB   (    (    (    sV   /public2/ftp/pub/ccp4/6.5/ccp4-6.5/lib/python2.7/site-packages/coot/rcrane/nextPhos.pyR   *   s   		$B,			'`	?	%c         C   só   | \ } } } |  \ } } } t  |  } t |  }	 t |  }
 | | | | | | } | | | | | |	 | | | | |
 } | | | | | |	 | | | | |
 } | | | | | |	 | | | | |
 } | | | g S(   s  Rotate a vector.
    
    ARGUMENTS:
        vector - the vector to rotate
        axis   - the axis to rotate about (note that this MUST be a unit vector)
        angle  - the angle to rotate by
    RETURNS:
        the rotated vector
    NOTE:
        This function is very similar to the rotateAtoms() function defined in strucCalc.py, but rotate()
        rotates only a single vector, not a list of atoms; rotate() doesn't normalize the axis vector; and
        rotate() has no optional translate argument.  This module could easily be rewritten to use
        rotateAtoms() instead, but rotate() may be slightly faster, so I've kept it.
    (   R    R   R   (   t   vectorRy   R   R~   R   R   R8   R9   R:   R   R   R   R   R   R   (    (    sV   /public2/ftp/pub/ccp4/6.5/ccp4-6.5/lib/python2.7/site-packages/coot/rcrane/nextPhos.pyR`     s    ...N()   RĪ   t   mathR    R   R   R   R   t   linearInterpR   t	   strucCalcR   R   R   R	   R
   R   R   R   R   t   safelogR   t   statsR   R   t   cootR   R   R   R   t   add_moleculeRĻ   R|   R\   Ræ   RĄ   RĆ   RF   RD   RW   R   R`   (    (    (    sV   /public2/ftp/pub/ccp4/6.5/ccp4-6.5/lib/python2.7/site-packages/coot/rcrane/nextPhos.pyt   <module>   s(   (@"’ ’ k