
     i2                         d 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	m
Z
mZ ddlmZ ddlmZmZ  ej        e          Z e
d	          d
             Z G d de          Zd ZdS )a  
Polymer analysis --- :mod:`MDAnalysis.analysis.polymer`
=======================================================


:Author: Richard J. Gowers
:Year: 2015, 2018
:Copyright: Lesser GNU Public License v2.1+

This module contains various commonly used tools in analysing polymers.
    N   )NoDataError)requires	AtomGroup)
calc_bonds   )AnalysisBaseResultsGroupbondsc                 x     fd D             }d t           |          D             }d t           |          D             }t          |          dk    r?t          d                    d                    d |D                                           t          |          dk    r?t          d	                    d                    d
 |D                                           t          |d         g          }t          t                     dz
            D ]}|d         }|j         z  |z
  }||z  }|S )a  Rearrange a linear AtomGroup into backbone order

    Requires that the backbone has bond information,
    and that only backbone atoms are provided (ie no side
    chains or hydrogens).

    Parameters
    ----------
    backbone : AtomGroup
      the backbone atoms, not necessarily in order

    Returns
    -------
    sorted_backbone : AtomGroup
      backbone in order, so `sorted_backbone[i]` is bonded to
      `sorted_backbone[i - 1]` and `sorted_backbone[i + 1]`


    .. versionadded:: 0.20.0
    c                 >    g | ]}t          |j        z            S  )lenbonded_atoms).0atombackbones     e/srv/www/vhosts/g4struct/public_html/venv/lib/python3.11/site-packages/MDAnalysis/analysis/polymer.py
<listcomp>z!sort_backbone.<locals>.<listcomp>F   s)    FFFTs4$x/00FFF    c                 $    g | ]\  }}|d k    |S )r   r   r   r   ds      r   r   z!sort_backbone.<locals>.<listcomp>G   s!    GGG74Q$r   c                      g | ]\  }}|d v	|S ))r   r   r   r   s      r   r   z!sort_backbone.<locals>.<listcomp>H   s(       qavooooor   r   zBackbone contains atoms with connectivity degree not equal to 1 or 2. This suggests branches or isolated atoms. Problematic atoms: {}.z, c              3   4   K   | ]}t          |          V  d S Nstrr   as     r   	<genexpr>z sort_backbone.<locals>.<genexpr>P   s(      <<1A<<<<<<r   r   zBackbone connectivity invalid: expected exactly 2 atoms with connectivity degree 1 (caps). Cyclical structures are not supported. Atoms with connectivity degree 1 found: {}.c              3   4   K   | ]}t          |          V  d S r   r   r   s     r   r!   z sort_backbone.<locals>.<genexpr>Y   s(      ;;1A;;;;;;r   r   )zipr   
ValueErrorformatjoinr   ranger   )r   degrees
deg1_atomswrong_atomssorted_backbone_end_atom	next_atoms   `       r   sort_backboner0   0   su   , GFFFXFFFGGGc(G&<&<GGGJ '22  K ;!vdii<<<<<<<==
 
 	
 :! vdii;;
;;;;;<<
 
 	
  A00O3x==1$%% 	% 	%"2& *X5H	 	9$r   c                        e Zd ZdZdZed             Z fdZd Zd Z	d Z
ed             Zed	             Zed
             Zd Zd Zd ZddZ xZS )PersistenceLengtha  Calculate the persistence length for polymer chains

    The persistence length is the length at which two points on the polymer
    chain become decorrelated.  This is determined by first measuring the
    autocorrelation (:math:`C(n)`) of two bond vectors
    (:math:`\mathbf{a}_i, \mathbf{a}_{i + n}`) separated by :math:`n` bonds

    .. math::

       C(n) = \langle \cos\theta_{i, i+n} \rangle =
               \langle \mathbf{a_i} \cdot \mathbf{a_{i+n}} \rangle

    where :math:`a_i` and :math:`a_{i+n}` are unit vectors
    along the bonds.

    An exponential decay is then fitted to this, which yields the
    persistence length

    .. math::

       C(n) \approx \exp\left( - \frac{n \bar{l_B}}{l_P} \right)

    where :math:`\bar{l_B}` is the average bond length, and :math:`l_P` is
    the persistence length which is fitted

    Parameters
    ----------
    atomgroups : iterable
       List of AtomGroups. Each should represent a single
       polymer chain, ordered in the correct order.
    verbose : bool, optional
       Show detailed progress of the calculation if set to ``True``.

    Attributes
    ----------
    results.bond_autocorrelation : numpy.ndarray
       the measured bond autocorrelation
    results.lb : float
       the average bond length

       .. versionadded:: 2.0.0

    lb : float

       Alias to the :attr:`results.lb`.

       .. deprecated:: 2.0.0
            Will be removed in MDAnalysis 3.0.0. Please use
            :attr:`results.lb` instead.

    results.x : numpy.ndarray
        length of the decorrelation predicted by *lp*

        .. versionadded:: 2.0.0

    results.lp : float
       calculated persistence length

       .. versionadded:: 2.0.0

    lp : float

       Alias to the :attr:`results.lp`.

       .. deprecated:: 2.0.0
            Will be removed in MDAnalysis 3.0.0. Please use
            :attr:`results.lp` instead.

    results.fit : numpy.ndarray
       the modelled backbone decorrelation predicted by *lp*

       .. versionadded:: 2.0.0

    fit : float

       Alias to the :attr:`results.fit`.

       .. deprecated:: 2.0.0
            Will be removed in MDAnalysis 3.0.0. Please use
            :attr:`results.fit` instead.

    See Also
    --------
    :func:`sort_backbone`
       for producing the sorted AtomGroup required for input.

    Example
    -------
    .. code-block:: python

        from MDAnalysis.tests.datafiles import TRZ_psf, TRZ
        import MDAnalysis as mda
        from MDAnalysis.analysis import polymer
        u = mda.Universe(TRZ_psf, TRZ)

        # this system is a pure polymer melt of polyamide,
        # so we can select the chains by using the .fragments attribute
        chains = u.atoms.fragments

        # select only the backbone atoms for each chain
        backbones = [chain.select_atoms('not name O* H*') for chain in chains]

        # sort the chains, removing any non-backbone atoms
        sorted_backbones = [polymer.sort_backbone(bb) for bb in backbones]
        persistence_length = polymer.PersistenceLength(sorted_backbones)

        # Run the analysis, this will average over all polymer chains
        # and all timesteps in trajectory
        persistence_length = persistence_length.run()
        print(f'The persistence length is: {persistence_length.results.lp}')

        # always check the visualisation of this:
        persistence_length.plot()


    .. versionadded:: 0.13.0
    .. versionchanged:: 0.20.0
       The run method now automatically performs the exponential fit
    .. versionchanged:: 1.0.0
       Deprecated :meth:`PersistenceLength.perform_fit` has now been removed.
    .. versionchanged:: 2.0.0
       Former ``results`` are now stored as ``results.bond_autocorrelation``.
       :attr:`lb`, :attr:`lp`, :attr:`fit` are now stored in a
       :class:`MDAnalysis.analysis.base.Results` instance.
    .. versionchanged:: 2.10.0
       introduced :meth:`get_supported_backends` allowing for parallel
       execution on ``multiprocessing`` and ``dask`` backends.
    Tc                     dS )N)serialmultiprocessingdaskr   )clss    r   get_supported_backendsz(PersistenceLength.get_supported_backends   s    44r   c                     t          t          |           j        |d         j        j        fi | || _        d |D             }t          |d                   t          fd|D                       st          d          | _	        d S )Nr   c                 ,    g | ]}t          |          S r   )r   )r   ags     r   r   z.PersistenceLength.__init__.<locals>.<listcomp>   s    ---BB---r   c              3   $   K   | ]
}|k    V  d S r   r   )r   lchainlengths     r   r!   z-PersistenceLength.__init__.<locals>.<genexpr>   s(      221#222222r   z%Not all AtomGroups were the same size)
superr2   __init__universe
trajectory_atomgroupsr   allr%   r>   )self
atomgroupskwargslensr>   	__class__s       @r   r@   zPersistenceLength.__init__   s    /&&/qM"-	
 	
17	
 	
 	
 & .-*---*Q-((2222T22222 	FDEEE&r   c                 j    t          j        | j        dz
  t           j                  | j        _        d S )Nr   )dtype)npzerosr>   float32resultsraw_bond_autocorrrE   s    r   _preparezPersistenceLength._prepare  s2    )+q 
*
 *
 *
&&&r   c           	         | j         D ]}|j        dd          |j        d d         z
  }|t          j        ||z                      d                    d d d f         z  }t          j        ||          }t          | j        dz
            D ]3}| j        j	        d | j        dz
  |z
  xx         |||d f         z  cc<   4d S )Nr   r#   )axis)
rC   	positionsrL   sqrtsuminnerr(   r>   rO   rP   )rE   chainvecsinner_pris        r   _single_framezPersistenceLength._single_frame  s     % 
	% 
	%E?122&")==DBGTD[--1-5566qqq$w??Dxd++H4+a/00 % %.0t'!+q00  ae_%    %
	% 
	%r   c                 :    t          dt           j        i          S )NrP   )lookup)r
   ndarray_sumrQ   s    r   _get_aggregatorz!PersistenceLength._get_aggregator  s&    #\%=
 
 
 	
r   c                 R    d}t          j        |t                     | j        j        S )NzThe `lb` attribute was deprecated in MDAnalysis 2.0.0 and will be removed in MDAnalysis 3.0.0. Please use `results.variance` instead.)warningswarnDeprecationWarningrO   lbrE   wmsgs     r   rf   zPersistenceLength.lb   +    5 	
 	d.///|r   c                 R    d}t          j        |t                     | j        j        S )NzThe `lp` attribute was deprecated in MDAnalysis 2.0.0 and will be removed in MDAnalysis 3.0.0. Please use `results.variance` instead.)rc   rd   re   rO   lprg   s     r   rk   zPersistenceLength.lp*  ri   r   c                 R    d}t          j        |t                     | j        j        S )NzThe `fit` attribute was deprecated in MDAnalysis 2.0.0 and will be removed in MDAnalysis 3.0.0. Please use `results.variance` instead.)rc   rd   re   rO   fitrg   s     r   rm   zPersistenceLength.fit4  s,    5 	
 	d.///|r   c                    t          j        | j        dz
  d| j        dz
            }|t          | j                  | j        j        z  z  }| j        j        |z  | j        _	        | 
                                 |                                  d S )Nr   )rL   linspacer>   r   rC   _trajectoryn_framesrO   rP   bond_autocorrelation_calc_bond_length_perform_fit)rE   norms     r   	_concludezPersistenceLength._conclude>  s    {4+a/D4Dq4HIID$%%(8(AAAL*T1 	) 	   r   c                     g }| j         D ]P}|j        }t          |dd         |dd                                                   }|                    |           Qt          j        |          | j        _        dS )zcalculate average bond lengthNr#   r   )rC   rU   r   meanappendrL   rO   rf   )rE   bsr;   posbs        r   rs   z#PersistenceLength._calc_bond_lengthG  sq    " 	 	B,C3ss8SW--2244AIIaLLLL'"++r   c                    	 | j         j         n# t          $ r t          d          dw xY w| j         j        t          j        t          | j         j                            z  | j         _        t          | j         j        | j         j                  | j         _
        t          j        | j         j         | j         j
        z            | j         _        dS )z'Fit the results to an exponential decayzUse the run method firstN)rO   rr   AttributeErrorr   rf   rL   aranger   xfit_exponential_decayrk   exprm   rQ   s    r   rt   zPersistenceLength._perform_fitP  s    	DL--- 	D 	D 	D899tC	D29122,
 ,
 
 0LNDL=
 
 64<>/DLO"CDDs    *Nc                    ddl m} ||                                \  }}|                    | j        j        | j        j        dd           |                    | j        j        | j        j        d           |                    d           |	                    d           |
                    d	d
| j        j        z             |                    d           |S )a  Visualize the results and fit

        Parameters
        ----------
        ax : matplotlib.Axes, optional
          if provided, the graph is plotted on this axis

        Returns
        -------
        ax : the axis that the graph was plotted on
        r   NroResult)labelFitr   z$C(x)$g        (   best)loc)matplotlib.pyplotpyplotsubplotsplotrO   r   rr   rm   
set_xlabel
set_ylabelset_xlimrf   legend)rE   axpltr-   s       r   r   zPersistenceLength.plot`  s     	(''''':LLNNEAr
LNL-	 	 	
 	
 	
 	 0>>>
d
i   
Cdlo-...
		f		r   r   )__name__
__module____qualname____doc__%_analysis_algorithm_is_parallelizableclassmethodr8   r@   rR   r]   ra   propertyrf   rk   rm   rv   rs   rt   r   __classcell__)rI   s   @r   r2   r2   m   s(        B -1)5 5 [5' ' ' ' '
 
 

% % %$
 
 
   X   X     X   & & &E E E        r   r2   c                 f    d }t           j                            || |          d         d         }|S )aZ  Fit a function to an exponential decay

    .. math::  y = \exp\left(- \frac{x}{a}\right)

    Parameters
    ----------
    x, y : array_like
      The two arrays of data

    Returns
    -------
    a : float
      The coefficient *a* for this decay

    Notes
    -----
    This function assumes that data starts at 1.0 and decays to 0.0

    c                 2    t          j        |  |z            S r   )rL   r   )r   r    s     r   expfuncz&fit_exponential_decay.<locals>.expfunc  s    vqb1f~~r   r   )scipyoptimize	curve_fit)r   yr   r    s       r   r   r     s;    *   	  !Q//215AHr   )r   numpyrL   scipy.optimizer   rc   logging r   core.groupsr   r   lib.distancesr   baser	   r
   	getLoggerr   loggerr0   r2   r   r   r   r   <module>r      s  0
 
                 - - - - - - - - & & & & & & , , , , , , , ,		8	$	$ 
'9 9 9xP P P P P P P Pf    r   