
     i04                         d Z ddlZddlZddlmZ ddlmZ ddlmZ ddlmZm	Z	 	 ddl
Zd	Zn# e$ r d
ZY nw xY w ej         e	d          ddd	           [	 G d de          Z	 	 	 	 ddZdS )a  
Leaflet identification --- :mod:`MDAnalysis.analysis.leaflet`
==============================================================

This module implements the *LeafletFinder* algorithm, described in
[Michaud-Agrawal2011]_. It can identify the lipids in a bilayer of
arbitrary shape and topology, including planar and undulating bilayers
under periodic boundary conditions or vesicles.

One can use this information to identify

* the upper and lower leaflet of a *planar membrane* by comparing the
  the :meth:`~MDAnalysis.core.groups.AtomGroup.center_of_geometry` of
  the leaflet groups, or

* the outer and inner leaflet of a *vesicle* by comparing histograms
  of distances from the centre of geometry (or possibly simply the
  :meth:`~MDAnalysis.core.groups.AtomGroup.radius_of_gyration`).

See example scripts in the MDAnalysisCookbook_ on how to use
:class:`LeafletFinder`. The function :func:`optimize_cutoff` implements a
(slow) heuristic method to find the best cut off for the LeafletFinder
algorithm.

.. _MDAnalysisCookbook: https://github.com/MDAnalysis/MDAnalysisCookbook/tree/master/examples


Algorithm
---------

1. build a graph of all phosphate distances < cutoff
2. identify the largest connected subgraphs
3. analyse first and second largest graph, which correspond to the leaflets

For further details see [Michaud-Agrawal2011]_.


Classes and Functions
---------------------

.. autoclass:: LeafletFinder
   :members:

.. autofunction:: optimize_cutoff

    N   )core   )	distances)
selections)dueDoiTFz10.1002/jcc.21787zLeafletFinder algorithmzMDAnalysis.analysis.leaflet)descriptionpathcite_modulec                   Z    e Zd ZdZddZd Zd Zd Zdd	Zd
 Z	ddZ
d Zd Zd Zd ZdS )LeafletFindera  Identify atoms in the same leaflet of a lipid bilayer.

    This class implements the *LeafletFinder* algorithm [Michaud-Agrawal2011]_.

    Parameters
    ----------
    universe : Universe
        :class:`~MDAnalysis.core.universe.Universe` object.
    select : AtomGroup or str
        A AtomGroup instance or a
        :meth:`Universe.select_atoms` selection string
        for atoms that define the lipid head groups, e.g.
        universe.atoms.PO4 or "name PO4" or "name P*"
    cutoff : float (optional)
        head group-defining atoms within a distance of `cutoff`
        Angstroms are deemed to be in the same leaflet [15.0]
    pbc : bool (optional)
        take periodic boundary conditions into account [``False``]
    sparse : bool (optional)
        ``None``: use fastest possible routine; ``True``: use slow
        sparse matrix implementation (for large systems); ``False``:
        use fast :func:`~MDAnalysis.lib.distances.distance_array`
        implementation [``None``].

    Raises
    ------
    ImportError
      This class requires the optional package `networkx`. If not found
      an ImportError is raised.

    Example
    -------
    The components of the graph are stored in the list
    :attr:`LeafletFinder.components`; the atoms in each component are numbered
    consecutively, starting at 0. To obtain the atoms in the input structure
    use :meth:`LeafletFinder.groups`::

       u = mda.Universe(PDB)
       L = LeafletFinder(u, 'name P*')
       leaflet0 = L.groups(0)
       leaflet1 = L.groups(1)

    The residues can be accessed through the standard MDAnalysis mechanism::

       leaflet0.residues

    provides a :class:`~MDAnalysis.core.groups.ResidueGroup`
    instance. Similarly, all atoms in the first leaflet are then ::

       leaflet0.residues.atoms


    .. versionchanged:: 1.0.0
       Changed `selection` keyword to `select`
    .. versionchanged:: 2.0.0
       The universe keyword no longer accepts non-Universe arguments. Please
       create a :class:`~MDAnalysis.core.universe.Universe` first.
          .@FNc                 8   t           sd}t          |          || _        || _        t	          | j        t
          j        j                  r| j        | _        n|	                    | j                  | _        || _
        || _        |                     |           d S )NzThe LeafletFinder class requires an installation of networkx. Please install networkx https://networkx.org/documentation/stable/install.html)HAS_NXImportErroruniverseselectionstring
isinstancer   groups	AtomGroup	selectionselect_atomspbcsparse_init_graph)selfr   selectcutoffr   r   errmsgs          e/srv/www/vhosts/g4struct/public_html/venv/lib/python3.11/site-packages/MDAnalysis/analysis/leaflet.py__init__zLeafletFinder.__init__   s     	&I 
 f%%% %d*DK,ABB 	I!1DNN%2243GHHDN         c                 x    || _         |                                 | _        |                                 | _        d S N)r   
_get_graphgraph_get_components
componentsr   r   s     r!   r   zLeafletFinder._init_graph   s1    __&&
..00r#   c                 F   | j         r| j        j        j        j        }nd}| j        j        }| j        du rJ	 t          j	        || j
        d|          }n# t          $ r t          j        dt          d            w xY w| j        du rt          j	        || j
        d	|          }nh	 t          j	        || j
        d|          }nI# t          $ r< t          j        d
t          d           t          j	        || j
        d	|          }Y nw xY wt          j        |          S )zBuild graph from adjacency matrix at the given cutoff.
        Automatically select between high and low memory usage versions of
        contact_matrix.NFnumpy)r   
returntypeboxz4N x N matrix too big, use sparse=True or sparse=Noner   )category
stacklevelTr   zcN x N matrix too big - switching to sparse matrix method (works fine, but is currently rather slow))r   r   
trajectoryts
dimensionsr   	positionsr   r   contact_matrixr   
ValueErrorwarningswarnUserWarningNXGraph)r   r.   coordadjs       r!   r&   zLeafletFinder._get_graph   s~   
 8 	-*-8CCC(;%
.$+'s      J(    
  [D  *dkhC  CC
.$+'s    
 
 
( 	     .$+(  
 x}}s   A (A=(C ADDc                 H    d t          j        | j                  D             S )zEReturn connected components (as sorted numpy arrays), sorted by size.c                 P    g | ]#}t          j        t          |                    $S  )npsortlist).0	components     r!   
<listcomp>z1LeafletFinder._get_components.<locals>.<listcomp>   s8     
 
 
 GDOO$$
 
 
r#   )r:   connected_componentsr'   r   s    r!   r(   zLeafletFinder._get_components   s0    
 
4TZ@@
 
 
 	
r#   c                 B    || j         }|                     |           dS )z5Update components, possibly with a different *cutoff*N)r   r   r*   s     r!   updatezLeafletFinder.update   s(    >[F     r#   c                 X    t          d t          | j                  D                       S )z/Dict of component index with size of component.c              3   >   K   | ]\  }}|t          |          fV  d S r%   )len)rD   idxrE   s      r!   	<genexpr>z&LeafletFinder.sizes.<locals>.<genexpr>   sE        "C c)nn%     r#   )dict	enumerater)   rH   s    r!   sizeszLeafletFinder.sizes   s:     &/&@&@  
 
 	
r#   c                 r    |!t          |                                           S |                     |          S )a  Return a :class:`MDAnalysis.core.groups.AtomGroup` for *component_index*.

        If no argument is supplied, then a list of all leaflet groups is returned.

        See Also
        --------
        :meth:`LeafletFinder.group`
        :meth:`LeafletFinder.groups_iter`
        )rC   groups_itergroupr   component_indexs     r!   r   zLeafletFinder.groups  s6     "((**+++::o...r#   c                 J    d | j         |         D             }| j        |         S )zIReturn a :class:`MDAnalysis.core.groups.AtomGroup` for *component_index*.c                     g | ]}|S r@   r@   )rD   is     r!   rF   z'LeafletFinder.group.<locals>.<listcomp>  s    ???1???r#   )r)   r   )r   rW   indicess      r!   rU   zLeafletFinder.group  s,     @?doo>???~g&&r#   c              #      K   t          t          | j                            D ]}|                     |          V  dS )z(Iterator over all leaflet :meth:`groups`N)rangerM   r)   rU   rV   s     r!   rT   zLeafletFinder.groups_iter  sL      $S%9%9:: 	. 	.O**_------	. 	.r#   c                    t          j        ||                    dd                    } ||f|                    dd           dj        d
i t	          |           d|5 }t          |                                           D ]4\  }}d                    |dz             }|                    ||	           5	 ddd           dS # 1 swxY w Y   dS )a   Write selections for the leaflets to *filename*.

        The format is typically determined by the extension of *filename*
        (e.g. "vmd", "pml", or "ndx" for VMD, PyMol, or Gromacs).

        See :class:`MDAnalysis.selections.base.SelectionWriter` for all
        options.
        formatNmodewz?leaflets based on select={selectionstring!r} cutoff={cutoff:f}
)r`   preamblezleaflet_{0:d}r   )namer@   )r   
get_writerpopr_   varsrQ   rT   write)r   filenamekwargsswwriterrZ   agrc   s           r!   write_selectionzLeafletFinder.write_selection  sD    "8VZZ$-G-GHHR
FC((^W^  t** 
 
 
 
 
	, "4#3#3#5#566 , ,2&--q1u66Rd++++,
	, 
	, 
	, 
	, 
	, 
	, 
	, 
	, 
	, 
	, 
	, 
	, 
	, 
	, 
	, 
	, 
	, 
	,s   "ACCCc                 ~    d                     | j        | j        | j        j        t          | j                            S )NzI<LeafletFinder({0!r}, cutoff={1:.1f} A) with {2:d} atoms in {3:d} groups>)r_   r   r   r   n_atomsrM   r)   rH   s    r!   __repr__zLeafletFinder.__repr__2  s:    Zaa KN"  	
 
 	
r#   )r   FNr%   )__name__
__module____qualname____doc__r"   r   r&   r(   rJ   rR   r   rU   rT   rm   rp   r@   r#   r!   r   r   c   s        9 9v! ! ! !(1 1 1. . .`
 
 
! ! ! !
 
 
/ / / /' ' '. . .
, , ,,
 
 
 
 
r#   r         $@      4@      ?皙?c                 `   |                     dd           g }t          j        |||          D ]}t          | |fd|i|}	|	                                }
t          |
          dk     r:t          |
d                   }t          |
d                   }t          j        ||z
            ||z   z  }||k    r|                    |t          |	                                          f           t          j	        
                    |d          }~|                    ddg	           |d         S )
aD  Find cutoff that minimizes number of disconnected groups.

    Applies heuristics to find best groups:

    1. at least two groups (assumes that there are at least 2 leaflets)
    2. reject any solutions for which:

       .. math::

              \frac{|N_0 - N_1|}{|N_0 + N_1|} > \mathrm{max_imbalance}

       with :math:`N_i` being the number of lipids in group
       :math:`i`. This heuristic picks groups with balanced numbers of
       lipids.

    Parameters
    ----------
    universe : Universe
        :class:`MDAnalysis.Universe` instance
    select : AtomGroup or str
        AtomGroup or selection string as used for :class:`LeafletFinder`
    dmin : float (optional)
    dmax : float (optional)
    step : float (optional)
        scan cutoffs from `dmin` to `dmax` at stepsize `step` (in Angstroms)
    max_imbalance : float (optional)
        tuning parameter for the balancing heuristic [0.2]
    kwargs : other keyword arguments
        other arguments for  :class:`LeafletFinder`

    Returns
    -------
    (cutoff, N)
         optimum cutoff and number of groups found


    .. Note:: This function can die in various ways if really no
              appropriate number of groups can be found; it ought  to be
              made more robust.

    .. versionchanged:: 1.0.0
       Changed `selection` keyword to `select`
    r   Nr   r   r   zcutoff,N)namesN)order)re   rA   aranger   rR   rM   floatabsappendrecfromrecordsrB   )r   r   dmindmaxstepmax_imbalanceri   _sizesr   LFrR   n0n1	imbalanceresultss                  r!   optimize_cutoffr   ;  s%   h JJxF)D$-- 1 18VEEFEfEE 

u::>>58__58__F27OOrBw/	}$$vs288::/0000f  z ::GLLXL'''1:r#   )ru   rv   rw   rx   )rt   r7   r,   rA    r   r   r   r   r	   networkxr:   r   r   citeobjectr   r   r@   r#   r!   <module>r      sS  2- -\                                FF    FFF 	C)	&	    U
 U
 U
 U
 U
F U
 U
 U
v 
		H H H H H Hs   - 77