
     i9                     ^   d Z ddlZddlmZ ddlmZ ddlmZm	Z	m
Z
mZ ddlmZ ddlmZ d	ej        d
efdZdej        dej        d
ej        fdZdej        dej        d
ej        fdZdej        d
ej        fdZdej        dej        d
efdZdej        dej        dej        d
efdZdej        dej        dej        d
efdZdej        d
eeej        f         fdZdej        dej        dej        d
ej        fdZej        fd ej        d!ej        d
ej        fd"Zd ej        d
efd#ZdS )$a  
Mathematical helper functions --- :mod:`MDAnalysis.lib.mdamath`
===============================================================


Helper functions for common mathematical operations. Some of these functions
are written in C/cython for higher performance.

Linear algebra
--------------

.. autofunction:: normal
.. autofunction:: norm
.. autofunction:: pdot
.. autofunction:: pnorm
.. autofunction:: angle
.. autofunction:: dihedral
.. autofunction:: stp
.. autofunction:: sarrus_det
.. autofunction:: triclinic_box
.. autofunction:: triclinic_vectors
.. autofunction:: box_volume


Connectivity
------------

.. autofunction:: make_whole
.. autofunction:: find_fragments


.. versionadded:: 0.11.0
.. versionchanged: 1.0.0
   Unused function :func:`_angle()` has now been removed.

    N   )NoDataError   )util)
make_wholefind_fragments_sarrus_det_single_sarrus_det_multiple)Unionvreturnc                 P    t          j        t          j        | |                     S )a  Calculate the norm of a vector v.

    .. math:: v = \sqrt{\mathbf{v}\cdot\mathbf{v}}

    This version is faster then numpy.linalg.norm because it only works for a
    single vector and therefore can skip a lot of the additional fuss
    linalg.norm does.

    Parameters
    ----------
    v : array_like
        1D array of shape (N) for a vector of length N

    Returns
    -------
    float
        norm of the vector

    )npsqrtdot)r   s    `/srv/www/vhosts/g4struct/public_html/venv/lib/python3.11/site-packages/MDAnalysis/lib/mdamath.pynormr   L   s    ( 726!Q<<       vec1vec2c                 d    t          j        | |          }t          |          }|dk    r|S ||z  S )a9  Returns the unit vector normal to two vectors.

    .. math::

       \hat{\mathbf{n}} = \frac{\mathbf{v}_1 \times \mathbf{v}_2}{|\mathbf{v}_1 \times \mathbf{v}_2|}

    If the two vectors are collinear, the vector :math:`\mathbf{0}` is returned.

    .. versionchanged:: 0.11.0
       Moved into lib.mdamath
            )r   crossr   )r   r   normalns       r   r   r   c   s8     (4..FVACxxA:r   abc                 .    t          j        d| |          S )a  Pairwise dot product.

    ``a`` must be the same shape as ``b``.

    Parameters
    ----------
    a: :class:`numpy.ndarray` of shape (N, M)
    b: :class:`numpy.ndarray` of shape (N, M)

    Returns
    -------
    :class:`numpy.ndarray` of shape (N,)
    zij,ij->i)r   einsum)r   r   s     r   pdotr    x   s     9ZA&&&r   c                 (    t          | |           dz  S )zEuclidean norm of each vector in a matrix

    Parameters
    ----------
    a: :class:`numpy.ndarray` of shape (N, M)

    Returns
    -------
    :class:`numpy.ndarray` of shape (N,)
    g      ?)r    )r   s    r   pnormr"      s     1::r   c                     t          j        | |          t          |           t          |          z  z  }t          j        |dd          }t          j        |          S )a  Returns the angle between two vectors in radians

    .. versionchanged:: 0.11.0
       Moved into lib.mdamath
    .. versionchanged:: 1.0.0
       Changed rounding-off code to use `np.clip()`. Values lower than
       -1.0 now return `np.pi` instead of `-np.pi`
    g            ?)r   r   r   cliparccos)r   r   xs      r   angler(      sJ     	q!Q$q'')*A
4A9Q<<r   vec3c                 R    t          j        |t          j        | |                    S )a  Takes the scalar triple product of three vectors.

    Returns the volume *V* of the parallel epiped spanned by the three
    vectors

    .. math::

        V = \mathbf{v}_3 \cdot (\mathbf{v}_1 \times \mathbf{v}_2)

    .. versionchanged:: 0.11.0
       Moved into lib.mdamath
    )r   r   r   )r   r   r)   s      r   stpr+      s"      6$t,,---r   abbccdc                     t          t          | |          t          ||                    }t          | ||          dk    r|n| S )u  Returns the dihedral angle in radians between vectors connecting A,B,C,D.

    The dihedral measures the rotation around bc::

         ab
       A---->B
              \ bc
              _\'
                C---->D
                  cd

    The dihedral angle is restricted to the range -π <= x <= π.

    .. versionadded:: 0.8
    .. versionchanged:: 0.11.0
       Moved into lib.mdamath
    r   )r(   r   r+   )r,   r-   r.   r'   s       r   dihedralr0      sC    $ 	fRnnfRnn--ABB3&&11QB.r   matrixc                 l   |                      t          j                  }|j        }|j        }|dk     s|dd         dk    r"t          d                    |                    |dk    rt          |          S t          |	                    d                    	                    |dd                   S )a  Computes the determinant of a 3x3 matrix according to the
    `rule of Sarrus`_.

    If an array of 3x3 matrices is supplied, determinants are computed per
    matrix and returned as an appropriately shaped numpy array.

    .. _rule of Sarrus:
       https://en.wikipedia.org/wiki/Rule_of_Sarrus

    Parameters
    ----------
    matrix : numpy.ndarray
        An array of shape ``(..., 3, 3)`` with the 3x3 matrices residing in the
        last two dimensions.

    Returns
    -------
    det : float or numpy.ndarray
        The determinant(s) of `matrix`.
        If ``matrix.shape == (3, 3)``, the determinant will be returned as a
        scalar. If ``matrix.shape == (..., 3, 3)``, the determinants will be
        returned as a :class:`numpy.ndarray` of shape ``(...,)`` and dtype
        ``numpy.float64``.

    Raises
    ------
    ValueError:
        If `matrix` has less than two dimensions or its last two dimensions
        are not of shape ``(3, 3)``.


    .. versionadded:: 0.20.0
    r   N   r5   z<Invalid matrix shape: must be (3, 3) or (..., 3, 3), got {}.)r5   r5   )
astyper   float64shapendim
ValueErrorformatr	   r
   reshape)r1   mr9   r:   s       r   
sarrus_detr?      s    D 	bj!!AGE6Daxx5:''fUmm
 
 	
 qyy!!$$$		* 5 566>>uSbSzJJJr   r'   yzc           	         t          j        | t           j                  } t          j        |t           j                  }t          j        |t           j                  }t          |           }t          |          }t          |          }t          j        d          5  t          j        t          j        t          j        ||          ||z  z                      }t          j        t          j        t          j        | |          ||z  z                      }t          j        t          j        t          j        | |          ||z  z                      }ddd           n# 1 swxY w Y   t          j        ||||||gt           j	                  }	t          j
        |	dk              r|dk     r|dk     r|dk     r|	S t          j        dt           j	                  S )aV  Convert the three triclinic box vectors to
    ``[lx, ly, lz, alpha, beta, gamma]``.

    If the resulting box is invalid, i.e., any box length is zero or negative,
    or any angle is outside the open interval ``(0, 180)``, a zero vector will
    be returned.

    All angles are in degrees and defined as follows:

    * ``alpha = angle(y,z)``
    * ``beta  = angle(x,z)``
    * ``gamma = angle(x,y)``

    Parameters
    ----------
    x : array_like
        Array of shape ``(3,)`` representing the first box vector
    y : array_like
        Array of shape ``(3,)`` representing the second box vector
    z : array_like
        Array of shape ``(3,)`` representing the third box vector

    Returns
    -------
    numpy.ndarray
        A numpy array of shape ``(6,)`` and dtype ``np.float32`` providing the
        unitcell dimensions in the same format as returned by
        :attr:`MDAnalysis.coordinates.timestep.Timestep.dimensions`:

        ``[lx, ly, lz, alpha, beta, gamma]``.

        Invalid boxes are returned as a zero vector.

    Note
    ----
    Definition of angles: http://en.wikipedia.org/wiki/Lattice_constant

    See Also
    --------
    :func:`~MDAnalysis.lib.mdamath.triclinic_vectors`


    .. versionchanged:: 0.20.0
       Calculations are performed in double precision and invalid box vectors
       result in an all-zero box.
    dtypeignore)invalidNr        f@   )r   asarrayr8   r   errstaterad2degr&   r   arrayfloat32allzeros)
r'   r@   rA   lxlylzalphabetagammaboxs
             r   triclinic_boxrW      s   ^ 	
1BJ'''A

1BJ'''A

1BJ'''A	aB	aB	aB	X	&	&	& @ @
29RVAq\\R"W%=>>??z")BF1aLLBG$<==>>
29RVAq\\R"W%=>>??@ @ @ @ @ @ @ @ @ @ @ @ @ @ @ (BBtU32:
F
F
FC	vcCi UU]]te||
8ARZ((((s   #B>E--E14E1
dimensionsrD   c                 .   t          j        | t           j                  }|\  }}}}}}t          j        |dk              r|dk     r|dk     r|dk     st          j        d|          }	n||cxk    r|cxk    rdk    r6n n3t          j        |dd                             |d	                    }	n_t          j        dt           j                  }	||	d
<   |dk    rd}
n&t          j        t          j        |                    }
|dk    rd}n&t          j        t          j        |                    }|dk    rd}d}n<t          j        |          }t          j        |          }t          j	        |          }||z  |	d<   ||z  |	d<   ||z  |	d<   ||
||z  z
  z  |z  |	d<   t          j
        ||z  |	d         dz  z
  |	d         dz  z
            |	d<   |	d         dk    r|	                    |d	          }	nt          j        d|          }	|	S )a  Convert ``[lx, ly, lz, alpha, beta, gamma]`` to a triclinic matrix
    representation.

    Original `code by Tsjerk Wassenaar`_ posted on the Gromacs mailinglist.

    If `dimensions` indicates a non-periodic system (i.e., all lengths are
    zero), zero vectors are returned. The same applies for invalid `dimensions`,
    i.e., any box length is zero or negative, or any angle is outside the open
    interval ``(0, 180)``.

    .. _code by Tsjerk Wassenaar:
       http://www.mail-archive.com/gmx-users@gromacs.org/msg28032.html

    Parameters
    ----------
    dimensions : array_like
        Unitcell dimensions provided in the same format as returned by
        :attr:`MDAnalysis.coordinates.timestep.Timestep.dimensions`:

        ``[lx, ly, lz, alpha, beta, gamma]``.
    dtype: numpy.dtype
        The data type of the returned box matrix.

    Returns
    -------
    box_matrix : numpy.ndarray
        A numpy array of shape ``(3, 3)`` and dtype `dtype`,
        with ``box_matrix[0]`` containing the first, ``box_matrix[1]`` the
        second, and ``box_matrix[2]`` the third box vector.

    Notes
    -----
    * The first vector is guaranteed to point along the x-axis, i.e., it has the
      form ``(lx, 0, 0)``.
    * The second vector is guaranteed to lie in the x/y-plane, i.e., its
      z-component is guaranteed to be zero.
    * If any box length is negative or zero, or if any box angle is zero, the
      box is treated as invalid and an all-zero-matrix is returned.


    .. versionchanged:: 0.7.6
       Null-vectors are returned for non-periodic (or missing) unit cell.
    .. versionchanged:: 0.20.0
       * Calculations are performed in double precision and zero vectors are
         also returned for invalid boxes.
       * Added optional output dtype parameter.
    rC   r   rG   r4        V@Nr5   F)copyr   r   r$   )r   r   r   r   )r   r   )r   r   r   r   r   )r   rI   r8   rN   rO   diagr7   cosdeg2radsinr   )rX   rD   dimrP   rQ   rR   rS   rT   rU   
box_matrix	cos_alphacos_beta	cos_gamma	sin_gammas                 r   triclinic_vectorsri   ?  sL   b *Zrz
2
2
2C%("BBtU 	sSy.7#emmu XfE222

	$	'	'	'	'%	'	'	'	'4	'	'	'	'	'WS!W^^E^>>??

 XfBJ777

4D==IIrz%0011I4<<HHvbj..//HD==IIIJu%%EuIuI	>
4	>
4=
4X	-A!ABYN
47Gj&!++j.>!.CC
 

4 dc!!#**5u*==JJ &666Jr   c                 &   t          j        | t           j                  }|\  }}}}}}||cxk    r|cxk    rdk    rn n|dk    r|dk    r|dk    r	||z  |z  }n5t          |t           j                  }	|	d         |	d         z  |	d         z  }|S )a]  Return the volume of the unitcell described by `dimensions`.

    The volume is computed as the product of the box matrix trace, with the
    matrix obtained from :func:`triclinic_vectors`.
    If the box is invalid, i.e., any box length is zero or negative, or any
    angle is outside the open interval ``(0, 180)``, the resulting volume will
    be zero.

    Parameters
    ----------
    dimensions : array_like
        Unitcell dimensions provided in the same format as returned by
        :attr:`MDAnalysis.coordinates.timestep.Timestep.dimensions`:

        ``[lx, ly, lz, alpha, beta, gamma]``.

    Returns
    -------
    volume : float
        The volume of the unitcell. Will be zero for invalid boxes.


    .. versionchanged:: 0.20.0
        Calculations are performed in double precision and zero is returned
        for invalid dimensions.
    rC   rZ   r   r\   r]   r^   )r   rI   r8   ri   )
rX   rc   rP   rQ   rR   rS   rT   rU   volumetri_vecss
             r   
box_volumerm     s    4 *Zrz
2
2
2C%("BBtU%%%%%%%%%%%%%"q&&R!VVQb2 %S
;;;$(4.08D>AMr   ) __doc__numpyr   
exceptionsr    r   _cutilr   r   r	   r
   numpy.typingtypingnptr   	ArrayLikefloatr   NDArrayr   r    r"   r(   r+   r0   r?   rW   rM   	DTypeLikeri   rm    r   r   <module>r{      s  0# #H     $ $ $ $ $ $                             
!CM !e ! ! ! !. cm     *'CK 'CK 'CK ' ' ' '"S[ S[    S] s}     .
-."}.47M.
. . . .&/ /CM /s} / / / / /,,Ks{ ,KuUCK-?'@ ,K ,K ,K ,K^>)
}>)>)+.=>)[>) >) >) >)D 79jc cc&)mc[c c c cL$3= $U $ $ $ $ $ $r   