ó
ž™xTc           @   sÓ   d  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	 m Z d d l m Z d d	 l m Z d d
 l Z d d
 l Z d d
 l Z d e f d „  ƒ  YZ e e d „ Z d
 S(   s  
  This code is a portion of simple_ncs_from_pdb.py (tct 2006-12-12)
  moved into cctbx (Aug-2014) to make the core functionality available
  without phenix dependencies

  The original file is at phenix\phenix\command_line\simple_ncs_from_pdb.py

  The original functionality and interface is maintained
  via simple_ncs_from_pdb.py
*****************************************************************************

Purpose:
  Figure out the ncs relations from the chains in a pdb object

Major assumption: residue numbers are consistent among chains

Approach:
  Use residue numbers to align the residue names, identify
  pairs of chains that can match. Choose groupings of chains that maximize the
  smallest number of matching residues between each member of a group and the
  first (reference) member of the group. Within a pair of chains, allow some
  segments to match and others not. Each pair of segments must have a
  length >= min_length and percent identity >=min_percent.  A pair of segments
  may not end in a mismatch. An overall pair of chains must have an rmsd
  of CA atoms of <= rmsd_max.

  If find_invariant_domain is specified then once all chains that can be matched
  with the above algorithm are identified, all remaining chains are matched,
  allowing the break-up of chains into invariant domains. The invariant
  domains each get a separate NCS group.

  If residue numbers are not the same for corresponding chains, but
  they are simply offset by a constant for each chain, this will be
  recognized and the chains will be aligned.
iÿÿÿÿ(   t   division(   t   find_domain(   t   flex(   t   adopt_init_args(   t	   superpose(   t   matrix(   t   Sorry(   t   ncsNt   ncs_from_pdbc           B   s¬  e  Z d  Z e e j d d d g  e e g  d d d d d d d	 d
 d „ Z d „  Z d „  Z	 d „  Z
 d „  Z d „  Z d d d d e e e d „ Z d „  Z d „  Z d „  Z d4 d4 d „ Z d „  Z d „  Z d „  Z d „  Z d „  Z d „  Z d  „  Z d! „  Z d" „  Z d# „  Z d$ „  Z d% „  Z d& „  Z d' „  Z  d( „  Z! d) „  Z" d* „  Z# d+ „  Z$ d, „  Z% d- „  Z& d. „  Z' d/ „  Z( d d0 e d1 „ Z) d2 „  Z* d3 „  Z+ RS(5   s/    find ncs relation in a biomolecules structure i   gffffffî?gš™™™™™É?g      à?g       @g      è?i   i    i   gš™™™™™¹?c         C   s&   i  |  _  d |  _ t |  t ƒ  ƒ d S(   s8    Setup common variables

    When two chains match but starts at a different residue number, use
    offset_dict to indicate that difference. For example Chains A and B
    match, but chain A first residue number is 1 and B first residue number
    is 10, so offset_dict[AB] = 9

    if njump is not 1, then we are only going to take residues with
    numbers such that mod(resno,njump)=0
    so if njump=10 then we take residue 0,10,20,30,40 and put them
    in position 1,2,3,4,5

    Args:
      verbose (bool): print out during ncs processing
      log: indicate where to log output
      njump (int): residue sampling factor, reduces the number of residues used
      min_length (int): minimum number of matching residues in a segment for
        recursive call
      min_percent (float): min percent identity of matching residues
      suggested_ncs_groups (list):
      require_equal_start_match (bool): require that all matching
        segments start at the same relative residue number for all members
        of an NCS group, trimming the matching region as necessary. This is
        same, but not otherwise
      maximize_size_of_groups (bool): request that the scoring be set up to
        maximize the number of members in NCS groups
        (maximize_size_of_groups=True) or that scoring is set up to maximize
        the length of the matching segments in the NCS group
        (maximize_size_of_groups=False)
      required_chains (list):
      min_fraction_domain (float):domain must be this fraction of a chain
      initial_rms (float): Guess of RMS among chains
      match_radius (float): Keep atoms that are within match_radius of NCS-related atoms
      similarity_threshold (float): Threshold for similarity between segments
      min_contig_length (int): segments < min_contig_length rejected
      smooth_length (int): two segments separated by smooth_length or less get
        connected
      max_rmsd_domain (int): max rmsd of domains
      min_fraction_represented (float): Minimum fraction of residues
        represented by NCS to keep. If less...skip ncs entirely
    i    N(   t   offset_dictt   total_residuesR   t   locals(   t   selft   verboset   logt   njumpt
   min_lengtht   min_percentt   suggested_ncs_groupst   require_equal_start_matcht   maximize_size_of_groupst   required_chainst   min_fraction_domaint   initial_rmst   match_radiust   similarity_thresholdt   min_contig_lengtht   smooth_lengtht   max_rmsd_domaint   min_fraction_represented(    (    sD   /public2/ftp/pub/ccp4/6.5/ccp4-6.5/lib/py2/mmtbx/ncs/ncs_from_pdb.pyt   __init__4   s    ;		c   '   	   C   s¤  g  } g  } g  } d } d } x5| j  ƒ  D]'} | d 7} | d k rM q+ n  x| j ƒ  D]ô}	 |	 j | k ru qZ n  |	 j }
 |
 | k rµ d } |  j rZ |  j | I|
 IJqZ qZ n  |  j rÔ |  j d I|
 IJn  d } x1|	 j ƒ  D]#} | d 7} | d k r	qç n  d } d } d } xi | j ƒ  D][ } | j ƒ  } | d 7} |  j | ƒ rYq(n  | | k rn| } n  | | k  r(| } q(q(W|  j r²d } |  j | I| I| IJn  g  } | | } | |  j	 d } x! t
 | ƒ D] } | j d ƒ qàWg  } x
| j ƒ  D]ü } | j ƒ  } |  j | ƒ r1q
n  | | k rCq
n  | j | ƒ |  j | j ƒ } | r
t } x< | j ƒ  D]. } | j d k sŸ| j d	 k r{t } Pq{q{W| r| d 7} | | |  j	 } | | | <|  j r|  j d
 I| j I| IJqqq
q
Wqç W| |  j |  j	 k rZ | j | ƒ | j |
 ƒ | j | ƒ qZ qZ Wq+ Wi  } t | | | ƒ } t | ƒ } xt
 | ƒ D]ô } | | \ } } }  xØ t
 | d ƒ D]Æ }! | |! \ }" }# }$ |  j | | |  |" |# |$ ƒ \ }% }& |% d k r8d }% |  j rm|  j d I|% I| I|# I| |# IJqmn5 |  j rm|  j d I|% I| I|# I| |# IJn  |% | |& <q±Wq‡W| |  _ | |  _ | | | | | f S(   s1  
    get list of chains. Each chain list is a list of (blanks or residue names)
    a chain list has a slot for each residue in a chain, it can be occupied
    or not.  Two chains have the same parent chain if all residues that are
    present match exactly.

    each chain starts at a specific residue number, stored as
    starting_residue_numbers for that chain

    Args:
      hierarchy
      ignore_chains

    Returns:
      chains (list of lists): list of the residue sequence list (one letter
        characters) of each chain
      chain_ids (list of str): list of chains IDs
      starting_residue_numbers (list): list of chains first residue numbers
      offset_dict (dict): offset_dict[id1+id2] to start2 to match seq of chain1
      total_residues (int): Total number of residues in the hierarchy
    i    i   s%   NOTE: duplicate chain ID (ignoring): s   Examining chain iÁ½ðÿi–˜ s   Residue range found: s    CA s    P  t   Residues   FAILED OFFSET s   OFFSET N(   t   modelst   chainst   idR   R   t
   conformerst   residuest   resseq_as_intt   skipR   t   xranget   appendt   Nonet   one_chart   resnamet   Falset   atomst   namet   Truet   resseqR   t   zipt   lent   find_offsetR	   R
   ('   R   t	   hierarchyt   ignore_chainsR!   t	   chain_idst   starting_residue_numberst   model_numberR
   t   modelt   chaint   chain_idt   msgt   conformer_numbert	   conformert   highest_residue_numbert   lowest_residue_numbert   number_of_good_residuest   residuet
   resseq_intt   seqt   res_dift	   res_ranget   it   residues_seen_alreadyR*   t   found_ca_or_pt   atomR	   t   zipped_datat   lt   chain1t   id1t   start1t   jt   chain2t   id2t   start2t   offsett
   offset_key(    (    sD   /public2/ftp/pub/ccp4/6.5/ccp4-6.5/lib/py2/mmtbx/ncs/ncs_from_pdb.pyt   get_chain_lists   s°    
  		 	 
 
 		
  

	-$	 /	 ,		c         C   sø   t  | d g | d g g d d „  ƒ} | d d } | d d | d d }	 d }
 d } x� t t | ƒ d t | ƒ d ƒ D]j } | | | |  j } |  j d | d | d | d	 | d
 | ƒ } | r€ | |
 k r€ | }
 | | } q€ q€ W| |	 f S(   s™  
    return offset that makes chain1 same as chain2 (no mismatches allowed)
    list chain1:
    first residue of chain2 can match any one of residues of chain1.
    offset can be:
    start2+offset=start1-len(chain2)+1  to start2+offset=start1+len(chain1)

    Args:
      chain1 (list): Residue single character list
      id1 (str): chain1 ID
      start1 (int):  number of first residue in chain 1
      chain2 (list): Residue single character list
      id1 (str): chain1 ID
      start2 (int): number of first residue in chain 2

    Returns:
      best_offset (dict): relative chains offset
      offset_key  (str): sorted by chain names, dictionary key
    i   iÿÿÿÿt   keyc         S   s   |  d S(   Ni    (    (   t   x(    (    sD   /public2/ftp/pub/ccp4/6.5/ccp4-6.5/lib/py2/mmtbx/ncs/ncs_from_pdb.pyt   <lambda>ñ   s    i    RM   RO   RQ   RS   RT   N(   t   sortedR)   R'   R2   R   t   get_overlap(   R   RM   RN   RO   RQ   RR   RS   t   tempt   reverse_offsetRU   t   best_overlapt   best_offsett   offset_aRT   t   overlap(    (    sD   /public2/ftp/pub/ccp4/6.5/ccp4-6.5/lib/py2/mmtbx/ncs/ncs_from_pdb.pyR3   Ý   s    '+	!c         C   s.  d } | } d } d }	 x½ t  t | ƒ ƒ D]© }
 |
 |  j | | } | |
 } | | | |  j } | d k r� | t | ƒ k  r� | | } n d } | d k r+ | d k r+ | | k rÇ | d 7} qÔ |	 d 7}	 q+ q+ Wd t | ƒ t t d | |	 ƒ ƒ |  j k  rd S| |  j |  j k r&| Sd Sd S(   s  
    Args:
      chain1 (list): Residue single character list
      start1 (int):  number of first residue in chain 1
      chain2 (list): Residue single character list
      start2 (int): number of first residue in chain 2
      offset (int):

    Returns:
      n_match
    i    i   g      Y@N(   R'   R2   R   R)   t   floatt   maxR   R   (   R   RM   RO   RQ   RS   RT   t   offset1t   offset2t   n_matcht
   mismatchesRG   t   resnot   res1RP   t   res2(    (    sD   /public2/ftp/pub/ccp4/6.5/ccp4-6.5/lib/py2/mmtbx/ncs/ncs_from_pdb.pyR[   ÿ   s(    
0c         C   sK   |  j  d k r t St d t j d |  j  | |  j  ƒ ƒ d k rG t Sd S(   s@     skip unless resno (residue number) falls on n * self.njump    i   g      à?id   i    N(   R   R,   t   intt   matht   fmodR/   (   R   Rh   (    (    sD   /public2/ftp/pub/ccp4/6.5/ccp4-6.5/lib/py2/mmtbx/ncs/ncs_from_pdb.pyR&   $  s    0c   	      C   sî  | j  ƒ  j d d ƒ } t | ƒ d k rG | d d= k rG | d } n’ t | ƒ d k rv | d d> k rv | d } nc | d? k rÙ xT t d d d d d g d	 d
 d d d g ƒ D]" \ } } | | k r° | } Pq° q° Wn  d d d d d d d d d d d d d d  d! d" d# d$ d% d& d' d( d) d* d+ d, g } d( d* d- d. d/ d0 d1 d) d2 d3 d4 d5 d6 d7 d8 d9 d: d; d< d+ d1 d( d) d* d+ d, g } xf t | | ƒ D]U \ } } t j t j  | ƒ d d ƒ t j t j  | ƒ d d ƒ k r‘t j  | ƒ Sq‘Wd@ S(A   sü   
    return one char for DNA/RNA/Protein
    070508 catch +G or DG and call both of them G:
    2010-12-01 also Ar == A (ribo) call it A

    Args:
      residue_name (str): 3 letters residue code

    Returns:
      (str): One letter residue code
    t    t    i   i    t   dt   +i   t   rt   adet   cytt   guat   thyt   urit   at   ct   gt   tt   ut   GLYt   ALAt   SERt   VALt   ILEt   LEUt   METt   CYSt   PHEt   TYRt   LYSt   ARGt   TRPt   HISt   GLUt   ASPt   GLNt   ASNt   PROt   THRt   MSEt   Gt   Ct   At   Tt   Ut   St   Vt   It   Lt   Mt   Ft   Yt   Kt   Rt   Wt   Ht   Et   Dt   Qt   Nt   P(   Rp   Rq   (   Rr   (   Rs   Rt   Ru   Rv   Rw   N(   t   lowert   replaceR2   R1   t   stringR)   (	   R   t   residue_namet   edited_residue_namet   onet   threet   aa_namest
   aa_lettersR.   t   letter(    (    sD   /public2/ftp/pub/ccp4/6.5/ccp4-6.5/lib/py2/mmtbx/ncs/ncs_from_pdb.pyR*   +  s>    """!i   g      Y@g      @i   c   9      C   s8  g  } t  | | | ƒ } t | ƒ } x>t | ƒ D]0} | | \ } } } | rh |  j | | ƒ rh q1 n  xöt | | ƒ D]å} | | \ } } } |  j r¶ |  j d I| I| IJn  |  j | | | | | | d | d | d |
 ƒ\ } } | rx | | g } |  j | ƒ } |  j | ƒ r"qx n  | } | | g } |  j	 | | | | | | ƒ \ } } } }  }! | sZt | ƒ d k  r}q]| rÆ| d | k rÆ|  j rZd | d | d f }" |  j |" IJqZq]| rA| d | k rA| d | k rA|  j d	 I| Id I| d IJd
 t
 t | d d ƒ ƒ }" |  j |" d IJq]| j | | | | g ƒ qx qx Wq1 W|  j r„|  j d I| IJn  | }# t }$ g  }% g  }& xC|$ rád }' d }( d }) d }* xS |# D]K }+ |  j |+ |# | ƒ \ }, } } |, |( k rÄ|, }( |+ }' | }* | }) qÄqÄW|( d k r¿|  j rJ|  j d I|) I|( I|* IJn  |% j |) ƒ |& j |* ƒ g  }- x* |# D]" }. |. |) k rq|- j |. ƒ qqqqW|- }# |  j rÞ|  j d I|# IJqÞqŸ|  j rØ|  j d IJn  t }$ qŸW|	 r.|  j r.|# r.|  j r|  j d I|% I|& IJn  g  }/ g  }0 g  }1 xY t  | | | ƒ D]E \ }2 }3 }4 |3 |# k rB|/ j |2 ƒ |0 j |3 ƒ |1 j |4 ƒ qBqBW|  j | |/ |0 |1 d |  j d |  j d d d d d t ƒ\ }5 }6 |5 r.|  j | |5 |6 |/ |0 |1 ƒ \ }7 }8 |7 r+|  j d I|7 I|8 IJ|% |7 |& |8 f Sq.n  |% |& f S(   sý  
    Args:
      hierarchy (object)
      chains (list of lists): list of the residue sequence list (one letter
        characters) of each chain
      chain_ids (list of str): list of chains IDs
      starting_residue_numbers (list): list of chains first residue numbers
      min_length (int): minimum number of matching residues in a segment for
        recursive call
      min_percent (float): min percent identity of matching residues
      max_rmsd  (float): max rmsd of domains
      max_rmsd_user (int): max rmsd of chains suggested by user
        (i.e., if called from phenix.refine with suggested ncs groups)
      called_by_self (bool):
      exact_match_only (bool):
      quick (bool):

    Returns:
      groups
      list_of_residue_range_list
    s
   Comparing R   R   t   exact_match_onlyi   i   s
   Alignment s    rejected with rmsd =s   NOTE: User-suggested alignment s   Set max_rmsd_user=g§èH.ÿï?s    to keep its   MATCH LIST: iayþÿi    s   Best new group:s   Current remaining idss   No new groupss   Current groups: t   max_rmsdg    ~„.At   max_rmsd_useri   t   called_by_selfs   Invariant groups found:N(   R1   R2   R'   t   have_enoughR   R   t   matches_approxt   are_in_suggested_ncs_groupst%   are_in_different_suggested_ncs_groupst   get_rmsdt   strRk   R(   R/   R)   t   get_score_and_groupR,   t   find_invariant_domainst   find_groupsR   R   t   find_invariant_groups(9   R   R4   R!   R6   R7   R   R   R²   R³   R´   R±   t   quickt
   match_listRK   t   data_lengthRG   RM   t	   chain_id1RO   RP   RQ   t	   chain_id2RS   t   matchest   keep_range_listt   groupt   in_suggested_ncs_groupst   residue_ranget   residue_range_listt	   rmsd_listt   r_listt
   trans_listt   center_listt   residues_in_common_listR<   t   remaining_idst   still_finding_groupst   groupst   list_of_residue_range_listt   best_idt
   best_scoret
   best_groupt   best_residue_range_listt   trial_idt   scoret   new_remaining_idsR"   t   remaining_chainst   remaining_chain_idst"   remaining_starting_residue_numbersR:   R;   t   starting_residue_numbert   additional_groupst%   additional_list_of_residue_range_listt   invariant_groupst$   invariant_list_of_residue_range_list(    (    sD   /public2/ftp/pub/ccp4/6.5/ccp4-6.5/lib/py2/mmtbx/ncs/ncs_from_pdb.pyR½   Z  sÈ    ! 	 	$	 						
			c   >      C   s©  g  } g  } | s | r$ | | f Sxxt  | | ƒ D]g\ }	 }
 |  j rq |  j d I|	 I|  j |
 |	 ƒ IJn  |	 d } |  j | | | | ƒ \ } } |
 d } d$ } d$ } g  } g  } g  } g  } g  } xÑt  |	 |
 ƒ D]À\ } } | | k rû qÝ n  |  j r&|  j d I| I| Id IJn  |  j | | | | ƒ \ } } | sR| r‡t d t | ƒ d t | ƒ d t | ƒ ƒ ‚ n  |  j | | | | | | | | ƒ } | s·qÝ n  |  j rÖ|  j d I| IJn  d } |  j	 d	 j
 t | | g ƒ ƒ } |  j | | | | ƒ \ } } |  j | | | | ƒ \ } }  |  j r_|  j d
 I| I| IJn  t |  j t t | ƒ ƒ t |  j ƒ ƒ }! | d$ k r�qÝ n  |! t | ƒ k r¾t | ƒ }! n  t | ƒ d k  rÖqÝ n  t | |  d |  j d |  j d |  j d |! ƒ}" g  }# g  }$ x� |" j D]’ }% g  }& g  }' |% d j ƒ  }( x; |( D]3 }) |) |$ k rE|' j |) ƒ |& j | |) ƒ qEqEW|$ |' 7}$ |# j |  j |  j |  j |& ƒ ƒ ƒ ƒ qW|  j r×|  j d I| I| IJn  g  }* g  }+ xæ t  |# |" j ƒ D]Ò \ }& }% |& s|% r/|  j rö|  j d IJqöqön  |  j r||  j d I|& IJ|  j d I|% d IJ|  j d I|% d IJn  |% d |  j k r®|  j rö|  j d IJqöqön  |* j |& ƒ |+ j |% ƒ qöW|+ sÚ|* rù|  j rÝ |  j d IJqÝ qÝ n  |  j r|  j d IJn  g  }, g  }- xqt  |* |+ ƒ D]`\ }& }% |  j rY|  j d I|& IJn  g  }. x |	 D] }/ |. j |& ƒ qfW|  j |	 | | | | |. ƒ \ }0 }1 }2 }3 }4 |  j rÕ|  j d I|& Id I|0 IJn  |0 sît |0 ƒ d k  røg  }, Pn  d }5 d }6 x9 t  |0 d |4 d ƒ D]  \ }7 }8 |5 |7 7}5 |6 |8 7}6 qW|5 t t |0 ƒ d ƒ }5 |6 t t |0 ƒ d ƒ }6 |, j |5 ƒ |- j |6 ƒ q.Wd }9 d$ }: |, r'd }; x1 t  |, |- ƒ D]  \ }7 }8 |9 |7 7}9 |; |8 7}; qºW|9 t t |, ƒ ƒ }9 |; t t |, ƒ ƒ }; t d |  j |9 ƒ |; }: n  |  j rL|  j d I|9 I|: IJn  |: d$ k	 rÝ | d$ k sp|: | k rÝ |: } |9 } |+ } |* } |" } |- }< |, } qÝ qÝ W| d$ k	 r4 | d$ k	 r4 |  j r*|  j d  I|	 Id! I| I|: IJ|  j d" IJx3 t  | |< ƒ D] \ }7 }8 |  j |7 I|8 IJqWn  |  j rI| j d# |  j ƒ n  xO | D]D }# | j |	 ƒ g  }= x |	 D] }) |= j |# ƒ qpW| j |= ƒ qPWq4 q4 W| | f S(%   sô   
    for each group in additional groups, see if there is some way to break
    it down into invariant sub-groups. Return list of these and new
    residue ranges...

    Returns:
      invariant_groups,invariant_list_of_residue_range_list
    s&   Looking for invariant domains for ...:i    s   Using s    to find domains...s	   Chain id Rn   s.    are not both present in remaining chain_ids: s   residues in commonRo   s	   Centers: i   R   R   t   overlap_threst   minimum_sizes   
Domains in s   Domain completely removed...s   Domain: s   RMSD: i   s   N: s&   RMSD too large...rejecting this domains   No domains from this pairs=   Evaluating rmsd for all chain pairs using these final matchess	   domain...s   rmsd_list for t   :i   g        i   s   rmsd for this match: s   Best rmsd for group s   : s"   Rmsd and residues used by domain: t   outN(    R1   R   R   t   add_offsetst	   get_chainR)   R   Rº   t   get_residues_in_commonR	   t   joinRZ   t   get_xyz_listRk   R   Rb   R2   R   R   R   R   R   RÄ   t   as_1dR(   t   remove_smallt   connect_ranget   list_to_rangeR   R¹   Rc   t   show(>   R   R4   RÞ   Rß   RÚ   RÛ   RÜ   Rà   Rá   RÆ   RÉ   RN   RM   RO   t   residue_range1t	   best_rmsdRÔ   t   best_matchest   best_domain_listt   best_domainst   best_overall_rmsd_listt   best_number_of_residues_usedRR   t   residue_range2RQ   RS   t   residue_listRd   Re   t   center1t	   xyz_list1t   center2t	   xyz_list2t   min_sizet   domainst   domain_listt	   used_listt   matcht   domain_residuest	   keep_listt   iselectRG   t   final_domain_listt   final_matchest   overall_rmsd_listt   number_of_residues_used_listt   list_of_domain_residuesR"   RÊ   RË   RÌ   RÍ   RÎ   t   overall_rmsdt   mean_residues_usedt   rmsdt   rest	   test_rmsdRØ   t   test_mean_lengtht!   best_number_of_residues_used_listt%   list_of_residue_ranges_for_this_group(    (    sD   /public2/ftp/pub/ccp4/6.5/ccp4-6.5/lib/py2/mmtbx/ncs/ncs_from_pdb.pyR¾   í  s@   
	
	
 	 " 	"	 )  				
	 	 		 	 		  	"$

	$	%	 	 c         C   s}   g  g  g  } } } xY t  | | | ƒ D]E \ } }	 }
 |	 | k r' | j | ƒ | j |	 ƒ | j |
 ƒ q' q' W| | | g S(   N(   R1   R(   (   R   R!   R6   R7   t   used_idst
   new_chainst   new_chain_idst   new_starting_residue_numbersR:   R"   t   start(    (    sD   /public2/ftp/pub/ccp4/6.5/ccp4-6.5/lib/py2/mmtbx/ncs/ncs_from_pdb.pyt   remove_used_chains   s    "c         C   sB   x; | D]3 } x* | D]" } | | k r | j  | ƒ q q Wq W| S(   N(   R(   (   R   RÑ   R  RÆ   R"   (    (    sD   /public2/ftp/pub/ccp4/6.5/ccp4-6.5/lib/py2/mmtbx/ncs/ncs_from_pdb.pyt   add_idsª  s
     c         C   sŠ   d } x5 | j  ƒ  D]' } x | j ƒ  D] } | | 7} q& Wq W| d k	 r† | d k r† t | ƒ t | ƒ } | |  j k  r t St Sn  t S(   sƒ   
    count up how many residues are represented in the NCS and return True
    if not a fraction self.min_fraction_represented
    i    N(   t
   ncs_groupsRÎ   R)   Rb   R   R/   R,   (   R   t
   ncs_objectR
   t   total_representedt	   ncs_groupt   commont   fraction(    (    sD   /public2/ftp/pub/ccp4/6.5/ccp4-6.5/lib/py2/mmtbx/ncs/ncs_from_pdb.pyt   too_few_residues_represented°  s    c         C   s¸   g  } g  } d } xt | D]l } | d k s; | | d k rQ | } | j | ƒ q | r | j | d d !| d ƒ | g } | } q q W| r´ | j | d d !| d ƒ g  } n  | S(   s@    [1,2,3,6,7] -> [[1,3],[6,7]]
    print >>self.log,"LIST",list  i   i    iÿÿÿÿN(   R)   R(   (   R   t   listt
   range_listt	   work_listt   i_prevRG   (    (    sD   /public2/ftp/pub/ccp4/6.5/ccp4-6.5/lib/py2/mmtbx/ncs/ncs_from_pdb.pyRî   Ä  s    		c         C   sF   x9 t  | | | ƒ D]% \ } } } | | k r | | f Sq Wg  d f S(   Ni    (   R1   (   R   RN   RÚ   RÛ   t   remaining_starting_res_numbersR:   R"   R  (    (    sD   /public2/ftp/pub/ccp4/6.5/ccp4-6.5/lib/py2/mmtbx/ncs/ncs_from_pdb.pyRç   Ù  s
    c         C   sv   |  j  |  j } g  } xY | D]Q } | d | d d | k  ra |  j rn |  j d I| IJqn q | j | ƒ q W| S(   sT   
    remove all ranges that are smaller than self.min_contig_length//self.njump
    i   i    s   Rejecting short range (   R   R   R   R   R(   (   R   R!  t   contig_lengtht   new_range_listt   range(    (    sD   /public2/ftp/pub/ccp4/6.5/ccp4-6.5/lib/py2/mmtbx/ncs/ncs_from_pdb.pyRì   á  s    	 c         C   s–   |  j  |  j } g  } g  } x] | D]U } | s8 | } q# | d | d | d k re | d | d <q# | j | ƒ | } q# W| r’ | j | ƒ n  | S(   s;    If two ranges are within self.smooth_length, connect them i    i   (   R   R   R(   (   R   R!  t   smoothR&  t
   work_rangeR'  (    (    sD   /public2/ftp/pub/ccp4/6.5/ccp4-6.5/lib/py2/mmtbx/ncs/ncs_from_pdb.pyRí   î  s    	
 c   
      C   s  g  } | d } |  j  r) |  j d IJn  x± t | | ƒ D]  \ } } |  j d j t | | g ƒ ƒ } |  j  r’ |  j | I| I| I| IJn  g  } x1 | D]) }	 | j |	 d | |	 d | g ƒ qŸ W| j | ƒ q9 W|  j  r|  j d I| I| IJn  | S(   sw   
    add offsets to all residue numbers in residue_range_list using
    information in self.offset_dict and group:
    i    s   OFFSETS:Ro   i   s
   OLD, NEW: (   R   R   R1   R	   Ré   RZ   R(   (
   R   RÉ   RÆ   t   new_residue_range_listRN   RR   RÈ   RT   t   new_residue_ranget   pair(    (    sD   /public2/ftp/pub/ccp4/6.5/ccp4-6.5/lib/py2/mmtbx/ncs/ncs_from_pdb.pyRæ   þ  s    
	 "	 "'	 c   
      C   s  g  } | d } |  j  r) |  j d IJn  x± t | | ƒ D]  \ } } |  j d j t | | g ƒ ƒ } |  j  r’ |  j | I| I| I| IJn  g  } x1 | D]) }	 | j |	 d | |	 d | g ƒ qŸ W| j | ƒ q9 W|  j  r|  j d I| I| IJn  | S(   s|   
    remove offsets from all residue numbers in residue_range_list using
    information in self.offset_dict and group:
    i    s   OFFSETS:Ro   i   s
   OLD, NEW: (   R   R   R1   R	   Ré   RZ   R(   (
   R   RÉ   RÆ   R*  RN   RR   RÈ   RT   R+  R,  (    (    sD   /public2/ftp/pub/ccp4/6.5/ccp4-6.5/lib/py2/mmtbx/ncs/ncs_from_pdb.pyt   subtract_offsets  s    
	 "	 "'	 c         C   sc  g  } xVt  | ƒ D]H\ } } | j d k	 r | j g | j } g  } g  } t } xÎ | D]Æ }	 |  j |	 ƒ }
 |
 d k rŒ |  j d IJd S|  j |
 | ƒ \ } } | d k s¼ | d k rÍ |  j d IJd S| | k rt d t	 | ƒ d d d d d ƒ ‚ n  | j
 | ƒ | j
 | ƒ qZ W| r[| r[|  j | | ƒ } | | | g g 7} q[q q W| S(	   s–   
    121706: make sure that all suggested ids are actually in chain_ids!
    interpret suggested ncs groups and make a list of them in our format
    s,   No matching residues in suggested NCS groupss   
The suggested chain s    was not found s3    in the input file...it could 
be the chain is too s5   short (try decreasing min_length) 
or that it is not s)   recognized as a chain. Note that ligands
s2    and solvent are not recognized as chains for NCS
N(   t	   enumeratet	   referenceR)   t	   selectionR/   t   atom_selectionR   t   get_id_and_rangesR   Rº   R(   R-  (   R   R   R6   t   suggested_group_listt   i_seqRÆ   t
   selectionsR!  t   firstt   selt   selection_objectR"   t   rangest   range_list_without_offsets(    (    sD   /public2/ftp/pub/ccp4/6.5/ccp4-6.5/lib/py2/mmtbx/ncs/ncs_from_pdb.pyt   get_suggested_group_list"  s4    c         C   sF  g  } g  } |  j  } | } | j ƒ  |  j j ƒ  j ƒ  k sB t ‚ x5 t |  j j ƒ  | ƒ D] \ } } t | ƒ | _ q[ Wxu| j ƒ  D]g}	 t	 }
 xX|	 j
 ƒ  D]J} t	 } d } x5| j ƒ  D]'} | d 7} | d k rá q¿ n  t	 } d } xÔ | j ƒ  D]Æ } |  j | ƒ rú |
 rt }
 n  | r-t } n  | r<t } n  | j | k r^| j | j ƒ n  | j ƒ  } | d k s†| | d k r·| d k	 r¨| j | | g ƒ n  | } | } qÀ| } qú qú W| d k	 r¿ | j | | g ƒ q¿ q¿ Wq  Wq‡ Wt | ƒ d k s| rd St | ƒ d k r8t d d d ƒ ‚ n  | d | f S(   s/  
    we want to return the chain ID and list of residue ranges referred
    to by this selection object. If there are >1 ID: raise an exception as
      we cannot be sure that it is handled correctly.
    assume that all residue numbers go up sequentially!
    In this routine there are no offsets.
    i    i   s;   This version of simple_ncs_from_pdb requires any input NCS sE   
specifications to have only one chain in each reference or selections&   
('chain A or chain B' is not allowed)N(   NN(   R4   t   sizet   pdb_inpR-   t   AssertionErrorR1   Rk   t   tmpR    R/   R!   R#   R)   R$   t   is_selectedR,   R"   R(   R%   R2   R   (   R   R8  R6   t   id_listRÉ   R4   R0  RJ   R@  R9   t   first_in_modelR:   t   first_in_chainR=   R>   t   first_in_conformert   last_residueRB   Rh   t   first_residue(    (    sD   /public2/ftp/pub/ccp4/6.5/ccp4-6.5/lib/py2/mmtbx/ncs/ncs_from_pdb.pyR2  E  sX    	'%
 			 	"c         C   s(   x! | j  ƒ  D] } | j r t Sq Wt S(   N(   R-   R?  R/   R,   (   R   RB   RJ   (    (    sD   /public2/ftp/pub/ccp4/6.5/ccp4-6.5/lib/py2/mmtbx/ncs/ncs_from_pdb.pyR@  }  s    	 c         C   sJ   y |  j  j d | ƒ } Wn* t k
 r/ ‚  n t k
 rE d  } n X| S(   NR©   (   t   all_chain_proxiesR0  t   KeyboardInterruptt	   ExceptionR)   (   R   t   sel_strR0  (    (    sD   /public2/ftp/pub/ccp4/6.5/ccp4-6.5/lib/py2/mmtbx/ncs/ncs_from_pdb.pyR1  ‚  s     
c         C   s½  g  } g  } g  } | s" | | f St  | ƒ t  d ƒ k sV |  j | | ƒ } | | f S| } xÃ | D]» } | d k r“ | rd } t | ƒ ‚ qqc | d k rÏ | s´ t d ƒ ‚ n  |  j | | ƒ \ } } qc | d k rc | | k rt d t | ƒ d t | ƒ ƒ ‚ n  | j | ƒ qc qc W| rC|  j | | ƒ \ } } n  g  }	 xc | D][ } xR | D]J }
 |
 |	 k ršt d d	 t |
 ƒ d
 t | ƒ ƒ ‚ n  |	 j |
 ƒ q]WqPW| | f Sd S(   s!    expect a phil object or text... t   ABCDt   [s:   Format for suggested_ncs_groups is "[ABCD][EFG]" or "ABCD"t   ]t   ABCDEFGHIJKLMNOPQRSTUVWXYZs   The chain ID 'sB   ' is not among the chain ids in this PDB file. 
Available chains: s8   Each chain can be used only once in suggested_ncs_groupss   
Chain s    is listed more than once in N(   t   typeR;  R   t   finish_suggested_groupRº   R(   (   R   R   R6   RÑ   RÆ   R3  t
   input_textt   charR<   t   list_of_used_chainsR"   (    (    sD   /public2/ftp/pub/ccp4/6.5/ccp4-6.5/lib/py2/mmtbx/ncs/ncs_from_pdb.pyt   get_suggested_groupsŠ  sH     
		
(c         C   sP   t  | ƒ d k  r3 t d t | ƒ d d ƒ ‚ n  | j | ƒ g  } | | f S(   Ni   s
   The group s#    seems to have fewer than 2 memberss;   
Format for suggested_ncs_groups is "[ABCD][EFG]" or "ABCD"(   R2   R   Rº   R(   (   R   RÆ   RÑ   (    (    sD   /public2/ftp/pub/ccp4/6.5/ccp4-6.5/lib/py2/mmtbx/ncs/ncs_from_pdb.pyRP  µ  s    c         C   sî  d } g  } g  } xO | D]G \ } } }	 }
 | | k r |	 | k r | j | ƒ | j |
 ƒ q q Wx… | D]} \ } } }	 }
 | | k rk |	 | k rk |	 | k rk | j |	 ƒ | j |
 ƒ | d k rÐ | } qè | | k rè | } qè qk qk W|  j r
|  j | | ƒ } n  |  j rA| d k	 rA| t j t t | ƒ ƒ ƒ } n  |  j	 r˜t
 } x' | D] } | |  j	 k rWt } PqWqWW| s˜d } g  } g  } q˜n  t | ƒ d k  r¿d } g  } g  } n  | rá|  j | ƒ rá| d 7} n  | | | f S(   sh  
    score as the MINIMUM number of matches of anything to the trial_id
    if all the members of a user-specified group are present, add 10000
      to score
    return residue ranges that are not necessarily the same for all members
    of a group...
    090708: allow user to increase score for large groups with
    self.maximize_size_of_groups

    021107:
    Solution: need to use only those with id1==trial_id to keep numbering
    consistent. Then we also need matches to include both directions.

    021207 this didn't do it completely...we want to return offsets
    based not on trial_id but on the firstid in the list...

    the real problem is that here we use a seed (C) to pull out the
      set of chains (A C E G) and the offset matches C here. Then later
      we assume that the offset matched A. One solution might be
    to always use the quick option...using each set of chains
    identified with sequence. HERE JUST this is the best plan?

    021207 better: make sure that trial_id is first in list!
    090808 allow calling program to require a particular set of
    chains to always be present
    i   i'  N(   R)   R(   R   t&   require_matches_to_start_at_same_placeR   Rl   t   sqrtRb   R2   R   R,   R/   t&   a_suggested_ncs_group_is_in_test_group(   R   R×   RÏ   RÀ   RØ   RÆ   RÉ   RÄ   RN   RR   RÈ   t   foundR"   (    (    sD   /public2/ftp/pub/ccp4/6.5/ccp4-6.5/lib/py2/mmtbx/ncs/ncs_from_pdb.pyR»   ¾  sH    $		"		c         C   sO   xH |  j  D]= } t } x$ | D] } | | k r t } Pq q W| r
 t Sq
 Wt S(   sa   
    Returns:
      (bool): True -> all of a suggested_ncs_group are contained in test_group
    (   R   R/   R,   (   R   t
   test_groupRÆ   t   are_inR"   (    (    sD   /public2/ftp/pub/ccp4/6.5/ccp4-6.5/lib/py2/mmtbx/ncs/ncs_from_pdb.pyRW    s    c         C   s½  g  } t  | ƒ d k  r" d g  f St  | d ƒ } | d g } xÑ t | | ƒ D]À \ } } | d k rv t  | ƒ } n  g  } | t  | ƒ  t  | ƒ t  | ƒ d g }	 x_ t |	 | ƒ D]N \ }
 } |
 d k	 rø | d k së |
 d | k rø |
 d } n  | j | ƒ q· W| } qO Wx£ t | | ƒ D]’ \ } } g  } | t  | ƒ  t  | ƒ t  | ƒ d g }	 xR t |	 | ƒ D]A \ }
 } |
 d k	 rp| d k	 rp|
 d | k rp| |
 d <qpqpWq#W| S(   s+   
    Returns:
      residue_range_list
    i   i    N(   R2   R)   R1   R(   (   R   RÆ   RÉ   R*  t   number_of_rangest   last_start_listt   rrRz   t   new_start_listt   rr_modRr   t   st   new_rr(    (    sD   /public2/ftp/pub/ccp4/6.5/ccp4-6.5/lib/py2/mmtbx/ncs/ncs_from_pdb.pyRU    s,     
+(
+(c      
   C   sª  g  } g  } g  }	 g  }
 g  } |  j  r= |  j d I| IJn  t | ƒ d k  rb | | |	 |
 | f S| d } | d } |  j | | | | ƒ \ } } | s­ | | |	 |
 | f Sxçt | | ƒ D]Ö\ } } |  j | | | | ƒ \ } } | s | | |	 |
 | f Sd | d | f } |  j  r+|  j | IJn  |  j | | | | | | | | ƒ } |  j  rn|  j d I| IJn  d } |  j d j t | | g ƒ ƒ } |  j	 | | | | ƒ \ } } |  j	 | | | | ƒ \ } } |  j  r÷|  j d I| I| IJn  | sBt | ƒ d k sB| sBt | ƒ d k sBt | ƒ t | ƒ k rtd	 } |  j  ra|  j | IJn  g  g  g  g  g  f St
 j d
 | d | ƒ } | j | j ƒ  ƒ } | j | ƒ | j t | ƒ ƒ | j | j ƒ |	 j | j ƒ |
 j | ƒ |  j  r½ t j ƒ  } | j | j t j | d ƒ | j ƒ |  j d I| Id I| IJ|  j d I| Id I| d IJ|  j d I| Id I| d IJq½ q½ W| | |	 |
 | f S(   s  
    get rmsd of all from the reference one, using only residues in
    residue_range_list for each chain
    residue_range_list is [residue_range1,residue_range2...]
    residue_range_1 is list of residue ranges: [[1,3],[7-9]...]

    NOTE: residue ranges are absolute
    s   GET_RMSD: residue_range_list: i   i    s   getting CA values for s    and s   Residues in common: Ro   s   Center: s0   Note: No overlap of segments in getting NCS rmsdt   reference_sitest   other_sitess   Getting atom 1 of chain s    from atom 1 of chain s   XYZ of atom 1 chain s    after application of RT: s   xyz of atom 1 chain s    : (   R   R   R2   t   find_chain_and_startR1   Rè   R	   Ré   RZ   Rê   R   t   least_squares_fitt   rms_differencet   other_sites_best_fitR(   Rr   R{   R   t   vec3_doubleR   t   col(   R   RÆ   R4   R!   R6   R7   RÉ   RÊ   RË   t   t_listRÍ   RÎ   RÂ   Rð   RM   RO   RÃ   R÷   RQ   RS   R<   Rø   Rd   Re   Rù   Rú   Rû   Rü   t   lsq_fitR  t   xyz(    (    sD   /public2/ftp/pub/ccp4/6.5/ccp4-6.5/lib/py2/mmtbx/ncs/ncs_from_pdb.pyR¹   2  sv    
	

	 	 "	 	 			(*c	         C   sî  d j  t | | g ƒ ƒ }	 |	 |  j j ƒ  k r@ |  j |	 }
 n |  j d I|	 IJd }
 | |
 } |  j rÚ |  j d IJ|  j d I| I| IJ|  j d I| I| I| IJ|  j d I| IJ|  j d I| IJn  g  } | sî | rò | S|  j | ƒ } |  j | ƒ } g  } x* | D]" } | | k r| j | ƒ qqWx¤ | D]œ } | | |  j } | | |  j } | d k rJ| t	 | ƒ k  rJ| d k rJ| t	 | ƒ k  rJ| | rJ| | rJ| | | | k rJ| j | ƒ qJqJW| S(	   s  
    NOTE: residue ranges are absolute

    Returns:
      residue_list (list): list of residue numbers shared by chain1 and chain2
      in range defined by intersection of residue_range1 and residue_range2
      residue_range_1 is list of residue ranges: [[1,3],[7-9]...]
    Ro   s   NO ID : i    s   Getting residues in commons   Chain1, start1: s   Chain2, start2: t   Residue_range1t   Residue_range2(
   Ré   RZ   R	   t   keysR   R   t   list_all_integers_in_rangeR(   R   R2   (   R   RM   RO   RQ   RS   Rð   R÷   RN   RR   R"   RT   t
   start2_useRø   t   all_residues1t   all_residues2t
   all_to_useR  t   i1t   i2(    (    sD   /public2/ftp/pub/ccp4/6.5/ccp4-6.5/lib/py2/mmtbx/ncs/ncs_from_pdb.pyRè   }  s8    
	 <(c         C   sŒ   g  } | s t  | ƒ d k  r# d  Sxb | D]Z } | d } | d } x= t | | d ƒ D]( } |  j | ƒ rs qX n  | j | ƒ qX Wq* W| S(   Ni   i    (   R2   R'   R&   R(   (   R   RÉ   t   all_intR'  R  t   endRG   (    (    sD   /public2/ftp/pub/ccp4/6.5/ccp4-6.5/lib/py2/mmtbx/ncs/ncs_from_pdb.pyRp  ª  s     

 c      	   C   sÞ  |  j  r% |  j d I| I| IJn  g  } t j ƒ  } d } t j ƒ  } | j d ƒ g  }	 x×| j ƒ  D]É}
 | d 7} | d k r‹ qi n  x¤|
 j ƒ  D]–} | j |	 k r³ q˜ n  |	 j | j ƒ | j | k rØ q˜ n  d } xM| j ƒ  D]?} | d 7} | d k rqë n  g  } x| j	 ƒ  D]} | j
 ƒ  } |  j | ƒ rGq n  | | k rYq n  | j | ƒ | | | k r t } xE | j ƒ  D]7 } | j d k s­| j d k r‰| j } t } Pq‰q‰W| rõ| j | ƒ | j | | ƒ | | 7} q&|  j  r&|  j d | j d t | ƒ IJq&q q Wqë Wq˜ Wqi W|  j d k r¢xZ | D]O } | | k rL|  j d	 I| IJ|  j d
 I| IJt d d d ƒ ‚ qLqLWn  t | ƒ rÖ| d t t | ƒ ƒ } | d | f Sd Sd S(   s   
    s   Getting xyz for i    g        i   s    CA s    P  s   NOTE: Missing CA/P for residue s
    of chain s   Residues expected: s   Residues found   : s.   Did not find expected residues in get_xyz_lists9   
It is possible that your PDB file has segments with one sA   chainID that are 
interspersed with segments with another chainIDg      ð?N(   g        g        g        (   NN(   R   R   R   Rh  R(   R    R!   R"   R#   R$   R%   R&   R,   R-   R.   Rl  R/   R0   Rº   R   R   R2   Rb   R)   (   R   R;   R4   Rø   RT   t   residue_found_listt   xyz_listR8   t   centert   chain_ids_seen_alreadyR9   R:   R=   R>   RH   RB   RC   RI   RJ   Rl  R  (    (    sD   /public2/ftp/pub/ccp4/6.5/ccp4-6.5/lib/py2/mmtbx/ncs/ncs_from_pdb.pyRê   ¶  sr    	 
   
  		1c         C   s   xx |  j  D]m } xd | D]\ } | | k r xG |  j  D]9 } | | k rK q3 n  x | D] } | | k rR t SqR Wq3 Wq q Wq
 Wt S(   sâ   
    find a group that contains a member of test_group. If any other member
    is in another group, return True

    Returns:
      (bool): True  when members of test_group is contained
        in > 1 suggested ncs group
    (   R   R/   R,   (   R   RY  t   group1R"   t   group2(    (    sD   /public2/ftp/pub/ccp4/6.5/ccp4-6.5/lib/py2/mmtbx/ncs/ncs_from_pdb.pyR¸   ô  s    	 c         C   s@   x9 t  | | | ƒ D]% \ } } } | | k r | | f Sq Wd S(   sJ   
    get chain and starting residue number for chain with id chain_id
    N(   NN(   R1   R)   (   R   RÂ   R!   R6   R7   R:   R;   R  (    (    sD   /public2/ftp/pub/ccp4/6.5/ccp4-6.5/lib/py2/mmtbx/ncs/ncs_from_pdb.pyRd    s    "c         C   sO   xH |  j  D]= } t } x$ | D] } | | k r t } Pq q W| r
 t Sq
 Wt S(   s`   
    Returns:
      (bool): True  when  all of test_group is contained in a suggested group
    (   R   R/   R,   (   R   RY  RÆ   RZ  R"   (    (    sD   /public2/ftp/pub/ccp4/6.5/ccp4-6.5/lib/py2/mmtbx/ncs/ncs_from_pdb.pyR·     s    i_   c
          C   s  d j  t | | g ƒ ƒ }
 |
 |  j j ƒ  k r@ |  j |
 } n |  j d I|
 IJd } | | } g  } | sw | r� d | f S| t | ƒ d |  j } | t | ƒ d |  j } | } | } | | k rØ | } n  | | k  rí | } n  | |  j } | |  j } |  j rD|  j d I| Id I| Id I| I| IJn  g  } x£ t | | |  j |  j ƒ D]… } | | | |  j } | | | |  j } | rß| rß| | k r¿| j	 t
 ƒ qì| j	 t ƒ |	 rìd | f Sqg| j	 t ƒ qgWg  } t
 } t | ƒ } d } xT | rd|  j | | | | ƒ \ } } | d k rJt } q| j	 | ƒ | | 7} qW| j ƒ  |  j rŽ|  j d I| IJn  x= | D]5 \ } } | j	 | |  j | | |  j | g ƒ q•W|  j r|  j d	 I| Id
 I| IJ|  j d I| IJn  | | f S(   s  
    return number of residues matching total, and a
    list of residue ranges over which chain1 and chain2 match
    within the tolerance min_percent and each with minimum length
    of min_length

    NOTE: residue range is in terms of position in chain (relative to start,
    and if njump>1 then the residue numbers are in  units of njump

    Returns:
      matching (int): number of matching residues
      keep_range_list (list): list of lists of the matching residues range,
        a list of ranges like [[1,3],[7-9]...]
    Ro   s   NO ID in matches_approx: i    i   s(   Finding matching segments in range from s    to s    for chains s   List of segments: s
   Possible: s    Matching: s   Residue range used: N(   Ré   RZ   R	   Ro  R   R2   R   R   R'   R(   R/   R,   t   find_best_segmentR)   t   sort(    R   RM   RO   RQ   RS   RN   RR   R   R   R±   R"   RT   Rq  RÅ   t   end1t   end2R  Rx  t   start_njumpt	   end_njumpt   matched_residuesRG   Ri   Rj   t   segmentst   still_lookingt   possiblet   matchingt   best_segmentt   best_lengtht	   pos_startt   pos_end(    (    sD   /public2/ftp/pub/ccp4/6.5/ccp4-6.5/lib/py2/mmtbx/ncs/ncs_from_pdb.pyR¶   !  sl    
 
 	 		'#		
	'	c   	      C   sË   t  | ƒ d k  r t Sx‰ | d D]} } t } x? | D]7 \ } } } } | | d k r4 | | k r4 t } q4 q4 W| s! |  j rš |  j d I| I| IJn  t Sq! W|  j rÇ |  j d I| I| IJn  t S(   s(    are all ids matched to a set of id #1? i   i   i    s   missing s   have (   R2   R/   R,   R   R   (	   R   R6   RÀ   R"   RX  RÄ   RN   RR   RÈ   (    (    sD   /public2/ftp/pub/ccp4/6.5/ccp4-6.5/lib/py2/mmtbx/ncs/ncs_from_pdb.pyRµ   }  s      	 	 c         C   sÒ  | } x< | D]4 \ } } x% t  | | d ƒ D] } t | | <q- Wq W|  j rd |  j d I| IJn  d }	 d }
 d } xt  d t | ƒ ƒ D]ù } | | s¢ qŒ n  xà t  | t | ƒ ƒ D]É } | | sÎ q¸ n  | | | d !j t ƒ } | | | d !j t ƒ } | | } | | |  j k  r%q¸ n  | s4d } n d t | ƒ t | ƒ } | | k  r`q¸ n  | | k r¸ | } | }	 | }
 q¸ q¸ WqŒ W|  j r´|  j d I|	 I|
 I| IJn  | rÊ|	 |
 g | f Sd Sd S(	   s¡    mask out all the residues that are used

    Returns:
      [best_start,best_end]: the start and end of a segment
      best_length (int): segment length
      i   s   Available_residues: i    g        g      Y@s   Best segment: N(   Ni    (
   R'   R,   R   R   R2   t   countR/   R   Rb   R)   (   R   R…  R†  R   R   t   available_residuesR  Rx  RG   t
   best_startt   best_endR‹  Rf   t   n_not_matcht   n_totalt   percent(    (    sD   /public2/ftp/pub/ccp4/6.5/ccp4-6.5/lib/py2/mmtbx/ncs/ncs_from_pdb.pyR  ‹  sD    	
 
 
 	 	"N(,   t   __name__t
   __module__t   __doc__R,   t   syst   stdoutR/   R   RV   R3   R[   R&   R*   R½   R¾   R  R  R)   R  Rî   Rç   Rì   Rí   Ræ   R-  R;  R2  R@  R1  RT  RP  R»   RW  RU  R¹   Rè   Rp  Rê   R¸   Rd  R·   R¶   Rµ   R  (    (    (    sD   /public2/ftp/pub/ccp4/6.5/ccp4-6.5/lib/py2/mmtbx/ncs/ncs_from_pdb.pyR   1   s|   .	j	"	%		4ˆ	³	
								#	8			+			F			K	-		>		
	V	c         C   s   |  r | r t  d ƒ ‚ n |  r6 | r6 |  j } n  t d t d t ƒ } t ƒ  } | j d | d g  ƒ \ } } } } } | j d | d | d | d | d	 d
 d d d d d d d t d t ƒ 
\ }	 }
 | j | |	 |
 | | | ƒ \ } } | rœ| } | } x– t	 | | ƒ D]… \ } } | j
 | | | | | | ƒ \ } } } } } | j | | ƒ } | | g } | j d | d | d | d | d | d | ƒ qW| Sd S(   s0    Build and return ncs object from pdb hierarchy s;   No input is provided. Please provide pdb_inp or hierarchy.
t	   exclude_dt	   exclude_hR4   R5   R!   R6   R7   R   i   R   gffffffî?R²   g       @R³   g      @R´   R¿   t   ncs_rota_matrRÊ   RÎ   t   center_ortht
   trans_ortht   chain_residue_idN(   R   R4   R   R/   R   RV   R½   R,   R¾   R1   R¹   Ræ   t   import_ncs_group(   R=  R4   R  t   ncs_processR!   R6   R7   R	   R
   t   sequence_groupst#   sequence_list_of_residue_range_listRà   Rá   RÑ   RÒ   RÆ   RÉ   RÊ   RË   RÌ   RÍ   RÎ   t   residue_range_list_with_offsetsRŸ  (    (    sD   /public2/ftp/pub/ccp4/6.5/ccp4-6.5/lib/py2/mmtbx/ncs/ncs_from_pdb.pyt   get_ncs_object_from_pdb»  sJ    	'		(   R—  t
   __future__R    t   mmtbx.invariant_domainR   t   cctbx.array_familyR   t   libtbxR   t   scitbx.mathR   R   t   libtbx.utilsR   t   mmtbx.ncs.ncsR   R©   Rl   R˜  t   objectR   R)   R¥  (    (    (    sD   /public2/ftp/pub/ccp4/6.5/ccp4-6.5/lib/py2/mmtbx/ncs/ncs_from_pdb.pyt   <module>#   s$   ÿ ÿ ÿ ÿ ÿ �