B
    bB                @   s.  d Z ddlmZmZ ddlZddlZddlZddlmZ ddl	m	Z	 ddl
ZddlmZ ddlmZ dd	lmZmZ dd
lmZ ddlmZmZmZmZ ddlmZmZmZmZmZm Z m!Z!m"Z"m#Z#m$Z$m%Z%m&Z&m'Z'm(Z(m)Z)m*Z*m+Z+m,Z,m-Z-m.Z.m/Z/m0Z0m1Z1m2Z2m3Z3m4Z4m5Z5m6Z6m7Z7 ddl8m9Z9m:Z:m;Z; ddl<m=Z= ddl>m?Z?m@Z@mAZA ddlBmCZCmDZD ddlEmFZF y(ddlGmHZH ddlImJZK ddlLmMZM W n eNk
r   d ZHZKY nX eOePZQdd ZRdd ZSdd ZTdd ZUdd ZVe=dd  ZWG d!d" d"eXZYG d#d$ d$eXZZG d%d& d&eXZ[d'd( Z\d)d* Z]dS )+z
This module contains the core base class for all of the chemical structures with
various topological and force field features.
    )absolute_importdivisionN)defaultdict)copy   )unit)residue)
DEG_TO_RADSMALL)ParameterError)STANDARD_BOND_LENGTHS_SQUARED!box_lengths_and_angles_to_vectors!box_vectors_to_lengths_and_angles	distance2)AcceptorDonorAngleAtomAtomListBondChiralFrameCmapDihedralDihedralTypeDihedralTypeList
ExtraPointGroupImproperMultipoleFrameNonbondedExceptionNoUreyBradleyOutOfPlaneBendOutOfPlaneExtraPointFrame	PiTorsionResidueListStretchBendThreeParticleExtraPointFrameTorsionTorsionTrackedListTrigonalAngleTwoParticleExtraPointFrameUnassignedAtomTypeUreyBradleyLink)PYPYfind_atom_pairstag_molecules)needs_openmm)integer_types	iteritemsstring_types)rangezip)Vec3)app)openmm)reducePeriodicBoxVectorsc          	   C   s   g }x| D ]}t |rN|jt jr:||t j q||t j q
t|t	rbt
dq
yt| t|}W n t
k
r   Y nX || q
W |S )NzUnit cell cannot have strings)uis_quantityr   Zis_compatibledegreeappendvalue_in_unit	angstroms
isinstancer3   	TypeErroriter_strip_box_units)argsZnew_argsarg rF   /lib/python3.7/site-packages/parmed/structure.pyrC   0   s    



rC   c             C   sX   | j dkrdS | j dkrdS | j dkr*dS | j dkr8dS | j d	krFd
S | j dkrTdS dS )N   g333333?r   g333333?   g?   g @   g?   g?g      ?)atomic_number)atomrF   rF   rG   _bondiF   s    
 
 
 
 
 
 rO   c             C   s@   | j dkr8| j}|d j dkr"dS |d j dkr4dS dS t| S )Nr   r   )rH   rI   g?)   rL   g?g333333?)rM   bond_partnersrO   )rN   ZbondedsrF   rF   rG   _mbondiO   s    
rR   c             C   s*   | j dkr"| jd j dkrdS dS t| S )Nr   r   rI   g?g333333?)rM   rQ   rO   )rN   rF   rF   rG   _mbondi2Y   s
    
rS   c             C   sh   | j jdkr*| jds$| jdrRdS n(| j jdkrR| jdsN| jdrRdS | jd	kr`dS t| S )
N)ZGLUZASPZGL4ZAS4ZOEZODgffffff?ZARGZHHZHEgQ?ZOXT)r   name
startswithrS   )rN   rF   rF   rG   _mbondi3`   s    
rV   c             C   s   |t jt jfkrt| }nt| }| jdkr4|dfS | jdkrF|dfS | jdkrX|dfS | jdkrj|dfS | jdkr||d	fS | jd
kr|dfS | jdkr|dfS |dfS )a  
    Gets the default GB parameters for a given atom according to a specific
    Generalized Born model

    Parameters
    ----------
    atom : :class:`Atom`
        The atom to get the default GB parameters for
    model : ``app.HCT, app.OBC1, or app.OBC2``
        The GB model to get the default parameters for (app.GBn and app.GBn2 are
        already handled in Structure._get_gb_parameters)

    Returns
    -------
    radius, screen [,alpha, beta, gamma] : ``float, float [,float, float, float]``
        The intrinsic radius of the atom and the screening factor of the atom.
        If the model is GBn2, alpha, beta, and gamma parameters are also
        returned
    r   g333333?rH   g
ףp=
?rI   gHzG?rP   	   g)\(?rK   gQ?rL   gQ?g?)r7   OBC1OBC2rS   rR   rM   )rN   ZmodelZradrF   rF   rG   _gb_rad_screenk   s$    

 
 
 
 
 
 
 rZ   c               @   s  e 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d Zdd ZdddZdd Zdd Zdd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/d0 Z d1d2 Z!e"d3d4 Z#d5d6 Z$dd8d9Z%d:d; Z&e"d<d= Z'e'j(d>d= Z'e"e)d?d@ Z*e"dAdB Z+e+j(dCdB Z+e"dDdE Z,e,j(dFdE Z,ddHdIZ-e"dJdK Z.e.j(dLdK Z.ddMdNZ/e"dOdP Z0e0j(dQdP Z0dRdS Z1e"dTdU Z2e2j(dVdU Z2e)d7dWe3j4 dXe3j4 d7dYd7d7dXe3j5 e3j6 dZe3j7 d[d\ddYd7d]dYddfd^d_Z8e)d`da Z9e)dbdc Z:e)ddddeZ;e)ddfdgZ<e)ddhdiZ=e)djdk Z>e)dldm Z?e)dndo Z@e)dpdq ZAe)d7d
e3j4 de3j4 d]d\fdrdsZBdtdu ZCdvdw ZDe)d7dxe3j4 d[d\d7dXe3j5 e3jE dZe3j7 dYfdydzZFe)d{d| ZGe)d}d~ ZHe)dd ZIe)dd ZJe)dd ZKdd ZLdd ZMdddZNdd ZOdd ZPdd ZQdd ZRdd ZSdd ZTdd ZUdd ZVdd ZWdd ZXdd ZYdd ZZe)dd Z[dd Z\dd Z]dd Z^dd Z_e_Z`dddZadd ZbebZceddd Zedd Zfdd Zgd7S )	Structurea  
    A chemical structure composed of atoms, bonds, angles, torsions, and other
    topological features

    Attributes
    ----------
    atoms : :class:`AtomList`
        List of all atoms in the structure
    residues : :class:`ResidueList`
        List of all residues in the structure
    bonds : :class:`TrackedList` (:class:`Bond`)
        List of all bonds in the structure
    angles : :class:`TrackedList` (:class:`Angle`)
        List of all angles in the structure
    dihedrals : :class:`TrackedList` (:class:`Dihedral`)
        List of all dihedrals in the structure
    rb_torsions : :class:`TrackedList` (:class:`Dihedral`)
        List of all Ryckaert-Bellemans torsions in the structure
    urey_bradleys : :class:`TrackedList` (:class:`UreyBradley`)
        List of all Urey-Bradley angle bends in the structure
    impropers : :class:`TrackedList` (:class:`Improper`)
        List of all CHARMM-style improper torsions in the structure
    cmaps : :class:`TrackedList` (:class:`Cmap`)
        List of all CMAP objects in the structure
    trigonal_angles : :class:`TrackedList` (:class:`TrigonalAngle`)
        List of all AMOEBA-style trigonal angles in the structure
    out_of_plane_bends : :class:`TrackedList` (:class:`OutOfPlaneBends`)
        List of all AMOEBA-style out-of-plane bending angles
    pi_torsions : :class:`TrackedList` (:class:`PiTorsion`)
        List of all AMOEBA-style pi-torsion angles
    stretch_bends : :class:`TrackedList` (:class:`StretchBend`)
        List of all AMOEBA-style stretch-bend compound bond/angle terms
    torsion_torsions : :class:`TrackedList` (:class:`TorsionTorsion`)
        List of all AMOEBA-style coupled torsion-torsion terms
    chiral_frames : :class:`TrackedList` (:class:`ChiralFrame`)
        List of all AMOEBA-style chiral frames defined in the structure
    multipole_frames : :class:`TrackedList` (:class:`MultipoleFrame`)
        List of all AMOEBA-style multipole frames defined in the structure
    adjusts : :class:`TrackedList` (:class:`NonbondedException`)
        List of all nonbonded pair-exception rules
    acceptors : :class:`TrackedList` (:class:`AcceptorDonor`)
        List of all H-bond acceptors, if that information is present
    donors : :class:`TrackedList` (:class:`AcceptorDonor`)
        List of all H-bond donors, if that information is present
    groups : :class:`TrackedList` (:class:`Group`)
        List of all CHARMM-style GROUP objects (whatever those are used for)
    box : ``list of 6 floats``
        Box dimensions (a, b, c, alpha, beta, gamma) for the unit cell. If no
        box is defined, `box` is set to `None`
    space_group : ``str``
        The space group of the structure (default is "P 1")
    nrexcl : ``int``
        The number of bonds away that an atom can be in order to be excluded
        from the direct nonbonded summation
    title : ``str``
        Cosmetic only, it is an arbitrary title assigned to the system. Default
        value is an empty string
    positions : u.Quantity(list(Vec3), u.angstroms)
        Unit-bearing atomic coordinates. If not all atoms have coordinates, this
        property is None
    coordinates : np.ndarray of shape (nframes, natom, 3)
        If no coordinates are set, this is set to None. The first frame will
        match the coordinates present on the atoms.
    symmetry : :class:`Symmetry`
        if no symmetry is set, this is set to None.
    links : :class:`TrackedList` (:class:`Link`)
        The list of Link definitions for this Structure

    Notes
    -----
    This class also has a handful of type lists for each of the attributes above
    (excluding `atoms`, `residues`, `chiral_frames`, and `multipole_frames`).
    They are all TrackedList instances that are designed to hold the relevant
    parameter type. The list is:
        bond_types, angle_types, dihedral_types, urey_bradley_types,
        improper_types, cmap_types, trigonal_angle_types,
        out_of_plane_bend_types, pi_torsion_types, stretch_bend_types,
        torsion_torsion_types, adjust_types

    dihedral_types _may_ be a list of :class:`DihedralType` instances, since
    torsion profiles are often represented by a Fourier series with multiple
    terms
    r   r               rH   rI   rP   rW   
         c             C   sD  t  | _t | _t | _t | _t | _t | _t | _	t | _
t | _t | _t | _t | _t | _t | _t | _t | _t | _t | _t | _t | _t | _t | _t | _t | _t | _t | _t | _t | _t | _t | _ t | _!t | _"t | _#t | _$d | _%d | _&d| _'d| _(d| _)d| _*d| _+d | _,d S )NzP 1Fr]    lorentz)-r   atomsr#   residuesr'   bondsangles	dihedralsrb_torsionsurey_bradleys	improperscmapstrigonal_anglesout_of_plane_bendspi_torsionsstretch_bendstorsion_torsionschiral_framesmultipole_framesadjusts	acceptorsdonorsgroups
bond_typesangle_typesdihedral_typesurey_bradley_typesimproper_typesrb_torsion_types
cmap_typestrigonal_angle_typesout_of_plane_bend_typespi_torsion_typesstretch_bend_typestorsion_torsion_typesadjust_typeslinks_box_coordinatesspace_groupunknown_functionalnrexcltitle_combining_rulesymmetry)selfrF   rF   rG   __init__   sT    zStructure.__init__c             C   s&  t | j}t | j}tdd | jD }dt| j|f g}|dkrR|d|  |d|  t | j}|d|  | jd k	r|d t	| jd	 d
 t
kst	| jd d
 t
kst	| jd d
 t
kr|d n
|d t | jdkr| jd jd k	r|d n
|d d|S )Nc             S   s   g | ]}t |tqS rF   )r@   r   ).0arF   rF   rG   
<listcomp>,  s    z&Structure.__repr__.<locals>.<listcomp>z<%s %d atomsr   z	 [%d EPs]z; %d residuesz
; %d bondsz; PBCr]   Z   r^   r_   z (triclinic)z (orthogonal)z; parametrized>z; NOT parametrized>rc   )lenre   rf   sumtype__name__r=   rg   boxabsr
   join)r   natomnresnextraretstrnbondrF   rF   rG   __repr__)  s&    




,
"
zStructure.__repr__rc   c             C   s&   | j |||||| | j| dS )a  
        Adds a new atom to the Structure, adding a new residue to `residues` if
        it has a different name or number as the last residue added and adding
        it to the `atoms` list.

        Parameters
        ----------
        atom : :class:`Atom`
            The atom to add to this residue list
        resname : ``str``
            The name of the residue this atom belongs to
        resnum : ``int``
            The number of the residue this atom belongs to
        chain : ``str``
            The chain ID character for this residue
        inscode : ``str``
            The insertion code ID character for this residue (it is stripped)
        segid : ``str``
            The segment identifier for this residue (it is stripped)

        Notes
        -----
        If the residue name and number differ from the last residue in this
        list, a new residue is added and the atom is added to that residue
        N)rf   add_atomre   r=   )r   rN   ZresnameZresnumchainZinscodesegidrF   rF   rG   r   D  s    zStructure.add_atomc             C   sb   |j | jk	rtd|jd }|| | jr<|| jd krJ| j| n| j|jd | dS )a  
        Adds a new atom to the Structure at the end if the given residue

        Parameters
        ----------
        atom : :class:`Atom`
            The atom to add to the system
        residue : :class:`Residue`
            The residue to which to add this atom. It MUST be part of this
            Structure instance already or a ValueError is raised

        Notes
        -----
        This atom is added at the end of the residue and is inserted into the
        `atoms` list in such a way that all residues are composed of atoms
        contiguous in the atoms list. For large systems, this may be a
        relatively expensive operation
        z$Residue is not part of the structurer   N)listrf   
ValueErrorre   r   r=   insertidx)r   rN   r   Z	last_atomrF   rF   rG   add_atom_to_residuec  s    

zStructure.add_atom_to_residuec             C   s   |  t| S )z A deep copy of the Structure )r   r   )r   rF   rF   rG   __copy__  s    zStructure.__copy__Fc       *      C   s
  | }x:| j D ]0}|j}t|}|||j|j|j|j|j qW x| j	D ]}|j	
t| qJW |j	  x| jD ]}|j
t| qtW |j  |r,d}	i }
xt| jD ]v\}}t|drxb|D ].}|j
t| |
|g 
|	 |	d7 }	qW q|
|g 
|	 |	d7 }	|j
t| qW n"x | jD ]}|j
t| q4W |j  x | jD ]}|j
t| q`W |j  x | jD ]}|j
t| qW |j  x | jD ]}|j
t| qW |j  x | jD ]}|j
t| qW |j  x | jD ]}|j
t| qW |j  x | jD ]}|j
t| q<W |j  x | jD ]}|j
t| qhW |j  x | jD ]}|j
t| qW |j  x | jD ]}|j
t| qW |j  x | jD ]}|j
t| qW |j  |j }xT| jD ]J}|j
t||jj ||jj |j oR|j	|j j  |j!|jd _!qW x^| j"D ]T}|j"
t#||jj ||jj ||j$j |j o|j|j j  |j!|j"d _!qtW |r x| j%D ]}t|j drxt&t'|j D ]}|j(p|t'|j d k }|
|j j | }|j%
t)||jj ||jj ||j$j ||j*j |j+||j| d |j,|j%d _,q W nn|
|j j d }|j%
t)||jj ||jj ||j$j ||j*j |j+|j(|j o|j| d |j,|j%d _,qW nx| j%D ]v}|j dkrd}n|j|j j }|j%
t)||jj ||jj ||j$j ||j*j |j+|j(|d |j,|j%d _,qW x\| j-D ]R}|j t.krt.}n|j o|j|j j }|j-
t/||jj ||jj | qW xZ| j0D ]P}|j0
t1||jj ||jj ||j$j ||j*j |j o0|j|j j  qW xj| j2D ]`}|j2
t)||jj ||jj ||j$j ||j*j |j o|j|j j d |j,|j2d _,qDW xr| j3D ]h} |j3
t4|| jj || jj || j$j || j*j || j5j | j o|j| j j  | j!|j3d _!qW xZ| j6D ]P}|j6
t7||jj ||jj ||j$j ||j*j |j ol|j|j j  q$W xZ| j8D ]P}!|j8
t9||!jj ||!jj ||!j$j ||!j*j |!j o|j|!j j  qW xn| j:D ]d}"|j:
t;||"jj ||"jj ||"j$j ||"j*j ||"j5j ||"j<j |"j o8|j|"j j  qW xP| j=D ]F}#|j=
t>||#jj ||#jj ||#j$j |#j o|j|#j j  qLW xd| j?D ]Z}|j?
t@||jj ||jj ||j$j ||j*j ||j5j |j o|j|j j  qW x6| jAD ],}$|jA
tB||$jj ||$jj |$jC 	qW x8| jDD ].}%|jD
tE||%jFj |%jG|%jH|%jI|%jJ 	q<W xF| jKD ]<}|jK
tL||jj ||jj |j 	o|j|j j  	qvW x2| jMD ](}|jM
tN||jj ||jj  	qW x2| jOD ](}|jO
tN||jj ||jj  	qW x0| jPD ]&}&|jP
tQ||&jFj |&j |&jR 
q&W x>| jSD ]4}'|jS
tT||'jj ||'jj |'jU|'jV|'jW 
qXW t| jX|_Xt| jY|_Y| jZ|_Zx$t[|j\| j\D ]\}(})|)j]|(_]
qW |S )a  
        Makes a copy of the current structure as an instance of a specified
        subclass

        Parameters
        ----------
        cls : Structure subclass
            The returned object is a copy of this structure as a `cls` instance
        split_dihedrals : ``bool``
            If True, then the Dihedral entries will be split up so that each one
            is paired with a single DihedralType (rather than a
            DihedralTypeList)

        Returns
        -------
        *cls* instance
            The instance of the Structure subclass `cls` with a copy of the
            current Structure's topology information
        r   __iter__r   r   )improper
ignore_endr   N)r   )^re   r   r   r   rT   numberr   insertion_coder   ry   r=   claimrz   	enumerater{   hasattr
setdefaultr|   r}   r~   r   r   r   r   r   r   r   rg   r   atom1r   atom2r   functrh   r   atom3ri   r4   r   r   r   atom4r   Z_functrk   r   r+   rl   r   rj   rm   r   atom5rn   r(   ro   r    rp   r"   atom6rq   r$   rr   r&   rs   r   	chiralityrt   r   rN   frame_pt_numvectailvecheadnvecru   r   rv   r   rw   rx   r   mover   r,   lengthZsymmetry_op1Zsymmetry_op2r   r   combining_ruler5   rf   ter)*r   clsZsplit_dihedralscrN   resr   ZbtatZndtZmapdtZidtZdttutitZrtctZtaZotZptstttre   bdiZieZtitypubrcmopsZchmglZr1Zr2rF   rF   rG   r     sh   "



















$ 
   
 
  ""&zStructure.copyc             C   s   ddl m} || S )aM   Generates a DataFrame from the current Structure's atomic properties

        Returns
        -------
        df : DataFrame
            DataFrame with all atomic properties

        See Also
        --------
        :func:`parmed.utils.pandautils.create_dataframe` for full
        documentation of the generated DataFrame
        r   )create_dataframe)parmed.utils.pandautilsr   )r   r   rF   rF   rG   to_dataframeq  s    zStructure.to_dataframec             C   s   ddl m} || |S )av   Loads atomic properties from an input DataFrame

        Parameters
        ----------
        df : pandas.DataFrame
            A pandas DataFrame with atomic properties that will be used to set
            the properties on the current list of atoms

        See Also
        --------
        :func:`parmed.utils.pandautils.load_dataframe` for full documentation
        r   )load_dataframe)r   r   )r   dfr   rF   rF   rG   r     s    zStructure.load_dataframec             C   sH  | j jpF| jjpF| jjpF| jjpF| jjpF| jjpF| jjpF| jjpF| j	jpF| j
jpF| jjpF| jjpF| jjpF| jjpF| jjpF| jjpF| jjpF| jjpF| jjpF| jjpF| jjpF| jjpF| jjpF| jjpF| jjpF| jjpF| jjpF| j
jpF| jjpF| jjpF| jjpF| jjpF| j jS )zB Determines if any of the topology has changed for this structure )!re   changedrf   rg   rn   ri   rk   rl   rm   rh   ro   rp   rq   rr   rs   rt   ru   rv   rw   rx   ry   rz   r{   r|   r   r}   r   r   r   r   r   rj   r~   )r   rF   rF   rG   
is_changed  s&    



zStructure.is_changedc             C   s   d| j _d| j_d| j_d| j_d| j_d| j_d| j_d| j_d| j	_d| j
_d| j_d| j_d| j_d| j_d| j_d| j_d| j_d| j_d| j_d| j_d| j_d| j_d| j_d| j_d| j_d| j_d| j_d| j_d| j_d| j_d| j_dS )z< Toggles all lists so that they do not indicate any changes FN) re   r   rf   rg   rh   ri   rk   rl   rm   rn   ro   rp   rq   rr   rs   rt   ru   rv   rw   rx   ry   rz   r{   r|   r}   r   r   r   r   r   r   r   )r   rF   rF   rG   unchange  s>    zStructure.unchangec             C   s|   |    |   |   |   |   |   |   |   |   | 	  | 
  |   |   |   |   dS )z
        Looks through all of the topological lists and gets rid of terms
        in which at least one of the atoms is None or has an `idx` attribute set
        to -1 (indicating that it has been removed from the `atoms` atom list)
        N)_prune_empty_bonds_prune_empty_angles_prune_empty_dihedrals_prune_empty_rb_torsions_prune_empty_ureys_prune_empty_impropers_prune_empty_cmaps_prune_empty_trigonal_angles_prune_empty_out_of_plane_bends_prune_empty_pi_torsions_prune_empty_stretch_bends_prune_empty_torsion_torsions_prune_empty_chiral_frames_prune_empty_multipole_frames_prune_empty_adjusts)r   rF   rF   rG   prune_empty_terms  s    zStructure.prune_empty_termsc             C   s   t  }g }x| jD ]}|jrq|j|jjks:|j|jjkrBd|_q|jj|jjf|kr^d|_qt|j	t
r|j	jdkr|| q||jj|jjf ||jj|jjf qW x&|D ]}|jj|jjf|krd|_qW dS )a2  
        Nonbonded exclusions and exceptions have the following priority:

        bond -> angle -> dihedral

        Since bonds and angles are completely excluded, any ring systems in
        which two atoms are attached by a bond or angle as well as a dihedral
        should be completely excluded as the bond and angle exclusion rules take
        precedence.  If a Bond or Angle was _added_ to the structure between a
        pair of atoms previously connected only by a dihedral term, it's
        possible that those two atoms have both an exclusion *and* an exception
        defined. The result of this scenario is that sander and pmemd will
        happily compute an energy, _including_ the 1-4 nonbonded terms between
        atoms now connected by a bond or an Angle.  OpenMM, on the other hand,
        will complain about an exception specified multiple times. This method
        scans through all of the dihedrals in which `ignore_end` is `False` and
        turns it to `True` if the two end atoms are in the bond or angle
        partners arrays
        Tr   N)setri   r   r   r   rQ   Zangle_partnersr   r@   r   r   perr=   add)r   Zset14Zdeferred_dihedralsZdihedralrF   rF   rG   update_dihedral_exclusions  s"     
z$Structure.update_dihedral_exclusionsc                s6  ddl m} t||r2|j| k	r(td|  nht|trL|| |  nNyt| W n& tk
r~   tdt|j	 Y nX t
 t
| jkrtdtdd t D }xt|D ]}| j|= qW |   | j  |   | jdk	r2trt fd	d| jD | _n| jddt dkf | _dS )
a  
        Deletes a subset of the atoms corresponding to an atom-based selection.

        Parameters
        ----------
        selection : :class:`AmberMask`, ``str``, or ``iterable``
            This is the selection of atoms that will be deleted from this
            structure. If it is a string, it will be interpreted as an
            AmberMask. If it is an AmberMask, it will be converted to a
            selection of atoms. If it is an iterable, it must be the same length
            as the `atoms` list.
        r   )	AmberMaskz(passed mask does not belong to Structurez#Selection not a supported type [%s]zSelection iterable wrong lengthc             S   s   g | ]\}}|r|qS rF   rF   )r   r   r   rF   rF   rG   r   5  s    z#Structure.strip.<locals>.<listcomp>Nc                s"   g | ]} fd dt |D qS )c                s,   g | ]$\}\}}} | d kr|||gqS )r   rF   )r   r   xyz)selrF   rG   r   @  s    z.Structure.strip.<locals>.<listcomp>.<listcomp>)r   )r   Zcrd)r   rF   rG   r   @  s   )parmed.amberr   r@   parmrA   	Selectionr3   r   r   r   r   re   r   sortedr   reversedr   rf   Zpruner   r   r-   nparray)r   	selectionr   Zatomlistr   rF   )r   rG   strip  s4    





zStructure.stripc          	   G   s  ddl m} t|}x|D ]}|| qW t }t }t }x| jD ]}t||}	|	dkrt||j || qFdd |jD }
x|jD ]}|j	|	j
kr|| q|	j
|j	 j|_xX|	j
|j	 jD ]F}|j	|
kr|
|j	 |jkr||
|j	 jkr| jt||
|j	  qW qW qFW xZt| jdd D ]B\}}t||}	|js0|jrp|j| j|d  jkrpq0t| j|d  |}|	dkr|dkrq0|	dkrH|jdkrq0x:| j|d  jD ]}|j	|jj	krP qW td q0xP|jD ]F}t|j|jf }t|||k r||jkr<| jt|| P qW q0|	jdkrXq0|dkrx&|jD ]}|j	|	jj	krjP qjW q0xZ| j|d  jD ]F}t|j|jf }t|||k r||jkr| jt|| P qW q0|jdkrq0x&|jD ]}|j	|	jj	krP qW q0x0| j|d  jD ]}|j	|jj	kr4P q4W q0||jkr0| jt|| q0W x| jD ]}t|j	d	kstj|j	sqtj|j	jd
krqxB|jD ]8}|j	dkrt|jdk r|| || P qW qW | jdkrdS t !t"t# }t$| ||}x|D ]}xR||j% D ]D}t|j|jf }t|||k rP||jkrP| jt|| qPW |j|ks@||krq@x^|jjD ]R}||krΐqt|j|jf }t|||k r||jkr| jt|| qW q@W dS )a  
        Assigns bonds to all atoms based on the provided residue template
        libraries. Atoms whose names are *not* in the templates, as well as
        those residues for whom no template is found, is assigned to bonds based
        on distances.

        Parameters
        ----------
        reslibs : dict{str: ResidueTemplate}
            Any number of residue template libraries. By default, assign_bonds
            knows about the standard amino acid, RNA, and DNA residues.
        r   )StandardBiomolecularResiduesNc             S   s   i | ]}||j qS rF   )rT   )r   r   rF   rF   rG   
<dictcomp>g  s    z*Structure.assign_bonds.<locals>.<dictcomp>r   r   zCould not find the head atom of the next template! Bond pattern may be wrong, which could lead to extra TER cards in a PDB filer]   ZCYSZSGr\   )&Zparmed.modellerr  r   updater   rf   _res_in_templlibre   r   rT   maprM   rQ   rg   r=   r   r   r   r   headLOGGERZwarningr   r   tailr   r   AminoAcidResiduehasgetabbrcoordinatesmathsqrtmaxvaluesr.   r   )r   Zreslibsr  Zall_residueslibZunassigned_residuesZunassigned_atomsZcysteine_sgr   ZtemplZresatomsr   Zbpr   Zntemplr  Zmaxdistr  ZmindistZpairsrN   partnerrF   rF   rG   assign_bondsI  s    



$ 
(


 


	
zStructure.assign_bondsc             O   s.   | j dkrtdddlm} || f||S )a  Use nglview for visualization. This only works with Jupyter notebook
        and require to install `nglview`

        Examples
        --------
        >>> import parmed as pmd
        >>> parm = pmd.download_PDB('1tsu')
        >>> parm.visualize()

        Parameters
        ----------
        args and kwargs : positional and keyword arguments given to nglview, optional
        Nzcoordinates must not be Noner   )show_parmed)r  r   Znglviewr  )r   rD   kwargsr  rF   rF   rG   	visualize  s    
zStructure.visualizec                s^  t |tr| j| S | |}|dkr0t|  S t |tr>|S t|}|dkrXt|  S |d g x0tdt|D ]} 	 |d  ||   qrW dd t
 |D  t|  x^t| jD ]P\}}|| sq|j}|jdkr|j}n|j}t||j||j|j|j qW  fdd}|jj| j| jdd	g |jj| j| jdd	d
g |jj| j| jdd	d
dddg |jj| j| jdd	d
dddg |jj| j| jdd	g |jj | j| j dd	d
dg |j!j"| j!| j"dd	d
ddg |j#j$| j#| j$dd	d
dg |j%j&| j%| j&dd	d
dg |j'j(| j'| j(dd	d
dddg |j)j*| j)| j*dd	d
g |j+j,| j+| j,dd	d
ddg |j-g | j-g dd	dg |j.g | j.g dddddg |j/j0| j/| j0dd	g |j1g | j1g dd	g |j2g | j2g dd	g |j3g | j3g dddg | j4_4| j5_5| j6_6S )aY  
        Allows extracting a single atom from the structure or a slice of atoms
        as a new Structure instance. The following syntaxes are allowed:

            - struct[str] : str is interpreted as an Amber selection mask
            - struct[[sel,[sel,]],sel] : sel can be a list of indices (or
                            strings for chain selection) an integer, or a slice

        Parameters
        ----------
        selection : str, or slice|iter|str, slice|iter|int, slice|iter|int
            Which atoms to select for the new structure

        Returns
        -------
        struct : :class:`Structure`
            If more than one atom is selected, the resulting return value is a
            new structure containing all selected atoms and all valence terms
            (and types) in which all involved atoms are present

        or

        atom : :class:`Atom`
            If the selection is a single integer, a tuple of two integers, or a
            tuple of a string and two integers. This is equivalent to selecting
            a particular atom, a particular atom from a particular residue, or a
            particular atom from a particular residue from a particular chain,
            respectively. All other selections return a Structure instance, even
            if that selection happens to only select a single atom.

        Notes
        -----
        When selecting more than 1 atom, this is a costly operation. It is
        currently implemented by making a full copy of the object and then
        stripping the unused atoms.

        Raises
        ------
        ``TypeError`` : if selection (or any part of the selection) is not an
                        allowed type

        ``ValueError`` : if the selection is a boolean-like list and its length
                         is not the same as the number of atoms in the system
        Nr   r   c             S   s   g | ]\}}|| qS rF   rF   )r   r   r   rF   rF   rG   r   ?  s    z)Structure.__getitem__.<locals>.<listcomp>c                sJ  dd |D }dd |D }x|D ]  fdd|D }fdd|D }t |sTq"t }	t drx jtkrxt|	d< n*|r jdk	r| jj |	d< d| jj< x6t|D ]*\}
}t|trj	|j d	  ||
< qW | 
t ||	 t d
r" j| d _q"W x(t||D ]\}}|r|
| qW t|drF|  dS )z Copies the valence terms from one list to another;
            oval=Other VALence; otyp=Other TYPe; sval=Self VALence;
            styp=Self TYPe; attrlist=ATTRibute LIST (atom1, atom2, ...)
            c             S   s   g | ]}t |qS rF   )r   )r   r   rF   rF   rG   r   O  s    zEStructure.__getitem__.<locals>.copy_valence_terms.<locals>.<listcomp>c             S   s   g | ]}d qS )FrF   )r   r   rF   rF   rG   r   P  s    c                s   g | ]}t  |qS rF   )getattr)r   attr)valrF   rG   r   R  s    c                s    g | ]}t |tr |j qS rF   )r@   r   r   )r   r   )scanrF   rG   r   T  s    r   NTr   r   r   r   )alldictr   r   r   r   r   r@   r   re   r=   r   r5   r   )ovalotypsvalstypattrlistotypcpZ
used_typesatsindiceskwsr   r   Zusedr   )r   struct)r  rG   copy_valence_termsJ  s0    



z1Structure.__getitem__.<locals>.copy_valence_termsr   r   r   r   r   r   r   r   r   rN   r   r   r   r   r   r   )7r@   r1   re   _get_selection_arrayr   r   r   r4   r   r=   r5   r   r   r   r   r   r   rT   r   r   r   rg   ry   rh   rz   ri   r{   rj   r~   rk   r|   rl   r}   rm   r   rn   r   ro   r   rp   r   rq   r   rr   r   rs   rt   ru   r   rw   rv   rx   r   r   r   )r   r  sumselr   rN   r   Znumr-  rF   )r   r,  rG   __getitem__  s    -







 
$ 





zStructure.__getitem__c                s  ddl m} t|tr,|| |}| }nt|trvdd | jD }x&ttt	| j| D ]}d||< q^W |}nft|t
r*t	|dkr*t	|dkr|\}}t|trt|tr| j| | S d}nJt	|d	kr|\}	}}tt}
x| jD ]}|
|j | qW t|	trnt|trnt|trnt|
}
y|
|	 | | S  tk
rl   td
|	 Y nX t|	tr|	|
krt|	gndS n^t|	tr| jd jg}x,| jD ]"}|j|d kr||j qW t||	 nt|	xD ]}||
krP qW dS d}t|tr@tttt	| j| n,t|tsXt|trdt|gnt|t|trtttt	| j|  n,t|tst|trt|g nt| |rz<xt|
D ]\}}|  qW  fdd| jD }W d| j  X n fdd| jD }ndd | jD }t|}t	|t	| jkr~xt|D ]\}}|r`d||< q`W nZt	|t	| jkrtdn<yx|D ]}d||< qW W n tk
r   tdY nX |}dd |D S )a  
        Private method to convert a selection into an array -- common use for
        viewing and regular selection

        Parameters
        ----------
        selection : selector (slice, tuple, ... etc.)
            The selection given to the [] operator
        r   )r   c             S   s   g | ]}d qS )r   rF   )r   r   rF   rF   rG   r     s    z2Structure._get_selection_array.<locals>.<listcomp>r   )r\   r]   r\   Fr]   zNo chain %s in StructureNr   Tc                sP   g | ]H}|j jkoJ|j jks,|j jkoJ|j kpJ|j|j d  j  kqS )r   )r   r   rT   r   )r   r   )atomsetchainsetressetrF   rG   r     s   c                sD   g | ]<}|j  ks(|j|jd  j  ko>|jj kp>|jjkqS )r   )rT   r   r   )r   r   )r1  r3  rF   rG   r     s   c             S   s   g | ]}d qS )r   rF   )r   rN   rF   rF   rG   r     s    zSelection iterable is too longzSelected atom out of rangec             S   s   g | ]}t t|qS rF   )intbool)r   r   rF   rF   rG   r     s    )r   r   r@   r3   r   slicere   r   r4   r   tupler1   rf   r   r'   r   r=   r"  KeyError
IndexErrorr   r2   r   r   r   )r   r  r   maskr   r   ZresselZatomselZ	has_chainZchainselZchainmapr   Zchainsr   r   Z
chain_namer   r  rF   )r1  r2  r3  rG   r.    s    







 

zStructure._get_selection_arrayc             C   s   t | S )z
        Returns an indexable object that can be indexed like a standard
        Structure, but returns a *view* rather than a copy

        See Also
        --------
        Structure.__getitem__
        )_StructureViewerCreator)r   rF   rF   rG   view  s    
zStructure.viewc                sl  t |  dd | jD }t|}g }g }t }dd t|D }x"| jD ]}||jd  | qHW xt|D ] |  }tdd |D }	t|	dkr$|d j	}
t
dd |
D }t
d	d |
D }t
d
d |
D }t
dd |
D }|
jt|
||||f}||kr$|||    qpd}xt|D ]\}}t|jt|kr2xt|j|D ]\}}d|j	|j	fks~td|j	j|j	jkrP |j|jkrP d|j d|j krP d|j d|j krP d|j d|j kr\P q\W ||   d}P q2W |spt|	dkr(t|||< |  fdd| jD  }|| |t g qpW tt||S )a  
        Split the current Structure into separate Structure instances for each
        unique molecule. A molecule is defined as all atoms connected by a graph
        of covalent bonds.

        Returns
        -------
        [structs, counts] : list of (:class:`Structure`, list) tuples
            List of all molecules in the order that they appear first in the
            parent structure accompanied by the list of the molecule numbers
            in which that molecule appears in the Structure
        c             S   s   g | ]
}|j qS rF   )marked)r   rN   rF   rF   rG   r   2  s    z#Structure.split.<locals>.<listcomp>c             S   s   g | ]}g qS rF   rF   )r   r   rF   rF   rG   r   8  s    r   c             s   s   | ]}|j jV  qd S )N)r   r   )r   rN   rF   rF   rG   	<genexpr>=  s    z"Structure.split.<locals>.<genexpr>r   c             s   s   | ]}|j V  qd S )N)rT   )r   r   rF   rF   rG   r>  E  s    c             s   s   | ]}d |j  V  qdS )z%.6fN)charge)r   r   rF   rF   rG   r>  F  s    c             s   s   | ]}d |j  V  qdS )z%.6fN)rmin)r   r   rF   rF   rG   r>  G  s    c             s   s   | ]}d |j  V  qdS )z%.6fN)epsilon)r   r   rF   rF   rG   r>  H  s    FNzResidues must all be setz%.6fTc                s   g | ]}|j  d  kqS )r   )r=  )r   rN   )r   rF   rG   r   _  s    )r/   re   r  r"  r4   r=  r=   r   r   r   r7  rT   r   r   r5   AssertionErrorr?  r@  rA  r   )r   ZmollistZnmolZstructsZcountsZres_moleculesZmolatomsrN   r   Zinvolved_residuesr   namesZchargesZrminsZepsilonsZ
oneres_keyZis_duplicatejr,  a1a2ZmolrF   )r   rG   split$  s^    

     
zStructure.splitNc             K   s  ddl m}m}m}m} ddddddddd	d
ddddddd}	t|dsftj|rv|svt	d| n|dkrvt
dd}
x6| jD ],}t|jtr|jtk	rt|j|_qd}
qW z|dk	r| }nXtj|\}}|dkrtj|d }y|	| }W n" tk
r   td| Y nX |dkr<| j|f| nf|dkrX| j|f| nJ|dkrx|jj| |f| n*|dkr|j| }|j|f| n|d	kr|jj| |f| n|d
kr|jj| |f| n|dkr|jj| |fddi| n|dkr0|j| }|j|f| nr|dkrP|j j| |f| nR|dkrF| j!s| j"s| j#s| j$s| j%s| j&s| j'r|j(| }|j)|f| n| j*s| j+s| j,r|j-| }|j)|f| nby|j.| }W nB t/k
r4 } z"dt|kr"|j-| }n W dd}~X Y nX |j)|f| n\|dkr|j0f dt1| ji|}| j2|_2| j3|_4| j5|_5|j||dkd ntd| W d|
rx| jD ]}t6|j|_qW X dS )a  
        Saves the current Structure in the requested file format. Supported
        formats can be specified explicitly or determined by file-name
        extension. The following formats are supported, with the recognized
        suffix and ``format`` keyword shown in parentheses:

            - PDB (.pdb, pdb)
            - PDBx/mmCIF (.cif, cif)
            - PQR (.pqr, pqr)
            - Amber topology file (.prmtop/.parm7, amber)
            - CHARMM PSF file (.psf, psf)
            - CHARMM coordinate file (.crd, charmmcrd)
            - Gromacs topology file (.top, gromacs)
            - Gromacs GRO file (.gro, gro)
            - Mol2 file (.mol2, mol2)
            - Mol3 file (.mol3, mol3)
            - Amber ASCII restart (.rst7/.inpcrd/.restrt, rst7)
            - Amber NetCDF restart (.ncrst, ncrst)

        Parameters
        ----------
        fname : str or file-like object
            Name of the file or file-like object to save. If ``format`` is
            ``None`` (see below), the file type will be determined based on
            the filename extension. If ``fname`` is file-like object,  ``format``
            must be  provided. If the type cannot be determined, a ValueError is raised.
        format : str, optional
            The case-insensitive keyword specifying what type of file ``fname``
            should be saved as. If ``None`` (default), the file type will be
            determined from filename extension of ``fname``
        overwrite : bool, optional
            If True, allow the target file to be overwritten. Otherwise, an
            IOError is raised if the file exists. Default is False
        kwargs : keyword-arguments
            Remaining arguments are passed on to the file writing routines that
            are called by this function

        Raises
        ------
        ValueError if either filename extension or ``format`` are not recognized
        TypeError if the structure cannot be converted to the desired format for
        whatever reason
        IOError if the file cannot be written either because it exists and
        ``overwrite`` is ``False``, the filesystem is read-only, or write
        permissions are not granted for the user
        r   )ambercharmmformatsgromacsZPDBZPQRZCIFZAMBERZPSFZGROMACSZGROZMOL2ZMOL3Z	CHARMMCRDRST7NCRST)z.pdbz.pqrz.cifz.pdbxz.parm7z.prmtopz.psfz.topz.groz.mol2z.mol3z.crdz.rst7z.inpcrdz.restrtz.ncrstwritez%s exists; not overwritingNz7Must provide supported format if using file-like objectTF)z.bz2z.gzr   z#Could not determine file type of %sZmol3zCannot translate exceptions)rL  rM  r   )ZnetcdfzNo file type matching %s)7ZparmedrH  rI  rJ  rK  r   ospathexistsIOErrorRuntimeErrorre   r@   r   r1   	atom_typer*   struppersplitextr8  r   Z	write_pdbZ	write_cifZPQRFilerN  ZCharmmPsfFileZfrom_structureZ	write_psfZGromacsGroFileZMol2FileZGromacsTopologyFileZCharmmCrdFilern   ro   rr   rp   rq   rs   rt   Z
AmoebaParmZ
write_parmrk   rl   rm   ZChamberParmZ	AmberParmrA   ZRst7r   r  
velocitiesZvelsr   r4  )r   fnameformatZ	overwriter  rH  rI  rJ  rK  ZextmapZall_intsrN   baseZextr   eZrst7rF   rF   rG   savef  s    /












zStructure.savec             C   s  | j s
dS tdd | j D r"dS tdd | jD r:dS t }t }t }xt| jD ]\}}|j|jk r|j|j	|j
|jf}n|j|j
|j	|jf}||kr|| |j || qXt  ||< }||j || ||_qXW || _ x&t|D ]}| j|   | j|= qW dS )a5  
        Joins multi-term torsions into a single term and makes all of the
        parameters DihedralTypeList instances. If any dihedrals are *already*
        DihedralTypeList instances, or any are not parametrized, or there are no
        dihedral_types, this method returns without doing anything
        Nc             s   s   | ]}t |tV  qd S )N)r@   r   )r   r   rF   rF   rG   r>     s    z+Structure.join_dihedrals.<locals>.<genexpr>c             s   s   | ]}|j d kV  qd S )N)r   )r   r   rF   rF   rG   r>    s    )r{   anyri   r   r"  r'   r   r   r   r   r   r=   r   r   r  delete)r   Zdihedrals_to_deleteZdihedrals_processedZnew_dihedral_typesr   r   keyZdtlrF   rF   rG   join_dihedrals  s0    

zStructure.join_dihedralsc             C   s   | j S )N)r   )r   rF   rF   rG   r     s    zStructure.combining_rulec             C   s   |dkrt d|| _d S )N)rd   	geometricz/combining_rule must be 'lorentz' or 'geometric')r   r   )r   thingrF   rF   rG   r   !  s    c          	   C   sn  |   s&y| jS  tk
r"   Y q6X n|   |   t  | _}| }y| jd j	}d}d}W n t
k
rz   | jS X xt| jD ]\}}|j|k	r||jj	kr|jj	}| }|j}||jj|}ytjj|j}W n tk
 r   d}Y nX ||j|| qW t| }	x,| jD ]"}
||	|
jj |	|
jj  q$W | jdk	rj|tt| j  |S )a"  
        The OpenMM Topology object. Cached when possible, but any changes to the
        Structure instance results in the topology being deleted and rebuilt

        Notes
        -----
        This function calls ``prune_empty_terms`` if any topology lists have
        changed.
        r   N) r   Z	_topologyAttributeErrorr   r   r7   ZTopologyZaddChainrf   r   r9  r   re   r   Z
addResiduerT   elementZElementZgetByAtomicNumberrM   r8  ZaddAtomr   rg   addBondr   r   r   r   ZsetPeriodicBoxVectorsr9   r   )r   topr   Z
last_chainZlast_residueZlast_omm_residuer   rN   elemre   bondrF   rF   rG   topology)  sF    

"zStructure.topologyc             C   s0   ydd | j D tj S  tk
r*   dS X dS )a,  
        A list of 3-element Quantity tuples of dimension length representing the
        atomic positions for every atom in the system. If set with unitless
        numbers, those numbers are assumed to be in angstroms. If any atoms do
        not have coordinates, this is simply ``None``.
        c             S   s   g | ]}t |j|j|jqS rF   )r6   xxxyxz)r   r   rF   rF   rG   r   n  s    z'Structure.positions.<locals>.<listcomp>N)re   r:   r?   rd  )r   rF   rF   rG   	positionse  s    zStructure.positionsc             C   s   t |r|t j}t|t| jkrVxt| jD ]\}}|| \|_|_|_	q4W n\t|dt| j krxDt| jD ],\}}|d }|||d  \|_|_|_	qxW nt
ddS )a  
        A list of 3-element Quantity tuples of dimension length representing the
        atomic positions for every atom in the system. If set with unitless
        numbers, those numbers are assumed to be in angstroms.

        Raises
        ------
        ValueError if the positions are not either a (natom, 3)-shape iterable
        of iterables or a (natom*3)-length iterable.
        r]   zWrong shape for position arrayN)r:   r;   r>   r?   r   re   r   rk  rl  rm  r   )r   valuer   rN   Zi3rF   rF   rG   rn  r  s    
"c             C   s4   ydd | j D }W n tk
r(   d S X t|S )Nc             S   s   g | ]}|j |j|jgqS rF   )rk  rl  rm  )r   r   rF   rF   rG   r     s    z)Structure.coordinates.<locals>.<listcomp>)re   rd  r  r  )r   coordsrF   rF   rG   r    s
    zStructure.coordinatesc          	   C   s  |dkrFd| _ x| jD ]*}y|`|`|`W q tk
r>   Y qX qW nt|r\|tj	}t
|}tj|tjddd}|dt| jdf}t|dkrx,t| j|d D ]\}}|\|_|_|_qW || _ n>x6| jD ],}y|`|`|`W q tk
r   Y qX qW d| _ dS )z? Setting coordinates will also set xx, xy, and xz on the atoms NFT)dtyper   subokr   r]   r   )r   re   rk  rl  rm  rd  r:   r;   r>   r?   r   r  r  float64reshaper   r5   )r   ro  rN   rp  r   xyzrF   rF   rG   r    s,    

r!  c             C   s   ydd | j D }W n tk
r,   d}Y nX t|}| jdk	r|dkrRd| _n@|j| jjdd krpd| _n"t|| jd   tkrd| _|dkr| jdk	r| jS |dk	r|	dt
| j dfS dS | jdkr|dkr|dk	r|S td| j| S )	a  
        In some cases, multiple conformations may be stored in the Structure.
        This function retrieves a particular frame's coordinates

        Parameters
        ----------
        frame : int or 'all', optional
            The frame number whose coordinates should be retrieved. Default is
            'all'

        Returns
        -------
        coords : np.ndarray, shape([#,] natom, 3) or None
            If frame is 'all', all coordinates are returned with shape
            (#, natom, 3). Otherwise the requested frame is returned with shape
            (natom, 3). If no coordinates exist and 'all' is requested, None is
            returned

        Raises
        ------
        IndexError if there are fewer than ``frame`` coordinates
        c             S   s   g | ]}|j |j|jgqS rF   )rk  rl  rm  )r   r   rF   rF   rG   r     s    z-Structure.get_coordinates.<locals>.<listcomp>Nr   r   r!  r]   zNo coordinate frames present)re   rd  r  r  r   shaper   r  r
   rt  r   r9  )r   framerp  rF   rF   rG   get_coordinates  s.    




zStructure.get_coordinatesc             C   s   | j d krd S | j d S )Nr   )r   )r   rF   rF   rG   r     s    
zStructure.boxc             C   s   |d krd | _ nlt|tjr"|}ntt|}tj|tjddd}|jdkrpt	|jdksh|jd dkrpt
d|d	| _ d S )
NFT)rq  r   rr  )rH   r\   r   rH   z Box information must be 6 floats)r   rH   )r   r@   r  ZndarrayrC   r   r  rs  rv  r   r   rt  )r   ro  r   rF   rF   rG   r     s    
c             C   s:   | j dkr|dkrtddS |dkr,| j S | j | S dS )a  
        In some cases, multiple conformations may be stored in the Structure.
        This function retrieves a particular frame's unit cell (box) dimensions

        Parameters
        ----------
        frame : int or 'all', optional
            The frame number whose unit cell should be retrieved. Default is
            'all'

        Returns
        -------
        box : np.ndarray, shape([#,] 6) or None
            If frame is 'all', all unit cells are returned with shape
            (#, 6). Otherwise the requested frame is returned with shape
            (6,). If no unit cell exist and 'all' is requested, None is
            returned

        Raises
        ------
        IndexError if there are fewer than ``frame`` unit cell dimensions
        Nr!  zNo unit cell frames present)r   r9  )r   rw  rF   rF   rG   get_box  s    
zStructure.get_boxc             C   s0   yt dd | jD S  tk
r*   dS X dS )z
        A (natom, 3)-shape numpy array with atomic velocities for every atom in
        the system (in units of angstrom/picosecond), or None if there are no
        velocities
        c             S   s   g | ]}|j |j|jgqS rF   )vxvyvz)r   r   rF   rF   rG   r   $  s    z(Structure.velocities.<locals>.<listcomp>N)r  r  re   rd  )r   rF   rF   rG   rX    s    zStructure.velocitiesc          	   C   s   t |r|t jt j }|dkr\x| jD ]*}y|`|`|`W q, t	k
rT   Y q,X q,W nNt
j|dddt| jdf}x,t| j|d D ]\}}|\|_|_|_qW dS )z
        A list of 3-element Quantity tuples of dimension length representing the
        atomic velocities for every atom in the system
        NF)r   r   r]   r   )r:   r;   r>   r?   Zpicosecondsre   rz  r{  r|  rd  r  r  rt  r   r5   )r   ro  rN   ru  rF   rF   rG   rX  (  s    
 c             C   sh   t  }x*| jD ] }|jtkrq|j|t|j< qW x0t|D ]$\}}x|jD ]}||krLdS qLW q<W dS )a  
        Returns whether or not any pairs of atom types have their LJ
        interactions modified by an NBFIX definition

        Returns
        -------
        has_nbfix : bool
            If True, at least two atom types have NBFIX mod definitions
        TF)r"  re   rT  r*   rU  r2   nbfix)r   Ztypemapr   r`  r   rF   rF   rG   	has_NBFIX=  s    

 zStructure.has_NBFIXc             C   s   | j dkrdS t| j S )zo
        3, 3-element tuple of unit cell vectors that are Quantity objects of
        dimension length
        N)r   r   r   )r   rF   rF   rG   box_vectorsV  s    
 zStructure.box_vectorsc             C   s   t | \\}}}\}}}|tj}|tj}|tj}|tj}|tj}|tj}tj||||||ggtjd| _dS )zo
        3, 3-element tuple of unit cell vectors that are Quantity objects of
        dimension length
        )rq  N)	r   r>   r:   r?   Zdegreesr  r  rs  r   )r   ro  r   r   r   ABGrF   rF   rG   r  _  s    g       @g        Tgfffffr@g      ?g     S@gMb@?c             C   s   | j rtd|dkrtj}t }|tjtjtjfkrJ| j	dkrJt
ddd | jD }|dk	rt|rx|tj}|dkrt
dxf| jD ]\}|jdkrd}x|jD ]}|jdkr|}P qW |dk	r|||j< ||j  ||j 8  < qW x|D ]}|| qW | ||| |  r0|   |   td	 | || ||| td
 | || || td | || | td | ||   td | ||    td | || !  td | || "  td | || #  td | || $  td | || %  td | || &  td | || '  td |dk	rd}nd}| || (||||| |dk	rtd | || )||||
||||	|	 |r|*t+  | j	dk	r|j,t-| j.  | /| |S )a$  
        Construct an OpenMM System representing the topology described by the
        prmtop file.

        Parameters
        ----------
        nonbondedMethod : cutoff method
            This is the cutoff method. It can be either the NoCutoff,
            CutoffNonPeriodic, CutoffPeriodic, PME, or Ewald objects from the
            simtk.openmm.app namespace
        nonbondedCutoff : float or distance Quantity
            The nonbonded cutoff must be either a floating point number
            (interpreted as nanometers) or a Quantity with attached units. This
            is ignored if nonbondedMethod is NoCutoff.
        switchDistance : float or distance Quantity
            The distance at which the switching function is turned on for van
            der Waals interactions. This is ignored when no cutoff is used, and
            no switch is used if switchDistance is 0, negative, or greater than
            the cutoff
        constraints : None, app.HBonds, app.HAngles, or app.AllBonds
            Which type of constraints to add to the system (e.g., SHAKE). None
            means no bonds are constrained. HBonds means bonds with hydrogen are
            constrained
        rigidWater : bool=True
            If True, water is kept rigid regardless of the value of constraints.
            A value of False is ignored if constraints is not None.
        implicitSolvent : None, app.HCT, app.OBC1, app.OBC2, app.GBn, app.GBn2
            The Generalized Born implicit solvent model to use.
        implicitSolventKappa : float or 1/distance Quantity = None
            This is the Debye kappa property related to modeling saltwater
            conditions in GB. It should have units of 1/distance (1/nanometers
            is assumed if no units present). A value of None means that kappa
            will be calculated from implicitSolventSaltConc (below)
        implicitSolventSaltConc : float or amount/volume Quantity=0 moles/liter
            If implicitSolventKappa is None, the kappa will be computed from the
            salt concentration. It should have units compatible with mol/L
        temperature : float or temperature Quantity = 298.15 kelvin
            This is only used to compute kappa from implicitSolventSaltConc
        soluteDielectric : float=1.0
            The dielectric constant of the protein interior used in GB
        solventDielectric : float=78.5
            The dielectric constant of the water used in GB
        useSASA : bool=False
            If True, use the ACE non-polar solvation model. Otherwise, use no
            SASA-based nonpolar solvation model.
        removeCMMotion : bool=True
            If True, the center-of-mass motion will be removed periodically
            during the simulation. If False, it will not.
        hydrogenMass : float or mass quantity = None
            If not None, hydrogen masses will be changed to this mass and the
            difference subtracted from the attached heavy atom (hydrogen mass
            repartitioning)
        ewaldErrorTolerance : float=0.0005
            When using PME or Ewald, the Ewald parameters will be calculated
            from this value
        flexibleConstraints : bool=True
            If False, the energies and forces from the constrained degrees of
            freedom will NOT be computed. If True, they will (but those degrees
            of freedom will *still* be constrained).
        verbose : bool=False
            If True, the progress of this subroutine will be printed to stdout
        splitDihedrals : bool=False
            If True, the dihedrals will be split into two forces -- proper and
            impropers. This is primarily useful for debugging torsion parameter
            assignments.

        Notes
        -----
        This function calls prune_empty_terms if any Topology lists have changed
        z'Cannot createSystem: unknown functionalNz(No periodic boundary conditions detectedc             S   s   g | ]
}|j qS rF   )mass)r   rN   rF   rF   rG   r     s    z*Structure.createSystem.<locals>.<listcomp>r   zHydrogen mass must be positiver   zAdding bonds...zAdding angles...zAdding dihedrals...z%Adding Ryckaert-Bellemans torsions...zAdding Urey-Bradleys...zAdding improper torsions...zAdding CMAP torsions...zAdding trigonal angle terms...zAdding out-of-plane bends...zAdding pi-torsions...zAdding stretch-bends...zAdding torsion-torsions...zAdding Nonbonded force...g      ?g     S@zAdding GB force...)0r   r   r7   NoCutoffmmZSystemCutoffPeriodicPMEEwaldr   r   re   r:   r;   r>   Zdaltonre  rQ   r   r  addParticleomm_add_constraintsr   r   r   r  info_add_force_to_systemomm_bond_forceomm_angle_forceomm_dihedral_forceomm_rb_torsion_forceomm_urey_bradley_forceomm_improper_forceomm_cmap_forceomm_trigonal_angle_forceomm_out_of_plane_bend_forceomm_pi_torsion_forceomm_stretch_bend_forceomm_torsion_torsion_forceomm_nonbonded_forceomm_gbsa_forceaddForceZCMMotionRemoverZsetDefaultPeriodicBoxVectorsr9   r  omm_set_virtual_sites)r   nonbondedMethodnonbondedCutoffswitchDistanceconstraints
rigidWaterimplicitSolventimplicitSolventKappaimplicitSolventSaltConctemperaturesoluteDielectricsolventDielectricuseSASAZremoveCMMotionZhydrogenMassewaldErrorToleranceflexibleConstraintsverboseZsplitDihedralssystemZmassesrN   Z
heavy_atomrF  r  Zrf_dielcrF   rF   rG   createSystemp  s    Y





 




















zStructure.createSystemc             C   s  |dkr|sdS |dt jt jt jfkr2td| tjtj}t	 }t	 }t
| }|t jksh|t jkrx| jD ]:}t|jtrqpt|jtrqp|t|jj|jjf qpW nj|t jkrx\| jD ]R}t|jtrqt|jtrq|jjdks|jjdkr|t|jj|jjf qW |rx^| jD ]T}t|jtr>q(t|jtrPq(||jjj r(|t|jj|jjf q(W xH| jD ]>}t|jj|jjf|kr||jj|jj|jj|  qW |t jkrVx~| jD ]t}	d}
|	jjdkr|
d7 }
|	jjdkr|
d7 }
|
dks4|
dkr|	jjdkr||	jj|	jj|	jjf qW |rx<| jD ]2}	||	jjj rd||	jj|	jj|	jjf qdW x| jD ]}	|	jj|	jj|	jjf|krt|	jj|	jjf|krqd }}xX|	jjD ]L}||	kr|	j|kr|jj| }n"||	kr|	j|kr|jj| }qW |dks|dkr^qt|	jjt }t|| ||  d| | |  }||	jj|	jj| qW dS )a   Adds constraints to a given system

        Parameters
        ----------
        system : mm.System
            The OpenMM system for which constraints should be added
        constraints : None, app.HBonds, app.AllBonds, or app.HAngles
            Which kind of constraints should be used
        rigidWater : bool
            If True, water bonds are constrained regardless of whether
            constrains is None
        Nz$Unrecognized constraints option (%s)r   r   r\   rP   )r7   HBondsAllBondsHAnglesr   r:   angstromconversion_factor_to	nanometerr   _settlerrg   r@   r   r   r   r   	frozensetr   re  r   ZaddConstraintr   reqrh   r   r  Zcostheteqr	   r  )r   r  r  r  length_convZconstraint_bond_setZconstraint_angle_setis_waterri  angleZnumHl1l2Zcostr   rF   rF   rG   r    s             $"

 &zStructure.omm_add_constraintsc             C   s  |  t| jkrtdx| jD ]}t|ts2q"|j}| }| }t|t	r|\}}|\}}	|
|jt|j|j||	 q"t|tr|\}}}
|\}}	}|
|jt|j|j|
j||	| q"t|tr"|\}}}
|\}}	}|
|jt|j|j|
j||	| q"W dS )an  
        Sets the virtual sites in a given OpenMM `System` object from the extra
        points defined in this system

        Parameters
        ----------
        system : mm.System
            The system for which the virtual sites will be set. All particles
            must have already been added to this System before calling this
            method
        z.OpenMM System does not correspond to StructureN)getNumParticlesr   re   r   r@   r   Z
frame_typeZget_weightsZ	get_atomsr)   ZsetVirtualSiter   r  ZTwoParticleAverageSiter%   ZThreeParticleAverageSiter!   ZOutOfPlaneSite)r   r  rN   r   ZweightsZrefatomsrE  rF  Zw1Zw2Za3Zw3rF   rF   rG   r  t  s,    

 


"


zStructure.omm_set_virtual_sitesc             C   s  |s|t jt jfks| jsdS tjtj}tjtj	d  }tj
tjd  }||}t| jdrt| jdrt }|| jjd |  || jjd |d   nt }|| j |rt| }	ndd | jD }	x| jD ]}
d	|
jj|
jjfkr|s|t jkrq|s(|	|
jjj r(q|
jdkr<td
| |
jj|
jj|
jj!| d|
jj" |  qW |# dkr~dS |S )aM  
        Creates an OpenMM Bond Force object (or AmoebaBondForce if the bonds are
        for an Amoeba-parametrized system)

        Parameters
        ----------
        constraints : None, app.HBonds, app.AllBonds, or app.HAngles
            The types of constraints that are on the system. If
            flexibleConstraints is False, then the constrained bonds will not be
            added to the resulting Force
        rigidWater : bool=True
            Should water-H bonds be constrained regardless of `constraints`?
        flexibleConstraints : bool=True
            If True, all bonds are added to the force regardless of
            `constraints`

        Returns
        -------
        force
            HarmonicBondForce (or AmoebaBondForce if this is an Amoeba system),
            or None if there are no bonds to add
        Nr\   r<   coeffsr]   r^   c             S   s   g | ]}d qS )FrF   )r   r   rF   rF   rG   r     s    z,Structure.omm_bond_force.<locals>.<listcomp>r   z Cannot find necessary parametersr   )$r7   r  r  rg   r:   r?   r  
nanometerskilocalorie_per_moler  kilojoule_per_moler  r   ry   r  ZAmoebaBondForceZsetAmoebaGlobalBondCubicr  ZsetAmoebaGlobalBondQuarticHarmonicBondForcesetForceGroupBOND_FORCE_GROUPr  rf   r   re  r   r  r   r   r   r   rf  r  kZgetNumBonds)r   r  r  r  r  _ambfrc_ommfrcfrc_convforcer  ri  rF   rF   rG   r    s:    


zStructure.omm_bond_forcec          	   C   s<  | j s
dS tjtj}t| jdrzt| jdrz| jj}t	 }|
|d  ||d  ||d  ||d  nt }|| j x| j D ]}|jjdk|jjdk }|tjkr|d	ks|dkr|jjd
kr|sq|jdkrtd||jj|jj|jj|jjt d	|jj |  qW | dkr8dS |S )a  
        Creates an OpenMM HarmonicAngleForce object (or AmoebaAngleForce if the
        angles are for an Amoeba-parametrized system)

        Parameters
        ----------
        constraints : None, app.HBonds, app.AllBonds, or app.HAngles
            The types of constraints that are on the system. If
            flexibleConstraints is False, then the constrained bonds will not be
            added to the resulting Force
        flexibleConstraints : bool=True
            If True, all bonds are added to the force regardless of
            `constraints`

        Returns
        -------
        force
            HarmonicAngleForce (or AmoebaAngleForce if this is an Amoeba
            system), or None if there are no angles to add
        Nr<   r  r]   r^   r_   rH   r   r\   rP   zCannot find angle parametersr   )rh   r:   kilocaloriesr  
kilojoulesr   rz   r  r  ZAmoebaAngleForceZsetAmoebaGlobalAngleCubicZsetAmoebaGlobalAngleQuarticZsetAmoebaGlobalAnglePenticZsetAmoebaGlobalAngleSexticZHarmonicAngleForcer  ANGLE_FORCE_GROUPr   re  r   r7   r  r   r   r   addAngler   r  r	   r  ZgetNumAngles)r   r  r  r  r   r  r  Znum_hrF   rF   rG   r    s2     
 zStructure.omm_angle_forcec             C   s6  | j s
dS tjtj}t }t }|| j || j	 x| j D ]}|j
dkr^td|rn|jrn|}n|}t|j
trx|j
D ]<}||jj|jj|jj|jjt|j|jt |j|  qW qH||jj|jj|jj|jjt|j
j|j
jt |j
j|  qHW | dkr|S | dkr.|S ||fS )a-   Creates the OpenMM PeriodicTorsionForce modeling dihedrals

        Parameters
        ----------
        split : bool, optional, default=False
            If True, separate PeriodicTorsionForce instances with the propers in
            the first and impropers in the second return item. If no impropers
            or propers are present, the instances with zero terms are not
            returned.

        Returns
        -------
        PeriodicTorsionForce[, PeriodicTorsionForce]
            Or None if no torsions are present in this system
        NzCannot find torsion parametersr   )ri   r:   r  r  r  r  ZPeriodicTorsionForcer  DIHEDRAL_FORCE_GROUPIMPROPER_FORCE_GROUPr   r   r   r@   r   
addTorsionr   r   r   r   r   r4  r   Zphaser	   phi_kZgetNumTorsions)r   rG  r  Zproperr   torr  r   rF   rF   rG   r  	  s2     

"zStructure.omm_dihedral_forcec             C   s   | j s
dS tjtj}t }|| j x|| j D ]r}|j	dkrJt
d||jj|jj|jj|jj|j	j| |j	j| |j	j| |j	j| |j	j| |j	j| 
 q4W |S )z Creates the OpenMM RBTorsionForce for Ryckaert-Bellemans torsions

        Returns
        -------
        RBTorsionForce
            Or None if no torsions are present in this system
        Nz"Cannot find R-B torsion parameters)rj   r:   r  r  r  r  ZRBTorsionForcer  RB_TORSION_FORCE_GROUPr   r   r  r   r   r   r   r   Zc0c1c2Zc3Zc4Zc5)r   Zconvr  r  rF   rF   rG   r  =	  s    	 
&zStructure.omm_rb_torsion_forcec             C   s   | j s
dS tjtj}tjtjd  }tjtjd  }||}t	
 }|| j xL| j D ]B}|jdkrttd||jj|jj|jj| d|jj |  q^W |S )z Creates the OpenMM Urey-Bradley force

        Returns
        -------
        HarmonicBondForce
            Or None, if no urey-bradleys are present
        Nr\   z#Cannot find urey-bradley parameters)rk   r:   r?   r  r  r  r  r  r  r  r  r  UREY_BRADLEY_FORCE_GROUPr   r   rf  r   r   r   r  r  )r   r  r  r  r  r  ZureyrF   rF   rG   r  T	  s    	 

z Structure.omm_urey_bradley_forcec          
   C   s   | j s
dS tjtj}d}|d7 }|d7 }|dtj 7 }t|}|	d |	d |
| j xV| j D ]L}|jdkrtd||jj|jj|jj|jj|jj| |jjt f qlW |S )	z Creates the OpenMM improper torsion force (quadratic bias)

        Returns
        -------
        CustomTorsionForce
            With the formula k*(phi-phi0)^2, or None if there are no impropers
        Nzk*dtheta_torus^2;z8dtheta_torus = dtheta - floor(dtheta/(2*pi)+0.5)*(2*pi);zdtheta = theta - theta0;zpi = %f;r  Ztheta0z'Cannot find improper torsion parameters)rl   r:   r  r  r  r  pir  ZCustomTorsionForceZaddPerTorsionParameterr  r  r   r   r  r   r   r   r   r   Zpsi_kZpsi_eqr	   )r   r  Zenergy_functionr  imprF   rF   rG   r  m	  s$    	 



zStructure.omm_improper_forcec                s  | j s
dS tjtj t }|| j g }t	 }xv| j D ]l}|j
dkrTtdt|j
|kr>|j
}|t| |j j}||j fdd|D }||t|< q>W xR| j D ]H}||t|j
 |jj|jj|jj|jj|jj|jj|jj|jj	 qW |S )z Creates the OpenMM CMAP torsion force

        Returns
        -------
        CMAPTorsionForce
            Or None, if no CMAP terms are present
        Nz#Cannot find CMAP torsion parametersc                s   g | ]}|  qS rF   rF   )r   r   )r  rF   rG   r   	  s    z,Structure.omm_cmap_force.<locals>.<listcomp>)rm   r:   r  r  r  r  ZCMAPTorsionForcer  CMAP_FORCE_GROUPr"  r   r   idr=   gridZswitch_rangeTZaddMap
resolutionr  r   r   r   r   r   r   )r   r  Zcmap_type_listZcmap_mapcmapr   r  r   rF   )r  rG   r  	  s*    	 
zStructure.omm_cmap_forcec                s"  | j s
dS tjtj}tjtj}t 	| j
 t|rP|tj}|dksb|tjkrrtjj n|tjkrtjj | n|tjkrtjj | nj|tjkrtjj | | n<|tjkrtjj | | ntd| | |d d }x0| j D ]&}	|	j|	j| t|	j|  qBW  fdd x | j D ]}	 |	|	d| j qW d| }| jdkrd	d
 }
n| jdkrdd
 }
| j sؐx| j!| j" D ]}|j#rqt$|j%t&r|d }}d}xJ|dks(|dkr\|t'|j%k r\|j%| j(}|j%| j)}|d7 }qW |dksr|dkrtdn|j%j(}|j%j)}y"|j*j+j,t-|j.j+ \}}}}W nZ t/t0fk
r   t|j*j1|j.j1 }t23|| | }|
|j*j4|j.j4}||9 }Y nX || | }|| | }|j*j|j.j | }5|j*j6|j.j6|||d xz|j*j7D ]n}t|j1|j.j1 }t23|| | }|
|j4|j.j4}||9 }|j|j.j | }5|j6|j.j6|||d q\W xz|j.j7D ]n}t|j1|j*j1 }t23|| | }|
|j4|j*j4}||9 }|j|j*j | }5|j6|j*j6|||d qW x|j*j7D ]z}xr|j8j7D ]f}t|j1|j1 }t23|| | }|
|j4|j4}||9 }|j|j | }5|j6|j6|||d qbW qTW qW xT| j D ]J}|j*j|j8j |j%j9 }5|j*j6|j8j6||j%j| |j%j| d qW x:| j D ]0}	x(|	j:D ]}5|	j6|j6dddd qBW q6W |r|tjk	rt|r|tj}d|  k r|k rn n;d <| | jdkr| = r| >|| ?|fS | ?|fS | = r| >|fS S )a   Creates the OpenMM NonbondedForce instance

        Parameters
        ----------
        nonbondedMethod : cutoff method
            This is the cutoff method. It can be either the NoCutoff,
            CutoffNonPeriodic, CutoffPeriodic, PME, or Ewald objects from the
            simtk.openmm.app namespace
        nonbondedCutoff : float or distance Quantity
            The nonbonded cutoff must be either a floating point number
            (interpreted as nanometers) or a Quantity with attached units. This
            is ignored if nonbondedMethod is NoCutoff.
        switchDistance : float or distance Quantity
            The distance at which the switching function is turned on for van
            der Waals interactions. This is ignored when no cutoff is used, and
            no switch is used if switchDistance is 0, negative, or greater than
            the cutoff
        ewaldErrorTolerance : float=0.0005
            When using PME or Ewald, the Ewald parameters will be calculated
            from this value
        reactionFieldDielectric : float=78.5
            If the nonbondedMethod is CutoffPeriodic or CutoffNonPeriodic, the
            region beyond the cutoff is treated using a reaction field method
            with this dielectric constant. It should be set to 1 if another
            implicit solvent model is being used (e.g., GB)

        Returns
        -------
        NonbondedForce
            This just implements the very basic NonbondedForce with the typical
            charge-charge and 12-6 Lennard-Jones interactions with the
            Lorentz-Berthelot combining rules.

        Notes
        -----
        Subclasses of Structure for which this nonbonded treatment is inadequate
        should override this method to implement what is needed.

        If nrexcl is set to 3 and no exception parameters are stored in the
        adjusts list, the 1-4 interactions are determined from the list of
        dihedrals
        Nz!Unrecognized nonbondedMethod (%s)r\   g)N>?c                s   ||krd S x|j D ]}|| kr"q|| k	rB| j|jdddd x&| jD ]}|j|jdddd qJW x&|jD ]}|j| jdddd qrW x6| jD ],}x&|jD ]}|j|jdddd qW qW  | ||d | qW d S )Ng        g      ?Tr   )rQ   addExceptionr   children)originrN   levelendr  childZchild2)
exclude_tor  rF   rG   r  	  s       z1Structure.omm_nonbonded_force.<locals>.exclude_tor   rd   c             S   s   d| |  S )Ng      ?rF   )sig1sig2rF   rF   rG   <lambda>
      z/Structure.omm_nonbonded_force.<locals>.<lambda>rb  c             S   s   t | | S )N)r  r  )r  r  rF   rF   rG   r  
  r  r   zADetected scaling constants of 0 for dihedral containing 1-4 info!Tg        g      ?)@re   r:   r  r  r  r  r  r  ZNonbondedForcer  NONBONDED_FORCE_GROUPr;   r>   r  r7   r  setNonbondedMethodCutoffNonPeriodicsetCutoffDistancer  r  ZsetEwaldErrorTolerancer  r   ZsetReactionFieldDielectricr  r?  sigmar   rA  r   r   ru   ri   rj   r   r@   r   r   r   sceescnbr   rT  r}  rU  r   r8  rd  Z
epsilon_14r  r  Zsigma_14r  r   r  r   ZchgscaleZexclusion_partnerssetUseSwitchingFunctionsetSwitchingDistancer~  _omm_nbfixed_force_omm_geometric_force)r   r  r  r  r  ZreactionFieldDielectricr  ene_convZsigma_scalerN   Zcomb_sigZdihr  r  r   rijwdijrij14wdij14ZepsprodZsigprodZchgprodr  r  r  ZpairrF  rF   )r  r  rG   r  	  s    . 






&
 &
"  *$



zStructure.omm_nonbonded_forcec       !   
   C   s  t jt j}t jt j}dd | jD }g g  }}d}g }	xt| jD ]\}
}|j}||
 rbqJ|d7 }|||
< |j	t
|jf}|	| ||j	 |t
|j xnt|
d t| jD ]V}| j| j}|| dkrq||kr|||< q|js|j	t
|jf}||kr|||< qW qJW dd t|| D }|dd }xt|D ]}
xt|D ]}|	| j}y|	|
 j| \}}}}W nD tk
r   ||
 ||  | }t||
 ||  | }Y nX ||9 }||9 }|d }t|| ||
||  < d| | ||
||  < qVW qHW td	}|d
t||| |dt||| |d || j |tjks|tjks|tjkr|tjj nD|tj kr|tjj  n(|tj!kr|tjj! nt"d| x|D ]}
|#|
d f qW x6t|$ D ]&}
|%|
\}}}|&|
|dd qW x6t|' D ]&}|(|\}
}}}} |)|
| qDW |*d |tj kr|tjj  nN|tj!kr|tjj! n2|tjtjtjfkr|tjj nt"d| |+|,  |- r|.d |/|0  |S )a   Private method for creating a CustomNonbondedForce with a lookup
        table. This should not be called by users -- you have been warned.

        Parameters
        ----------
        nonbfrc : NonbondedForce
            NonbondedForce for the "standard" nonbonded interactions. This will
            be modified (specifically, L-J ixns will be zeroed)
        nonbondedMethod : Nonbonded Method (e.g., NoCutoff, PME, etc.)
            The nonbonded method to apply here. Ewald and PME will be
            interpreted as CutoffPeriodic for the CustomNonbondedForce.

        Returns
        -------
        force : CustomNonbondedForce
            The L-J force with NBFIX implemented as a lookup table
        c             S   s   g | ]}d qS )r   rF   )r   rN   rF   rF   rG   r   
  s    z0Structure._omm_nbfixed_force.<locals>.<listcomp>r   r   c             S   s   g | ]}d qS )r   rF   )r   r   rF   rF   rG   r   
  s    NrH   r\   zP(a/r6)^2-b/r6; r6=r2*r2*r2; r2=r^2; a=acoef(type1, type2); b=bcoef(type1, type2)acoefbcoefr   z"Unrecognized nonbonded method [%s]g      ?g        TzUnsupported nonbonded method %s)1r:   r?   r  r  r  r  re   r   rT  r@  r   rA  r=   r4   r   r}  rT   r8  r  r  r  CustomNonbondedForceZaddTabulatedFunctionZDiscrete2DFunctionaddPerParticleParameterr  r  r7   r  r  r  r  r  r  rB  r  r  getParticleParameterssetParticleParametersgetNumExceptionsgetExceptionParametersaddExclusionsetUseLongRangeCorrectionr  getCutoffDistancegetUseSwitchingFunctionr  r  getSwitchingDistance)!r   nonbfrcr  r  r  Zlj_idx_listZlj_radiiZ	lj_depthsZnum_lj_typesZlj_type_listr   rN   ZatypeZljtyperD  Zatype2Zljtype2r  r  Znamejr  r  r  r  Zrij6r  chgsigepsiiqqsseerF   rF   rG   r  m
  s    
 
 

 $





zStructure._omm_nbfixed_forcec             C   s  t jt j}t jt j}td}|d |d |	| j
 |tjksd|tjksd|tjkrt|tjj n@|tjkr|tjj n&|tjkr|tjj ntd| x@| jD ]6}t|j| d }t|j| }|||f qW x6t| D ]&}	||	\}
}}||	|
dd qW x6t| D ]&}||\}	}}}}||	| q<W | d |tjkr|tjj nN|tjkr|tjj n2|tjtjtjfkr|tjj ntd	| |!|"  |# r
|$d |%|&  |S )
a   Private method for creating a CustomNonbondedForce with a lookup
        table. This should not be called by users -- you have been warned.

        Parameters
        ----------
        nonbfrc : NonbondedForce
            NonbondedForce for the "standard" nonbonded interactions. This will
            be modified (specifically, L-J ixns will be zeroed)
        nonbondedMethod : Nonbonded Method (e.g., NoCutoff, PME, etc.)
            The nonbonded method to apply here. Ewald and PME will be
            interpreted as CutoffPeriodic for the CustomNonbondedForce.

        Returns
        -------
        force : CustomNonbondedForce
            The L-J force with NBFIX implemented as a lookup table
        z`epsilon1*epsilon2*(sigr6^2-sigr6); sigr6=sigr2*sigr2*sigr2; sigr2=(sigc/r)^2; sigc=sigma1*sigma2rA  r  z"Unrecognized nonbonded method [%s]r\   g      ?g        TzUnsupported nonbonded method %s)'r:   r?   r  r  r  r  r  r  r  r  r  r7   r  r  r  r  r  r  rB  re   r  r  rA  r  r  r4   r  r  r  r   r  r  r  r  r  r  r  r  r  )r   r  r  r  r  r  rN   r
  r	  r   r  r  rD  r  r  r  rF   rF   rG   r  
  sJ    








zStructure._omm_geometric_forceg      >@c
             C   s  ddl m}
m}m}m}m} yddl m} W n tk
rH   dd }Y nX |dkrVdS |	r`d}nd}|dkrrtj	}|tj
tjtjtjtjfkrtd|| |t|}|dkr
t|r|tjtj }|}t|r|tj}d	t|| |  }|d
9 }nt|r&|tjd }|tj	kr8d}nt|rR|tj}n|}|tj
krv|
|||||d}n|tjkr||||||d}nh|tjkr||||||d}nH|tjkr||||||d}n(|tjkr||||||d}ntdx0t| j|D ] \}}||j gt!|  qW y|"  W n t#k
rR   Y nX |tj	krp|$t%j&j	 n>|tj'kr|$t%j&j' |(| n|$t%j&j) |(| |*| j+ |S )a  
        Creates a Generalized Born force for running implicit solvent
        calculations

        Parameters
        ----------
        implicitSolvent : app.HCT, app.OBC1, app.OBC2, app.GBn, app.GBn2
            The Generalized Born implicit solvent model to use.
        nonbondedMethod : cutoff method
            This is the cutoff method. It can be either the NoCutoff,
            CutoffNonPeriodic, CutoffPeriodic, PME, or Ewald objects from the
            simtk.openmm.app namespace. Default is NoCutoff
        nonbondedCutoff : float or distance Quantity
            The nonbonded cutoff must be either a floating opint number
            (interpreted as nanometers) or a Quantity with attached units. This
            is ignored if nonbondedMethod is NoCutoff
        implicitSolventKappa : float or 1/distance Quantity = None
            This is the Debye kappa property related to modeling saltwater
            conditions in GB. It should have units of 1/distance (1/nanometers
            is assumed if no units present). A value of None means that kappa
            will be calculated from implicitSolventSaltConc (below)
        implicitSolventSaltConc : float or amount/volume Quantity=0 moles/liter
            If implicitSolventKappa is None, the kappa will be computed from the
            salt concentration. It should have units compatible with mol/L
        temperature : float or temperature Quantity = 298.15 kelvin
            This is only used to compute kappa from implicitSolventSaltConc
        soluteDielectric : float=1.0
            The dielectric constant of the protein interior used in GB
        solventDielectric : float=78.5
            The dielectric constant of the water used in GB
        r   )GBSAHCTForceGBSAOBC1ForceGBSAOBC2ForceGBSAGBnForceGBSAGBn2Force)convertParametersc             S   s   | S )NrF   )ZparamsZchoicerF   rF   rG   r  M  r  z*Structure.omm_gbsa_force.<locals>.<lambda>NZACEz#Unrecognized implicit solvent modelgX2ı*I@g333333@r   )Zkappaz7Unexpected implicit solvent model... should not be here),Z(simtk.openmm.app.internal.customgbforcesr  r  r  r  r  r  ImportErrorr7   r  ZHCTrX   rY   GBnGBn2r   _get_gb_parametersrU  r:   r;   r>   molesliterkelvinr  r  r  r  rB  r5   re   r  r?  r   finalizerd  r  r  ZCustomGBForcer  r  r  r  r  )r   r  r  r  r  r  r  r  r  r  r  r  r  r  r  r  ZsasaZgb_parmsZsccutoffr  rN   ZparmsrF   rF   rG   r    s~    ) 





zStructure.omm_gbsa_forcec          
   C   s   | j s
dS tjtj}t| jdr0t| jds8tdt	 }| jj
}||d  ||d  ||d  ||d  || j xP| j D ]F}|jdkrtd	||jj|jj|jj|jj|jj|jj|  qW |S )
z Creates the Amoeba trigonal-angle force

        Returns
        -------
        AmoebaInPlaneAngleForce
            The trigonal in-plane Angle force
        Nr<   r  z5Do not have the trigonal angle force table parametersr]   r^   r_   rH   z!Missing trigonal angle parameters)rn   r:   r  r  r  r   r   r   r  ZAmoebaInPlaneAngleForcer  Z setAmoebaGlobalInPlaneAngleCubicZ"setAmoebaGlobalInPlaneAngleQuarticZ!setAmoebaGlobalInPlaneAnglePenticZ!setAmoebaGlobalInPlaneAngleSexticr  TRIGONAL_ANGLE_FORCE_GROUPr   r  r   r   r   r   r   r  r  )r   r  r  r   angrF   rF   rG   r    s&    	 
z"Structure.omm_trigonal_angle_forcec          	   C   s   | j s
dS tjtj}t| jdr0t| jds8tdt	 }| jj
}||d  ||d  ||d  ||d  || j xN| j D ]D}|jdkrtd	||jj|jj|jj|jjd
|jj |  qW |S )z Creates the Amoeba out-of-plane bend force

        Returns
        -------
        AmoebaOutOfPlaneBendForce
            The out-of-plane bend Angle force
        Nr<   r  z5Do not have the trigonal angle force table parametersr]   r^   r_   rH   z$Missing out-of-plane bend parametersr\   )ro   r:   r  r  r  r   r   r   r  ZAmoebaOutOfPlaneBendForcer  Z"setAmoebaGlobalOutOfPlaneBendCubicZ$setAmoebaGlobalOutOfPlaneBendQuarticZ#setAmoebaGlobalOutOfPlaneBendPenticZ#setAmoebaGlobalOutOfPlaneBendSexticr  OUT_OF_PLANE_BEND_FORCE_GROUPr   ZaddOutOfPlaneBendr   r   r   r   r   r  )r   r  r  r   r  rF   rF   rG   r    s&    	 
z%Structure.omm_out_of_plane_bend_forcec             C   s   | j s
dS tjtj}t }|| j xV| j D ]L}|j	dkrJt
d||jj|jj|jj|jj|jj|jj|j	j|  q4W |S )z Creates the Amoeba pi-torsion force

        Returns
        -------
        AmoebaPiTorsionForce
            The pi-torsion force
        NzMissing pi-torsion parameters)rp   r:   r  r  r  r  ZAmoebaPiTorsionForcer  PI_TORSION_FORCE_GROUPr   r   ZaddPiTorsionr   r   r   r   r   r   r   r  )r   r  r  r  rF   rF   rG   r    s    	 
zStructure.omm_pi_torsion_forcec             C   s   | j s
dS tjd d }tjtj}t }|	| j
 xr| j D ]h}|jdkrXtd||jj|jj|jj|jj| |jj| |jjtj d |jj| |jj|  qBW |S )z Create the OpenMM Amoeba stretch-bend force for this system

        Returns
        -------
        AmoebaStretchBendForce
            The stretch-bend force containing all terms in this system
        N   gQD@zMissing stretch-bend parameters)rq   r  r  r:   r?   r  r  r  ZAmoebaStretchBendForcer  STRETCH_BEND_FORCE_GROUPr   r   ZaddStretchBendr   r   r   r   Zreq1Zreq2r  Zk1Zk2)r   r  r  r  ZstrbndrF   rF   rG   r    s    	 
z Structure.omm_stretch_bend_forcec             C   s   | j s
dS tddS )z Create the OpenMM Amoeba coupled-torsion (CMAP) force

        Returns
        -------
        AmoebaTorsionTorsionForce
            The torsion-torsion (CMAP) force with all coupled-torsion parameters
            for this system
        Nz$Torsion-torsions not yet implemented)rr   NotImplementedError)r   rF   rF   rG   r    s    
 z#Structure.omm_torsion_torsion_forcec             C   sp   xjt tt| jD ]T}| j| }|jdkr@|jdkr@| j|= q|jjdksX|jjdkr|  | j|= qW dS )z Gets rid of any empty bonds Nr   )r  r4   r   rg   r   r   r   r_  )r   r   ri  rF   rF   rG   r     s    

zStructure._prune_empty_bondsc             C   s|   xvt tt| jD ]`}| j| }|jdkrJ|jdkrJ|jdkrJ| j|= qd|jj|jj|jjfkr|  | j|= qW dS )z Gets rid of any empty angles Nr   )	r  r4   r   rh   r   r   r   r   r_  )r   r   r  rF   rF   rG   r   !  s    


zStructure._prune_empty_anglesri   c             C   s   xt ttt| |D ]|}t| || }|jdkr`|jdkr`|jdkr`|jdkr`t| ||= qd|jj|jj|jj|jjfkr|	  t| ||= qW dS )z! Gets rid of any empty dihedrals Nr   )
r  r4   r   r  r   r   r   r   r   r_  )r   Zdlistr   ZdihedrF   rF   rG   r   .  s     z Structure._prune_empty_dihedralsc             C   s   |  d dS )z$ Gets rid of any empty R-B torsions rj   N)r   )r   rF   rF   rG   r   ;  s    z"Structure._prune_empty_rb_torsionsc             C   sp   xjt tt| jD ]T}| j| }|jdkr@|jdkr@| j|= q|jjdksX|jjdkr|  | j|= qW dS )z* Gets rid of any empty Urey-Bradley terms Nr   )r  r4   r   rk   r   r   r   r_  )r   r   r   rF   rF   rG   r   A  s    

zStructure._prune_empty_ureysc             C   s   xt tt| jD ]p}| j| }|jdkrT|jdkrT|jdkrT|jdkrT| j|= qd|jj|jj|jj|jjfkr|	  | j|= qW dS )z) Gets rid of any empty improper torsions Nr   )
r  r4   r   rl   r   r   r   r   r   r_  )r   r   r  rF   rF   rG   r   M  s    
(
 z Structure._prune_empty_impropersc             C   s   xt tt| jD ]}| j| }|jdkr^|jdkr^|jdkr^|jdkr^|jdkr^| j|= qd|jj	|jj	|jj	|jj	|jj	fkr|
  | j|= qW dS )z" Gets rid of any empty CMAP terms Nr   )r  r4   r   rm   r   r   r   r   r   r   r_  )r   r   r  rF   rF   rG   r   Y  s    

zStructure._prune_empty_cmapsc             C   s   |  d dS )z' Gets rid of any empty trigonal angles rn   N)r   )r   rF   rF   rG   r   g  s    z&Structure._prune_empty_trigonal_anglesc             C   s   |  d dS )z* Gets rid of any empty out-of-plane bends ro   N)r   )r   rF   rF   rG   r   m  s    z)Structure._prune_empty_out_of_plane_bendsc             C   s   xt tt| jD ]}| j| }|jdkrh|jdkrh|jdkrh|jdkrh|jdkrh|j	dkrh| j|= qd|jj
|jj
|jj
|jj
|jj
|j	j
fkr| j|= qW dS )z# Gets rid of any empty pi-torsions Nr   )r  r4   r   rp   r   r   r   r   r   r   r   )r   r   ZpitrF   rF   rG   r   s  s    

z"Structure._prune_empty_pi_torsionsc             C   s~   xxt tt| jD ]b}| j| }|jdkrJ|jdkrJ|jdkrJ| j|= q|jjdksn|jjdksn|jjdkr| j|= qW dS )z* Gets rid of any empty stretch-bend terms Nr   )r  r4   r   rq   r   r   r   r   )r   r   ZsbrF   rF   rG   r     s    

$z$Structure._prune_empty_stretch_bendsc             C   s   xt tt| jD ]}| j| }|jdkr^|jdkr^|jdkr^|jdkr^|jdkr^| j|= qd|jj	|jj	|jj	|jj	|jj	fkr|
  | j|= qW dS )z- Gets rid of any empty torsion-torsion terms Nr   )r  r4   r   rr   r   r   r   r   r   r   r_  )r   r   r   rF   rF   rG   r     s    

&z'Structure._prune_empty_torsion_torsionsc             C   sh   xbt tt| jD ]L}| j| }|jdks6|jdkr@| j|= q|jjdksX|jjdkr| j|= qW dS )z* Gets rid of any empty chiral frame terms Nr   )r  r4   r   rs   r   r   r   )r   r   ZcfrF   rF   rG   r     s    

z$Structure._prune_empty_chiral_framesc             C   sH   xBt tt| jD ],}| j| }|jdks8|jjdkr| j|= qW dS )z- Gets rid of any empty multipole frame terms Nr   )r  r4   r   rt   rN   r   )r   r   ZmfrF   rF   rG   r     s    
z'Structure._prune_empty_multipole_framesc             C   sh   xbt tt| jD ]L}| j| }|jdks6|jdkr@| j|= q|jjdksX|jjdkr| j|= qW dS )z7 Gets rid of any empty nonbonded exception adjustments Nr   )r  r4   r   ru   r   r   r   )r   r   ZadjrF   rF   rG   r     s    

zStructure._prune_empty_adjustsc       	         s  |t jkrdd | jD }dd | jD }xt| jD ]\}}|jdkrRd||< nN|jdkrfd||< n:|jdkrzd	||< n&|jd
krd||< n|jdkrd||< || dkr6t|||< q6W n|t jkr6dd | jD }dd | jD }dd | jD }dd | jD }dd | jD }xzt| jD ]\}}|jdkrbd||< d||< d||< d||< n|jdkrd||< d||< d||< d||< n|jdkrd||< d||< d||< d||< nZ|jd
krd ||< d!||< d"||< d#||< n,|jdkrd$||< d!||< d"||< d#||< || s*t|||< q*W ndd%d | jD }d&d | jD }xBt| jD ]4\}}|| r~|| sbt||\||< ||< qbW t	j
t	j  fd'd|D }|t jkrtt|||||S tt||S )(a}   Gets the GB parameters for the requested GB model used by OpenMM

        Parameters
        ----------
        implicitSolvent : app.HCT, app.OBC1, app.OBC2, app.GBn, or app.GBn2
            The object specifying a particular GB model in OpenMM

        Returns
        -------
        parameters : list of float
            List of parameters for the requested GB model
        c             S   s   g | ]}d qS )g      ?rF   )r   rN   rF   rF   rG   r     s    z0Structure._get_gb_parameters.<locals>.<listcomp>c             S   s   g | ]
}|j qS rF   )solvent_radius)r   rN   rF   rF   rG   r     s    rH   g,-?r   gw#t?rI   g1\^Yg?rP   gdU?rL   gfE?r   c             S   s   g | ]}d qS )g      ?rF   )r   r   rF   rF   rG   r     s    c             S   s   g | ]}d qS )g?rF   )r   r   rF   rF   rG   r     s    c             S   s   g | ]}d qS )gffffff@rF   )r   r   rF   rF   rG   r     s    c             S   s   g | ]}d qS )g      ?rF   )r   r   rF   rF   rG   r     s    c             S   s   g | ]
}|j qS rF   )r%  )r   rN   rF   rF   rG   r     s    g̰Q?gz?g>?4?g#	Y?gZ?gvۅ:?g"4?gr۾G?g,y?gzю?g@F?g4Op?g}?gY!?g>d?g@-?gkтc             S   s   g | ]
}|j qS rF   )r%  )r   rN   rF   rF   rG   r     s    c             S   s   g | ]
}|j qS rF   )screen)r   rN   rF   rF   rG   r     s    c                s   g | ]}|  qS rF   rF   )r   r   )r  rF   rG   r     s    )r7   r  re   r   re  rO   r  rV   rZ   r:   r  r  r  r   r5   )	r   r  r&  Zradiir   rN   ZalphaZbetaZgammarF   )r  rG   r    sx    














zStructure._get_gb_parametersc             C   s   t | dr| jr| jS t| S )NrT   )r   rT   repr)r   rF   rF   rG   __str__  s    zStructure.__str__c             C   s   t | }||7 }|S )N)r   )r   othercprF   rF   rG   __add__  s    zStructure.__add__c       	         s>  t |tstS d}tj yjd jd }W n tk
rN   d}Y nX x:|jD ]0}|j	}
t||j|j| |j|j|j qXW  fdd}||j|jjjddg ||j|jjjddd	g ||j|jjjddd	d
ddg ||j|jjjddd	d
ddg ||j|jjjddg ||j|jjjddd	d
g ||j|jjjddd	d
dg ||j|j jj ddd	d
g ||j!|j"j!j"ddd	d
g ||j#|j$j#j$ddd	d
ddg ||j%|j&j%j&ddd	g ||j'|j(j'j(ddd	d
dg ||j)g j)g dddg ||j*g j*g dddddg ||j+|j,j+j,ddg ||j-g j-g ddg ||j.g j.g ddg ||j/g j/g dddg |d ks|j0d krd _0n`|d}t1|j2d |j2d }t3j4|d |d d d d f |d |d d d d f fdd_0S )Nr!  r   r   r   c       
         s   dd |D }x| D ]  fdd|D }x2t |D ]&\}}t|tr4j|j  ||< q4W t }	t dr jtkrt|	d< n|r jdk	r| jj |	d< |	t ||	 t dr j
|d _
qW || t|dr|  dS )	z Copies the valence terms from one list to another;
            oval=Other VALence; otyp=Other TYPe; sval=Self VALence;
            styp=Self TYPe; attrlist=ATTRibute LIST (atom1, atom2, ...)
            c             S   s   g | ]}t |qS rF   )r   )r   r   rF   rF   rG   r   6  s    zBStructure.__iadd__.<locals>.copy_valence_terms.<locals>.<listcomp>c                s   g | ]}t  |qS rF   )r  )r   r  )r  rF   rG   r   8  s    r   Nr   r   r   )r   r@   r   re   r   r"  r   r   r   r=   r   extendr   )
r#  r$  r%  r&  r'  r(  r)  r   r   r+  )aoffsetr   )r  rG   r-  1  s"    





z.Structure.__iadd__.<locals>.copy_valence_termsr   r   r   r   r   r   r   r   r   rN   r   r   r   r   r   r   )Zaxis)5r@   r[   NotImplementedrx  r   re   rf   r   r9  r   r   r   rT   r   r   r   r   rg   ry   rh   rz   ri   r{   rj   r~   rk   r|   rl   r}   rm   r   rn   r   ro   r   rp   r   rq   r   rr   r   rs   rt   ru   r   rw   rv   rx   r   minrv  r  Zconcatenate)	r   r)  ZmycrdroffsetrN   r   r-  ZocrdZnframesrF   )r-  r   rG   __iadd__  st    

	








@zStructure.__iadd__c             C   s   t | }||| S )z2 Replicates the current Structure `ncopies` times )r   __imul__)r   ncopiesr*  rF   rF   rG   __mul__x  s    zStructure.__mul__c       	         s  t |tstS  fdd}|d kr*t }xtt|d D ]b}t j} jd jd }x:|jD ]0}|j	} 
t||j|j| |j|j|j qbW ||j| j jddg ||j| j jdddg ||j| j jddddd	d
g ||j| j jddddd	d
g ||j| j jddg ||j| j jddddg ||j| j jdddddg ||j| j jddddg ||j | j  j!ddddg ||j"| j" j#ddddddg ||j$| j$ j%dddg ||j&| j& j'dddddg ||j(| j(g dddg ||j)| j)g dddddg ||j*| j* j+ddg ||j,| j,g ddg ||j-| j-g ddg ||j.| j.g dddg q:W  j/d k	rt01 fddt|D  _/ S )Nc       	         s   x| D ]  fdd|D }x2t |D ]&\}}t|tr&j|j|  ||< q&W t }t drt jtkrtt|d< n|r jdk	r| jj |d< |	t || t dr j
|d _
qW dS )z Copies the valence terms from one list to another;
            oval=Other VALence; otyp=Other TYPe; sval=Self VALence;
            styp=Self TYPe; attrlist=ATTRibute LIST (atom1, atom2, ...)
            c                s   g | ]}t  |qS rF   )r  )r   r  )r  rF   rG   r     s    zBStructure.__imul__.<locals>.copy_valence_terms.<locals>.<listcomp>r   Nr   r   )r   r@   r   re   r   r"  r   r   r   r=   r   )	r#  r-  r%  r&  r'  r)  r   r   r+  )r   )r  rG   r-    s    



z.Structure.__imul__.<locals>.copy_valence_termsr   r   r   r   r   r   r   r   r   r   r   rN   r   r   r   r   r   r   c                s   g | ]
} j qS rF   )r   )r   r   )r   rF   rG   r     s    z&Structure.__imul__.<locals>.<listcomp>)2r@   r1   r.  r   r4   r   re   rf   r   r   r   rT   r   r   r   r   rg   ry   rh   rz   ri   r{   rj   r~   rk   r|   rl   r}   rm   r   rn   r   ro   r   rp   r   rq   r   rr   r   rs   rt   ru   r   rw   rv   rx   r   r  Zhstack)	r   r3  r)  r-  r   r-  r0  rN   r   rF   )r   rG   r2    sf    
 

zStructure.__imul__c             C   s   t | jp| jp| jp| jp| jp| jp| jp| jp| j	p| j
p| jp| jp| j	p| jp| jp| jp| jp| jp| jp| jp| jp| jp| jp| jp| jp| jp| jp| jp| jp| jp| jp| jp| j S )N)!r5  re   rf   rg   rh   ri   rl   rj   rm   rr   rq   ro   rn   rp   rk   rs   rt   ru   rv   rw   rx   ry   rz   r{   r|   r}   r~   r   r   r   r   r   r   )r   rF   rF   rG   __bool__  s     zStructure.__bool__c             C   sJ   |dkrdS t |ts t |tr<x|D ]}| | q&W dS | | dS )z< Adds an OpenMM force to a system IFF the force is not None N)r@   r7  r   r  )r  r  frF   rF   rG   r    s     
zStructure._add_force_to_systemc                sB  t | j| j| j| j| j| j| j| j| j	| j
| j| j| j| j| j| j| j| j| j| j| jd}dd   fdd| jD |d<  fdd| jD |d<  fd	d| jD |d
<  fdd| jD |d<  fdd| jD |d<  fdd| jD |d<  fdd| jD |d<  fdd| jD |d<  fdd| jD |d<  fdd| jD |d<  fdd| j D |d<  fdd| j!D |d< dd | j"D |d< dd | j#D |d <  fd!d| j$D |d"< d#d | j%D |d$< d%d | j&D |d&< d'd | j'D |d(< x<d)D ]4}yt(| |||< W n t)k
r6   wY nX qW |S )*z Serializes a structure )rf   ry   rz   r{   r|   r}   r~   r   r   r   r   r   r   r   rx   r   r   r   r   r   r   c             S   s   | d k	r| j S d S )N)r   )rc  rF   rF   rG   r     s    z#Structure.__getstate__.<locals>.idxc                s$   g | ]}|j j|jj |jfqS rF   )r   r   r   r   )r   r   )r   rF   rG   r     s   z*Structure.__getstate__.<locals>.<listcomp>rg   c                s*   g | ]"}|j j|jj|jj |jfqS rF   )r   r   r   r   r   )r   r   )r   rF   rG   r     s   rh   c          
      s8   g | ]0}|j j|jj|jj|jj|j|j |jfqS rF   )r   r   r   r   r   r   r   r   )r   r   )r   rF   rG   r   	  s   ri   c                s0   g | ](}|j j|jj|jj|jj |jfqS rF   )r   r   r   r   r   r   )r   r   )r   rF   rG   r     s   rl   c                s0   g | ](}|j j|jj|jj|jj |jfqS rF   )r   r   r   r   r   r   )r   r   )r   rF   rG   r     s   rj   c                s$   g | ]}|j j|jj |jfqS rF   )r   r   r   r   )r   r:   )r   rF   rG   r     s   rk   c          	      s6   g | ].}|j j|jj|jj|jj|jj |jfqS rF   )r   r   r   r   r   r   r   )r   r   )r   rF   rG   r     s   rm   c                s0   g | ](}|j j|jj|jj|jj |jfqS rF   )r   r   r   r   r   r   )r   r   )r   rF   rG   r     s   rn   c                s0   g | ](}|j j|jj|jj|jj |jfqS rF   )r   r   r   r   r   r   )r   r   )r   rF   rG   r     s   ro   c          
      s<   g | ]4}|j j|jj|jj|jj|jj|jj |jfqS rF   )r   r   r   r   r   r   r   r   )r   r   )r   rF   rG   r     s   rp   c                s*   g | ]"}|j j|jj|jj |jfqS rF   )r   r   r   r   r   )r   r   )r   rF   rG   r     s   rq   c          	      s6   g | ].}|j j|jj|jj|jj|jj |jfqS rF   )r   r   r   r   r   r   r   )r   r   )r   rF   rG   r     s   rr   c             S   s    g | ]}|j j|jj|jfqS rF   )r   r   r   r   )r   r   rF   rF   rG   r     s   rs   c             S   s&   g | ]}|j j|j|j|j|jfqS rF   )rN   r   r   r   r   r   )r   r6  rF   rF   rG   r     s   rt   c                s$   g | ]}|j j|jj |jfqS rF   )r   r   r   r   )r   r\  )r   rF   rG   r   !  s    ru   c             S   s   g | ]}|j j|jjfqS rF   )r   r   r   )r   r   rF   rF   rG   r   "  s    rv   c             S   s   g | ]}|j j|jjfqS rF   )r   r   r   )r   r   rF   rF   rG   r   #  s    rw   c             S   s    g | ]}t d d |jD qS )c             s   s   | ]}|j V  qd S )N)r   )r   r\  rF   rF   rG   r>  $  s    z4Structure.__getstate__.<locals>.<listcomp>.<genexpr>)r7  Z_exclusion_partners)r   r   rF   rF   rG   r   $  s    
exclusions)experimentaljournalauthorskeywordsdoipmidjournal_authorsvolumer   yearr  related_entries)*r"  rf   ry   rz   r{   r|   r}   r~   r   r   r   r   r   r   r   rx   r   r   r   r   r   r   rg   rh   ri   rl   rj   rk   rm   rn   ro   rp   rq   rr   rs   rt   ru   rv   rw   re   r  rd  )r   Zretdictr`  rF   )r   rG   __getstate__  sx    













zStructure.__getstate__c                s  x*dD ]"}t |||  t|  qW x$dD ]}||kr2t |||  q2W t _xjD ]}j|j qbW dd  t fdd|d D _t fdd|d	 D _	t fd
d|d D _
t fdd|d D _t fdd|d D _t fdd|d D _t fdd|d D _t fdd|d D _t fdd|d D _t fdd|d D _t fdd|d D _t fdd|d D _tfdd|d D _tfd d|d! D _t fd"d|d# D _tfd$d|d% D _tfd&d|d' D _x>tj|d( D ]*\}}x|D ]}|j|  qW qW d S ))N)rf   ry   rz   r{   r|   r}   r~   r   r   r   r   r   rx   r   r   )r8  r9  r:  r;  r<  r=  r>  r?  r   r@  r  rA  r   r   r   r   r   r   c             S   s   |d krd S | | S )NrF   )Ztypelistr   rF   rF   rG   assign_typeG  s    z+Structure.__setstate__.<locals>.assign_typec             3   s<   | ]4}t j|d   j|d   j|d dV  qdS )r   r   r\   )r   N)r   re   ry   )r   r   )rC  r   rF   rG   r>  N  s   z)Structure.__setstate__.<locals>.<genexpr>rg   c          	   3   sH   | ]@}t j|d   j|d  j|d   j|d dV  qdS )r   r   r\   r]   )r   N)r   re   rz   )r   r   )rC  r   rF   rG   r>  R  s   rh   c             3   s`   | ]X}t j|d   j|d  j|d  j|d  |d |d  j|d dV  qdS )	r   r   r\   r]   r^   r_   rH   )r   r   r   N)r   re   r{   )r   r   )rC  r   rF   rG   r>  W  s   ri   c          
   3   sT   | ]L}t j|d   j|d  j|d  j|d   j|d dV  qdS )r   r   r\   r]   r^   )r   N)r   re   r}   )r   r   )rC  r   rF   rG   r>  \  s   rl   c             3   s<   | ]4}t j|d   j|d   j|d dV  qdS )r   r   r\   )r   N)r+   re   r|   )r   r   )rC  r   rF   rG   r>  `  s   rk   c          
   3   sT   | ]L}t j|d   j|d  j|d  j|d   j|d dV  qdS )r   r   r\   r]   r^   )r   N)r   re   r~   )r   r   )rC  r   rF   rG   r>  e  s   rj   c             3   s`   | ]X}t j|d   j|d  j|d  j|d  j|d   j|d dV  qdS )r   r   r\   r]   r^   r_   )r   N)r   re   r   )r   r   )rC  r   rF   rG   r>  j  s   rm   c          
   3   sT   | ]L}t j|d   j|d  j|d  j|d   j|d dV  qdS )r   r   r\   r]   r^   )r   N)r(   re   r   )r   r   )rC  r   rF   rG   r>  o  s   rn   c          
   3   sT   | ]L}t j|d   j|d  j|d  j|d   j|d dV  qdS )r   r   r\   r]   r^   )r   N)r    re   r   )r   r   )rC  r   rF   rG   r>  t  s   ro   c             3   sl   | ]d}t j|d   j|d  j|d  j|d  j|d  j|d   j|d dV  qdS )	r   r   r\   r]   r^   r_   rH   )r   N)r"   re   r   )r   r   )rC  r   rF   rG   r>  y  s   rp   c          	   3   sH   | ]@}t j|d   j|d  j|d   j|d dV  qdS )r   r   r\   r]   )r   N)r$   re   r   )r   r   )rC  r   rF   rG   r>    s   rq   c             3   s`   | ]X}t j|d   j|d  j|d  j|d  j|d   j|d dV  qdS )r   r   r\   r]   r^   r_   )r   N)r&   re   r   )r   r   )rC  r   rF   rG   r>    s   rr   c             3   s2   | ]*}t  j|d    j|d  |d V  qdS )r   r   r\   N)r   re   )r   r   )r   rF   rG   r>    s    rs   c             3   s.   | ]&}t  j|d   f|dd  V  qdS )r   r   N)r   re   )r   r   )r   rF   rG   r>    s    rt   c             3   s:   | ]2}t j|d   j|d   j|d V  qdS )r   r   r\   N)r   re   r   )r   r   )rC  r   rF   rG   r>    s   ru   c             3   s,   | ]$}t  j|d    j|d  V  qdS )r   r   N)r   re   )r   r   )r   rF   rG   r>    s    rv   c             3   s,   | ]$}t  j|d    j|d  V  qdS )r   r   N)r   re   )r   r   )r   rF   rG   r>    s    rw   r7  )setattrr  r   r   re   rf   r,  r'   rg   rh   ri   rl   rk   rj   rm   rn   ro   rp   rq   rr   rs   rt   ru   rv   rw   r5   Zexclude)r   r   r  r`  r   rN   Zexclr   rF   )rC  r   rG   __setstate__1  sx    

 
zStructure.__setstate__)rc   rc   rc   )F)NF)r!  )r!  )NTT)NT)F)ri   )N)hr   
__module____qualname____doc__r  r  r  r  r  r  r  r   r!  r#  ZTORSION_TORSION_FORCE_GROUPr  r  r   r   r   r   r   r   r   r   r   r   r   r   r  r  r  r0  r.  propertyr<  rG  r]  ra  r   setterr0   rj  rn  r  rx  r   ry  rX  r~  r  r:   r?   r  Zlitersr  r  r  r  r  r  r  r  r  r  r  r  r  r  r  r  r  r  r  r  r  r   r   r   r   r   r   r   r   r   r   r   r   r   r   r   r  r(  r+  r1  r4  __rmul__r2  r5  __nonzero__staticmethodr  rB  rE  rF   rF   rF   rG   r[      s  S5
 
 i&.0    B
 &;
3
"	 V)?1-&

 ;mDr
	R	_
OFr[   c               @   s    e Zd ZdZdd Zdd ZdS )r;  z= Class responsible for creating a StructureView when indexed c             C   s
   || _ d S )N)r,  )r   r,  rF   rF   rG   r     s    z _StructureViewerCreator.__init__c       	   	      s  | j }t|tr|j| S t }||}|d kr6|S t|trD|S t|}|dkrX|S |d g x0tdt	|D ]} 
 |d  ||   qrW dd t |D  t }xRt|jD ]D\}}|| sq|j
| |j|krq|j
|j ||j qW  fdd}||j|jddg ||j|jddd	g ||j|jddd	d
g ||j|jddd	d
g ||j|jddg ||j|jddd	d
g ||j|jddd	d
dg ||j|jddd	d
g ||j|jddd	d
g ||j|jddd	d
ddg ||j|jddd	g ||j|jddd	d
dg ||j|jddg ||j|jdg ||j|jddg ||j |j ddg ||j!|j!ddg |S )Nr   r   c             S   s   g | ]\}}|| qS rF   rF   )r   r   r   rF   rF   rG   r     s    z7_StructureViewerCreator.__getitem__.<locals>.<listcomp>c                sJ   xD|D ]<  fdd|D }fdd|D }t |s8q|   qW dS )z Adds the valence terms from one list to another;
            oval=Other VALence; otyp=Other TYPe; sval=Self VALence;
            styp=Self TYPe; attrlist=ATTRibute LIST (atom1, atom2, ...)
            c                s   g | ]}t  |qS rF   )r  )r   r  )r  rF   rG   r     s    zR_StructureViewerCreator.__getitem__.<locals>.add_valence_terms.<locals>.<listcomp>c                s    g | ]}t |tr |j qS rF   )r@   r   r   )r   r   )r   rF   rG   r     s    N)r!  r=   )r#  r%  r'  r)  r*  )r   )r  rG   add_valence_terms  s    
z>_StructureViewerCreator.__getitem__.<locals>.add_valence_termsr   r   r   r   r   r   rN   )"r,  r@   r1   re   StructureViewr.  r   r   r4   r   r=   r5   r   r   r   rf   r   rg   rh   ri   rj   rk   rl   rm   rn   ro   rp   rq   rr   rs   rt   ru   rw   rv   )	r   r  r,  r<  r/  r   Zsel_resrN   rN  rF   )r   rG   r0    sb    




 
 




z#_StructureViewerCreator.__getitem__N)r   rF  rG  rH  r   r0  rF   rF   rF   rG   r;    s   r;  c               @   s\   e Zd ZdZdd Zdd Zdd Zedd	 Zed
d Z	dd Z
dd Ze
Zdd ZdS )rO  aS  
    A view of a Structure. In many cases, this can serve as a duck-typed
    Structure and it has many of the same attributes. However, none of its lists
    *own* their objects, and the lists of atoms, residues, and
    parameters/topologies are regular lists, rather than TrackedList instances.
    Therefore, the indexes correspond to the indexes from the *original*
    Structure from which this view was taken. Furthermore, there are no "type"
    lists, as they would be exactly equivalent to the type lists of the parent
    Structure instance.

    Attributes
    ----------
    atoms : :class:`AtomList`
        List of all atoms in the structure
    residues : :class:`ResidueList`
        List of all residues in the structure
    bonds : :class:`TrackedList` (:class:`Bond`)
        List of all bonds in the structure
    angles : :class:`TrackedList` (:class:`Angle`)
        List of all angles in the structure
    dihedrals : :class:`TrackedList` (:class:`Dihedral`)
        List of all dihedrals in the structure
    rb_torsions : :class:`TrackedList` (:class:`RBTorsion`)
        List of all Ryckaert-Bellemans torsions in the structure
    urey_bradleys : :class:`TrackedList` (:class:`UreyBradley`)
        List of all Urey-Bradley angle bends in the structure
    impropers : :class:`TrackedList` (:class:`Improper`)
        List of all CHARMM-style improper torsions in the structure
    cmaps : :class:`TrackedList` (:class:`Cmap`)
        List of all CMAP objects in the structure
    trigonal_angles : :class:`TrackedList` (:class:`TrigonalAngle`)
        List of all AMOEBA-style trigonal angles in the structure
    out_of_plane_bends : :class:`TrackedList` (:class:`OutOfPlaneBends`)
        List of all AMOEBA-style out-of-plane bending angles
    pi_torsions : :class:`TrackedList` (:class:`PiTorsion`)
        List of all AMOEBA-style pi-torsion angles
    stretch_bends : :class:`TrackedList` (:class:`StretchBend`)
        List of all AMOEBA-style stretch-bend compound bond/angle terms
    torsion_torsions : :class:`TrackedList` (:class:`TorsionTorsion`)
        List of all AMOEBA-style coupled torsion-torsion terms
    chiral_frames : :class:`TrackedList` (:class:`ChiralFrame`)
        List of all AMOEBA-style chiral frames defined in the structure
    multipole_frames : :class:`TrackedList` (:class:`MultipoleFrame`)
        List of all AMOEBA-style multipole frames defined in the structure
    adjusts : :class:`TrackedList` (:class:`NonbondedException`)
        List of all nonbonded pair-exception rules
    acceptors : :class:`TrackedList` (:class:`AcceptorDonor`)
        List of all H-bond acceptors, if that information is present
    donors : :class:`TrackedList` (:class:`AcceptorDonor`)
        List of all H-bond donors, if that information is present
    positions : u.Quantity(list(Vec3), u.angstroms)
        Unit-bearing atomic coordinates. If not all atoms have coordinates, this
        property is None
    coordinates : np.ndarray of shape (nframes, natom, 3)
        If no coordinates are set, this is set to None. The first frame will
        match the coordinates present on the atoms.
    c             C   sv   g | _ g | _g | _g | _g | _g | _g | _g | _g | _g | _	g | _
g | _g | _g | _g | _g | _g | _g | _g | _d S )N)re   rf   rg   rh   ri   rj   rk   rl   rm   rn   ro   rp   rq   rr   rs   rt   ru   rv   rw   )r   rF   rF   rG   r   *  s&    zStructureView.__init__c             C   s   ddl m} || S )aM   Generates a DataFrame from the current Structure's atomic properties

        Returns
        -------
        df : DataFrame
            DataFrame with all atomic properties

        See Also
        --------
        :func:`parmed.utils.pandautils.create_dataframe` for full
        documentation of the generated DataFrame
        r   )r   )r   r   )r   r   rF   rF   rG   r   ?  s    zStructureView.to_dataframec             C   s   ddl m} || |S )av   Loads atomic properties from an input DataFrame

        Parameters
        ----------
        df : pandas.DataFrame
            A pandas DataFrame with atomic properties that will be used to set
            the properties on the current list of atoms

        See Also
        --------
        :func:`parmed.utils.pandautils.load_dataframe` for full documentation
        r   )r   )r   r   )r   r   r   rF   rF   rG   r   O  s    zStructureView.load_dataframec             C   s0   yt dd | jD S  tk
r*   d S X d S )Nc             S   s   g | ]}|j |j|jgqS rF   )rk  rl  rm  )r   r   rF   rF   rG   r   b  s    z-StructureView.coordinates.<locals>.<listcomp>)r  r  re   rd  )r   rF   rF   rG   r  _  s    zStructureView.coordinatesc             C   s0   ydd | j D tj S  tk
r*   d S X d S )Nc             S   s   g | ]}t |j|j|jqS rF   )r6   rk  rl  rm  )r   r   rF   rF   rG   r   i  s    z+StructureView.positions.<locals>.<listcomp>)re   r:   r?   rd  )r   rF   rF   rG   rn  f  s    zStructureView.positionsc             C   s|   t | jpx| jpx| jpx| jpx| jpx| jpx| jpx| jpx| j	px| j
px| jpx| jpx| j	px| jpx| jpx| jpx| jpx| jpx| jpx| jS )N)r5  re   rf   rg   rh   ri   rl   rj   rm   rr   rq   ro   rn   rp   rk   rs   rt   ru   rv   rw   )r   rF   rF   rG   r5  m  s    zStructureView.__bool__c             C   s   t | j}t | j}tdd | jD }dt| j|f g}|dkrR|d|  |d|  t | j}|d|  d|S )	Nc             S   s   g | ]}t |tqS rF   )r@   r   )r   r   rF   rF   rG   r   {  s    z*StructureView.__repr__.<locals>.<listcomp>z<%s %d atomsr   z	 [%d EPs]z; %d residuesz; %d bonds>rc   )	r   re   rf   r   r   r   r=   rg   r   )r   r   r   r   r   r   rF   rF   rG   r   x  s    


zStructureView.__repr__c             C   s
   t | jS )N)rB   re   )r   rF   rF   rG   r     s    zStructureView.__iter__N)r   rF  rG  rH  r   r   r   rI  r  rn  r5  r   rL  r   rF   rF   rF   rG   rO    s   9rO  c             C   s   g }xv| j D ]l}tdd |D }|dkr6|d qx@|D ].}x&|jD ]}|j|k	rH|d P qHW q<P q<W |d qW t|t| j kstd|S )z8 Identifies residues that can have SETTLE applied to it c             s   s   | ]}t |tsd V  qdS )r   N)r@   r   )r   r   rF   rF   rG   r>    s    z_settler.<locals>.<genexpr>r]   FTzIncorrect length)rf   r   r=   rQ   r   r   rB  )r   r  r   Znar   rF  rF   rF   rG   r    s     



r  c             C   s   | j |kr|| j  S t| j dkrDtj| j rD|tj| j j S tj| j rf|tj| j j S tj| j rtj| j jdkr|tj| j j S dS )z: Returns the residue template inside lib that matches res r]   r  N)	rT   r   r   r  r  r  r  Z
DNAResidueZ
RNAResidue)r   r  rF   rF   rG   r	    s    

"r	  )^rH  Z
__future__r   r   Zloggingr  rO  collectionsr   r   Znumpyr  rc   r   r:   r   Z	constantsr	   r
   
exceptionsr   Zgeometryr   r   r   r   Ztopologyobjectsr   r   r   r   r   r   r   r   r   r   r   r   r   r   r   r   r    r!   r"   r#   r$   r%   r&   r'   r(   r)   r*   r+   r,   Zutilsr-   r.   r/   Zutils.decoratorsr0   Z	utils.sixr1   r2   r3   Zutils.six.movesr4   r5   Zvec3r6   Zsimtk.openmmr7   Zsimtkr8   r  Z"simtk.openmm.app.internal.unitcellr9   r  Z	getLoggerr   r  rC   rO   rR   rS   rV   rZ   objectr[   r;  rO  r  r	  rF   rF   rF   rG   <module>   s   |
	
$                            .N 