
     in                       d Z ddlmZ ddlZddlZddlZddlZddlmZ	 ddl
Z
ddlZddlmZ 	 ddlZddlZdZn# e$ r dZY nw xY wddlZdd	lmZmZmZmZmZmZ dd
lmZmZ ddlm Z m!Z! ddl"m#Z# ddl$m%Z% ddl&m'Z'm(Z(m)Z)m*Z*m+Z+m,Z,m-Z-m.Z.m/Z/m0Z0 ddl$m1Z1m2Z2m3Z3 d Z4d Z5d Z6d Z7dZ8d Z9 G d de:          Z; G d de<e;          Z= G d de=          Z> G d de=          Z? G d  d!e=          Z@ G d" d#e=          ZA G d$ d%eA          ZB G d& d'          ZC G d( d)eCeA          ZD G d* d+eD          ZE G d, d-eD          ZF G d. d/eD          ZG G d0 d1eA          ZH G d2 d3eD          ZI G d4 d5eD          ZJ G d6 d7eA          ZK G d8 d9eA          ZL G d: d;eA          ZM G d< d=eA          ZN G d> d?eA          ZO G d@ dAeD          ZP G dB dCeA          ZQ G dD dEeA          ZR G dF dGeA          ZS G dH dIeA          ZT G dJ dKeA          ZU G dL dMeA          ZV G dN dOeA          ZW G dP dQeA          ZX G dR dSeA          ZY G dT dUe=          ZZ G dV dWeCeZ          Z[ G dX dYeZ          Z\ G dZ d[e[          Z] G d\ d]eZ          Z^ G d^ d_e[          Z_ G d` dae[          Z` G db dceZ          Za G dd dee=          Zb G df dgeCeb          Zc G dh diec          Zddj Ze G dk dle;          Zf G dm dneAef          Zg G do dpeg          Zh G dq dreg          Zi G ds dteg          Zj G du dveg          Zk G dw dxeg          Zl G dy dzeg          ZmdS ){a  
Topology attribute objects --- :mod:`MDAnalysis.core.topologyattrs`
===================================================================

Common :class:`TopologyAttr` instances that are used by most topology
parsers.

TopologyAttrs are used to contain attributes such as atom names or resids.
These are usually read by the TopologyParser.

References
----------

.. footbibliography::

    )defaultdictN)	signature)
MethodTypeTF   )cachedconvert_aa_codeiterablewarn_if_not_uniqueunique_int_1dcheck_atomgroup_not_empty)transformationsmdamath)NoDataErrorSelectionError   )TopologyGroup)	selection)
ComponentBase	GroupBaseAtomResidueSegment	AtomGroupResidueGroupSegmentGroupcheck_wrap_and_unwrap_pbc_to_wrap)_TOPOLOGY_ATTRS_TOPOLOGY_TRANSPLANTS_TOPOLOGY_ATTRNAMESc                 `     ddd t          j                    fd            }|S )a  Wrapper which checks the length of inputs to set_X

    Eg:

    @_check_length
    def set_X(self, group, values):

    Will check the length of *values* compared to *group* before proceeding with
    anything in the *set_X* method.

    Pseudo code for the check:

    if group in (Atom, Residue, Segment):
        values must be single values, ie int, float or string
    else:
        values must be single value OR same length as group

    zoSetting {cls} {attrname} with wrong sized input. Must use single value, length of supplied values: {lenvalues}.zvSetting {group} {attrname} with wrong sized array. Length {group}: {lengroup}, length of supplied values: {lenvalues}.c                 B    t          |           rt          |           S dS Nr   )r	   lenvaluess    g/srv/www/vhosts/g4struct/public_html/venv/lib/python3.11/site-packages/MDAnalysis/core/topologyattrs.py	_attr_lenz _check_length.<locals>._attr_lenz   s%     F 	v;;1    c           	          |          }t          |t                    r;|dk    s4t                              |j        j        | j        |                    n[|dk    sU|t          |          k    sBt                              |j        j        | j        t          |          |                     | ||          S )Nr   )clsattrname	lenvalues)groupr,   lengroupr-   )	
isinstancer   
ValueErrorformat	__class____name__singularr$   r,   )attrr.   r&   val_len_GROUP_VALUE_ERROR_SINGLE_VALUE_ERRORr(   funcs       r'   wrapperz_check_length.<locals>.wrapper   s    )F##e]++ 	a<< '..!O4!%") /       qLLGs5zz$9$9 &--#o6!%!$U")	 .     tD%(((r)   	functoolswraps)r:   r;   r8   r9   r(   s   ` @@@r'   _check_lengthr?   X   sq    (	I 	N    _T) ) ) ) ) ) ) )2 Nr)   c                 *   t          |t          t          f          rd}n=t          |t          t          f          rd}nt          |t
          t          f          rd}t          | t                    rd}d}n3t          | t                    rd}d}nt          | t                    rd}d}t          |t                    r||k    r|d         }| j        }n|d         }| j        }d}t          |                    ||j        j        |	                    S )
a  Generate an error for setting attr at wrong level

    attr : TopologyAttr that was accessed
    group : Offending Component/Group

    Eg:
    setting mass of residue, gets called with attr=Masses, group=residue

    raises a NotImplementedError with:
    'Cannot set masses from Residue.  Use 'Residue.atoms.masses'

    Mainly used to ensure consistent and helpful error messages
    r   r      )atomsatom)residuesresidue)segmentssegmentr   z=Cannot set {attr} from {cls}. Use '{cls}.{correct}.{attr} = ')r6   r+   correct)r0   r   r   r   r   r   r   AtomAttrResidueAttrSegmentAttrr   r5   r,   NotImplementedErrorr2   r3   r4   )r6   r.   group_levelcorr_classes
attr_levelrH   r,   err_msgs           r'   _wronglevel_errorrQ      s3    %$	*++ 	EG\2	3	3 	EG\2	3	3  $!! (

	D+	&	& .

	D+	&	& .
%'' !Z+-E-E q/=q/=MG ( 	 	
 	
  r)   c                       fd}t          j        d                                        }t          j        |j                  dz   |z   |_         |_        t          |          |_        |S )a  
    Build a stub for a transplanted method.

    A transplanted stub is a dummy method that gets attached to a core class
    (usually from :mod:`MDAnalysis.core.groups`) and raises a
    :exc:`NoDataError`.
    The stub mimics the original method for everything that has traits with the
    documentation (docstring, name, signature). It gets overwritten by the
    actual method when the latter is transplanted at universe creation.

    Parameters
    ----------
    method_name: str
        The name of the attribute in the destination class.
    method: Callable
        The method to be mimicked.
    attribute_name: str
        The name topology attribute that is required for the method to be
        relevant (e.g. masses, charges, ...)

    Returns
    -------
    The stub.
    c                 f    d                     | j        j                  }t          |          )NzJ{class_name}.{method_name}() not available; this requires {attribute_name})
class_namemethod_nameattribute_name)r2   r3   r4   r   )selfargskwargsmessagerV   rU   s       r'   stub_methodz _build_stub.<locals>.stub_method   s?    <
&~.#)  
 
 	 '"""r)   z        .. note::

          This requires the underlying topology to have {}. Otherwise, a
          :exc:`~MDAnalysis.exceptions.NoDataError` is raised.


    z

)textwrapdedentr2   __doc__r4   inspect_signature__signature__)rU   methodrV   r[   
annotations   ` `  r'   _build_stubrc      s    4	# 	# 	# 	# 	# 	# 	 		
 	
 J #/&.99FBZOK&K 1& 9 9Kr)   c                 d   |j         }|                                D ]\  }}|dk    rddlm} |}|D ]}\  }}|                    d          rd}	 |j        }d}n# t          $ r Y nw xY wt          |||           }	|r!t          ||t          |	dd                     lt          |||	           ~dS )aN  
    Transplant a stub for every method that will be transplanted from a
    topology attribute.

    Parameters
    ----------
    attribute_name: str
        User-facing name of the topology attribute (e.g. masses, charges, ...)
    topology_attribute_class:
        Topology attribute class to inspect for transplant methods.

    Universer   )re   _FTN)
transplantsitemsuniversere   
startswithfgetAttributeErrorrc   setattrproperty)
rV   topology_attribute_classrg   
dest_classmethodsre   rU   method_callbackis_propertystubs
             r'   _attach_transplant_stubsru     s    +6K*0022 7 7
G## +*****!J,3 	7 	7(K %%c** K"1"6"!   {O^LLD 7
K$d1K1KLLLL
K6666'	77 7s   	A
A&%A&zThe bfactor topology attribute is only provided as an alias to the tempfactor attribute. It will be removed in 3.0. Please use the tempfactor attribute instead.c                       fd}|S )Nc                  R    t          j        t          t                      | i |S )z,
        Bfactor alias with warning
        )warningswarnBFACTOR_WARNINGDeprecationWarning)rX   rY   r:   s     r'   r;   z*deprecate_bfactor_warning.<locals>.wrapperE  s-     	o'9:::tT$V$$$r)    r:   r;   s   ` r'   deprecate_bfactor_warningr~   D  s#    % % % % % Nr)   c                       e Zd ZdZd ZdS )_TopologyAttrMetaa  Register TopologyAttrs on class creation

    Each topology attribute is added to the top-level dictionaries
    for various record purposes. The class itself is added to
    :data:`_TOPOLOGY_ATTRS` and :data:`_TOPOLOGY_ATTRNAMES`. Transplanted
    methods are also added to :data:`_TOPOLOGY_TRANSPLANTS.`

    We also attempt to make the topology attribute selectable with
    atom selection language by automatically generating a relevant
    selection class with the singular name (``singular``) as the
    selection token. Only certain ``dtype``\ s are supported; if a
    selection class cannot be generated, a warning will be raised
    but no error.

    See also
    --------
    :func:`MDAnalysis.core.selection.gen_selection_class`

    c                 2   t                               t           |||           |                    d          }|                    d|          }||}|r| xt          |<   t          |<   |                                                    dd          }|                                                    dd          }|t          |<   |t          |<   | j                                        D ]L\  }}	|	D ]D\  }}
||
|gt          |<   |                                                    dd          }|t          |<   EMdD ]+}	 ||         }t          ||            # t          $ r Y (w xY w|t          j        j        vr|t          j        j        |<   |t          j        j        vr|t          j        j        |<   |t          j        vr{|                    d          }|d|                    d|d         j                  }	 t          j        ||||           n*# t(          $ r d	| d
}t+          j        |           Y nw xY w|dk    rZ| xt          d<   t          d<   t          j        dd|                    d          d          }t/          |j                  |_        d S d S )Nr,   r5   rf    )r5   r,   dtype
per_objectr   zAA selection keyword could not be automatically generated for the zg attribute. If you need a selection keyword, define it manually by subclassing core.selection.SelectiontempfactorsbfactorbfactorsrC   )r   )type__init__getr   lowerreplacer    rg   rh   r   ru   KeyErrorr   SameSelection
prop_transPropertySelectionprops_SELECTIONDICTr   gen_selection_classr1   rx   ry   r~   apply)r+   namebases	classdictr,   r5   	_singular	_attrnameclstyperg   ra   cleanr6   r   per_objmsgselclss                    r'   r   z_TopologyAttrMeta.__init__d  s   dD%333==,,==X66H 	6DGGOH%(A ((00b99I ((00b99I-5	*-5	*(+(=(=(?(? 6 6$$/ 6 6LD&3;VW2M)$/ JJLL00b99E15'..6
 - 	8 	8D8$T? )37777     92===;CI#.x8 96<<<:BI'-h7 9333MM'**E #--eAh6IJJ'1 (E7    " ' ' 'B#B B B  M#&&&&&' }$$GJJOI&)D2g&&!	  F 5V\BBFLLL %$s$   7E
EE5H $H43H4N)r4   
__module____qualname__r^   r   r|   r)   r'   r   r   O  s7         (AC AC AC AC ACr)   r   c                       e Zd ZdZdZdZdZdZ ee	          Z
g ZdZdZdZddZed             Ze	 dd            Zd	 Zd
 Zd Zd Zed             Zd Zd Zd Zd Zd Zd Zd Z ed             Z!dS )TopologyAttra  Base class for Topology attributes.

    Note
    ----
    This class is intended to be subclassed, and mostly amounts to
    a skeleton. The methods here should be present in all
    :class:`TopologyAttr` child classes, but by default they raise
    appropriate exceptions.


    Attributes
    ----------
    attrname : str
        the name used for the attribute when attached to a ``Topology`` object
    singular : str
        name for the attribute on a singular object (Atom/Residue/Segment)
    per_object : str
        If there is a strict mapping between Component and Attribute
    dtype : int/float/object
        Type to coerce this attribute to be.  For string use 'object'
    top : Topology
        handle for the Topology object TopologyAttr is associated with

    topologyattrstopologyattrNFc                 r    | j         || _        n t          j        || j                   | _        || _        d S Nr   )r   r&   npasarray_guessed)rW   r&   guesseds      r'   r   zTopologyAttr.__init__  s6    : DKK*V4:>>>DKr)   c                      t          d          )zPopulate an initial empty data structure for this Attribute

        The only provided parameters are the "shape" of the Universe

        Eg for charges, provide np.zeros(n_atoms)
        zNo default valuesrL   )n_atoms
n_residues
n_segmentss      r'   _gen_initial_valuesz TopologyAttr._gen_initial_values  s     ""5666r)   c                     ||                      |||          }n"| j        t          j        || j                  } | |          S )a  Create a blank version of this TopologyAttribute

        Parameters
        ----------
        n_atoms : int, optional
          Size of the TopologyAttribute atoms
        n_residues: int, optional
          Size of the TopologyAttribute residues
        n_segments : int, optional
          Size of the TopologyAttribute segments
        values : optional
          Initial values for the TopologyAttribute
        Nr   )r   r   r   r   )r+   r   r   r   r&   s        r'   
from_blankzTopologyAttr.from_blank  sN    " >,,Wj*MMFFY"Zci888Fs6{{r)   c                 h    |                      | j                                        | j                  S )#Return a deepcopy of this attribute)r   )r3   r&   copyr   rW   s    r'   r   zTopologyAttr.copy  s(    ~~dk..00$-~HHHr)   c                 *    t          | j                  S )z2Length of the TopologyAttr at its intrinsic level.)r$   r&   r   s    r'   __len__zTopologyAttr.__len__  s    4;r)   c                 ,   t          |t          t          f          r|                     |          S t          |t          t
          f          r|                     |          S t          |t          t          f          r| 	                    |          S dS )z2Accepts an AtomGroup, ResidueGroup or SegmentGroupN)
r0   r   r   	get_atomsr   r   get_residuesr   r   get_segments)rW   r.   s     r'   __getitem__zTopologyAttr.__getitem__  s    edI.// 	,>>%(((677 	,$$U+++677 	,$$U+++	, 	,r)   c                 2   t          |t          t          f          r|                     ||          S t          |t          t
          f          r|                     ||          S t          |t          t          f          r| 	                    ||          S d S N)
r0   r   r   	set_atomsr   r   set_residuesr   r   set_segments)rW   r.   r&   s      r'   __setitem__zTopologyAttr.__setitem__  s    edI.// 	4>>%000677 	4$$UF333677 	4$$UF333	4 	4r)   c                     | j         S )z4Bool of if the source of this information is a guessr   r   s    r'   
is_guessedzTopologyAttr.is_guessed  s     }r)   c                 l    t          j        | j        t          j        |g          g          | _        dS )zkResize TopologyAttr to one larger, with *newval* as the new value

        .. versionadded:: 2.1.0
        N)r   concatenater&   array)rW   newvals     r'   _add_newzTopologyAttr._add_new  s,    
 ndk28VH3E3E%FGGr)   c                     t           )z)Get atom attributes for a given AtomGroupr   rW   ags     r'   r   zTopologyAttr.get_atoms      r)   c                     t           )z)Set atom attributes for a given AtomGroupr   rW   r   r&   s      r'   r   zTopologyAttr.set_atoms      !!r)   c                     t           )z/Get residue attributes for a given ResidueGroupr   rW   rgs     r'   r   zTopologyAttr.get_residues#  r   r)   c                     t           )z/Set residue attributes for a given ResidueGroupr   rW   r   r&   s      r'   r   zTopologyAttr.set_residues'  r   r)   c                     t           )z/Get segment attributes for a given SegmentGroupr   rW   sgs     r'   r   zTopologyAttr.get_segments+  r   r)   c                     t           )z.Set segmentattributes for a given SegmentGroupr   rW   r   r&   s      r'   r   zTopologyAttr.set_segments/  r   r)   c                 t    t          | dd          }|t          j        u rt          j        |          S ||k    S )zScheck if an attribute has a missing value

        .. versionadded:: 2.8.0
        missing_value_labelN)getattrr   nanisnan)r+   r&   r   s      r'   are_values_missingzTopologyAttr.are_values_missing3  s@     &c+@$GG"&((8F###000r)   F)NNNN)"r4   r   r   r^   r,   r5   r   topr   listrg   target_classesgroupdoc	singledocr   r   staticmethodr   classmethodr   r   r   r   r   rn   r   r   r   r   r   r   r   r   r   r|   r)   r'   r   r     s        2 HHJ
C+d##KNHIE        7 7 \7 DH   [.I I I     , , ,4 4 4   XH H H  " " "  " " "  " " " 
1 
1 [
1 
1 
1r)   r   )	metaclassc                   H    e Zd ZdZdZdZeeee	gZ
eZd Zd Zd Zd Zd Zd	S )
Atomindicesa  Globally unique indices for each atom in the group.

    If the group is an AtomGroup, then this gives the index for each atom in
    the group. This is the unambiguous identifier for each atom in the
    topology, and it is not alterable.

    If the group is a ResidueGroup or SegmentGroup, then this gives the indices
    of each atom represented in the group in a 1-D array, in the order of the
    elements in that group.

    indicesindexc                     d| _         d S NFr   r   s    r'   r   zAtomindices.__init__V      r)   c                      t          d          )Nz,Atom indices are fixed; they cannot be resetrl   r   s      r'   r   zAtomindices.set_atomsY  s    KLLLr)   c                     |j         S r   ixr   s     r'   r   zAtomindices.get_atoms\  	    ur)   c                 d    t          | j        j                            |j                            S r   )r   r   ttresidues2atoms_2dr   r   s     r'   r   zAtomindices.get_residues_  $    DHK11"%88999r)   c                 d    t          | j        j                            |j                            S r   )r   r   r   segments2atoms_2dr   r   s     r'   r   zAtomindices.get_segmentsb  r   r)   N)r4   r   r   r^   r,   r5   r   r   r   r   r   intr   r   r   r   r   r   r|   r)   r'   r   r   D  s        
 
 HH|TBNE  M M M  : : :: : : : :r)   r   c                   J    e Zd ZdZdZdZeeee	e
gZeZd Zd Zd Zd Zd Zd	S )

Resindicesa  Globally unique resindices for each residue in the group.

    If the group is an AtomGroup, then this gives the resindex for each atom in
    the group. This unambiguously determines each atom's residue membership.
    Resetting these values changes the residue membership of the atoms.

    If the group is a ResidueGroup or SegmentGroup, then this gives the
    resindices of each residue represented in the group in a 1-D array, in the
    order of the elements in that group.

    
resindicesresindexc                     d| _         d S r   r   r   s    r'   r   zResindices.__init__x  r   r)   c                 J    | j         j                            |j                  S r   )r   r   atoms2residuesr   r   s     r'   r   zResindices.get_atoms{      x{))"%000r)   c                     |j         S r   r   r   s     r'   r   zResindices.get_residues~  r   r)   c                      t          d          )Nz/Residue indices are fixed; they cannot be resetr   r   s      r'   r   zResindices.set_residues      NOOOr)   c                 d    t          | j        j                            |j                            S r   )r   r   r   segments2residues_2dr   r   s     r'   r   zResindices.get_segments  s$    DHK44RU;;<<<r)   N)r4   r   r   r^   r,   r5   r   r   r   r   r   r   r  r   r   r   r   r   r   r|   r)   r'   r  r  f  s        
 
 HH|T7KNE  1 1 1  P P P= = = = =r)   r  c                   L    e Zd ZdZdZdZeZee	e
eeegZd Zd Zd Zd Zd Zd	S )

Segindicesa  Globally unique segindices for each segment in the group.

    If the group is an AtomGroup, then this gives the segindex for each atom in
    the group. This unambiguously determines each atom's segment membership.
    It is not possible to set these, since membership in a segment is an
    attribute of each atom's residue.

    If the group is a ResidueGroup or SegmentGroup, then this gives the
    segindices of each segment represented in the group in a 1-D array, in the
    order of the elements in that group.

    
segindicessegindexc                     d| _         d S r   r   r   s    r'   r   zSegindices.__init__  r   r)   c                 J    | j         j                            |j                  S r   )r   r   atoms2segmentsr   r   s     r'   r   zSegindices.get_atoms  r	  r)   c                 J    | j         j                            |j                  S r   )r   r   residues2segmentsr   r   s     r'   r   zSegindices.get_residues  s    x{,,RU333r)   c                     |j         S r   r   r   s     r'   r   zSegindices.get_segments  r   r)   c                      t          d          )Nz/Segment indices are fixed; they cannot be resetr   r   s      r'   r   zSegindices.set_segments  r  r)   N)r4   r   r   r^   r,   r5   r  r   r   r   r   r   r   r   r   r   r   r   r   r   r|   r)   r'   r  r    s          HHEN  1 1 14 4 4  P P P P Pr)   r  c                   Z    e Zd ZdZdZdZeeee	gZ
d Zed             Zd Zd Zd Zd	 Zd
S )rI   zBase class for atom attributes.	atomattrsatomattrc                 &    | j         |j                 S r   r&   r   r   s     r'   r   zAtomAttr.get_atoms      {25!!r)   c                 $    || j         |j        <   d S r   r  r   s      r'   r   zAtomAttr.set_atoms      #BEr)   c                 h      j         j                            |j                  } fd|D             S )By default, the values for each atom present in the set of residues
        are returned in a single array. This behavior can be overriden in child
        attributes.

        c                 *    g | ]}j         |         S r|   r%   .0aixrW   s     r'   
<listcomp>z)AtomAttr.get_residues.<locals>.<listcomp>       111SC 111r)   )r   r   r   r   )rW   r   aixss   `  r'   r   zAtomAttr.get_residues  8     x{,,RU331111D1111r)   c                 "    t          | |          r   rQ   r   s      r'   r   zAtomAttr.set_residues      b)))r)   c                 h      j         j                            |j                  } fd|D             S )r#  c                 *    g | ]}j         |         S r|   r%   r%  s     r'   r(  z)AtomAttr.get_segments.<locals>.<listcomp>  r)  r)   )r   r   r   r   )rW   r   r*  s   `  r'   r   zAtomAttr.get_segments  r+  r)   c                 "    t          | |          r   r-  r   s      r'   r   zAtomAttr.set_segments  r.  r)   N)r4   r   r   r^   r,   r5   r   r   r   r   r   r   r?   r   r   r   r   r   r|   r)   r'   rI   rI     s        ))HH|TBN" " " $ $ ]$2 2 2* * *2 2 2* * * * *r)   rI   c                   8    e Zd ZdZdZdZdZeZe	d             Z
dS )AtomidszID for each atom.idsidrC   c                 2    t          j        d| dz             S Nr   r   arangenanrnss      r'   r   zAtomids._gen_initial_values      yBF###r)   Nr4   r   r   r^   r,   r5   r   r  r   r   r   r|   r)   r'   r3  r3    sG        HHJE$ $ \$ $ $r)   r3  c                   &    e Zd ZdZddZd Zd ZdS )_StringInternerMixina  String interning pattern

    Used for faster matching of strings (see _ProtoStringSelection)

     self.namedict (dict)
     - maps actual string to string index (str->int)
     self.namelookup (array dtype object)
     - maps string index to actual string (int->str)
     self.nmidx (array dtype int)
     - maps atom index to string index (int->int)
     self.values (array dtype object)
     - the premade per-object string values

    .. versionadded:: 2.1.0
       Mashed together the different implementations to keep it DRY.
    Fc                    || _         t                      | _        g }t          j        |t
                    | _        t          |          D ]h\  }}	 | j        |         | j        |<   # t          $ r@ t          | j                  }|| j        |<   |
                    |           || j        |<   Y ew xY wt          j        |t                    | _        | j        | j                 | _        d S r   )r   dictnamedictr   
zeros_liker  nmidx	enumerater   r$   appendr   objectname_lookupr&   )rW   valsr   rJ  ivalnextidxs          r'   r   z_StringInternerMixin.__init__  s     ]4s333
  oo 	( 	(FAs( $c 2
1 ( ( (dm,,%,c"""3''' '
1( 8Kv>>>&tz2s   A((AB21B2c                 F   	 | j         |         }nO# t          $ rB t          | j                   }|| j         |<   t          j        | j        |gg          | _        Y nw xY wt          j        | j        |gg          | _        t          j        | j        |gg          | _        dS )aB  Append new value to the TopologyAttr

        Parameters
        ----------
        newval : str
          value to append

        resizes this attr to size+1 and adds newval as the value of the new entry
        for string interning this is slightly different hence the override

        .. versionadded:: 2.1.0
        N)rD  r   r$   r   r   rJ  rF  r&   )rW   r   newidxs      r'   r   z_StringInternerMixin._add_new  s    	L]6*FF 	L 	L 	L''F$*DM&!!~t/?&.JKKD	L
 ^TZ&$:;;
ndkF8%<==s    A	AAc                 z   g }t          |t                    rR	 | j        |         }n# t          $ r6 t	          | j                  }|| j        |<   |                    |           Y nw xY wt          j        |t                    }t          |          D ]^\  }}	 | j        |         ||<   # t          $ r; t	          | j                  }|| j        |<   |                    |           |||<   Y [w xY w|| j
        |j        <   |r t          j        | j        |g          | _        | j        | j
                 | _        d S r   )r0   strrD  r   r$   rH  r   rE  r  rG  rF  r   r   rJ  r&   )rW   r   r&   newnamesrP  rL  rM  rN  s           r'   _set_Xz_StringInternerMixin._set_X*  sf    fc"" 	((v. ( ( (T]++(.f%'''''(
 ]6555F#F++ ( (3( $c 2F1II ( ( (!$-00G)0DM#&OOC((( 'F1III	(  	
25  	L!~t/?.JKKD&tz2s"   ' =A'&A'B++AC0/C0Nr   )r4   r   r   r^   r   r   rT  r|   r)   r'   rA  rA    sP         "3 3 3 3.> > >.3 3 3 3 3r)   rA  c                   :    e Zd Zed             Zed             ZdS )AtomStringAttrc                 .    |                      ||          S r   rT  r   s      r'   r   zAtomStringAttr.set_atomsK      {{2v&&&r)   c                 :    t          j        | dt                    S Nr   r   r   fullrI  r:  s      r'   r   z"AtomStringAttr._gen_initial_valuesO      wr2V,,,,r)   N)r4   r   r   r?   r   r   r   r|   r)   r'   rV  rV  J  H        ' ' ]' - - \- - -r)   rV  c                      e Zd ZdZdZdZdZeZ e	e
          ZddZee                             d	ef           dd
Zee                             def           ddZee                             def           d Zee                             def           d Zee                             def           ddZee                             def           ddZee                             def           ddZee                             def           	 	 	 	 d dZee                             def           	 	 	 	 d dZee                             def           dS )!	AtomnameszName for each atom.namesr   rC   CNCAc                 6     j         j         j        dz
           } j        j        } j        dz
  }|j        j        |k    r|j        |k    sNd                    ||          }	  j                             |          j        d         }n# t          $ r Y dS w xY w|j	        |j	        j
        |k             }t          |          dk    sdS  j	        j
        |||g}	 fd|	D             }
t          d |
D                       sdS |t          |
          z   }|S )a  Select AtomGroup corresponding to the phi protein backbone dihedral
        C'-N-CA-C.

        Parameters
        ----------
        c_name: str (optional)
            name for the backbone C atom
        n_name: str (optional)
            name for the backbone N atom
        ca_name: str (optional)
            name for the alpha-carbon atom

        Returns
        -------
        AtomGroup
            4-atom selection in the correct order. If no C' found in the
            previous residue (by resid) then this method returns ``None``.

        .. versionchanged:: 1.0.0
            Added arguments for flexible atom names and refactored code for
            faster atom matching with boolean arrays.
        r   segid {} and resid {}r   Nc                 2    g | ]}j         |k             S r|   rB   r&  natnamesrE   s     r'   r(  z+Atomnames.phi_selection.<locals>.<listcomp>  $    @@@gl+@@@r)   c              3   <   K   | ]}t          |          d k    V  dS r   Nr$   r&  r   s     r'   	<genexpr>z*Atomnames.phi_selection.<locals>.<genexpr>  ,      //B3r77a<//////r)   )ri   rD   r   rG   segidresidr2   select_atoms
IndexErrorrB   rb  r$   allsum)rE   c_namen_nameca_nameprevsidridselc_
ncac_namesncacrl  s   `          @r'   phi_selectionzAtomnames.phi_selection^  s>   0 (a8o#ma"c))djC.?.?)00c::C'44S99B1E   ttZ
(F232ww!||4-%gv.
@@@@@Z@@@//$///// 	43t99n
s   %%B 
BBr  c                    | sg S | d         j         }|j        | j        dz
           }| j        }| j        dz
  }||gd}t          j        |j        |k    |j        |k    z            d         }	g }
t          |	          rt          |          }t          ||	         ||	         |	          D ]c\  }}}	 |
                    |                    ||                    j        d         ||<   ?# t          $ r |
                    |           Y `w xY wt          |          }fd|D             }fd| D             }t          j        |          t          j        |          z  }d||
<   t          j        | t"                    }d|| <   ||         }| |         } t          j        |          d         }|j        |j        j        k             }| j        | j        j        |k             }| j        | j        j        |k             }| j        | j        j        k             }d	 t          ||||          D             ||<   t          |          S )
av  Select list of AtomGroups corresponding to the phi protein
        backbone dihedral C'-N-CA-C.

        Parameters
        ----------
        c_name: str (optional)
            name for the backbone C atom
        n_name: str (optional)
            name for the backbone N atom
        ca_name: str (optional)
            name for the alpha-carbon atom

        Returns
        -------
        list of AtomGroups
            4-atom selections in the correct order. If no C' found in the
            previous residue (by resid) then corresponding item in the list
            is ``None``.

        .. versionadded:: 1.0.0
        r   r   rg  c                 R    g | ]#}t          |j        j        k              d k    $S r   ry  rB   rb  )r&  rrz  s     r'   r(  z,Atomnames.phi_selections.<locals>.<listcomp>  s/    EEE1S&011Q6EEEr)   c                 H    g | ]t          fd D                       S )c              3   Z   K   | ]%}t          j        j        |k              d k    V  &dS ro  r  r&  rk  r  s     r'   rr  z6Atomnames.phi_selections.<locals>.<listcomp>.<genexpr>  9      AAAGMQ&''1,AAAAAAr)   rx  r&  r  r  s    @r'   r(  z,Atomnames.phi_selections.<locals>.<listcomp>  G     
 
 
 AAAAjAAAAA
 
 
r)   Fr   Nc                 ,    g | ]}t          |          S r|   ry  r&  rB   s     r'   r(  z,Atomnames.phi_selections.<locals>.<listcomp>  s    EEE%3u::EEEr)   )ri   rD   r   segidsresidsr   wherer$   r   ziprv  r2   rw  rH  ry  r   rE  rI  rB   rb  )rD   rz  r{  r|  ur}  rsidpridr  wixinvalidprevlssr  rL  	keep_prevkeep_reskeepresultskeepixr  rk  cacr  s    `                      @r'   phi_selectionszAtomnames.phi_selections  sk   .  	IQK z(+/*"gv.
% ht+t0CDEEaHs88 	$ZZFtCy$s)S99 & &1a& !szz!Q/?/? @ @ I! LF1II! & & &NN1%%%%%&v;;DEEEEEEE	
 
 
 

 
 
 x	""RXh%7%77W-777DzD>$"Z
(F23N8>/69:^HN0G;<N8>/69:EE3r1b!3D3DEEEG}}s   47C,,DDr  c                 j    d} j         j        } j        dz   }	  j        j         j        dz            }|j         j        |k    r|j        |k    sd}n# t          $ r d}Y nw xY w|rNd                    ||          }	  j                            |          j        d         }n# t          $ r Y dS w xY w|j	        |j	        j
        |k             }	t          |	          dk    sdS  j	        j
        |||g}
 fd|
D             }t          d |D                       sdS t          |          |	z   }|S )	a  Select AtomGroup corresponding to the psi protein backbone dihedral
        N-CA-C-N'.

        Parameters
        ----------
        c_name: str (optional)
            name for the backbone C atom
        n_name: str (optional)
            name for the backbone N atom
        ca_name: str (optional)
            name for the alpha-carbon atom

        Returns
        -------
        AtomGroup
            4-atom selection in the correct order. If no N' found in the
            following residue (by resid) then this method returns ``None``.

        .. versionchanged:: 1.0.0
            Added arguments for flexible atom names and refactored code for
            faster atom matching with boolean arrays.
        Fr   Trg  r   Nc                 2    g | ]}j         |k             S r|   ri  rj  s     r'   r(  z+Atomnames.psi_selection.<locals>.<listcomp>  rm  r)   c              3   <   K   | ]}t          |          d k    V  dS ro  rp  rq  s     r'   rr  z*Atomnames.psi_selection.<locals>.<genexpr>  rs  r)   )rG   rt  ru  ri   rD   r   rw  r2   rv  rB   rb  r$   rx  ry  )rE   rz  r{  r|  _manual_selr~  r  nxtr  n_r  r  rl  s   `           @r'   psi_selectionzAtomnames.psi_selection  s   2 o#ma	#"+GJN;C K%,,c1A1A"	  	 	 	KKK	  	)00c::C&33C88A!D   ttYsy&012ww!||4-%gv.
@@@@@Z@@@//$///// 	4$ii"n
s#   A A#"A#?%B% %
B32B3r  c                 F   	 | d         j         }n# t          $ r | cY S w xY wt          j        dgt	          |           z  t
                    }t          j        t	          |                     }t          | j                  }|t	          |j	                  dz
  k    r| j        |k    }||         }| |         } |j	        | j        dz            x||<   }| j
        }| j        dz   }d}	t          j        |j
        |k    |j        |k    z            d         }
t	          |
          r}t          ||
         ||
         |
          D ]_\  }}}	 |                    |	                    ||                    j	        d         |||         <   E# t          $ r d|||         <   Y \w xY w|S )aX  Select list of Residues corresponding to the next resid for each
        residue in `residues`.

        Returns
        -------
        List of Residues
            List of the next residues in the Universe, by resid and segid.
            If not found, the corresponding item in the list is ``None``.

        .. versionadded:: 1.0.0
        r   Nr   r   rg  )ri   rw  r   r   r$   rI  r9  maxr   rD   r  r  r  r  rv  r2   )rD   r  nxresr   lastnotlastr  r  nridr  r  r  r  rL  s                 r'   _get_next_residues_by_residz%Atomnames._get_next_residues_by_resid
  s   	$AA 	 	 	OOO	$#h--/v>>>Ys8}}%%8;3qz??Q&&&kT)GGB(H*X[1_55b	C"% h
d*szT/ABCCAFs88 	(tCy$s)S99 ( (1a(#$>>#**Q2B2B#C#C#LQ#OE"Q%LL! ( ( (#'E"Q%LLL(s    =FFFr  c                 N   	 | d         j         }n# t          $ r | cY S w xY wt          j        dgt	          |           z            }|j        | j        dz
           x|dd<   }| j        }| j        dz
  }d}t          j	        |j        |k    |j        |k    z            d         }t	          |          rqt          ||         ||         |          D ]S\  }}	}
	 |                    |                    ||	                    j        d         ||
<   ?# t          $ r d||
<   Y Pw xY w|S )a`  Select list of Residues corresponding to the previous resid for each
        residue in `residues`.

        Returns
        -------
        List of Residues
            List of the previous residues in the Universe, by resid and segid.
            If not found, the corresponding item in the list is ``None``.

        .. versionadded:: 1.0.0
        r   Nr   rg  )ri   rw  r   r   r$   rD   r   r  r  r  r  rv  r2   )rD   r  pvresr}  r  r  r  r  r  r  rL  s              r'   _get_prev_residues_by_residz%Atomnames._get_prev_residues_by_resid6  sK   	$AA 	 	 	OOO	$#h--/00*X[1_55aaa4"% ht+t0CDEEaHs88 	$tCy$s)S99 $ $1a$ ~~cjjA.>.>??HKE!HH! $ $ $#E!HHH$s    7DD"!D"r  c                 $   | sg S t          j        dgt          |           z  t                    }|                                 }t          j        |          d         }t          ||                   }| |         } ||gfd|D             }fd| D             }	t          j        |          t          j        |	          z  }
||
         }| |
         } t          j        |
          d         }| j        | j        j        k             }| j        | j        j        |k             }| j        | j        j        |k             }|j        |j        j        k             }d t          ||||          D             |||         <   t          |          S )a{  Select list of AtomGroups corresponding to the psi protein
        backbone dihedral N-CA-C-N'.

        Parameters
        ----------
        c_name: str (optional)
            name for the backbone C atom
        n_name: str (optional)
            name for the backbone N atom
        ca_name: str (optional)
            name for the alpha-carbon atom

        Returns
        -------
        List of AtomGroups
            4-atom selections in the correct order. If no N' found in the
            following residue (by resid) then the corresponding item in the
            list is ``None``.

        .. versionadded:: 1.0.0
        Nr   r   c                 R    g | ]#}t          |j        j        k              d k    $S r  r  )r&  r  r{  s     r'   r(  z,Atomnames.psi_selections.<locals>.<listcomp>{  s/    CCC!C/00A5CCCr)   c                 H    g | ]t          fd D                       S )c              3   Z   K   | ]%}t          j        j        |k              d k    V  &dS ro  r  r  s     r'   rr  z6Atomnames.psi_selections.<locals>.<listcomp>.<genexpr>}  r  r)   r  r  s    @r'   r(  z,Atomnames.psi_selections.<locals>.<listcomp>|  r  r)   c                 ,    g | ]}t          |          S r|   r  r  s     r'   r(  z,Atomnames.psi_selections.<locals>.<listcomp>  s    JJJuE

JJJr)   r   r   r$   rI  r  r  ry  rB   rb  r  r   )rD   rz  r{  r|  r  nxtresrixr  keep_nxtr  r  r  rk  r  r  r  r  s     `             @r'   psi_selectionszAtomnames.psi_selectionsZ  s   .  	I(D6CMM1@@@5577hvq!&+C=gv.
CCCCsCCC
 
 
 

 
 
 x!!BHX$6$66$iD>$"N8>/69:^HN0G;<N8>/69:Ysy&01JJAr1b8I8IJJJFG}}r)   r  c                    d}| j         j        }| j        dz   }	 | j        j        | j        dz            }|j         j        |k    r|j        |k    sd}n# t          $ r d}Y nw xY w|rNd                    ||          }	 | j                            |          j        d         }n# t          $ r Y dS w xY w| j	        | j	        j
        |k             }	| j	        | j	        j
        |k             }
|j	        |j	        j
        |k             }|j	        |j	        j
        |k             }t          d |||	|
fD                       sdS |	|
z   |z   |z   S )a  Select AtomGroup corresponding to the omega protein backbone dihedral
        CA-C-N'-CA'.

        omega describes the -C-N- peptide bond. Typically, it is trans (180
        degrees) although cis-bonds (0 degrees) are also occasionally observed
        (especially near Proline).

        Parameters
        ----------
        c_name: str (optional)
            name for the backbone C atom
        n_name: str (optional)
            name for the backbone N atom
        ca_name: str (optional)
            name for the alpha-carbon atom

        Returns
        -------
        AtomGroup
            4-atom selection in the correct order. If no C' found in the
            previous residue (by resid) then this method returns ``None``.

        .. versionchanged:: 1.0.0
            Added arguments for flexible atom names and refactored code for
            faster atom matching with boolean arrays.
        Fr   Trg  r   Nc              3   <   K   | ]}t          |          d k    V  dS ro  rp  rq  s     r'   rr  z,Atomnames.omega_selection.<locals>.<genexpr>  s,      ;;B3r77a<;;;;;;r)   )rG   rt  ru  ri   rD   r   rw  r2   rv  rB   rb  rx  )rE   rz  r{  r|  r  r~  r  r  r  r  r  r  ca_s                r'   omega_selectionzAtomnames.omega_selection  s   8 o#ma	#"+GJN;C K%,,c1A1A"	  	 	 	KKK	  	)00c::C&33C88A!D   tt ]7=.'9:M'--78Ysy&01i	723;;3B*:;;;;; 	4Av{S  s#   A A! A!=%B# #
B10B1r  c                 *   | sg S t          j        dgt          |           z  t                    }|                                 }t          j        |          d         }t          ||                   }| |         } ||g||gfd|D             }fd| D             }	t          j        |          t          j        |	          z  }
||
         }| |
         } t          j        |
          d         }| j        | j        j        |k             }| j        | j        j        |k             }|j        |j        j        |k             }|j        |j        j        |k             }d t          ||||          D             |||         <   t          |          S )a=  Select list of AtomGroups corresponding to the omega protein
        backbone dihedral CA-C-N'-CA'.

        omega describes the -C-N- peptide bond. Typically, it is trans (180
        degrees) although cis-bonds (0 degrees) are also occasionally observed
        (especially near Proline).

        Parameters
        ----------
        c_name: str (optional)
            name for the backbone C atom
        n_name: str (optional)
            name for the backbone N atom
        ca_name: str (optional)
            name for the alpha-carbon atom

        Returns
        -------
        List of AtomGroups
            4-atom selections in the correct order. If no C' found in the
            previous residue (by resid) then the corresponding item in the
            list is ``None``.

        .. versionadded:: 1.0.0
        Nr   r   c                 H    g | ]t          fd D                       S )c              3   Z   K   | ]%}t          j        j        |k              d k    V  &dS ro  r  r  s     r'   rr  z8Atomnames.omega_selections.<locals>.<listcomp>.<genexpr>  9      ??AGMQ&''1,??????r)   r  )r&  r  nxtatomss    @r'   r(  z.Atomnames.omega_selections.<locals>.<listcomp>  sD     
 
 
DEC????h?????
 
 
r)   c                 H    g | ]t          fd D                       S )c              3   Z   K   | ]%}t          j        j        |k              d k    V  &dS ro  r  r  s     r'   rr  z8Atomnames.omega_selections.<locals>.<listcomp>.<genexpr>  r  r)   r  )r&  r  resatomss    @r'   r(  z.Atomnames.omega_selections.<locals>.<listcomp>  sG     
 
 
 ????h?????
 
 
r)   c                 ,    g | ]}t          |          S r|   r  r  s     r'   r(  z.Atomnames.omega_selections.<locals>.<listcomp>  s    LLLuE

LLLr)   r  )rD   rz  r{  r|  r  r  r  r  r  r  r  r  r  r  r  r  r  r  s                   @@r'   omega_selectionszAtomnames.omega_selections  s   6  	I(D6CMM1@@@5577hvq!&+C=V$V$
 
 
 
IL
 
 

 
 
 

 
 
 x!!BHX$6$66$iD>$"N8>/69:^HN0G;<Ysy&01i	723LLB2s8K8KLLLFG}}r)   r  CBCG CG1 OG OG1 SGc                      ||||g} j         j         fd|D             }t          d |D                       rdS t          |          S )az  Select AtomGroup corresponding to the chi1 sidechain dihedral ``N-CA-CB-*G.``
        The gamma atom is taken to be the heavy atom in the gamma position. If more than one
        heavy atom is present (e.g. CG1 and CG2), the one with the lower number is used (CG1).

        .. warning::

            This numbering of chi1 atoms here in following with the IUPAC 1970 rules.
            However, it should be noted that analyses which use dihedral angles may have
            different definitions. For example, the
            :class:`MDAnalysis.analysis.dihedrals.Janin` class does not incorporate
            amino acids where the gamma atom is not carbon, into its chi1 selections.

        Parameters
        ----------
        c_name: str (optional)
            name for the backbone C atom
        ca_name: str (optional)
            name for the alpha-carbon atom
        cb_name: str (optional)
            name for the beta-carbon atom
        cg_name: str (optional)
            name for the gamma-carbon atom

        Returns
        -------
        AtomGroup
            4-atom selection in the correct order. If no CB and/or CG is found
            then this method returns ``None``.


        .. versionadded:: 0.7.5
        .. versionchanged:: 1.0.0
           Added arguments for flexible atom names and refactored code for
           faster atom matching with boolean arrays.
        c                 t    g | ]4}j         t          j        |                                                   5S r|   rB   r   isinsplitrj  s     r'   r(  z,Atomnames.chi1_selection.<locals>.<listcomp>0  s4    IIIaw}RWWaggii889IIIr)   c              3   <   K   | ]}t          |          d k    V  dS ro  rp  rq  s     r'   rr  z+Atomnames.chi1_selection.<locals>.<genexpr>1  s,      **s2ww!|******r)   N)rB   rb  anyry  )rE   r{  r|  cb_namecg_namerb  agsrl  s   `      @r'   chi1_selectionzAtomnames.chi1_selection  sj    T '73-%IIIII5III**c***** 	43xxr)   r  c                 F   	
  sg S t          j        dgt                     z            }||||g

fd D             }t          j        |          d         } |           j        j        		 fd
D             }d t          | D             ||<   t          |          S )a  Select list of AtomGroups corresponding to the chi1 sidechain dihedral
        N-CA-CB-CG.

        Parameters
        ----------
        c_name: str (optional)
            name for the backbone C atom
        ca_name: str (optional)
            name for the alpha-carbon atom
        cb_name: str (optional)
            name for the beta-carbon atom
        cg_name: str (optional)
            name for the gamma-carbon atom

        Returns
        -------
        List of AtomGroups
            4-atom selections in the correct order. If no CB and/or CG is found
            then the corresponding item in the list is ``None``.

        .. versionadded:: 1.0.0
        Nc                 H    g | ]t          fd D                       S )c              3      K   | ]F}t          t          j        j        j        |                                                    d k    V  GdS ro  )ry  r   r  rB   rb  r  r  s     r'   rr  z7Atomnames.chi1_selections.<locals>.<listcomp>.<genexpr>[  sH      KKBGAGM177995566!;KKKKKKr)   r  )r&  r  rb  s    @r'   r(  z-Atomnames.chi1_selections.<locals>.<listcomp>Z  sG     
 
 
 KKKKUKKKKK
 
 
r)   r   c                 t    g | ]4}j         t          j        |                                                   5S r|   r  )r&  rk  rl  rD   s     r'   r(  z-Atomnames.chi1_selections.<locals>.<listcomp>b  s4    JJJqx~bggqwwyy99:JJJr)   c                 ,    g | ]}t          |          S r|   r  r  s     r'   r(  z-Atomnames.chi1_selections.<locals>.<listcomp>c  s    ===%3u::===r)   )r   r   r$   r  rB   rb  r  r   )rD   r{  r|  r  r  r  r  r  r  rl  rb  s   `        @@r'   chi1_selectionszAtomnames.chi1_selections7  s    <  	I(D6CMM122'73
 
 
 

 
 
 $"D>.&JJJJJEJJJ==39===G}}r)   r  N)rc  rd  re  )rd  re  r  r  )r4   r   r   r^   r,   r5   r   rI  r   r   r   rg   r  r   rH  r  r   r  r  r  r  r  r  r  r  r|   r)   r'   ra  ra  U  st       HHJE+d##K, , , ,\ - @AAA? ? ? ?B $$&6%GHHH5 5 5 5n - @AAA& & &P $$	&(CD    @ $$	&(CD  0 0 0 0d $$&6%GHHH6! 6! 6! 6!p !2O DEEE8 8 8 8t $$&8:J%KLLL "/ / / /b !1> BCCC "- - - -^ $$&7%IJJJJJr)   ra  c                   "    e Zd ZdZdZdZdZeZdS )	AtomtypeszType for each atomtypesr   rC   N	r4   r   r   r^   r,   r5   r   rI  r   r|   r)   r'   r  r  j  s(        HHJEEEr)   r  c                   4    e Zd ZdZdZdZeZed             Z	dS )ElementszElement for each atomelementselementc                 f    t          j        d t          |           D             t                    S )Nc                     g | ]}d S r   r|   r&  rf   s     r'   r(  z0Elements._gen_initial_values.<locals>.<listcomp>}      //////r)   r   r   r   rangerI  r:  s      r'   r   zElements._gen_initial_values{  ,    x//U2YY///v>>>>r)   N)
r4   r   r   r^   r,   r5   rI  r   r   r   r|   r)   r'   r  r  t  sB        HHE? ? \? ? ?r)   r  c                   8    e Zd ZdZdZdZdZeZe	d             Z
dS )RadiizRadii for each atomradiiradiusrC   c                 *    t          j        |           S r   r   zerosr:  s      r'   r   zRadii._gen_initial_values      x||r)   Nr4   r   r   r^   r,   r5   r   floatr   r   r   r|   r)   r'   r  r    sG        HHJE  \  r)   r  c                   8    e Zd ZdZdZdZdZeZe	d             Z
dS )RecordTypeszFor PDB-like formats, indicates if ATOM or HETATM

    Defaults to 'ATOM'

    .. versionchanged:: 0.20.0
       Now stores array of dtype object rather than boolean mapping
    record_typesrecord_typerC   c                 @    t          j        dg| z  t                    S )NATOMr   )r   r   rI  r:  s      r'   r   zRecordTypes._gen_initial_values  s    x2V4444r)   Nr4   r   r   r^   r,   r5   r   rI  r   r   r   r|   r)   r'   r  r    sM          HHJE5 5 \5 5 5r)   r  c                   "    e Zd ZdZdZdZdZeZdS )ChainIDszeChainID per atom

    Note
    ----
    This is an attribute of the Atom, not Residue or Segment
    chainIDschainIDrC   Nr  r|   r)   r'   r  r    s.          HHJEEEr)   r  c            
       r   e Zd ZdZdZdZdZeZ e	e
          Zed             Zed             Zed             Zed             Zed	             Zee                             d
 eeedej                  f           eeeeefD ]0Zee                             d eeedej                  f           1dS )TempfactorszTempfactor for atomsr   
tempfactorrC   c                 *    t          j        |           S r   r  r:  s      r'   r   zTempfactors._gen_initial_values  r  r)   c                 :    | j         j        | j                 j        S )a  Alias for tempfactor

        The bfactor topology attribute is only
        provided as an alias to the tempfactor
        attribute. It will be removed in
        3.0. Please use the tempfactor attribute
        instead.

        .. versionadded:: 2.0.0

        .. deprecated:: 2.0.0
            Will be removed in 3.0.0. Use the
            ``tempfactor`` attribute instead.
        ri   rB   r   r
  r   s    r'   r   zTempfactors.bfactor  s      }"47+66r)   c                 >    || j         j        | j                 _        dS )zLTempfactor alias property for atom

        .. versionadded:: 2.0.0
        Nr  rW   values     r'   bfactor_setterzTempfactors.bfactor_setter  s     38DG$///r)   c                 D    | j         j        | j        j                 j        S )a  Alias for tempfactors

        The bfactor topology attribute is only
        provided as an alias to the tempfactor
        attribute. It will be removed in
        3.0. Please use the tempfactor attribute
        instead.

        .. versionadded:: 2.0.0

        .. deprecated:: 2.0.0
            Will be removed in 3.0.0. Use the
            ``tempfactor`` attribute instead.
        ri   rB   r   r   r   s    r'   r   zTempfactors.bfactors  s      }"4:=1==r)   c                 H    || j         j        | j        j                 _        dS )zWTempfactor alias property for groups of atoms

        .. versionadded:: 2.0.0
        Nr  r  s     r'   bfactors_setterzTempfactors.bfactors_setter  s      :?DJM*666r)   r   Nr   )r4   r   r   r^   r,   r5   r   r  r   r   r   rg   r   r   r~   r   r  r   r  r   rH  rn   r   r   r   r   r   r.   r|   r)   r'   r	  r	    s[       HHJE+d##K  \ 7 7 7" 8 8 8 > > >" ? ? ? 	HHWndGOLLM   WlG\J 
 
E!!?D(:JKK	
 	
 	
 	

 
r)   r	  c                   v   e Zd ZdZdZdZej        Ze	e
eeeegZ ee          Zej        ZdZdZed             Zd Zd Zeeeedd                                                Zee          !                    def           eedd                        Z"ee          !                    de"f           eeeedd                                                Z#ee          !                    de#f           eeed d                                    Z$ee          !                    de$f           eeedd                                    Z%ee          !                    de%f           eeedd                                    Z&ee          !                    de&f           eeeedd                                                Z'ee          !                    de'f           eeed d                                    Z(ee          !                    de(f           d Z)ee          !                    de)f           dS )!MassesmassesmassrC   a-  Mass of each component in the Group.

    If the Group is an AtomGroup, then the masses are for each atom. If the
    Group is a ResidueGroup or SegmentGroup, the masses are for each residue or
    segment, respectively. These are obtained by summation of the member atoms
    for each component.
    zMass of the component.c                 *    t          j        |           S r   r  r:  s      r'   r   zMasses._gen_initial_values  r  r)   c                    | j         j                            |j                  }t	          |j        t          j                  r-| j        t          |                   
                                }nXt          j        t          |                    }t          |          D ]'\  }}| j        |         
                                ||<   (|S r   r   r   r   r   r0   _ixnumbersIntegralr&   tuplery  r   emptyr$   rG  )rW   r   r  r  rL  rows         r'   r   zMasses.get_residues  s    8;0077bfg.// 	3[x15577FF Xc"gg&&F#H-- 3 33 K,0022q		r)   c                 (     j         j                            |j                  }t	          |j        t          j                  r- j        t          |                   
                                }n t          j         fd|D                       }|S )Nc                 N    g | ]!}j         |                                         "S r|   r&   ry  r&  r"  rW   s     r'   r(  z'Masses.get_segments.<locals>.<listcomp>2  s,    JJJ#t{3/3355JJJr)   r   r   r   r   r0   r  r  r  r&   r   ry  r   r   )rW   r   segatomsr  s   `   r'   r   zMasses.get_segments*  s    8;0077bfg.// 	L[x15577FF XJJJJJJJKKFr)   Fr.   c                 L    | j         }|                    |j        |||          S )a<  Center of mass of (compounds of) the group

        .. math::
            \boldsymbol R = \frac{\sum_i m_i \boldsymbol r_i}{\sum m_i}

        where :math:`m_i` is the mass and :math:`\boldsymbol r_i` the
        position of atom :math:`i` in the given
        :class:`MDAnalysis.core.groups.AtomGroup`.
        Centers of mass per :class:`Residue`, :class:`Segment`, molecule, or
        fragment can be obtained by setting the `compound` parameter
        accordingly. If the masses of a compound sum up to zero, the
        center of mass coordinates of that compound will be ``nan`` (not a
        number).

        Parameters
        ----------
        wrap : bool, optional
            If ``True`` and `compound` is ``'group'``, move all atoms to the
            primary unit cell before calculation.
            If ``True`` and `compound` is not ``group``, the
            centers of mass of each compound will be calculated without moving
            any atoms to keep the compounds intact. Instead, the resulting
            center-of-mass position vectors will be moved to the primary unit
            cell after calculation.
        unwrap : bool, optional
            If ``True``, compounds will be unwrapped before computing their
            centers.
        compound : {'group', 'segments', 'residues', 'molecules', 'fragments'},\
                   optional
            If ``'group'``, the center of mass of all atoms in the group will
            be returned as a single position vector. Otherwise, the centers of
            mass of each :class:`Segment`, :class:`Residue`, molecule, or
            fragment will be returned as an array of position vectors, i.e. a 2d
            array.
            Note that, in any case, *only* the positions of :class:`Atoms<Atom>`
            *belonging to the group* will be taken into account.

        Returns
        -------
        center : numpy.ndarray
            Position vector(s) of the center(s) of mass of the group.
            If `compound` was set to ``'group'``, the output will be a single
            position vector.
            If `compound` was set to ``'segments'`` or ``'residues'``, the
            output will be a 2d coordinate array of shape ``(n, 3)`` where ``n``
            is the number of compounds.

        Note
        ----
        This method can only be accessed if the underlying topology has
        information about atomic masses.


        .. versionchanged:: 0.8
           Added `pbc` parameter
        .. versionchanged:: 0.19.0
           Added `compound` parameter
        .. versionchanged:: 0.20.0
           Added ``'molecules'`` and ``'fragments'`` compounds;
           added `unwrap` parameter
        .. versionchanged:: 2.1.0
           Renamed `pbc` kwarg to `wrap`. `pbc` is still accepted but
           is deprecated and will be removed in version 3.0.
        weightswrapcompoundunwrap)rB   centerr  r.   r,  r.  r-  rB   s        r'   center_of_masszMasses.center_of_mass6  s2    J ||Lthv  
 
 	
r)   r1  c                 0    |                      d|          S )a  Total mass of (compounds of) the group.

        Computes the total mass of :class:`Atoms<Atom>` in the group.
        Total masses per :class:`Residue`, :class:`Segment`, molecule, or
        fragment can be obtained by setting the `compound` parameter
        accordingly.

        Parameters
        ----------
        compound : {'group', 'segments', 'residues', 'molecules', 'fragments'},\
                   optional
            If ``'group'``, the total mass of all atoms in the group will be
            returned as a single value. Otherwise, the total masses per
            :class:`Segment`, :class:`Residue`, molecule, or fragment will be
            returned as a 1d array.
            Note that, in any case, *only* the masses of :class:`Atoms<Atom>`
            *belonging to the group* will be taken into account.

        Returns
        -------
        float or numpy.ndarray
            Total mass of (compounds of) the group.
            If `compound` was set to ``'group'``, the output will be a single
            value. Otherwise, the output will be a 1d array of shape ``(n,)``
            where ``n`` is the number of compounds.


        .. versionchanged:: 0.20.0 Added `compound` parameter
        r  r-  
accumulater.   r-  s     r'   
total_masszMasses.total_mass  s    @ 8<<<r)   r7  c                    | j         }|                    |||          }|dk    rB|| j        dddf         z                      d          | j                                        z  }|r|                    d          |z
  }n'|r|                    |d          |z
  }n
|j        |z
  }|j        }t          j        d	t          j	        
          }||dddf         dz  |dddf         dz  z   z                                  |d         d<   ||dddf         z  |dddf         z                                   x|d         d<   |d         d<   ||dddf         z  |dddf         z                                   x|d         d<   |d         d<   ||dddf         dz  |dddf         dz  z   z                                  |d         d<   ||dddf         z  |dddf         z                                   x|d         d<   |d         d<   ||dddf         dz  |dddf         dz  z   z                                  |d         d<   |S )a
  Moment of inertia tensor relative to center of mass.

        Parameters
        ----------
        wrap : bool, optional
            If ``True`` and `compound` is ``'group'``, move all atoms to the
            primary unit cell before calculation.
            If ``True`` and `compound` is not ``group``, the
            centers of mass of each compound will be calculated without moving
            any atoms to keep the compounds intact. Instead, the resulting
            center-of-mass position vectors will be moved to the primary unit
            cell after calculation.
        unwrap : bool, optional
            If ``True``, compounds will be unwrapped before computing their
            centers and tensor of inertia.
        compound : {'group', 'segments', 'residues', 'molecules', 'fragments'},\
                   optional
            `compound` determines the behavior of `wrap`.
            Note that, in any case, *only* the positions of :class:`Atoms<Atom>`
            *belonging to the group* will be taken into account.

        Returns
        -------
        moment_of_inertia : numpy.ndarray
            Moment of inertia tensor as a 3 x 3 numpy array.

        Notes
        -----
        The moment of inertia tensor :math:`\mathsf{I}` is calculated for a group of
        :math:`N` atoms with coordinates :math:`\mathbf{r}_i,\ 1 \le i \le N`
        relative to its center of mass from the relative coordinates

        .. math::
           \mathbf{r}'_i = \mathbf{r}_i - \frac{1}{\sum_{i=1}^{N} m_i} \sum_{i=1}^{N} m_i \mathbf{r}_i

        as

        .. math::
           \mathsf{I} = \sum_{i=1}^{N} m_i \Big[(\mathbf{r}'_i\cdot\mathbf{r}'_i) \sum_{\alpha=1}^{3}
                 \hat{\mathbf{e}}_\alpha \otimes \hat{\mathbf{e}}_\alpha - \mathbf{r}'_i \otimes \mathbf{r}'_i\Big]

        where :math:`\hat{\mathbf{e}}_\alpha` are Cartesian unit vectors, or in Cartesian coordinates

        .. math::
           I_{\alpha,\beta} = \sum_{k=1}^{N} m_k
                 \Big(\big(\sum_{\gamma=1}^3 (x'^{(k)}_{\gamma})^2 \big)\delta_{\alpha,\beta}
                 - x'^{(k)}_{\alpha} x'^{(k)}_{\beta} \Big).

        where :math:`x'^{(k)}_{\alpha}` are the Cartesian coordinates of the
        relative coordinates :math:`\mathbf{r}'_k`.


        .. versionchanged:: 0.8
           Added `pbc` keyword
        .. versionchanged:: 0.20.0
           Added `unwrap` parameter
        .. versionchanged:: 2.1.0
           Renamed `pbc` kwarg to `wrap`. `pbc` is still accepted but
           is deprecated and will be removed in version 3.0.
        r,  r.  r-  r.   Nr   axisFinplace)r-  r=  )rA   rA   r   r   r   )
rB   r1  r  ry  pack_into_boxr.  	positionsr   r  float64)	r.   r,  r.  r-  	atomgroupcomposr  tenss	            r'   moment_of_inertiazMasses.moment_of_inertia  s   B K	&&fx ' 
 
 waaag..33 4    ""#C  	,))%)883>CC 	,""He"DDsJCC%+C! xbj111AAAqD	QQQQTa ?@EEGGQ
$*SAY$6QQQT$B#G#G#I#I"IIQ
T!WQZ$*SAY$6QQQT$B#G#G#I#I"IIQ
T!WQZAAAqD	QQQQTa ?@EEGGQ
$*SAY$6QQQT$B#G#G#I#I"IIQ
T!WQZAAAqD	QQQQTa ?@EEGGQ
r)   rE  c           	      <   | j         }|j        }|                    |          }|r|                    d          |z
  }n
|j        |z
  }t          j        d|t          j        d||                    |                                z  }t          j        |          S )a  Radius of gyration.

        Parameters
        ----------
        wrap : bool, optional
            If ``True``, move all atoms within the primary unit cell before
            calculation. [``False``]


        .. versionchanged:: 0.8
           Added `pbc` keyword
        .. versionchanged:: 2.1.0
           Renamed `pbc` kwarg to `wrap`. `pbc` is still accepted but
           is deprecated and will be removed in version 3.0.
        r,  Fr<  i,i->ij,ij->i)	rB   r  r1  r>  r?  r   einsumr7  sqrt)r.   r,  rY   rA  r  rB  recenteredposrog_sqs           r'   radius_of_gyrationzMasses.radius_of_gyration  s    & K	!&&D&11 	6%33E3BBSHMM%/#5M I	*m]CC 
 ""$$% 	 wvr)   rN  c                 B   d | j         }|j        |                    |||          |dk    rQ|r|                    d          z
  }n(|r|                    d|d          z
  }n
|j        z
  } |          }n|                    |          \  }}}	|r|                    |dd          n|j        t          j        |	d	ft          j	        
          }t          ||          D ]+\  }
fdt          |
          D             |ddf<   ,|S )u"  Moments of the gyration tensor.

        The moments are defined as the eigenvalues of the gyration
        tensor.

        .. math::

            \mathsf{T} = \frac{1}{N} \sum_{i=1}^{N} (\mathbf{r}_\mathrm{i} -
                \mathbf{r}_\mathrm{COM})(\mathbf{r}_\mathrm{i} - \mathbf{r}_\mathrm{COM})

        Where :math:`\mathbf{r}_\mathrm{COM}` is the center of mass.

        See [Dima2004a]_ for background information.

        Parameters
        ----------
        wrap : bool, optional
            If ``True``, move all atoms within the primary unit cell before
            calculation. [``False``]
        unwrap : bool, optional
            If ``True``, compounds will be unwrapped before computing their centers.
        compound : {'group', 'segments', 'residues', 'molecules', 'fragments'}, optional
            Which type of component to keep together during unwrapping.

        Returns
        -------
        principle_moments_of_gyration : numpy.ndarray
            Gyration vector(s) of (compounds of) the group in :math:`Å^2`.
            If `compound` was set to ``'group'``, the output will be a single
            vector of length 3. Otherwise, the output will be a 2D array of shape
            ``(n,3)`` where ``n`` is the number of compounds.


        .. versionadded:: 2.5.0
        c           	         t          |j                  dk    rt          j        |          }t          j        d| t          j        d| |                    }t          j                            |t          j        |          z            S )Nr   	ki,kj->ijij,i->ij)r$   shaper   squeezerJ  linalgeigvalshry  )rL  r  tensors      r'   	_gyrationz*Masses.gyration_moments.<locals>._gyratione  ss    6<  1$$F++Y	*mV<< F
 9%%frvf~~&=>>>r)   r9  r.   Fr<  Nr=  r-  	referencer-  rZ  r=  rA   r   c                 x    g | ]6\  }} |                  |         z
  |         d d d f                   7S r   r|   )r&  rL  maskrX  rB  compound_maskcoordsr  s      r'   r(  z+Masses.gyration_moments.<locals>.<listcomp>  se     . . .
  4	 Its='9!'<<tQQQW- . . .r)   )rB   r  r1  r>  r.  r?  _split_by_compound_indicesr   r!  r@  r  rG  )r.   r,  r.  r-  rA  rL  eig_vals
atom_maskscompound_masksn_compounds	atom_maskrX  rB  r^  r_  r  s              @@@@@r'   gyration_momentszMasses.gyration_moments=  s   P	? 	? 	? K	!&&fx ' 
 
 w : ) 7 7 7 F F L 
:$$ %!)"& %  
   !* 3c 9 y77HH 44X>> 6Z  -"))%u *   #,xa 0
CCCH,/
,K,K  (y. . . . . . . .
 $-Y#7#7. . .)** r)   rf  c                    | j         }|                    |||          }t          |j                  dk    r[dt	          j        |t	          j        |d          z
  d          z  t	          j        t	          j        |d          d          z  }nTdt	          j        |t	          j        |          z
            z  t	          j        t	          j        |          d          z  }|S )a  Shape parameter.

        See [Dima2004a]_ for background information.

        Parameters
        ----------
        wrap : bool, optional
            If ``True``, move all atoms within the primary unit cell before
            calculation. [``False``]
        unwrap : bool, optional
            If ``True``, compounds will be unwrapped before computing their centers.
        compound : {'group', 'segments', 'residues', 'molecules', 'fragments'}, optional
            Which type of component to keep together during unwrapping.


        .. versionadded:: 0.7.7
        .. versionchanged:: 0.8
           Added `pbc` keyword
        .. versionchanged:: 2.1.0
           Renamed `pbc` kwarg to `wrap`. `pbc` is still accepted but
           is deprecated and will be removed in version 3.0.
           Superfluous kwargs were removed.
        .. versionchanged:: 2.5.0
           Added calculation for any `compound` type
        r9  r   g      ;@r:  rA   )	rB   rf  r$   rS  r   prodmeanpowerry  r.   r,  r.  r-  rA  ra  rS  s          r'   shape_parameterzMasses.shape_parameter  s    : K	--fx . 
 
 x~""'(RWXA%>%>%>>QGGGH(26(333Q778 E '(RWX%6%66778(26(++Q//0  r)   rl  c                    | j         }|                    |||          }t          |j                  dk    rNdt	          j        |t	          j        |d          z
  dz  d          t	          j        |d          dz  z  z  }nGdt	          j        |t	          j        |          z
  dz            t	          j        |          dz  z  z  }|S )a  Asphericity.

        See [Dima2004b]_ for background information.

        Parameters
        ----------
        wrap : bool, optional
            If ``True``, move all atoms within the primary unit cell before
            calculation. [``False``]
        unwrap : bool, optional
            If ``True``, compounds will be unwrapped before computing their centers.
        compound : {'group', 'segments', 'residues', 'molecules', 'fragments'}, optional
            Which type of component to keep together during unwrapping.


        .. versionadded:: 0.7.7
        .. versionchanged:: 0.8
           Added `pbc` keyword
        .. versionchanged:: 0.20.0
           Added *unwrap* and *compound* parameter
        .. versionchanged:: 2.1.0
           Renamed `pbc` kwarg to `wrap`. `pbc` is still accepted but
           is deprecated and will be removed in version 3.0.
        .. versionchanged:: 2.5.0
           Added calculation for any `compound` type
        r9  r   g      ?r:  r   )rB   rf  r$   rS  r   ry  ri  rk  s          r'   asphericityzMasses.asphericity  s    > K	--fx . 
 
 x~""278!#<#<#<<BKKK&***a/0EE
 278#4#44:;;&""a'(E
 r)   rn  c                 b   | j         }t          j                            |                    |                    \  }}t          j        |          ddd         }|dd|f         j        }t          j        t          j        |d         |d                   |d                   dk     r|dz  }|S )a  Calculate the principal axes from the moment of inertia.

        e1,e2,e3 = AtomGroup.principal_axes()

        The eigenvectors are sorted by eigenvalue, i.e. the first one
        corresponds to the highest eigenvalue and is thus the first principal
        axes.

        The eigenvectors form a right-handed coordinate system.

        Parameters
        ----------
        wrap : bool, optional
            If ``True``, move all atoms within the primary unit cell before
            calculation. [``False``]

        Returns
        -------
        axis_vectors : array
            3 x 3 array with ``v[0]`` as first, ``v[1]`` as second, and
            ``v[2]`` as third eigenvector.


        .. versionchanged:: 0.8
           Added `pbc` keyword
        .. versionchanged:: 1.0.0
           Always return principal axes in right-hand convention.
        .. versionchanged:: 2.1.0
           Renamed `pbc` kwarg to `wrap`. `pbc` is still accepted but
           is deprecated and will be removed in version 3.0.
        rG  Nr   r   r   )	rB   r   rU  eigrE  argsortTdotcross)r.   r,  rA  e_vale_vecr   s         r'   principal_axeszMasses.principal_axes  s    F K	y}}Y%@%@d%@%K%KLLu *U##DDbD)aaaj!# 6"(58U1X..a99A==RKEr)   rx  c                     |                                  |         }t          j        t          j        ||                    }t          j        ||          }|                     ||          S )a  Align principal axis with index `axis` with `vector`.

        Parameters
        ----------
        axis : {0, 1, 2}
            Index of the principal axis (0, 1, or 2), as produced by
            :meth:`~principal_axes`.
        vector : array_like
            Vector to align principal axis with.

        Notes
        -----
        To align the long axis of a channel (the first principal axis, i.e.
        *axis* = 0) with the z-axis::

          u.atoms.align_principal_axis(0, [0,0,1])
          u.atoms.write("aligned.pdb")
        )rx  r   degreesr   angler   rotaxisrotateby)r.   r;  vectorpr{  axs         r'   align_principal_axiszMasses.align_principal_axis6  s]    &   ""4(
7=F3344$Q// ~~eR(((r)   r  NFFr.   r.   r   )*r4   r   r   r,   r5   r   r   r   r   r   r   r   r   r   r   r   r   r   rg   r@  r   r   r   r   r   r   r   r
   r   r   r   r1  r   rH  r7  rE  rN  rf  rl  rn  rx  r  r|   r)   r'   r  r    s       HHJ&N +d##KJEH -I  \  
 
 
 D
 D
 D
   \ D
L 	!!#3^"DEEE= = =  =@ 	!!<"<===f f f   \ fP 	!!#68I"JKKK" " "  \ "H 	!!#79K"LMMM[ [ [  \ [z 	!!#57G"HIII+ + +  \ +Z 	!!#4o"FGGG* * *   \ *X 	!!=+">???, , ,  \ ,\ 	!!#3^"DEEE) ) )4 	!!	!56    r)   r  c                      e Zd ZdZdZdZeeee	e
egZ ee          ZeZed             Zd Zd Zeeeedd	                                                Zee                             d
ef           eedd                        Zee                             def           eee	 dd                                    Zee                             def           d Zee                             def           eee	 dd                                    Z ee                             de f           d Z!ee                             de!f           dS )ChargeschargeschargerC   c                 *    t          j        |           S r   r  r:  s      r'   r   zCharges._gen_initial_valuese  r  r)   c                    | j         j                            |j                  }t	          |j        t          j                  r-| j        t          |                   
                                }nXt          j        t          |                    }t          |          D ]'\  }}| j        |         
                                ||<   (|S r   r  )rW   r   r  r  rL  r"  s         r'   r   zCharges.get_residuesi  s    8;0077bfg.// 	4k%//26688GGhs2ww''G#H-- 4 43![-1133

r)   c                 (     j         j                            |j                  }t	          |j        t          j                  r- j        t          |                   
                                }n t          j         fd|D                       }|S )Nc                 N    g | ]!}j         |                                         "S r|   r%  r&  s     r'   r(  z(Charges.get_segments.<locals>.<listcomp>}  s,    KKK3C 0 4 4 6 6KKKr)   r'  )rW   r   r(  r  s   `   r'   r   zCharges.get_segmentsu  s    8;0077bfg.// 	Mk%//26688GG hKKKK(KKKLLGr)   Fr.   c                 p    | j         }|                    |j                                        |||          S )a
  Center of (absolute) charge of (compounds of) the group

        .. math::
            \boldsymbol R = \frac{\sum_i \vert q_i \vert \boldsymbol r_i}
                                 {\sum_i \vert q_i \vert}

        where :math:`q_i` is the charge and :math:`\boldsymbol r_i` the
        position of atom :math:`i` in the given
        :class:`MDAnalysis.core.groups.AtomGroup`.
        Centers of charge per :class:`Residue`, :class:`Segment`, molecule, or
        fragment can be obtained by setting the `compound` parameter
        accordingly. If the charges of a compound sum up to zero, the
        center of mass coordinates of that compound will be ``nan`` (not a
        number).

        Parameters
        ----------
        wrap : bool, optional
            If ``True`` and `compound` is ``'group'``, move all atoms to the
            primary unit cell before calculation.
            If ``True`` and `compound` is not ``group``, the
            centers of mass of each compound will be calculated without moving
            any atoms to keep the compounds intact. Instead, the resulting
            center-of-mass position vectors will be moved to the primary unit
            cell after calculation.
        unwrap : bool, optional
            If ``True``, compounds will be unwrapped before computing their
            centers.
        compound : {'group', 'segments', 'residues', 'molecules', \
                    'fragments'}, optional
            If ``'group'``, the center of mass of all atoms in the group will
            be returned as a single position vector. Otherwise, the centers of
            mass of each :class:`Segment`, :class:`Residue`, molecule, or
            fragment will be returned as an array of position vectors, i.e.
            a 2d array.
            Note that, in any case, *only* the positions of
            :class:`Atoms<Atom>` *belonging to the group* will be taken into
            account.

        Returns
        -------
        center : numpy.ndarray
            Position vector(s) of the center(s) of charge of the group.
            If `compound` was set to ``'group'``, the output will be a single
            position vector.
            If `compound` was set to ``'segments'`` or ``'residues'``, the
            output will be a 2d coordinate array of shape ``(n, 3)`` where
            ``n`` is the number of compounds.

        Note
        ----
        This method can only be accessed if the underlying topology has
        information about atomic charges.

        .. versionadded:: 2.2.0
        r*  )rB   r/  r  __abs__r0  s        r'   center_of_chargezCharges.center_of_charge  sA    z ||M))++	  
 
 	
r)   r  c                 0    |                      d|          S )a  Total charge of (compounds of) the group.

        Computes the total charge of :class:`Atoms<Atom>` in the group.
        Total charges per :class:`Residue`, :class:`Segment`, molecule, or
        fragment can be obtained by setting the `compound` parameter
        accordingly.

        Parameters
        ----------
        compound : {'group', 'segments', 'residues', 'molecules', 'fragments'},\
                   optional
            If 'group', the total charge of all atoms in the group will
            be returned as a single value. Otherwise, the total charges per
            :class:`Segment`, :class:`Residue`, molecule, or fragment
            will be returned as a 1d array.
            Note that, in any case, *only* the charges of :class:`Atoms<Atom>`
            *belonging to the group* will be taken into account.

        Returns
        -------
        float or numpy.ndarray
            Total charge of (compounds of) the group.
            If `compound` was set to ``'group'``, the output will be a single
            value. Otherwise, the output will be a 1d array of shape ``(n,)``
            where ``n`` is the number of compounds.


        .. versionchanged:: 0.20.0 Added `compound` parameter
        r  r3  r4  r6  s     r'   total_chargezCharges.total_charge  s    @ 	H===r)   r  r  c           
      p   |                                 }| j        }|j        }|dk    r |j        }|                    |||          }n6|dk    r|                    |||          }nddg}	t          d| d          |dk    ro|r|                    d          |z
  }
n(|r|                    d|d	
          |z
  }
n
|j	        |z
  }
t          j        d|
|d	d	t          j        f                   }n|                    |          \  }}}|r|                    |d	d          }n|j	        }|j        }t          j        |dft          j                  }t!          ||          D ]M\  }}t          j        d||         ||         d	d	d	d	d	f         z
  ||         d	d	d	d	d	f                   ||<   N|S )u	  Dipole vector of the group.

        .. math::
            \boldsymbol{\mu} = \sum_{i=1}^{N} q_{i} ( \mathbf{r}_{i} - 
            \mathbf{r}_{COM} )

        Computes the dipole vector of :class:`Atoms<Atom>` in the group.
        Dipole vector per :class:`Residue`, :class:`Segment`, molecule, or
        fragment can be obtained by setting the `compound` parameter
        accordingly.

        Note that the magnitude of the dipole moment is independent of the
        ``center`` chosen unless the species has a net charge. In the case of
        a charged group the dipole moment can be later adjusted  with:

        .. math::
            \boldsymbol{\mu}_{COC} = \boldsymbol{\mu}_{COM} + 
            q_{ag}\mathbf{r}_{COM} - q_{ag}\boldsymbol{r}_{COC}

        Where :math:`\mathbf{r}_{COM}` is the center of mass and 
        :math:`\mathbf{r}_{COC}` is the center of charge.

        Parameters
        ----------
        wrap : bool, optional
            If ``True`` and `compound` is ``'group'``, move all atoms to the
            primary unit cell before calculation.
            If ``True`` and `compound` is not ``group``, the
            centers of mass of each compound will be calculated without moving
            any atoms to keep the compounds intact.
        unwrap : bool, optional
            If ``True``, compounds will be unwrapped before computing their
            centers.
        compound : {'group', 'segments', 'residues', 'molecules', \
                    'fragments'}, optional
            If ``'group'``, a single dipole vector returns. Otherwise, an
            array of each :class:`Segment`, :class:`Residue`, molecule, or
            fragment will be returned as an array of position vectors, i.e.
            a 2d array.
            Note that, in any case, *only* the positions of
            :class:`Atoms<Atom>` *belonging to the group* will be taken into
            account.
        center : {'mass', 'charge'}, optional
            Choose whether the dipole vector is calculated at the center of 
            "mass" or the center of "charge", default is "mass".

        Returns
        -------
        numpy.ndarray
            Dipole vector(s) of (compounds of) the group in :math:`eÅ`.
            If `compound` was set to ``'group'``, the output will be a single
            value. Otherwise, the output will be a 1d array of shape ``(n,3)``
            where ``n`` is the number of compounds.


        .. versionadded:: 2.4.0
        r  r9  r  zThe dipole center, ,, is not supported. Choose one of: {choices}r.   Fr<  NrY  zij,ij->jr[  rA   r   zijk,ijk->ik)r   rB   r  r  r1  r  r1   r>  r.  r?  r   rJ  newaxisr`  r!  r@  r  )r.   r,  r.  r-  r/  rA  r  r  refchoicesrL  dipole_vectorrb  rc  rd  r_  chgsr^  re  s                      r'   r  zCharges.dipole_vector  sZ   @ >>##K	#V%F**&8 +  CC x,,&8 -  CC x(G%f % % %  
 w : ) 7 7 7 F F L 
:$$ %!)"& %  
   !* 3c 9IM7111bj=+A MM
 44X>> 6Z  -"))%u *   #,$DHk1%5RZHHHM,/
,K,K  (y/1y!I&]);AAAtQQQJ)GGOAAAqqq$J/0 0m,, r)   r  c                     | j         } |j        di |}t          |j                  dk    r)t	          j        t	          j        d||                    }n(t	          j        t	          j        d||                    }|S )u  Dipole moment of the group or compounds in a group.

        .. math::
            \mu = |\boldsymbol{\mu}| = \sqrt{ \sum_{i=1}^{D} \mu^2 }

        Where :math:`D` is the number of dimensions, in this case 3.

        Computes the dipole moment of :class:`Atoms<Atom>` in the group.
        Dipole per :class:`Residue`, :class:`Segment`, molecule, or
        fragment can be obtained by setting the `compound` parameter
        accordingly.

        Note that when there is a net charge, the magnitude of the dipole 
        moment is dependent on the `center` chosen. 
        See :meth:`~dipole_vector`.

        Parameters
        ----------
        wrap : bool, optional
            If ``True`` and `compound` is ``'group'``, move all atoms to the
            primary unit cell before calculation.
            If ``True`` and `compound` is not ``group``, the
            centers of mass of each compound will be calculated without moving
            any atoms to keep the compounds intact.
        unwrap : bool, optional
            If ``True``, compounds will be unwrapped before computing their
            centers.
        compound : {'group', 'segments', 'residues', 'molecules', \
                    'fragments'}, optional
            If ``'group'``, a single dipole vector returns. Otherwise, an
            array of each :class:`Segment`, :class:`Residue`, molecule, or
            fragment will be returned as an array of position vectors, i.e.
            a 2d array.
            Note that, in any case, *only* the positions of
            :class:`Atoms<Atom>` *belonging to the group* will be taken into
            account.
        center : {'mass', 'charge'}, optional
            Choose whether the dipole vector is calculated at the center of 
            "mass" or the center of "charge", default is "mass".

        Returns
        -------
        numpy.ndarray
            Dipole moment(s) of (compounds of) the group in :math:`eÅ`.
            If `compound` was set to ``'group'``, the output will be a single
            value. Otherwise, the output will be a 1d array of shape ``(n,)``
            where ``n`` is the number of compounds.


        .. versionadded:: 2.4.0
        r   rI  rH  r|   )rB   r  r$   rS  r   rK  rJ  )r.   rY   rA  r  dipole_moments        r'   r  zCharges.dipole_momentk	  s    j K	/	/99&99}"##a''G	*m]CC MM G	'=-@@ M r)   r  c                    d |                                 }| j        }|j        }|dk    r |j        }|                    |||          n6|dk    r|                    |||          nddg}t          d| d          |dk    rQ|r|                    d	          z
  }	n(|r|                    d|d
          z
  }	n
|j	        z
  }	 |	|          }
n|
                    |          \  }}}|r|                    |d
d          n|j	        |j        t          j        |ddft          j                  }
t          ||          D ].\  }fdt          |          D             |
d
d
d
d
f<   /|
S )u
  Traceless quadrupole tensor of the group or compounds.

        This tensor is first computed as the outer product of vectors from
        a reference point to some atom, and multiplied by the atomic charge.
        The tensor of each atom is then summed to produce the quadrupole
        tensor of the group:

        .. math::
            \mathsf{Q} = \sum_{i=1}^{N} q_{i} ( \mathbf{r}_{i} - 
            \mathbf{r}_{COM} ) \otimes ( \mathbf{r}_{i} - \mathbf{r}_{COM} )

        The traceless quadrupole tensor, :math:`\hat{\mathsf{Q}}`, is then
        taken from:

        .. math::
            \hat{\mathsf{Q}} = \frac{3}{2} \mathsf{Q} - \frac{1}{2} 
            tr(\mathsf{Q})

        Computes the quadrupole tensor of :class:`Atoms<Atom>` in the group.
        Tensor per :class:`Residue`, :class:`Segment`, molecule, or
        fragment can be obtained by setting the `compound` parameter
        accordingly.

        Note that when there is an unsymmetrical plane in the molecule or 
        group, the magnitude of the quadrupole tensor is dependent on the 
        ``center`` (e.g., :math:`\mathbf{r}_{COM}`) chosen and cannot be translated.

        Parameters
        ----------
        wrap : bool, optional
            If ``True`` and `compound` is ``'group'``, move all atoms to the
            primary unit cell before calculation.
            If ``True`` and `compound` is not ``group``, the
            centers of mass of each compound will be calculated without moving
            any atoms to keep the compounds intact.
        unwrap : bool, optional
            If ``True``, compounds will be unwrapped before computing their
            centers.
        compound : {'group', 'segments', 'residues', 'molecules', \
                    'fragments'}, optional
            If ``'group'``, a single quadrupole value returns. Otherwise, an
            array of each :class:`Segment`, :class:`Residue`, molecule, or
            fragment will be returned as an array of position vectors, i.e.
            a 1d array.
            Note that, in any case, *only* the positions of
            :class:`Atoms<Atom>` *belonging to the group* will be taken into
            account.
        center : {'mass', 'charge'}, optional
            Choose whether the dipole vector is calculated at the center of 
            "mass" or the center of "charge", default is "mass".

        Returns
        -------
        numpy.ndarray
            Quadrupole tensor(s) of (compounds of) the group in :math:`eÅ^2`.
            If `compound` was set to ``'group'``, the output will be a single
            tensor of shape ``(3,3)``. Otherwise, the output will be a 1d array 
            of shape ``(n,3,3)`` where ``n`` is the number of compounds.


        .. versionadded:: 2.4.0
        c           	         t          |j                  dk    rt          j        |          }t          j        d| t          j        d| |                    }d|z  dz  t          j        d          t          j        |          z  dz  z
  S )z)Calculate the traceless quadrupole tensorr   rQ  rR  rA   r   )r$   rS  r   rT  rJ  identitytrace)rL  r  rW  s      r'   __quadrupole_tensorz6Charges.quadrupole_tensor.<locals>.__quadrupole_tensor	  s    7=!!A%%*W--Y	*mW== F
 v:>BKNNRXf5E5E$E$IIIr)   r  r9  r  zThe quadrupole center, r  r.   Fr<  NrY  r[  rA   r   c                 x    g | ]6\  }} |                  |         z
  |         d d d f                   7S r   r|   )r&  rL  r]  _Charges__quadrupole_tensorr  r^  r_  r  s      r'   r(  z-Charges.quadrupole_tensor.<locals>.<listcomp>4
  sf     4 4 4
  4	 ('ts='9!'<<T
111d7+ 4 4 4r)   )r   rB   r  r  r1  r  r1   r>  r.  r?  r`  r   r!  r@  r  rG  )r.   r,  r.  r-  r/  rA  r  r  r  rL  quad_tensorrb  rc  rd  re  r  r  r^  r_  r  s                  @@@@@r'   quadrupole_tensorzCharges.quadrupole_tensor	  s`   J		J 		J 		J >>##K	#V%F**&8 +  CC x,,&8 -  CC x(G%& % % %  
 w : ) 7 7 7 F F L 
:$$ %!)"& %  
   !* 3c 9--mWEEKK 44X>> 6Z  -"))%u *   #,$D(KA#6bjIIIK,/
,K,K  (y4 4 4 4 4 4 4 4
 $-Y#7#74 4 4M111aaa/00 r)   r  c                     | j         }d  |j        di |}t          |j                  dk    r |          }n t	          j        fd|D                       }|S )uH	  Quadrupole moment of the group according to :footcite:p:`Gray1984`.
         
        .. math::
            Q = \sqrt{\frac{2}{3}{\hat{\mathsf{Q}}}:{\hat{\mathsf{Q}}}}

        where the quadrupole moment is calculated from the tensor double 
        contraction of the traceless quadropole tensor :math:`\hat{\mathsf{Q}}`

        Computes the quadrupole moment of :class:`Atoms<Atom>` in the group.
        Quadrupole per :class:`Residue`, :class:`Segment`, molecule, or
        fragment can be obtained by setting the `compound` parameter
        accordingly.

        Note that when there is an unsymmetrical plane in the molecule or 
        group, the magnitude of the quadrupole moment is dependant on the 
        ``center`` chosen and cannot be translated.

        Parameters
        ----------
        wrap : bool, optional
            If ``True`` and `compound` is ``'group'``, move all atoms to the
            primary unit cell before calculation.
            If ``True`` and `compound` is not ``group``, the
            centers of mass of each compound will be calculated without moving
            any atoms to keep the compounds intact.
        unwrap : bool, optional
            If ``True``, compounds will be unwrapped before computing their
            centers.
        compound : {'group', 'segments', 'residues', 'molecules', \
                    'fragments'}, optional
            If ``'group'``, a single quadrupole value returns. Otherwise, an
            array of each :class:`Segment`, :class:`Residue`, molecule, or
            fragment will be returned as an array of position vectors, i.e.
            a 1d array.
            Note that, in any case, *only* the positions of
            :class:`Atoms<Atom>` *belonging to the group* will be taken into
            account.
        center : {'mass', 'charge'}, optional
            Choose whether the dipole vector is calculated at the center of 
            "mass" or the center of "charge", default is "mass".

        Returns
        -------
        numpy.ndarray
            Quadrupole moment(s) of (compounds of) the group in :math:`eÅ^2`.
            If `compound` was set to ``'group'``, the output will be a single
            value. Otherwise, the output will be a 1d array of shape ``(n,)``
            where ``n`` is the number of compounds.


        .. versionadded:: 2.4.0
        c                 \    t          j        dt          j        | |           z  dz            S )Nr   rA   )r   rK  	tensordot)rW  s    r'   __quadrupole_momentz6Charges.quadrupole_moment.<locals>.__quadrupole_momentx
  s(    71r|FF;;;a?@@@r)   r   c                 &    g | ]} |          S r|   r|   )r&  x_Charges__quadrupole_moments     r'   r(  z-Charges.quadrupole_moment.<locals>.<listcomp>
  s%    ===A$$Q''===r)   r|   )rB   r  r$   rS  r   r   )r.   rY   rA  r  quad_momentr  s        @r'   quadrupole_momentzCharges.quadrupole_moment@
  s    l K		A 	A 	A 2i1;;F;;{ !!Q&&--k::KK(======= K r)   r  Nr  r  )FFr.   r  )"r4   r   r   r,   r5   r   r   r   r   r   r   r   r   r   r   rg   r  r   r   r   r   r   r
   r   r   r   r  r   rH  r  r  r  r  r  r|   r)   r'   r  r  V  sV       HHJN +d##KE  \
 
 

 
 
 ?
 ?
 ?
   \ ?
B 	!!#57G"HIII> > >  >@ 	!!><"@AAABHx x x  \ xt 	!!?M"BCCCB B BH 	!!?M"BCCCBHH H H  \ HT 	!!#68I"JKKKD D DL 	!!#68I"JKKKKKr)   r  c                   8    e Zd ZdZdZdZdZeZe	d             Z
dS )FormalChargeszFormal charge on each atomformalchargesformalchargerC   c                 *    t          j        |           S r   r  r:  s      r'   r   z!FormalCharges._gen_initial_values
  r  r)   Nr?  r|   r)   r'   r  r  
  sG        $$HHJE  \  r)   r  c                   4    e Zd ZdZdZdZeZed             Z	dS )Occupanciesoccupancies	occupancyrC   c                 *    t          j        |           S r   r  r:  s      r'   r   zOccupancies._gen_initial_values
  r  r)   N)
r4   r   r   r,   r5   r   r  r   r   r   r|   r)   r'   r  r  
  sA        HHJE  \  r)   r  c                   8    e Zd ZdZdZdZdZeZe	d             Z
dS )AltLocszAltLocs for each atomaltLocsaltLocrC   c                 f    t          j        d t          |           D             t                    S )Nc                     g | ]}d S r  r|   r  s     r'   r(  z/AltLocs._gen_initial_values.<locals>.<listcomp>
  r  r)   r   r  r:  s      r'   r   zAltLocs._gen_initial_values
  r  r)   Nr  r|   r)   r'   r  r  
  sG        HHJE? ? \? ? ?r)   r  c                   8    e Zd ZdZdZdZdZeZe	d             Z
dS )	GBScreensz!Generalized Born screening factor	gbscreensgbscreenrC   c                 *    t          j        |           S r   r  r:  s      r'   r   zGBScreens._gen_initial_values
  r  r)   Nr  r|   r)   r'   r  r  
  sG        ++HHJE  \  r)   r  c                   8    e Zd ZdZdZdZdZeZe	d             Z
dS )SolventRadiizIntrinsic solvation radiussolventradiisolventradiusrC   c                 *    t          j        |           S r   r  r:  s      r'   r   z SolventRadii._gen_initial_values
  r  r)   Nr  r|   r)   r'   r  r  
  sG        $$HHJE  \  r)   r  c                   8    e Zd ZdZdZdZdZeZe	d             Z
dS )NonbondedIndiceszNonbonded index (AMBER)	nbindicesnbindexrC   c                 B    t          j        | t           j                  S r   )r   r  int32r:  s      r'   r   z$NonbondedIndices._gen_initial_values
  s    x"(++++r)   Nr?  r|   r)   r'   r  r  
  sG        !!HHJE, , \, , ,r)   r  c                   8    e Zd ZdZdZdZdZeZe	d             Z
dS )RMinszThe Rmin/2 LJ parameterrminsrminrC   c                 *    t          j        |           S r   r  r:  s      r'   r   zRMins._gen_initial_values
  r  r)   Nr  r|   r)   r'   r  r  
  sG        !!HHJE  \  r)   r  c                   8    e Zd ZdZdZdZdZeZe	d             Z
dS )EpsilonszThe epsilon LJ parameterepsilonsepsilonrC   c                 *    t          j        |           S r   r  r:  s      r'   r   zEpsilons._gen_initial_values
  r  r)   Nr  r|   r)   r'   r  r  
  sG        ""HHJE  \  r)   r  c                   8    e Zd ZdZdZdZdZeZe	d             Z
dS )RMin14sz,The Rmin/2 LJ parameter for 1-4 interactionsrmin14srmin14rC   c                 *    t          j        |           S r   r  r:  s      r'   r   zRMin14s._gen_initial_values
  r  r)   Nr  r|   r)   r'   r  r  
  sG        66HHJE  \  r)   r  c                   8    e Zd ZdZdZdZdZeZe	d             Z
dS )
Epsilon14sz-The epsilon LJ parameter for 1-4 interactions
epsilon14s	epsilon14rC   c                 *    t          j        |           S r   r  r:  s      r'   r   zEpsilon14s._gen_initial_values  r  r)   Nr  r|   r)   r'   r  r  
  sG        77HHJE  \  r)   r  c                   8    e Zd ZdZdZdZdZeZe	d             Z
dS )AromaticitiesAromaticityaromaticitiesaromaticityrC   c                 8    t          j        | t                    S r   )r   r  boolr:  s      r'   r   z!Aromaticities._gen_initial_values  s    x$''''r)   N)r4   r   r   r^   r,   r5   r   r  r   r   r   r|   r)   r'   r  r    sG        HHJE( ( \( ( (r)   r  c                       e Zd ZdZdZdZdZdS )RSChiralityzR/S chiralitychiralities	chiralityU1N)r4   r   r   r^   r,   r5   r   r|   r)   r'   r  r    s#        HHEEEr)   r  c                   \    e Zd ZdZdZeeeee	gZ
dZd Zd Zd Zed             Zd Zd	 Zd
S )rJ   residueattrsresidueattrrE   c                 d    | j         j                            |j                  }| j        |         S r   )r   r   r  r   r&   )rW   r   r  s      r'   r   zResidueAttr.get_atoms&  (    hk((//{3r)   c                 "    t          | |          r   r-  r   s      r'   r   zResidueAttr.set_atoms*  r.  r)   c                 &    | j         |j                 S r   r  r   s     r'   r   zResidueAttr.get_residues-  r  r)   c                 $    || j         |j        <   d S r   r  r   s      r'   r   zResidueAttr.set_residues0  r!  r)   c                 h      j         j                            |j                  } fd|D             S )zBy default, the values for each residue present in the set of
        segments are returned in a single array. This behavior can be overriden
        in child attributes.

        c                 *    g | ]}j         |         S r|   r%   )r&  r  rW   s     r'   r(  z,ResidueAttr.get_segments.<locals>.<listcomp>;  r)  r)   )r   r   r  r   )rW   r   rixss   `  r'   r   zResidueAttr.get_segments4  s8     x{//661111D1111r)   c                 "    t          | |          r   r-  r   s      r'   r   zResidueAttr.set_segments=  r.  r)   N)r4   r   r   r,   r5   r   r   r   r   r   r   r   r   r   r   r?   r   r   r   r|   r)   r'   rJ   rJ      s        HH|T7KNJ     * * *" " " $ $ ]$2 2 2* * * * *r)   rJ   c                   :    e Zd Zed             Zed             ZdS )ResidueStringAttrc                 .    |                      ||          S r   rX  r   s      r'   r   zResidueStringAttr.set_residuesD  rY  r)   c                 :    t          j        |dt                    S r[  r\  r:  s      r'   r   z%ResidueStringAttr._gen_initial_valuesH  r^  r)   N)r4   r   r   r?   r   r   r   r|   r)   r'   r  r  C  r_  r)   r  c                   4    e Zd ZdZdZdZeZed             Z	dS )Residsz
Residue IDr  ru  c                 2    t          j        d|dz             S r7  r8  r:  s      r'   r   zResids._gen_initial_valuesU  r>  r)   N)
r4   r   r   r^   r,   r5   r  r   r   r   r|   r)   r'   r  r  N  sB        HHE$ $ \$ $ $r)   r  c                       e Zd ZdZdZ ee          ZeZ	e
d             Zd Zee                             def           dS )Resnamesresnamesresnamec                 f    t          j        d t          |          D             t                    S )Nc                     g | ]}d S r  r|   r  s     r'   r(  z0Resnames._gen_initial_values.<locals>.<listcomp>c  r  r)   r   r  r:  s      r'   r   zResnames._gen_initial_valuesa  r  r)   c                    t           sd}t          |          d}|                    dd          }||vr6t          d                    |d                    |                              	 d                    d | j        j        D                       }n-# t          $ r }d	|j	         d
}t          |          dd}~ww xY w|dk    r|S t          j                            |          }|dk    r|S t          j        j        |fi |S )a  Returns the amino acid sequence.

        The format of the sequence is selected with the keyword *format*:

        ============== ============================================
        *format*       description
        ============== ============================================
        'SeqRecord'    :class:`Bio.SeqRecord.SeqRecord` (default)
        'Seq'          :class:`Bio.Seq.Seq`
        'string'       string
        ============== ============================================

        The sequence is returned by default (keyword ``format = 'SeqRecord'``)
        as a :class:`Bio.SeqRecord.SeqRecord` instance, which can then be
        further processed. In this case, all keyword arguments (such as the
        *id* string or the *name* or the *description*) are directly passed to
        :class:`Bio.SeqRecord.SeqRecord`.

        If the keyword *format* is set to ``'Seq'``, all *kwargs* are ignored
        and a :class:`Bio.Seq.Seq` instance is returned. The difference to the
        record is that the record also contains metadata and can be directly
        used as an input for other functions in :mod:`Bio`.

        If the keyword *format* is set to ``'string'``, all *kwargs* are
        ignored and a Python string is returned.

        .. rubric:: Example: Write FASTA file

        Use :func:`Bio.SeqIO.write`, which takes sequence records::

           import Bio.SeqIO

           # get the sequence record of a protein component of a Universe
           protein = u.select_atoms("protein")
           record = protein.sequence(id="myseq1", name="myprotein")

           Bio.SeqIO.write(record, "single.fasta", "fasta")

        A FASTA file with multiple entries can be written with ::

           Bio.SeqIO.write([record1, record2, ...], "multi.fasta", "fasta")

        Parameters
        ----------
        format : string, optional
           - ``"string"``: return sequence as a string of 1-letter codes
           - ``"Seq"``: return a :class:`Bio.Seq.Seq` instance
           - ``"SeqRecord"``: return a :class:`Bio.SeqRecord.SeqRecord`
             instance

            Default is ``"SeqRecord"``
        id : optional
           Sequence ID for SeqRecord (should be different for different
           sequences)
        name : optional
           Name of the protein.
        description : optional
           Short description of the sequence.
        kwargs : optional
           Any other keyword arguments that are understood by
           class:`Bio.SeqRecord.SeqRecord`.

        Raises
        ------
        :exc:`ValueError` if a residue name cannot be converted to a
        1-letter IUPAC protein amino acid code; make sure to only
        select protein residues.

        :exc:`TypeError` if an unknown *format* is selected.

        :exc:`ImportError` is the Biopython package is not available.


        .. versionadded:: 0.9.0
        .. versionchanged:: 2.7.0
           Biopython is now an optional dependency
        zThe `sequence_alignment` method requires an installation of `Biopython`. Please install `Biopython` to use this method: https://biopython.org/wiki/Download)stringSeq	SeqRecordr2   r  z)Unknown format='{0}': must be one of: {1}, r   c                 ,    g | ]}t          |          S r|   )r   )r&  r  s     r'   r(  z%Resnames.sequence.<locals>.<listcomp>  s     DDD##DDDr)   z#AtomGroup contains a residue name 'z7' that does not have a IUPAC protein 1-letter characterNr  r  )HAS_BIOPYTHONImportErrorpop	TypeErrorr2   joinrD   r  r   rZ   r1   Bior  r  )rW   rY   errmsgformatsr2   sequenceerrseqs           r'   r  zResnames.sequencee  sR   \  	&6  f%%%0Hk22  ;BBDIIg..   
		/wwDDT]-CDDD HH  	/ 	/ 	/Eck E E E  V$$$.	/ XOgkk(##U??J}&s55f555s   ,)B 
C  B;;C r  N)r4   r   r   r,   r5   r   r   rg   rI  r   r   r   r  r   rH  r|   r)   r'   r   r   [  sz        HH+d##KE? ? \?o6 o6 o6b $$j(%;<<<<<r)   r   c                   0    e Zd ZdZdZeZed             ZdS )Resnumsresnumsresnumc                 2    t          j        d|dz             S r7  r8  r:  s      r'   r   zResnums._gen_initial_values  r>  r)   N)	r4   r   r   r,   r5   r  r   r   r   r|   r)   r'   r  r    s<        HHE$ $ \$ $ $r)   r  c                       e Zd ZdZdZdZeZdS )ICodeszInsertion code for AtomsicodesicodeNr4   r   r   r^   r,   r5   rI  r   r|   r)   r'   r  r    s#        ""HHEEEr)   r  c                       e Zd ZdZdZdZeZdS )MoltypesznName of the molecule type

    Two molecules that share a molecule type share a common template topology.
    moltypesmoltypeNr  r|   r)   r'   r!  r!    s)         
 HHEEEr)   r!  c                   (    e Zd ZdZdZdZej        ZdS )MolnumszIndex of molecule from 0molnumsmolnumN)	r4   r   r   r^   r,   r5   r   intpr   r|   r)   r'   r%  r%    s%        ""HHGEEEr)   r%  c                   b    e Zd ZdZdZdZeeee	e
egZdZd Zd Zd Zd Zd	 Zed
             ZdS )rK   z"Base class for segment attributes.segmentattrssegmentattrrG   c                 d    | j         j                            |j                  }| j        |         S r   )r   r   r  r   r&   )rW   r   sixs      r'   r   zSegmentAttr.get_atoms  r  r)   c                 "    t          | |          r   r-  r   s      r'   r   zSegmentAttr.set_atoms  r.  r)   c                 d    | j         j                            |j                  }| j        |         S r   )r   r   r  r   r&   )rW   r   r-  s      r'   r   zSegmentAttr.get_residues  s(    hk++BE22{3r)   c                 "    t          | |          r   r-  r   s      r'   r   zSegmentAttr.set_residues  r.  r)   c                 &    | j         |j                 S r   r  r   s     r'   r   zSegmentAttr.get_segments  r  r)   c                 $    || j         |j        <   d S r   r  r   s      r'   r   zSegmentAttr.set_segments"  r!  r)   N)r4   r   r   r^   r,   r5   r   r   r   r   r   r   r   r   r   r   r   r   r   r?   r   r|   r)   r'   rK   rK     s        ,,HHN J     * * *     * * *" " " $ $ ]$ $ $r)   rK   c                   :    e Zd Zed             Zed             ZdS )SegmentStringAttrc                 .    |                      ||          S r   rX  r   s      r'   r   zSegmentStringAttr.set_segments*  rY  r)   c                 :    t          j        |dt                    S r[  r\  r:  s      r'   r   z%SegmentStringAttr._gen_initial_values.  r^  r)   N)r4   r   r   r?   r   r   r   r|   r)   r'   r4  r4  )  r_  r)   r4  c                   F    e Zd ZdZdZ ee          ZeZ	e
d             ZdS )Segidsr  rt  c                 f    t          j        d t          |          D             t                    S )Nc                     g | ]}d S r  r|   r  s     r'   r(  z.Segids._gen_initial_values.<locals>.<listcomp><  r  r)   r   r  r:  s      r'   r   zSegids._gen_initial_values:  r  r)   N)r4   r   r   r,   r5   r   r   rg   rI  r   r   r   r|   r)   r'   r8  r8  4  sK        HH+d##KE? ? \? ? ?r)   r8  c                 F     t          j                    fd            }|S )a  
    Checks values passed to _Connection methods for:
     - appropriate number of atom indices
     - coerces them to tuples of ints (for hashing)
     - ensures that first value is less than last (reversibility & hashing)

    .. versionadded:: 1.0.0

    c                 <    t           fd|D                       s-t          d                     j         j                            g }|D ]A}|d         |d         k    r|d d d         }|                    t          |                     B  |g|R i |S )Nc              3   z   K   | ]5}t          |          j        k    ot          d  |D                       V  6dS )c              3   X   K   | ]%}t          |t          t          j        f          V  &d S r   )r0   r  r   integer)r&  ys     r'   rr  zF_check_connection_values.<locals>.wrapper.<locals>.<genexpr>.<genexpr>N  s3      @@Jq3
"344@@@@@@r)   N)r$   _n_atomsrx  )r&  r  rW   s     r'   rr  z<_check_connection_values.<locals>.wrapper.<locals>.<genexpr>L  sf       
 
  FFdm# A@@a@@@@@
 
 
 
 
 
r)   z5{} must be an iterable of tuples with {} atom indicesr   rp  )rx  r1   r2   r,   rA  rH  r   )rW   r&   rX   rY   r   vr:   s   `     r'   r;   z)_check_connection_values.<locals>.wrapperJ  s     
 
 
 
 
 
 
 
 
 		
 N&66  
  	# 	#Atae||dddGLLq""""tD%1$111&111r)   r<   r}   s   ` r'   _check_connection_valuesrC  ?  s:     _T2 2 2 2 2& Nr)   c                   "     e Zd ZdZ fdZ xZS )_ConnectionTopologyAttrMetaz
    Specific metaclass for atom-connectivity topology attributes.

    This class adds an ``intra_{attrname}`` property to groups
    to return only the connections within the atoms in the group.
    c                 .   t                                          |||           |                    d          Xfd}t          ||           }t	          |d d |j                  }| j        t                                       d |f           d S d S )Nr,   c                 2    |                     d          S )z*Get connections only within this AtomGroupF)outside)get_connections)rW   r   r,   s     r'   intra_connectionz>_ConnectionTopologyAttrMeta.__init__.<locals>.intra_connectionp  s    ))(E)BBBr)   intra_)	superr   r   r   rn   r^   rg   r   rH  )	r+   r   r   r   rJ  ra   propr,   r3   s	          @r'   r   z$_ConnectionTopologyAttrMeta.__init__i  s    ui000==,,C C C C C   0#66FFD$??DOI&--/B/B/BD.IJJJJJ  r)   )r4   r   r   r^   r   __classcell__)r3   s   @r'   rE  rE  a  sK         K K K K K K K K Kr)   rE  c                       e Zd ZdZedd            Zd Zd Ze e	d          d                         Z
d	 Zd
 Zedd            Zed             ZdS )_ConnectionzBase class for connectivity between atoms

    .. versionchanged:: 1.0.0
        Added type checking to atom index values.
    NFc                     || _         |d gt          |          z  }|| _        |dv r|gt          |          z  }|| _        |d gt          |          z  }|| _        t                      | _        d S )NTF)r&   r$   r  r   orderrC  _cache)rW   r&   r  r   rS  s        r'   r   z_Connection.__init__  sz    =FS[[(E
m## i#f++-G=FS[[(E
ffr)   c                     |                      t          j        | j                  t          j        | j                  t          j        | j                  t          j        | j                            S )r   )r3   r   r&   r  r   rS  r   s    r'   r   z_Connection.copy  sT    ~~Idk""Idj!!Idm$$Idj!!	
 
 	
r)   c                 *    t          | j                  S r   )r$   	_bondDictr   s    r'   r   z_Connection.__len__  s    4>"""r)   bdc                     t          t                    }t          | j        | j        | j        | j                  D ]+\  }}}}|D ]!}||                             ||||f           ",|S )z#Lazily built mapping of atoms:bonds)r   r   r  r&   r  r   rS  rH  )rW   rX  btgoas          r'   rW  z_Connection._bondDict  s     KT]DJ
 
 	+ 	+JAq!Q  + +1aAq\****+	r)   c                      t          d          S )NzCannot set bond informationr   r   s     r'   r   z_Connection.set_atoms  s    "#@AAAr)   c                 t    	 t          t          j         fd|j        D                        }n"# t          $ r  j        |j                 }Y nw xY wt          j        t          |          t                    }t          j
        |d          \  }}}}t          j        |                                                                t          j                  }|                                }|                                }|                                }t          ||j         j        dd         |||          S )z
        Get connection values where the atom indices are in
        the given atomgroup.

        Parameters
        ----------
        ag : AtomGroup

        c                 *    g | ]}j         |         S r|   )rW  )r&  r^  rW   s     r'   r(  z)_Connection.get_atoms.<locals>.<listcomp>  s     !C!C!C$."3!C!C!Cr)   r      Nrp  )set	itertoolschainr   r  rW  r   r   sortedrI  hsplitraveltolistr  r   ri   r5   )rW   r   unique_bondsbond_idxr  r   rS  s   `      r'   r   z_Connection.get_atoms  s    	1!C!C!C!CRU!C!C!CD LL  	1 	1 	1>"%0LLL	1 x| 4 4FCCC*,)L!*D*D'%%8HNN,,3355RXFFF--//bk4="#5ugu
 
 	
s   ,0 AATc                    |t          j        d          }|dv rt          j        |f          }|t          j        d          }t          | j                  }t	          ||||          D ]s\  }}}}	||vrh| j                            |           | j                            |           | j                            |           | j                            |	           t	 | j	        d= d S # t          $ r Y d S w xY w)Nr   rR  rX  )rd  cyclerc  r&   r  rH  r  r   rS  rT  r   )
rW   r&   r  r   rS  existingrB  r[  r\  r]  s
             r'   
_add_bondsz_Connection._add_bonds  s   =OG,,Em##owj11G=OG,,Et{##feWe<< 	% 	%JAq!Q  ""1%%%
!!!$$$$$Q'''
!!!$$$	D!!! 	 	 	DD	s   !C+ +
C98C9c                   
 t          |          
t          | j                  }
                    |          sV
|z
  }d                    t	          t
          |                    }t          d                    | j        |                    
fdt          | j                  D             }t          |d          D ]
}| j        |= dD ]Y}t          j        t          | |          d	          }t          j        ||          }	t          | |t!          |	                     Z	 | j        d
= dS # t$          $ r Y dS w xY w)z)
        .. versionadded:: 1.0.0
        r	  z@Cannot delete nonexistent {attrname} with atom indices:{indices})r,   r   c                 "    g | ]\  }}|v 	|S r|   r|   )r&  rL  r  to_checks      r'   r(  z-_Connection._delete_bonds.<locals>.<listcomp>  s"    EEETQqH}}q}}}r)   T)reverse)r  r   rS  rI  r   rX  N)rc  r&   issubsetr  maprR  r1   r2   r,   rG  rf  r   r   r   deleterm   r   rT  r   )rW   r&   self_valuesmissingr   idxrL  r6   arrnewrr  s             @r'   _delete_bondsz_Connection._delete_bonds  sc    v;;$+&&  -- 		,GiiC 1 122G  &$-&AA   FEEEYt{33EEET*** 	 	AA2 	+ 	+D(74..h???C)C%%CD$S		****	D!!! 	 	 	DD	s   )D3 3
E E)NFN)NTN)r4   r   r   r^   rC  r   r   r   rn   r   rW  r   r   ro  r|  r|   r)   r'   rP  rP  y  s             
 
 
# # # VD\\	 	 \ X	B B B
 
 
6    (     r)   rP  c            	          e Zd ZdZdZdZ ee          ZdZ	d Z
ee                             d ee
dde
j                  f           d Z edd	
          d             Zd Z edd	
          d             Zd Zee                             d eeddej                  f           ee                             d eeddej                  f           ee                             d eeddej                  f           ee                             d eeddej                  f           ee                             d eeddej                  f           dS )BondszBonds between two atoms

    Must be initialised by a list of zero based tuples.
    These indices refer to the atom indices.
    E.g., ` [(0, 1), (1, 2), (2, 3)]`

    Also adds the `bonded_atoms`, `fragment` and `fragments`
    attributes.
    bondsr   c                 N      fd j         D             } j        j        |         S )zAn :class:`~MDAnalysis.core.groups.AtomGroup` of all
        :class:`Atoms<MDAnalysis.core.groups.Atom>` bonded to this
        :class:`~MDAnalysis.core.groups.Atom`.c                 D    g | ]}|                               j        S r|   )partnerr   )r&  rZ  rW   s     r'   r(  z&Bonds.bonded_atoms.<locals>.<listcomp>  s&    999qyy$999r)   )r  ri   rB   )rW   ry  s   ` r'   bonded_atomszBonds.bonded_atoms  s0     :999dj999}"3''r)   r  Nc                 :    | j         j        | j                 j        S )zThe index (ID) of the
        :class:`~MDAnalysis.core.topologyattrs.Bonds.fragment` this
        :class:`~MDAnalysis.core.groups.Atom` is part of.


        .. versionadded:: 0.20.0
        )ri   	_fragdictr   r   s    r'   	fragindexzBonds.fragindex  s     }&tw/22r)   fragindicesT)universe_validationc                 ~    | j         j        t          j        fd| j        D             t          j                  S )a  The
        :class:`fragment indices<MDAnalysis.core.topologyattrs.Bonds.fragindex>`
        of all :class:`Atoms<MDAnalysis.core.groups.Atom>` in this
        :class:`~MDAnalysis.core.groups.AtomGroup`.

        A :class:`numpy.ndarray` with
        :attr:`~numpy.ndarray.shape`\ ``=(``\ :attr:`~AtomGroup.n_atoms`\ ``,)``
        and :attr:`~numpy.ndarray.dtype`\ ``=numpy.int64``.


        .. versionadded:: 0.20.0
        c                 *    g | ]}|         j         S r|   r   r&  r'  fragdicts     r'   r(  z%Bonds.fragindices.<locals>.<listcomp>7  s     ===c#)===r)   r   )ri   r  r   r   r   r(  rW   r  s    @r'   r  zBonds.fragindices(  s=     =*x====TW===RWMMMMr)   c                 :    | j         j        | j                 j        S )ab  An :class:`~MDAnalysis.core.groups.AtomGroup` representing the
        fragment this :class:`~MDAnalysis.core.groups.Atom` is part of.

        A fragment is a
        :class:`group of atoms<MDAnalysis.core.groups.AtomGroup>` which are
        interconnected by :class:`~MDAnalysis.core.topologyattrs.Bonds`, i.e.,
        there exists a path along one
        or more :class:`~MDAnalysis.core.topologyattrs.Bonds` between any pair
        of :class:`Atoms<MDAnalysis.core.groups.Atom>`
        within a fragment. Thus, a fragment typically corresponds to a molecule.


        .. versionadded:: 0.9.0
        )ri   r  r   fragmentr   s    r'   r  zBonds.fragment9  s     }&tw/88r)   	fragmentsc                     | j         j        t          t          t	          fd| j        D                       d                     S )a  Read-only :class:`tuple` of
        :class:`fragments<MDAnalysis.core.topologyattrs.Bonds.fragment>`.

        Contains all fragments that
        any :class:`~MDAnalysis.core.groups.Atom` in this
        :class:`~MDAnalysis.core.groups.AtomGroup` is part of.

        A fragment is a
        :class:`group of atoms<MDAnalysis.core.groups.AtomGroup>` which are
        interconnected by :class:`~MDAnalysis.core.topologyattrs.Bonds`, i.e.,
        there exists a path along one
        or more :class:`~MDAnalysis.core.topologyattrs.Bonds` between any pair
        of :class:`Atoms<MDAnalysis.core.groups.Atom>`
        within a fragment. Thus, a fragment typically corresponds to a molecule.

        Note
        ----
        * The contents of the fragments may extend beyond the contents of this
          :class:`~MDAnalysis.core.groups.AtomGroup`.


        .. versionadded:: 0.9.0
        c              3   2   K   | ]}|         j         V  d S r   )r  r  s     r'   rr  z"Bonds.fragments.<locals>.<genexpr>f  s*      >>sHSM*>>>>>>r)   c                     | d         j         S r#   r   )r  s    r'   <lambda>z!Bonds.fragments.<locals>.<lambda>g  s    adg r)   )key)ri   r  r   rf  rc  r   r  s    @r'   r  zBonds.fragmentsJ  s[    2 =*>>>>dg>>>>>%%  
 
 	
r)   c                 D    t          t          | j                            S )a   The number of unique
        :class:`~MDAnalysis.core.topologyattrs.Bonds.fragments` the
        :class:`Atoms<MDAnalysis.core.groups.Atom>` of this
        :class:`~MDAnalysis.core.groups.AtomGroup` are part of.


        .. versionadded:: 0.20.0
        )r$   r   r  r   s    r'   n_fragmentszBonds.n_fragmentsk  s     =!122333r)   r  r  r  )r4   r   r   r^   r,   r5   r   r   rg   rA  r  r   rH  rn   r  r   r  r  r  r  r   r|   r)   r'   r~  r~    s5         H H+d##KH( ( ( H\4|/CDD	
  3 3 3 VMt444N N 54N 9 9 9" VKT222
 
 32
@	4 	4 	4 	XXhdH4DEEF   	hhy$i6GHHI   	!!	hhy$i6GHHI   	!!	dD+:MNNO   	!!	dD+:MNNO    r)   r~  c                   4    e Zd ZdZdZdZ ee          ZdZ	dS )UreyBradleyszAngles between two atoms

    Initialise with a list of 2 long tuples

    These indices refer to the atom indices.

    .. versionadded:: 1.0.0
    ureybradleysr   N
r4   r   r   r^   r,   r5   r   r   rg   rA  r|   r)   r'   r  r    s8          HH+d##KHHHr)   r  c                   4    e Zd ZdZdZdZ ee          ZdZ	dS )AngleszAngles between three atoms

    Initialise with a list of 3 long tuples
    E.g.,  `[(0, 1, 2), (1, 2, 3), (2, 3, 4)]`

    These indices refer to the atom indices.
    anglesrA   Nr  r|   r)   r'   r  r    s8          HH+d##KHHHr)   r  c                   4    e Zd ZdZdZdZ ee          ZdZ	dS )	Dihedralsz*A connection between four sequential atoms	dihedralsrb  Nr  r|   r)   r'   r  r    s2        44HH+d##KHHHr)   r  c                   4    e Zd ZdZdZdZ ee          ZdZ	dS )	Impropersz(An imaginary dihedral between four atoms	impropersrb  Nr  r|   r)   r'   r  r    s2        22HH+d##KHHHr)   r  c                   4    e Zd ZdZdZdZ ee          ZdZ	dS )CMapszE
    A connection between five atoms
    .. versionadded:: 1.0.0
    cmaps   Nr  r|   r)   r'   r  r    s8         
 HH+d##KHHHr)   r  )nr^   collectionsr   r   r=   rd  r  inspectr   r_   rx   r\   r  r   Bio.Seqr  Bio.SeqRecordr  r  numpyr   lib.utilr   r   r	   r
   r   r   libr   r   
exceptionsr   r   topologyobjectsr   r   r   groupsr   r   r   r   r   r   r   r   r   r   r   r   r    r?   rQ   rc   ru   rz   r~   r   r   rI  r   r   r  r  rI   r3  rA  rV  ra  r  r  r  r  r  r	  r  r  r  r  r  r  r  r  r  r  r  r  r  r  rJ   r  r  r   r  r  r!  r%  rK   r4  r8  rC  rE  rP  r~  r  r  r  r  r  r|   r)   r'   <module>r     s?  0 " $ # # # # #           2 2 2 2 2 2        NNN MM    MMM
                    + * * * * * * * 4 4 4 4 4 4 4 4 * * * * * *                              K J J J J J J J J JE E EP2 2 2j7 7 7t(7 (7 (7Z   VC VC VC VC VC VC VC VCrV1 V1 V1 V1 V16%6 V1 V1 V1 V1x: : : : :, : : :D= = = = = = = =D'P 'P 'P 'P 'P 'P 'P 'PZ$* $* $* $* $*| $* $* $*P
$ 
$ 
$ 
$ 
$h 
$ 
$ 
$[3 [3 [3 [3 [3 [3 [3 [3@- - - - -)8 - - -QK QK QK QK QK QK QK QKj       	? 	? 	? 	? 	?~ 	? 	? 	?
 
 
 
 
H 
 
 
5 5 5 5 5. 5 5 5&    ~   L
 L
 L
 L
 L
( L
 L
 L
^T	 T	 T	 T	 T	X T	 T	 T	ppL pL pL pL pLh pL pL pLf
 
 
 
 
H 
 
 
    (   
? 
? 
? 
? 
?n 
? 
? 
?
 
 
 
 
 
 
 

 
 
 
 
8 
 
 

, 
, 
, 
, 
,x 
, 
, 
,
 
 
 
 
H 
 
 

 
 
 
 
x 
 
 

 
 
 
 
h 
 
 

 
 
 
 
 
 
 

( 
( 
( 
( 
(H 
( 
( 
(    (   * * * * *, * * *F- - - - -,k - - -	$ 	$ 	$ 	$ 	$[ 	$ 	$ 	${= {= {= {= {=  {= {= {=~$ $ $ $ $k $ $ $                   k   "$ "$ "$ "$ "$, "$ "$ "$N- - - - -,k - - -? ? ? ? ? ? ? ?  DK K K K K"3 K K K0B B B B B(&A B B B BJJ J J J JK J J JZ    ;        [                 	 	 	 	 	K 	 	 	 	 	s   9 AA