function fmri_design = spm_cfg_fmri_design
% SPM Configuration file for fMRI model specification (design only)
%_______________________________________________________________________
% Copyright (C) 2005-2016 Wellcome Trust Centre for Neuroimaging

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

% ---------------------------------------------------------------------
% dir Directory
% ---------------------------------------------------------------------
dir         = cfg_files;
dir.tag     = 'dir';
dir.name    = 'Directory';
dir.help    = {'Select a directory where the SPM.mat file containing the specified design matrix will be written.'};
dir.filter = 'dir';
dir.ufilter = '.*';
dir.num     = [1 1];
% ---------------------------------------------------------------------
% units Units for design
% ---------------------------------------------------------------------
units         = cfg_menu;
units.tag     = 'units';
units.name    = 'Units for design';
units.help    = {'The onsets of events or blocks can be specified in either scans or seconds.'};
units.labels = {
                'Scans'
                'Seconds'
}';
units.values = {
                'scans'
                'secs'
}';
% ---------------------------------------------------------------------
% RT Interscan interval
% ---------------------------------------------------------------------
RT         = cfg_entry;
RT.tag     = 'RT';
RT.name    = 'Interscan interval';
RT.help    = {'Interscan interval, TR, (specified in seconds).  This is the time between acquiring a plane of one volume and the same plane in the next volume.  It is assumed to be constant throughout.'};
RT.strtype = 'r';
RT.num     = [1 1];
% ---------------------------------------------------------------------
% fmri_t Microtime resolution
% ---------------------------------------------------------------------
fmri_t         = cfg_entry;
fmri_t.tag     = 'fmri_t';
fmri_t.name    = 'Microtime resolution';
fmri_t.help    = {
                  'The microtime resolution, t, is the number of time-bins per scan used when building regressors. '
                  'If you have performed slice-timing correction, change this parameter to match the number of slices specified there; otherwise, you would typically not need to change this.'
                  ''
}';
fmri_t.strtype = 'n';
fmri_t.num     = [1 1];
fmri_t.def     = @(val)spm_get_defaults('stats.fmri.t', val{:});
% ---------------------------------------------------------------------
% fmri_t0 Microtime onset
% ---------------------------------------------------------------------
fmri_t0         = cfg_entry;
fmri_t0.tag     = 'fmri_t0';
fmri_t0.name    = 'Microtime onset';
fmri_t0.help    = {
                   'The microtime onset, t0, is the reference time-bin at which the regressors are resampled to coincide with data acquisition.'
                   'If you have performed slice-timing correction, you must change this parameter to match the reference slice specified there.'
                   'Otherwise, you might still want to change this if you have non-interleaved acquisition and you wish to sample the regressors so that they are appropriate for a slice in a particular part of the brain.'
                   'For example, if t0 = 1, then the regressors will be appropriate for the first slice; if t0=t, then the regressors will be appropriate for the last slice.'
                   'Setting t0 = t/2 is a good compromise if you are interested in slices at the beginning and end of the acquisition, or if you have interleaved data, or if you have 3D EPI data.'
                   ''
}';
fmri_t0.strtype = 'n';
fmri_t0.num     = [1 1];
fmri_t0.def     = @(val)spm_get_defaults('stats.fmri.t0', val{:});
% ---------------------------------------------------------------------
% timing Timing parameters
% ---------------------------------------------------------------------
timing         = cfg_branch;
timing.tag     = 'timing';
timing.name    = 'Timing parameters';
timing.val     = {units RT fmri_t fmri_t0 };
timing.help    = {
                  'Specify various timing parameters needed to construct the design matrix. This includes the units of the design specification and the interscan interval.'
                  ''
                  'Also, with longs TRs you may want to shift the regressors so that they are aligned to a particular slice.  This is effected by changing the microtime resolution and onset. '
}';
% ---------------------------------------------------------------------
% nscan Number of scans
% ---------------------------------------------------------------------
nscan         = cfg_entry;
nscan.tag     = 'nscan';
nscan.name    = 'Number of scans';
nscan.help    = {'Specify the number of scans for this session.The actual scans must be specified in a separate batch job ''fMRI data specification''.'};
nscan.strtype = 'n';
nscan.num     = [1 1];
% ---------------------------------------------------------------------
% name Name
% ---------------------------------------------------------------------
name         = cfg_entry;
name.tag     = 'name';
name.name    = 'Name';
name.help    = {'Condition Name'};
name.strtype = 's';
name.num     = [1 Inf];
% ---------------------------------------------------------------------
% onset Onsets
% ---------------------------------------------------------------------
onset         = cfg_entry;
onset.tag     = 'onset';
onset.name    = 'Onsets';
onset.help    = {'Specify a vector of onset times for this condition type. '};
onset.strtype = 'r';
onset.num     = [Inf 1];
% ---------------------------------------------------------------------
% duration Durations
% ---------------------------------------------------------------------
duration         = cfg_entry;
duration.tag     = 'duration';
duration.name    = 'Durations';
duration.help    = {'Specify the event durations. Epoch and event-related responses are modeled in exactly the same way but by specifying their different durations.  Events are specified with a duration of 0.  If you enter a single number for the durations it will be assumed that all trials conform to this duration. If you have multiple different durations, then the number must match the number of onset times.'};
duration.strtype = 'r';
duration.num     = [Inf 1];
% ---------------------------------------------------------------------
% tmod Time Modulation
% ---------------------------------------------------------------------
tmod         = cfg_menu;
tmod.tag     = 'tmod';
tmod.name    = 'Time Modulation';
tmod.help    = {
                'This option allows for the characterisation of linear or nonlinear time effects. For example, 1st order modulation would model the stick functions and a linear change of the stick function heights over time. Higher order modulation will introduce further columns that contain the stick functions scaled by time squared, time cubed etc.'
                ''
                'Interactions or response modulations can enter at two levels.  Firstly the stick function itself can be modulated by some parametric variate (this can be time or some trial-specific variate like reaction time) modeling the interaction between the trial and the variate or, secondly interactions among the trials themselves can be modeled using a Volterra series formulation that accommodates interactions over time (and therefore within and between trial types).'
}';
tmod.labels = {
               'No Time Modulation'
               '1st order Time Modulation'
               '2nd order Time Modulation'
               '3rd order Time Modulation'
               '4th order Time Modulation'
               '5th order Time Modulation'
               '6th order Time Modulation'
}';
tmod.values = {0 1 2 3 4 5 6};
tmod.val    = {0};
% ---------------------------------------------------------------------
% name Name
% ---------------------------------------------------------------------
name1         = cfg_entry;
name1.tag     = 'name';
name1.name    = 'Name';
name1.help    = {'Enter a name for this parameter.'};
name1.strtype = 's';
name1.num     = [1 Inf];
% ---------------------------------------------------------------------
% param Values
% ---------------------------------------------------------------------
param         = cfg_entry;
param.tag     = 'param';
param.name    = 'Values';
param.help    = {'Enter a vector of values, one for each occurence of the event.'};
param.strtype = 'r';
param.num     = [Inf 1];
% ---------------------------------------------------------------------
% poly Polynomial Expansion
% ---------------------------------------------------------------------
poly         = cfg_menu;
poly.tag     = 'poly';
poly.name    = 'Polynomial Expansion';
poly.help    = {'For example, 1st order modulation would model the stick functions and a linear change of the stick function heights over different values of the parameter. Higher order modulation will introduce further columns that contain the stick functions scaled by parameter squared, cubed etc.'};
poly.labels = {
               '1st order'
               '2nd order'
               '3rd order'
               '4th order'
               '5th order'
               '6th order'
}';
poly.values = {1 2 3 4 5 6};
% ---------------------------------------------------------------------
% pmod Parameter
% ---------------------------------------------------------------------
pmod         = cfg_branch;
pmod.tag     = 'pmod';
pmod.name    = 'Parameter';
pmod.val     = {name1 param poly };
pmod.help    = {
                'Model interactions with user specified parameters. This allows nonlinear effects relating to some other measure to be modelled in the design matrix.'
                ''
                'Interactions or response modulations can enter at two levels.  Firstly the stick function itself can be modulated by some parametric variate (this can be time or some trial-specific variate like reaction time) modeling the interaction between the trial and the variate or, secondly interactions among the trials themselves can be modeled using a Volterra series formulation that accommodates interactions over time (and therefore within and between trial types).'
}';
% ---------------------------------------------------------------------
% generic Parametric Modulations
% ---------------------------------------------------------------------
generic2         = cfg_repeat;
generic2.tag     = 'generic';
generic2.name    = 'Parametric Modulations';
generic2.help    = {'The stick function itself can be modulated by some parametric variate (this can be time or some trial-specific variate like reaction time) modeling the interaction between the trial and the variate. The events can be modulated by zero or more parameters.'};
generic2.values  = {pmod };
generic2.num     = [0 Inf];
% ---------------------------------------------------------------------
% porth Orthogonalise modulations
% ---------------------------------------------------------------------
porth         = cfg_menu;
porth.tag     = 'orth';
porth.name    = 'Orthogonalise modulations';
porth.help    = {'Orthogonalise regressors within trial types.'};
porth.labels  = {'Yes' 'No'};
porth.values  = {1 0};
porth.val     = {1};
% ---------------------------------------------------------------------
% cond Condition
% ---------------------------------------------------------------------
cond         = cfg_branch;
cond.tag     = 'cond';
cond.name    = 'Condition';
cond.val     = {name onset duration tmod generic2 porth};
cond.check   = @cond_check;
cond.help    = {'An array of input functions is contructed, specifying occurrence events or epochs (or both). These are convolved with a basis set at a later stage to give regressors that enter into the design matrix. Interactions of evoked responses with some parameter (time or a specified variate) enter at this stage as additional columns in the design matrix with each trial multiplied by the [expansion of the] trial-specific parameter. The 0th order expansion is simply the main effect in the first column.'};
% ---------------------------------------------------------------------
% generic Conditions
% ---------------------------------------------------------------------
generic1         = cfg_repeat;
generic1.tag     = 'generic';
generic1.name    = 'Conditions';
generic1.help    = {'You are allowed to combine both event- and epoch-related responses in the same model and/or regressor. Any number of condition (event or epoch) types can be specified.  Epoch and event-related responses are modeled in exactly the same way by specifying their onsets [in terms of onset times] and their durations.  Events are specified with a duration of 0.  If you enter a single number for the durations it will be assumed that all trials conform to this duration.For factorial designs, one can later associate these experimental conditions with the appropriate levels of experimental factors. '};
generic1.values  = {cond };
generic1.num     = [0 Inf];
% ---------------------------------------------------------------------
% multi Multiple conditions
% ---------------------------------------------------------------------
multi         = cfg_files;
multi.tag     = 'multi';
multi.name    = 'Multiple conditions';
multi.val     = {{''}};
multi.help    = {
                 'Select the *.mat file containing details of your multiple experimental conditions. '
                 ''
                 'If you have multiple conditions then entering the details a condition at a time is very inefficient. This option can be used to load all the required information in one go. You will first need to create a *.mat file containing the relevant information. '
                 ''
                 'This *.mat file must include the following cell arrays (each 1 x n): names, onsets and durations. eg. names=cell(1,5), onsets=cell(1,5), durations=cell(1,5), then names{2}=''SSent-DSpeak'', onsets{2}=[3 5 19 222], durations{2}=[0 0 0 0], contain the required details of the second condition. These cell arrays may be made available by your stimulus delivery program, eg. COGENT. The duration vectors can contain a single entry if the durations are identical for all events. Optionally, a (1 x n) cell array named orth can also be included, with a 1 or 0 for each condition to indicate whether parameteric modulators should be orthogonalised.'
                 ''
                 'Time and Parametric effects can also be included. For time modulation include a cell array (1 x n) called tmod. It should have a have a single number in each cell. Unused cells may contain either a 0 or be left empty. The number specifies the order of time modulation from 0 = No Time Modulation to 6 = 6th Order Time Modulation. eg. tmod{3} = 1, modulates the 3rd condition by a linear time effect.'
                 ''
                 'For parametric modulation include a structure array, which is up to 1 x n in size, called pmod. n must be less than or equal to the number of cells in the names/onsets/durations cell arrays. The structure array pmod must have the fields: name, param and poly.  Each of these fields is in turn a cell array to allow the inclusion of one or more parametric effects per column of the design. The field name must be a cell array containing strings. The field param is a cell array containing a vector of parameters. Remember each parameter must be the same length as its corresponding onsets vector. The field poly is a cell array (for consistency) with each cell containing a single number specifying the order of the polynomial expansion from 1 to 6.'
                 ''
                 'Note that each condition is assigned its corresponding entry in the structure array (condition 1 parametric modulators are in pmod(1), condition 2 parametric modulators are in pmod(2), etc. Within a condition multiple parametric modulators are accessed via each fields cell arrays. So for condition 1, parametric modulator 1 would be defined in  pmod(1).name{1}, pmod(1).param{1}, and pmod(1).poly{1}. A second parametric modulator for condition 1 would be defined as pmod(1).name{2}, pmod(1).param{2} and pmod(1).poly{2}. If there was also a parametric modulator for condition 2, then remember the first modulator for that condition is in cell array 1: pmod(2).name{1}, pmod(2).param{1}, and pmod(2).poly{1}. If some, but not all conditions are parametrically modulated, then the non-modulated indices in the pmod structure can be left blank. For example, if conditions 1 and 3 but not condition 2 are modulated, then specify pmod(1) and pmod(3). Similarly, if conditions 1 and 2 are modulated but there are 3 conditions overall, it is only necessary for pmod to be a 1 x 2 structure array.'
                 ''
                 'EXAMPLE:'
                 'Make an empty pmod structure: '
                 '  pmod = struct(''name'',{''''},''param'',{},''poly'',{});'
                 'Specify one parametric regressor for the first condition: '
                 '  pmod(1).name{1}  = ''regressor1'';'
                 '  pmod(1).param{1} = [1 2 4 5 6];'
                 '  pmod(1).poly{1}  = 1;'
                 'Specify 2 parametric regressors for the second condition: '
                 '  pmod(2).name{1}  = ''regressor2-1'';'
                 '  pmod(2).param{1} = [1 3 5 7]; '
                 '  pmod(2).poly{1}  = 1;'
                 '  pmod(2).name{2}  = ''regressor2-2'';'
                 '  pmod(2).param{2} = [2 4 6 8 10];'
                 '  pmod(2).poly{2}  = 1;'
                 ''
                 'The parametric modulator should be mean corrected if appropriate. Unused structure entries should have all fields left empty.'
}';
multi.filter = 'mat';
multi.ufilter = '.*';
multi.num     = [0 1];
% ---------------------------------------------------------------------
% name Name
% ---------------------------------------------------------------------
name         = cfg_entry;
name.tag     = 'name';
name.name    = 'Name';
name.help    = {'Enter name of regressor eg. First movement parameter'};
name.strtype = 's';
name.num     = [1 Inf];
% ---------------------------------------------------------------------
% val Value
% ---------------------------------------------------------------------
val         = cfg_entry;
val.tag     = 'val';
val.name    = 'Value';
val.help    = {'Enter the vector of regressor values'};
val.strtype = 'r';
val.num     = [Inf 1];
% ---------------------------------------------------------------------
% regress Regressor
% ---------------------------------------------------------------------
regress         = cfg_branch;
regress.tag     = 'regress';
regress.name    = 'Regressor';
regress.val     = {name val };
regress.help    = {'regressor'};
% ---------------------------------------------------------------------
% generic Regressors
% ---------------------------------------------------------------------
generic2         = cfg_repeat;
generic2.tag     = 'generic';
generic2.name    = 'Regressors';
generic2.help    = {'Regressors are additional columns included in the design matrix, which may model effects that would not be convolved with the haemodynamic response.  One such example would be the estimated movement parameters, which may confound the data.'};
generic2.values  = {regress };
generic2.num     = [0 Inf];
% ---------------------------------------------------------------------
% multi_reg Multiple regressors
% ---------------------------------------------------------------------
multi_reg         = cfg_files;
multi_reg.tag     = 'multi_reg';
multi_reg.name    = 'Multiple regressors';
multi_reg.val     = {{''}};
multi_reg.help    = {
                     'Select the *.mat/*.txt file(s) containing details of your multiple regressors. '
                     ''
                     'If you have multiple regressors eg. realignment parameters, then entering the details a regressor at a time is very inefficient. This option can be used to load all the required information in one go. '
                     ''
                     'You will first need to create a *.mat file containing a matrix R or a *.txt file containing the regressors. Each column of R will contain a different regressor. When SPM creates the design matrix the regressors will be named R1, R2, R3, ..etc.'
                     ''
                     'You can also select a PPI.mat file and SPM will automatically create regressors from fields PPI.ppi, PPI.Y and PPI.P.'
                     }';
multi_reg.filter = 'mat';
multi_reg.ufilter = '.*';
multi_reg.num     = [0 Inf];
% ---------------------------------------------------------------------
% hpf High-pass filter
% ---------------------------------------------------------------------
hpf         = cfg_entry;
hpf.tag     = 'hpf';
hpf.name    = 'High-pass filter';
hpf.help    = {'The default high-pass filter cutoff is 128 seconds.Slow signal drifts with a period longer than this will be removed. Use ''explore design'' to ensure this cut-off is not removing too much experimental variance. High-pass filtering is implemented using a residual forming matrix (i.e. it is not a convolution) and is simply to a way to remove confounds without estimating their parameters explicitly.  The constant term is also incorporated into this filter matrix.'};
hpf.strtype = 'r';
hpf.num     = [1 1];
hpf.def     = @(val)spm_get_defaults('stats.fmri.hpf', val{:});
% ---------------------------------------------------------------------
% sess Subject/Session
% ---------------------------------------------------------------------
sess         = cfg_branch;
sess.tag     = 'sess';
sess.name    = 'Subject/Session';
sess.val     = {nscan generic1 multi generic2 multi_reg hpf };
sess.check   = @sess_check;
sess.help    = {'The design matrix for fMRI data consists of one or more separable, session-specific partitions.  These partitions are usually either one per subject, or one per fMRI scanning session for that subject.'};
% ---------------------------------------------------------------------
% generic Data & Design
% ---------------------------------------------------------------------
generic         = cfg_repeat;
generic.tag     = 'generic';
generic.name    = 'Data & Design';
generic.help    = {
                   'The design matrix defines the experimental design and the nature of hypothesis testing to be implemented.  The design matrix has one row for each scan and one column for each effect or explanatory variable. (e.g. regressor or stimulus function).  '
                   ''
                   'This allows you to build design matrices with separable session-specific partitions.  Each partition may be the same (in which case it is only necessary to specify it once) or different.  Responses can be either event- or epoch related, where the latter model involves prolonged and possibly time-varying responses to state-related changes in experimental conditions.  Event-related response are modelled in terms of responses to instantaneous events.  Mathematically they are both modelled by convolving a series of delta (stick) or box-car functions, encoding the input or stimulus function. with a set of hemodynamic basis functions.'
}';
generic.values  = {sess };
generic.num     = [1 Inf];
% ---------------------------------------------------------------------
% name Name
% ---------------------------------------------------------------------
name         = cfg_entry;
name.tag     = 'name';
name.name    = 'Name';
name.help    = {'Name of factor, eg. ''Repetition'' '};
name.strtype = 's';
name.num     = [1 Inf];
% ---------------------------------------------------------------------
% levels Levels
% ---------------------------------------------------------------------
levels         = cfg_entry;
levels.tag     = 'levels';
levels.name    = 'Levels';
levels.help    = {'Enter number of levels for this factor, eg. 2'};
levels.strtype = 'n';
levels.num     = [Inf 1];
% ---------------------------------------------------------------------
% fact Factor
% ---------------------------------------------------------------------
fact         = cfg_branch;
fact.tag     = 'fact';
fact.name    = 'Factor';
fact.val     = {name levels };
fact.help    = {'Add a new factor to your experimental design'};
% ---------------------------------------------------------------------
% generic Factorial design
% ---------------------------------------------------------------------
generic1         = cfg_repeat;
generic1.tag     = 'generic';
generic1.name    = 'Factorial design';
generic1.help    = {
                    'If you have a factorial design then SPM can automatically generate the contrasts necessary to test for the main effects and interactions. '
                    ''
                    'This includes the F-contrasts necessary to test for these effects at the within-subject level (first level) and the simple contrasts necessary to generate the contrast images for a between-subject (second-level) analysis.'
                    ''
                    'To use this option, create as many factors as you need and provide a name and number of levels for each.  SPM assumes that the condition numbers of the first factor change slowest, the second factor next slowest etc. It is best to write down the contingency table for your design to ensure this condition is met. This table relates the levels of each factor to the conditions. '
                    ''
                    'For example, if you have 2-by-3 design  your contingency table has two rows and three columns where the the first factor spans the rows, and the second factor the columns. The numbers of the conditions are 1,2,3 for the first row and 4,5,6 for the second. '
}';
generic1.values  = {fact };
generic1.num     = [0 Inf];
% ---------------------------------------------------------------------
% derivs Model derivatives
% ---------------------------------------------------------------------
derivs         = cfg_menu;
derivs.tag     = 'derivs';
derivs.name    = 'Model derivatives';
derivs.help    = {'Model HRF Derivatives. The canonical HRF combined with time and dispersion derivatives comprise an ''informed'' basis set, as the shape of the canonical response conforms to the hemodynamic response that is commonly observed. The incorporation of the derivate terms allow for variations in subject-to-subject and voxel-to-voxel responses. The time derivative allows the peak response to vary by plus or minus a second and the dispersion derivative allows the width of the response to vary. The informed basis set requires an SPM{F} for inference. T-contrasts over just the canonical are perfectly valid but assume constant delay/dispersion. The informed basis set compares favourably with eg. FIR bases on many data sets. '};
derivs.labels = {
                 'No derivatives'
                 'Time derivatives'
                 'Time and Dispersion derivatives'
}';
derivs.values = {[0 0] [1 0] [1 1]};
derivs.val    = {[0 0]};
% ---------------------------------------------------------------------
% hrf Canonical HRF
% ---------------------------------------------------------------------
hrf         = cfg_branch;
hrf.tag     = 'hrf';
hrf.name    = 'Canonical HRF';
hrf.val     = {derivs };
hrf.help    = {'Canonical Hemodynamic Response Function. This is the default option. Contrasts of these effects have a physical interpretation and represent a parsimonious way of characterising event-related responses. This option is also useful if you wish to look separately at activations and deactivations (this is implemented using a t-contrast with a +1 or -1 entry over the canonical regressor). '};
% ---------------------------------------------------------------------
% length Window length
% ---------------------------------------------------------------------
length         = cfg_entry;
length.tag     = 'length';
length.name    = 'Window length';
length.help    = {'Post-stimulus window length (in seconds)'};
length.strtype = 'r';
length.num     = [1 1];
% ---------------------------------------------------------------------
% order Order
% ---------------------------------------------------------------------
order         = cfg_entry;
order.tag     = 'order';
order.name    = 'Order';
order.help    = {'Number of basis functions'};
order.strtype = 'n';
order.num     = [1 1];
% ---------------------------------------------------------------------
% fourier Fourier Set
% ---------------------------------------------------------------------
fourier         = cfg_branch;
fourier.tag     = 'fourier';
fourier.name    = 'Fourier Set';
fourier.val     = {length order };
fourier.help    = {'Fourier basis functions. This option requires an SPM{F} for inference.'};
% ---------------------------------------------------------------------
% length Window length
% ---------------------------------------------------------------------
length         = cfg_entry;
length.tag     = 'length';
length.name    = 'Window length';
length.help    = {'Post-stimulus window length (in seconds)'};
length.strtype = 'r';
length.num     = [1 1];
% ---------------------------------------------------------------------
% order Order
% ---------------------------------------------------------------------
order         = cfg_entry;
order.tag     = 'order';
order.name    = 'Order';
order.help    = {'Number of basis functions'};
order.strtype = 'n';
order.num     = [1 1];
% ---------------------------------------------------------------------
% fourier_han Fourier Set (Hanning)
% ---------------------------------------------------------------------
fourier_han         = cfg_branch;
fourier_han.tag     = 'fourier_han';
fourier_han.name    = 'Fourier Set (Hanning)';
fourier_han.val     = {length order };
fourier_han.help    = {'Fourier basis functions with Hanning Window - requires SPM{F} for inference.'};
% ---------------------------------------------------------------------
% length Window length
% ---------------------------------------------------------------------
length         = cfg_entry;
length.tag     = 'length';
length.name    = 'Window length';
length.help    = {'Post-stimulus window length (in seconds)'};
length.strtype = 'r';
length.num     = [1 1];
% ---------------------------------------------------------------------
% order Order
% ---------------------------------------------------------------------
order         = cfg_entry;
order.tag     = 'order';
order.name    = 'Order';
order.help    = {'Number of basis functions'};
order.strtype = 'n';
order.num     = [1 1];
% ---------------------------------------------------------------------
% gamma Gamma Functions
% ---------------------------------------------------------------------
gamma         = cfg_branch;
gamma.tag     = 'gamma';
gamma.name    = 'Gamma Functions';
gamma.val     = {length order };
gamma.help    = {'Gamma basis functions - requires SPM{F} for inference.'};
% ---------------------------------------------------------------------
% length Window length
% ---------------------------------------------------------------------
length         = cfg_entry;
length.tag     = 'length';
length.name    = 'Window length';
length.help    = {'Post-stimulus window length (in seconds)'};
length.strtype = 'r';
length.num     = [1 1];
% ---------------------------------------------------------------------
% order Order
% ---------------------------------------------------------------------
order         = cfg_entry;
order.tag     = 'order';
order.name    = 'Order';
order.help    = {'Number of basis functions'};
order.strtype = 'n';
order.num     = [1 1];
% ---------------------------------------------------------------------
% fir Finite Impulse Response
% ---------------------------------------------------------------------
fir         = cfg_branch;
fir.tag     = 'fir';
fir.name    = 'Finite Impulse Response';
fir.val     = {length order };
fir.help    = {'Finite impulse response - requires SPM{F} for inference.'};
% ---------------------------------------------------------------------
% bases Basis Functions
% ---------------------------------------------------------------------
bases         = cfg_choice;
bases.tag     = 'bases';
bases.name    = 'Basis Functions';
bases.val     = {hrf };
bases.help    = {'The most common choice of basis function is the Canonical HRF with or without time and dispersion derivatives. '};
bases.values  = {hrf fourier fourier_han gamma fir };
% ---------------------------------------------------------------------
% volt Model Interactions (Volterra)
% ---------------------------------------------------------------------
volt         = cfg_menu;
volt.tag     = 'volt';
volt.name    = 'Model Interactions (Volterra)';
volt.help    = {
                'Generalized convolution of inputs (U) with basis set (bf).'
                ''
                'For first order expansions the causes are simply convolved (e.g. stick functions) in U.u by the basis functions in bf to create a design matrix X.  For second order expansions new entries appear in ind, bf and name that correspond to the interaction among the orginal causes. The basis functions for these efects are two dimensional and are used to assemble the second order kernel. Second order effects are computed for only the first column of U.u.'
                'Interactions or response modulations can enter at two levels.  Firstly the stick function itself can be modulated by some parametric variate (this can be time or some trial-specific variate like reaction time) modeling the interaction between the trial and the variate or, secondly interactions among the trials themselves can be modeled using a Volterra series formulation that accommodates interactions over time (and therefore within and between trial types).'
}';
volt.labels = {
               'Do not model Interactions'
               'Model Interactions'
}';
volt.values = {1 2};
volt.val    = {1};
% ---------------------------------------------------------------------
% global Global normalisation
% ---------------------------------------------------------------------
xGlobal         = cfg_menu;
xGlobal.tag     = 'global';
xGlobal.name    = 'Global normalisation';
xGlobal.help    = {'Global intensity normalisation'};
xGlobal.labels = {
                  'Scaling'
                  'None'
}';
xGlobal.values = {
                  'Scaling'
                  'None'
}';
xGlobal.val     = {'None'};
%----------------------------------------------------------------------
% gMT Masking threshold
%----------------------------------------------------------------------
gMT         = cfg_entry;
gMT.tag     = 'mthresh';
gMT.name    = 'Masking threshold';
gMT.help    = {'Masking threshold, defined as proportion of globals.'};
gMT.strtype = 'r';
gMT.num     = [1 1];
gMT.def     = @(val)spm_get_defaults('mask.thresh', val{:});
% ---------------------------------------------------------------------
% cvi Serial correlations
% ---------------------------------------------------------------------
cvi         = cfg_menu;
cvi.tag     = 'cvi';
cvi.name    = 'Serial correlations';
cvi.help    = {
               'Serial correlations in fMRI time series due to aliased biorhythms and unmodelled neuronal activity can be accounted for using an autoregressive AR(1) model during Classical (ReML) parameter estimation.  '
               ''
               'This estimate assumes the same correlation structure for each voxel, within each session.  ReML estimates are then used to correct for non-sphericity during inference by adjusting the statistics and degrees of freedom appropriately.  The discrepancy between estimated and actual intrinsic (i.e. prior to filtering) correlations are greatest at low frequencies.  Therefore specification of the high-pass filter is particularly important. '
               ''
               'Serial correlation can be ignored if you choose the ''none'' option. Note that the above options only apply if you later specify that your model will be estimated using the Classical (ReML) approach. If you choose Bayesian estimation these options will be ignored. For Bayesian estimation, the choice of noisemodel (AR model order) is made under the estimation options. '
}';
cvi.labels  = {'none', 'AR(1)', 'FAST'};
cvi.values  = {'none', 'AR(1)', 'FAST'};
cvi.def     = @(val)spm_get_defaults('stats.fmri.cvi', val{:});
% ---------------------------------------------------------------------
% fmri_design fMRI model specification (design only)
% ---------------------------------------------------------------------
fmri_design         = cfg_exbranch;
fmri_design.tag     = 'fmri_design';
fmri_design.name    = 'fMRI model specification (design only)';
fmri_design.val     = {dir timing generic generic1 bases volt xGlobal gMT cvi };
fmri_design.help    = {
    'Specification of a General Linear Model for statistical analysis of fMRI data (design only).'
    ''
    'It comprises the following steps (1) specification of the GLM design matrix, fMRI data files and filtering (2) estimation of GLM paramaters using classical or Bayesian approaches and (3) interrogation of results using contrast vectors to produce Statistical Parametric Maps (SPMs) or Posterior Probability Maps (PPMs).'
    ''
    'The design matrix defines the experimental design and the nature of hypothesis testing to be implemented.  The design matrix has one row for each scan and one column for each effect or explanatory variable. (eg. regressor or stimulus function). You can build design matrices with separable session-specific partitions.  Each partition may be the same (in which case it is only necessary to specify it once) or different. '
    ''
    'Responses can be either event- or epoch related, the only distinction is the duration of the underlying input or stimulus function. Mathematically they are both modeled by convolving a series of delta (stick) or box functions (u), indicating the onset of an event or epoch with a set of basis functions.  These basis functions model the hemodynamic convolution, applied by the brain, to the inputs.  This convolution can be first-order or a generalized convolution modeled to second order (if you specify the Volterra option). The same inputs are used by the Hemodynamic model or Dynamic Causal Models which model the convolution explicitly in terms of hidden state variables. '
    ''
    'Basis functions can be used to plot estimated responses to single events once the parameters (i.e. basis function coefficients) have been estimated.  The importance of basis functions is that they provide a graceful transition between simple fixed response models (like the box-car) and finite impulse response (FIR) models, where there is one basis function for each scan following an event or epoch onset.  The nice thing about basis functions, compared to FIR models, is that data sampling and stimulus presentation does not have to be synchronized thereby allowing a uniform and unbiased sampling of peri-stimulus time.'
    ''
    'Event-related designs may be stochastic or deterministic.  Stochastic designs involve one of a number of trial-types occurring with a specified probability at successive intervals in time.  These probabilities can be fixed (stationary designs) or time-dependent (modulated or non-stationary designs).  The most efficient designs obtain when the probabilities of every trial type are equal. A critical issue in stochastic designs is whether to include null events If you wish to estimate the evoked response to a specific event type (as opposed to differential responses) then a null event must be included (even if it is not modeled explicitly).'
    ''
    'In SPM, analysis of data from multiple subjects typically proceeds in two stages using models at two ''levels''. The ''first level'' models are used to implement a within-subject analysis. Typically there will be as many first level models as there are subjects. Analysis proceeds as described using the ''Specify first level'' and ''Estimate'' options. The results of these analyses can then be presented as ''case studies''. More often, however, one wishes to make inferences about the population from which the subjects were drawn. This is an example of a ''Random-Effects (RFX) analysis'' (or, more properly, a mixed-effects analysis). In SPM, RFX analysis is implemented using the ''summary-statistic'' approach where contrast images from each subject are used as summary measures of subject responses. These are then entered as data into a ''second level'' model. '
    }';
fmri_design.prog = @spm_run_fmri_spec;
fmri_design.vout = @vout_stats;
fmri_design.modality = {'FMRI'};

%==========================================================================
function t = cond_check(job)
t   = {};
if (numel(job.onset) ~= numel(job.duration)) && (numel(job.duration)~=1)
    t = {sprintf('"%s": Number of event onsets (%d) does not match the number of durations (%d).',...
        job.name, numel(job.onset),numel(job.duration))};
end
for i=1:numel(job.pmod)
    if numel(job.onset) ~= numel(job.pmod(i).param)
        t = {t{:}, sprintf('"%s" & "%s":Number of event onsets (%d) does not equal the number of parameters (%d).',...
            job.name, job.pmod(i).name, numel(job.onset),numel(job.pmod(i).param))};
    end
end

%==========================================================================
function t = sess_check(sess)
t = {};
for i=1:numel(sess.regress)
    if sess.nscan ~= numel(sess.regress(i).val)
        t = {t{:}, sprintf('Num scans (%d) ~= Num regress[%d] (%d).',numel(sess.nscan),i,numel(sess.regress(i).val))};
    end
end

%==========================================================================
function dep = vout_stats(job)
dep(1)            = cfg_dep;
dep(1).sname      = 'SPM.mat File';
dep(1).src_output = substruct('.','spmmat');
dep(1).tgt_spec   = cfg_findspec({{'filter','mat','strtype','e'}});
%dep(2)            = cfg_dep;
%dep(2).sname      = 'SPM Variable';
%dep(2).src_output = substruct('.','spmvar');
%dep(2).tgt_spec   = cfg_findspec({{'strtype','e'}});


function z = proj_cone(z,c)
    z = z + proj_dual_cone(-z,c);
end


function outdata=specscope(indata)
% record and plot audio spectrogram
%
% Usage: outdata=specscope(indata)
%
%  Input: indata (optional)
%    Displays a recorded piece of data, if an argument is passed
%    Otherwise displays audio data from an attached microphone
%
%  Output: outdata (optional)
%    If present, will return up to 10 minutes
%    of captured audio data.
%
%  Note: Parameters such as sampling frequency, number of tapers
%    and display refresh rate may be set below if desired.
%    You can also acquire data from a national instruments card.
%

close all;

%=======================================================================
% Check toolboxes
%=======================================================================

% Check for toolboxes
if not(exist('analoginput','file'));
    fprintf('You need to install the DAQ toolbox first\n');
    return
end
if not(exist('mtspecgramc','file'));
    fprintf('You need to install the Chronux toolbox first from http://chronux.org/\n');
    return
end

%=======================================================================
% Set parameters
%=======================================================================

global acq;

% Set defaults
acq.params.Fs = 44100;
acq.pause = 0;
acq.skips = 0;
acq.stop = 0;
acq.restart = 0;
acq.plot_frequency = 10;
acq.samples_acquired = 0;
acq.spectra = [];
acq.times = [];
defaults
audio_instr;
fig=create_ui;

%=======================================================================
% Check arguments, start DAQ
%=======================================================================

if nargout
   % save up to ten minutes data, preallocated...
    fprintf('Pre-allocating memory for data save - please be patient.\n');
   outdata=zeros( (acq.params.Fs * 60 * 10), 1 );
end

if nargin == 1;
    acq.indata = indata;
    acq.live = 0;
else
    % Create and set up and start analog input daq
    input=1;
    if input==1;
        acq.ai = analoginput('winsound');
        addchannel( acq.ai, 1 );
    else
        acq.ai = analoginput('nidaq', 1);
        addchannel(acq.ai, 0);
        set(acq.ai,'InputType','SingleEnded')
        set(acq.ai,'TransferMode','Interrupts')
        set(acq.ai,'TriggerType','Manual');
    end
    set( acq.ai, 'SampleRate', acq.params.Fs )
    acq.params.Fs = get( acq.ai, 'SampleRate' );
    set( acq.ai, 'SamplesPerTrigger', inf )
    start(acq.ai)
    acq.live = 1;

    if input==2;
        trigger(acq.ai);
    end
end

acq.samples_per_frame = acq.params.Fs / acq.plot_frequency;

%=======================================================================
% The scope main loop
%=======================================================================

acq.t0=clock;
acq.tn=clock;

% Loop over frames to acquire and display
while 1;

    % Check for quit signal
    if acq.stop;
        break;
    end

    % Calculate times
    calctime = acq.samples_acquired / acq.params.Fs;
    acq.samples_acquired = acq.samples_acquired + acq.samples_per_frame;
    acq.t1 = clock;
    elapsed = etime(acq.t1,acq.t0);

    % Get a small snippet of data
    if ( acq.live )
       data = getdata( acq.ai, acq.samples_per_frame );
    else
      while elapsed < acq.samples_acquired / acq.params.Fs
        pause( acq.samples_acquired / (acq.params.Fs) - elapsed );
        acq.t1=clock;
        elapsed = etime(acq.t1,acq.t0);
      end
      if acq.samples_acquired + 2 * acq.samples_per_frame >= length( acq.indata )
        acq.stop=1;
      end
      data = acq.indata(floor(acq.samples_acquired+1):floor(acq.samples_per_frame+acq.samples_acquired));
    end

    if nargout
        outdata(floor(acq.samples_acquired+1):floor(acq.samples_acquired+length(data))) = data(:);
    end

    if acq.restart;
       acq.restart = 0;
       acq.spectra = [];
       acq.times = [];
    end

    % Calculate spectrogram of data snippet
    if acq.deriv
      [s, t, f] = mtspecgramc(diff(data), acq.moving_window, acq.params );
    else
      [s, t, f] = mtspecgramc(data, acq.moving_window, acq.params );
    end

    % Add new spectra to that already calculated
    acq.times = [acq.times t+calctime];
    if acq.log
        acq.spectra = [acq.spectra log(s')];
    else
        acq.spectra = [acq.spectra s'];
    end

    % Remove old spectra once window reaches desired size
    while acq.times(1,end) - acq.times(1,1) > acq.display_size;

        % Ring buffer!
        y = length(t);
        acq.times(:,1:y) = [];
        acq.spectra(:,1:y) = [];

    end

    % Only plot if display is keeping up with real time and not paused
    show_plot=1;
    if nargin==0
       if get(acq.ai, 'SamplesAvailable' ) > 10 * acq.samples_per_frame && acq.pause==0
	  show_plot=0;
       end
    else
      if elapsed > calctime + 0.5
	show_plot=0;
      end
    end

    if acq.pause
       show_plot=0;
    end
    if show_plot

        if  acq.bgsub
            acq.mean_spectra = mean( acq.spectra, 2 );
        end

        % Normalize until full screen passes by if requested
        if acq.normalize>=1;
            if acq.normalize==1
                acq.tn=clock;
                acq.normalize=2;
            end
            if etime(clock,acq.tn)>1.25*acq.display_size
                acq.normalize=0;
            end
            mins = min(min(acq.spectra));
            maxs = max(max(acq.spectra));
        end

        % Scale the spectra based upon current offset and scale
        if acq.bgsub
           scaled_spectra = acq.offset + ( acq.scale ) * ( acq.spectra - repmat( acq.mean_spectra, [1,size(acq.spectra,2)]) ) / ( maxs - mins );
        else
            scaled_spectra = acq.offset + acq.scale * ( acq.spectra - mins ) / ( maxs - mins );
        end

        % Draw the image to the display
        image( acq.times, f, scaled_spectra ); axis xy;
        drawnow;

    else
        % Keep track of skipped displays
        acq.skips = acq.skips + 1;
    end

end

%=======================================================================
% Clean up
%=======================================================================

acq.t1=clock;
elapsed = etime(acq.t1,acq.t0);
fprintf( 'Elapsed time %f seconds\n', elapsed );

% Warn if many skips were encountered
if acq.skips > 5;
    fprintf( '\nWARNING:\nThis program skipped plotting %d times to keep pace.\n', acq.skips )
    fprintf( 'Run again without keyboard interaction or changing the figure size.\n' )
    fprintf( 'If this message reappears you should reduce the plot frequency parameter.\n\n' );
end

% Clean up the analoginput object
if acq.live
  stop(acq.ai);delete( acq.ai );clear acq.ai;
end

% Clean up the figure
delete(fig);
delete(gcf);

if nargout
   % save up to ten minutes data, preallocated...
    fprintf('Saving output data\n');
   outdata=outdata(1:floor(acq.samples_acquired));
end

return;

%
%
%=======================================================================
% Functions called
%=======================================================================
%
%

%=======================================================================
% Handle Keypresses
%=======================================================================

% Handle figure window keypress events
function keypress(varargin)

global acq;
keypressed=get(gcf,'CurrentCharacter');

% ignore raw control, shift, alt keys
if keypressed;

    % Save current frame as gif
    if strcmp( keypressed, 'g');
       saveas( acq.fig, sprintf( 'frame%d.png',acq.times(length(acq.times)) ) )
    end

    % Offset changes
    increment=1;
    if strcmp( keypressed, 'l');
	acq.offset = acq.offset - increment;
    elseif strcmp( keypressed, 'o');
        acq.offset = acq.offset + increment;

    % Scale changes
    elseif strcmp( keypressed, 'x');
        acq.scale = acq.scale - increment;
    elseif strcmp( keypressed, 's');
        acq.scale = acq.scale + increment;

    % Reset defaults
    elseif strcmp( keypressed, 'd');
        defaults
	acq.restart=1;
    % Normalize spectra
    elseif strcmp( keypressed, 'n');
	   request_normalize

    % Quit
    elseif strcmp( keypressed, 'q');
	request_quit

    % Pause
    elseif strcmp( keypressed, 'p');
	   request_pause

    % Help
    elseif strcmp( keypressed, 'h');
        audio_instr

    % Change colormaps for 0-9,a-c
    elseif strcmp( keypressed, '0' );
        colormap( 'jet' );
    elseif strcmp( keypressed, '1' );
        colormap( 'bone' );
    elseif strcmp( keypressed, '2' );
        colormap( 'colorcube' );
    elseif strcmp( keypressed, '3' );
        colormap( 'cool' );
    elseif strcmp( keypressed, '4' );
        colormap( 'copper' );
    elseif strcmp( keypressed, '5' );
        colormap( 'gray' );
    elseif strcmp( keypressed, '6' );
        colormap( 'hot' );
    elseif strcmp( keypressed, '7' );
        colormap( 'hsv' );
    elseif strcmp( keypressed, '8' );
        colormap( 'autumn' );
    elseif strcmp( keypressed, '9' );
        colormap( 'pink' );
    elseif strcmp( keypressed, 'a' );
        colormap( 'spring' );
    elseif strcmp( keypressed, 'b' );
        colormap( 'summer' );
    elseif strcmp( keypressed, 'c' );
        colormap( 'winter' );
    end

    update_display

end
return

%=======================================================================
% Defaults
%=======================================================================

% Reset defaults
function defaults()
  global acq;
  acq.params.raw_tapers = [2 3];
  acq.moving_window = [0.02 0.02];
  acq.params.tapers=dpsschk(acq.params.raw_tapers,round(acq.params.Fs*acq.moving_window(1)),acq.params.Fs);
  acq.offset = 0;
  acq.scale = 64;
  acq.display_size = 3;
  acq.params.fpass = [50 8000];
  acq.deriv=1;
  acq.log=1;
  acq.bgsub = 1;
  acq.params.pad= 0;
  acq.normalize = 2;
return

function update_display()
global acq;
    set(acq.tapers_ui,'String',sprintf( '%.0f %.0f', acq.params.raw_tapers(1), acq.params.raw_tapers(2) ));
    set(acq.window_ui,'String',sprintf( '%.2f %.2f', acq.moving_window(1), acq.moving_window(2) ));
    set(acq.offset_ui,'String',sprintf( '%d', acq.offset ));
    set(acq.scale_ui,'String',sprintf( '%d', acq.scale ));
    set(acq.display_size_ui,'String',sprintf( '%.1f', acq.display_size ));
    set(acq.frequency_ui,'String',sprintf( '%.1f %.1f', acq.params.fpass(1), acq.params.fpass(2)  ))
    set(acq.derivative_ui,'Value',acq.deriv);
    set(acq.log_ui,'Value',acq.log);
    set(acq.bgsub_ui,'Value',acq.bgsub);
    return

%=======================================================================
% Update ui controls
%=======================================================================

function request_quit(varargin)
	 global acq;
	 acq.stop=1;
return

function request_pause(varargin)
	 global acq;
	 acq.pause = not( acq.pause );
return

function request_normalize(varargin)
	global acq;
        acq.normalize = 2;
return

function update_defaults(varargin)
  global acq;
  defaults
  update_display
  acq.restart=1;
return

function update_tapers(varargin)
	 global acq;
     acq.params.raw_tapers = sscanf(get( gco, 'string' ),'%f %d')';
     acq.params.tapers=dpsschk(acq.params.raw_tapers,round(acq.params.Fs*acq.moving_window(1)),acq.params.Fs); % check tapers
return

function update_window(varargin)
	 global acq;
	 acq.moving_window = sscanf(get( gco, 'string' ),'%f %f');
         acq.params.tapers=dpsschk(acq.params.raw_tapers,round(acq.params.Fs*acq.moving_window(1)),acq.params.Fs);
	 acq.restart = 1;
return

function update_offset(varargin)
	 global acq;
	 acq.offset = sscanf(get( gco, 'string' ),'%f');
	 return

function update_scale(varargin)
	 global acq;
	 acq.scale = sscanf(get( gco, 'string' ),'%f');
	 return

function update_display_size(varargin)
	 global acq;
	 acq.display_size = sscanf(get( gco, 'string' ),'%f');
	 return

function update_fpass(varargin)
	 global acq;
	 acq.params.fpass = sscanf(get( gco, 'string' ),'%f %f');
         acq.restart = 1;
	 return

function update_deriv(varargin)
	 global acq;
     acq.deriv=get( gco, 'Value' );
     acq.normalize=1;
     return

function update_log(varargin)
	 global acq;
     acq.log=get( gco, 'Value' );
     acq.normalize=1;
     return

function update_bgsub(varargin)
	 global acq;
     acq.bgsub=get( gco, 'Value' );
     return

%=======================================================================
% UI display
%=======================================================================

function fig=create_ui()
    global acq;

    bgcolor = [1 1 1]; % .7 .7 .7
    % ===Create main figure==========================
    fig = figure('Position',centerfig(800,600),...
        'NumberTitle','off',...
        'Name','Real-time spectrogram',...
        'doublebuffer','on',...
        'HandleVisibility','on',...
	'Renderer', 'openGL', ...
	'KeyPressFcn', @keypress, ...
        'Color',bgcolor);

    acq.fig = fig;
    offset = 80;
    % ===text==========
    uicontrol(gcf,'Style','text',...
        'String', 'tapers',...
        'Position',[offset+225 20 45 20],...
        'BackgroundColor',bgcolor);
    uicontrol(gcf,'Style','text',...
        'String', 'moving win',...
        'Position',[offset+300 20 70 20],...
        'BackgroundColor',bgcolor);
    uicontrol(gcf,'Style','text',...
        'String', 'offset',...
        'Position',[offset+375 20 30 20],...
        'BackgroundColor',bgcolor);
    uicontrol(gcf,'Style','text',...
        'String', 'scale',...
        'Position',[offset+410 20 30 20],...
        'BackgroundColor',bgcolor);
    uicontrol(gcf,'Style','text',...
        'String', 't axis',...
        'Position',[offset+445 20 30 20],...
        'BackgroundColor',bgcolor);
    uicontrol(gcf,'Style','text',...
        'String', 'f axis',...
        'Position',[offset+480 20 40 20],...
        'BackgroundColor',bgcolor);
    uicontrol(gcf,'Style','text',...
        'String', 'deriv',...
        'Position',[offset+550 20 35 20],...
        'BackgroundColor',bgcolor);
    uicontrol(gcf,'Style','text',...
        'String', 'log',...
        'Position',[offset+580 20 35 20],...
        'BackgroundColor',bgcolor);
    uicontrol(gcf,'Style','text',...
        'String', 'bgsub',...
        'Position',[offset+610 20 35 20],...
        'BackgroundColor',bgcolor);

    % ===The quit button===============================
    uicontrol('Style','pushbutton',...
        'Position',[offset+5 5 45 20],...
        'String','Quit',...
        'Interruptible','off',...
        'BusyAction','cancel',...
        'Callback',@request_quit);

    % ===The pause button===============================
    uicontrol('Style','pushbutton',...
        'Position',[offset+55 5 45 20],...
        'String','Pause',...
        'Interruptible','off',...
        'BusyAction','cancel',...
        'Callback',@request_pause);

    % ===The defaults button===============================
    uicontrol('Style','pushbutton',...
        'Position',[offset+105 5 50 20],...
        'String','Defaults',...
        'Interruptible','off',...
        'BusyAction','cancel',...
        'Callback',@update_defaults);

    % ===The normalize button===============================
    uicontrol('Style','pushbutton',...
        'Position',[offset+160 5 60 20],...
        'String','Normalize',...
        'Interruptible','off',...
        'BusyAction','cancel',...
        'Callback',@request_normalize );

    % ===Tapers============================================
    acq.tapers_ui = uicontrol(gcf,'Style','edit',...
        'String', sprintf( '%.0f %.0f', acq.params.raw_tapers(1), acq.params.raw_tapers(2) ),...
        'Position',[offset+225 5 70 20],...
        'CallBack', @update_tapers);

    % ===Window============================================
    acq.window_ui=uicontrol(gcf,'Style','edit',...
        'String', sprintf( '%.2f %.2f', acq.moving_window(1), acq.moving_window(2) ),...
        'Position',[offset+300 5 70 20],...
        'CallBack', @update_window);

    % ===Offset============================================
    acq.offset_ui = uicontrol(gcf,'Style','edit',...
        'String', sprintf( '%d', acq.offset ),...
        'Position',[offset+375 5 30 20],...
        'CallBack', @update_offset);

    % ===Scale============================================
    acq.scale_ui = uicontrol(gcf,'Style','edit',...
        'String', sprintf( '%d', acq.scale ),...
        'Position',[offset+410 5 30 20],...
        'CallBack', @update_scale);

    % ===display size======================================
    acq.display_size_ui = uicontrol(gcf,'Style','edit',...
        'String', sprintf( '%.1f', acq.display_size ),...
        'Position',[offset+445 5 30 20],...
        'CallBack', @update_display_size);

    % ===frequency axis=====================================
    acq.frequency_ui = uicontrol(gcf,'Style','edit',...
        'String', sprintf( '%.1f %.1f', acq.params.fpass(1), acq.params.fpass(2)  ),...
        'Position',[offset+480 5 80 20],...
        'CallBack', @update_fpass);

    % ===derivative=====================================
    acq.derivative_ui = uicontrol(gcf,'Style','checkbox',...
        'Value',acq.deriv,...
        'Position',[offset+565 5 20 20],...
        'CallBack', @update_deriv);

    % ===log=====================================
    acq.log_ui = uicontrol(gcf,'Style','checkbox',...
        'Value',acq.log,...
        'Position',[offset+590 5 20 20],...
        'CallBack', @update_log);

    % ===bgsub=====================================
    acq.bgsub_ui = uicontrol(gcf,'Style','checkbox',...
        'Value',acq.bgsub,...
        'Position',[offset+615 5 20 20],...
        'CallBack', @update_bgsub);

return

%=======================================================================
% Assorted functions
%=======================================================================

function pos = centerfig(width,height)
% Find the screen size in pixels
screen_s = get(0,'ScreenSize');
pos = [screen_s(3)/2 - width/2, screen_s(4)/2 - height/2, width, height];
return

function audio_instr()
% Show instructions

  fprintf('INSTRUCTIONS:\n');
  fprintf('Click on figure window first to activate controls.\n')
  fprintf('Adjust tapers, windows, scales, offsets and axes using the gui\n');
  fprintf('The deriv checkbox toggles derivative of the data\n');
  fprintf('The log checkbox toggles a log of the spectrum\n');
  fprintf('Press d or use defaults button to reset most parameters to defaults.\n')
  fprintf('Press n or use normalize button to normalize spectra based upon values in current display.\n')
  fprintf('Press 0-9,a-c to choose a colormap (default 0).\n')
  fprintf('Press p to pause and unpause display.\n')
  fprintf('Press o and l to adjust offset, or use offset textbox on gui.\n');
  fprintf('Press s and x to adjust scale, or use scale textbox on gui.\n');
  fprintf('Press h for this message.\n')
  fprintf('Press q to quit, or use quit button on gui.\n\n')

return


function [tissueModel,coreRxnBool,coreMetBool,coreCtrsBool] = fastcore(model, coreRxnInd, epsilon, printLevel)
% Use the FASTCORE algorithm ('Vlassis et al, 2014') to extract a context
% specific model. FASTCORE algorithm defines one set of core
% reactions that is guaranteed to be active in the extracted model and find
% the minimum of reactions possible to support the core.
%
% USAGE:
%
%    tissueModel = fastcore(model, coreRxnInd)
%
% INPUTS:
%    model:             (the following fields are required - others can be supplied)
%                         * S  - `m x 1` Stoichiometric matrix
%                         * lb - `n x 1` Lower bounds
%                         * ub - `n x 1` Upper bounds
%                         * rxns   - `n x 1` cell array of reaction abbreviations
%
%   coreRxnInd:          indices of reactions in cobra model that are part of the
%                        core set of reactions (called 'C' in 'Vlassis et al,
%                        2014')
%
% OPTIONAL INPUTS:
%   epsilon:             smallest flux value that is considered nonzero
%                        (default getCobraSolverParams('LP', 'feasTol')*100)
%   printLevel:          0 = silent, 1 = summary, 2 = debug (default - 0)
%
% OUTPUT:
%
%   tissueModel:         extracted model
%
%   coreRxnBool:         n x 1 boolean vector indicating core reactions
%
% 'Vlassis, Pacheco, Sauter (2014). Fast reconstruction of compact
% context-specific metbolic network models. PLoS Comput. Biol. 10,
% e1003424.'
%
% .. Authors:
%       - Nikos Vlassis, Maria Pires Pacheco, Thomas Sauter, 2013 LCSB / LSRU, University of Luxembourg
%       - Ronan Fleming, commenting of code and inputs/outputs
%       - Anne Richelle, code adaptation to fit with createTissueSpecificModel

if nargin < 4 || ~exist('printLevel','var')
    printLevel = 0;
end
if nargin < 3 || isempty(epsilon)
    epsilon=getCobraSolverParams('LP', 'feasTol')*100;
end

if printLevel > 1
    tic
end

model_orig = model;

[nMets,nRxns] = size(model.S);

LPproblem = buildLPproblemFromModel(model);

%reactions irreversible in the reverse direction
Ir = model.lb < 0 & model.ub<=0;

%flip direction of reactions irreversible in the reverse direction
LPproblem.A(:,Ir) = -LPproblem.A(:,Ir);
tmp = LPproblem.ub(Ir);
LPproblem.ub(Ir) = -LPproblem.lb(Ir);
LPproblem.lb(Ir) = -tmp;

%Find irreversible reactions
irrevRxns = find(model.lb>=0);

A = [];
flipped = false;
singleton = false;

% Find irreversible core reactions
J = intersect(coreRxnInd, irrevRxns);

if printLevel > 0
    fprintf('|J|=%d  ', length(J));
end

%Find all the reactions that are not in the core
nbRxns = 1:nRxns;
% Non Core reactions (penalized)
P = setdiff(nbRxns, coreRxnInd);

% Find the minimum of set reactions from P that need to be included to
% support the irreversible core set of reactions
[Supp, basis] = findSparseMode(J, P, singleton, model, LPproblem, epsilon);

if ~isempty(setdiff(J, Supp))
    warning('fastcore.m Error: Global network is not flux consistent, ignoring the following irreversible core reactions:\n');
    model.rxns(setdiff(J, Supp))
    coreRxnInd = setdiff(coreRxnInd,setdiff(J, Supp));
    %error ('fastcore.m Error: Inconsistent irreversible core reactions.\n');
end

A = Supp;
if printLevel > 0
    fprintf('|A|=%d\n', length(A));
end

% J is the set of core reactions not already in the extracted model
J = setdiff(coreRxnInd, A);
if printLevel > 0
    fprintf('|J|=%d  ', length(J));
end

% Main loop that reduce at each iteration the number of reactions from P that need to be included to
% support the complete core set of reactions
while ~isempty(J)

    P = setdiff(P, A);

    %reuse the basis from the previous solve if it exists
    [Supp, basis] = findSparseMode(J, P, singleton, model, LPproblem, epsilon, basis);

    A = union(A, Supp);
    if printLevel > 0
        fprintf('|A|=%d\n', length(A));
    end

    if ~isempty( intersect(J, A))
        J = setdiff(J, A);
        if printLevel > 0
            fprintf('|J|=%d  ', length(J));
        end
        flipped = false;
    else
        if singleton
            JiRev = setdiff(J(1),irrevRxns);
        else
            JiRev = setdiff(J,irrevRxns);
        end
        if flipped || isempty(JiRev)
            if singleton
                warning('\n fastcore.m: Global network is not flux consistent, ignoring corresponding core reaction:\n');
                disp(model.rxns(J))
                J = [];
                %error('\n fastcore.m Error: Global network is not consistent.\n');
            else
                flipped = false;
                singleton = true;
            end
        else
            LPproblem.A(:,JiRev) = -LPproblem.A(:,JiRev);
            tmp = LPproblem.ub(JiRev);
            LPproblem.ub(JiRev) = -LPproblem.lb(JiRev);
            LPproblem.lb(JiRev) = -tmp;
            flipped = true;

            if printLevel > 0
                fprintf('(flip)  ');
            end
        end
    end
end
if printLevel > 0
    fprintf('|A|=%d\n', length(A)); % A : indices of reactions in the new model
end

if printLevel > 1
    toc
end

coreRxnBool=false(size(model.S,2),1);
coreRxnBool(A)=1;

rxnRemoveList = setdiff(model.rxns,model.rxns(A));

dummyMetBool = contains(model.mets,'dummy_Met_');
dummyRxnBool = contains(model.rxns,'dummy_Rxn_');
dummyRxnList = model.rxns(dummyRxnBool);
if any(dummyMetBool) || any(dummyRxnBool)
    model = destroyDummyModel(model,dummyMetBool,dummyRxnBool);
    rxnRemoveList = setdiff(rxnRemoveList,dummyRxnList);
end

%removes any infeasible coupling constraints also
[tissueModel, metRemoveList, ctrsRemoveList] = removeRxns(model, rxnRemoveList,'metRemoveMethod','exclusive','ctrsRemoveMethod','infeasible');

coreMetBool=~ismember(model_orig.mets,metRemoveList);
if isfield(model,'ctrs')
    coreCtrsBool = ~ismember(model_orig.ctrs,ctrsRemoveList);
else
    coreCtrsBool = ctrsRemoveList;
end

%coreGeneBool
tissueModel = removeUnusedGenes(tissueModel);


function [uniformScan, firstSliceZValue] = scanUniformize(scanStruct, scanArray, scanInfo, dim3Spacing, tMin, tMax, keepSlice, optS, hBar)
%"scanUniformize"
%   Interpolates the input CT data values to a grid of values
%   uniform in the z direction (and therefore in each direction).
%   The scan in the passed scanStruct is used.
%
%   Format: Scan array input in (rows,cols,k) and output in
%   (rows, cols, k).
%
%   keepSlice is either 'last' or 'first', depending on which
%   slice should be kept. The uniform z-value calculations are
%   made beginning from that slice. Default value is 'first'.
%
%   note: this program updates a waitbar between the values of
%         tMin and tMax. Suggested use is to create a waitbar
%         before calling this function and to close it afterwards.
%
%Latest modifications:
% 14 Aug 02, V H Clark, creation
% Jan 02, JOD, added 8-bit support for reduced memory.
% 23 Apr 03, JOD, added back 16-bit support and fixed bug.
% 09 Apr 03, JOD, added hBar to parameter list.
% 18 Feb 05, JRA, Added scanStruct parameter for multiscan support.
%
%Usage:
%   function [uniformScan, firstSliceZValue] = scanUniformize(scanStruct, scanArray, scanInfo, dim3Spacing, tMin, tMax, keepSlice, optS, hBar)
%
% Copyright 2010, Joseph O. Deasy, on behalf of the CERR development team.
%
% This file is part of The Computational Environment for Radiotherapy Research (CERR).
%
% CERR development has been led by:  Aditya Apte, Divya Khullar, James Alaly, and Joseph O. Deasy.
%
% CERR has been financially supported by the US National Institutes of Health under multiple grants.
%
% CERR is distributed under the terms of the Lesser GNU Public License.
%
%     This version of CERR 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.
%
% CERR 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 CERR.  If not, see <http://www.gnu.org/licenses/>.

if nargin < 6
  keepSlice = 'first';
end

tDelta = tMax - tMin;

%find desired z values, zi:

firstZValue = scanInfo(1).zValue;
lastZValue  = scanInfo(end).zValue;

if strcmp(keepSlice,'first')
  ziValues = [firstZValue : dim3Spacing : lastZValue];
elseif strcmp(keepSlice,'last')
  ziValuesRev = [lastZValue : -dim3Spacing : firstZValue];
  ziValues = ziValuesRev(end:-1:1);
end
firstSliceZValue = ziValues(1);

zValues  = [scanInfo(:).zValue];
helperIndex = 1;

xSize = scanInfo(1).sizeOfDimension2; %doesn't matter which slice is used as the scanInfo index -- they should all be the same.
ySize = scanInfo(1).sizeOfDimension1;
numOfElts = xSize*ySize;

xUnits = scanInfo(1).grid1Units;
yUnits = scanInfo(1).grid2Units;

xMax = xUnits*(xSize - 1);
yMax = yUnits*(ySize - 1);

if strcmpi(optS.uniformizedDataType,'uint8')
  uniformScan = zeros(ySize, xSize, length(ziValues),'uint8');
elseif strcmpi(optS.uniformizedDataType,'uint16') %assume uint16
  uniformScan = zeros(ySize, xSize, length(ziValues),'uint16');
end

if strcmpi(optS.uniformizedDataType,'uint8')
  CTMin = scanStruct.uniformScanInfo.minCTValue;
  CTMax = scanStruct.uniformScanInfo.maxCTValue;
  CTScale = 255 / (CTMax - CTMin);
elseif strcmpi(optS.uniformizedDataType,'uint16')
  CTMin = scanStruct.uniformScanInfo.minCTValue;
  CTMax = scanStruct.uniformScanInfo.maxCTValue;
  CTScale = 65535 / (CTMax - CTMin);
end

waitbar(tMin, hBar);
for k = 1 : length(ziValues)
  zi = ziValues(k);

  %Find nearest slices to zi value.
  [cranialSlice, caudalSlice, helperIndex] = findSurroundingSlices(zi, zValues, helperIndex);

  sliceWidth = abs(zValues(cranialSlice) - zValues(caudalSlice));
  if sliceWidth ~= 0
      cranialWeight = 1 - abs(zValues(cranialSlice) - zi) / sliceWidth;
      caudalWeight  = 1 - abs(zValues(caudalSlice) - zi) / sliceWidth;
  else
      cranialWeight = 1;
      caudalWeight  = 0;
  end

  %Use simple linear interpolation between the two slices, by weight.
  interpSlice = double(scanArray(:,:,cranialSlice)) * cranialWeight + double(scanArray(:,:,caudalSlice)) * caudalWeight;
  if strcmpi(optS.uniformizedDataType,'uint8')
      uniformScan(:,:,k) = uint8((interpSlice - CTMin) * CTScale);
  elseif  strcmpi(optS.uniformizedDataType,'uint16')
      uniformScan(:,:,k) = uint16((interpSlice - CTMin) * CTScale);
  end
  waitbar(tMin + (k/length(ziValues))*tDelta, hBar);
end

return

function [cranialSlice, caudalSlice, hi] = findSurroundingSlices(zi, zValues, hi)
% Find the cranial and caudal slice numbers.
% assumes that z values increase with index number.
% hi is a helper index that must be equal to or lower than the cranial slice number desired.
%    (it makes this function faster)

done = 0;
while ~done
  if (zi < zValues(hi))
    caudalSlice  = hi;
    cranialSlice = hi-1;
    hi = cranialSlice;
    done = 1;
  elseif (zValues(hi) == zi)
    cranialSlice = hi;
    caudalSlice = hi;
    done = 1;
  else
    hi = hi+1;
  end
end

return


classdef GlobalPooling < dagnn.Filter
  properties
    method = 'avg';
    poolSize = [1 1];
  end

  methods
    function outputs = forward(self, inputs, params)
      outputs{1} = vl_nnglobalpool(inputs{1}, 'method', self.method) ;
    end

    function [derInputs, derParams] = backward(self, inputs, params, derOutputs)
      derInputs{1} = vl_nnglobalpool(inputs{1}, derOutputs{1}, 'method', self.method) ;
      derParams = {} ;
    end

    function kernelSize = getKernelSize(obj)
      kernelSize = obj.poolSize ;
    end

    function outputSizes = getOutputSizes(obj, inputSizes)
      %outputSizes = getOutputSizes@dagnn.Filter(obj, inputSizes) ;
      %outputSizes{1}(3) = inputSizes{1}(3) ;
      poolSize = [inputSizes{1}(1)  inputSizes{1}(2)];
      outputSizes{1}=[1,1,inputSizes{1}(3),inputSizes{1}(4)];
    end

    function obj = Pooling(varargin)
      obj.load(varargin) ;
    end
  end
end


%  When you load any ANALYZE or NIfTI file with 'load_nii.m', and view
%  it with 'view_nii.m', you may find that the image is L-R flipped.
%  This is because of the confusion of radiological and neurological
%  convention in the medical image before NIfTI format is adopted. You
%  can find more details from:
%
%  http://www.rotman-baycrest.on.ca/~jimmy/UseANALYZE.htm
%
%  Sometime, people even want to convert RAS (standard orientation) back
%  to LAS orientation to satisfy the legend programs or processes. This
%  program is only written for those purpose. So PLEASE BE VERY CAUTIOUS
%  WHEN USING THIS 'FLIP_LR.M' PROGRAM.
%
%  With 'flip_lr.m', you can convert any ANALYZE or NIfTI (no matter
%  3D or 4D) file to a flipped NIfTI file. This is implemented simply
%  by flipping the affine matrix in the NIfTI header. Since the L-R
%  orientation is determined there, so the image will be flipped.
%
%  Usage: flip_lr(original_fn, flipped_fn, [old_RGB],[tolerance],[preferredForm])
%
%  original_fn  -  filename of the original ANALYZE or NIfTI (3D or 4D) file
%
%  flipped_fn  -  filename of the L-R flipped NIfTI file
%
%  old_RGB (optional)  -  a scale number to tell difference of new RGB24
%	from old RGB24. New RGB24 uses RGB triple sequentially for each
%	voxel, like [R1 G1 B1 R2 G2 B2 ...]. Analyze 6.0 from AnalyzeDirect
%	uses old RGB24, in a way like [R1 R2 ... G1 G2 ... B1 B2 ...] for
%	each slices. If the image that you view is garbled, try to set
%	old_RGB variable to 1 and try again, because it could be in
%	old RGB24. It will be set to 0, if it is default or empty.
%
%  tolerance (optional) - distortion allowed for non-orthogonal rotation
%	or shearing in NIfTI affine matrix. It will be set to 0.1 (10%),
%	if it is default or empty.
%
%  preferredForm (optional)  -  selects which transformation from voxels
%	to RAS coordinates; values are s,q,S,Q.  Lower case s,q indicate
%	"prefer sform or qform, but use others if preferred not present".
%	Upper case indicate the program is forced to use the specificied
%	tranform or fail loading.  'preferredForm' will be 's', if it is
%	default or empty.	- Jeff Gunter
%
%  Example: flip_lr('avg152T1_LR_nifti.nii', 'flipped_lr.nii');
%           flip_lr('avg152T1_RL_nifti.nii', 'flipped_rl.nii');
%
%  You will find that 'avg152T1_LR_nifti.nii' and 'avg152T1_RL_nifti.nii'
%  are the same, and 'flipped_lr.nii' and 'flipped_rl.nii' are also the
%  the same, but they are L-R flipped from 'avg152T1_*'.
%
%  NIFTI data format can be found on: http://nifti.nimh.nih.gov
%
%  - Jimmy Shen (jimmy@rotman-baycrest.on.ca)
%
function flip_lr(original_fn, flipped_fn, old_RGB, tolerance, preferredForm)

   if ~exist('original_fn','var') | ~exist('flipped_fn','var')
      error('Usage: flip_lr(original_fn, flipped_fn, [old_RGB],[tolerance])');
   end

   if ~exist('old_RGB','var') | isempty(old_RGB)
      old_RGB = 0;
   end

   if ~exist('tolerance','var') | isempty(tolerance)
      tolerance = 0.1;
   end

   if ~exist('preferredForm','var') | isempty(preferredForm)
      preferredForm= 's';				% Jeff
   end

   nii = load_nii(original_fn, [], [], [], [], old_RGB, tolerance, preferredForm);
   M = diag(nii.hdr.dime.pixdim(2:5));
   M(1:3,4) = -M(1:3,1:3)*(nii.hdr.hist.originator(1:3)-1)';
   M(1,:) = -1*M(1,:);
   nii.hdr.hist.sform_code = 1;
   nii.hdr.hist.srow_x = M(1,:);
   nii.hdr.hist.srow_y = M(2,:);
   nii.hdr.hist.srow_z = M(3,:);
   save_nii(nii, flipped_fn);

   return;					% flip_lr


function [scores, candidateIds] = cnn_computeScores_pairwiseModel( net, imdb, getBatch, varargin )
%cnn_computeScores_pairwiseModel computes the scores using the structure network

if ~exist('varargin', 'var')
    varargin = {};
end

%% compute results w.r.t. patches
opts = struct;
opts.conserveMemory = true;
opts.sync = true;
opts.imageSet = 1 : size( imdb.imageFiles, 4 );
opts.scoreMode = 'maxMarginals';
% parse input
opts = vl_argparse(opts, varargin);

%% do the job
numImages = length( opts.imageSet );
scores = cell( max(opts.imageSet), 1);
candidateIds = cell( max(opts.imageSet), 1);

for iImageId = 1 : numImages
    iImage = opts.imageSet( iImageId );
    fprintf('Image %d/%d: ', iImageId, numImages);
    tImageStart = tic;

    [patchData, patchLabels, patchInfo] = getBatch( imdb, iImage );
    curNumCandidates = size( patchData, 4 );
    fprintf('patches=%d, ', curNumCandidates );

    [~, ~, predictions] = vl_structuredNetwork_pairwiseModel(net, patchData, [], patchLabels, [], ...
        'computeMaxMarginals', true, ...
        'disableDropout', true, ...
        'conserveMemory', opts.conserveMemory, ...
        'sync', opts.sync);
    maxMarginals = predictions{1}.maxMarginals;

    candidateIds{ iImage } = int32( patchInfo.candidateIds{1}(:) );

    switch opts.scoreMode
        case 'maxMarginals'
            curScores = maxMarginals(:, 1) - maxMarginals(:, 2);
        otherwise
            error('cnn_computeScores_pairwiseModel:unknownScoreMode', 'options scoreMode is of incorrect value');
    end

    curScores = curScores(:);
    if numel(curScores) ~= numel( candidateIds{iImage} )
        error('cnn_computeScores_pairwiseModel:inconsistentCandidates', 'something went wrong')
    end
    scores{ iImage } = single( curScores );

    fprintf('time: %fs\n', toc(tImageStart) );
end

end


function y = pcone(z,x,y,alpha)
%PCONE Defines a power cone x^alpha y ^(1-alpha) > |z|
%
% Input
%    z,y,x   : sclar SDPVAR objects.
%    alpha   : scalar double 0<=alpha<=1
%
% Example
%    F = pcone(z,x,y,alpha)
%
% An alternative syntax with only one argument is also possible
%    F = pcone(z)
%
%
% See also CONE

if numel(z)>1
    error('x must be a scalar')
end
if numel(x)>1
    error('x must be a scalar')
end
if numel(y)>1
    error('y must be a scalar')
end

try
    y = [x;y;z;alpha];
    y.typeflag = 20;
    y = lmi(y);
catch
    rethrow(lasterror)
end


function [gx,dgdx] = g_RFX(x,P,u,in)

gx = in.X*x;
dgdx = in.X';


% Test file for chebtech/simplify.m

function pass = test_simplify(pref)

% Get preferences:
if ( nargin < 1 )
    pref = chebtech.techPref();
end

% Generate a few random points to use as test values.
seedRNG(6178);
x = 2 * rand(100, 1) - 1;

% Tolerance for passing to simplify:
simptol = 1e-6;

for n = 1:2
    if ( n == 1 )
        testclass = chebtech1();
    else
        testclass = chebtech2();
    end

    %%
    % Test pathological inputs.

    % Empty CHEBTECH objects should be left alone.
    f = testclass.make();
    g = simplify(f);
    pass(n, 1) = isequal(f, g);

    % Unhappy CHEBTECH objects should be left alone.
    f = testclass.make(@(x) sqrt(x));
    g = simplify(f);
    pass(n, 2) = ~f.ishappy && isequal(f, g);

    %%
    % Test for a scalar-valued function:

    f = testclass.make(@(x) sin(100*(x + 0.1)));
    g = simplify(f, simptol);
    pass(n, 3) = abs(g.coeffs(end)) ~= 0;
    pass(n, 4) = length(g) < length(f);
    pass(n, 5) = norm(feval(f, x) - feval(g, x), inf) < 1e2*simptol*vscale(f);

    %%
    % Lengths of simplifications should be invariant under scaling:

    f1 = 1e-8*f;
    g1 = simplify(f1, simptol);
    pass(n, 6) = all(abs(g1.coeffs) >= eps*vscale(g1));
    pass(n, 7) = length(g1) == length(g);

    f2 = 1e8*f;
    g2 = simplify(f2, simptol);
    pass(n, 8) = all(abs(g2.coeffs) >= eps*vscale(g2));
    pass(n, 9) = length(g2) == length(g);

    %%
    % Test for an array-valued function:

    f = testclass.make(@(x) [sin(100*(x + 0.1)) cos(100*(x + 0.1)) exp(x)]);
    g = simplify(f, simptol);
    pass(n, 10) = any(abs(g.coeffs(1, :)) ~= 0);
    pass(n, 11) = length(g) < length(f);
    pass(n, 12) = all(norm(feval(f, x) - feval(g, x), inf) < ...
        10*max(simptol.*vscale(f)));

    %%
    % Try a contrived example which will leave a length 1 CHEBTECH:

    f = testclass.make(@(x) sin(100*(x + 0.1)));
    g = simplify(f, 1e20);
    pass(n, 13) = length(g) == 1;

    % Check that a long identically-zero CHEBTECH simplifies correctly:
    f = testclass.make(@(x) 0*x, [], struct('fixedLength', 8));
    g = simplify(f);
    pass(n, 14) = iszero(g) && (length(g) == 1);

end

end


function y = permute( x, order )

%   Disciplined convex/geometric programming information for PERMUTE:
%      PERMUTE(A,ORDER) imposes no convexity restrictions on A. ORDER
%      must be constant.

%
% Determine the permutation
%

s = x.size_;
ndxs = 1 : prod( s );
ndx2 = permute( reshape( ndxs, s ), order );

%
% Permute the data
%

b = x.basis_;
try
    b = x.basis_( :, ndx2 );
catch
    ndxs( ndx2( : ).' ) = ndxs;
    [ r, c, v ] = find( b );
    b = sparse( r, ndxs( c ), v, size( b, 1 ), size( b, 2 ) );
    clear r c v
end
y = cvx( size( ndx2 ), b );

% Copyright 2010 Michael C. Grant and Stephen P. Boyd.
% See the file COPYING.txt for full copyright information.
% The command 'cvx_where' will show where this file is located.


function c4_uniform_01_test ( )

%*****************************************************************************80
%
%% C4_UNIFORM_01_TEST tests C4_UNIFORM_01.
%
%  Licensing:
%
%    This code is distributed under the GNU LGPL license.
%
%  Modified:
%
%    29 June 2006
%
%  Author:
%
%    John Burkardt
%
  seed = 123456789;

  fprintf ( 1, '\n' );
  fprintf ( 1, 'C4_UNIFORM_01_TEST\n' );
  fprintf ( 1, '  C4_UNIFORM_01 computes pseudorandom complex values\n' );
  fprintf ( 1, '  in the unit circle.\n' );

  fprintf ( 1, '\n' );
  fprintf ( 1, '  The initial seed is %d\n', seed );
  fprintf ( 1, '\n' );

  for i = 1 : 10
    [ x, seed ] = c4_uniform_01 ( seed );
    fprintf ( 1, '  %6d  ( %f, %f )\n', i, real ( x ), imag ( x ) );
  end

  return
end


function [sumdetector,sumphi,sumspectr,peaks,bgpeaks] = proceed_spectra(spec,bg,range,peakpositions)
% procede Dubna spectra
%
% Input
%  spec  - spectra
%  bg    - background
%  range -
%  peakpositions - double
%
% Output
%  sumdetector - sum over all detectors (range x 72)
%  sumphi      - sum over all phi (range x 19)
%  sumspectr   - sum over all spectra (72 x 19)
%  peaks       - peak sums (peaks x 72 x 19)
%

coeff = fclencurt(19+18,0,1);
sumdetector = reshape(reshape(spec,[],size(spec,3))*coeff(1:19),size(spec,1),size(spec,2));
sumphi = sum(spec,2);
spec = spec - bg;
sumspectr = squeeze(sum(bg(range,:,:),1));
sumspectr = sumspectr ./ mean(sumspectr(:));
peaks = zeros(length(peakpositions),size(spec,2),size(spec,3));
for p = 1:size(peaks,1)
  peaks(p,:) = sum(spec(peakpositions(p,1):peakpositions(p,2),:),1);
end

bgpeaks = zeros(length(peakpositions),size(spec,2),size(spec,3));
for p = 1:size(peaks,1)
  bgpeaks(p,:) = sum(bg(peakpositions(p,1):peakpositions(p,2),:),1);
end


function [ops, stat, Fcell, FcellNeu]      = extractSignalsNoOverlaps2(ops, m, stat)

ops.saveNeuropil = getOr(ops, 'saveNeuropil', 0);

Nk = numel(stat);

Ny = numel(ops.yrange);
Nx = numel(ops.xrange);

% make new set of basis functions (larger coverage)
ops.neuropilRange = 10;

S = getNeuropilBasis(ops, Ny, Nx, 'raisedcosyne'); % 'raisedcosyne', 'Fourier'
S = normc(S);

% S = m.S;

S = reshape(S, [], size(S, ndims(S)));
nBasis = size(S,2);
S = double(S);

% initialize mask
maskNeu = ones(size(S,1), 1);

stat = getNonOverlapROIs(stat, Ny, Nx);

% create cell masks and cell exclusion areas
[stat, cellPix, cellMasks] = createCellMasks(stat, Ny, Nx);
cellMasks   = sparse(double(cellMasks(:,:)));

LtS = cellMasks * S;

% LtS = zeros(Nk, size(S,2));
% lam = cell(Nk,1);
% for k = 1:Nk
%     ix = stat(k).ipix(~stat(k).isoverlap);
%
%
%     lam{k} = stat(k).lam(~stat(k).isoverlap)';
%     lam{k} = lam{k}/sum(lam{k}(:));
%
%     maskNeu(stat(k).ipix)= 0;
%     if numel(ix)==0 || sum(~stat(k).isoverlap)==0
%         LtS(k,:) = 0;
%     else
%         LtS(k,:) = lam{k} * S(ix, :);
%     end
% end

% add all pixels within X um
if isfield(ops, 'exclFracCell') && ops.exclFracCell>0
    H       = fspecial('disk', round(ops.diameter * ops.exclFracCell));
    maskNeu = reshape(maskNeu, Ny, Nx);
    maskNeu = imfilter(maskNeu, H, 'replicate');
    maskNeu = single(maskNeu(:) > 1-1e-3);
end
%% get signals
S    = bsxfun(@times, S, maskNeu(:));
StS = S' * S;
StS = StS + 1e-2 * eye(size(StS));
iLtS = LtS * (StS\S');

nimgbatch = 2000;

ix = 0;
fclose all;
fid = fopen(ops.RegFile, 'r');

tic
F        = zeros(Nk, sum(ops.Nframes), 'single');
Fneu    = zeros(Nk, sum(ops.Nframes), 'single');
if ops.saveNeuropil
    Ntraces = zeros(nBasis, sum(ops.Nframes), 'single');
end
% S    = bsxfun(@times, S, maskNeu(:));

[Ly Lx] = size(ops.mimg1);

mimg1 = ops.mimg1(ops.yrange, ops.xrange);
% find indices of good clusters
while 1
    data = fread(fid,  Ly*Lx*nimgbatch, '*int16');
    if isempty(data)
       break;
    end
    data = reshape(data, Ly, Lx, []);

    data = data(ops.yrange, ops.xrange, :);
    data = double(data);

%     data = bsxfun(@minus, data, mimg1);

    NT   = size(data,3);
    data = reshape(data, [], NT);

    % process the data

%     Ftemp = zeros(Nk, NT, 'single');
%     for k = 1:Nk
%        ipix = stat(k).ipix(~stat(k).isoverlap)';
%        if ~isempty(ipix)
%            Ftemp(k,:) = lam{k} * data(ipix,:);
%        end
%     end
    Ftemp               = cellMasks * data;
    F(:,ix + (1:NT))    = Ftemp;

%     Tneu                = StS\(S' * data);
    Ftemp2              = iLtS * data; %LtS * Tneu;
    Fneu(:,ix + (1:NT)) = Ftemp2;

%     Fneu(:,ix + (1:NT))     = m.LtS * Fdeconv(1+Nk:end, :); % estimated neuropil
%     F(:,ix + (1:NT))        = Fneu(:,ix + (1:NT)) + Fdeconv(1:Nk, :); % estimated ROI signal

    if ops.saveNeuropil
        Tneu =  StS\(S' * data);
        Ntraces(:,ix + (1:NT)) = Tneu;
    end

    ix = ix + NT;
    if rem(ix, 3*NT)==0
        fprintf('Frame %d done in time %2.2f \n', ix, toc)
    end
end
fclose(fid);

%%
% get activity stats
[stat, F, Fneu] = getActivityStats(ops, stat, F, Fneu);

%
csumNframes = [0 cumsum(ops.Nframes)];
Fcell       = cell(1, length(ops.Nframes));
FcellNeu    = cell(1, length(ops.Nframes));
for i = 1:length(ops.Nframes)
    Fcell{i}     = F(:, csumNframes(i) + (1:ops.Nframes(i)));
    FcellNeu{i}  = Fneu(:, csumNframes(i) + (1:ops.Nframes(i)));
end

if getOr(ops, 'saveNeuropil', 0)
    S = reshape(S, numel(ops.yrange), numel(ops.xrange), nBasis);
    save(sprintf('%s/NEU_%s_%s_plane%d.mat', ops.ResultsSavePath, ...
        ops.mouse_name, ops.date, ops.iplane),  'ops', 'S', 'Ntraces', '-v7.3')
end


function grid2mri_interp = grid_interp_mri_seeg(GridLoc, MRI)
% GRID_INTERP_MRI_SEEG: Interpolate a grid of points into a MRI.
%
% USAGE:  grid2mri_interp = grid_interp_mri(GridLoc, MRI)
%
% INPUT:
%     - GridLoc     : [Nx3] matrix, 3D positions of the volume grid points
%     - MRI         : Brainstorm MRI structure
% OUTPUT:
%     - grid2mri_interp : Sparse matrix [nVoxels, nGridLoc]

% @=============================================================================
% This function is part of the Brainstorm software:
% https://neuroimage.usc.edu/brainstorm
%
% Copyright (c) University of Southern California & McGill University
% This software is distributed under the terms of the GNU General Public License
% as published by the Free Software Foundation. Further details on the GPLv3
% license can be found at http://www.gnu.org/copyleft/gpl.html.
%
% FOR RESEARCH PURPOSES ONLY. THE SOFTWARE IS PROVIDED "AS IS," AND THE
% UNIVERSITY OF SOUTHERN CALIFORNIA AND ITS COLLABORATORS DO NOT MAKE ANY
% WARRANTY, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO WARRANTIES OF
% MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE, NOR DO THEY ASSUME ANY
% LIABILITY OR RESPONSIBILITY FOR THE USE OF THIS SOFTWARE.
%
% For more information type "brainstorm license" at command prompt.
% =============================================================================@
%
% Authors: Francois Tadel, 2017-2020

% ===== CHECK MRI =====
% Check that MRI SCS is well defined
if ~isfield(MRI,'SCS') || ~isfield(MRI.SCS,'R') || ~isfield(MRI.SCS,'T') || isempty(MRI.SCS.R) || isempty(MRI.SCS.T)
    error(['MRI SCS (Subject Coordinate System) was not defined or subjectimage file is from another version of Brainstorm.' 10 10,...
           'Please define the SCS fiducials on this MRI.']);
end
cubeSize = size(MRI.Cube(:,:,:,1));
% Convert coordinates
GridLoc = cs_convert(MRI, 'scs', 'voxel', GridLoc);

% ===== CHECK VERTICES LOCATION =====
% Get all the vertices that are outside the MRI volume
iOutsideVert = find((GridLoc(:,1) >= cubeSize(1)) | (GridLoc(:,1) < 2) | ...
                    (GridLoc(:,2) >= cubeSize(2)) | (GridLoc(:,2) < 2) | ...
                    (GridLoc(:,3) >= cubeSize(3)) | (GridLoc(:,3) < 2));
% Compute percentage of vertices outside the MRI
percentOutside = length(iOutsideVert) / length(GridLoc);
% If more than 95% vertices are outside the MRI volume : exit with ar error message
if (percentOutside > .95)
    grid2mri_interp = [];
    java_dialog('error', ['SEEG/ECOG contacts are not registered with the MRI.' 10 'Please try to import the position of the contacts again.'], 'SEEG/ECOG -> MRI');
    return;
% If more than 40% vertices are outside the MRI volume : display warning message
elseif (percentOutside > .4)
    java_dialog('warning', 'SEEG/ECOG contacts do not seem to be registered with the MRI.', 'SEEG/ECOG -> MRI');
end

%% ===== COMPUTE INTERPOLATION =====
% Initialize interpolation matrix
N = size(GridLoc,1);
grid2mri_interp = sparse([],[],[], prod(cubeSize), N, N);
% Generate a 3x3 block
[Xs, Ys, Zs] = meshgrid([-1,0,1],[-1,0,1],[-1,0,1]);
% Add entry for each grid point
for i = 1:N
    % Find the closest voxel to the SEEG contact
    P = round(GridLoc(i,:));
    % Add the 3x3 block around the center
    X = min(max(1, P(1)+Xs(:)), cubeSize(1));
    Y = min(max(1, P(2)+Ys(:)), cubeSize(2));
    Z = min(max(1, P(3)+Zs(:)), cubeSize(3));
    indVol = sub2ind(cubeSize, X, Y, Z);
    % Set the voxel value to exactly the contact value
    grid2mri_interp(indVol,i) = 1;
end


function [X,n] = shiftdim(varargin)
% SHIFTDIM (overloaded)

Y = varargin{1};
X = Y;
X.basis = [];
for i = 1:size(Y.basis,2)
    base = reshape(full(Y.basis(:,i)),[X.dim(1) X.dim(2)]);
    [base,n] = shiftdim(base,varargin{2:end});
    X.basis = [X.basis sparse(base(:))];
end
[X.dim(1), X.dim(2)] = size(base);
X.conicinfo = [0 0];
X = clean(X);


function determ = sweet3_determinant ( )

%*****************************************************************************80
%
%% SWEET3_DETERMINANT returns the determinant of the SWEET3 matrix.
%
%  Licensing:
%
%    This code is distributed under the GNU LGPL license.
%
%  Modified:
%
%    30 January 2015
%
%  Author:
%
%    John Burkardt
%
%  Parameters:
%
%    Output, real DETERM, the determinant.
%
  determ = - 5.4056067E+07;

  return
end


function [cl1,cl2,dat1,dat2] = iimg_cluster_intersect(dat1,dat2,volInfo)
% Prunes two image data vectors (dat1 and dat2) assumed to contain suprathreshold
% contiguous clusters ("blobs") by saving only those blobs that have one or
% more significant (nonzero) elements in both images
%
% :Usage:
% ::
%
%     [cl1,cl2,dat1,dat2] = iimg_cluster_intersect(dat1,dat2,volInfo)
%
% :Inputs:
%
%   **volInfo.xyzlist:**
%        must contain xyz coordinates corresponding to dat1 and dat2
%
%   **dat1 and dat2:**
%        can be either image-length or in-mask length vectorized images
%
% Try iimg_threshold to create dat vectors from Analyze images (e.g.,
% statistic images)
%
% The outputs cl1 and cl2 are the overlap (intersection) clusters, in the
% space of dat1 (cl1) and dat2 (cl2).  The outputs dat1 and dat2 are the
% 'pruned' intersection data vectors.
%
% ..
%    tor wager, july 06
% ..

% prune dat1 with sig values in dat2
[dat1] = iimg_cluster_prune(dat1,dat2,volInfo);

% do the reverse
[dat2] = iimg_cluster_prune(dat2,dat1,volInfo);

% make clusters
cl1 = iimg_indx2clusters(dat1,volInfo);
cl2 = iimg_indx2clusters(dat2,volInfo);

return


function drawSurfPatch(u, v, z, varargin)
%DRAWSURFPATCH Draw a 3D surface patch, with 2 parametrized surfaces
%
%   usage:
%   drawSurfPatch(u, v, zuv)
%   where u, v, and zuv are three matrices the same size, u and
%   corresponding to each parameter, and zuv being equal to a function of u
%   and v.
%
%   drawSurfPatch(u, v, zuv, p0)
%   If p0 is specified, two lines with u(p0(1)) and v(p0(2)) are drawn on
%   the surface, and corresponding tangent are also shown.
%
%
%   ---------
%
%   author : David Legland
%   INRA - TPV URPOI - BIA IMASTE
%   created the 24/05/2005.
%

%   HISTORY
%   2005-06-08 add doc.
%   2007-01-04 remove unused variables and change function name
%   2010-03-08 code cleanup, use drawPolyline3d

% prepare figure
hold on;

% draw the surface interior
surf(u, v, z, 'FaceColor', 'g', 'EdgeColor', 'none');

% draw the surface boundaries
drawPolyline3d(u(1,:), v(1,:), z(1,:))
drawPolyline3d(u(end,:), v(end,:), z(end,:))
drawPolyline3d(u(:,end), v(:,end), z(:,end))
drawPolyline3d(u(:,1), v(:,1), z(:,1))

% eventually draw two perpendicular lines on the surface
if ~isempty(varargin)
    pos = varargin{1};
    drawPolyline3d(u(pos(1),:), v(pos(1),:), z(pos(1),:));
    drawPolyline3d(u(:,pos(2)), v(:,pos(2)), z(:,pos(2)));
end


function a_n = extractAxisCoeffs(a_nm)
%EXTRACTAXISCOEFFS Exctract the N+1 coeffs of m=0 from the full (order+1)^2
% coefficient vector
%
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%
% EXTRACTAXISCOEFFS.M - 11/7/2013
% Archontis Politis, archontis.politis@aalto.fi
%
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%

N = sqrt(size(a_nm,1))-1;
nSets = size(a_nm,2);
a_n = zeros(N+1,nSets);
for ns=1:nSets
    for n=0:N
        a_n(n+1,ns) = a_nm(n^2 + n + 1);
    end
end

end