B
    ]t\                 @   s  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Z
G dd deZG d	d
 d
eZG dd deZG dd dZG dd dZG dd deZG dd deZG dd deZG dd deZd-ddZdd Zdd  Zd!d" Zd#d$ Zd%d& Zd'd( Zd)d* Zd+d, ZdS ).z(
Interpolation inside triangular grids.
    N)Triangulation)	TriFinder)TriAnalyzer)TriInterpolatorLinearTriInterpolatorCubicTriInterpolatorc               @   s4   e Zd ZdZdddZdZdZddd	Zd
d ZdS )r   a  
    Abstract base class for classes used to perform interpolation on
    triangular grids.

    Derived classes implement the following methods:

        - ``__call__(x, y)`` ,
          where x, y are array_like point coordinates of the same shape, and
          that returns a masked array of the same shape containing the
          interpolated z-values.

        - ``gradient(x, y)`` ,
          where x, y are array_like point coordinates of the same
          shape, and that returns a list of 2 masked arrays of the same shape
          containing the 2 derivatives of the interpolator (derivatives of
          interpolated z values with respect to x and y).

    Nc             C   s~   t |tstd|| _t|| _| jj| jjjkr>td|d k	rXt |t	sXtd|pd| j
 | _d| _d| _d | _d S )NzExpected a Triangulation objectz=z array must have same length as triangulation x and y arrayszExpected a TriFinder objectg      ?)
isinstancer   
ValueError_triangulationnpasarray_zshapexr   Zget_trifinder
_trifinder_unit_x_unit_y
_tri_renum)selftriangulationz	trifinder r   <lib/python3.7/site-packages/matplotlib/tri/triinterpolate.py__init__#   s    
zTriInterpolator.__init__a  
        Returns a masked array containing interpolated values at the specified
        x,y points.

        Parameters
        ----------
        x, y : array-like
            x and y coordinates of the same shape and any number of
            dimensions.

        Returns
        -------
        z : np.ma.array
            Masked array of the same shape as *x* and *y*; values corresponding
            to (*x*, *y*) points outside of the triangulation are masked out.

        a  
        Returns a list of 2 masked arrays containing interpolated derivatives
        at the specified x,y points.

        Parameters
        ----------
        x, y : array-like
            x and y coordinates of the same shape and any number of
            dimensions.

        Returns
        -------
        dzdx, dzdy : np.ma.array
            2 masked arrays of the same shape as *x* and *y*; values
            corresponding to (x,y) points outside of the triangulation
            are masked out.
            The first returned array contains the values of
            :math:`\frac{\partial z}{\partial x}` and the second those of
            :math:`\frac{\partial z}{\partial y}`.

        r   c          	   C   s  t j|t jd}t j|t jd}|j}|j|jkrFtd|j|jt |}t |}|| j }|| j }t 	|}|dkr| 
||}n&|j|krtd|j|t |}|dk}	| jdkr||	 }
n| j||	  }
||	 }||	 }g }x|D ]}ydddd	| }W n tk
r.   td
Y nX dd| j d| j g| }t j|t jd}t j||	 < | ||
||| ||	< |t jj||ddg7 }qW |S )a!
  
        Versatile (private) method defined for all TriInterpolators.

        :meth:`_interpolate_multikeys` is a wrapper around method
        :meth:`_interpolate_single_key` (to be defined in the child
        subclasses).
        :meth:`_interpolate_single_key actually performs the interpolation,
        but only for 1-dimensional inputs and at valid locations (inside
        unmasked triangles of the triangulation).

        The purpose of :meth:`_interpolate_multikeys` is to implement the
        following common tasks needed in all subclasses implementations:

            - calculation of containing triangles
            - dealing with more than one interpolation request at the same
              location (e.g., if the 2 derivatives are requested, it is
              unnecessary to compute the containing triangles twice)
            - scaling according to self._unit_x, self._unit_y
            - dealing with points outside of the grid (with fill value np.nan)
            - dealing with multi-dimensionnal *x*, *y* arrays: flattening for
              :meth:`_interpolate_params` call and final reshaping.

        (Note that np.vectorize could do most of those things very well for
        you, but it does it by function evaluations over successive tuples of
        the input arrays. Therefore, this tends to be more time consuming than
        using optimized numpy functions - e.g., np.dot - which can be used
        easily on the flattened inputs, in the child-subclass methods
        :meth:`_interpolate_single_key`.)

        It is guaranteed that the calls to :meth:`_interpolate_single_key`
        will be done with flattened (1-d) array_like input parameters `x`, `y`
        and with flattened, valid `tri_index` arrays (no -1 index allowed).

        Parameters
        ----------
        x, y : array_like
            x and y coordinates indicating where interpolated values are
            requested.
        tri_index : integer array_like, optional
            Array of the containing triangle indices, same shape as
            *x* and *y*. Defaults to None. If None, these indices
            will be computed by a TriFinder instance.
            (Note: For point outside the grid, tri_index[ipt] shall be -1).
        return_keys : tuple of keys from {'z', 'dzdx', 'dzdy'}
            Defines the interpolation arrays to return, and in which order.

        Returns
        -------
        ret : list of arrays
            Each array-like contains the expected interpolated values in the
            order defined by *return_keys* parameter.
        )dtypez2x and y shall have same shapes. Given: {0} and {1}NzTtri_index array is provided and shall have same shape as x and y. Given: {0} and {1}r         )r   dzdxdzdyz<return_keys items shall take values in {'z', 'dzdx', 'dzdy'}g      ?F)copy)r   r   float64r   r	   formatravelr   r   sizer   r   KeyErroremptynan_interpolate_single_keyZmaZmasked_invalidreshape)r   r   y	tri_indexreturn_keysZsh_retZx_scaledZy_scaledZsize_retZmask_inZvalid_tri_indexZvalid_xZvalid_yret
return_keyreturn_indexZscaleZret_locr   r   r   _interpolate_multikeysj   sJ    8









 z&TriInterpolator._interpolate_multikeysc             C   s   t ddS )a`  
        Performs the interpolation at points belonging to the triangulation
        (inside an unmasked triangles).

        Parameters
        ----------
        return_index : string key from {'z', 'dzdx', 'dzdy'}
            Identifies the requested values (z or its derivatives)
        tri_index : 1d integer array
            Valid triangle index (-1 prohibited)
        x, y : 1d arrays, same shape as `tri_index`
            Valid locations where interpolation is requested.

        Returns
        -------
        ret : 1-d array
            Returned array of the same size as *tri_index*
        zCTriInterpolator subclassesshould implement _interpolate_single_key!N)NotImplementedError)r   r0   r-   r   r,   r   r   r   r*      s    z'TriInterpolator._interpolate_single_key)N)Nr   )	__name__
__module____qualname____doc__r   _docstring__call___docstringgradientr2   r*   r   r   r   r   r      s   
/ 
kr   c               @   sB   e Zd ZdZdddZdd Zeje_dd Zej	e_d	d
 Z
dS )r   a  
    A LinearTriInterpolator performs linear interpolation on a triangular grid.

    Each triangle is represented by a plane so that an interpolated value at
    point (x,y) lies on the plane of the triangle containing (x,y).
    Interpolated values are therefore continuous across the triangulation, but
    their first derivatives are discontinuous at edges between triangles.

    Parameters
    ----------
    triangulation : :class:`~matplotlib.tri.Triangulation` object
        The triangulation to interpolate over.
    z : array_like of shape (npoints,)
        Array of values, defined at grid points, to interpolate between.
    trifinder : :class:`~matplotlib.tri.TriFinder` object, optional
          If this is not specified, the Triangulation's default TriFinder will
          be used by calling
          :func:`matplotlib.tri.Triangulation.get_trifinder`.

    Methods
    -------
    `__call__` (x, y) :  Returns interpolated values at x,y points
    `gradient` (x, y) : Returns interpolated derivatives at x,y points

    Nc             C   s$   t | ||| | j| j| _d S )N)r   r   r
   Zcalculate_plane_coefficientsr   _plane_coefficients)r   r   r   r   r   r   r   r     s    zLinearTriInterpolator.__init__c             C   s   | j ||d ddd S )N)r   )r-   r.   r   )r2   )r   r   r,   r   r   r   __call__  s    
zLinearTriInterpolator.__call__c             C   s   | j ||d ddS )N)r    r!   )r-   r.   )r2   )r   r   r,   r   r   r   gradient  s    
zLinearTriInterpolator.gradientc             C   sv   |dkr:| j |df | | j |df |  | j |df  S |dkrP| j |df S |dkrf| j |df S td| d S )Nr   r   r   r   r    r!   zInvalid return_key: )r:   r	   )r   r0   r-   r   r,   r   r   r   r*     s    "z-LinearTriInterpolator._interpolate_single_key)N)r4   r5   r6   r7   r   r;   r   r8   r<   r9   r*   r   r   r   r   r      s   
r   c               @   sp   e Zd ZdZdddZdd Zeje_dd	 Zej	e_d
d Z
dddZedd Zedd Zedd ZdS )r   a  
    A CubicTriInterpolator performs cubic interpolation on triangular grids.

    In one-dimension - on a segment - a cubic interpolating function is
    defined by the values of the function and its derivative at both ends.
    This is almost the same in 2-d inside a triangle, except that the values
    of the function and its 2 derivatives have to be defined at each triangle
    node.

    The CubicTriInterpolator takes the value of the function at each node -
    provided by the user - and internally computes the value of the
    derivatives, resulting in a smooth interpolation.
    (As a special feature, the user can also impose the value of the
    derivatives at each node, but this is not supposed to be the common
    usage.)

    Parameters
    ----------
    triangulation : :class:`~matplotlib.tri.Triangulation` object
        The triangulation to interpolate over.
    z : array_like of shape (npoints,)
        Array of values, defined at grid points, to interpolate between.
    kind : {'min_E', 'geom', 'user'}, optional
        Choice of the smoothing algorithm, in order to compute
        the interpolant derivatives (defaults to 'min_E'):

            - if 'min_E': (default) The derivatives at each node is computed
              to minimize a bending energy.
            - if 'geom': The derivatives at each node is computed as a
              weighted average of relevant triangle normals. To be used for
              speed optimization (large grids).
            - if 'user': The user provides the argument `dz`, no computation
              is hence needed.

    trifinder : :class:`~matplotlib.tri.TriFinder` object, optional
        If not specified, the Triangulation's default TriFinder will
        be used by calling
        :func:`matplotlib.tri.Triangulation.get_trifinder`.
    dz : tuple of array_likes (dzdx, dzdy), optional
        Used only if  *kind* ='user'. In this case *dz* must be provided as
        (dzdx, dzdy) where dzdx, dzdy are arrays of the same shape as *z* and
        are the interpolant first derivatives at the *triangulation* points.

    Methods
    -------
    `__call__` (x, y) :  Returns interpolated values at x,y points
    `gradient` (x, y) : Returns interpolated derivatives at x,y points

    Notes
    -----
    This note is a bit technical and details the way a
    :class:`~matplotlib.tri.CubicTriInterpolator` computes a cubic
    interpolation.

    The interpolation is based on a Clough-Tocher subdivision scheme of
    the *triangulation* mesh (to make it clearer, each triangle of the
    grid will be divided in 3 child-triangles, and on each child triangle
    the interpolated function is a cubic polynomial of the 2 coordinates).
    This technique originates from FEM (Finite Element Method) analysis;
    the element used is a reduced Hsieh-Clough-Tocher (HCT)
    element. Its shape functions are described in [1]_.
    The assembled function is guaranteed to be C1-smooth, i.e. it is
    continuous and its first derivatives are also continuous (this
    is easy to show inside the triangles but is also true when crossing the
    edges).

    In the default case (*kind* ='min_E'), the interpolant minimizes a
    curvature energy on the functional space generated by the HCT element
    shape functions - with imposed values but arbitrary derivatives at each
    node. The minimized functional is the integral of the so-called total
    curvature (implementation based on an algorithm from [2]_ - PCG sparse
    solver):

        .. math::

            E(z) = \frac{1}{2} \int_{\Omega} \left(
                \left( \frac{\partial^2{z}}{\partial{x}^2} \right)^2 +
                \left( \frac{\partial^2{z}}{\partial{y}^2} \right)^2 +
                2\left( \frac{\partial^2{z}}{\partial{y}\partial{x}} \right)^2
            \right) dx\,dy

    If the case *kind* ='geom' is chosen by the user, a simple geometric
    approximation is used (weighted average of the triangle normal
    vectors), which could improve speed on very large grids.

    References
    ----------
    .. [1] Michel Bernadou, Kamal Hassan, "Basis functions for general
        Hsieh-Clough-Tocher triangles, complete or reduced.",
        International Journal for Numerical Methods in Engineering,
        17(5):784 - 789. 2.01.
    .. [2] C.T. Kelley, "Iterative Methods for Optimization".

    min_ENc             C   s   t | ||| | j  t| j}|dd\}}}	}
}|| _|
| _|dk}| j| j||  < | j|  | _t	
|| _t	
|	| _t	|| j |	| j g| _| j| j | _| | j| _| j||d| _t | _d S )NTr   )dz)r   r   r
   Zget_cpp_triangulationr   Z_get_compressed_triangulation
_trianglesr   r   r   Zptpr   r   Zcolumn_stack_pts	_tris_pts_compute_tri_eccentricities_eccs_compute_dof_dof_ReducedHCT_Element_ReferenceElement)r   r   r   kindr   r>   Ztri_analyzerZcompressed_trianglesZcompressed_xZcompressed_yZ	tri_renumZ
node_renumZ	node_maskr   r   r   r     s"    


zCubicTriInterpolator.__init__c             C   s   | j ||d ddd S )N)r   )r-   r.   r   )r2   )r   r   r,   r   r   r   r;     s    
zCubicTriInterpolator.__call__c             C   s   | j ||d ddS )N)r    r!   )r-   r.   )r2   )r   r   r,   r   r   r   r<     s    
zCubicTriInterpolator.gradientc             C   s   | j | }| |||}| j| }tj| j| dd}|dkrN| j|||S |dkr| |}	| j	||	||}
|dkr|
d d ddf S |
d d ddf S nt
d| d S )Nr   )axisr   )r    r!   r    r   zInvalid return_key: )rA   _get_alpha_vecrC   r   expand_dimsrE   rG   get_function_values_get_jacobianget_function_derivativesr	   )r   r0   r-   r   r,   tris_ptsalphaeccdofJr    r   r   r   r*     s    



z,CubicTriInterpolator._interpolate_single_keyc             C   s`   |dkr&|dkrt dt| |d}n2|dkr8t| }n |dkrJt| }nt d|| S )ap  
        Computes and returns nodal dofs according to kind

        Parameters
        ----------
        kind: {'min_E', 'geom', 'user'}
            Choice of the _DOF_estimator subclass to perform the gradient
            estimation.
        dz: tuple of array_likes (dzdx, dzdy), optional
            Used only if *kind*=user; in this case passed to the
            :class:`_DOF_estimator_user`.

        Returns
        -------
        dof : array_like, shape (npts,2)
              Estimation of the gradient at triangulation nodes (stored as
              degree of freedoms of reduced-HCT triangle elements).
        userNzQFor a CubicTriInterpolator with *kind*='user', a valid *dz* argument is expected.)r>   Zgeomr=   zTCubicTriInterpolator *kind* proposed: {0}; should be one of: 'user', 'geom', 'min_E')r	   _DOF_estimator_user_DOF_estimator_geom_DOF_estimator_min_Er$   compute_dof_from_df)r   rH   r>   ZTEr   r   r   rD     s    

z!CubicTriInterpolator._compute_dofc             C   s.  |j d }|dddddf |dddddf  }|dddddf |dddddf  }tj||gdd}t|}tj| |gdd|dddddf  }t||}	t|	}
t|tt||}t|
|}td|ddddf  |ddddf  g|ddddf g|ddddf gg}|S )aT  
        Fast (vectorized) function to compute barycentric coordinates alpha.

        Parameters
        ----------
        x, y : array-like of dim 1 (shape (nx,))
                  Coordinates of the points whose points barycentric
                  coordinates are requested
        tris_pts : array like of dim 3 (shape: (nx,3,2))
                    Coordinates of the containing triangles apexes.

        Returns
        -------
        alpha : array of dim 2 (shape (nx,3))
                 Barycentric coordinates of the points inside the containing
                 triangles.
        r   Nr   r   r   )rI   )ndimr   stack_transpose_vectorized_prod_vectorized_pseudo_inv22sym_vectorizedrK   _to_matrix_vectorized)r   r,   rO   rY   abZabTZabZOMZmetricZ
metric_invZCovarksirP   r   r   r   rJ     s    
,,(

Rz#CubicTriInterpolator._get_alpha_vecc             C   s   t | dddddf | dddddf  }t | dddddf | dddddf  }t|dddf |dddf g|dddf |dddf gg}|S )a  
        Fast (vectorized) function to compute triangle jacobian matrix.

        Parameters
        ----------
        tris_pts : array like of dim 3 (shape: (nx,3,2))
                    Coordinates of the containing triangles apexes.

        Returns
        -------
        J : array of dim 3 (shape (nx,2,2))
                 Barycentric coordinates of the points inside the containing
                 triangles.
                 J[itri,:,:] is the jacobian matrix at apex 0 of the triangle
                 itri, so that the following (matrix) relationship holds:
                    [dz/dksi] = [J] x [dz/dx]
                    with x: global coordinates
                    ksi: element parametric coordinates in triangle first apex
                    local basis.
        Nr   r   r   )r   arrayr^   )rO   r_   r`   rS   r   r   r   rM     s
    22 $z"CubicTriInterpolator._get_jacobianc             C   s"  t j| dddddf | dddddf  dd}t j| dddddf | dddddf  dd}t j| dddddf | dddddf  dd}tt||ddddf }tt||ddddf }tt||ddddf }t|| | g|| | g|| | ggS )a  
        Computes triangle eccentricities

        Parameters
        ----------
        tris_pts : array like of dim 3 (shape: (nx,3,2))
                   Coordinates of the triangles apexes.

        Returns
        -------
        ecc : array like of dim 2 (shape: (nx,3))
              The so-called eccentricity parameters [1] needed for
              HCT triangular element.
        Nr   r   )rI   r   )r   rK   r\   r[   r^   )rO   r_   r`   cZdot_aZdot_bZdot_cr   r   r   rB   1  s    666z0CubicTriInterpolator._compute_tri_eccentricities)r=   NN)N)r4   r5   r6   r7   r   r;   r   r8   r<   r9   r*   rD   staticmethodrJ   rM   rB   r   r   r   r   r   %  s   ^ 
(
#(r   c               @   s  e Zd ZdZeddddddddddg
ddddddddddg
ddddddddddg
dddddd	d	ddd	g
ddddd
dddddg
d
dddddddddg
dddddddd	d	d	g
d
dddddddddg
dddd
ddddddg
g	Zeddddddddddg
ddddddddddg
ddddddddddg
ddddddddddg
ddddddddddg
ddddddddddg
dddddddddd	g
ddddddddddg
ddddddddddg
g	Zeddddddddddg
ddddddddddg
ddddddddddg
ddddddddddg
ddddddddddg
ddddddddddg
ddddddddddg
d
dddddddddg
ddddddddddg
g	Zeddddddddddg
d
dddddddddg
ddddddddddg
ddddddddddg
ddddddddddg
ddddddddddg
ddddddddddg
ddddddddddg
ddddddddddg
g	Z	eddgddgddgddgddgddggZ
edddgdddgdddgdddgdddgdddgdddgdddgdddgg	ZdZejdddgdddgdddgdddgdddgdddgdddgdddgdddgg	ejdZejdgejdd ZedddgdddgdddggZeddgddggZeddgddggZdd Zdd Zdd Zd d! Zd"d# Zd*d%d&Zd'd( Zd)S )+rF   aN  
    Implementation of reduced HCT triangular element with explicit shape
    functions.

    Computes z, dz, d2z and the element stiffness matrix for bending energy:
    E(f) = integral( (d2z/dx2 + d2z/dy2)**2 dA)

    *** Reference for the shape functions: ***
    [1] Basis functions for general Hsieh-Clough-Tocher _triangles, complete or
        reduced.
        Michel Bernadou, Kamal Hassan
        International Journal for Numerical Methods in Engineering.
        17(5):784 - 789.  2.01

    *** Element description: ***
    9 dofs: z and dz given at 3 apex
    C1 (conform)

    g        g      @g      пg      ?g      ?g      ?g      g      @g      ?g      g      g      ?g      g      ?g      g       	   gqq?gqq?gqq?g98?)r   g      "@g       @c             C   s  t j|dddddf }t|| dd}t|| dd}|ddddf }|ddddf }|ddddf }	|| }
|| }|	|	 }t|
| g|| g||	 g|
|	 g|
| g|| g||	 g|| g|| g|| |	 gg
}t| j|}|t|ddddf t| j|7 }|t|ddddf t| j|7 }|t|ddddf t| j	|7 }t|d| dd}t||ddddf S )a  
        Parameters
        ----------
        alpha : is a (N x 3 x 1) array (array of column-matrices) of
        barycentric coordinates,
        ecc : is a (N x 3 x 1) array (array of column-matrices) of triangle
        eccentricities,
        dofs : is a (N x 1 x 9) arrays (arrays of row-matrices) of computed
        degrees of freedom.

        Returns
        -------
        Returns the N-array of interpolated function values.
        r   )rI   Nr   r      )
r   argmin_roll_vectorizedr^   r\   M_scalar_vectorizedM0M1M2)r   rP   rQ   dofssubtrira   Er   r,   r   x_sqy_sqz_sqVprodsr   r   r   rL     s*    0*z'_ReducedHCT_Element.get_function_valuesc             C   s  t j|dddddf }t|| dd}t|| dd}|ddddf }|ddddf }	|ddddf }
|| }|	|	 }|
|
 }td| d| gd| dgdd| gd	| |
 d	| |
 | gd	| |	 | d	| |	 gd
| |	 | | gd
|	 |
 |g|d
|	 |
 g| d
| |
 | g||
 |	|
  ||	 |	|
  gg
}t|t| j|ddd}t| j|}|t|ddddf t| j	|7 }|t|ddddf t| j
|7 }|t|ddddf t| j|7 }t|d| dd}t||}t|}t|t|}|S )a  
        Parameters
        ----------
        *alpha* is a (N x 3 x 1) array (array of column-matrices of
        barycentric coordinates)
        *J* is a (N x 2 x 2) array of jacobian matrices (jacobian matrix at
        triangle first apex)
        *ecc* is a (N x 3 x 1) array (array of column-matrices of triangle
        eccentricities)
        *dofs* is a (N x 1 x 9) arrays (arrays of row-matrices) of computed
        degrees of freedom.

        Returns
        -------
        Returns the values of interpolated function derivatives [dz/dx, dz/dy]
        in global coordinates at locations alpha, as a column-matrices of
        shape (N x 2 x 1).
        r   )rI   Nr   r   g      g      @g        g       g       @)
block_sizerI   rf   )r   rg   rh   r^   r\   _extract_submatrices	rotate_dVri   rj   rk   rl   rm   _safe_inv22_vectorizedr[   )r   rP   rS   rQ   rn   ro   ra   rp   r   r,   r   rq   rr   rs   ZdVru   ZdsdksidfdksiJ_invZdfdxr   r   r   rN     sD    

$
z,_ReducedHCT_Element.get_function_derivativesc       	      C   s2   |  ||}t||}| |}t||}t|S )a  
        Parameters
        ----------
        *alpha* is a (N x 3 x 1) array (array of column-matrices) of
        barycentric coordinates
        *J* is a (N x 2 x 2) array of jacobian matrices (jacobian matrix at
        triangle first apex)
        *ecc* is a (N x 3 x 1) array (array of column-matrices) of triangle
        eccentricities
        *dofs* is a (N x 1 x 9) arrays (arrays of row-matrices) of computed
        degrees of freedom.

        Returns
        -------
        Returns the values of interpolated function 2nd-derivatives
        [d2z/dx2, d2z/dy2, d2z/dxdy] in global coordinates at locations alpha,
        as a column-matrices of shape (N x 3 x 1).
        )get_d2Sidksij2r\   get_Hrot_from_Jr[   )	r   rP   rS   rQ   rn   d2sdksi2Zd2fdksi2H_rotZd2fdx2r   r   r   get_function_hessians  s
    


z)_ReducedHCT_Element.get_function_hessiansc             C   s  t j|dddddf }t|| dd}t|| dd}|ddddf }|ddddf }|ddddf }td| d| d| gd| ddgdd| dgd| d| d	|  d| d|  gd| d	|  d| d| d|  gd| d	|  dd
| gd| dd| gdd| d| gdd| d	|  d
| gd
| d
| || | gg
}	t|	t| j|ddd}	t| j|	}
|
t|ddddf t| j	|	7 }
|
t|ddddf t| j
|	7 }
|
t|ddddf t| j|	7 }
t|
d| dd}|S )a  
        Parameters
        ----------
        *alpha* is a (N x 3 x 1) array (array of column-matrices) of
        barycentric coordinates
        *ecc* is a (N x 3 x 1) array (array of column-matrices) of triangle
        eccentricities

        Returns
        -------
        Returns the arrays d2sdksi2 (N x 3 x 1) Hessian of shape functions
        expressed in covariante coordinates in first apex basis.
        r   )rI   Nr   r   g      @g        g       @g      @g       rf   )rw   rI   )r   rg   rh   r^   r\   rx   
rotate_d2Vri   rj   rk   rl   rm   )r   rP   rQ   ro   ra   rp   r   r,   r   Zd2Vru   r   r   r   r   r}   +  s8    $$z"_ReducedHCT_Element.get_d2Sidksij2c             C   s  t |d}t| j|}t| j|}t j|ddgt jd}d|ddddf< d|ddddf< d|ddddf< ||ddddddf< ||ddddddf< ||ddd	dd	df< | j|d
d\}}t j|ddgt jd}	| j}
| j	}xzt
| jD ]l}t ||ddf ||d}t |d}|
| }| ||}t||}|	|tt|| jt| 7 }	qW ttt||	|}	t||	S )a  
        Parameters
        ----------
        *J* is a (N x 2 x 2) array of jacobian matrices (jacobian matrix at
        triangle first apex)
        *ecc* is a (N x 3 x 1) array (array of column-matrices) of triangle
        eccentricities

        Returns
        -------
        Returns the element K matrices for bending energy expressed in
        GLOBAL nodal coordinates.
        K_ij = integral [ (d2zi/dx2 + d2zi/dy2) * (d2zj/dx2 + d2zj/dy2) dA]
        tri_J is needed to rotate dofs from local basis to global basis
        r   re   )r   r   Nrf            T)return_arear   )r   r&   r\   J0_to_J1J0_to_J2zerosr#   r~   gauss_w	gauss_ptsrangen_gaussZtiler+   rK   r}   rp   r[   rj   )r   rS   rQ   nJ1J2ZDOF_rotr   areaKweightsZptsZigaussrP   ZweightZ	d2Skdksi2Zd2Skdx2r   r   r   get_bending_matricesW  s2     


z(_ReducedHCT_Element.get_bending_matricesFc       
      C   s  t |}|ddddf }|ddddf }|ddddf }|ddddf }t|| || || g|| || || gd| | d| | || ||  gg}|s|S d|ddddf |ddddf  |ddddf |ddddf    }	||	fS dS )as  
        Parameters
        ----------
        *J* is a (N x 2 x 2) array of jacobian matrices (jacobian matrix at
        triangle first apex)

        Returns
        -------
        Returns H_rot used to rotate Hessian from local basis of first apex,
        to global coordinates.
        if *return_area* is True, returns also the triangle area (0.5*det(J))
        Nr   r   r   g      ?)rz   r^   )
r   rS   r   r|   ZJi00ZJi11ZJi10ZJi01r   r   r   r   r   r~     s    *Lz#_ReducedHCT_Element.get_Hrot_from_Jc             C   s  t |d}t j|t jd}t j|t jd }ddddddg}dd	d
g}	t||dddf d |dddf d d ||dddf d |dddf d d ||dddf d |dddf d d g	g}
t j|ddgt jd}tt|
t|}t||
}| ||}t 	|t 
||| }t 	|t 
||| }t 	|t 
||| }|t 
|||	 }t j|dd}t||dddddf  }|
t 
|dg| dddddf }t jt 	|t 	|d}||||fS )aG  
        Builds K and F for the following elliptic formulation:
        minimization of curvature energy with value of function at node
        imposed and derivatives 'free'.
        Builds the global Kff matrix in cco format.
        Builds the full Ff vec Ff = - Kfc x Uc

        Parameters
        ----------
        *J* is a (N x 2 x 2) array of jacobian matrices (jacobian matrix at
        triangle first apex)
        *ecc* is a (N x 3 x 1) array (array of column-matrices) of triangle
        eccentricities
        *triangles* is a (N x 3) array of nodes indexes.
        *Uc* is (N x 3) array of imposed displacements at nodes

        Returns
        -------
        (Kff_rows, Kff_cols, Kff_vals) Kff matrix in coo format - Duplicate
        (row, col) entries must be summed.
        Ff: force vector - dim npts * 3
        r   )r   r   r   r      r      rf   r   Nre   )rI   )r   )r   r&   arangeint32onesr^   r\   r[   r   r%   Zix_rK   bincount)r   rS   rQ   	trianglesUcZntriZ	vec_rangeZ	c_indicesZf_dofZc_dofZf_dof_indicesZexpand_indicesZf_row_indicesZf_col_indicesZK_elemKff_valsKff_rowsKff_colsZKfc_elemZUc_elemZFf_elemZ
Ff_indicesFfr   r   r   get_Kff_and_Ff  s.    
**2

&z"_ReducedHCT_Element.get_Kff_and_FfN)F)r4   r5   r6   r7   r   rb   ri   rk   rl   rm   ry   r   r   r#   r   r   r   rp   r   r   rL   rN   r   r}   r   r~   r   r   r   r   r   rF   R  s   "%;,5
rF   c               @   s4   e Zd ZdZdd Zdd Zdd Zedd	 Zd
S )_DOF_estimatoraj  
    Abstract base class for classes used to perform estimation of a function
    first derivatives, and deduce the dofs for a CubicTriInterpolator using a
    reduced HCT element formulation.
    Derived classes implement compute_df(self,**kwargs), returning
    np.vstack([dfx,dfy]).T where : dfx, dfy are the estimation of the 2
    gradient coordinates.
    c             K   s^   t |tstd|j| _|j| _|j| _|j| _|j|j	 | _| _	| j
f || _|   d S )Nz&Expected a CubicTriInterpolator object)r   r   r	   r@   rA   r   r   r?   r   r   
compute_dzr>   rX   )r   Zinterpolatorkwargsr   r   r   r     s    
z_DOF_estimator.__init__c             K   s   t d S )N)r3   )r   r   r   r   r   r   	  s    z_DOF_estimator.compute_dzc             C   s6   t | j}| j| j }| j| j }| |||}|S )za
        Computes reduced-HCT elements degrees of freedom, knowing the
        gradient.
        )r   rM   rA   r   r?   r>   get_dof_vec)r   rS   tri_ztri_dzZtri_dofr   r   r   rX     s
    z"_DOF_estimator.compute_dof_from_dfc             C   sr  | j d }tj|dgtjd}ttj|}ttj|}t|tj|dddddf dd}t|tj|dddddf dd}t|tj|dddddf dd}	t	|ddddf |ddddf |	ddddf g|ddddf |ddddf |	ddddf gg}
| |ddddd	f< |
dddf |dddd
d	f< |
dddf |ddddd	f< |S )a  
        Computes the dof vector of a triangle, knowing the value of f, df and
        of the local Jacobian at each node.

        *tri_z*: array of shape (3,) of f nodal values
        *tri_dz*: array of shape (3,2) of df/dx, df/dy nodal values
        *J*: Jacobian matrix in local basis of apex 0

        Returns dof array of shape (9,) so that for each apex iapex:
            dof[iapex*3+0] = f(Ai)
            dof[iapex*3+1] = df(Ai).(AiAi+)
            dof[iapex*3+2] = df(Ai).(AiAi-)]
        r   re   )r   Nr   )rI   r   r   rf   r   )
r   r   r   r#   r\   rF   r   r   rK   r^   )r   r   rS   ZnptrR   r   r   Zcol0Zcol1Zcol2r{   r   r   r   r     s    
&&&28""z_DOF_estimator.get_dof_vecN)	r4   r5   r6   r7   r   r   rX   rd   r   r   r   r   r   r     s
   r   c               @   s   e Zd ZdZdd ZdS )rU   z5 dz is imposed by user / Accounts for scaling if any c             C   s,   |\}}|| j  }|| j }t||gjS )N)r   r   r   vstackT)r   r>   r    r!   r   r   r   r   :  s    

z_DOF_estimator_user.compute_dzN)r4   r5   r6   r7   r   r   r   r   r   rU   8  s   rU   c               @   s(   e Zd ZdZdd Zdd Zdd ZdS )	rV   z? Fast 'geometric' approximation, recommended for large arrays. c             C   s  |   }|  }tjt| jt|d}t|}t|}xhtdD ]\}|dd|f |dddf  |dd|f< |dd|f |dddf  |dd|f< qJW tjt| jt|d}tjt| jt|d}|| }	|| }
t|	|
gj	S )a  
        self.df is computed as weighted average of _triangles sharing a common
        node. On each triangle itri f is first assumed linear (= ~f), which
        allows to compute d~f[itri]
        Then the following approximation of df nodal values is then proposed:
            f[ipt] = SUM ( w[itri] x d~f[itri] , for itri sharing apex ipt)
        The weighted coeff. w[itri] are proportional to the angle of the
        triangle itri at apex ipt
        )r   rf   Nr   r   )
compute_geom_weightscompute_geom_gradsr   r   r%   r?   
empty_liker   r   r   )r   Z	el_geom_wZel_geom_gradZ
w_node_sumZdfx_el_wZdfy_el_wZiapexZdfx_node_sumZdfy_node_sumZ	dfx_estimZ	dfy_estimr   r   r   r   C  s     


,0z_DOF_estimator_geom.compute_dzc       
      C   sP  t t | jddg}| j}x*tdD ]}|dd|d ddf }|dd|d d ddf }|dd|d d ddf }t |dddf |dddf  |dddf |dddf  }t |dddf |dddf  |dddf |dddf  }t t || t j	 d}	dt |	d  |dd|f< q*W |S )z
        Builds the (nelems x 3) weights coeffs of _triangles angles,
        renormalized so that np.sum(weights, axis=1) == np.ones(nelems)
        r   rf   Nr   g      ?g      ?)
r   r   r&   r?   rA   r   Zarctan2absmodZpi)
r   r   rO   ZiptZp0Zp1Zp2Zalpha1Zalpha2Zangler   r   r   r   d  s    DD"z(_DOF_estimator_geom.compute_geom_weightsc             C   s~  | j }| j| j }|dddddf |dddddf  }|dddddf |dddddf  }t||g}t|}|dddf |dddf  }|dddf |dddf  }t||gj}	t|	}
|	dddf |ddddf  |	dddf |ddddf   |
dddf< |	dddf |ddddf  |	dddf |ddddf   |
dddf< |
S )z
        Compute the (global) gradient component of f assumed linear (~f).
        returns array df of shape (nelems,2)
        df[ielem].dM[ielem] = dz[ielem] i.e. df = dz x dM = dM.T^-1 x dz
        Nr   r   r   )	rA   r   r?   r   Zdstackrz   r   r   r   )r   rO   Ztris_fZdM1ZdM2ZdMZdM_invZdZ1ZdZ2ZdZZdfr   r   r   r   z  s    ,,  
PPz&_DOF_estimator_geom.compute_geom_gradsN)r4   r5   r6   r7   r   r   r   r   r   r   r   rV   A  s   !rV   c               @   s    e Zd ZdZdd Zdd ZdS )rW   z
    The 'smoothest' approximation, df is computed through global minimization
    of the bending energy:
      E(f) = integral[(d2z/dx2 + d2z/dy2 + 2 d2z/dxdy)**2 dA]
    c             C   s   |j | _ t| | d S )N)rC   rV   r   )r   ZInterpolatorr   r   r   r     s    z_DOF_estimator_min_E.__init__c             C   s  t | }t|}t }t| j}| j}| j	}| j
| j	 }|||||\}}	}
}d}|jd }t|
||	||fd}|  t||||d\}}tj||| }||k rtd |}tj| jjd dgtjd}|ddd |dddf< |d	dd |ddd	f< |S )
z{
        Elliptic solver for bending energy minimization.
        Uses a dedicated 'toy' sparse Jacobi PCG solver.
        g|=r   )r   )Ar`   x0tolzIn TriCubicInterpolator initialization, PCG sparse solver did not converge after 1000 iterations. `geom` approximation is used instead of `min_E`r   )r   Nr   )rV   r   r   r%   rF   r   rM   rA   rC   r?   r   r   r   _Sparse_Matrix_coocompress_csc_cglinalgnormdotwarningswarnr(   r@   r#   )r   Zdz_initZUf0Zreference_elementrS   Zeccsr   r   r   r   r   r   r   Zn_dofZKff_cooZUferrZerr0r>   r   r   r   r     s.    



z_DOF_estimator_min_E.compute_dzN)r4   r5   r6   r7   r   r   r   r   r   r   rW     s   rW   c               @   sH   e Zd Zdd Zdd Zdd Zdd Zd	d
 Zdd Ze	dd Z
dS )r   c             C   sF   |\| _ | _tj|tjd| _tj|tjd| _tj|tjd| _dS )a4  
        Creates a sparse matrix in coo format
        *vals*: arrays of values of non-null entries of the matrix
        *rows*: int arrays of rows of non-null entries of the matrix
        *cols*: int arrays of cols of non-null entries of the matrix
        *shape*: 2-tuple (n,m) of matrix shape

        )r   N)	r   mr   r   r#   valsr   rowscols)r   r   r   r   r   r   r   r   r     s    	z_Sparse_Matrix_coo.__init__c             C   s2   |j | jfksttj| j| j|| j  | jdS )z
        Dot product of self by a vector *V* in sparse-dense to dense format
        *V* dense vector of shape (self.m,)
        )r   Z	minlength)r   r   AssertionErrorr   r   r   r   r   )r   rt   r   r   r   r     s    z_Sparse_Matrix_coo.dotc             C   sR   t j| j| j| j  ddd\}}}| j| | _| j| | _t j|| jd| _dS )zV
        Compress rows, cols, vals / summing duplicates. Sort for csc format.
        T)r1   return_inverse)r   N)r   uniquer   r   r   r   r   )r   _r   indicesr   r   r   r     s    z_Sparse_Matrix_coo.compress_cscc             C   sR   t j| j| j | j ddd\}}}| j| | _| j| | _t j|| jd| _dS )zV
        Compress rows, cols, vals / summing duplicates. Sort for csr format.
        T)r1   r   )r   N)r   r   r   r   r   r   r   )r   r   r   r   r   r   r   compress_csr  s    z_Sparse_Matrix_coo.compress_csrc             C   s\   t j| j| jgt jd}| jj}x6t|D ]*}|| j| | j	| f  | j| 7  < q*W |S )zb
        Returns a dense matrix representing self.
        Mainly for debugging purposes.
        )r   )
r   r   r   r   r#   r   r&   r   r   r   )r   r/   Znvalsir   r   r   to_dense  s
    *z_Sparse_Matrix_coo.to_densec             C   s   |    S )N)r   __str__)r   r   r   r   r   	  s    z_Sparse_Matrix_coo.__str__c             C   s>   | j | jk}tjt| j| jtjd}| j| || j | < |S )zF
        Returns the (dense) vector of the diagonal elements.
        )r   )r   r   r   r   minr   r#   r   )r   Zin_diagdiagr   r   r   r     s    z_Sparse_Matrix_coo.diagN)r4   r5   r6   r   r   r   r   r   r   propertyr   r   r   r   r   r     s   
r   绽|=  c             C   s>  |j }| j|kst| j|ks"ttj|}| j}t|dk|d}|dkrZt	|}n|}|| 
| }	|	| }
t	|}d}t
|	|
}d}xtt||| kr||k r|
||  }| 
|}|t
|| }|	||  }	|	| }
|}t
|	|
}|||  }|| }|d7 }qW tj| 
|| }||fS )ah  
    Use Preconditioned Conjugate Gradient iteration to solve A x = b
    A simple Jacobi (diagonal) preconditionner is used.

    Parameters
    ----------
    A: _Sparse_Matrix_coo
        *A* must have been compressed before by compress_csc or
        compress_csr method.

    b: array
        Right hand side of the linear system.

    Returns
    -------
    x: array.
        The converged solution.
    err: float
        The absolute error np.linalg.norm(A.dot(x) - b)

    Other parameters
    ----------------
    x0: array.
        Starting guess for the solution.
    tol: float.
        Tolerance to achieve. The algorithm terminates when the relative
        residual is below tol.
    maxiter: integer.
        Maximum number of iterations. Iteration will stop
        after maxiter steps even if the specified tolerance has not
        been achieved.
    gư>Ng        r   r   )r&   r   r   r   r   r   r   r   wherer   r   Zsqrtr   )r   r`   r   r   maxiterr   Zb_normZkvecr   rwpZbetaZrhokr   rP   Zrhooldr   r   r   r   r     s8    !
$
r   c             C   s^  | j dkst| jdd dks$tt| }| ddddf | ddddf  }|| ddddf | ddddf   }t|dt| k}t|rd| }n t| jd }d||  ||< | ddddf | |ddddf< | ddddf  | |ddddf< | ddddf  | |ddddf< | ddddf | |ddddf< |S )	z
    Inversion of arrays of (2,2) matrices, returns 0 for rank-deficient
    matrices.

    *M* : array of (2,2) matrices to inverse, shape (n,2,2)
    rf   N)r   r   r   r   g:0yE>g      ?)rY   r   r   r   r   r   allr   )ri   M_invprod1deltarank2Z	delta_invr   r   r   rz     s    
$(

$&&$rz   c       	      C   sj  | j dkst| jdd dks$tt| }| ddddf | ddddf  }|| ddddf | ddddf   }t|dt| k}t|r6| ddddf | |ddddf< | ddddf  | |ddddf< | ddddf  | |ddddf< | ddddf | |ddddf< n0|| }| |ddf | ||ddf< | |ddf  | ||ddf< | |ddf  | ||ddf< | |ddf | ||ddf< | }| |ddf | |ddf  }t|dk }d| |d	 |  }| |ddf | ||ddf< | |ddf | ||ddf< | |ddf | ||ddf< | |ddf | ||ddf< |S )
a  
    Inversion of arrays of (2,2) SYMMETRIC matrices; returns the
    (Moore-Penrose) pseudo-inverse for rank-deficient matrices.

    In case M is of rank 1, we have M = trace(M) x P where P is the orthogonal
    projection on Im(M), and we return trace(M)^-1 x P == M / trace(M)**2
    In case M is of rank 0, we return the null matrix.

    *M* : array of (2,2) matrices to inverse, shape (n,2,2)
    rf   r   N)r   r   r   r   g:0yE>g      ?r   )rY   r   r   r   r   r   r   )	ri   r   r   r   r   Zrank01ZtrZtr_zerosZ	sq_tr_invr   r   r   r]     s2    
$($&&(r]   c             C   s   | j }|j }t|dkstt|dks,t|d |d ks@tt|}t|d |d |d f}tt| |dtjf |dtjddf  dS )zm
    Matrix product between arrays of matrices, or a matrix and an array of
    matrices (*M1* and *M2*)
    r   r   r   r   .N)r   lenr   r   r   sum	transposenewaxis)rl   rm   Zsh1Zsh2Zndim1Zt1_indexr   r   r   r\     s    r\   c             C   s   | ddt jt jf | S )z6
    Scalar product between scalars and matrices.
    N)r   r   )Zscalarri   r   r   r   rj     s    rj   c             C   s   t | dddgS )z4
    Transposition of an array of matrices *M*.
    r   r   r   )r   r   )ri   r   r   r   r[     s    r[   c             C   s&  |dkst | j}|dkst |j}|dks0t | j}|dd \}}|d |jd ks\t tj|d tjd}t| }	|dkrxt|D ]<}
x6t|D ]*}| || |
 | |f |	dd|
|f< qW qW nT|dkr"xHt|D ]<}
x6t|D ]*}| ||
| | | f |	dd|
|f< qW qW |	S )z
    Rolls an array of matrices along an axis according to an array of indices
    *roll_indices*
    *axis* can be either 0 (rolls rows) or 1 (rolls columns).
    )r   r   rf   r   r   Nr   )r   )r   rY   r   r   r   r   r   r   )ri   Zroll_indicesrI   rY   Z	ndim_rollshr   rc   Zvec_indicesZM_rolliricr   r   r   rh     s&    
0
.rh   c       
      C   s   t | ttfsttdd | D s(ttdd | D }t||d  dksVtt| }|d }t| d d }|j}|j	d ||g}tj
||d}xBt|D ]6}x0t|D ]$}	t| | |	 |dd||	f< qW qW |S )z
    Builds an array of matrices from individuals np.arrays of identical
    shapes.
    *M*: ncols-list of nrows-lists of shape sh.

    Returns M_res np.array of shape (sh, nrow, ncols) so that:
        M_res[...,i,j] = M[i][j]
    c             s   s   | ]}t |ttfV  qd S )N)r   tuplelist).0itemr   r   r   	<genexpr>$  s    z(_to_matrix_vectorized.<locals>.<genexpr>c             S   s   g | ]}t |qS r   )r   )r   r   r   r   r   
<listcomp>%  s    z)_to_matrix_vectorized.<locals>.<listcomp>r   )r   N)r   r   r   r   r   r   r   r   r   r   r(   r   )
ri   Zc_vecr   rc   ZM00dtr   ZM_retZirowZicolr   r   r   r^     s    	(r^   c             C   s   |j dkst|dkst| j\}}|dkr>|jd ||g}n|dkrV|jd ||g}| j}tj||d}|dkrxt|D ].}	| || |	 ddf |dd|	ddf< q|W nD|dkrx:t|D ].}
| dd|| |
 f |dddd|
f< qW |S )z
    Extracts selected blocks of a matrices *M* depending on parameters
    *block_indices* and *block_size*.

    Returns the array of extracted matrices *Mres* so that:
        M_res[...,ir,:] = M[(block_indices*block_size+ir), :]
    r   )r   r   r   )r   N)rY   r   r   r   r   r(   r   )ri   Zblock_indicesrw   rI   r   rc   r   r   ZM_resr   r   r   r   r   rx   3  s     
0.rx   )Nr   r   )r7   r   Znumpyr   Zmatplotlib.trir   Zmatplotlib.tri.trifinderr   Zmatplotlib.tri.tritoolsr   __all__objectr   r   r   rF   r   rU   rV   rW   r   r   rz   r]   r\   rj   r[   rh   r^   rx   r   r   r   r   <module>   s<    ^8  /   %D	T:H
y/