function realignunwarp = spm_cfg_realignunwarp
% SPM Configuration file for Realign & Unwarp
%__________________________________________________________________________
% Copyright (C) 2005-2016 Wellcome Trust Centre for Neuroimaging

% $Id: spm_cfg_realignunwarp.m 6952 2016-11-25 16:03:13Z guillaume $

%--------------------------------------------------------------------------
% scans Images
%--------------------------------------------------------------------------
scans         = cfg_files;
scans.tag     = 'scans';
scans.name    = 'Images';
scans.help    = {
    'Select scans for this session.'
    'In the coregistration step, the sessions are first realigned to each other, by aligning the first scan from each session to the first scan of the first session.  Then the images within each session are aligned to the first image of the session. The parameter estimation is performed this way because it is assumed (rightly or not) that there may be systematic differences in the images between sessions.'
    }';
scans.filter  = 'image';
scans.ufilter = '.*';
scans.num     = [1 Inf];
scans.preview = @(f) spm_check_registration(char(f));

%--------------------------------------------------------------------------
% pmscan Phase map (vdm* file)
%--------------------------------------------------------------------------
pmscan         = cfg_files;
pmscan.tag     = 'pmscan';
pmscan.name    = 'Phase map (vdm* file)';
pmscan.help    = {
    'Select pre-calculated phase map, or leave empty for no phase correction.'
    'The vdm* file is assumed to be already in alignment with the first scan of the first session.'
    }';
pmscan.filter  = 'image';
pmscan.ufilter = '^vdm5_.*';
pmscan.num     = [0 1];
pmscan.val     = {''};
pmscan.preview = @(f) spm_image('Display',char(f));

%--------------------------------------------------------------------------
% data Session
%--------------------------------------------------------------------------
data         = cfg_branch;
data.tag     = 'data';
data.name    = 'Session';
data.val     = {scans pmscan};
data.help    = {
    'Only add similar session data to a realign+unwarp branch, i.e., choose Data or Data+phase map for all sessions, but don''t use them interchangeably.'
    ''
    'In the coregistration step, the sessions are first realigned to each other, by aligning the first scan from each session to the first scan of the first session.  Then the images within each session are aligned to the first image of the session. The parameter estimation is performed this way because it is assumed (rightly or not) that there may be systematic differences in the images between sessions.'
    }';

%--------------------------------------------------------------------------
% generic Data
%--------------------------------------------------------------------------
generic         = cfg_repeat;
generic.tag     = 'generic';
generic.name    = 'Data';
generic.help    = {'Data sessions to unwarp.'};
generic.values  = {data};
generic.num     = [1 Inf];

%--------------------------------------------------------------------------
% quality Quality
%--------------------------------------------------------------------------
quality         = cfg_entry;
quality.tag     = 'quality';
quality.name    = 'Quality';
quality.help    = {
    'Quality versus speed trade-off.'
    'Highest quality (1) gives most precise results, whereas lower qualities gives faster realignment. The idea is that some voxels contribute little to the estimation of the realignment parameters. This parameter is involved in selecting the number of voxels that are used.'
    }';
quality.strtype = 'r';
quality.num     = [1 1];
quality.extras  = [0 1];
quality.def     = @(val)spm_get_defaults('realign.estimate.quality', val{:});

%--------------------------------------------------------------------------
% sep Separation
%--------------------------------------------------------------------------
sep         = cfg_entry;
sep.tag     = 'sep';
sep.name    = 'Separation';
sep.help    = {
    'The separation (in mm) between the points sampled in the reference image.'
    'Smaller sampling distances gives more accurate results, but will be slower.'};
sep.strtype = 'r';
sep.num     = [1 1];
sep.def     = @(val)spm_get_defaults('realign.estimate.sep', val{:});

%--------------------------------------------------------------------------
% fwhm Smoothing (FWHM)
%--------------------------------------------------------------------------
fwhm         = cfg_entry;
fwhm.tag     = 'fwhm';
fwhm.name    = 'Smoothing (FWHM)';
fwhm.help    = {
    'The FWHM of the Gaussian smoothing kernel (mm) applied to the images before estimating the realignment parameters.'
    ''
    '    * PET images typically use a 7 mm kernel.'
    ''
    '    * MRI images typically use a 5 mm kernel.'
    }';
fwhm.strtype = 'r';
fwhm.num     = [1 1];
fwhm.def     = @(val)spm_get_defaults('realign.estimate.fwhm', val{:});

%--------------------------------------------------------------------------
% rtm Num Passes
%--------------------------------------------------------------------------
rtm         = cfg_menu;
rtm.tag     = 'rtm';
rtm.name    = 'Num Passes';
rtm.help    = {
    'Register to first: Images are registered to the first image in the series. Register to mean: A two pass procedure is used in order to register the images to the mean of the images after the first realignment.'
    ''
    '    * PET images are typically registered to the mean.'
    ''
    '    * MRI images are typically registered to the first image.'
    }';
rtm.labels  = {
               'Register to first'
               'Register to mean'
}';
rtm.values  = {0 1};
rtm.def     = @(val)spm_get_defaults('unwarp.estimate.rtm', val{:});

%--------------------------------------------------------------------------
% einterp Interpolation
%--------------------------------------------------------------------------
einterp         = cfg_menu;
einterp.tag     = 'einterp';
einterp.name    = 'Interpolation';
einterp.help    = {
    'The method by which the images are sampled when estimating the optimum transformation.'
    'Higher degree interpolation methods provide the better interpolation, but they are slower because they use more neighbouring voxels /* \cite{thevenaz00a,unser93a,unser93b}*/.'
    }';
einterp.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'
}';
einterp.values  = {0 1 2 3 4 5 6 7};
einterp.def     = @(val)spm_get_defaults('realign.estimate.interp', val{:});

%--------------------------------------------------------------------------
% ewrap Wrapping
%--------------------------------------------------------------------------
ewrap         = cfg_menu;
ewrap.tag     = 'ewrap';
ewrap.name    = 'Wrapping';
ewrap.help    = {
    'This indicates which directions in the volumes the values should wrap around in.'
    'These are typically:'
    '* No wrapping - for images that have already been spatially transformed.'
    '* Wrap in Y   - for (un-resliced) MRI where phase encoding is in the Y direction (voxel space).'
    }';
ewrap.labels = {
                'No wrap'
                'Wrap X'
                'Wrap Y'
                'Wrap X & Y'
                'Wrap Z '
                'Wrap X & Z'
                'Wrap Y & Z'
                'Wrap X, Y & Z'
}';
ewrap.values = {[0 0 0] [1 0 0] [0 1 0] [1 1 0] [0 0 1] [1 0 1] [0 1 1]...
                [1 1 1]};
ewrap.def    = @(val)spm_get_defaults('realign.estimate.wrap', val{:});

%--------------------------------------------------------------------------
% weight Weighting
%--------------------------------------------------------------------------
weight         = cfg_files;
weight.tag     = 'weight';
weight.name    = 'Weighting';
weight.val     = {''};
weight.help    = {
    'Optional weighting image to weight each voxel of the reference image differently when estimating the realignment parameters.'
    'The weights are proportional to the inverses of the standard deviations. For example, when there is a lot of extra-brain motion - e.g., during speech, or when there are serious artifacts in a particular region of the images.'
    }';
weight.filter  = 'image';
weight.ufilter = '.*';
weight.num     = [0 1];
weight.preview = @(f) spm_image('Display',char(f));

%--------------------------------------------------------------------------
% eoptions Estimation Options
%--------------------------------------------------------------------------
eoptions         = cfg_branch;
eoptions.tag     = 'eoptions';
eoptions.name    = 'Estimation Options';
eoptions.val     = {quality sep fwhm rtm einterp ewrap weight };
eoptions.help    = {'Various registration options that could be modified to improve the results. Whenever possible, the authors of SPM try to choose reasonable settings, but sometimes they can be improved.'};

%--------------------------------------------------------------------------
% basfcn Basis Functions
%--------------------------------------------------------------------------
basfcn         = cfg_menu;
basfcn.tag     = 'basfcn';
basfcn.name    = 'Basis Functions';
basfcn.help    = {
    'Number of basis functions to use for each dimension.'
    'If the third dimension is left out, the order for that dimension is calculated to yield a roughly equal spatial cut-off in all directions. Default: [12 12 *]'
    }';
basfcn.labels  = {
                  '8x8x*'
                  '10x10x*'
                  '12x12x*'
                  '14x14x*'
}';
basfcn.values  = {[8 8] [10 10] [12 12] [14 14]};
basfcn.def     = @(val)spm_get_defaults('unwarp.estimate.basfcn', val{:});

%--------------------------------------------------------------------------
% regorder Regularisation
%--------------------------------------------------------------------------
regorder         = cfg_menu;
regorder.tag     = 'regorder';
regorder.name    = 'Regularisation';
regorder.help    = {
    'Unwarp looks for the solution that maximises the likelihood (minimises the variance) while simultaneously maximising the smoothness of the estimated field (c.f. Lagrange multipliers). This parameter determines how to balance the compromise between these (i.e. the value of the multiplier). Test it on your own data (if you can be bothered) or go with the defaults. '
    ''
    'Regularisation of derivative fields is based on the regorder''th (spatial) derivative of the field. The choices are 0, 1, 2, or 3.  Default: 1'
    }';
regorder.labels = {
                   '0'
                   '1'
                   '2'
                   '3'
}';
regorder.values = {0 1 2 3};
regorder.def    = @(val)spm_get_defaults('unwarp.estimate.regorder', val{:});

%--------------------------------------------------------------------------
% lambda Reg. Factor
%--------------------------------------------------------------------------
lambda         = cfg_menu;
lambda.tag     = 'lambda';
lambda.name    = 'Reg. Factor';
lambda.help    = {'Regularisation factor. Default: Medium.'};
lambda.labels  = {
                 'A little'
                 'Medium'
                 'A lot'
}';
lambda.values  = {10000 100000 1000000};
lambda.def     = @(val)spm_get_defaults('unwarp.estimate.regwgt', val{:});

%--------------------------------------------------------------------------
% jm Jacobian deformations
%--------------------------------------------------------------------------
jm         = cfg_menu;
jm.tag     = 'jm';
jm.name    = 'Jacobian deformations';
jm.help    = {
    'Option to include Jacobian intensity modulation when estimating the fields.'
    '"Jacobian intensity modulation" refers to the dilution/concentration of intensity that ensue as a consequence of the distortions. Think of a semi-transparent coloured rubber sheet that you hold against a white background. If you stretch a part of the sheet (induce distortions) you will see the colour fading in that particular area. In theory it is a brilliant idea to include also these effects when estimating the field (see e.g. Andersson et al, NeuroImage 20:870-888). In practice for this specific problem it is NOT a good idea. Default: No'
    }';
jm.labels  = {
              'Yes'
              'No'
}';
jm.values  = {1 0};
jm.def     = @(val)spm_get_defaults('unwarp.estimate.jm', val{:});

%--------------------------------------------------------------------------
% fot First-order effects
%--------------------------------------------------------------------------
fot         = cfg_entry;
fot.tag     = 'fot';
fot.name    = 'First-order effects';
fot.help    = {
    'Vector of first order effects to model.'
    ''
    'Theoretically (ignoring effects of shimming) one would expect the field to depend only on subject out-of-plane rotations. Hence the default choice ("Pitch and Roll", i.e., [4 5]). Go with that unless you have very good reasons to do otherwise'
    ''
    'Movements to be modelled are referred to by number. 1= x translation; 2= y translation; 3= z translation 4 = x rotation,  5 = y rotation and 6 = z rotation.'
    ''
    'To model pitch & roll enter: [4 5]'
    ''
    'To model all movements enter: [1:6]'
    ''
    'Otherwise enter a customised set of movements to model'
    }';
fot.strtype = 'n';
fot.num     = [1 Inf];
fot.def     = @(val)spm_get_defaults('unwarp.estimate.foe', val{:});

%--------------------------------------------------------------------------
% sot Second-order effects
%--------------------------------------------------------------------------
sot         = cfg_entry;
sot.tag     = 'sot';
sot.name    = 'Second-order effects';
sot.help    = {
    'List of second order terms to model second derivatives of.'
    'This is entered as  a vector of movement parameters similar to first order effects, or leave blank for NONE.'
    ''
    'Movements to be modelled are referred to by number:'
    ''
    '1= x translation; 2= y translation; 3= z translation 4 = x rotation,  5 = y rotation and 6 = z rotation.'
    ''
    'To model the interaction of pitch & roll enter: [4 5]'
    ''
    'To model all movements enter: [1:6]'
    ''
    'The vector will be expanded into an n x 2 matrix of effects. For example [4 5] will be expanded to:'
    ''
    '[ 4 4'
    ''
    '  4 5'
    ''
    '  5 5 ]'
    }';
sot.strtype = 'n';
sot.num     = [Inf Inf];
sot.def     = @(val)spm_get_defaults('unwarp.estimate.soe', val{:});

%--------------------------------------------------------------------------
% uwfwhm Smoothing for unwarp (FWHM)
%--------------------------------------------------------------------------
uwfwhm         = cfg_entry;
uwfwhm.tag     = 'uwfwhm';
uwfwhm.name    = 'Smoothing for unwarp (FWHM)';
uwfwhm.help    = {'FWHM (mm) of smoothing filter applied to images prior to estimation of deformation fields.'};
uwfwhm.strtype = 'r';
uwfwhm.num     = [1 1];
uwfwhm.def     = @(val)spm_get_defaults('unwarp.estimate.fwhm', val{:});

%--------------------------------------------------------------------------
% rem Re-estimate movement params
%--------------------------------------------------------------------------
rem         = cfg_menu;
rem.tag     = 'rem';
rem.name    = 'Re-estimate movement params';
rem.help    = {'Re-estimation means that movement-parameters should be re-estimated at each unwarping iteration.'};
rem.labels  = {
              'Yes'
              'No'
}';
rem.values  = {1 0};
rem.def     = @(val)spm_get_defaults('unwarp.estimate.rem', val{:});

%--------------------------------------------------------------------------
% noi Number of Iterations
%--------------------------------------------------------------------------
noi         = cfg_entry;
noi.tag     = 'noi';
noi.name    = 'Number of Iterations';
noi.help    = {'Maximum number of iterations.'};
noi.strtype = 'n';
noi.num     = [1 1];
noi.def     = @(val)spm_get_defaults('unwarp.estimate.noi', val{:});

%--------------------------------------------------------------------------
% expround Taylor expansion point
%--------------------------------------------------------------------------
expround         = cfg_menu;
expround.tag     = 'expround';
expround.name    = 'Taylor expansion point';
expround.help    = {
    'Point in position space to perform Taylor-expansion around.'
    'Choices are (''First'', ''Last'' or ''Average''). ''Average'' should (in principle) give the best variance reduction. If a field-map acquired before the time-series is supplied then expansion around the ''First'' MIGHT give a slightly better average geometric fidelity.'
    };
expround.labels = {
                   'Average'
                   'First'
                   'Last'
}';
expround.values = {
                   'Average'
                   'First'
                   'Last'
}';
expround.def     = @(val)spm_get_defaults('unwarp.estimate.expround', val{:});

%--------------------------------------------------------------------------
% uweoptions Unwarp Estimation Options
%--------------------------------------------------------------------------
uweoptions      = cfg_branch;
uweoptions.tag  = 'uweoptions';
uweoptions.name = 'Unwarp Estimation Options';
uweoptions.val  = {basfcn regorder lambda jm fot sot uwfwhm rem noi expround};
uweoptions.help = {'Various registration & unwarping estimation options.'};

%--------------------------------------------------------------------------
% uwwhich Reslices images (unwarp)?
%--------------------------------------------------------------------------
uwwhich         = cfg_menu;
uwwhich.tag     = 'uwwhich';
uwwhich.name    = 'Resliced images (unwarp)?';
uwwhich.help    = {
    'Specify the images to reslice.'
    'All Images (1..n) '
    '  This reslices and unwarps all the images. '
    ' '
    'All Images + Mean Image '
    '  In addition to reslicing the images, it also creates a mean of the resliced images.'
    }';
uwwhich.labels = {
                  ' All Images (1..n)'
                  ' All Images + Mean Image'
}';
uwwhich.values = {[2 0] [2 1]};
uwwhich.def    = @(val)spm_get_defaults('realign.write.which', val{:});

%--------------------------------------------------------------------------
% rinterp Interpolation
%--------------------------------------------------------------------------
rinterp         = cfg_menu;
rinterp.tag     = 'rinterp';
rinterp.name    = 'Interpolation';
rinterp.help    = {
    'The method by which the images are sampled when being written in a different space.'
    'Nearest Neighbour is fastest, but not recommended for image realignment. Trilinear Interpolation is probably OK for PET, but not so suitable for fMRI because higher degree interpolation generally gives better results/* \cite{thevenaz00a,unser93a,unser93b}*/. Although higher degree methods provide better interpolation, but they are slower because they use more neighbouring voxels.'
    }';
rinterp.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'
}';
rinterp.values = {0 1 2 3 4 5 6 7};
rinterp.def    = @(val)spm_get_defaults('realign.write.interp', val{:});

%--------------------------------------------------------------------------
% wrap Wrapping
%--------------------------------------------------------------------------
wrap         = cfg_menu;
wrap.tag     = 'wrap';
wrap.name    = 'Wrapping';
wrap.help    = {
    'This indicates which directions in the volumes the values should wrap around in.'
    'These are typically:'
    '* No wrapping - for images that have already been spatially transformed.'
    '* Wrap in Y  - for (un-resliced) MRI where phase encoding is in the Y direction (voxel space).'
    }';
wrap.labels = {
               'No wrap'
               'Wrap X'
               'Wrap Y'
               'Wrap X & Y'
               'Wrap Z '
               'Wrap X & Z'
               'Wrap Y & Z'
               'Wrap X, Y & Z'
}';
wrap.values = {[0 0 0] [1 0 0] [0 1 0] [1 1 0] [0 0 1] [1 0 1] [0 1 1]...
               [1 1 1]};
wrap.def    = @(val)spm_get_defaults('realign.write.wrap', val{:});

%--------------------------------------------------------------------------
% mask Masking
%--------------------------------------------------------------------------
mask         = cfg_menu;
mask.tag     = 'mask';
mask.name    = 'Masking';
mask.help    = {'Because of subject motion, different images are likely to have different patterns of zeros from where it was not possible to sample data. With masking enabled, the program searches through the whole time series looking for voxels which need to be sampled from outside the original images. Where this occurs, that voxel is set to zero for the whole set of images (unless the image format can represent NaN, in which case NaNs are used where possible).'};
mask.labels  = {
                'Mask images'
                'Dont mask images'
}';
mask.values  = {1 0};
mask.def     = @(val)spm_get_defaults('realign.write.mask', val{:});

%--------------------------------------------------------------------------
% prefix Filename Prefix
%--------------------------------------------------------------------------
prefix         = cfg_entry;
prefix.tag     = 'prefix';
prefix.name    = 'Filename Prefix';
prefix.help    = {'Specify the string to be prepended to the filenames of the smoothed image file(s). Default prefix is ''u''.'};
prefix.strtype = 's';
prefix.num     = [1 Inf];
prefix.def     = @(val)spm_get_defaults('unwarp.write.prefix', val{:});

%--------------------------------------------------------------------------
% uwroptions Unwarp Reslicing Options
%--------------------------------------------------------------------------
uwroptions         = cfg_branch;
uwroptions.tag     = 'uwroptions';
uwroptions.name    = 'Unwarp Reslicing Options';
uwroptions.val     = {uwwhich rinterp wrap mask prefix};
uwroptions.help    = {'Various registration & unwarping estimation options.'};

%--------------------------------------------------------------------------
% realignunwarp Realign & Unwarp
%--------------------------------------------------------------------------
realignunwarp         = cfg_exbranch;
realignunwarp.tag     = 'realignunwarp';
realignunwarp.name    = 'Realign & Unwarp';
realignunwarp.val     = {generic eoptions uweoptions uwroptions};
realignunwarp.help    = {
    'Within-subject registration and unwarping of time series.'
    ''
    'The realignment part of this routine realigns a time-series of images acquired from the same subject using a least squares approach and a 6 parameter (rigid body) spatial transformation.  The first image in the list specified by the user is used as a reference to which all subsequent scans are realigned. The reference scan does not have to the the first chronologically and it may be wise to chose a "representative scan" in this role.'
    ''
    'The aim is primarily to remove movement artefact in fMRI and PET time-series (or more generally longitudinal studies). This affects the header of each of the input images which contains details about the voxel-to-world mapping. The details of the transformation are displayed in the results window as plots of translation and rotation. A set of realignment parameters are saved for each session, named rp_*.txt.'
    ''
    'In the coregistration step, the sessions are first realigned to each other, by aligning the first scan from each session to the first scan of the first session.  Then the images within each session are aligned to the first image of the session. The parameter estimation is performed this way because it is assumed (rightly or not) that there may be systematic differences in the images between sessions.'
    ''
    'See spm_uw_estimate.m for a detailed description of the implementation.'
    ''
    'Even after realignment there is considerable variance in fMRI time series that covary with, and is most probably caused by, subject movements/* \cite{ja_geometric}*/. It is also the case that this variance is typically large compared to experimentally induced variance. Anyone interested can include the estimated movement parameters as covariates in the design matrix, and take a look at an F-contrast encompassing those columns. It is quite dramatic. The result is loss of sensitivity, and if movements are correlated to task specificity. I.e. we may mistake movement induced variance for true activations. The problem is well known, and several solutions have been suggested. A quite pragmatic (and conservative) solution is to include the estimated movement parameters (and possibly squared) as covariates in the design matrix. Since we typically have loads of degrees of freedom in fMRI we can usually afford this. The problems occur when movements are correlated with the task, since the strategy above will discard "good" and "bad" variance alike (i.e. remove also "true" activations).'
    ''
    'The "covariate" strategy described above was predicated on a model where variance was assumed to be caused by "spin history" effects, but will work pretty much equally good/bad regardless of what the true underlying cause is. Others have assumed that the residual variance is caused mainly by errors introduced by the interpolation kernel in the resampling step of the realignment. One has tried to solve this through higher order resampling (huge Sinc kernels, or k-space resampling). Unwarp is based on a different hypothesis regarding the residual variance. EPI images are not particularly faithful reproductions of the object, and in particular there are severe geometric distortions in regions where there is an air-tissue interface (e.g. orbitofrontal cortex and the anterior medial temporal lobes). In these areas in particular the observed image is a severely warped version of reality, much like a funny mirror at a fair ground. When one moves in front of such a mirror ones image will distort in different ways and ones head may change from very elongated to seriously flattened. If we were to take digital snapshots of the reflection at these different positions it is rather obvious that realignment will not suffice to bring them into a common space.'
    ''
    'The situation is similar with EPI images, and an image collected for a given subject position will not be identical to that collected at another. We call this effect susceptibility-by-movement interaction. Unwarp is predicated on the assumption that the susceptibility-by-movement interaction is responsible for a sizable part of residual movement related variance.'
    ''
    'Assume that we know how the deformations change when the subject changes position (i.e. we know the derivatives of the deformations with respect to subject position). That means that for a given time series and a given set of subject movements we should be able to predict the "shape changes" in the object and the ensuing variance in the time series. It also means that, in principle, we should be able to formulate the inverse problem, i.e. given the observed variance (after realignment) and known (estimated) movements we should be able to estimate how deformations change with subject movement. We have made an attempt at formulating such an inverse model, and at solving for the "derivative fields". A deformation field can be thought of as little vectors at each position in space showing how that particular location has been deflected. A "derivative field" is then the rate of change of those vectors with respect to subject movement. Given these "derivative fields" we should be able to remove the variance caused by the susceptibility-by-movement interaction. Since the underlying model is so restricted we would also expect experimentally induced variance to be preserved. Our experiments have also shown this to be true.'
    ''
    'In theory it should be possible to estimate also the "static" deformation field, yielding an unwarped (to some true geometry) version of the time series. In practise that doesn''t really seem to work. Hence, the method deals only with residual movement related variance induced by the susceptibility-by-movement interaction. This means that the time-series will be undistorted to some "average distortion" state rather than to the true geometry. If one wants additionally to address the issue of anatomical fidelity one should combine Unwarp with a measured fieldmap.'
    ''
    'The description above can be thought of in terms of a Taylor expansion of the field as a function of subject movement. Unwarp alone will estimate the first (and optionally second, see below) order terms of this expansion. It cannot estimate the zeroth order term (the distortions common to all scans in the time series) since that doesn''t introduce (almost) any variance in the time series. The measured fieldmap takes the role of the zeroth order term. Refer to the FieldMap toolbox and the documents FieldMap.man and FieldMap_principles.man for a description of how to obtain fieldmaps in the format expected by Unwarp.'
    ''
    'If we think of the field as a function of subject movement it should in principle be a function of six variables since rigid body movement has six degrees of freedom. However, the physics of the problem tells us that the field should not depend on translations nor on rotation in a plane perpendicular to the magnetic flux. Hence it should in principle be sufficient to model the field as a function of out-of-plane rotations (i.e. pitch and roll). One can object to this in terms of the effects of shimming (object no longer immersed in a homogenous field) that introduces a dependence on all movement parameters. In addition SPM/Unwarp cannot really tell if the transversal slices it is being passed are really perpendicular to the flux or not. In practice it turns out thought that it is never (at least we haven''t seen any case) necessary to include more than Pitch and Roll. This is probably because the individual movement parameters are typically highly correlated anyway, which in turn is probably because most heads that we scan are attached to a neck around which rotations occur. On the subject of Taylor expansion we should mention that there is the option to use a second-order expansion (through the defaults) interface. This implies estimating also the rate-of-change w.r.t. to some movement parameter of the rate-of-change of the field w.r.t. some movement parameter (colloquially known as a second derivative). It can be quite interesting to watch (and it is amazing that it is possible) but rarely helpful/necessary.'
    ''
    'In the defaults there is also an option to include Jacobian intensity modulation when estimating the fields. "Jacobian intensity modulation" refers to the dilution/concentration of intensity that ensue as a consequence of the distortions. Think of a semi-transparent coloured rubber sheet that you hold against a white background. If you stretch a part of the sheet (induce distortions) you will see the colour fading in that particular area. In theory it is a brilliant idea to include also these effects when estimating the field (see e.g. Andersson et al, NeuroImage 20:870-888). In practice for this specific problem it is NOT a good idea.'
    ''
    'It should be noted that this is a method intended to correct data afflicted by a particular problem. If there is little movement in your data to begin with this method will do you little good. If on the other hand there is appreciable movement in your data (>1deg) it will remove some of that unwanted variance. If, in addition, movements are task related it will do so without removing all your "true" activations. The method attempts to minimise total (across the image volume) variance in the data set. It should be realised that while (for small movements) a rather limited portion of the total variance is removed, the susceptibility-by-movement interaction effects are quite localised to "problem" areas. Hence, for a subset of voxels in e.g. frontal-medial and orbitofrontal cortices and parts of the temporal lobes the reduction can be quite dramatic (>90). The advantages of using Unwarp will also depend strongly on the specifics of the scanner and sequence by which your data has been acquired. When using the latest generation scanners distortions are typically quite small, and distortion-by-movement interactions consequently even smaller. A small check list in terms of distortions is '
    'a) Fast gradients->short read-out time->small distortions '
    'b) Low field (i.e. <3T)->small field changes->small distortions '
    'c) Low res (64x64)->short read-out time->small distortions '
    'd) SENSE/SMASH->short read-out time->small distortions '
    'If you can tick off all points above chances are you have minimal distortions to begin with and Unwarp might not be of use to you.'
    }';
realignunwarp.prog     = @spm_run_realignunwarp;
realignunwarp.vout     = @vout_realignunwarp;
realignunwarp.modality = {'PET','FMRI'};

%==========================================================================
function dep = vout_realignunwarp(job)
for k=1:numel(job.data)
    cdep(1)            = cfg_dep;
    cdep(1).sname      = sprintf('Realignment Param File (Sess %d)', k);
    cdep(1).src_output = substruct('.','sess', '()',{k}, '.','rpfile');
    cdep(1).tgt_spec   = cfg_findspec({{'filter','mat','strtype','e'}});
    cdep(2)            = cfg_dep;
    cdep(2).sname      = sprintf('Unwarp Params File (Sess %d)', k);
    cdep(2).src_output = substruct('.','sess', '()',{k}, '.','dsfile');
    cdep(2).tgt_spec   = cfg_findspec({{'filter','any','strtype','e'}});
    if job.uwroptions.uwwhich(1) == 2
        cdep(3)            = cfg_dep;
        cdep(3).sname      = sprintf('Unwarped Images (Sess %d)', k);
        cdep(3).src_output = substruct('.','sess', '()',{k}, '.','uwrfiles');
        cdep(3).tgt_spec   = cfg_findspec({{'filter','image','strtype','e'}});
    end
    if k == 1
        dep = cdep;
    else
        dep = [dep cdep];
    end
end

if job.uwroptions.uwwhich(2)
    dep(end+1)          = cfg_dep;
    dep(end).sname      = 'Unwarped Mean Image';
    dep(end).src_output = substruct('.','meanuwr');
    dep(end).tgt_spec   = cfg_findspec({{'filter','image','strtype','e'}});
end


classdef TestMatchGMS
    %TestMatchGMS

    methods (Static)
        function test_1
            im1 = imread(fullfile(mexopencv.root(),'test','left01.jpg'));
            im2 = imread(fullfile(mexopencv.root(),'test','right01.jpg'));
            sz1 = [size(im1,2), size(im1,1)];
            sz2 = [size(im2,2), size(im2,1)];
            obj = cv.ORB('MaxFeatures',5000, 'FastThreshold',0);
            [kpts1, feat1] = obj.detectAndCompute(im1);
            [kpts2, feat2] = obj.detectAndCompute(im2);
            matcher = cv.DescriptorMatcher('BruteForce-Hamming');
            m = matcher.match(feat1, feat2);

            mGMS = cv.matchGMS(sz1, kpts1, sz2, kpts2, m);
            validateattributes(mGMS, {'struct'}, {'vector'});
            assert(all(ismember(TestDescriptorMatcher.fields, ...
                fieldnames(mGMS))));
        end

        function test_error_argnum
            try
                cv.matchGMS();
                throw('UnitTest:Fail');
            catch e
                assert(strcmp(e.identifier,'mexopencv:error'));
            end
        end
    end

end


function updatedInfo = matRad_daoVec2ApertureInfo(apertureInfo,apertureInfoVect)
% matRad function to translate vector representation into struct
% The vector representation of the aperture shape and weight are translated
% into an aperture info struct. At the same time, the updated bixel weight
% vector w is computed and a vector listing the correspondence between leaf
% tips and bixel indices for gradient calculation
%
% call
%   updatedInfo = matRad_daoVec2ApertureInfo(apertureInfo,apertureInfoVect)
%
% input
%   apertureInfo:     aperture shape info struct
%   apertureInfoVect: aperture weights and shapes parameterized as vector
%
% output
%   updatedInfo: updated aperture shape info struct according to apertureInfoVect
%
% References
%
%
% %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%

% %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%
% Copyright 2015 the matRad development team.
%
% This file is part of the matRad project. It is subject to the license
% terms in the LICENSE file found in the top-level directory of this
% distribution and at https://github.com/e0404/matRad/LICENSES.txt. No part
% of the matRad project, including this file, may be copied, modified,
% propagated, or distributed except according to the terms contained in the
% LICENSE file.
%
% %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%

% function to update the apertureInfo struct after the each iteraton of the
% optimization

w = zeros(apertureInfo.totalNumOfBixels,1);

% initializing variables
updatedInfo = apertureInfo;

updatedInfo.apertureVector = apertureInfoVect;

shapeInd = 1;

indVect = NaN*ones(apertureInfo.totalNumOfShapes + apertureInfo.totalNumOfLeafPairs,1);

% helper function to cope with numerical instabilities through rounding
round2 = @(a,b) round(a*10^b)/10^b;

%% update the shapeMaps
% here the new colimator positions are used to create new shapeMaps that
% now include decimal values instead of binary

% loop over all beams
for i = 1:numel(updatedInfo.beam)

    %posOfRightCornerPixel = apertureInfo.beam(i).posOfCornerBixel(1) + (size(apertureInfo.beam(i).bixelIndMap,2)-1)*apertureInfo.bixelWidth;

    % pre compute left and right bixel edges
    edges_l = updatedInfo.beam(i).posOfCornerBixel(1)...
                 + ([1:size(apertureInfo.beam(i).bixelIndMap,2)]-1-1/2)*updatedInfo.bixelWidth;
    edges_r = updatedInfo.beam(i).posOfCornerBixel(1)...
                 + ([1:size(apertureInfo.beam(i).bixelIndMap,2)]-1+1/2)*updatedInfo.bixelWidth;

    % loop over all shapes
    for j = 1:updatedInfo.beam(i).numOfShapes

        % update the shape weight
        updatedInfo.beam(i).shape(j).weight = apertureInfoVect(shapeInd);

        % get dimensions of 2d matrices that store shape/bixel information
        n = apertureInfo.beam(i).numOfActiveLeafPairs;

        % extract left and right leaf positions from shape vector
        vectorIx     = updatedInfo.beam(i).shape(j).vectorOffset + ([1:n]-1);
        leftLeafPos  = apertureInfoVect(vectorIx);
        rightLeafPos = apertureInfoVect(vectorIx+apertureInfo.totalNumOfLeafPairs);

        % update information in shape structure
        updatedInfo.beam(i).shape(j).leftLeafPos  = leftLeafPos;
        updatedInfo.beam(i).shape(j).rightLeafPos = rightLeafPos;

        % rounding for numerical stability
        leftLeafPos  = round2(leftLeafPos,6);
        rightLeafPos = round2(rightLeafPos,6);

        %
        xPosIndLeftLeaf  = round((leftLeafPos - apertureInfo.beam(i).posOfCornerBixel(1))/apertureInfo.bixelWidth + 1);
        xPosIndRightLeaf = round((rightLeafPos - apertureInfo.beam(i).posOfCornerBixel(1))/apertureInfo.bixelWidth + 1);

        % check limits because of rounding off issues at maximum, i.e.,
        % enforce round(X.5) -> X
        xPosIndLeftLeaf(leftLeafPos == apertureInfo.beam(i).lim_r) = ...
            .5 + (leftLeafPos(leftLeafPos == apertureInfo.beam(i).lim_r) ...
            - apertureInfo.beam(i).posOfCornerBixel(1))/apertureInfo.bixelWidth;
        xPosIndRightLeaf(rightLeafPos == apertureInfo.beam(i).lim_r) = ...
            .5 + (rightLeafPos(rightLeafPos == apertureInfo.beam(i).lim_r) ...
            - apertureInfo.beam(i).posOfCornerBixel(1))/apertureInfo.bixelWidth;

        % find the bixel index that the leaves currently touch
        bixelIndLeftLeaf  = apertureInfo.beam(i).bixelIndMap((xPosIndLeftLeaf-1)*n+[1:n]');
        bixelIndRightLeaf = apertureInfo.beam(i).bixelIndMap((xPosIndRightLeaf-1)*n+[1:n]');

        if any(isnan(bixelIndLeftLeaf)) || any(isnan(bixelIndRightLeaf))
            error('cannot map leaf position to bixel index');
        end

        % store information in index vector for gradient calculation
        indVect(apertureInfo.beam(i).shape(j).vectorOffset+[1:n]-1) = bixelIndLeftLeaf;
        indVect(apertureInfo.beam(i).shape(j).vectorOffset+[1:n]-1+apertureInfo.totalNumOfLeafPairs) = bixelIndRightLeaf;

        % calculate opening fraction for every bixel in shape to construct
        % bixel weight vector

        coveredByLeftLeaf  = bsxfun(@minus,leftLeafPos,edges_l)  / updatedInfo.bixelWidth;
        coveredByRightLeaf = bsxfun(@minus,edges_r,rightLeafPos) / updatedInfo.bixelWidth;

        tempMap = 1 - (coveredByLeftLeaf  + abs(coveredByLeftLeaf))  / 2 ...
                    - (coveredByRightLeaf + abs(coveredByRightLeaf)) / 2;

        % find open bixels
        tempMapIx = tempMap > 0;

        currBixelIx = apertureInfo.beam(i).bixelIndMap(tempMapIx);
        w(currBixelIx) = w(currBixelIx) + tempMap(tempMapIx)*updatedInfo.beam(i).shape(j).weight;

        % save the tempMap (we need to apply a positivity operator !)
        updatedInfo.beam(i).shape(j).shapeMap = (tempMap  + abs(tempMap))  / 2;

        % increment shape index
        shapeInd = shapeInd +1;
    end

end

updatedInfo.bixelWeights = w;
updatedInfo.bixelIndices = indVect;

end


classdef SlidingWindowSegmentation < Algorithm
    properties (Access = public)
        windowSize = 512;
        iterationSize = 256;
    end

    methods (Access = public)
        function obj = SlidingWindowSegmentation(windowSize,iterationSize)
            if nargin > 0
                obj.windowSize = windowSize;
                if nargin > 1
                    obj.iterationSize = iterationSize;
                end
            end

            obj.name = 'slidingWindow';
            obj.inputPort = DataType.kSignal;
            obj.outputPort = DataType.kSegment;
        end

        function segments = compute(obj,data)
            file = Algorithm.GetSharedContextVariable(Constants.kSharedVariableCurrentDataFile);
            nSamples = length(data);
            nSegments = int32 ((nSamples - obj.windowSize + 1) / obj.iterationSize);
            segments = repmat(Segment,1,nSegments);
            segmentsCount = 1;
            for i = 1 : obj.iterationSize : nSamples - obj.windowSize
                endSample = i + obj.windowSize - 1;
                segment = Segment(file.fileName,file.data(i:endSample,:));
                segment.startSample = i;
                segment.endSample = endSample;
                segments(segmentsCount) = segment;
                segmentsCount = segmentsCount + 1;
            end
        end

        function str = toString(obj)
            str = sprintf('%s_%d_%d',obj.name,obj.windowSize,obj.iterationSize);
        end

        function metrics = computeMetrics(obj,input)
            file = Algorithm.GetSharedContextVariable(Constants.kSharedVariableCurrentDataFile);
            nSamples = length(input);
            nSegments = int32 ((nSamples - obj.windowSize + 1) / obj.iterationSize);
            flops = (nSamples - obj.windowSize ) / obj.iterationSize;
            memory = obj.windowSize * file.numColumns * Constants.kSensorDataBytes;
            outputSize = obj.windowSize * file.numColumns * nSegments * Constants.kSensorDataBytes;
            metrics = Metric(flops,memory,outputSize);
        end

        function editableProperties = getEditableProperties(obj)
            property1 = Property('windowSize',obj.windowSize,50,1024,PropertyType.kNumber);
            property2 = Property('iterationSize',obj.iterationSize,10,1024,PropertyType.kNumber);
            editableProperties = [property1,property2];
        end
    end
end


function stopnow = mystopfun(problem, x, info, last)
    stopnow = (last >= 3 && info(last-2).cost - info(last).cost < 1e-3);
end


function p = mtexExamplePath
% returns the default path to EBSD data files
%
% Syntax
%   mtexEBSDPath
%   getMTEXpref('EBSDPath') % long form of mtexEBSDPath
%   setMTEXpref('EBSDPath',path) % change the path to EBSD files
%
% See also
% mtexDataPath mtexCifPath mtexEBSDPath mtexPoleFigurePath mtexODFPath
% mtexTensorPath

examplePath = getMTEXpref('ExamplePath');

if exist(examplePath,'dir')
  p = examplePath;
else
  error('Examples not found!');
end


function sl_customization(cm)

% Copyright 1990-2013 The MathWorks, Inc.
% $Revision: 1.1.8.1 $

    cm.addCustomMenuFcn('Simulink:ContextMenu',@getMyMenuItems);
    cm.addCustomFilterFcn('sig_call_back',@myFilter);
end

%% Define the custom menu function.
function schemaFcns = getMyMenuItems(callbackInfo)
  schemaFcns = {@getItem1};
end

%% create filter for menu to appear only for Simscape Probe blocks
function state = myFilter(callbackInfo)
  if strmatch(get_param(gcb,'maskdescription'),'Simscape Probe','exact')
    state = 'Enabled';
  else
    state = 'Hidden';
  end
end

%% Define the schema function for first menu item.
function schema = getItem1(callbackInfo)
  schema = sl_container_schema;
  if strmatch(get_param(gcb,'maskdescription'),'Simscape Probe','exact')
    schema.state = 'Enabled';
    schema.childrenFcns = {@units, @outPort @tagType};
    schema.label = 'Configure Probe';
  else
    schema.state = 'Hidden';
  end
end
%% Define Sub-menu entries
function schema = units(callbackInfo)
  schema = sl_action_schema;
  schema.label = 'Set Units';
  schema.callback = @setUnits;
end

function schema = outPort(callbackInfo)
  schema = sl_action_schema;
  schema.label = 'Add Output Port';
  schema.callback = @addOutputPort;
end

function schema = tagType(callbackInfo)
  schema = sl_toggle_schema;
  schema.label = 'Global';
  if strcmp(get_param([gcb, '/Goto'], 'TagVisibility'),'global') == 1
    schema.checked = 'checked';
  else
    schema.checked = 'unchecked';
  end
  schema.callback = @setTag;
end

%% Function callbacks from menu options
function setUnits(callbackInfo)

open_system([gcb, '/PS-S']) % Open PS-S dialog box to set units

end

function addOutputPort(callbackInfo)
p=get_param([gcb, '/PS-S'],'Position'); % get position of PS-S block as a reference
hOutblock = add_block('built-in/Outport', [gcb '/Out'],...
            'MakeNameUnique', 'on','Position', ...
            [p(1)+150 p(2)+100 p(3)+175 p(4)+100]);
add_line(gcb, ['PS-S', '/1'], ['Out', '/1'],'autorouting','on');
end

function setTag(callbackInfo)
tv=get_param([gcb, '/Goto'],'TagVisibility');
  if  regexp(tv,'global') == 1
     set_param([gcb, '/Goto'],'TagVisibility', 'local');
  elseif regexp(tv,'local') == 1
     set_param([gcb, '/Goto'],'TagVisibility', 'global');
  end
end


%Chromosome Segregation
%
% @wholeCellModelID Process_ChromosomeSegregation
% @name             Chromosome Segregation
% @description
%   Biology
%   ======================
%   Chromosome segregation in Mycoplasma genitalium has not been well described.
%   Chromosome segregation in M. genitalium is believed to result from two
%   factors
%   - entropically favorable segregation throughout DNA replication
%   - four chromosome segregation proteins which act to decatenate the
%     chromosomes following the completion of replication
%   Little is known about the times at which these two factors contribute to
%   chromosome segregation.
%
%   Bacterial chromosome segregation is believed to be entropically favorable
%   and occur during replication (Bloom et al. 2010, Jun et al. 2006). That is,
%   its believed to be entropically unfavorable for two chromosomes to be
%   located near each other, and so as the replication fork moves, the
%   replicated DNA molecules migrate away from each other toward the poles. We
%   assume that by the end of replication the chromosomes have already migrated
%   toward the poles.
%
%   Four proteins are believed to be involved in chromosome decatenation in M.
%   genitalium:
%   - MG_470_MONOMER  nucleotide binding domain protein CobQ/CobB/MinD/ParA
%   - MG_221_OCTAMER  MraZ
%   - MG_387_MONOMER  GTP binding protein Era
%   - MG_384_MONOMER  GTPase Obg
%   The specific function, kinetics, and metabolic costs of these proteins are
%   not known. Furthemore, because M. genitalium contains a reduced complement
%   of segregation proteins, it is difficult to infer their functions from
%   studies of other bacterial species.
%
%   Knowledge Base
%   ======================
%   The knowledge base contains the value of the gtpCost parameter.
%
%   Representation
%   ======================
%   The substrates and enzymes properties represent the counts of available
%   metabolites and segregation enzymes. gtpCost represents the energetic
%   (GTP) cost of chromosome segregation. The segregation status of the
%   chromosomes is represented as a boolean properties (segregated) of the
%   Chromosome class.
%
%   Initialization
%   ======================
%   Chromosome initializes to a state with 1 chromosome (which obviously
%   hasn't yet segregated from the second chromosome which will be later
%   produced).
%
%   Simulation
%   ======================
%   Because little is known about the molecular biology of chromosome
%   segregation, we have chosen to implement this process as a simple boolean
%   rule: chromosome segregation can occur if:
%   - the chromosome is replicated
%   - the chromosome is properly supercoiled
%   - there is at least one free molecule of each segregation proteins, and
%   - there is at least gtpCost free GTP molecules
%
%   Note, although the Glass et al. gene essentiality study suggests that the
%   cobQ/cobB/minD/parA gene is non-essential, we model this gene as essential
%   because we don't know its specific function and how the other segregation
%   proteins compensate in its absence.
%
%   References
%   ======================
%   1. Bloom, K., Joglekar, A. (2010). Towards building a chromosome segregation
%      machine. Nature 463: 446-456.
%   2. Jun, S., Mulder, B. (2006). Entropy-driven special organization of highly
%      confined polymers: Lessons for the bacterial chromosome. PNAS 103:
%      12388-12393.
%   3. Glass, J.I., Assad-Garcia, N., Alperovich, N., Yooseph, S., Lewis, M.R.,
%      Maruf, M., Hutchison III, C.A., Smith, H.O., Venter, J.C. (2006).
%      Essential genes of a minimal bacterium. PNAS 103: 425-430.
%
% Author: Jayodita Sanghvi, jayodita@stanford.edu
% Author: Jonathan Karr, jkarr@stanford.edu
% Author: Jared Jacobs, jmjacobs@stanford.edu
% Affilitation: Covert Lab, Department of Bioengineering, Stanford University
% Last updated: 7/7/2010
classdef  ChromosomeSegregation < edu.stanford.covert.cell.sim.Process & edu.stanford.covert.cell.sim.ChromosomeProcessAspect
    %property annotations
    properties (Constant)
        optionNames__              = {}; %names of option properties
        fixedConstantNames__       = {   %names of fixed constant properties
            'gtpCost'};
        fittedConstantNames__      = {}; %names of fitted constant properties
        localStateNames__          = {}; %names of simulation state properties redundant with timecourses in this or other processes or the simulation
    end

    %IDs, names, and local indices
    properties
        stimuliWholeCellModelIDs   = {}; %whole cell model IDs of stimuli

        substrateWholeCellModelIDs = {   %whole cell model IDs of substrates
            'GTP';'GDP';'H';'H2O';'PI'};
        substrateIndexs_gtp       = 1; %index of ATP within substrateWholeCellModelIDs
        substrateIndexs_gdp       = 2; %index of ADP within substrateWholeCellModelIDs
        substrateIndexs_hydrogen  = 3; %index of hydrogen within substrateWholeCellModelIDs
        substrateIndexs_water     = 4; %index of water within substrateWholeCellModelIDs
        substrateIndexs_phosphate = 5; %index of inorganic phosphate within substrateWholeCellModelIDs

        enzymeWholeCellModelIDs = {      %whole cell model IDs of enzymes
            'MG_470_MONOMER'       %CobQ/CobB/MinD/ParA nucleotide binding domain
            'MG_221_OCTAMER'       %mraZ protein
            'MG_387_MONOMER'       %GTP-binding protein Era
            'MG_384_MONOMER'       %GTPase1 Obg
            'MG_203_204_TETRAMER'  %DNA topoisomerase IV
            };
        enzymeIndexs_cobQ   = 1;
        enzymeIndexs_mraZ   = 2;
        enzymeIndexs_obg    = 3;
        enzymeIndexs_era    = 4;
        enzymeIndexs_topoIV = 5;
    end

    %fixed biological constants
    properties
        gtpCost %number of GTP required for chromosome segregation (1); true value unknown
    end

    %constructor
    methods
        function this = ChromosomeSegregation(wholeCellModelID, name)
            this = this@edu.stanford.covert.cell.sim.Process(wholeCellModelID, name);
        end
    end

    %communication between process/simulation
    methods
        %set references to state objects
        function storeObjectReferences(this, simulation)
            this.storeObjectReferences@edu.stanford.covert.cell.sim.Process(simulation);
            this.storeObjectReferences@edu.stanford.covert.cell.sim.ChromosomeProcessAspect(simulation);
        end

        %initialize constants
        function initializeConstants(this, knowledgeBase, simulation, varargin)
            this.initializeConstants@edu.stanford.covert.cell.sim.Process(...
                knowledgeBase, simulation, varargin{:});
            this.initializeConstants@edu.stanford.covert.cell.sim.ChromosomeProcessAspect(...
                knowledgeBase, simulation, varargin{:});
        end
    end

    %model
    methods
        %Calculate
        %- contribution to FBA objective
        %- minimum expression consistent with cell cycle length
        function [bmProd, byProd, minEnzExp, maxEnzExp] = calcResourceRequirements_LifeCycle(this, ~, ~)
            %% initialize
            bmProd = zeros(size(this.substrateWholeCellModelIDs));
            byProd = zeros(size(this.substrateWholeCellModelIDs));
            minEnzExp = zeros(size(this.enzymeWholeCellModelIDs));
            maxEnzExp = Inf(size(this.enzymeWholeCellModelIDs));

            %% substrate and byproducts: GTP required to decatenate chromosomes, and its hydrolysis (GTP + H2O ==> GDP + PI + H)
            bmProd(this.substrateIndexs_gtp)       = this.gtpCost;
            bmProd(this.substrateIndexs_water)     = this.gtpCost;
            byProd(this.substrateIndexs_gdp)       = this.gtpCost;
            byProd(this.substrateIndexs_phosphate) = this.gtpCost;
            byProd(this.substrateIndexs_hydrogen)  = this.gtpCost;

            %% Segregation requires at least 1 copy of every enzyme
            minEnzExp(:) = 2;
        end

        %initialization: chromosome state initializes chromosome to state with 1
        %chromosome (which trivially is not segregated)
        function initializeState(~)
        end

        %resource requirements
        function result = calcResourceRequirements_Current(this)
            c = this.chromosome;
            result = zeros(size(this.substrates));
            if ...
                    ~c.segregated && ...
                    collapse(c.polymerizedRegions) == c.nCompartments * c.sequenceLen && ...
                    all(this.enzymes)

                result(this.substrateIndexs_gtp) = this.gtpCost;
                result(this.substrateIndexs_water) = result(this.substrateIndexs_gtp);
            end
        end

        %simulation
        function evolveState(this)
            c = this.chromosome;

            if ...
                    ~c.segregated && ...
                    collapse(c.polymerizedRegions) == c.nCompartments * c.sequenceLen && ...
                    collapse(c.supercoiled) == c.nCompartments && ...
                    all(this.enzymes) && ...
                    this.substrates(this.substrateIndexs_gtp) >= this.gtpCost && ...
                    this.substrates(this.substrateIndexs_water) >= this.gtpCost

                c.segregated = true;

                this.substrates(this.substrateIndexs_gtp)       = this.substrates(this.substrateIndexs_gtp)       - this.gtpCost;
                this.substrates(this.substrateIndexs_water)     = this.substrates(this.substrateIndexs_water)     - this.gtpCost;
                this.substrates(this.substrateIndexs_gdp)       = this.substrates(this.substrateIndexs_gdp)       + this.gtpCost;
                this.substrates(this.substrateIndexs_phosphate) = this.substrates(this.substrateIndexs_phosphate) + this.gtpCost;
                this.substrates(this.substrateIndexs_hydrogen)  = this.substrates(this.substrateIndexs_hydrogen)  + this.gtpCost;
            end
        end
    end
end


function varargout=wqrs(varargin)
%
% wqrs(recordName,N,N0,signal,threshold,findJ,powerLineFrequency,resample)
%
%    Wrapper to WFDB WQRS:
%         http://www.physionet.org/physiotools/wag/wqrs-1.htm
%
%    Creates a WQRS annotation file  at the current MATLAB directory.
%    The annotation file will have the same name as the recorName file,
%    but followed with the *.wqrs suffix. Use RDANN to read the annoations
%    into MATLAB's workspace in order to read the sample QRS locations.
%
%    If recordName is the path to a record at PhysioNet's database, then
%    the annation files will be stored in a subdirectory with the same relative
%    path as recordName and under the current directory.
%
%
%    NOTE: In order to read the generated annotation file using RDANN, it is
%    necessary to have the WFDB record (*.hea and *.dat) files in the same
%    directory as the annotation file.
%
%
% CITING CREDIT: To credit this function, please cite the following paper in your work:
%
% Zong, W., G. B. Moody, and D. Jiang."A robust open-source algorithm to detect onset
% and duration of QRS complexes." Computers in Cardiology, 2003. IEEE, 2003.
%
%
% Required Parameters:
%
% recorName
%       String specifying the name of the record in the WFDB path or
%       in the current directory.
%
%
% Optional Parameters are:
%
% N
%       A 1x1 integer specifying the sample number at which to stop reading the
%       record file (default read all = N).
% N0
%       A 1x1 integer specifying the sample number at which to start reading the
%       annotion file (default 1 = begining of the record).
%
% signal
%       A 1x1 integer. Specify the signal to obtain the annotation (default
%       = 1, first signal).
%
% threshold
%       A 1x1 double. Specify the detection threshold in millivolts
%      (default = 100). Use higher values to reduce false detections, or lower values to
%       reduce the number of missed beats.
%
% findJ
%       A 1x1 boolean. Find and annotate J-points (QRS ends) as well as QRS onsets.
%       Default is false.
%
%
% powerLineFrequency
%       A 1x1 double. Specify the power line main frequency in Hz (default=
%       60 Hz), wqrs will apply a notch filter of the specified frequency
%       to the input signal before length-transforming it.
%
% resample
%       A 1x1 boolean. Resample the input at 120 Hz if the power line frequency
%       is 60 Hz, or at 150 Hz otherwise (default= false : do not resample).
%
%
%
% Source code written by Wei Zong and George B. Moody.
%
% MATLAB wrapper written by Ikaro Silva, 2013
% Last Modified: -
% Version 1.0
% Since 0.0.1
%
% %Example - Requires write permission to current directory
%wqrs('challenge/2013/set-a/a01');

%endOfHelp

javaWfdbExec=getWfdbClass('wqrs');

%Set default pararamter values
inputs={'recordName','N','N0','signal','threshold', ...
    'findJ','powerLineFrequency','resample'};
N=[];
N0=1;
signal=[]; %use application default
threshold=[];%use application default
findJ=[];
powerLineFrequency=[];
resample=[];
for n=1:nargin
    if(~isempty(varargin{n}))
        eval([inputs{n} '=varargin{n};']);
    end
end

N0=num2str(N0-1); %-1 is necessary because WFDB is 0 based indexed.
wfdb_argument={'-r',recordName,'-f',['s' N0]};

if(~isempty(N))
    wfdb_argument{end+1}='-t';
    %-1 is necessary because WFDB is 0 based indexed.
    wfdb_argument{end+1}=['s' num2str(N-1)];
end
if(~isempty(signal))
    wfdb_argument{end+1}='-s';
    %-1 is necessary because WFDB is 0 based indexed.
    wfdb_argument{end+1}=num2str(signal-1);
end
if(~isempty(threshold))
    wfdb_argument{end+1}='-m';
    %-1 is necessary because WFDB is 0 based indexed.
    wfdb_argument{end+1}=num2str(threshold-1);
end
if(~isempty(findJ) && findJ)
    wfdb_argument{end+1}='-j';
end

if(~isempty(powerLineFrequency))
    wfdb_argument{end+1}='-p';
    %-1 is necessary because WFDB is 0 based indexed.
    wfdb_argument{end+1}=num2str(powerLineFrequency);
end

if(~isempty(resample) && resample)
    wfdb_argument{end+1}='-R';
end

javaWfdbExec.execToStringList(wfdb_argument);


function out = pedfremap(x)
% PEDFREMAP Piecewise extended density format remap
%
% //////////////////////////////////////////
% /// CLASSIFICATION: UNCLASSIFIED       ///
% //////////////////////////////////////////

    out = amplitudetodensity(x);
    out(out > 128) = .5 * (out(out>128) + 128);
    out = uint8(out);
end
% //////////////////////////////////////////
% /// CLASSIFICATION: UNCLASSIFIED       ///
% //////////////////////////////////////////


% resolve conflict between trackers
function trackers = handle_conflicting_trackers(trackers, bboxes_det, opt)

% collect bboxes from trackers
bboxes_track = [];
for i = 1:numel(trackers)
    tracker = trackers{i};
    bboxes = sub_bboxes(tracker.bboxes, numel(tracker.bboxes.fr));

    if tracker.state == opt.STATE_TRACKED || tracker.state == opt.STATE_ACTIVATED
        if isempty(bboxes_track)
            bboxes_track = bboxes;
        else
            bboxes_track = concatenate_bboxes(bboxes_track, bboxes);
        end
    end

    if tracker.state == opt.STATE_STOP
        tracker.eco = [];
    end
end

% compute overlaps
num_det = numel(bboxes_det.fr);
if isempty(bboxes_track)
    num_track = 0;
else
    num_track = numel(bboxes_track.fr);
end

flag = zeros(num_track, 1);
for i = 1:num_track
    if flag(i) == 1
        continue;
    end
    [~, o] = calc_overlap(bboxes_track, i, bboxes_track, 1:num_track);
    o(i) = 0;
    o(flag == 1) = 0;
    [max_ov, j] = max(o);
    if max_ov > opt.overlap_sup
        num1 = trackers{bboxes_track.id(i)}.num_tracked;
        num2 = trackers{bboxes_track.id(j)}.num_tracked;
        o1 = max(calc_overlap(bboxes_track, i, bboxes_det, 1:num_det));
        o2 = max(calc_overlap(bboxes_track, j, bboxes_det, 1:num_det));

        if num1 > num2
            suppressed_idx = j;
            winner_idx = i;
        elseif num1 < num2
            suppressed_idx = i;
            winner_idx = j;
        else
            if o1 > o2
                suppressed_idx = j;
                winner_idx = i;
            else
                suppressed_idx = i;
                winner_idx = j;
            end
        end

        if numel(trackers{bboxes_track.id(suppressed_idx)}.bboxes.fr) == 1
            trackers{bboxes_track.id(suppressed_idx)}.state = opt.STATE_STOP;
            trackers{bboxes_track.id(suppressed_idx)}.bboxes.state(end) = opt.STATE_STOP;
        else
            trackers{bboxes_track.id(suppressed_idx)}.state = opt.STATE_LOST;
            trackers{bboxes_track.id(suppressed_idx)}.bboxes.state(end) = opt.STATE_LOST;
        end
        if opt.is_print
            fprintf('target %d suppressed by %d\n', bboxes_track.id(suppressed_idx), bboxes_track.id(winner_idx));
        end
        flag(suppressed_idx) = 1;
    end
end


function depth(fileName, sensorType, varName)

    %% Check if input is valid
    if ~isstring(fileName) && ~ischar(fileName)
        error("File name must a string or char array\n")
    end

    if ~strcmp(sensorType, "depth")
       error("Wrong sensor selected\n")
    end

    if ~isvarname(varName)
        error("Invalid variable name\n")
    end

    %% Create a python file
    file = fopen(strcat(fileName, '.py'), 'w');

    % Automatically genrates a python file containing the sensor call back
    % bindings
    fprintf(file, 'import numpy as np\n');
    fprintf(file, 'import cv2\n');
    fprintf(file, '\n');
    fprintf(file, 'def bindSensor(sensor):\n');
    fprintf(file, '    sensor.listen(lambda _image: do_something(_image))\n');
    fprintf(file, '\n');
    fprintf(file, 'def do_something(_image):\n');
    fprintf(file, '    global %s\n', varName);
    fprintf(file, '    data = np.frombuffer(_image.raw_data, dtype=np.dtype("uint8"))\n');
    fprintf(file, '\n');
    fprintf(file, '    # Convert to depth in meters\n');
    fprintf(file, '    data = np.reshape(data, (_image.height, _image.width, 4))\n');
    fprintf(file, '    B = data[:, :, 0].astype("float64")\n');
    fprintf(file, '    G = data[:, :, 1].astype("float64")\n');
    fprintf(file, '    R = data[:, :, 2].astype("float64")\n');
    fprintf(file, '\n');
    fprintf(file, '    data = 1000 * (R + G * 256 + B * 256 * 256) / (256 * 256 * 256 - 1)\n');
    fprintf(file, '\n');

    fprintf(file, '    # Convert the data into MATLAB cast compatible type\n');
    fprintf(file, '    %s = np.ascontiguousarray(data)\n', varName);

    fclose(file);

end


%% (Internal) Create new QRS detections based on other lead/algorithms detections
%
%   artificial_annotations = combine_anns(time_serie, estimated_labs, header)
%
% Arguments:
%
%      + time_serie: all the QRS detections
%
%      + estimated_labs: estimated labels (TP, FP, FN) of each detection
%
%      + header: ECG header struct.
%
% Output:
%
%      + artificial_annotations: all the QRS detections plus the new ones
%      created.
%
% Example:
%
%         aux_idx = best_detections_idx(1:min(10, length(best_detections_idx)));
%         artificial_annotations = combine_anns(all_annotations(aux_idx), estimated_labs(aux_idx), ECG_struct.header);
%
% See also QRScorrector
%
% Author: Mariano Llamedo Soria llamedom@electron.frba.utn.edu.ar
% Version: 0.1 beta
% Last update: 14/5/2014
% Birthdate  : 21/4/2015
% Copyright 2008-2015
%
function artificial_annotations = combine_anns(time_serie, estimated_labs, header)

    % cantidad de leads artificiales que generar�
    min_artificial_leads = 3;
    win_size = 20; % seconds
    win_size = round(win_size*header.freq); % milliseconds

%     lreferences = length(time_serie);
    for ii = 1:min_artificial_leads
        artificial_annotations(ii).time = [];
    end

    start_sample = min(cell2mat(cellfun(@(a)(min(a)),time_serie, 'UniformOutput', false)));
    end_sample = max(cell2mat(cellfun(@(a)(max(a)),time_serie, 'UniformOutput', false))) + 1;

%     aux_seq = (start_sample+win_size):round(win_size/2):end_sample;
    aux_seq = min(start_sample+win_size, end_sample):win_size:end_sample;

    if( isempty(aux_seq) )
        str_aux = disp_string_framed(0, 'Recording too short for combining detections'  );
        fprintf(2, '\n%s\n', str_aux);
        return
    end

    if(aux_seq(end) ~= end_sample )
        aux_seq = [aux_seq (aux_seq(end)+win_size) ];
    end

    laux_seq = length(aux_seq);

    aux_idx = arrayfun(@(a)( ...
                                cellfun( @(b)( ...
                                                findStartEnd(  b >= (a - win_size) & b < a ) ...
                                            ), time_serie, 'UniformOutput', false  )...
                            ), aux_seq, 'UniformOutput', false);

    aux_q = cellfun( @(a)( cell2mat(cellfun( @(b, c)( ...
                                    calc_q_val( b, c ) ...
                                ), estimated_labs, a, 'UniformOutput', false  ))...
                ), aux_idx, 'UniformOutput', false  );

    [~, aux_q_idx] = cellfun( @(a)( sort(a, 'descend') ), aux_q, 'UniformOutput', false );

    % TODO: hacer una estrategia que divida los segmentos de  aux_seq hasta
    % que no haya problemas de transiciones de los segmentos solapados.
%     while()
%         aux_idx = arrayfun( @(ii)( cell2mat(arrayfun( @(jj)( find_disagreements(aux_idx, aux_q_idx, ii, jj ) ), 1:laux_seq , 'UniformOutput', false)) ), 1:3, 'UniformOutput', false );
%     end

    aux_val = arrayfun( @(ii)( cell2mat(cellfun( @(a, q_idx)( build_combined_series(time_serie, a, q_idx, ii ) ), aux_idx, aux_q_idx, 'UniformOutput', false)) ), 1:min_artificial_leads, 'UniformOutput', false );

    cant_artificial_leads = min(min_artificial_leads, sum(cellfun(@(a)(~isempty(a)), aux_val )) );

    if( cant_artificial_leads > 0 )

        for ii = 1:cant_artificial_leads
            % avoid annotations very close each other.
            aux_time_serie = aux_val{ii};
            aux_time_serie(find( diff(sort(aux_time_serie)) <= round(0.15 * header.freq) ) +1) = [];
            if( ~isempty(aux_time_serie) )
                artificial_annotations(ii).time = colvec(aux_time_serie);
            end
        end

        if( cant_artificial_leads < min_artificial_leads )
            for ii = cant_artificial_leads+1:min_artificial_leads
                artificial_annotations(ii).time = artificial_annotations(cant_artificial_leads).time;
            end
        end

    end

function start_end_aux = findStartEnd( bAux )

    start_aux = find(  bAux, 1, 'first' );
    end_aux = find(  bAux, 1, 'last' );
    start_end_aux = [start_aux end_aux];

function this_q = calc_q_val(this_labs, strt_end)
%         win_size in milliseconds

    if( isempty(strt_end) || isempty(this_labs) )
        this_q = [];
    else
        this_labs = this_labs(strt_end(1):strt_end(2));

        this_se = sum(this_labs == 3) / sum(this_labs == 3 | this_labs == 1) ;
        this_pp = sum(this_labs == 3) / sum(this_labs == 3 | this_labs == 2) ;

        % paper metric
        %this_q = (2*this_se + this_pp)/3;
        % F1 score
        this_q = 2/(1/this_se + 1/this_pp);
    end

function new_str_end = find_disagreements(str_end, q_idx, ii, jj)

    this_q_idx = q_idx{jj};
    next_q_idx = q_idx{jj+1};

    if( isempty(this_q_idx) || ii > length(q_idx) )
        new_str_end = [];
    else
        if( q_idx(ii) == q_idx(ii+1) )
            new_str_end = [];
        else

        end
    end

function combined_series = build_combined_series(ts, str_end, q_idx, ii)

    if( isempty(q_idx) || ii > length(q_idx) )
        combined_series = [];
    else
        q_idx = q_idx(ii);
        aux_idx = str_end{q_idx};
        aux_val = ts{q_idx};
        if( isempty(aux_idx) || isempty(aux_val)  )
            combined_series = [];
        else
            combined_series = rowvec(aux_val(aux_idx(1):aux_idx(2)));
        end
    end


function [eid,emsg,varargout]=getargs(pnames,dflts,varargin)
%GETARGS Process parameter name/value pairs
%   [EID,EMSG,A,B,...]=GETARGS(PNAMES,DFLTS,'NAME1',VAL1,'NAME2',VAL2,...)
%   accepts a cell array PNAMES of valid parameter names, a cell array
%   DFLTS of default values for the parameters named in PNAMES, and
%   additional parameter name/value pairs.  Returns parameter values A,B,...
%   in the same order as the names in PNAMES.  Outputs corresponding to
%   entries in PNAMES that are not specified in the name/value pairs are
%   set to the corresponding value from DFLTS.  If nargout is equal to
%   length(PNAMES)+1, then unrecognized name/value pairs are an error.  If
%   nargout is equal to length(PNAMES)+2, then all unrecognized name/value
%   pairs are returned in a single cell array following any other outputs.
%
%   EID and EMSG are empty if the arguments are valid.  If an error occurs,
%   EMSG is the text of an error message and EID is the final component
%   of an error message id.  GETARGS does not actually throw any errors,
%   but rather returns EID and EMSG so that the caller may throw the error.
%   Outputs will be partially processed after an error occurs.
%
%   This utility can be used for processing name/value pair arguments.
%
%   Example:
%       pnames = {'color' 'linestyle', 'linewidth'}
%       dflts  = {    'r'         '_'          '1'}
%       varargin = {{'linew' 2 'nonesuch' [1 2 3] 'linestyle' ':'}
%       [eid,emsg,c,ls,lw] = statgetargs(pnames,dflts,varargin{:})    % error
%       [eid,emsg,c,ls,lw,ur] = statgetargs(pnames,dflts,varargin{:}) % ok

% We always create (nparams+2) outputs:
%    one each for emsg and eid
%    nparams varargs for values corresponding to names in pnames
% If they ask for one more (nargout == nparams+3), it's for unrecognized
% names/values

%   Original Copyright 1993-2008 The MathWorks, Inc.
%   Modified by Deng Cai (dengcai@gmail.com) 2011.11.27

% Initialize some variables
emsg = '';
eid = '';
nparams = length(pnames);
varargout = dflts;
unrecog = {};
nargs = length(varargin);

% Must have name/value pairs
if mod(nargs,2)~=0
    eid = 'WrongNumberArgs';
    emsg = 'Wrong number of arguments.';
else
    % Process name/value pairs
    for j=1:2:nargs
        pname = varargin{j};
        if ~ischar(pname)
            eid = 'BadParamName';
            emsg = 'Parameter name must be text.';
            break;
        end
        i = strcmpi(pname,pnames);
        i = find(i);
        if isempty(i)
            % if they've asked to get back unrecognized names/values, add this
            % one to the list
            if nargout > nparams+2
                unrecog((end+1):(end+2)) = {varargin{j} varargin{j+1}};
                % otherwise, it's an error
            else
                eid = 'BadParamName';
                emsg = sprintf('Invalid parameter name:  %s.',pname);
                break;
            end
        elseif length(i)>1
            eid = 'BadParamName';
            emsg = sprintf('Ambiguous parameter name:  %s.',pname);
            break;
        else
            varargout{i} = varargin{j+1};
        end
    end
end

varargout{nparams+1} = unrecog;


function metID = findMetIDs(model, metList)
% Finds metabolite numbers in a model
%
% USAGE:
%
%    metID = findMetIds(model, metList)
%
% INPUTS:
%    model:      COBRA model structure
%    metList:    List of metabolites
%
% OUTPUT:
%    metID:      List of metabolite IDs corresponding to `metList`
%
% .. Author: - Jan Schellenberger 8/15/08

if (iscell(metList))
    [tmp,metID] = ismember(metList,model.mets);
else
    metID = find(strcmp(model.mets,metList));
    if (isempty(metID))
        metID = 0;
    end
    if (length(metID) > 1)
        metID = metID(1);
    end
end


%%% [3dmatrix] = convert_video_to_3d(struct)
%
function [V] = convert_video_to_3d(video)
  for i = 1:video.nrFramesTotal
    frame = video.frames(i).cdata;
    if(size(frame,3) == 3)
      frame = rgb2gray(frame);
    end
    V(:,:,i) = frame;
  end
end


function varargout=rotqr2qc(varargin)
%
% For calling details please see v_rotqr2qc.m
%
% This dummy routine is included for backward compatibility only
% and will be removed in a future release of voicebox. Please use
% v_rotqr2qc.m in future and/or update with v_voicebox_update.m
%
%      Copyright (C) Mike Brookes 2018
%      Version: $Id: rotqr2qc.m 10863 2018-09-21 15:39:23Z dmb $
%
if nargout
    varargout=cell(1,nargout);
    [varargout{:}]=v_rotqr2qc(varargin{:});
else
    v_rotqr2qc(varargin{:});
end


function [name mfcc] = readKaldiFeature(fileName)

endian = 'l';

% FID = fopen('D:\Data\MagorBN\MFCC_LDA_MLLT_MVN\Ark\cml_mfcc_train.10.ark', 'r');
FID = fopen(fileName, 'r');
name = {};
mfcc = {};
byte_cnt = 1;
while 1
    [tmp,byte_cnt] = readUttName(FID, byte_cnt);
    if length(tmp)==0
        break;
    end
    name{end+1} = tmp;
    % fprintf('name{%d} = %s\n', length(name), name{end});
    header = readHeader(FID, byte_cnt, endian);
    data = fread(FID, header.nframe * header.dim, 'float32', 0, endian)';
    mfcc{end+1} = reshape(data, header.dim, header.nframe);
    if 0
        imagesc(mfcc{end});
        title(regexprep(name{end}, '_', '\\_'));
        colorbar;
        pause
    end
end
fclose(FID);

%%
function [header,byte_cnt] = readHeader(FID,byte_cnt, endian)
header.format = [];
byte_cnt = skipGap(FID, byte_cnt);
while 1
    tmp = fread(FID, 1, 'char');
    byte_cnt = byte_cnt + 1;
    if tmp==' '
        break;
    else
        header.format(end+1) = tmp;
    end
end
header.format = char(header.format);
byte_cnt = skipGap(FID,byte_cnt);
header.nframe = fread(FID, 1, 'int32', 0, endian); byte_cnt = byte_cnt + 4;
byte_cnt = skipGap(FID,byte_cnt);
header.dim = fread(FID, 1, 'int32', 0, endian); byte_cnt = byte_cnt + 4;

function byte_cnt = skipGap(FID, byte_cnt)
while 1
    tmp = fread(FID, 1, 'int8');
    byte_cnt = byte_cnt + 1;
    if tmp==0 || tmp==4
        break;
    end
end

function [uttName,byte_cnt] = readUttName(FID,byte_cnt)
uttName = [];
while 1
    tmp = fread(FID, 1, 'char');
    if length(tmp) == 0 % read end of the file
        break;
    elseif tmp==' '
        break;
    else
        uttName(end+1) = tmp;
    end
    byte_cnt = byte_cnt + 1;
end
uttName = char(uttName);


function mapVals = grayAmplitudeVals(V, ampType, varargin);
% Return event-related amplitudes for a gray view
%
%  mapVals = grayAmplitudeVals(V, ampType, [options]);
%
% ras, 09/30/2009
if notDefined('V'),				V = getSelectedGray;		end
if notDefined('ampType'),       ampType = 'z-score';		end

%% checks
% check that a GLM has been run
if ~isequal(viewGet(V, 'DTName'), 'GLMs')
	error('Need to be in the GLMs data type.')
end

% get scan num, # of non-null conditions
scan = viewGet(V, 'CurScan');
stim = er_concatParfiles(V);
N = length(stim.condNames) - 1;  % omit baseline condition

%% params
% default params
preserveCoords = 0;
saveAmps = 0;

% parse options (these will override the dialog values)
for ii = 1:2:length(varargin)
	val = varargin{ii+1};
	eval( sprintf('%s = val;', varargin{ii}) );
end

%% if the beta maps haven't been xformed from inplanes, do it now
testFile = fullfile( dataDir(V), sprintf('betas-predictor%i.mat', N) );
if ~exist(testFile, 'file')
	hI = initHiddenInplane('GLMs', 1);

	for i = 1:N     % loop across conditions
		mapPath = fullfile(dataDir(hI), 'RawMaps', ...
			sprintf('betas_predictor%i.mat', i));
		hI = loadParameterMap(hI, mapPath);
		V = ip2volParMap(hI, V, 0, 1, 'linear'); % trilinear interpolation

		mapPath = fullfile(dataDir(hI), 'RawMaps', ...
			sprintf('stdDev_predictor%i.mat', i));
		hI = loadParameterMap(hI, mapPath);
		V = ip2volParMap(hI, V, 0, 1, 'linear');
	end

	hI = loadParameterMap(hI, 'Residual Variance.mat');
	V = ip2volParMap(hI, V, 0, 1, 'linear');
end

if notDefined('whichConds'),
	whichConds=1:1:N;
else
	N=length(whichConds);
end

%% get the amplitude estimate for each voxel
switch lower(ampType)
	case 'subtracted-betas'
		for i = 1:N
			n=whichConds(i);
			mapName = sprintf('betas-predictor%i', n);
			V = loadParameterMap(V, mapName);
			mapVals(i,:) = V.map{scan};
		end

		% remove the "cocktail blank" or mean of all conditions for each voxel
		mapVals = mapVals - repmat( nanmean(mapVals), [N 1] );

	case {'raw-betas' 'rawbetas' 'raw betas' 'betas'}
		for i = 1:N
			n=whichConds(i);
			mapName = sprintf('betas-predictor%i', n);
			V = loadParameterMap(V, mapName);

			mapVals(i,:) = V.map{scan};
		end

	case {'z-score' 'z score' 'zscore'}
		% load the betas
		for i = 1:N
			n=whichConds(i);
			mapName = sprintf('betas-predictor%i', n);
			V = loadParameterMap(V, mapName);
			mapVals(i,:) = V.map{scan};
		end

		% load the residual variance map
		V = loadParameterMap(V, 'Residual Variance');
		sigmaVals = V.map{scan};

		% convert from res. var -> std. dev
		% (we need some info from the GLM model: degrees of freedom)
		modelFile = sprintf('Inplane/GLMs/Scan%i/glmSlice1.mat', scan);
		load(modelFile, 'dof');
		sigmaVals = sqrt( sigmaVals .^ 2 ./ dof );

		% remove the "cocktail blank" or DC component for each voxel
		mapVals = mapVals - repmat( nanmean(mapVals), [N 1] );

		% now, normalize by dividing by the estimated residual variance at
		% each voxel
		mapVals = mapVals ./ repmat( sigmaVals, [N 1] );

	otherwise
		error('Invalid amplitude type.')
end

%% return only values in the ROI? (Maybe we don't want to do this)
if isempty(V.ROIs)
    I = 1:size(mapVals, 2);
else
    I = roiIndices(V, V.ROIs(end).coords, preserveCoords);
end
mapVals = mapVals(:,I);

return


function plot_3d_hdc_sheet_gtvo(visualDataFile, expMapHistoryFile, odoMapHistoryFile, groundTruthFile,vtHistoryFile, emHistoryFile, varargin)
%     NeuroSLAM System Copyright (C) 2018-2019
%     NeuroSLAM: A Brain inspired SLAM System for 3D Environments
%
%     Fangwen Yu (www.yufangwen.com), Jianga Shang, Youjian Hu, Michael Milford(www.michaelmilford.com)
%
%     The NeuroSLAM V1.0 (MATLAB) was developed based on the OpenRatSLAM (David et al. 2013).
%     The RatSLAM V0.3 (MATLAB) developed by David Ball, Michael Milford and Gordon Wyeth in 2008.
%
%     Reference:
%     Ball, David, Scott Heath, Janet Wiles, Gordon Wyeth, Peter Corke, and Michael Milford.
%     "OpenRatSLAM: an open source brain-based SLAM system." Autonomous Robots 34, no. 3 (2013): 149-176.
%
%     This program is free software: you can redistribute it and/or modify
%     it under the terms of the GNU General Public License as published by
%     the Free Software Foundation, either version 3 of the License, or
%     (at your option) any later version.
%
%     This program is distributed in the hope that it will be useful,
%     but WITHOUT ANY WARRANTY; without even the implied warranty of
%     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
%     GNU General Public License for more details.
%
%     You should have received a copy of the GNU General Public License
%     along with this program.  If not, see <http://www.gnu.org/licenses/>.

    %% Initial some variables
    % Transform the angle from degree to radian
    global DEGREE_TO_RADIAN;
    DEGREE_TO_RADIAN = pi / 180;

    % Transform the angle from radian to degree
    global RADIAN_TO_DEGREE;
    RADIAN_TO_DEGREE = 180 / pi;

    % define the size of block in reading video
    global BLOCK_READ;

    % define the render rate for dyawing vo
    global RENDER_RATE;

    global GT_ODO_X_SCALING;
    global GT_ODO_Y_SCALING;
    global GT_ODO_Z_SCALING;
    global GT_EXP_X_SCALING;
    global GT_EXP_Y_SCALING;
    global GT_EXP_Z_SCALING;

    global ODO_MAP_X_SCALING;
    global ODO_MAP_Y_SCALING;
    global ODO_MAP_Z_SCALING;
    global EXP_MAP_X_SCALING;
    global EXP_MAP_Y_SCALING;
    global EXP_MAP_Z_SCALING;

    % Process the parameters
    for i=1:(nargin - 6)
        if ischar(varargin{i})
            switch varargin{i}
                case 'BLOCK_READ', BLOCK_READ = varargin{i+1};
                case 'RENDER_RATE', RENDER_RATE = varargin{i+1};
                case 'GT_ODO_X_SCALING', GT_ODO_X_SCALING = varargin{i+1};
                case 'GT_ODO_Y_SCALING', GT_ODO_Y_SCALING = varargin{i+1};
                case 'GT_ODO_Z_SCALING', GT_ODO_Z_SCALING = varargin{i+1};
                case 'GT_EXP_X_SCALING', GT_EXP_X_SCALING = varargin{i+1};
                case 'GT_EXP_Y_SCALING', GT_EXP_Y_SCALING = varargin{i+1};
                case 'GT_EXP_Z_SCALING', GT_EXP_Z_SCALING = varargin{i+1};
                case 'ODO_MAP_X_SCALING', ODO_MAP_X_SCALING = varargin{i+1};
                case 'ODO_MAP_Y_SCALING', ODO_MAP_Y_SCALING = varargin{i+1};
                case 'ODO_MAP_Z_SCALING', ODO_MAP_Z_SCALING = varargin{i+1};
                case 'EXP_MAP_X_SCALING', EXP_MAP_X_SCALING = varargin{i+1};
                case 'EXP_MAP_Y_SCALING', EXP_MAP_Y_SCALING = varargin{i+1};
                case 'EXP_MAP_Z_SCALING', EXP_MAP_Z_SCALING = varargin{i+1};
            end
        end
    end

    %% vt
    global PREV_VT_ID;
    global SUB_VT_IMG;
    global VT_HISTORY;
    global IMG_TYPE;

    %% vo
    % for drawing images for estimating pitch and yaw
    global SUB_HORI_TRANS_IMG;
    global SUB_ROT_IMG;
    global SUB_VERT_TRANS_IMG;
    global SUB_PITCH_IMG;

    % for limit the velocity of gtvo
    global MAX_HORI_TRANS_V_THRESHOLD;
    global MAX_ROT_V_THRESHOLD;
    global MAX_VERT_TRANS_V_THRESHOLD;
    global MAX_PITCH_V_THRESHOLD;

    %% yaw_pitch_hdc
    global YAW_PITCH_HDC;

    % The dimension of yaw in yaw_pitch_hdc network
    global YAW_PITCH_HDC_Y_DIM;

    % The dimension of pitch in yaw_pitch_hdc network
    global YAW_PITCH_HDC_P_DIM;

    % The yaw theta size of each unit in radian, 2*pi/ YAW_PITCH_HDC_Y_DIM
    % radian e.g. 2*pi/360 = 0.0175
    global YAW_PITCH_HDC_Y_TH_SIZE;
    global YAW_PITCH_HDC_P_TH_SIZE;
    global MAX_ACTIVE_YAW_PITCH_HIS_PATH;

    %% 3D gridcells
    global GRIDCELLS;

    global GC_X_DIM;
    global GC_Y_DIM;
    global GC_Z_DIM;

    % set the initial position in the grid cell network
    [gcX, gcY, gcZ] = get_gc_initial_pos();

    global MAX_ACTIVE_XYZ_PATH;

    %% 3D EM
    global EXPERIENCES;

    % Experience history
    global EXP_HISTORY;

    % The namber of total experiences
    global NUM_EXPS;

    %% read imgs as VT input

    % get the visual data info
    [subFoldersPathSet, numSubFolders] = get_images_data_info(visualDataFile);

    % initial some variables for drawing pitch and yaw
    odoPitchTheta = [0 0 0];
    Theta = [0 0 0 0 0 0];
    Rho = [0 0 0 0 0 0];
    startpoint =[0 0];
    endpoint = [0.8 0.8];

    odoYawTheta = [0 0 0];

    hdcPitchTheta = [0 0 0];

    hdcYawTheta = [0 0 0];

    hdcPitchTheta(1,3)= 0;
    hdcYawTheta(1,3)= 0;

    zAxisHDC = 1:2:36;

    % for drawing the activity packet of HDC
    zThirdDim = 36;
    tempYawPitchHDC = zeros(YAW_PITCH_HDC_Y_DIM, YAW_PITCH_HDC_P_DIM, zThirdDim);

    % for drawing the activity packet in toriodal ring
    R = 12;
    r = 6;
    xTorus = nan(36,36);
    yTorus = nan(36,36);
    zTorus = nan(36,36);
    for j = 1 : 36
        for i = 1 : 36
            phi = (i - 1) * 2 * pi / 35;
            theta = (j - 1) * 2 * pi / 35;
            xTorus(i,j)= cos(phi) * (R + cos(theta) * r);
            yTorus(i,j)= sin(phi) * (R + cos(theta) * r);
            zTorus(i,j)= sin(theta) * r;
        end
    end

    %% for drawing contour3 in 3D ring
    % define color map based on activity in 3D ring
%     coMap = zeros(YAW_PITCH_HDC_Y_DIM * YAW_PITCH_HDC_P_DIM, 3);

    %% processing two ring model for hd integration
    % x,y,z, yaw, pitch
    expTrajectory(1,1) = 0;
    expTrajectory(1,2) = 0;
    expTrajectory(1,3) = 0;
    expTrajectory(1,4) = 0;
    expTrajectory(1,5) = 0;

    odoMapTrajectory(1,1) = 0;
    odoMapTrajectory(1,2) = 0;
    odoMapTrajectory(1,3) = 0;
    odoMapTrajectory(1,4) = 0;
    odoMapTrajectory(1,5) = 0;

    transOdoTraj(1,1) = 0;
    transOdoTraj(1,2) = 0;
    transOdoTraj(1,3) = 0;

    % load ground truth data
    [frameId, gt_x, gt_y, gt_z, gt_rx, gt_ry, gt_rz] = load_ground_truth_data(groundTruthFile);
%     groundTruthData = [gt_x gt_y gt_z];

    horiTransVHis = [];

    preHoriTransV = 0;
    preVertTransV = 0;
    preYawRotV = 0;
    prePitchRotV = 0;

    % for all frames do
    replace = 0;

    % end libviso2

    %% process
    for iSubFolder = 1 : numSubFolders

        [curFolderPath, imgFilesPathList, numImgs] = get_cur_img_files_path_list(subFoldersPathSet, IMG_TYPE, iSubFolder);

        if numImgs > 0
            for curFrame = 1 : numImgs

                [curImg] = read_current_image(curFolderPath, imgFilesPathList, curFrame);

                % visual templates and visual odo uses intensity so convert to grayscale
                curGrayImg = rgb2gray(curImg);
                curGrayImg = im2double(curGrayImg);

                if curFrame > 1

                    tempHoriTransV = sqrt((gt_x(curFrame) - gt_x(curFrame - 1))^2 + ...
                        (gt_y(curFrame) - gt_y(curFrame - 1))^2 );
                    if abs(tempHoriTransV) < MAX_HORI_TRANS_V_THRESHOLD
                        horiTransV = tempHoriTransV;
                        preHoriTransV = horiTransV;
                    else
                        horiTransV = preHoriTransV;
                    end

                    tempYawRotV = get_signed_delta_radian(gt_rz(curFrame), gt_rz(curFrame - 1));

                    if abs(tempYawRotV) < MAX_ROT_V_THRESHOLD
                        yawRotV = tempYawRotV;
                        preYawRotV = yawRotV;
                    else
                        yawRotV = preYawRotV;
                    end

                    tempPitchRotV = get_signed_delta_radian(gt_rx(curFrame),gt_rx(curFrame - 1));

                    if abs(tempPitchRotV) < MAX_PITCH_V_THRESHOLD
                        pitchRotV = tempPitchRotV;
                        prePitchRotV = pitchRotV;
                    else
                        pitchRotV = prePitchRotV;
                    end

                    odoPitchTheta(curFrame, 3) = odoPitchTheta(curFrame - 1, 3) + pitchRotV;
                    odoYawTheta(curFrame, 3) = odoYawTheta(curFrame -1, 3) + yawRotV;

                    tempVertTransV = sqrt((gt_x(curFrame) - gt_x(curFrame - 1))^2 + ...
                        (gt_y(curFrame) - gt_y(curFrame - 1))^2 + ...
                        (gt_z(curFrame) - gt_z(curFrame - 1))^2) * sin(odoPitchTheta(curFrame, 3));

                    if abs(tempVertTransV) < MAX_VERT_TRANS_V_THRESHOLD
                        vertTransV = tempVertTransV;
                        preVertTransV = vertTransV;
                    else
                        vertTransV = preVertTransV;
                    end

                else
                    horiTransV = 0;
                    pitchRotV = 0;
                    vertTransV = 0;
                    yawRotV = 0;

                    odoPitchTheta(curFrame, 3) = pitchRotV;
                    odoYawTheta(curFrame, 3) = yawRotV;

                end

                %% step3: processing vt
                % get the most active view template
                [vt_id] = visual_template(curGrayImg, gcX, gcY,gcZ, yawRotV, pitchRotV);

                %% step4: processing the integration of yaw_pitch_hdc
                yaw_pitch_hdc_iteration(vt_id, yawRotV, pitchRotV);

                [curYawTheta, curPitchTheta] = get_current_yaw_pitch_theta();

                % transform to radian
                curYawThetaInRadian = curYawTheta * YAW_PITCH_HDC_Y_TH_SIZE;
                curPitchThetaInRadian = curPitchTheta * YAW_PITCH_HDC_P_TH_SIZE;

                MAX_ACTIVE_YAW_PITCH_HIS_PATH = [MAX_ACTIVE_YAW_PITCH_HIS_PATH; curYawTheta curPitchTheta];

                % 3d grid cells interation
                gc_iteration(vt_id, horiTransV, curYawThetaInRadian, vertTransV, curPitchThetaInRadian);

                [gcX, gcY, gcZ] = get_gc_xyz();

                MAX_ACTIVE_XYZ_PATH = [MAX_ACTIVE_XYZ_PATH; gcX gcY gcZ];

                % 3d experience map interation
                exp_map_iteration(vt_id, horiTransV, yawRotV, vertTransV, pitchRotV, gcX, gcY, gcZ, curYawTheta, curPitchTheta);

                % for drawing HDC pitch theta
                hdcPitchTheta(curFrame, 1) = cos(curPitchTheta * YAW_PITCH_HDC_P_TH_SIZE);
                hdcPitchTheta(curFrame, 2) = sin(curPitchTheta * YAW_PITCH_HDC_P_TH_SIZE);
                hdcPitchTheta(curFrame, 3) = curPitchTheta * YAW_PITCH_HDC_P_TH_SIZE;

                if curFrame > 1
                    % for drawing odometry pitch theta
                    odoPitchTheta(curFrame, 1) = cos(odoPitchTheta(curFrame, 3));
                    odoPitchTheta(curFrame + 1, 2) = sin(odoPitchTheta(curFrame, 3));
    %                 odoPitchTheta(curFrame + 1, 3) = odoPitchTheta(curFrame, 3);

                    % for drawing HDC yaw theta
                    hdcYawTheta(curFrame, 1) = cos(curYawTheta * YAW_PITCH_HDC_Y_TH_SIZE);
                    hdcYawTheta(curFrame, 2) = sin(curYawTheta * YAW_PITCH_HDC_Y_TH_SIZE);
                    hdcYawTheta(curFrame, 3) = curYawTheta * YAW_PITCH_HDC_Y_TH_SIZE;

                    % for drawing odometry yaw theta
                    odoYawTheta(curFrame, 1) = cos(odoYawTheta(curFrame, 3));
                    odoYawTheta(curFrame, 2) = sin(odoYawTheta(curFrame, 3));
    %                 odoYawTheta(curFrame + 1, 3) = odoYawTheta(curFrame, 3) + yawRotV;

                    odoMapTrajectory(curFrame,1) = odoMapTrajectory(curFrame - 1, 1) + horiTransV * cos(odoYawTheta(curFrame, 3));
                    odoMapTrajectory(curFrame,2) = odoMapTrajectory(curFrame - 1, 2) + horiTransV * sin(odoYawTheta(curFrame, 3));
                    odoMapTrajectory(curFrame,3) = odoMapTrajectory(curFrame - 1, 3) + vertTransV;
                    odoMapTrajectory(curFrame,4) = odoYawTheta(curFrame, 3);
                    odoMapTrajectory(curFrame,5) = odoPitchTheta(curFrame, 3);
    %                 transOdoTraj(curFrame + 1,1) = odoMapTrajectory(curFrame + 1,1);
    %                 transOdoTraj(curFrame + 1,2) = odoMapTrajectory(curFrame + 1,2);
    %                 transOdoTraj(curFrame + 1,3) = odoMapTrajectory(curFrame + 1,3);

                end

                for ind = 1 : YAW_PITCH_HDC_Y_DIM
                    tempYawPitchHDC(:,:,ind) = YAW_PITCH_HDC;
                end

                for ind = 1 : NUM_EXPS
                    expTrajectory(ind,1) = EXPERIENCES(ind).x_exp;
                    expTrajectory(ind,2) = EXPERIENCES(ind).y_exp;
                    expTrajectory(ind,3) = EXPERIENCES(ind).z_exp;
                    expTrajectory(ind,4) = EXPERIENCES(ind).yaw_exp_rad;
                    expTrajectory(ind,5) = EXPERIENCES(ind).pitch_exp_rad;
%                     transExpTraj(ind,1) =   expTrajectory(ind,1);
%                     transExpTraj(ind,2) =   expTrajectory(ind,2);
%                     transExpTraj(ind,3) =   expTrajectory(ind,3);
                end

                % draw the results
                if (mod(curFrame, RENDER_RATE) == 1)

%
                    % drawing the activity of yaw_pitch_hdc
                    figure('color',[1 1 1]);
                    subplot(1, 1, 1,'replace');
                    [x,y]= meshgrid(1:1:36);
                    z = YAW_PITCH_HDC ;
                    surf(x,y,z,'EdgeColor','b');
                    % surf(x,y,z,'FaceColor','red','EdgeColor','none');
%                     shading interp
                    axis([1 YAW_PITCH_HDC_Y_DIM 1 YAW_PITCH_HDC_P_DIM 0 0.02]);
                    % meshc(x,y,z);
                    view(0, 90);
                    xl = xlabel('Pitch');
                    yl = ylabel('Yaw');
                    zlabel('Acitivity');
%                     set(xl,'Rotation',15);
%                     set(yl,'Rotation',-30);
%                     title('Yaw Pitch HDCell Activity');
                    axis on
%

                    drawnow;

                end

                PREV_VT_ID = vt_id;
            end

            % save history data (x, y, z, yaw, pitch)
%             save_history_data(expMapHistoryFile, expTrajectory);
%             save_history_data(odoMapHistoryFile, odoMapTrajectory);
%             save_em_history_data(emHistoryFile, VT_HISTORY);
%             save_vt_history_data(vtHistoryFile, EXP_HISTORY);
        end
    end
end