U
    f»{jgâ  ã                   @   sþ  d dl Z d dlmZ d dlZd dlZddlmZ ddl	m
Z
 ddlmZ ddlmZmZmZmZ ddlmZmZmZ ddlmZmZmZ dd	lmZmZmZmZmZ m!Z!m"Z"m#Z#m$Z$m%Z%mZm&Z&m'Z'm(Z(m)Z)m*Z* edYdd„ƒZ+dZdd„Z,dddddddddddd d!d"d#d$d%gZ-e!G d&d'„ d'ƒƒZ.e/ƒ Z0d[d(d)„Z1d*d+„ Z2d,d-„ Z3d\d/d0„Z4d1d2„ Z5d]d5d6„Z6d7d8„ Z7d^d9d:„Z8d;d<„ Z9d=d>„ Z:d?d@„ Z;d_dAdB„Z<dCdD„ Z=ed`dEdF„ƒZ>e&dGƒdHdI„ ƒZ?dJdK„ Z@e&dGƒdLdM„ ƒZAdNdO„ ZBdPdQ„ ZCdRdS„ ZDdTdU„ ZEdVZFdWdX„ ZGdS )aé    Né   )Ú_get_img_fdata)Úread_morph_map)Úparallel_func)Ú_BaseSurfaceSourceEstimateÚ_BaseVolSourceEstimateÚ_BaseSourceEstimateÚ_get_ico_tris)ÚSourceSpacesÚ_ensure_srcÚ_grid_interp)Ú
mesh_edgesÚread_surfaceÚ_compute_nearest)ÚloggerÚverboseÚcheck_versionÚget_subjects_dirÚwarnÚfill_docÚ_check_optionÚ_validate_typeÚ
BunchConstÚ_check_fnamer   Ú_custom_lru_cacheÚ_ensure_intÚProgressBarÚuse_log_levelÚ_import_h5io_funcsÚ	fsaverageÚauto©éd   r"   é
   ©é   r%   é   r%   TFc           &      C   s¨  t | ƒ\}}}t||ƒ}~ t|tdfdƒ t|tdfdƒ |dkrR|dkrRtdƒ‚t||dƒ}|rfdn|	}	|dkr~|
r~tdƒ‚|r’|dkr’tdƒ‚t|d	d
�}d } } } }}tƒ tƒ  }}|dk�rhtddd� ddl	}t
 d¡ t dd¡}t |||¡}t
 d| ¡ t ¡ � | |¡}W 5 Q R X t |||¡}t |¡�sTtd| ƒ‚t
 d| ¡ t ¡ � | |¡}W 5 Q R X d}|dk�r¢|dk�rBtdƒ‚n |jdk�r²dnd} t |d d d |d d d ¡}!|!dd…  d9  < |d d |!f|d < d!d"„ || d… D ƒ}t |d d d ¡dd… d# }t|ƒ}t|||ƒ}t|||||ƒ\}}}}}|d$k�r<t
 d%¡ |d& }"|�r¾|dk	�rœtd'ƒ‚|
�rªtd(ƒ‚t|"|||ƒ\}}n~|dk	�rð|jd$k�sØt‚d)d"„ |dd… D ƒ}nt|||d*ƒ}t|||"||||	|
d+�}td,d-„ |D ƒƒ}#|jd |#k�s<t‚|| }$|dk	�rdt |$ƒt |ƒk�sdt‚t!|||||||||
||$|||||dƒ}%|�rš|% "¡  t
 d.¡ |%S )/aÅ  Create a SourceMorph from one subject to another.

    Method is based on spherical morphing by FreeSurfer for surface
    cortical estimates :footcite:`GreveEtAl2013` and
    Symmetric Diffeomorphic Registration for volumic data
    :footcite:`AvantsEtAl2008`.

    Parameters
    ----------
    src : instance of SourceSpaces | instance of SourceEstimate
        The SourceSpaces of subject_from (can be a
        SourceEstimate if only using a surface source space).
    subject_from : str | None
        Name of the original subject as named in the SUBJECTS_DIR.
        If None (default), then ``src[0]['subject_his_id]'`` will be used.
    subject_to : str | None
        Name of the subject to which to morph as named in the SUBJECTS_DIR.
        Default is ``'fsaverage'``. If None, ``src_to[0]['subject_his_id']``
        will be used.

        .. versionchanged:: 0.20
           Support for subject_to=None.
    %(subjects_dir)s
    zooms : float | tuple | str | None
        The voxel size of volume for each spatial dimension in mm.
        If spacing is None, MRIs won't be resliced, and both volumes
        must have the same number of spatial dimensions.
        Can also be ``'auto'`` to use ``5.`` if ``src_to is None`` and
        the zooms from ``src_to`` otherwise.

        .. versionchanged:: 0.20
           Support for 'auto' mode.
    niter_affine : tuple of int
        Number of levels (``len(niter_affine)``) and number of
        iterations per level - for each successive stage of iterative
        refinement - to perform the affine transform.
        Default is niter_affine=(100, 100, 10).
    niter_sdr : tuple of int
        Number of levels (``len(niter_sdr)``) and number of
        iterations per level - for each successive stage of iterative
        refinement - to perform the Symmetric Diffeomorphic Registration (sdr)
        transform. Default is niter_sdr=(5, 5, 3).
    spacing : int | list | None
        The resolution of the icosahedral mesh (typically 5).
        If None, all vertices will be used (potentially filling the
        surface). If a list, then values will be morphed to the set of
        vertices specified in in ``spacing[0]`` and ``spacing[1]``.
        This will be ignored if ``src_to`` is supplied.

        .. versionchanged:: 0.21
           src_to, if provided, takes precedence.
    smooth : int | str | None
        Number of iterations for the smoothing of the surface data.
        If None, smooth is automatically defined to fill the surface
        with non-zero values. Can also be ``'nearest'`` to use the nearest
        vertices on the surface (requires SciPy >= 1.3).

        .. versionchanged:: 0.20
           Added support for 'nearest'.
    warn : bool
        If True, warn if not all vertices were used. The default is warn=True.
    xhemi : bool
        Morph across hemisphere. Currently only implemented for
        ``subject_to == subject_from``. See notes below.
        The default is xhemi=False.
    sparse : bool
        Morph as a sparse source estimate. Works only with (Vector)
        SourceEstimate. If True the only parameters used are subject_to and
        subject_from, and spacing has to be None. Default is sparse=False.
    src_to : instance of SourceSpaces | None
        The destination source space.

        - For surface-based morphing, this is the preferred over ``spacing``
          for providing the vertices.
        - For volumetric morphing, this should be passed so that 1) the
          resultingmorph volume is properly constrained to the brain volume,
          and 2) STCs from multiple subjects morphed to the same destination
          subject/source space have the vertices.
        - For mixed (surface + volume) morphing, this is required.

        .. versionadded:: 0.20
    precompute : bool
        If True (default False), compute the sparse matrix representation of
        the volumetric morph (if present). This takes a long time to
        compute, but can make morphs faster when thousands of points are used.
        See :meth:`mne.SourceMorph.compute_vol_morph_mat` (which can be called
        later if desired) for more information.

        .. versionadded:: 0.22
    %(verbose)s

    Returns
    -------
    morph : instance of SourceMorph
        The :class:`mne.SourceMorph` object.

    Notes
    -----
    This function can be used to morph surface data between hemispheres by
    setting ``xhemi=True``. The full cross-hemisphere morph matrix maps left
    to right and right to left. A matrix for cross-mapping only one hemisphere
    can be constructed by specifying the appropriate vertices, for example, to
    map the right hemisphere to the left::

        vertices_from=[[], vert_rh], vertices_to=[vert_lh, []]

    Cross-hemisphere mapping requires appropriate ``sphere.left_right``
    morph-maps in the subject's directory. These morph maps are included
    with the ``fsaverage_sym`` FreeSurfer subject, and can be created for other
    subjects with the ``mris_left_right_register`` FreeSurfer command. The
    ``fsaverage_sym`` subject is included with FreeSurfer > 5.1 and can be
    obtained as described `here
    <https://surfer.nmr.mgh.harvard.edu/fswiki/Xhemi>`_. For statistical
    comparisons between hemispheres, use of the symmetric ``fsaverage_sym``
    model is recommended to minimize bias :footcite:`GreveEtAl2013`.

    .. versionadded:: 0.17.0

    .. versionadded:: 0.21.0
       Support for morphing mixed source estimates.

    References
    ----------
    .. footbibliography::
    NÚsrc_toÚ
subject_toz-subject_to cannot be None when src_to is NoneFÚsurfacezJInter-hemispheric morphing can only be used with surface source estimates.z9Only surface source estimates can compute a sparse morph.T©Zraise_error©ÚvolumeÚmixedú2.1.0ú0.10.1©ÚnibabelÚdipyr   z!Volume source space(s) present...Zmriz	brain.mgzz    Loading %s as "from" volumezcannot read file: %sz    Loading %s as "to" volumer-   z7src_to must be provided when using a mixed source spaceé   éÿÿÿÿÚ	mri_ras_tÚtransÚ	src_mri_tr&   ç     @�@ÚshapeÚ
to_vox_mapc                 S   s   g | ]}|d  ‘qS ©Zvertno© ©Ú.0Úsr<   r<   úH/var/www/html/bwave/python/venv/lib/python3.8/site-packages/mne/morph.pyÚ
<listcomp>Ý   s     z(compute_source_morph.<locals>.<listcomp>iè  ©r)   r-   z surface source space present ...Úvertices_fromz+spacing must be set to None if sparse=True.z-xhemi=True can only be used with sparse=Falsec                 S   s   g | ]}|d    ¡ ‘qS r;   ©Úcopyr=   r<   r<   r@   rA   õ   s     r   )Úsubject_fromr(   rC   Úvertices_toÚsubjects_dirÚsmoothr   Úxhemic                 s   s   | ]}t |ƒV  qd S ©N©Úlen©r>   Úvr<   r<   r@   Ú	<genexpr>þ   s     z'compute_source_morph.<locals>.<genexpr>ú[done])#Ú_get_src_dataÚ_check_subject_srcr   r
   ÚstrÚ
ValueErrorr   ÚlistÚ
_check_depr1   r   ÚinfoÚopÚjoinÚwarningsÚcatch_warningsÚloadÚisfileÚIOErrorÚkindÚnpÚdotÚdiagÚtupleÚ_check_zoomsÚ_compute_morph_sdrÚ_compute_sparse_morphÚAssertionErrorÚgrade_to_verticesÚ_compute_morph_matrixÚsumr9   rM   ÚSourceMorphÚcompute_vol_morph_mat)&ÚsrcrF   r(   rH   ÚzoomsÚniter_affineÚ	niter_sdrÚspacingrI   r   rJ   Úsparser'   Z
precomputer   Úsrc_datar`   Úsrc_subjectr9   ÚaffineÚ
pre_affineÚ	sdr_morphÚ	morph_matZvertices_to_surfZvertices_to_volZnibZmri_subpathZmri_path_fromÚmri_fromZmri_path_toÚmri_toÚzooms_src_toZsurf_offsetZ	src_ras_trC   Zn_vertsrG   Úmorphr<   r<   r@   Úcompute_source_morph   sÜ     







ÿ"    ÿ


   ÿ

   ÿ    ü

          ý
r~   c                 C   sÎ   ddl m} t|||ƒ}d}tƒ }tƒ }t| |ƒD ]F\}	}
t|
|	 ƒ}t |¡}| || ¡ | || ¡ |t	|ƒ7 }q2t 
|¡}t t	|ƒ¡}t t	|ƒ¡}|j|||fft	|ƒt	|ƒfd� ¡ }||fS )z1Get nearest vertices from one subject to another.r   ©rs   ©r9   )Úscipyrs   r   rV   ÚzipÚ_sparse_argmax_nnz_rowra   ÚargsortÚappendrM   ÚconcatenateÚarangeÚonesÚ
coo_matrixÚtocsr)rC   rF   r(   rH   rs   ÚmapsZcntÚverticesÚcolsÚvertsZmap_hemiZvertno_hÚorderÚrowsÚdatary   r<   r<   r@   rg     s$    

ÿ
rg   rF   r(   r`   ro   rp   rq   rr   rI   rJ   ry   rG   r9   rv   rw   rx   rt   Úvol_morph_matc                   @   s‚   e Zd ZdZeddœdd„ƒZedd„ ƒZedd	„ ƒZd
d„ Z	eddd„ƒZ
eddœdd„ƒZddd„Zdd„ Zeddd„ƒZdS )rl   a–	  Morph source space data from one subject to another.

    .. note:: This class should not be instantiated directly.
              Use :func:`mne.compute_source_morph` instead.

    Parameters
    ----------
    subject_from : str | None
        Name of the subject from which to morph as named in the SUBJECTS_DIR.
    subject_to : str | array | list of array
        Name of the subject on which to morph as named in the SUBJECTS_DIR.
        The default is 'fsaverage'. If morphing a volume source space,
        subject_to can be the path to a MRI volume. Can also be a list of
        two arrays if morphing to hemisphere surfaces.
    kind : str | None
        Kind of source estimate. E.g. 'volume' or 'surface'.
    zooms : float | tuple
        See :func:`mne.compute_source_morph`.
    niter_affine : tuple of int
        Number of levels (``len(niter_affine)``) and number of
        iterations per level - for each successive stage of iterative
        refinement - to perform the affine transform.
    niter_sdr : tuple of int
        Number of levels (``len(niter_sdr)``) and number of
        iterations per level - for each successive stage of iterative
        refinement - to perform the Symmetric Diffeomorphic Registration (sdr)
        transform :footcite:`AvantsEtAl2008`.
    spacing : int | list | None
        See :func:`mne.compute_source_morph`.
    smooth : int | str | None
        See :func:`mne.compute_source_morph`.
    xhemi : bool
        Morph across hemisphere.
    morph_mat : scipy.sparse.csr_matrix
        The sparse surface morphing matrix for spherical surface
        based morphing :footcite:`GreveEtAl2013`.
    vertices_to : list of ndarray
        The destination surface vertices.
    shape : tuple
        The volume MRI shape.
    affine : ndarray
        The volume MRI affine.
    pre_affine : instance of dipy.align.AffineMap
        The transformation that is applied before the before ``sdr_morph``.
    sdr_morph : instance of dipy.align.DiffeomorphicMap
        The class that applies the the symmetric diffeomorphic registration
        (SDR) morph.
    src_data : dict
        Additional source data necessary to perform morphing.
    vol_morph_mat : scipy.sparse.csr_matrix | None
        The volumetric morph matrix, if :meth:`compute_vol_morph_mat`
        was used.
    %(verbose)s

    Notes
    -----
    .. versionadded:: 0.17

    References
    ----------
    .. footbibliography::
    N)r   c                C   sž   || _ || _|| _|| _|| _|| _|| _|| _|	| _|
| _	|| _
|| _|| _|| _|| _|| _|d ks|t|ƒdkr”|dkr”|d d ksŒt‚|  ¡ }|| _d S )Nr   r,   r:   )rF   r(   r`   ro   rp   rq   rr   rI   rJ   ry   r9   rv   rx   rw   rt   r’   rM   rh   Ú_get_vol_vertices_to_nzrG   )ÚselfrF   r(   r`   ro   rp   rq   rr   rI   rJ   ry   rG   r9   rv   rw   rx   rt   r’   r   r<   r<   r@   Ú__init__l  s(    zSourceMorph.__init__c                 C   s,   t | jd tƒst‚dd„ | jd D ƒ}|S )NÚinusec                 S   s   g | ]}t  |¡d  ‘qS ©r   )ra   Úwhere)r>   Zin_r<   r<   r@   rA   ’  s     z2SourceMorph._vol_vertices_from.<locals>.<listcomp>)Ú
isinstancert   rV   rh   )r”   rC   r<   r<   r@   Ú_vol_vertices_from�  s    zSourceMorph._vol_vertices_fromc                 C   s   | j | jdkrdndd … S )Nr,   r   r3   )rG   r`   ©r”   r<   r<   r@   Ú_vol_vertices_to•  s    zSourceMorph._vol_vertices_toc              
   C   sh   t  d¡ tdd„ | jD ƒƒ}t |df¡}tdƒ�* t | j|ddd�¡d gW  5 Q R £ S Q R X d S )	Nz*Computing nonzero vertices after morph ...c                 s   s   | ]}t |ƒV  qd S rK   rL   rN   r<   r<   r@   rP   ›  s     z6SourceMorph._get_vol_vertices_to_nz.<locals>.<genexpr>r   FÚ )Ú	subselectr   )	r   rX   rk   rš   ra   rˆ   r   r˜   Ú_morph_vols)r”   Ú
n_verticesrˆ   r<   r<   r@   r“   ™  s
    

z#SourceMorph._get_vol_vertices_to_nzÚstcFc           
      C   sÊ   t |tdƒ t |tddƒ t|tƒr.d}d}nd}d}td|||ƒ t |¡}|dkrZ|n|}|jdkrp| j	|_| j	dkr‚|j| _	|j| j	kr¢t
d	|j| j	f ƒ‚t| |ƒ}	|d
krÆt| |	|||d�}	|	S )aû  Morph source space data.

        Parameters
        ----------
        stc_from : VolSourceEstimate | VolVectorSourceEstimate | SourceEstimate | VectorSourceEstimate
            The source estimate to morph.
        output : str
            Can be 'stc' (default) or possibly 'nifti1', or 'nifti2'
            when working with a volume source space defined on a regular
            grid.
        mri_resolution : bool | tuple | int | float
            If True the image is saved in MRI resolution. Default False.
            WARNING: if you have many time points the file produced can be
            huge. The default is mri_resolution=False.
        mri_space : bool | None
            Whether the image to world registration should be in mri space. The
            default (None) is mri_space=mri_resolution.
        %(verbose)s

        Returns
        -------
        stc_to : VolSourceEstimate | SourceEstimate | VectorSourceEstimate | Nifti1Image | Nifti2Image
            The morphed source estimates.
        ÚoutputÚstc_fromzsource estimate)r¡   z%when stc is a surface source estimate)r¡   Únifti1Únifti2r�   Nz>stc_from.subject and morph.subject_from must match. (%s != %s)r¡   )Úmri_resolutionÚ	mri_spacer¢   )r   rT   r   r™   r   r   rE   ÚdeepcopyÚsubjectrF   rU   Ú_apply_morph_dataÚ_morphed_stc_as_volume)
r”   r£   r¢   r¦   r§   r   Zallowed_kindsÚextrar¡   Úoutr<   r<   r@   Úapply   s<    ÿ




þ
   þzSourceMorph.applyc                C   s4   | j dks| jdk	rdS t d¡ |  dd¡| _| S )aV  Compute the sparse matrix representation of the volumetric morph.

        Parameters
        ----------
        %(verbose)s

        Returns
        -------
        morph : instance of SourceMorph
            The instance (modified in-place).

        Notes
        -----
        For a volumetric morph, this will compute the morph for an identity
        source volume, i.e., with one source vertex active at a time, and store
        the result as a :class:`sparse <scipy.sparse.csr_matrix>`
        morphing matrix. This takes a long time (minutes) to compute initially,
        but drastically speeds up :meth:`apply` for STCs, so it can be
        beneficial when many time points or many morphs (i.e., greater than
        the number of volumetric ``src_from`` vertices) will be performed.

        When calling :meth:`save`, this sparse morphing matrix is saved with
        the instance, so this only needs to be called once. This function does
        nothing if the morph matrix has already been computed, or if there is
        no volume morphing necessary.

        .. versionadded:: 0.22
        NzAComputing sparse volumetric morph matrix (will take some time...)ZVertex)rv   r’   r   rX   rŸ   )r”   r   r<   r<   r@   rm   ×  s
    
z!SourceMorph.compute_vol_morph_matTc                 C   sú  ddl m} ddlm} | jd  ¡ d d …t | j¡f }|d krL|j	d n|j	d }t 
|¡rddnd}t|ƒdkrztjntj}	|d kr¢tƒ tƒ dgf}
|s¦t‚nd }
|r¸t | j¡}ntd ƒ}t | jd	 | jd
 ¡}|d d…  d9  < | jd d d d… }t|| jjtj |¡| jj ƒ}t| jj| jjtj | jj¡| jj | jj ƒ}|| }d }ttt|ƒƒ|d�D �]^}|D �]P}|d k�rœ|d d …|f }n|t|d d …|f |ƒ }t||d|ƒ || }|  |¡�rà| !¡ }|j"| jjdd�}| j#d k	�r
| j# $|¡}t|| jdƒ | jd d k	�rê| j}t %| jd d ¡d d… }tj&| j'|dd��st||| j| j'|ƒ\}}t||dƒ |d k�r¸t|j	| jd d tj |¡| jd d  ƒ}||j(dd� }t|| jd d d| jd d ƒ |j(dd�| }|
d k�r"|d k	�r"tj)|j*|f|	d�}
|d k�rzt +|¡d }|
d  ,|| ¡ |
d  ,|¡ |
d  -|
d d t|ƒ ¡ nP|dk�r¦|
d d …|f | |
d d …|f< n$|
d d …|f d|  |
d d …|f< �qz�qp|d k�rö|j.|
t|ƒ|fd� /¡ }
|
S )Nr   r   ©ÚresliceÚinterpolatorr   )ÚrealÚimag)r²   r3   Úsrc_affine_rasÚsrc_affine_voxr&   r8   Úsrc_shape_fullr4   )ÚmesgÚFromÚF©r�   zFrom-reslice-transformr:   gü©ñÒMbP?)ZatolzFrom-reslice-transform-srcz$From-reslice-transform-src-subselect©Údtyper²   y              ð?r€   )0r�   rs   Údipy.align.reslicer°   rt   Ztocscra   r†   rš   r9   ÚiscomplexobjrM   Ú
complex128Úfloat64rV   rh   rœ   Úslicerb   r   rw   Zcodomain_shapeZlinalgÚinvZcodomain_grid2worldZdomain_shaperv   Zdomain_grid2worldr   ÚrangeÚgetattrÚ
_debug_imgÚissparseZtoarrayÚreshaperx   Ú	transformrc   Zallclosero   ZravelÚzerosÚsizer˜   Úextendr…   Ú
csc_matrixrŠ   )r”   Úvolsr·   rž   rs   r°   ÚinterpZn_volsÚattrsr¼   Zimg_toZ	vol_vertsÚfrom_affineÚ	src_shapeZresamp_0Zresamp_1Z
resamp_0_1Zresamp_2ÚiiÚattrZimg_realrv   Zto_zoomsÚidxr<   r<   r@   rŸ   ü  sÀ    
ÿ
þ þ ÿþþ

 ÿ   ÿÿ
 
ÿþþ
 
",
 
ÿ
zSourceMorph._morph_volsc                 C   sœ   d| j  }|d| j| jf 7 }| j dkrZ|d | j¡7 }|d | j¡7 }|d | j¡7 }n:| j dkr”|d | j¡7 }|d	| j 7 }|| j	rŽd
nd7 }d| S )Nz%sz
, %s -> %sr,   z, zooms : {}z, niter_affine : {}z, niter_sdr : {})r)   Zvectorz, spacing : {}z, smooth : %sz, xhemir�   z<SourceMorph | %s>)
r`   rF   r(   Úformatro   rp   rq   rr   rI   rJ   )r”   r?   r<   r<   r@   Ú__repr__r  s    


zSourceMorph.__repr__c                    sr   t ƒ \}}t||dd�}| d¡s*d| }‡ fdd„tD ƒ}dD ]}|| dk	r@|| j||< q@||||d	� dS )
a  Save the morph for source estimates to a file.

        Parameters
        ----------
        fname : str
            The stem of the file name. '-morph.h5' will be added if fname does
            not end with '.h5'.
        %(overwrite)s
        %(verbose)s
        F)Ú	overwriteZ
must_existz.h5z%s-morph.h5c                    s   i | ]}|t ˆ |ƒ“qS r<   )rÄ   )r>   Úkr›   r<   r@   Ú
<dictcomp>‘  s      z$SourceMorph.save.<locals>.<dictcomp>)rw   rx   N)r×   )r   r   ÚendswithÚ_SOURCE_MORPH_ATTRIBUTESÚ__dict__)r”   Úfnamer×   r   Ú_Z
write_hdf5Zout_dictÚkeyr<   r›   r@   Úsave€  s    

zSourceMorph.save)r¡   FNN)T)FN)Ú__name__Ú
__module__Ú__qualname__Ú__doc__r   r•   Úpropertyrš   rœ   r“   r®   rm   rŸ   rÖ   rà   r<   r<   r<   r@   rl   +  s(   ?ü"

    ÿ6$
vrl   c                 C   s   d S rK   r<   )r‘   rv   Útitler9   r<   r<   r@   rÅ   ›  s    rÅ   c                 C   sˆ   t |tƒr"|dkr"|d k	r|nd}|d kr<| j ¡ d d… }t |¡ t¡}|jdkrbt 	|d¡}|jdkr|t
d|jf ƒ‚t|ƒ}|S )Nr    g      @r&   ©r   )r&   zAzooms must be None, a singleton, or have shape (3,), got shape %s)r™   rT   ÚheaderZ	get_zoomsra   Z
atleast_1dÚastypeÚfloatr9   ÚrepeatrU   rd   )rz   ro   r|   r<   r<   r@   re   «  s    

ÿre   c                 C   s2   dd l }|jj d |d |d | j|¡j| dd�S )Nr   r   T)Zresample_only)Údipy.align.imaffineÚalignZimaffineÚ	AffineMapr9   rÈ   )Úimgrv   r:   r2   r<   r<   r@   Ú_resample_from_to»  s       þ þrð   rn   c                 C   s‚   t |tƒr|}n$|d kr| }n|j}|d kr4tdƒ | d krB|} n$|d k	rf| |krftd||| |f ƒ‚| d kr~td||f ƒ‚| S )Nz The source space does not contain the subject name, we recommend regenerating the source space (and forward / inverse if applicable) for better code reliabilityz'%s does not match %s subject (%s != %s)z6%s could not be inferred from %s, it must be specified)r™   rT   Ú_subjectr   rU   )r©   rn   ÚnameÚsrc_nameZsubject_checkr<   r<   r@   rS   É  s$    

ÿÿrS   c                 C   sæ   t ƒ \}}|| ƒ}|d dk	rHddlm} |d }|dƒ|d< ||d _|d dk	r€ddlm} |d }|dg ƒ|d< ||d _t|d tjƒrž|d g|d< t|d  	d	d¡tjƒrÌ|d d	 g|d d	< | 	d
d¡|d
< t
f |ŽS )zèLoad the morph for source estimates from a file.

    Parameters
    ----------
    fname : str
        Full filename including path.

    Returns
    -------
    source_morph : instance of SourceMorph
        The loaded morph.
    rw   Nr   ©rî   rx   )ÚDiffeomorphicMaprG   rt   r–   r’   )r   rì   rî   rÜ   Zdipy.align.imwarprõ   r™   ra   ZndarrayÚgetrl   )rÝ   Z	read_hdf5rÞ   Úvalsrî   rv   rõ   r}   r<   r<   r@   Úread_source_morphß  s$    


rø   r.   r/   c                 C   sF   t ddg| |gƒD ].\}}|s"dnt||ƒ}|std||f ƒ‚qdS )zCheck dependencies.r1   r2   TzF%s %s or higher must be correctly installed and accessible from PythonN)r‚   r   ÚImportError)r1   r2   ÚlibÚverZpassedr<   r<   r@   rW     s    ÿÿÿrW   c              	   C   sÜ  t |tƒst‚|jdkr | ¡ }tddd� t|ƒ\}}t |ttfƒrVt|ƒfd }nt |t	ƒrd|}t |t
ƒr~|rzt| ƒnd}|ƒ }| dd¡ d|j |d	 d
< | jd dk	rÎ| jd d }	| jd d }
n| j}	| j}
|jjdksêt‚|jjd }t t |	¡|f¡}|j||jd dd…f< |j|	|f dd�}~	t ¡ � |||
|d�}W 5 Q R X | jdd… }|dk	�rÄddlm} |dd… }|t|ƒ|j||ƒ\}}
t ¡ � |||
ƒ}W 5 Q R X |}|j t	|ƒd ¡ |S )z>Return volume source space as Nifti1Image and/or save to disk.r&   r.   Fr0   NÚmmÚmsecr8   Úpixdimé   r:   r   r   r3   r¹   rº   ©rè   r¯   rç   ) r™   r   rh   Z
_data_ndimZ	magnituderW   Ú_triage_outputÚintrê   rd   ÚboolÚ_get_zooms_origÚset_xyzt_unitsÚtsteprt   r9   rv   r‘   Úndimra   rÉ   ÚprodrŒ   rÇ   r[   r\   ro   r½   r°   r   rè   Z	set_zooms)r}   r¡   r¦   r§   r¢   Ú
NiftiImageÚNiftiHeaderZ	new_zoomsÚhdrr9   rv   Ún_timesrï   ro   r°   r<   r<   r@   r«     sR    




ý
r«   c                 C   s¤  t | tdtfddƒ t| tƒrJt| jd d�t| jd d�g}d}| j}nt| ƒ ¡ }|j	}|j
}~ td|d	ƒ tƒ }|d
k�rr|d }|d }|dkrœdnd}t||d … |ƒD ]4\}	}
|
 dd ¡d kr²|rÜtd|	f ƒ‚d } �qq²tdd„ ||d … D ƒdƒ}dd„ ||d … D ƒ}| |d |d |d f|d d |d d |d d |d |d |d f||d dœ¡ |dk�rš|jdd„ |d d… D ƒd � |||fS )!Nz	path-likern   z'source space or surface source estimater   r;   r   r)   zsrc kind©r)   r,   r-   r+   r4   r9   r,   r3   r±   zGMRI interpolator not present in src[%d], cannot use mri_resolution=Truec                 s   s   | ]}|d  V  qdS )r±   Nr<   r=   r<   r<   r@   rP   l  s     z _get_src_data.<locals>.<genexpr>g        c                 S   s   g | ]}|d  ‘qS ©r–   r<   r=   r<   r<   r@   rA   m  s     z!_get_src_data.<locals>.<listcomp>Z	vox_mri_tr6   r7   r5   Z
mri_heightZ	mri_depthZ	mri_width)rÑ   rµ   Úsrc_affine_srcr´   r¶   r±   r–   r:   rB   c                 S   s   g | ]}|d    ¡ ‘qS r;   rD   r=   r<   r<   r@   rA   z  s     )rC   )r   r   r
   r™   ÚdictrŒ   r©   r   rE   r`   rñ   r   Ú	enumeraterö   ÚRuntimeErrorrk   Úupdate)rn   r¦   Zsrc_tZsrc_kindru   rt   Zuse_srcr9   ÚstartÚsir?   r±   Zinusesr<   r<   r@   rR   M  s^      þ
 
ÿÿ


 þ÷
rR   c                 C   sP   t d| dddgƒ | dkr,ddlm}m} n| dks8t‚ddlm}m} ||fS )	Nr¢   Úniftir¤   r¥   )r  r¤   r   )ÚNifti1ImageÚNifti1Header)ÚNifti2ImageÚNifti2Header)r   r1   r  r  rh   r  r  )r¢   r	  r
  r<   r<   r@   r  €  s    r  c              	   C   s  t ddd� t|ƒ\}}t| tddƒ |jdks4t‚d}t|ttfƒr^t|t	ƒs^t|ƒfd }t|t
ƒrŒt ddd� d	d
lm} |}	d}d}t|tƒ�r(|jdks¦t‚|jdkr´dnd	}
|rÄtdƒ‚dd„ ||
d… D ƒ}dd„ ||
d… D ƒ}tttt
|ƒƒƒdk�st‚|j}tt||ƒd	 d�}n|jd }|j}t|tƒ�sHt‚| jdk	�rbt| j|dƒ | jjd }|jd ddd… |f }t | j¡�rœtjntj}tj t !|dd… ¡|d f|dd�}d	}|D ]>}| "t	¡}t #|¡}t$||| ƒ}| j| ||< ||7 }�qÐ|�rV|jd dk�r.t%dƒ‚|jd ddd… |f }|jd | }tj&||dd�}|�rx|jd }n
|jd  }|�ršt '|jd! |¡}|dd…  d"9  < |ƒ }| (d#d$¡ d"| j) |d% d&< |�rî|||t*|ƒ|	ƒ\}}t+ ,¡ � ||||d'�}W 5 Q R X |S )(z(Interpolate source estimate data to MRI.r.   Fr0   r¡   zvolume source estimater+   r&   r/   r   r¯   Tr-   r3   zkCannot infer original voxel size for reslicing... set mri_resolution to boolean value or apply morph first.c                 S   s   g | ]}|d  ‘qS r  r<   r=   r<   r<   r@   rA   ®  s     z%_interpolate_data.<locals>.<listcomp>Nc                 S   s   g | ]}|d  ‘qS r€   r<   r=   r<   r<   r@   rA   ¯  s     r   )rt   r–   zstc.subjectrÑ   r4   r¹   )r¼   r�   r±   zdCannot morph with mri_resolution when add_interpolator=False was used with setup_volume_source_spacer¶   rº   rµ   r  r´   r8   rü   rý   rþ   rÿ   r   )-rW   r  r   r   r`   rh   r™   r  rê   r  rd   r½   r°   r
   rU   rM   ÚsetÚmaprñ   r   rR   rt   rF   rV   r©   rS   r‘   r9   ra   r¾   r¿   rÀ   rÉ   r  ré   rk   rÁ   r  rÇ   rb   r  r  r  r[   r\   )r¡   r}   r¦   r§   r¢   r	  r
  Zvoxel_size_definedr°   Z
voxel_sizeÚoffsetr–   rÑ   ru   r  r9   r¼   rÍ   Zn_vertices_seenZ
this_inuser    Z	stc_slicerv   rè   r<   r<   r@   Ú_interpolate_dataŒ  s’    ÿ ÿ
ÿ
&

ÿ
   ÿ
r  c                 C   sx   ddl m} ddlm} |r dnd}t||||r4|ndd�}|| ||||d	�\}	}
}}}}||	||||ƒ}	||||	|
fS )
z:Get a matrix that morphs data from one subject to another.r   )Ú_compute_volume_registrationr   rô   ÚallZaffinesrç   )ÚtranslationZrigidrv   Zsdr)ro   ÚniterÚpipeline)Z
transformsr  rì   rî   r  )rz   r{   rp   rq   ro   r  rî   r#  r"  rw   rx   Zto_shapeZ	to_affineZ
from_shaperÐ   r<   r<   r@   rf   ó  s.    
þ    ÿÿ    ÿrf   c              
   C   sR  ddl m} t d¡ t|dd�}t| |ƒ}	t| |||ƒ}
g }tdƒD ]<}|rVd| n|}| t	|	| || || ||
| |ƒ¡ qFt
dd	„ |D ƒƒt
d
d	„ |D ƒƒf}dd„ |D ƒ}dd„ |D ƒ}dd„ |D ƒ}||rÜdnd  t|d ƒ7  < t |¡}|d dd… t|d ƒ |d< t |¡}t |¡}|j|||f|d�}t d¡ |S )zCompute morph matrix.r   r   zComputing morph matrix...Tr*   r3   r   c                 s   s   | ]}t |ƒV  qd S rK   rL   rN   r<   r<   r@   rP     s     z(_compute_morph_matrix.<locals>.<genexpr>c                 s   s   | ]}t |ƒV  qd S rK   rL   rN   r<   r<   r@   rP     s     c                 S   s   g | ]
}|j ‘qS r<   )r‘   ©r>   Úmr<   r<   r@   rA     s     z)_compute_morph_matrix.<locals>.<listcomp>c                 S   s   g | ]}|j  ¡ ‘qS r<   )ÚindicesrE   r$  r<   r<   r@   rA     s     c                 S   s   g | ]}|j  ¡ ‘qS r<   )ÚindptrrE   r$  r<   r<   r@   rA     s     Nr€   rQ   )r�   rs   r   rX   r   Ú_get_subject_sphere_trisr   rÃ   r…   Ú_hemi_morphrk   rM   ra   r†   Ú
csr_matrix)rF   r(   rC   rG   rI   rH   r   rJ   rs   Útrisr‹   ZmorpherZhemi_toZ	hemi_fromr9   r‘   r&  r'  r<   r<   r@   rj     s<    

    þÿ 
 


rj   c                 C   s„  ddl m} t|td dfdƒ t|ƒdkr<| t|ƒdf¡S t| ƒ}d|j|jdk< |jd }||j	|dd�7 }t
|tƒrštd	|d
dd� t||ƒ ¡ }	n’|dkrâ|jt t|ƒ¡|t t|ƒd ¡f|jd t|ƒfd� ¡ }	nJt|||ƒ\}	}
}|
�r|�rt|
› d|jd › d�ƒ t d|› d�¡ |	j|t|ƒfk�sDt‚|d k	�r\|| |	 }	n|	| }	|	jt|ƒt|ƒfk�s€t‚|	S )Nr   r   úint-likeúsmoothing stepsr   r3   Úcsr©rÕ   rI   )Znearestz when used as a string.)r¬   r€   ú/zL vertices not included in smoothing, consider increasing the number of stepsz    z smooth iterations done.)r�   rs   r   rT   rM   r*  r   r‘   r9   Úeyer™   r   Ú_surf_nearestrŠ   rÌ   ra   rˆ   r‡   Ú_surf_upsampling_matÚwarn_r   rX   rh   )r+  rG   rC   rI   r‹   r   rs   Úer    rü   Ú	n_missingÚn_iterr<   r<   r@   r)  +  s>    

ÿþü
r)  c                    s¸  t |tddfdƒ ˆdkr@t|tƒr@|dkr@t d¡t d¡gS tˆdd�‰‡‡fd	d
„dD ƒ}dd
„ |D ƒ\}}|dk	�r”t|tƒr t|ƒdksštdƒ‚|}nòt	|ƒ}t
|dd�}	|t tj|d dd�¡dd…df  }|t tj|d dd�¡dd…df  }tt|ƒ\}
‰ }dd
„ |||	d fD ƒ\}}‰|
‡ ‡fdd„||fD ƒƒ}dd
„ |D ƒ}|D ]0}t |¡dk ¡ �r`td|ˆt|ƒf ƒ‚�q`n t |jd ¡t |jd ¡g}|S )aÅ  Convert a grade to source space vertices for a given subject.

    Parameters
    ----------
    subject : str
        Name of the subject.
    grade : int | list
        Resolution of the icosahedral mesh (typically 5). If None, all
        vertices will be used (potentially filling the surface). If a list,
        then values will be morphed to the set of vertices specified in
        in grade[0] and grade[1]. Note that specifying the vertices (e.g.,
        grade=[np.arange(10242), np.arange(10242)] for fsaverage on a
        standard grade 5 source space) can be substantially faster than
        computing vertex locations. Note that if subject='fsaverage'
        and 'grade=5', this set of vertices will automatically be used
        (instead of computed) for speed, since this is a common morph.
    %(subjects_dir)s
    %(n_jobs)s
    %(verbose)s

    Returns
    -------
    vertices : list of array of int
        Vertex numbers for LH and RH.
    r,  NÚgrader   r%   i(  Tr*   c              	      s    g | ]}t  ˆˆ d |d ¡‘qS ©Zsurfz.sphere.reg©rY   rZ   ©r>   Úxh©r©   rH   r<   r@   rA   o  s   ÿ
ÿz%grade_to_vertices.<locals>.<listcomp>©ZlhZrhc                 S   s   g | ]}t |ƒd  ‘qS r—   ©r   r=   r<   r<   r@   rA   q  s     r3   zBgrade as a list must have two elements (arrays of output vertices))Zreturn_surfr   )Zaxisc                 S   s   g | ]}|  tj¡‘qS r<   )ré   ra   Zfloat32)r>   Úar<   r<   r@   rA   ƒ  s   ÿÚrrc                 3   s   | ]}ˆ |ˆƒV  qd S rK   r<   )r>   Zxhs)Úmy_compute_nearestrA  r<   r@   rP   …  s   ÿz$grade_to_vertices.<locals>.<genexpr>c                 S   s   g | ]}t  |¡‘qS r<   )ra   Úsort)r>   rŽ   r<   r<   r@   rA   ˆ  s     r   zÂCannot use icosahedral grade %s with subject %s, mapping %s vertices onto the high-resolution mesh yields repeated vertices, use a lower grade or a list of vertices from an existing source space)r   rV   r™   r  ra   r‡   r   rM   rU   r   r	   Úsqrtrk   r   r   ÚdiffÚanyr9   )r©   r8  rH   Zn_jobsr   Z
spheres_toÚlhsÚrhsrŒ   ZicoÚparallelrÞ   rŽ   r<   )rB  rA  r©   rH   r@   ri   M  sF    ÿ

((ÿÿÿüÿ
 ri   é   c                 C   s¼   ddl m} ddlm} tddƒs*tdƒ‚t | ¡}| | } ||d| ddd	�\}}}t | |¡}|| }t 	t
|ƒ¡}t t
|ƒ¡}	| |	||ff¡}
|
j|jd t
| ƒfks¸t|
jƒ‚|
S )
Nr   r   )Údijkstrar�   z1.3zpscipy >= 1.3 is required to use nearest smoothing, consider upgrading SciPy or using a different smoothing valueFT)r&  Zmin_onlyZreturn_predecessors)r�   rs   Zscipy.sparse.csgraphrK  r   rU   ra   r„   Zsearchsortedr‡   rM   rˆ   r‰   r9   rh   )rŒ   Zadj_matrs   rK  r�   rÞ   ÚsourcesÚcolÚrowr‘   Zmatr<   r<   r@   r2  ˜  s     


ÿ"r2  c                 C   s@   |j | j d fkst‚|  jt ||d¡ t | j¡¡  _d S )Nr   r   )r9   rh   r‘   ra   r˜   rë   rE  r'  )r‘   Zrow_normr<   r<   r@   Ú_csr_row_norm¯  s    rO  c                 C   s´  ddl m} t||jƒst‚|jd }|j||fks8t‚|jt| ƒdd�}t|dt	dfdƒ |dk	rŒt
|dƒ}|dkr„td|› �ƒ‚|d	 }| }d
}t |¡}tdƒD ]Ö}	|	dkrÆt|ƒ|k rÆ|| }t|ƒ|k râ|dd…|f n|}
|
| }~
|�rNt|ƒ|k�r0t | d¡¡dd…df }t |¡}d}nd	||< || }t |¡d }t||ƒ |	|k�sv|dkr¦t|ƒ|kr¦ �q~q¦|j|t| ƒfk�s–t‚|t|ƒ }|	d	 }|||fS )z6Upsample data on a subject's surface given mesh edges.r   r   r.  r/  r,  Nr-  z=The number of smoothing operations has to be at least 0, got r   Tr"   r4   F)r�   rs   r™   r*  rh   r9   r1  rM   r   rT   r   rU   ra   rÉ   rÃ   Zasarrayrk   r‡   r˜   rO  )Zidx_fromr5  rI   rs   Zn_totr‘   rÔ   Zrecompute_idx_sumZmultrØ   Zuse_eZrow_sumr6  r7  r<   r<   r@   r3  ¸  sJ    

ÿ
 

r3  c                 C   sN   | j d }tj|tjd�}t|ƒD ]&}| |  ¡ }|jt |j¡ ||< q"|S )z7Return index of the maximum non-zero index in each row.r   r»   )	r9   ra   ÚemptyZint64rÃ   ZtocoorM  Zargmaxr‘   )Zcsr_matZn_rowsrÔ   rØ   rN  r<   r<   r@   rƒ   ë  s    
rƒ   c                    s&   ‡ ‡fdd„dD ƒ}dd„ |D ƒ}|S )Nc              	      s    g | ]}t  ˆˆ d |d ¡‘qS r9  r:  r;  r=  r<   r@   rA   ö  s   ÿ
ÿz,_get_subject_sphere_tris.<locals>.<listcomp>r>  c                 S   s   g | ]}t |ƒd  ‘qS rç   r?  r=   r<   r<   r@   rA   ø  s     r<   )r©   rH   Zspheresr+  r<   r=  r@   r(  õ  s
    ÿr(  c                 C   s*   dd„ t | j| j| jd ddd… ƒD ƒS )z>Compute src zooms from morph zooms, morph shape and src shape.c                 S   s   g | ]\}}}|| | ‘qS r<   r<   )r>   ZmzÚmsÚssr<   r<   r@   rA     s     z#_get_zooms_orig.<locals>.<listcomp>r¶   Nr4   )r‚   ro   r9   rt   )r}   r<   r<   r@   r  þ  s
    
ÿÿr  c                 C   sH   t  | |¡sDd}t  || ¡ ¡ r$d}tdt| ƒt|ƒ|| ||f ƒ‚d S )Nr�   z: Vertices were likely excluded during forward computation.z•vertices do not match between morph (%s) and stc (%s) for %s:
%s
%s
Perhaps src_to=fwd["src"] needs to be passed when calling compute_source_morph.%s)ra   Zarray_equalZin1dr   rU   rM   )Úv1Úv2rò   Úextr<   r<   r@   Ú_check_vertices_match  s    þÿrV  g      ð?c                 C   s´  |j dk	r*|j | jkr*td|j | jf ƒ‚td| jdƒ | jdkrRt|tddƒ n6| jdkrlt|tdd	ƒ n| jd
kszt‚t|t	ddƒ t
|tƒ }t
|tƒ }|r¨dnd}tdd„ |jd|… D ƒƒ}tdd„ | jd|… D ƒƒ}|jjd }| j}| jd
k�r"||�rdnd|�rdnd… }tdd„ |D ƒƒ}	|jjdk�rFdnd}
t |j|jjd df¡}|jd }t |	|f|jj¡}t |jd t¡}t |jd t¡}|�r¾|j|d… }| j}tt||ƒƒD ] \}\}}t||d|f ƒ �qÎt||ƒ}||  ¡ �rt‚d||< t||	ƒ}||  ¡ �r0t‚d||< | jdk�rf|t|	|  k�rftdƒ |   ¡  | jdk�ršt! "d¡ |  #|| |
¡||dd…f< n$t! "d¡ | j||  ||dd…f< |�rZtd| j$d |jdd… ƒD ]\}}}t||d|f ƒ �qàtd|ƒ}||  ¡ �rt‚d||< td|ƒ}||  ¡ �r@t‚d||< | j%||  ||< | &¡ �sht‚| &¡ �svt‚|jd f|jjdd…  |_|j'}||||j(|j)| j*ƒ}|S )z4Morph a source estimate from one subject to another.Nz+stc.subject (%s) != morph.subject_from (%s)z
morph.kindr  r)   r£   z1volume source estimate when using a surface morphr,   z1surface source estimate when using a volume morphr-   z/source estimate when using a mixed source morphr3   r   c                 s   s   | ]}t |ƒV  qd S rK   rL   rN   r<   r<   r@   rP   *  s     z$_apply_morph_data.<locals>.<genexpr>c                 s   s   | ]}t |ƒV  qd S rK   rL   rN   r<   r<   r@   rP   +  s     c                 s   s   | ]}t |ƒV  qd S rK   rL   rN   r<   r<   r@   rP   0  s     r&   u   Ori Ã— TimeZTimer4   r   z
volume[%d]TzÂComputing a sparse volume morph matrix will save time over directly morphing, calling morph.compute_vol_morph_mat(). Consider (re-)saving your instance to disk to avoid subsequent recomputation.zUsing individual volume morphz Using sparse volume morph matrix)ÚleftÚrightrC   z%s hemisphere)+r©   rF   rU   r   r`   r   r   r   rh   r   r™   rk   rŒ   rG   r‘   r9   r  ra   rÇ   rP  r¼   rÉ   r  rš   r  r‚   rV  rÁ   rF  r’   Ú_VOL_MAT_CHECK_RATIOr   rm   r   ÚdebugrŸ   rt   ry   r   Ú	__class__Ztminr  r(   )r}   r£   Zdo_volZdo_surfZvol_src_offsetZfrom_surf_stopZto_surf_stopZfrom_vol_stoprG   Zto_vol_stopr·   Z	data_fromr  r‘   Zto_usedZ	from_usedZstc_from_verticesrC   rÒ   rS  rT  Zfrom_slZto_slZhemiÚklassZstc_tor<   r<   r@   rª     s–    
ÿ
ÿ
ÿÿ 


ÿ

þ

ÿrª   )Nr   Nr    r!   r$   r%   NTFFNFF)N)N)rF   rn   )r.   r/   )T)NNTF)NNN)HrE   Úos.pathÚpathrY   r[   Únumpyra   Úfixesr   Z	morph_mapr   rI  r   Zsource_estimater   r   r   r	   Zsource_spacer
   r   r   r)   r   r   r   Úutilsr   r   r   r   r   r4  r   r   r   r   r   r   r   r   r   r   r~   rg   rÛ   rl   rV   Z_slicersrÅ   re   rð   rS   rø   rW   r«   rR   r  r  rf   rj   r)  ri   r2  rO  r3  rƒ   r(  r  rV  rY  rª   r<   r<   r<   r@   Ú<module>   s¦   H                    û s ÿ
             ü  n

&
<
3g      þ
("  ÿJ
	
2
	