3
dS                 @   s  d Z ddlZddlmZ ddlm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mZmZmZmZmZ dd
lmZ ddlmZ ddlmZmZmZ dZe	j dZ!dd Z"dd Z#dd Z$d"ddZ%G dd deZ&dd Z'G dd deZ(G dd deZ)G d d! d!eZ*dS )#a  The spm module provides basic functions for interfacing with SPM  tools.

In order to use the standalone MCR version of spm, you need to ensure that
the following commands are executed at the beginning of your script::

   from nipype.interfaces import spm
   matlab_cmd = '/path/to/run_spm8.sh /path/to/Compiler_Runtime/v713/ script'
   spm.SPMCommand.set_mlab_paths(matlab_cmd=matlab_cmd, use_mcr=True)

you can test by calling::

   spm.SPMCommand().version
    N)deepcopy)load   )logging)spm_docs   )	BaseInterfacetraits	isdefinedInputMultiPathBaseInterfaceInputSpec	Directory	Undefined	ImageFilePackageInfo)NoDefaultSpecified)MatlabCommand)dueDoiBibTeXZrestructuredtextznipype.interfacec             C   sT   t | trt| d S t| }|j}t|dksHt|dkrL|d dkrLdS dS dS )z(Checks if input functional files are 3d.r   r         TFN)
isinstancelist
func_is_3dr   shapelen)in_fileimgr    r   </tmp/pip-build-7vycvbft/nipype/nipype/interfaces/spm/base.pyr   /   s    
$r   c             C   s&   t | sd S t| d tr"| d S | S )Nr   )r   r   r   )Zin_filesr   r   r    get_first_3dfile=   s
    r!   c             C   s   t | trDtjt| ftd}x t| D ]\}}d| ||< q(W |S t| }t|jdkrntj	d|  ftdS |jd }tj|ftd}x$t
|D ]}d| |d f ||< qW |S dS )zReads a nifti file and converts it to a numpy array storing
    individual nifti volumes.

    Opens images so will fail if they are not found.

    )dtypez%s,1r   z%s,%dr   N)r   r   npzerosr   object	enumerater   r   arrayrange)fnamescansZsnofr   Zn_scansr   r   r    scans_for_fnameE   s    

r,   Fc             C   s   d}t | d ts$t| d r$| g} |s,|r@tjt| ftd}xt| D ]\}}|r|rt |trxtj|td||< qtj|gtd||< qt	|||< qJ|r|||< qJt	|}|dkr|}qJtj
||f}qJW |S )a|  Converts a list of files to a concatenated numpy array for each
    volume.

    keep4d : boolean
        keeps the entries of the numpy array as 4d files instead of
        extracting the individual volumes.
    separate_sessions: boolean
        if 4d nifti files are being used, then separate_sessions
        ensures a cell array per session is created in the structure.

    Nr   )r"   )r   r   r   r#   r$   r   r%   r&   r'   r,   Zconcatenate)fnamesZkeep4dZseparate_sessionsflistir+   r*   r   r   r    scans_for_fnames\   s(    

r0   c               @   s\   e Zd ZdZdZdZdZdZdZe	dddZ
e	dddZe	dddZe	dd	d
ZdS )InfoaI  Handles SPM version information

    If you use `SPMCommand.set_mlab_paths` to set alternate entries for
    matlab_cmd, paths, and use_mcr, then you will need to use the same entries
    to any call in the Info class to maintain memoization. Otherwise, it will
    default to the parameters in the `getinfo` function below.
    Nc             C   s   | j ||| | jS )N)getinfo_path)klass
matlab_cmdpathsuse_mcrr   r   r    path   s    z	Info.pathc             C   s   | j ||| | jS )N)r2   _version)r4   r5   r6   r7   r   r   r    version   s    zInfo.versionc             C   s   | j ||| | jS )N)r2   _name)r4   r5   r6   r7   r   r   r    name   s    z	Info.namec             C   s  |pdt jk}|p*|r t jdp*t jdd}| jrd| jrd| jrd| j|krd| j|krd| j| j| jdS tj	d t
|dd}d|j_|r||j_|rt|j_t|j_t|j_d	|j_d	|j_d
|j_y|j }W nP ttfk
r } z.tj	d| d| _d| _d| _|| _|| _dS d}~X nX tj|jj}i }x*|jdD ]}|jd\}	}
|
||	< q>W |d | _|d | _|d | _|| _|| _|S )a4  
        Returns the path to the SPM directory in the Matlab path
        If path not found, returns None.

        Parameters
        ----------
        matlab_cmd: str
            Sets the default matlab command. If None, the value of the
            environment variable SPMMCRCMD will be used if set and use_mcr
            is True or the environment variable FORCE_SPMMCR is set.
            If one of FORCE_SPMMCR or SPMMCRCMD is not set, the existence
            of the environment variable MATLABCMD is checked and its value
            is used as the matlab command if possible.
            If none of the above was successful, the fallback value of
            'matlab -nodesktop -nosplash' will be used.
        paths : str
            Add paths to matlab session
        use_mcr : bool
            Whether to use the MATLAB Common Runtime. In this case, the
            matlab_cmd is expected to be a valid MCR call.

        Returns
        -------
        spm_path : string representing path to SPM directory

            returns None of path not found
        FORCE_SPMMCR	SPMMCRCMDZ	MATLABCMDzmatlab -nodesktop -nosplash)r<   r8   releasez8matlab command or path has changed. recomputing version.F)r5   resource_monitorTz
if isempty(which('spm')),
throw(MException('SPMCheck:NotFound','SPM not in matlab path'));
end;
spm_path = spm('dir');
[name, version] = spm('ver');
fprintf(1, 'NIPYPE path:%s|name:%s|release:%s', spm_path, name, version);
exit;
        z%sN|:r?   r8   r<   )osenvirongetenvr;   r3   r9   _command_pathsloggerdebugr   inputsmfiler6   r   	nodesktopnosplashsingle_comp_threaduses_mcrscriptrunIOErrorRuntimeErrorsdZ_strip_headerruntimestdoutsplit)r4   r5   r6   r7   mlabouteZout_dictpartkeyvalr   r   r    r2      sV    


	


zInfo.getinfo)NNN)NNN)NNN)NNN)__name__
__module____qualname____doc__r3   r;   rF   rG   r9   classmethodr8   r:   r<   r2   r   r   r   r    r1      s   r1   c               C   s"   dt jkstj dkrdS dS dS )zChecks if SPM is NOT installed
    used with pytest.mark.skipif decorator to skip tests
    that will fail if spm is not installedZNIPYPE_NO_MATLABNTF)rC   rD   r1   r:   r   r   r   r    no_spm   s    rc   c               @   sT   e Zd ZejddZee ddZej	ddddZ
ej	ddZej	dddd	d
ZdS )SPMCommandInputSpeczmatlab command to use)desczPaths to add to matlabpathTzRun m-code using m-file)re   
usedefaultzRun m-code using SPM MCR8z(Generate SPM8 and higher compatible jobs)Zmin_verrf   re   N)r^   r_   r`   r	   Strr5   r   r   r6   BoolrK   r7   use_v8structr   r   r   r    rd     s   rd   c                   s   e Zd ZdZeZdgZdZdZdZ	dZ
dZedddgd	gZ fd
dZed)ddZdd Zdd Zedd Zedd Zedd Zdd Zdd Zdd Zdd Zf fd d!Zd"d# Zd*d%d&Zd+d'd(Z  ZS ),
SPMCommandzExtends `BaseInterface` class to implement SPM specific interfaces.

    WARNING: Pseudo prototype class, meant to be subclassed
    fieldZbasetypebasenameNz@book{FrackowiakFristonFrithDolanMazziotta1997,author={R.S.J. Frackowiak, K.J. Friston, C.D. Frith, R.J. Dolan, and J.C. Mazziotta},title={Human Brain Function},publisher={Academic Press USA},year={1997},}z<The fundamental text on Statistical Parametric Mapping (SPM)implementation)entrydescriptiontagsc                sF   t t| jf | | jj| jddddg | j  | j  | j  d S )Nr5   rK   r6   r7   )superrk   __init__rJ   Zon_trait_change_matlab_cmd_update_find_mlab_cmd_defaults_check_mlab_inputs)selfrJ   )	__class__r   r    rs   5  s    zSPMCommand.__init__c             C   s&   || _ || _|| _tj|||d}d S )N)r5   r6   r7   )_matlab_cmdrG   _use_mcrr1   r2   )clsr5   r6   r7   	info_dictr   r   r    set_mlab_paths>  s    zSPMCommand.set_mlab_pathsc             C   sJ   | j sdtjkrFd| _ | jd krFytjd | _W n tk
rD   Y nX d S )Nr=   Tr>   )rz   rC   rD   ry   KeyError)rw   r   r   r    ru   E  s    
z"SPMCommand._find_mlab_cmd_defaultsc             C   s   t | jj| jj| jjdd| _d| jjjdd j	  | jj_
t| jjr| jjrt| jj_t| jj_t| jj_d| jj_d| jj_d S )NF)r5   rK   r6   r@   zpyscript_%s.m.r   T)r   rJ   r5   rK   r6   rX   rx   r^   rW   lowerZscript_filer
   r7   r   rL   rM   rN   rO   )rw   r   r   r    rt   P  s    
 



zSPMCommand._matlab_cmd_updatec             C   sB   t j| jj| jj| jjd}|r>d|d jdd |d f S d S )N)r5   r6   r7   z%s.%sr<   ZSPMr   r?   r   )r1   r2   rJ   r5   r6   r7   rW   )rw   r|   r   r   r    r:   d  s    zSPMCommand.versionc             C   s   | j S )N)_jobtype)rw   r   r   r    jobtypen  s    zSPMCommand.jobtypec             C   s   | j S )N)_jobname)rw   r   r   r    jobnamer  s    zSPMCommand.jobnamec             C   s^   t | jj r| jr| j| j_t | jj r<| jr<| j| j_t | jj rZ| jrZ| j| j_d S )N)r
   rJ   r5   ry   r6   rG   r7   rz   )rw   r   r   r    rv   v  s    

zSPMCommand._check_mlab_inputsc             C   sn   | j t| j | jj_| jj }|jj|_| jjj	rLd|jj
krL| j| |jj
|_
|jj|_|jj|_|S )z'Executes the SPM function using MATLAB.ZSkipped)_make_matlab_commandr   _parse_inputsrX   rJ   rP   rQ   rU   
returncoderO   rV   Zraise_exceptionstderrZmerged)rw   rU   resultsr   r   r    _run_interface~  s    






zSPMCommand._run_interfacec             C   s   t dS )z/Determine the expected outputs based on inputs.N)NotImplementedError)rw   r   r   r    _list_outputs  s    zSPMCommand._list_outputsc             C   s0   |j tjrt|S |j tjr(t|S |S dS )z,Convert input to appropriate format for SPM.N)Zis_trait_typer	   ri   intTupler   )rw   optspecr]   r   r   r    _format_arg  s
    zSPMCommand._format_argc             C   s   i }t dd d}xt| jjf |j D ]\}}|r@||kr@q*t| j|}t|sVq*|j}d|kr|jd}|}	x4|d d D ]$}
|
t|	j	 kri |	|
< |	|
 }	qW | j
||||	|d < q*| j
|||||< q*W |gS )Nc             S   s   | d k	S )Nr   )tr   r   r    <lambda>  s    z*SPMCommand._parse_inputs.<locals>.<lambda>)rl   r   r   r   r   )dictr   rJ   r	   itemsgetattrr
   rl   rW   keysr   )rw   skipZspmdictmetadatar<   r   valuerl   fieldsZdictrefr+   r   r   r    r     s&     
zSPMCommand._parse_inputsc             C   sl   i }yFx>t |j D ].\}}t|tr:|rB| j|||< q|||< qW |gS  tk
rf   td Y nX dS )a  Encloses a dict representation within hierarchical lists.

        In order to create an appropriate SPM job structure, a Python
        dict storing the job needs to be modified so that each dict
        embedded in dict needs to be enclosed as a list element.

        Examples
        --------
        >>> a = SPMCommand()._reformat_dict_for_savemat(dict(a=1,
        ...                                                  b=dict(c=2, d=3)))
        >>> a == [{'a': 1, 'b': [{'c': 2, 'd': 3}]}]
        True

        zRequires dict inputN)r   r   r   r   _reformat_dict_for_savemat	TypeErrorprint)rw   contentsZnewdictr\   r   r   r   r    r     s    
z%SPMCommand._reformat_dict_for_savemat c             C   sr  d}|dkr|S t |trxxXt|D ]L\}}|jdrPd|dd |d f }nd||d f }|| j||7 }q$W |S t |trx4t|j D ]$\}}d||f }|| j||7 }qW |S t |tjr6|j	tj	t
kr|r|d| 7 }n|d	7 }xt|D ]\}}t |tjr*|| jd|d
7 }nt |trg }	x,|D ]$}
|	t |
ttfsZdndg7 }	q@W dj|	j}|dj|| 7 }n0t |ttfr|dj|7 }n|dt| 7 }q W |d7 }njxht|D ]\\}}xP|j	jD ]D}|rd||d |f }nd|d |f }|| j||| 7 }qW qW |S t |ttfrZ|d||f 7 }|S |d|t|f 7 }|S )af  Recursive function to generate spm job specification as a string

        Parameters
        ----------
        prefix : string
            A string that needs to get
        contents : dict
            A non-tuple Python structure containing spm job
            information gets converted to an appropriate sequence of
            matlab commands.

        r   N)z%s,%d)r   z%s(%d)z%s.%sz
%s = {...
z{...
)prefixr   z{}z'{}'z, z	[{}];...
z	'{}';...
z%s;...
z};
z	%s(%d).%sz(%d).%sz%s = '%s';
z	%s = %s;
r   )r   r   r&   endswith_generate_jobr   r   r#   Zndarrayr"   r%   strbytesjoinformatr   )rw   r   r   Z	jobstringr/   r   Z	newprefixr\   r]   Zitems_formatelZ
val_formatrl   r   r   r    r     s\    



"
 zSPMCommand._generate_jobc          	   C   s   t j }d}| jjjrt| jjrL| jjrL|| jd| j| j	f |d 7 }nL| j	dkrx|| jd| j| j	f |d 7 }n || jd| j| j	f |d 7 }nVddl
m} d| j| j	| j|d igigi}|t jj|d| j	 | |d| j	 7 }|d7 }| jjr
|d7 }|dk	r||7 }|S )ag  Generates a mfile to build job structure
        Parameters
        ----------

        contents : list
            a list of dicts generated by _parse_inputs
            in each subclass

        cwd : string
            default os.getcwd()

        Returns
        -------
        mscript : string
            contents of a script called by matlab

        a  
        %% Generated by nipype.interfaces.spm
        if isempty(which('spm')),
             throw(MException('SPMCheck:NotFound', 'SPM not in matlab path'));
        end
        [name, version] = spm('ver');
        fprintf('SPM version: %s Release: %s\n',name, version);
        fprintf('SPM path: %s\n', which('spm'));
        spm('Defaults','fMRI');

        if strcmp(name, 'SPM8') || strcmp(name(1:5), 'SPM12'),
           spm_jobman('initcfg');
           spm_get_defaults('cmdline', 1);
        end

        zjobs{1}.spm.%s.%sr   stsmoothpreprocpreproc8	fmri_specfmri_estfactorial_designdefszjobs{1}.%s{1}.%s(1)zjobs{1}.%s{1}.%s{1})savematjobszpyjobs_%s.matzload pyjobs_%s;

z+
        spm_jobman('run', jobs);

        z|
        if strcmp(name, 'SPM8') || strcmp(name(1:5), 'SPM12'),
            close('all', 'force');
        end;
            N)r   r   r   r   r   r   r   r   )rC   getcwdrX   rJ   rK   r
   rj   r   r   r   Zscipy.ior   Zreformat_dict_for_savematr8   r   r7   )rw   r   Z
postscriptcwdZmscriptr   Zjobdefr   r   r    r     sF    
       

zSPMCommand._make_matlab_command)NNN)r   N)N) r^   r_   r`   ra   rd   Z
input_specZ_additional_metadatar   r   ry   rG   rz   r   Z_referencesrs   rb   r}   ru   rt   propertyr:   r   r   rv   r   r   r   r   r   r   r   __classcell__r   r   )rx   r    rk     s8   	
	
Brk   c                   s(   e Zd ZdZeddf fdd	Z  ZS )ImageFileSPMz1Defines a trait whose value must be a NIfTI file.Fc                s*   t t| jf ||ddgd|d| dS )zCreate an ImageFileSPM trait.Znifti1Znifti2F)r   existstypesZallow_compressedresolveN)rr   r   rs   )rw   r   r   r   r   )rx   r   r    rs   l  s    zImageFileSPM.__init__)r^   r_   r`   ra   r   rs   r   r   r   )rx   r    r   i  s   r   )FF)+ra   rC   copyr   Znibabelr   numpyr#   r   r   utilsr   rT   baser   r	   r
   r   r   r   r   r   r   Zbase.traits_extensionr   Zmatlabr   Zexternal.duer   r   r   Z__docformat__	getLoggerrH   r   r!   r,   r0   r1   rc   rd   rk   r   r   r   r   r    <module>   s.   ,

'z  V