ó
ž™xTc           @   s�  d  d l  m Z d  d l m Z d  d l m Z d  d l m Z d  d l m	 Z	 d  d l
 m Z d  d l Z d e f d	 „  ƒ  YZ d
 e f d „  ƒ  YZ d e f d „  ƒ  YZ d d e d d „ Z d „  Z d „  Z d „  Z d „  Z d „  Z d d „ Z d „  Z d d d „ Z d d d „ Z d d d „ Z d „  Z d „  Z d  „  Z d! d" d d# „ Z  d$ „  Z! d% „  Z" d& „  Z# d d d' „ Z$ d S((   iÿÿÿÿ(   t   division(   t   eigensystem(   t   flex(   t	   superpose(   t   Sorry(   t   matrixNt   NCS_groups_containerc           B   s   e  Z d  „  Z RS(   c         C   s(   g  |  _  g  |  _ g  |  _ g  |  _ d S(   sq  
    A Container for ncs groups
    Note that the first copy is the master ncs

    Attributes:
      iselections (list of flex.size_t):selection array for the complete ASU
      residue_index_list (list): list of list of matching residues indices
      copies (list of lists):List of lists of the ncs copies chain IDs
      transforms (list of transform objects):
    N(   t   iselectionst   residue_index_listt   copiest
   transforms(   t   self(    (    sB   /public2/ftp/pub/ccp4/6.5/ccp4-6.5/lib/py2/mmtbx/ncs/ncs_search.pyt   __init__   s    			(   t   __name__t
   __module__R   (    (    (    sB   /public2/ftp/pub/ccp4/6.5/ccp4-6.5/lib/py2/mmtbx/ncs/ncs_search.pyR   	   s   t	   Transformc           B   s#   e  Z d d d d d d  d „ Z RS(   i    c         C   s@   | |  _  | |  _ | |  _ t | ƒ |  _ | |  _ | |  _ d S(   s‹  
    Basic transformation properties

    Args:
      rotation : Rotation matrix object
      translation: Translation matrix object
      serial_num : (int) Transform serial number
      coordinates_present: equals 1 when coordinates are presents in PDB file
      ncs_group_id : (int) The group ID of the group containing this transform
      rmsd (float): RMS distance between ncs copies
    N(   t   rt   tt
   serial_numt   boolt   coordinates_presentt   ncs_group_idt   rmsd(   R   t   rotationt   translationR   R   R   R   (    (    sB   /public2/ftp/pub/ccp4/6.5/ccp4-6.5/lib/py2/mmtbx/ncs/ncs_search.pyR      s    				N(   R   R   t   NoneR   (    (    (    sB   /public2/ftp/pub/ccp4/6.5/ccp4-6.5/lib/py2/mmtbx/ncs/ncs_search.pyR      s   t   Score_recordc           B   s&   e  Z d  d d d d „ Z d „  Z RS(   i
   i    i   c         C   s:   | |  _  d |  _ d |  _ | |  _ | |  _ | |  _ d S(   sÎ  
    score object used when aligning sequences

    Attributes:
      score (int)
      consecutive_matches (int): num of consecutive matches in current segment
      match_count (int): number of matching residues
      min_contig_length (int): segments < min_contig_length rejected
      gap_penalty (int): penalty for gaps
      origin (tuple): (row,col) of the matrix cell we from the previous
        alignment step. Used to trace back optimal alignment
    i    N(   t   scoret   consecutive_matchest   match_countt   min_contig_lengtht   gap_penaltyt   origin(   R   R   R   R   R    (    (    sB   /public2/ftp/pub/ccp4/6.5/ccp4-6.5/lib/py2/mmtbx/ncs/ncs_search.pyR   8   s    					c         C   s\   t  |  j | ƒ } |  j | k  rO |  j |  j |  j 8_ |  j |  j 8_ n  d |  _ d S(   sÜ   
    Args:
      seq_length (int): length of shortest of the compared lists

    When there is a gap in the matching, reset the consecutive_matches and
    adjust the score if consecutive_matches < min_contig_length
    i    N(   t   minR   R   R   R   R   (   R   t
   seq_lengtht   min_matches(    (    sB   /public2/ftp/pub/ccp4/6.5/ccp4-6.5/lib/py2/mmtbx/ncs/ncs_search.pyt   reset_match_countingN   s
    (   i    i    (   R   R   R   R$   (    (    (    sB   /public2/ftp/pub/ccp4/6.5/ccp4-6.5/lib/py2/mmtbx/ncs/ncs_search.pyR   6   s   i
   gš™™™™™É?g      @c   	      C   sm   t  d |  d | d | ƒ } t | |  | ƒ } | rH t | ƒ \ } } n t | ƒ \ } } t | | ƒ } | S(   s�  
  Find NCS relation in hierarchy

  Args:
    ph (object): hierarchy
    min_contig_length (int): minimum length of matching chain segments
    min_fraction_domain (float): Threshold for similarity between chains
      similarity define as:
      (number of matching res) / (number of res in longer chain)
    use_minimal_master_ncs (bool): use maximal or minimal common chains
        in master ncs groups
    rmsd_eps (float): limit of rms difference chains when aligned together

  Return:
    groups_list (list of NCS_groups_container objects)
    group_dict (dict):
      keys: tuple of master chain IDs
      values: NCS_groups_container objects
  t   phR   t   min_fraction_domain(   t   search_ncs_relationst   clean_chain_matchingt   minimal_master_ncs_groupingt   minimal_ncs_operators_groupingt   build_group_dict(	   R%   R   R&   t   use_minimal_master_ncst   rmsd_epst   chain_match_listt
   match_dictt   transform_to_groupt
   group_dict(    (    sB   /public2/ftp/pub/ccp4/6.5/ccp4-6.5/lib/py2/mmtbx/ncs/ncs_search.pyt   find_ncs_in_hierarchy\   s    	c   8      C   s³  t  |  ƒ } d „  | Dƒ } t  | ƒ } i  } i  } t ƒ  } d } xj| D]b\ } } |  | | f \ }	 }
 } } } } } | | k r� qJ n  | | k rŸ qJ n  t | | | ƒ \ } } | rD| | | d k rç d } | | } } qQ| | } } |  j | | f ƒ t | | ƒ \ } } |
 |	 | | | | | g |  | | f <n | | } } | rS| | d } | | k r¬| j | ƒ rÃ| j | d ƒ } x | D] } | j | d ƒ q™W| g | | <n  | j | ƒ r| j | d ƒ } x! | D] } | j | d ƒ qëWn  | | d j | ƒ | | d j | ƒ | j t | | d ƒ ƒ q¬qJ | d 7} | g | g | | f g | | <| j | ƒ rŸ| | j | ƒ qJ | g | | <qJ Wx¸ | j	 ƒ  D]ª \ } } | d } | d } t | ƒ t | ƒ @} xU | rJ| j ƒ  } | j
 | ƒ } | j | ƒ | j | ƒ t | ƒ t | ƒ @} qöW| | | d <| | | d <q½Wg  | j	 ƒ  D]( \ } } t | d ƒ d k rx| ^ qx} g  | j	 ƒ  D]( \ } } t | d ƒ d k r³| ^ q³} x| D]}  | |  d }! | |  d }" xí | D]å }# | j |# ƒ r| |# d d }$ | |# d d }% |$ |! k o_|% |" k }& |% |! k ow|$ |" k }' |% |" k o�|$ |" k }( |% |! k o§|$ |! k }) |% | k o¿|$ | k }* |& sà|' sà|( sà|) sà|* rö| j |# d ƒ qöqqWqèWg  | j	 ƒ  D]" \ } } t | d ƒ | g ^ q}+ |+ j ƒ  t | ƒ }, t ƒ  }- t ƒ  }. t ƒ  }/ x	t |, ƒ rot |+ ƒ ro|+ j ƒ  \ }0 } | | \ } } \ }1 }2 t t | ƒ |, @ƒ t | ƒ k }3 t t | ƒ j |. ƒ ƒ }4 t t | ƒ j |/ ƒ ƒ }5 |3 rg|4 rg|5 rg|- j | ƒ |. j t | ƒ ƒ |/ j t | ƒ ƒ |, t | ƒ 8}, |, t | ƒ 8}, qgqgW| j ƒ  }6 x* |6 D]" }7 |7 |- k rƒ| j |7 ƒ qƒqƒW| |  f S(   s‚  
  Look for NCS groups with the smallest number of chains in the master copy
  This is not the minimal number of NCS operations

  Args:
    match_dict(dict):
      key:(chains_id_1,chains_id_2)
      val:[selection_1,selection_2,res_list_1,res_list_2,rot,trans,rmsd]
      chain_ID (str), selection_1/2 (flex.size_t)
      res_list_1/2 (list): list of matching residues indices
      rot (matrix obj): rotation matrix
      tran (matrix obj): translation vector
      rmsd (float)

  Returns:
    group_dict (dict):
      keys: tuple of master chain IDs
      values: NCS_groups_container objects
    match_dict (dict): updated match_dict
  c         S   s#   h  |  ] } | D] } | ’ q q S(    (    (   t   .0t   keyt   c_id(    (    sB   /public2/ftp/pub/ccp4/6.5/ccp4-6.5/lib/py2/mmtbx/ncs/ncs_search.pys	   <setcomp>œ   s   	 i    i   N(   t   sortedt   sett   find_same_transformR   t   popt   inverse_transformt   has_keyt   appendt   updatet	   iteritemst   indext   lent   sortR   t   intersectiont   addt   keys(8   R/   t   sorted_chain_groups_keyst	   chain_idsR0   t   copy_to_transformt   chains_in_groupst   tr_snt	   master_idt   copy_idt   sel_1t   sel_2t   res_1t   res_2R   R   R   t   tr_numt   is_transposet   temp_mastert	   temp_copyt
   copies_idst   tr_listt   trt   kt   vt   mastersR	   t
   common_idst   ch_idt   it   multiple_tr_numt   singles_tr_numt   m_tr_numt   m_mt   m_ct   s_tr_numt   s_mt   s_ct   t1t   t2t   t3t   t4t   t5t   master_sizet   chain_left_to_addt   transform_to_uset   chains_in_mastert   chains_in_copiest   nt   rott   transt   test1t   test2t   test3RD   R4   (    (    sB   /public2/ftp/pub/ccp4/6.5/ccp4-6.5/lib/py2/mmtbx/ncs/ncs_search.pyR*   „   sÀ    	%  (!


	""5
			"c         C   sò  t  |  ƒ } d „  | Dƒ } t  | ƒ } i  } t ƒ  } d } x‹| D]ƒ\ } } |  | | f \ } }	 }
 } } } } | | k s� | | k r© |  j | | f d ƒ qD n  t | | | ƒ \ } } | rQ| | | d k rñ d } | | } } q^| | } } |  j | | f d ƒ t | | ƒ \ } } |	 | | |
 | | | g |  | | f <n | | } } | j | ƒ | rž| | d j | ƒ | | d j | ƒ qD | d 7} | g | g | | f g | | <qD Wg  | j ƒ  D]" \ } } t	 | d ƒ | g ^ qØ} | j
 ƒ  t | ƒ } t ƒ  } x� t | ƒ r®t | ƒ r®| j d ƒ \ } } | | } t t | d ƒ | @ƒ r"| j | ƒ | t | d ƒ 8} | t | d ƒ 8} q"q"W| j ƒ  } x* | D]" } | | k rÂ| j | ƒ qÂqÂW| |  f S(   sŠ  
  Look for NCS groups with the smallest number of chains in the master copy
  This is not the minimal number of NCS operations

  Args:
    match_dict(dict):
      key:(chains_id_1,chains_id_2)
      val:[selection_1,selection_2,res_list_1,res_list_2,rot,trans,rmsd]
      chain_ID (str), selection_1/2 (flex.size_t)
      res_list_1/2 (list): list of matching residues indices
      rot (matrix obj): rotation matrix
      tran (matrix obj): translation vector
      rmsd (float)

  Returns:
    transform_to_group (dict):
      keys: tuple of master chain IDs
      values: NCS_groups_container objects
    match_dict (dict): updated match_dict
  c         S   s#   h  |  ] } | D] } | ’ q q S(    (    (   R3   R4   R5   (    (    sB   /public2/ftp/pub/ccp4/6.5/ccp4-6.5/lib/py2/mmtbx/ncs/ncs_search.pys	   <setcomp>4  s   	 i    i   N(   R6   R7   R9   R   R8   R:   RC   R<   R>   R@   RA   R   RD   (   R/   RE   RF   R0   RH   RI   RJ   RK   RL   RM   RN   RO   R   R   R   RP   RQ   RR   RS   RW   RX   Rj   Rk   Rl   Ro   RV   t   tr_sns(    (    sB   /public2/ftp/pub/ccp4/6.5/ccp4-6.5/lib/py2/mmtbx/ncs/ncs_search.pyR)     sV    	%(
#5
	
c         C   s¨  i  } d } d } x�|  j  ƒ  D]�\ } } | \ } } \ }	 }
 t | ƒ } g  | D] } | j | ƒ ^ qS } g  | D] } | | ^ qu } t | ƒ } t | | | ƒ \ } } | j | ƒ r2t | | | | j d ƒ } x� t | ƒ D]� \ } } | \ } } } t	 | t
 | ƒ ƒ } t	 | t
 | ƒ ƒ } | | k rè t | | j | | | ƒ \ } } | | | <| | | _ qè qè W| d 7} | | d | d f \ } } } } }	 }
 } t d |	 d |
 d | d t d | d | ƒ } | | j j | ƒ | | j j | ƒ | | j j | ƒ | | j j | ƒ q | d 7} | d 7} | | d | d f \ } } } } }	 }
 } t ƒ  } t d t j d d d d d d d d d g	 ƒ d t j d d d g ƒ d | d t d | d d ƒ } | j j | ƒ | j j | ƒ | j j | ƒ | j j | ƒ | d 7} t d |	 d |
 d | d t d | d | ƒ } | j j | ƒ | j j | ƒ | j j | ƒ | j j | ƒ | | | <q W| S(	   sà  
  find all transforms with common masters and organize the chains
  in the same order as the master and build groups transform dictionary

  Args:
    transform_to_group (dict):
      key: temporary transform number
      values:[masters],[copies],(rotation,translation)]
    match_dict(dict):
      key:(chains_id_1,chains_id_2)
      val:[selection_1,selection_2,rot,trans,rmsd]
          chain_ID (str), selection_1/2 (flex.size_t)
          residue_index_list_1/2 (list): matching residues indices
          rot (matrix obj): rotation matrix
          tran (matrix obj): translation vector
          rmsd (float)

  Returns:
    group_dict (dict):
      keys: tuple of master chain IDs
      values: NCS_groups_container objects
  i    i   R   R   R   R   R   R   (   R>   R6   R?   t   tuplet   get_iselectionR;   t   zipR   t	   enumerateR7   R!   t   update_selectionsR   t   TrueR<   R   R	   R
   R   R   t   sqrt   col(   R0   R/   R1   t   group_idRI   t   _RX   RY   R	   R   R   t   sorted_masterst   xt   sort_mapR\   R4   t
   m_sel_listt
   c_sel_listt   zipped_paramt   rect   m_selt   c_selt   current_mastert   current_master_sett	   m_sel_sett   updated_iselectiont   res_l_mt   res_l_cR   RV   t   new_ncs_group(    (    sB   /public2/ftp/pub/ccp4/6.5/ccp4-6.5/lib/py2/mmtbx/ncs/ncs_search.pyR+   u  s~    "

-	

-	*	
	c         C   s,  |  d | } t  | t | ƒ ƒ } t | ƒ } t  | | ƒ } | | } | | }	 | rÔ g  }
 xw |  D]f } | | } t | ƒ } t  | | ƒ } t | | ƒ } t j | ƒ | } | | | <|
 j | ƒ qg Wn |  }
 |	 r"t | ƒ } t  | | ƒ } t | |	 ƒ } t j | ƒ | } n  |
 | f S(   s|  
  Update the total master and copies selection with the smallest common
  selection, among all ncs copies

  Args:
    iselections (list): list of flex.size_t iselection for all NCS copies
    m_sel,c_sel (flex.size_t): iselection for master and a single copy
    i (int): chain number in iselections

  Returns:
    iselections : updated iselections
    c_sel : updated c_sel
  i    (   R7   R!   t   listR   t   size_tR<   (   R   R‡   Rˆ   R\   R‰   R‹   t   master_offsetRŠ   t   remove_from_old_ncs_copiest   remove_from_new_copyt   new_iselectionst	   isel_listt   iselt   offsett   isel_sett	   c_sel_set(    (    sB   /public2/ftp/pub/ccp4/6.5/ccp4-6.5/lib/py2/mmtbx/ncs/ncs_search.pyRz   Ö  s.    



c   	      C   si   g  } g  } xP t  |  | ƒ D]? } | | \ } } } } } } } | j | ƒ | j | ƒ q W| | f S(   s]  
  Combine iselection of all chains in NCS master and NCS copy to a single
  iselelction

  Args:
    sorted_masters (list): list of master chain IDs
    copies (list): list of copies chain IDs
    match_dict(dict):
      key:(chains_id_1,chains_id_2)
      val:[selection_1,selection_2,rot,trans,rmsd]
      chain_ID (str), selection_1/2 (flex.size_t)
      residue_index_list_1/2 (list): matching residues indices
      rot (matrix obj): rotation matrix
      tran (matrix obj): translation vector
      rmsd (float)

  Returns:
    m_sel,c_sel (list of flex.size_t): list of selected atoms per chain
  (   Rx   R<   (	   R€   R	   R/   R‡   Rˆ   R4   RL   RM   R   (    (    sB   /public2/ftp/pub/ccp4/6.5/ccp4-6.5/lib/py2/mmtbx/ncs/ncs_search.pyRw   ÿ  s    i   c            sH  g  |  D] } | d d k r | ^ q } i  } i  } xð | D]è } | \ } }	 }
 } } } } t  | | | |	 | ƒ \ } } | j |
 ƒ j ƒ  j ƒ  } | j | ƒ j ƒ  j ƒ  } t j d | d | ƒ } | j } | j } | j | j	 ƒ  ƒ } t
 | d ƒ } |
 | | | | | | g | | |	 f <q< W‡  f d †  | j ƒ  Dƒ } | S(   sD  
  Remove all bad matches from chain_match_list

  Args:
    ph (object): hierarchy
    chain_match_list (list): list of
      [chain_ID_1, chain_ID_2, sel_1, sel_1,res_m/res_c similarity]
      chain_ID (str), sel_1/2 (flex.bool)
      res_m/res_c (lists): indices of the aligned components
      similarity (float): similarity between chains
    rmsd_eps (float): limit of rms difference chains

  Returns:
    match_dict(dict): key:(chains_id_1,chains_id_2)
                      val:[selection_1,selection_2,
                           res_list_1,res_list_2,rot,trans,rmsd]
  i   i    t   reference_sitest   other_sitesc            s/   i  |  ]% \ } } | d  ˆ  k r | | “ q S(   iÿÿÿÿ(    (   R3   RW   RX   (   R-   (    sB   /public2/ftp/pub/ccp4/6.5/ccp4-6.5/lib/py2/mmtbx/ncs/ncs_search.pys
   <dictcomp>C  s   	 (   t   update_best_matches_dictt   selectt   atomst   extract_xyzR   t   least_squares_fitR   R   t   rms_differencet   other_sites_best_fitt   roundR>   (   R.   R%   R-   R�   t
   match_listt   best_matchesR/   t   matcht   ch_a_idt   ch_b_idt   sel_at   sel_bt
   res_list_1t
   res_list_2t
   similarityRœ   t	   ref_sitest   lsq_fit_objR   R   R   (    (   R-   sB   /public2/ftp/pub/ccp4/6.5/ccp4-6.5/lib/py2/mmtbx/ncs/ncs_search.pyR(     s&    )				)c         C   sb  t  ƒ  } x"| | g D]} |  j | ƒ rg  } |  | d d } | | k rË x] |  | D]Q \ }	 \ }
 } |	 | d k r˜ | j |	 |
 | f g ƒ qZ | j |
 | f ƒ qZ W| j | | | f g ƒ n9 | | d k rú | j d | | | f g ƒ n
 |  | } | |  | <q | | | f g g |  | <q W| rXx! | D] } | j | d ƒ q;Wn  |  | f S(   s  
  Updates the best_matches dictionaries best_matches,match_dict to keep only
  matches that are at least 95% of best match

  Args:
    best_matches (dict):
      key: chain_ID (str)
      Val: [[similarity,(chain_ID,chain_ID2)],[similarity,(chain_ID3,chain_ID)]]
    match_dict (dict):
      key: (chain_id_a,chain_id_b)
      val: [selection_1,selection_2,res_list_1,res_list_2,rot,trans,rmsd]
    ch_a_id,ch_b_id (str): chain IDs
    similarity (float): similarity between chains

  Returns:
    updated best_matches,match_dict
  iÿÿÿÿi    gffffffî?N(   R7   R;   R<   RC   t   insertR9   R   (   R¦   R/   R¨   R©   R®   t   records_to_removeR[   t   temp_rect   max_simt   st   at   bR4   (    (    sB   /public2/ftp/pub/ccp4/6.5/ccp4-6.5/lib/py2/mmtbx/ncs/ncs_search.pyR�   F  s(    	
gš™™™™™¹?c      
   C   sž   t  } d } x… | j ƒ  D]w \ } } t | d ƒ rI | j }	 | j }
 n | d \ }	 }
 t |  | |	 |
 d | d | ƒ\ } } | r | | f Sq W| | f S(   s(  
  Check if the rotation r and translation t exist in the transform dictionary.

  Comparing rotations and the result of applying rotation and translation on
  a test vector

  Args:
    r (matrix.sqr): rotation
    t (matrix.col): translation
    transforms (dict): dictionary of all transforms
    angle_eps (float): allowed difference in similar rotations
    eps (float): allowed difference in the average distance between

  Returns:
    tr_num: (str) transform serial number
    is_transpose: (bool) True if the matching transform is transpose
  R   i   t   epst	   angle_epsN(   t   FalseR   R>   t   hasattrR   R   t   is_same_transform(   R   R   R
   R¸   R¹   RQ   RP   RW   RX   t   rrt   ttt   is_the_same(    (    sB   /public2/ftp/pub/ccp4/6.5/ccp4-6.5/lib/py2/mmtbx/ncs/ncs_search.pyR8   s  s    	$c   !      C   s9  |  j  ƒ  } g  } |  j ƒ  d } t d „  | j ƒ  Dƒ ƒ } t | ƒ } t | ƒ } | j ƒ  } xÐt | d ƒ D]¾}	 | |	 j }
 | j d |
 ƒ } |  j	 | ƒ } | |	 } x|t |	 d | ƒ D]g} | | j } | j d | ƒ } |  j	 | ƒ } | | } t
 | ƒ \ } } t
 | ƒ \ } } g  | D] \ } } | ^ q0} g  | D] \ } } | ^ qO} t d | d | d | d | ƒ \ } } } t | | | | | | ƒ \ } } } } | rÆ | j ƒ  } | j ƒ  } | t | j ƒ  ƒ 7} | t | j ƒ  ƒ 7} |
 | | | | | | g }  | j |  ƒ qÆ qÆ Wqs W| S(	   s  
  Search for NCS relations between chains or parts of chains, in a protein
  hierarchy

  Args:
    ph (object): hierarchy
    min_contig_length (int): segments < min_contig_length rejected
    min_fraction_domain (float): Threshold for similarity between chains.
      similarity define as:
      (number of matching res) / (number of res in longer chain)

  Returns:
    chain_match_list (list): list of
      [chain_ID_1,chain_ID_2,sel_1,sel_2,res_sel_m, res_sel_c,similarity]
      chain_ID (str), sel_1 (flex.bool), sel_1 (flex.bool),
      res_sel_m/c (lists): indices of the aligned components
      similarity (float): similarity between chains
    We use selection_1 and selection_2 because in some PDB records a residue
    might contain side chain in one chain but not in another
  i    c         S   s   h  |  ] } | j  ’ q S(    (   t   id(   R3   R�   (    (    sB   /public2/ftp/pub/ccp4/6.5/ccp4-6.5/lib/py2/mmtbx/ncs/ncs_search.pys	   <setcomp>®  s   	 i   s   chain t   seq_at   seq_bR   R&   (   t   atom_selection_cachet   modelsR�   t   chainsR6   R@   t   xrangeRÀ   t	   selectionRž   t   get_residue_sequencet   res_alignmentt   get_matching_atomst
   iselectionR!   R<   (!   R%   R   R&   t   cacheR.   t   modelRF   t   n_chainst	   ph_chainsR\   t   master_ch_idt   m_selectiont   m_pht   m_chaint   jt
   copy_ch_idt   c_selectiont   c_pht   c_chaint
   chain_id_mt   res_mt
   chain_id_ct   res_cR�   t   yt   seq_mt   seq_ct	   res_sel_mt	   res_sel_cR®   t   sel_mt   sel_cR†   (    (    sB   /public2/ftp/pub/ccp4/6.5/ccp4-6.5/lib/py2/mmtbx/ncs/ncs_search.pyR'   “  sH    

$	c         C   s  t  |  ƒ } t  | ƒ } | d k s0 | d k r= g  g  d f Sd } d | | } t d | | | ƒ } | }	 t d | d | d |	 d | d | ƒ }
 xt d | d ƒ D]} xÿt d | d ƒ D]ê} |  | d j ƒ  | | d j ƒ  k } |
 | d | d f j | | } |
 | d | f j | } |
 | | d f j | } t | | | ƒ } t d | d	 | ƒ |
 | | f <| | k r|
 | d | d f j d |
 | | f _ | d | d f |
 | | f _	 |
 | d | d f j
 d |
 | | f _
 qÄ | | k r$| d | } } n | | d } } | | f |
 | | f _	 |
 | | f j
 |
 | | f _
 |
 | | f j |
 | | f _ |
 | | f j t | | ƒ ƒ qÄ Wqª W|
 | | f j t | | ƒ ƒ t d
 |
 d | d | d | ƒ \ } } } | | | f S(   sz  
  Align two chains hierarchies.

  Penalize misalignment, gaps, when contiguous section is less
  than min_contig_length and when the
  Do not give any points for alignment. (score only change when "bad" things
  happens)
  Stop if the alignment is less than the "similarity_threshold"
  After alignment verify that aligned parts are >= similarity_threshold

  Args:
    seq_a, seq_b (lists of str): list of characters to compare
    min_fraction_domain (float): min percent of similarity between hierarchies
      similarity define as:
      (number of matching res) / (number of res in longer chain)
    min_contig_length (int): domain < min_contig_length rejected

  Returns:
    aligned_sel_a (list): the indices of the aligned components of seq_a
    aligned_sel_b (list): the indices of the aligned components of seq_b
    similarity (float): actual similarity between hierarchies
  i    i   i   t   rowR}   t	   max_scoreR   R   R   t   RR&   (   R@   t   intt   build_score_matrixRÆ   t   lowerR   t   maxR   R   R    R   R$   R!   t   get_matching_res_indices(   RÁ   RÂ   R   R&   R¶   R·   R   t   misalign_penaltyt   max_mis_alignR   Ræ   RÔ   R\   t   not_alignedt   s1t   s2t   s3Rµ   t   i_tempt   j_tempt   aligned_sel_at   aligned_sel_bR®   (    (    sB   /public2/ftp/pub/ccp4/6.5/ccp4-6.5/lib/py2/mmtbx/ncs/ncs_search.pyRÉ   Õ  sD     (#,!/  ( $c   	      C   sÁ  | } | } g  } g  } |  j  | | f ƒ sL t j | ƒ t j | ƒ d f S|  | | f j t | | ƒ } | | k  r— t j | ƒ t j | ƒ d f Sxè | d k r�| d k r�|  | | f j | d | d f k r| j | d ƒ | j | d ƒ | d 8} | d 8} qš |  | | f j | d | f k rB| d 8} qš |  | | f j | | d f k rr| d 8} qš t d ƒ ‚ qš W| j ƒ  | j ƒ  t	 | ƒ t	 | ƒ k s´t
 ‚ | | | f S(   s  
  Trace back best solution and collect the indices of matching pairs

  Args:
    R (list of lists of int): the score matrix
    row (int): number of rows
    col (int): number of columns
    min_fraction_domain (float): min percent of similarity between hierarchies
      similarity define as:
      (number of matching res) / (number of res in longer chain)

  Returns:
    sel_a (list): matching indices sequence a
    sel_b (list): matching indices sequence b
    similarity (float): actual similarity between hierarchies
  i    i   s   Sequence alignment error(   R;   R   R‘   R   Rê   R    R<   R   t   reverseR@   t   AssertionError(	   Ræ   Rä   R}   R&   t   j_maxt   i_maxRª   R«   R®   (    (    sB   /public2/ftp/pub/ccp4/6.5/ccp4-6.5/lib/py2/mmtbx/ncs/ncs_search.pyRë     s0     '
##

c         C   s7  |  j  ƒ  j } | j  ƒ  j } |  j ƒ  j ƒ  } | j ƒ  j ƒ  }	 t j t g | ƒ }
 t j t g |	 ƒ } g  | j ƒ  D] } | j ƒ  ^ q{ } g  | j ƒ  D] } | j ƒ  ^ q  } g  } g  } x`t	 | | | | ƒ D]I\ } } } } | d | ƒ } | d | ƒ } |  j
 | ƒ } | j
 | ƒ } t | j ƒ  j ƒ  ƒ } t | j ƒ  j ƒ  ƒ } t d | d | d d ƒ \ } } } t j | ƒ t | j ƒ  ƒ } t j | ƒ t | j ƒ  ƒ } | j ƒ  d k rë| j | ƒ | j | ƒ n  t j | | ƒ } t j |	 | ƒ } |
 | B}
 | | B} qÚ W|
 | | | f S(   sÉ  
  Get selection of matching chains, match residues atoms
  We keep only residues with continuous matching atoms

  Args:
    ph_a (hierarchy): first chain
    ph_b (hierarchy): second chain
    res_num_a/b (list of int): indices of matching residues numbers, ph_a/b
    chain_a/b (chain hierarchy): chains hierarchies of chains a and b

  Returns:
    sel_a, sel_b (flex.bool): matching atoms selection
    res_num_a/b (list of int): updated res_num_a/b
  s   resid RÁ   RÂ   R   id   i    (   RÃ   RÇ   RŸ   t   sizeR   R   Rº   t   residuest   residRx   Rž   R�   t   extract_nameRÉ   R‘   R!   RË   R<   (   t   ph_at   ph_bt	   res_num_at	   res_num_bt   chain_at   chain_bt   atom_cache_at   atom_cache_bt   l_at   l_bRª   R«   R�   t	   res_ids_at	   res_ids_bt   res_num_a_updatedt   res_num_b_updatedt   resid_at   resid_bt   nat   nbt   sat   sbt   res_at   res_bt   atoms_names_at   atoms_names_bt   atoms_at   atoms_bR®   (    (    sB   /public2/ftp/pub/ccp4/6.5/ccp4-6.5/lib/py2/mmtbx/ncs/ncs_search.pyRÊ   I  s<    %%(
c         C   s­   g  |  j  ƒ  D] } | j ^ q } g  |  j ƒ  D] } | j ^ q/ } g  t | | ƒ D]* \ } } | j ƒ  d k rT | | f ^ qT } |  j ƒ  } | d j ƒ  j } | | f S(   sØ   
  Get a list of pairs (residue name, residue number) and the chain ID
  Exclude water

  Args:
    chain_ph (iotbx_pdb_hierarchy_ext): hierarchy of a single chain

  Returns:
    chain_id (str)
    res_seq (list)
  t   hohi    (	   t   atom_groupst   resnamet   residue_groupst   resseqRx   Ré   RŸ   t   chainRÀ   (   t   chain_phR�   t   res_listt
   resid_listRÝ   t   res_seqRŸ   t   chain_id(    (    sB   /public2/ftp/pub/ccp4/6.5/ccp4-6.5/lib/py2/mmtbx/ncs/ncs_search.pyRÈ   {  s    ""@iè  i   c      
   C   sº   i  } xU t  |  d ƒ D]C } | | | } t d | d | d | d d f ƒ | | d f <q WxU t  | d ƒ D]C } | | | } t d | d | d d | d f ƒ | d | f <qo W| S(   s+  
  Build a matrix in a dictionary form
  The matrix values are initialized according the the gap penalties.

  We only initializing the zero row and column, the rest of the items are
  created while doing the alignment

  Args:
    row (int): number of rows
    col (int): number of columns
    max_score (int): the score assigned for perfect alignment
    gap_penalty (int): penalty for gaps
    min_contig_length (int): segments < min_contig_length rejected

  Returns:
    R (dict): the score matrix in a form of a dictionary of Score_record objects
  i   R   R   R    i    (   RÆ   R   (   Rä   R}   Rå   R   R   Ræ   R\   R   (    (    sB   /public2/ftp/pub/ccp4/6.5/ccp4-6.5/lib/py2/mmtbx/ncs/ncs_search.pyRè   �  s    --c         C   s!   |  j  ƒ  }  |  | } |  | f S(   s"    inverse rotation and translation (   t	   transpose(   R   R   (    (    sB   /public2/ftp/pub/ccp4/6.5/ccp4-6.5/lib/py2/mmtbx/ncs/ncs_search.pyR:   ±  s    c         C   s<   |  j  | ƒ } t j t d | ƒ ƒ } | d t j 9} | S(   s    get angle between two vectorsi   i´   (   t   dott   matht   acosR!   t   pi(   t   v1t   v2t	   cos_anglet   result(    (    sB   /public2/ftp/pub/ccp4/6.5/ccp4-6.5/lib/py2/mmtbx/ncs/ncs_search.pyt   angle_between_rotations·  s    c         C   sZ   t  j |  j ƒ  ƒ } | j ƒ  } | j ƒ  } t | j d ƒ ƒ j d ƒ } | | | d !S(   s7    get the eigen vector associated with the eigen value 1i   i   i   (   R   t   real_symmetrict   as_sym_mat3t   vectorst   valuesR�   R¤   R?   (   R   t   eigent   eigenvectorst   eigenvaluesR\   (    (    sB   /public2/ftp/pub/ccp4/6.5/ccp4-6.5/lib/py2/mmtbx/ncs/ncs_search.pyt   get_rotation_vec¾  s
    c         C   s£  |  j  ƒ  r•| j  ƒ  r•|  j d d ƒ s2 t ‚ | j d d ƒ sJ t ‚ t j d d d g ƒ } |  j | | j ƒ  } t |  | ƒ \ } }	 | j | |	 j ƒ  }
 t |  ƒ } t | ƒ } | j | | j ƒ  } | | } | j	 | ƒ d | j
 ƒ  } |
 | } | j	 | ƒ d | j
 ƒ  } t | | ƒ } t | d | ƒ } | | k  rf| | k  rft t f S| | k  rˆ| | k  rˆt t f St t f Sn
 t t f Sd S(   s²   
  Args:
    r1, r2: Rotation matrices
    t1, t2: Translation vectors
    eps, angle_eps: allowed numerical difference

  Returns:
    (bool,bool) (is_the_same, is_transpose)
  t   rms_tolerancegü©ñÒMbP?i   ig   i  g     @Àg       @g      $@g        g     X€@g     ÀYÀg      à?i´   N(   i   ig   i  (   g     @Àg       @g      $@(   g        g     X€@g     ÀYÀ(   t   is_zerot   is_r3_rotation_matrixR÷   R   t   vec3_doublet   elemst	   as_doubleR:   R4  R$  Rú   R,  R!   R{   Rº   (   t   r1Re   t   r2Rf   R¸   R¹   t   xyzt   a_reft   rtR¾   t   a_ref_transposeR(  R)  R¶   t   dt   dtt   angt   d_ang(    (    sB   /public2/ftp/pub/ccp4/6.5/ccp4-6.5/lib/py2/mmtbx/ncs/ncs_search.pyR¼   Æ  s,    




(%   t
   __future__R    t   scitbx.linalgR   t   scitbx.array_familyR   t   scitbx.mathR   t   libtbx.utilsR   t   scitbxR   R%  t   objectR   R   R   R{   R2   R*   R)   R+   Rz   Rw   R(   R�   R8   R'   RÉ   Rë   RÊ   RÈ   Rè   R:   R,  R4  R¼   (    (    (    sB   /public2/ftp/pub/ccp4/6.5/ccp4-6.5/lib/py2/mmtbx/ncs/ncs_search.pyt   <module>   sF   '$	˜	Y	a	)	*	-!A@	2	2				