function shoot = tbx_cfg_shoot
% MATLABBATCH Configuration file for toolbox 'Shoot Tools'
%__________________________________________________________________________

% John Ashburner
% Copyright (C) 2009-2022 Wellcome Centre for Human Neuroimaging


if ~isdeployed, addpath(fullfile(spm('dir'),'toolbox','Shoot')); end

% ---------------------------------------------------------------------
% images Images
% ---------------------------------------------------------------------
images1         = cfg_files;
images1.tag     = 'images';
images1.name    = 'Images';
images1.help    = {'Select a set of imported images of the same type to be registered by minimising a measure of difference from the template.'};
images1.filter = 'image';
images1.ufilter = '^r.*';
images1.num     = [1 Inf];
% ---------------------------------------------------------------------
% images Images
% ---------------------------------------------------------------------
images         = cfg_repeat;
images.tag     = 'images';
images.name    = 'Images';
images.help    = {'Select the images to be warped together. Multiple sets of images can be simultaneously registered. For example, the first set may be a bunch of grey matter images, and the second set may be the white matter images of the same subjects.'};
images.values  = {images1};
images.val     = {images1};
images.num     = [1 Inf];
% ---------------------------------------------------------------------
% warp Run Shoot (create Templates)
% ---------------------------------------------------------------------
warp         = cfg_exbranch;
warp.tag     = 'warp';
warp.name    = 'Run Shooting (create Templates)';
warp.val     = {images };
warp.help    = {'Run the geodesic shooting nonlinear image registration procedure /* \cite{ashburner2011diffeomorphic} */. This involves iteratively matching all the selected images to a template generated from their own mean /* \cite{john_averageshape} */. A series of Template*.nii files are generated, which become increasingly crisp as the registration proceeds.'};
warp.prog = @spm_shoot_template;
warp.vout = @vout_shoot_template;
% ---------------------------------------------------------------------
% images Images
% ---------------------------------------------------------------------
images1         = cfg_files;
images1.tag     = 'images';
images1.name    = 'Images';
images1.help    = {'Select a set of imported images of the same type to be registered by minimising a measure of difference from the template.'};
images1.filter = 'image';
images1.ufilter = '^r.*';
images1.num     = [1 Inf];
% ---------------------------------------------------------------------
% images Images
% ---------------------------------------------------------------------
images         = cfg_repeat;
images.tag     = 'images';
images.name    = 'Images';
images.help    = {'Select the images to be warped together. Multiple sets of images can be simultaneously registered. For example, the first set may be a bunch of grey matter images, and the second set may be the white matter images of the same subjects.'};
images.values  = {images1 };
images.num     = [1 Inf];
% ---------------------------------------------------------------------
% template Template
% ---------------------------------------------------------------------
template         = cfg_files;
template.tag     = 'templates';
template.name    = 'Templates';
template.help    = {'Select templates. Smoother templates should be used for the early iterations. Note that the template should be a 4D file, with the 4th dimension equal to the number of sets of images.'};
template.filter = 'nifti';
template.ufilter = '.*';
template.num     = [1 Inf];
% ---------------------------------------------------------------------
% warp1 Run Shooting (existing Templates)
% ---------------------------------------------------------------------
warp1         = cfg_exbranch;
warp1.tag     = 'warp1';
warp1.name    = 'Run Shoot (existing Templates)';
warp1.val     = {images template };
warp1.check   = @check_shoot_template;
warp1.help    = {'Run the Shoot nonlinear image registration procedure /* \cite{ashburner2011diffeomorphic} */ to match individual images to pre-existing template data. Start out with smooth templates, and select crisp templates for the later iterations.'};
warp1.prog = @spm_shoot_warp;
warp1.vout = @vout_shoot_warp;
% ---------------------------------------------------------------------
% velocities Velocity fields
% ---------------------------------------------------------------------
velocities         = cfg_files;
velocities.tag     = 'velocities';
velocities.name    = 'Velocity fields';
velocities.help    = {'The velocity fields store the deformation information. The same fields can be used for both forward or backward deformations (or even, in principle, half way or exaggerated deformations).'};
velocities.filter = 'nifti';
velocities.ufilter = '^v_.*';
velocities.num     = [1 Inf];
% ---------------------------------------------------------------------
% images Images
% ---------------------------------------------------------------------
images1         = cfg_files;
images1.tag     = 'images';
images1.name    = 'Images';
images1.help    = {'Select images to be warped. Note that there should be the same number of images as there are velocity fields, such that each velocity field warps one image.'};
images1.filter = 'nifti';
images1.ufilter = '.*';
images1.num     = [1 Inf];
% ---------------------------------------------------------------------
% images Images
% ---------------------------------------------------------------------
images         = cfg_repeat;
images.tag     = 'images';
images.name    = 'Images';
images.help    = {'The velocity field deformations can be applied to multiple images. At this point, you are choosing how many images each velocity field should be applied to.'};
images.values  = {images1 };
images.num     = [1 Inf];
% ---------------------------------------------------------------------
% deformations Deformation fields
% ---------------------------------------------------------------------
deformations         = cfg_files;
deformations.tag     = 'deformations';
deformations.name    = 'Deformation fields';
deformations.help    = {'Select the deformation fields for each subject.'};
deformations.filter = 'nifti';
deformations.ufilter = '^y_.*';
deformations.num     = [1 Inf];
% ---------------------------------------------------------------------
% See later
% ---------------------------------------------------------------------
many_subj = cfg_branch;
many_subj.tag = 'subjs';
many_subj.name = 'Many Subjects';
many_subj.val  = {deformations,images};
many_subj.help = {[...
'Select this option if you have many subjects to spatially normalise, ',...
'but there are a small and fixed number of scans for each subject.']};
% ---------------------------------------------------------------------
% jactransf Modulation
% ---------------------------------------------------------------------
jactransf         = cfg_menu;
jactransf.tag     = 'jactransf';
jactransf.name    = 'Modulation';
jactransf.val     = {0};
jactransf.help    = {'This allows the spatially normalised images to be rescaled by the Jacobian determinants of the deformations.'};
jactransf.labels  = {
                    'Pres. concentration (no "modulation")'
                    'Pres. amount ("modulation")'
}';
jactransf.values  = {0 1};
% ---------------------------------------------------------------------
% interp Interpolation
% ---------------------------------------------------------------------
interp         = cfg_menu;
interp.tag     = 'interp';
interp.name    = 'Interpolation';
interp.val     = {1};
interp.help    = {
                  'The method by which the images are sampled when being written in a different space.'
                  '    Nearest Neighbour:          - Fastest, but not normally recommended.'
                  '    Trilinear Interpolation:    - OK for PET, or realigned fMRI.'
                  '    B-spline Interpolation:     - Better quality (but slower) interpolation/* \cite{thevenaz00a}*/, especially with higher degree splines.  Do not use B-splines when there is any region of NaN or Inf in the images. '
}';
interp.labels  = {
                 'Nearest neighbour'
                 'Trilinear'
                 '2nd Degree B-spline'
                 '3rd Degree B-Spline '
                 '4th Degree B-Spline '
                 '5th Degree B-Spline'
                 '6th Degree B-Spline'
                 '7th Degree B-Spline'
}';
interp.values  = {0 1 2 3 4 5 6 7};
% ---------------------------------------------------------------------
% velocities Velocity fields
% ---------------------------------------------------------------------
velocities         = cfg_files;
velocities.tag     = 'velocities';
velocities.name    = 'Velocity fields';
velocities.help    = {'The velocity fields store the deformation information. The same fields can be used for both forward or backward deformations (or even, in principle, half way or exaggerated deformations).'};
velocities.filter = 'nifti';
velocities.ufilter = '^v_.*';
velocities.num     = [1 Inf];
% ---------------------------------------------------------------------
% jacdet Jacobian determinants
% ---------------------------------------------------------------------
jacdet         = cfg_exbranch;
jacdet.tag     = 'jacdet';
jacdet.name    = 'Jacobian determinants';
jacdet.val     = {velocities};
jacdet.help    = {'Create Jacobian determinant fields from velocities.'};
%jacdet.prog = @spm_shoot_jacobian;
% ---------------------------------------------------------------------
% velocities Velocity fields
% ---------------------------------------------------------------------
velocities         = cfg_files;
velocities.tag     = 'velocities';
velocities.name    = 'Velocity fields';
velocities.help    = {'The velocity fields store the deformation information. The same fields can be used for both forward or backward deformations (or even, in principle, half way or exaggerated deformations).'};
velocities.filter = 'nifti';
velocities.ufilter = '^v_.*';
velocities.num     = [1 Inf];
% ---------------------------------------------------------------------
% images Images
% ---------------------------------------------------------------------
images         = cfg_files;
images.tag     = 'images';
images.name    = 'Images';
images.help    = {'Select the image(s) to be inverse normalised.  These should be in alignment with the template image generated by the warping procedure.'};
images.filter = 'nifti';
images.ufilter = '.*';
images.num     = [1 Inf];
% ---------------------------------------------------------------------
% interp Interpolation
% ---------------------------------------------------------------------
interp         = cfg_menu;
interp.tag     = 'interp';
interp.name    = 'Interpolation';
interp.val     = {1};
interp.help    = {
                  'The method by which the images are sampled when being written in a different space.'
                  '    Nearest Neighbour:          - Fastest, but not normally recommended.'
                  '    Trilinear Interpolation:    - OK for PET, or realigned fMRI.'
                  '    B-spline Interpolation:     - Better quality (but slower) interpolation/* \cite{thevenaz00a}*/, especially with higher degree splines.  Do not use B-splines when there is any region of NaN or Inf in the images.'
}';
interp.labels = {
                 'Nearest neighbour'
                 'Trilinear'
                 '2nd Degree B-spline'
                 '3rd Degree B-Spline '
                 '4th Degree B-Spline '
                 '5th Degree B-Spline'
                 '6th Degree B-Spline'
                 '7th Degree B-Spline'
}';
interp.values  = {0 1 2 3 4 5 6 7};
% ---------------------------------------------------------------------
%
% ---------------------------------------------------------------------
velocityfield         = cfg_files;
velocityfield.tag     =  'velocityfield';
velocityfield.name    = 'Velocity Field';
velocityfield.filter  = 'nifti';
velocityfield.ufilter = '^v_.*\.nii$';
velocityfield.num     = [1 1];
velocityfield.help    = {'Shoot velocity field for this subject.'};
% ---------------------------------------------------------------------
%
% ---------------------------------------------------------------------
deformation         = cfg_files;
deformation.tag     = 'deformation';
deformation.name    = 'Deformation field';
deformation.help    = {'Select the deformation field for this subject.'};
deformation.filter  = 'nifti';
deformation.ufilter = '^y_.*\.nii$';
deformation.num     = [1 1];
% ---------------------------------------------------------------------
%
% ---------------------------------------------------------------------
images        = cfg_files;
images.tag    = 'images';
images.name   = 'Images';
images.filter = 'nifti';
images.num    = [1 Inf];
images.help   = {'Images for this subject to spatially normalise.'};
% ---------------------------------------------------------------------
%
% ---------------------------------------------------------------------
subj      = cfg_branch;
subj.tag  = 'subj';
subj.name = 'Subject';
subj.val  = {deformation,images};
subj.help = {'Subject to be spatially normalised.'};
% ---------------------------------------------------------------------
%
% ---------------------------------------------------------------------
few_subj        = cfg_repeat;
few_subj.tag    = 'few_subj';
few_subj.name   = 'Few Subjects';
few_subj.values = {subj};
few_subj.help   = {[...
'Select this option if there are only a few subjects, each with many or ',...
'a variable number of scans each. You will then need to specify a series of subjects, and the velocity field and images of each of them.']};
% ---------------------------------------------------------------------
%
% ---------------------------------------------------------------------
way        = cfg_choice;
way.tag    = 'data';
way.name   = 'Select according to';
way.values = {few_subj,many_subj};
way.help   = {...
['You may wish to spatially normalise only a few subjects, '...
 'but have many scans per subject (eg for fMRI), '...
 'or you may have lots of subjects, but with a small and fixed number '...
 'of scans for each of them (eg for VBM).  The idea is to chose the way of '...
 'selecting files that is easier.']};
% ---------------------------------------------------------------------
%
% ---------------------------------------------------------------------
template        = cfg_files;
template.tag    = 'template';
template.name   = 'Shoot Template';
template.filter = 'nifti';
template.num    = [0 1];
template.val    = {};
template.help   = {...
['Select the final Template file generated by Shoot. This will be affine '...
 'registered with a TPM file, such that the resulting spatially normalised '...
 'images are closer aligned to MNI space. Leave empty if you do not wish to '...
 'incorporate a transform to MNI space '...
 '(ie just click **done** on the file selector, without selecting any images).']};
% ---------------------------------------------------------------------
%
% ---------------------------------------------------------------------
fwhm         = cfg_entry;
fwhm.tag     = 'fwhm';
fwhm.name    = 'Gaussian FWHM';
fwhm.val     = {0};
fwhm.strtype = 'e';
fwhm.num     = [1 1];
fwhm.help    = {'Specify the full width at half maximum (FWHM) of the isotropic Gaussian blurring kernel in mm.'};
% ---------------------------------------------------------------------
%
% ---------------------------------------------------------------------
preserve         = cfg_menu;
preserve.tag     = 'preserve';
preserve.name    = 'Preserve';
preserve.help    = {
'    * **Preserve concentrations**: Smoothed spatially normalised images (sw*) represent weighted averages of the signal under the smoothing kernel, approximately preserving the intensities of the original images. This option is currently suggested for eg fMRI.'
'    * **Preserve amount**: Smoothed and spatially normalised images preserve the total amount of signal from each region in the images (smw*). Areas that are expanded during warping are correspondingly reduced in intensity. This option is suggested for VBM.'
}';
preserve.labels = {
                   'Preserve concentrations (no "modulation")'
                   'Preserve amount ("modulation")'
}';
preserve.values = {0 1};
preserve.val    = {0};
% ---------------------------------------------------------------------
%
% ---------------------------------------------------------------------
vox          = cfg_entry;
vox.tag      = 'vox';
vox.name     = 'Voxel sizes';
vox.num      = [1 3];
vox.strtype  = 'e';
vox.val      = {[NaN NaN NaN]};
vox.help     = {[...
'Specify the voxel sizes for the warped images. ',...
'Non-finite values will default to the voxel sizes of the template image ',...
'that was originally used to estimate the deformation.']};
% ---------------------------------------------------------------------
%
% ---------------------------------------------------------------------
bb           = cfg_entry;
bb.tag       = 'bb';
bb.name      = 'Bounding box';
bb.strtype   = 'e';
bb.num       = [2 3];
bb.val     = {[NaN NaN NaN
               NaN NaN NaN]};
bb.help      = {[...
'Specify the bounding box for the warped images. ',...
'Non-finite values will default to the bounding box of the template image ',...
'that was originally used to estimate the deformation.']};
% ---------------------------------------------------------------------
%
% ---------------------------------------------------------------------
nrm       = cfg_exbranch;
nrm.tag   = 'norm';
nrm.name  = 'Write Normalised';
nrm.val   = {template,way,vox,bb,preserve,fwhm};
nrm.prog  = @spm_shoot_norm;
nrm.vout  = @vout_norm;
nrm.check = @check_norm;
nrm.help  = {[...
'Normally, Shoot generates deformations that align with the average shaped template. ',...
'This routine includes the option to incorporate an affine registration of the template (the final one ',...
'generated by Shoot), with the TPM data released with SPM.'],[...
'"Smoothed" (blurred) spatially normalised images are generated in such a ',...
'way that the original signal is preserved as well as possible. ',...
'Note that trilinear interpolation is used, and no masking is done.  It ',...
'is therefore essential that any fMRI/PET time series are realigned and resliced ',...
'before they are spatially normalised.  Alternatively, contrast images ',...
'generated from unsmoothed native space fMRI/PET data can be spatially ',...
'normalised for a 2nd level analysis.'],[...
'Two "preserve" options are provided.  One of them should do the ',...
'equivalent of generating smoothed "modulated" spatially normalised ',...
'images.  The other does the equivalent of smoothing the modulated ',...
'normalised fMRI/PET, and dividing by the smoothed Jacobian determinants.']};
% ---------------------------------------------------------------------
% images Images
% ---------------------------------------------------------------------
images1         = cfg_files;
images1.tag     = 'images';
images1.name    = 'Images';
images1.help    = {'Select tissue class images (one per subject).'};
images1.filter = 'nifti';
images1.ufilter = '^r.*c';
images1.num     = [1 Inf];
% ---------------------------------------------------------------------
% images Images
% ---------------------------------------------------------------------
images         = cfg_repeat;
images.tag     = 'images';
images.name    = 'Images';
images.help    = {'Multiple sets of images are used here. For example, the first set may be a bunch of grey matter images, and the second set may be the white matter images of the same subjects.  The number of sets of images must be the same as was used to generate the template.'};
images.values  = {images1 };
images.num     = [1 Inf];
% ---------------------------------------------------------------------
% jacobians Jacobian determinant fields
% ---------------------------------------------------------------------
jacobians         = cfg_files;
jacobians.tag     = 'jacobians';
jacobians.name    = 'Jacobian determinant fields';
jacobians.help    = {'Select the Jacobian determinant fields for each subject.  Residual differences are computed between the warped images and template. These are then scaled by the Jacobian determinants at each point, and spatially smoothed.'};
jacobians.filter = 'nifti';
jacobians.ufilter = '^j_.*';
jacobians.num     = [1 Inf];
% ---------------------------------------------------------------------
% template Template
% ---------------------------------------------------------------------
template         = cfg_files;
template.tag     = 'template';
template.name    = 'Template';
template.help    = {'Residual differences are computed between the warped images and template. These are then scaled by the Jacobian determinants at each point, and spatially smoothed.'};
template.filter = 'nifti';
template.ufilter = '^Template.*';
template.num     = [0 1];
% ---------------------------------------------------------------------
% fwhm Smoothing
% ---------------------------------------------------------------------
fwhm         = cfg_menu;
fwhm.tag     = 'fwhm';
fwhm.name    = 'Smoothing';
fwhm.help    = {'The scalar momenta can be smoothed with a Gaussian to reduce dimensionality. More smoothing is recommended if there are fewer training images or if more channels of data were used for driving the registration. From preliminary experiments, a value of about 10mm seems to work reasonably well.'};
fwhm.labels  = {
               'None'
               ' 2mm'
               ' 4mm'
               ' 6mm'
               ' 8mm'
               '10mm'
               '12mm'
               '14mm'
               '16mm'
}';
fwhm.values  = {0 2 4 6 8 10 12 14 16};
fwhm.val     = {10};
% ---------------------------------------------------------------------
% scalmom Generate Scalar Momenta
% ---------------------------------------------------------------------
scalmom         = cfg_exbranch;
scalmom.tag     = 'scalmom';
scalmom.name    = 'Generate Scalar Momenta';
scalmom.val     = {template images deformations jacobians fwhm};
scalmom.check   = @check_scalmom;
scalmom.help    = {'Generate spatially smoothed *scalar momenta* /* cite{singh2010multivariate,singh2012genetic} */ in a form suitable for using with pattern recognition. In principle, a Gaussian Process model can be used to determine the optimal (positive) linear combination of kernel matrices.  The idea would be to combine a kernel matrix derived from these, with a kernel derived from the velocity fields. Such a combined kernel should then encode more relevant information than the individual kernels alone.  The scalar momentum fields that are generated contain a number of volumes equal to the number of sets of ``rc*`` images used (equal to the number of volumes in the template - 1).  /* See Figures 10 and 11 of \cite{ashburner2011multivariate} for examples of scalar momenta (Jacobian scaled residuals) for simulated data. */'};
scalmom.prog = @spm_shoot_scalmom;
scalmom.vout = @vout_scalmom;
% ---------------------------------------------------------------------
% images Data
% ---------------------------------------------------------------------
images         = cfg_files;
images.tag     = 'images';
images.name    = 'Data';
images.help    = {'Select images to generate dot products from.'};
images.filter = 'nifti';
images.ufilter = '.*';
images.num     = [1 Inf];
% ---------------------------------------------------------------------
% weight Weighting image
% ---------------------------------------------------------------------
weight         = cfg_files;
weight.tag     = 'weight';
weight.name    = 'Weighting image';
weight.val = {{}};
weight.help    = {'The kernel can be generated so that some voxels contribute to the similarity measures more than others.  This is achieved by supplying a weighting image, which each of the component images are multiplied before the dot products are computed. This image needs to have the same dimensions as the component images, but orientation information (encoded by matrices in the headers) is ignored. If left empty, then all voxels are weighted equally.'};
weight.filter = 'image';
weight.ufilter = '.*';
weight.num     = [0 1];
% ---------------------------------------------------------------------
% dotprod Dot product Filename
% ---------------------------------------------------------------------
dotprod         = cfg_entry;
dotprod.tag     = 'dotprod';
dotprod.name    = 'Dot product Filename';
dotprod.help    = {'Enter a filename for results (it will be prefixed by ``dp_`` and saved in the current directory).'};
dotprod.strtype = 's';
dotprod.num     = [1 Inf];
% ---------------------------------------------------------------------
% reskern Kernel from Resids
% ---------------------------------------------------------------------
reskern         = cfg_exbranch;
reskern.tag     = 'reskern';
reskern.name    = 'Kernel from Images';
reskern.val     = {images weight dotprod };
reskern.help    = {'Generate a kernel matrix from images. In principle, this same function could be used for generating kernels from any image data (e.g. "modulated" grey matter). If there is prior knowledge about some region providing more predictive information (e.g. the hippocampi for AD), then it is possible to weight the generation of the kernel accordingly. The matrix of dot products is saved in a variable ``K``, which can be loaded from the dp_*.mat file. The "kernel trick" can be used to convert these dot products into distance measures for e.g. radial basis function approaches.'};
reskern.prog = @spm_dotprods2;
reskern.vout = @vout_dotprod;
% ---------------------------------------------------------------------
% velocities Velocity fields
% ---------------------------------------------------------------------
velocities         = cfg_files;
velocities.tag     = 'velocities';
velocities.name    = 'Velocity fields';
velocities.help    = {'Select the velocity fields for each subject.'};
velocities.filter = 'nifti';
velocities.ufilter = '^v_.*';
velocities.num     = [1 Inf];
% ---------------------------------------------------------------------
% dotprod Dot product Filename
% ---------------------------------------------------------------------
dotprod         = cfg_entry;
dotprod.tag     = 'dotprod';
dotprod.name    = 'Dot product Filename';
dotprod.help    = {'Enter a filename for results (it will be prefixed by ``dp_`` and saved in the current directory.'};
dotprod.strtype = 's';
dotprod.num     = [1 Inf];
% ---------------------------------------------------------------------
% velkern Kernel from Velocities
% ---------------------------------------------------------------------
velkern         = cfg_exbranch;
velkern.tag     = 'velkern';
velkern.name    = 'Kernel from velocities';
velkern.val     = {velocities dotprod};
velkern.help    = {'Generate a kernel from velocity fields. The dot products are saved in a variable ``K`` in the resulting dp_*.mat file.'};
velkern.prog = @spm_shoot_kernel;
velkern.vout = @vout_kernel;
% ---------------------------------------------------------------------
% kernfun Kernel Utilities
% ---------------------------------------------------------------------
kernfun         = cfg_choice;
kernfun.tag     = 'kernfun';
kernfun.name    = 'Kernel Utilities';
kernfun.help    = {'The Shoot toolbox can be used for generating matrices of dot products for various kernel pattern recognition procedures.'
}';
kernfun.values  = {velkern scalmom reskern};
% ---------------------------------------------------------------------
% shoot Shoot Tools
% ---------------------------------------------------------------------
shoot         = cfg_choice;
shoot.tag     = 'shoot';
shoot.name    = 'Shoot Tools';
shoot.help    = {'This toolbox is based around the "Diffeomorphic Registration using Geodesic Shooting and Gauss-Newton Optimisation" paper /* \cite{ashburner2011diffeomorphic} */. The idea is to register images by estimating an initial velocity field, which can then be integrated to generate both forward and backward deformations.'
}';
shoot.values  = {warp warp1 nrm kernfun};

%_______________________________________________________________________
%
%_______________________________________________________________________
function chk = check_shoot_template(job)
n1 = numel(job.images);
n2 = numel(job.images{1});
chk = '';
for i=1:n1
    if numel(job.images{i}) ~= n2
        chk = 'Incompatible number of images';
        break;
    end
end
%_______________________________________________________________________

%_______________________________________________________________________
function dep = vout_shoot_template(job)

d = spm_shoot_defaults;
if isfield(d, 'tname') && ~isempty(deblank(d.tname))
    for it=0:ceil((numel(d.sched)-1)/6)
        tdep(it+1)            = cfg_dep;
        tdep(it+1).sname      = sprintf('Template (%d)', it);
        tdep(it+1).src_output = substruct('.','template','()',{it+1});
        tdep(it+1).tgt_spec   = cfg_findspec({{'filter','nifti'}});
    end
else
    tdep = cfg_dep;
    tdep = tdep(false);
end
vdep            = cfg_dep;
vdep.sname      = 'Velocity Fields';
vdep.src_output = substruct('.','vel','()',{':'});
vdep.tgt_spec   = cfg_findspec({{'filter','nifti'}});

ydep            = cfg_dep;
ydep.sname      = 'Deformation Fields';
ydep.src_output = substruct('.','def','()',{':'});
ydep.tgt_spec   = cfg_findspec({{'filter','nifti'}});

jdep            = cfg_dep;
jdep.sname      = 'Jacobian Fields';
jdep.src_output = substruct('.','jac','()',{':'});
jdep.tgt_spec   = cfg_findspec({{'filter','nifti'}});

dep = [tdep vdep ydep jdep];
%_______________________________________________________________________

%_______________________________________________________________________
function dep = vout_shoot_warp(job)
dep            = cfg_dep;
dep.sname      = 'Velocity Fields';
dep.src_output = substruct('.','files','()',{':'});
dep.tgt_spec   = cfg_findspec({{'filter','nifti'}});
%_______________________________________________________________________

%_______________________________________________________________________
function chk = check_norm(job)
chk = '';
if isfield(job.data,'subjs')
    PU = job.data.subjs.deformations;
    PI = job.data.subjs.images;
    n1 = numel(PU);
    for i=1:numel(PI)
        if numel(PI{i}) ~= n1
            chk = 'Incompatible number of images';
            break;
        end
    end
end
%_______________________________________________________________________

%_______________________________________________________________________
function dep = vout_norm(job)
if any(job.fwhm~=0), smo = 'Smo. '; else
                     smo = ''; end
if job.preserve,     mod = 'Amount'; else
                     mod = 'Concn.'; end
sname = [smo 'Warped-' mod];

dep = cfg_dep;

if isfield(job.data,'subj')
    for m=1:numel(job.data.subj)
        dep(m)            = cfg_dep;
        dep(m).sname      = sprintf('%s (Subject %d)',sname,m);
        dep(m).src_output = substruct('{}',{m},'()',{':'});
        dep(m).tgt_spec   = cfg_findspec({{'filter','nifti'}});
    end
end

if isfield(job.data,'subjs')
    for m=1:numel(job.data.subjs.images)
        dep(m)            = cfg_dep;
        dep(m).sname      = sprintf('%s (Image %d)',sname,m);
        dep(m).src_output = substruct('()',{':',m});
        dep(m).tgt_spec   = cfg_findspec({{'filter','nifti'}});
    end
end
%_______________________________________________________________________

%_______________________________________________________________________
function chk = check_scalmom(job)
chk = '';
PY = job.deformations;
PI = job.images;
n1 = numel(PY);
for i=1:numel(PI)
    if numel(PI{i}) ~= n1
        chk = 'Incompatible number of images';
        break;
    end
end
%_______________________________________________________________________

%_______________________________________________________________________
function dep = vout_scalmom(job)
dep            = cfg_dep;
dep.sname      = 'Scalar Momentum Fields';
dep.src_output = substruct('.','scalmom','()',{':'});
dep.tgt_spec   = cfg_findspec({{'filter','nifti'}});
%_______________________________________________________________________

%_______________________________________________________________________
function dep = vout_kernel(job)
dep            = cfg_dep;
dep.sname      = 'Velocity Kernel';
dep.src_output = substruct('.','fname','()',{':'});
dep.tgt_spec   = cfg_findspec({{'filter','mat'}});
%_______________________________________________________________________

%_______________________________________________________________________
function dep = vout_dotprod(job)
dep            = cfg_dep;
dep.sname      = 'Image Kernel';
dep.src_output = substruct('.','fname','()',{':'});
dep.tgt_spec   = cfg_findspec({{'filter','mat'}});
%_______________________________________________________________________
