B
    b;                 @   sP   d Z ddlmZ ddlmZ ddlZddlmZ G dd dZG dd	 d	Z	dS )
zBase class for Residue, Chain, Model and Structure classes.

It is a simple container class, with list and dictionary like properties.
    )deque)copyN)PDBConstructionExceptionc               @   s  e Zd ZdZdd Zdd Zdd Zdd	 Zd
d Zdd Z	dd Z
dd Zdd Zdd Zdd Zdd Zdd Zdd Zdd Zed d! Zejd"d! Zd#d$ Zd%d& Zd'd( Zd)d* Zd+d, Zd-d. Zd/d0 Zd1d2 Zd3d4 Zd5d6 Zd7d8 Z d9d: Z!d;d< Z"dCd>d?Z#d@dA Z$dBS )DEntityzBasic container object for PDB heirachy.

    Structure, Model, Chain and Residue are subclasses of Entity.
    It deals with storage and lookup.
    c             C   s(   || _ d| _d| _g | _i | _i | _dS )zInitialize the class.N)_idfull_idparent
child_list
child_dictxtra)selfid r   -lib/python3.7/site-packages/Bio/PDB/Entity.py__init__   s    zEntity.__init__c             C   s
   t | jS )zReturn the number of children.)lenr	   )r   r   r   r   __len__'   s    zEntity.__len__c             C   s
   | j | S )zReturn the child with given id.)r
   )r   r   r   r   r   __getitem__+   s    zEntity.__getitem__c             C   s
   |  |S )zRemove a child.)detach_child)r   r   r   r   r   __delitem__/   s    zEntity.__delitem__c             C   s
   || j kS )z4Check if there is a child element with the given id.)r
   )r   r   r   r   r   __contains__3   s    zEntity.__contains__c             c   s   | j E dH  dS )zIterate over children.N)r	   )r   r   r   r   __iter__7   s    zEntity.__iter__c             C   sJ   t |t| rB| jdkr$| j|jkS | jdd |jdd kS ntS dS )zJTest for equality. This compares full_id including the IDs of all parents.N   )
isinstancetyper   r   r   NotImplemented)r   otherr   r   r   __eq__=   s
    
zEntity.__eq__c             C   sJ   t |t| rB| jdkr$| j|jkS | jdd |jdd kS ntS dS )zTest for inequality.Nr   )r   r   r   r   r   r   )r   r   r   r   r   __ne__G   s
    
zEntity.__ne__c             C   sJ   t |t| rB| jdkr$| j|jkS | jdd |jdd kS ntS dS )zTest greater than.Nr   )r   r   r   r   r   r   )r   r   r   r   r   __gt__Q   s
    
zEntity.__gt__c             C   sJ   t |t| rB| jdkr$| j|jkS | jdd |jdd kS ntS dS )zTest greater or equal.Nr   )r   r   r   r   r   r   )r   r   r   r   r   __ge__[   s
    
zEntity.__ge__c             C   sJ   t |t| rB| jdkr$| j|jk S | jdd |jdd k S ntS dS )zTest less than.Nr   )r   r   r   r   r   r   )r   r   r   r   r   __lt__e   s
    
zEntity.__lt__c             C   sJ   t |t| rB| jdkr$| j|jkS | jdd |jdd kS ntS dS )zTest less or equal.Nr   )r   r   r   r   r   r   )r   r   r   r   r   __le__o   s
    
zEntity.__le__c             C   s
   t | jS )z&Hash method to allow uniqueness (set).)hashr   )r   r   r   r   __hash__y   s    zEntity.__hash__c          	   C   s>   x.| D ]&}y|   W q tk
r*   Y qX qW |  | _dS )zReset the full_id (PRIVATE).

        Resets the full_id of this entity and
        recursively of all its children based on their ID.
        N)_reset_full_idAttributeError_generate_full_idr   )r   childr   r   r   r%      s    

zEntity._reset_full_idc             C   sN   |   }|g}|  }x&|dk	r<|  }|| | }qW |  t|S )zGenerate full_id (PRIVATE).

        Generate the full_id of the Entity based on its
        Id and the IDs of the parents.
        N)get_id
get_parentappendreversetuple)r   	entity_idpartsr   r   r   r   r'      s    

zEntity._generate_full_idc             C   s   | j S )zReturn identifier.)r   )r   r   r   r   r      s    z	Entity.idc             C   sh   || j krdS | jrV|| jjkr>td| j  d| d| d| jj| j = | | jj|< || _ |   dS )zChange the id of this entity.

        This will update the child_dict of this entity's parent
        and invalidate all cached full ids involving this entity.

        @raises: ValueError
        NzCannot change id from `z` to `z`. The id `z/` is already used for a sibling of this entity.)r   r   r
   
ValueErrorr%   )r   valuer   r   r   r      s    	
c             C   s   | j S )zReturn level in hierarchy.

        A - atom
        R - residue
        C - chain
        M - model
        S - structure
        )level)r   r   r   r   	get_level   s    	zEntity.get_levelc             C   s   || _ |   dS )zSet the parent Entity object.N)r   r%   )r   entityr   r   r   
set_parent   s    zEntity.set_parentc             C   s
   d| _ dS )zDetach the parent.N)r   )r   r   r   r   detach_parent   s    zEntity.detach_parentc             C   s*   | j | }|  | j |= | j| dS )zRemove a child.N)r
   r6   r	   remove)r   r   r(   r   r   r   r      s    
zEntity.detach_childc             C   sD   |  }| |r t| d||  | j| || j|< dS )zAdd a child to the Entity.z defined twiceN)r)   has_idr   r5   r	   r+   r
   )r   r4   r.   r   r   r   add   s    

z
Entity.addc             C   sH   |  }| |r t| d||  |g| j||< || j|< dS )z2Add a child to the Entity at a specified position.z defined twiceN)r)   r8   r   r5   r	   r
   )r   posr4   r.   r   r   r   insert   s    

zEntity.insertc             c   s   | j E dH  dS )zReturn iterator over children.N)r	   )r   r   r   r   get_iterator   s    zEntity.get_iteratorc             C   s
   t | jS )z&Return a copy of the list of children.)r   r	   )r   r   r   r   get_list   s    zEntity.get_listc             C   s
   || j kS )z&Check if a child with given id exists.)r
   )r   r   r   r   r   r8      s    zEntity.has_idc             C   s   | j S )z Return the parent Entity object.)r   )r   r   r   r   r*      s    zEntity.get_parentc             C   s   | j S )zReturn the id.)r   )r   r   r   r   r)      s    zEntity.get_idc             C   s   | j dkr|  | _ | j S )ak  Return the full id.

        The full id is a tuple containing all id's starting from
        the top object (Structure) down to the current object. A full id for
        a Residue object e.g. is something like:

        ("1abc", 0, "A", (" ", 10, "A"))

        This corresponds to:

        Structure with id "1abc"
        Model with id 0
        Chain with id "A"
        Residue with id (" ", 10, "A")

        The Residue id indicates that the residue is not a hetero-residue
        (or a water) because it has a blank hetero field, that its sequence
        identifier is 10 and its insertion code "A".
        N)r   r'   )r   r   r   r   get_full_id   s    

zEntity.get_full_idc             C   s"   x|   D ]}||| q
W dS )aJ  Apply rotation and translation to the atomic coordinates.

        :param rot: A right multiplying rotation matrix
        :type rot: 3x3 Numeric array

        :param tran: the translation vector
        :type tran: size 3 Numeric array

        Examples
        --------
        This is an incomplete but illustrative example::

            from numpy import pi, array
            from Bio.PDB.vectors import Vector, rotmat
            rotation = rotmat(pi, Vector(1, 0, 0))
            translation = array((0, 0, 1), 'f')
            entity.transform(rotation, translation)

        N)r=   	transform)r   ZrotZtranor   r   r   r?     s    zEntity.transformFc       	      C   s   t | st|  dddh}dh}t| g}xF| }|j|krP|| 7 }n
||j7 }dd |D }||kr0P q0W tjdd |D tj	d	}|rd
}ntjdd |D tj	d	}tj
|d|dS )zReturn the center of mass of the Entity as a numpy array.

        If geometric is True, returns the center of geometry instead.
        z does not have childrenRCAc             S   s   h | ]
}|j qS r   )r2   ).0er   r   r   	<setcomp>?  s    z(Entity.center_of_mass.<locals>.<setcomp>c             S   s   g | ]
}|j qS r   )Zcoord)rD   ar   r   r   
<listcomp>C  s    z)Entity.center_of_mass.<locals>.<listcomp>)ZdtypeNc             S   s   g | ]
}|j qS r   )Zmass)rD   rG   r   r   r   rH   G  s    r   )ZaxisZweights)r   r0   r   popleftr2   Zget_unpacked_listr	   npZasarrayZfloat32Zaverage)	r   Z	geometricZmaybe_disorderedZonly_atom_levelZentitiesrE   ZelevelsZcoordsZmassesr   r   r   center_of_mass*  s$    


zEntity.center_of_massc             C   sJ   t | }g |_i |_t | j|_|  x| jD ]}||   q0W |S )zCopy entity recursively.)r   r	   r
   r   r6   r9   )r   shallowr(   r   r   r   r   K  s    zEntity.copyN)F)%__name__
__module____qualname____doc__r   r   r   r   r   r   r   r   r   r    r!   r"   r$   r%   r'   propertyr   setterr3   r5   r6   r   r9   r;   r<   r=   r8   r*   r)   r>   r?   rK   r   r   r   r   r   r      sB   





		
!r   c               @   s   e Zd ZdZdd Zdd Zdd Zdd	 Zd
d Zdd Z	dd Z
dd Zdd Zdd Zdd Zdd Zdd Zdd Zdd Zd d! Zd"d# Zd$d% Zd&d' Zd(d) Zd*d+ Zd,d- Zd.d/ Zd5d1d2Zd3d4 Zd0S )6DisorderedEntityWrappera  Wrapper class to group equivalent Entities.

    This class is a simple wrapper class that groups a number of equivalent
    Entities and forwards all method calls to one of them (the currently selected
    object). DisorderedResidue and DisorderedAtom are subclasses of this class.

    E.g.: A DisorderedAtom object contains a number of Atom objects,
    where each Atom object represents a specific position of a disordered
    atom in the structure.
    c             C   s   || _ i | _d| _d| _dS )zInitialize the class.N)r   r
   selected_childr   )r   r   r   r   r   r   f  s    z DisorderedEntityWrapper.__init__c             C   s&   |dkrt t| dst t| j|S )z.Forward the method call to the selected child.__setstate__rT   )r&   hasattrgetattrrT   )r   methodr   r   r   __getattr__o  s
    
z#DisorderedEntityWrapper.__getattr__c             C   s
   | j | S )z#Return the child with the given id.)rT   )r   r   r   r   r   r   z  s    z#DisorderedEntityWrapper.__getitem__c             C   s   || j |< dS )z*Add a child, associated with a certain id.N)r
   )r   r   r(   r   r   r   __setitem__  s    z#DisorderedEntityWrapper.__setitem__c             C   s
   || j kS )z$Check if the child has the given id.)rT   )r   r   r   r   r   r     s    z$DisorderedEntityWrapper.__contains__c             C   s
   t | jS )zReturn the number of children.)iterrT   )r   r   r   r   r     s    z DisorderedEntityWrapper.__iter__c             C   s
   t | jS )zReturn the number of children.)r   rT   )r   r   r   r   r     s    zDisorderedEntityWrapper.__len__c             C   s
   | j | S )z Subtraction with another object.)rT   )r   r   r   r   r   __sub__  s    zDisorderedEntityWrapper.__sub__c             C   s
   | j |kS )z&Return if child is greater than other.)rT   )r   r   r   r   r   r     s    zDisorderedEntityWrapper.__gt__c             C   s
   | j |kS )z/Return if child is greater or equal than other.)rT   )r   r   r   r   r   r      s    zDisorderedEntityWrapper.__ge__c             C   s
   | j |k S )z#Return if child is less than other.)rT   )r   r   r   r   r   r!     s    zDisorderedEntityWrapper.__lt__c             C   s
   | j |kS )z,Return if child is less or equal than other.)rT   )r   r   r   r   r   r"     s    zDisorderedEntityWrapper.__le__c             C   s:   t | }i |_|  x|  D ]}||   q W |S )z"Copy disorderd entity recursively.)r   r
   r6   disordered_get_listdisordered_add)r   rL   r(   r   r   r   r     s    zDisorderedEntityWrapper.copyc             C   s   | j S )zReturn the id.)r   )r   r   r   r   r)     s    zDisorderedEntityWrapper.get_idc             C   s
   || j kS )z<Check if there is an object present associated with this id.)r
   )r   r   r   r   r   disordered_has_id  s    z)DisorderedEntityWrapper.disordered_has_idc             C   s$   d| _ x|  D ]}|  qW dS )zDetach the parent.N)r   r]   r6   )r   r(   r   r   r   r6     s    z%DisorderedEntityWrapper.detach_parentc             C   s   | j S )zReturn parent.)r   )r   r   r   r   r*     s    z"DisorderedEntityWrapper.get_parentc             C   s&   || _ x|  D ]}|| qW dS )z/Set the parent for the object and its children.N)r   r]   r5   )r   r   r(   r   r   r   r5     s    z"DisorderedEntityWrapper.set_parentc             C   s   | j | | _dS )zSelect the object with given id as the currently active object.

        Uncaught method calls are forwarded to the selected child object.
        N)r
   rT   )r   r   r   r   r   disordered_select  s    z)DisorderedEntityWrapper.disordered_selectc             C   s   t dS )zdAdd disordered entry.

        This is implemented by DisorderedAtom and DisorderedResidue.
        N)NotImplementedError)r   r(   r   r   r   r^     s    z&DisorderedEntityWrapper.disordered_addc             C   s   t dS )zgRemove disordered entry.

        This is implemented by DisorderedAtom and DisorderedResidue.
        N)ra   )r   r(   r   r   r   disordered_remove  s    z)DisorderedEntityWrapper.disordered_removec             C   s   dS )zBReturn 2, indicating that this Entity is a collection of Entities.   r   )r   r   r   r   is_disordered  s    z%DisorderedEntityWrapper.is_disorderedc             C   s
   t | jS )zReturn a list of id's.)sortedr
   )r   r   r   r   disordered_get_id_list  s    z.DisorderedEntityWrapper.disordered_get_id_listNc             C   s   |dkr| j S | j| S )zsGet the child object associated with id.

        If id is None, the currently selected child is returned.
        N)rT   r
   )r   r   r   r   r   disordered_get  s    z&DisorderedEntityWrapper.disordered_getc             C   s   t | j S )zReturn list of children.)listr
   values)r   r   r   r   r]     s    z+DisorderedEntityWrapper.disordered_get_list)N)rM   rN   rO   rP   r   rY   r   rZ   r   r   r   r\   r   r    r!   r"   r   r)   r_   r6   r*   r5   r`   r^   rb   rd   rf   rg   r]   r   r   r   r   rS   Z  s4   
	
	rS   )
rP   collectionsr   r   ZnumpyrJ   ZBio.PDB.PDBExceptionsr   r   rS   r   r   r   r   <module>
   s     H