% Most Software Machine Data File

%% scanimage.SI (ScanImage)

% Global microscope properties
objectiveResolution = 27.5;     % Resolution of the objective in microns/degree of scan angle

% Data file location

% Custom Scripts
startUpScript = 'ScanImageStartScript';     % Name of script that is executed in workspace 'base' after scanimage initializes
shutDownScript = '';     % Name of script that is executed in workspace 'base' after scanimage exits

fieldCurvatureZs = [];     % Field curvature for mesoscope
fieldCurvatureRxs = [];     % Field curvature for mesoscope
fieldCurvatureRys = [];     % Field curvature for mesoscope
useJsonHeaderFormat = false;     % Use JSON format for TIFF file header

fieldCurvatureTip = 0;
fieldCurvatureTilt = 0;

%% scanimage.components.Motors (SI Motors)
% SI Stage/Motor Component.
motorXYZ = {'ScopeHolder' 'ScopeHolder' 'ScopeHolder'};     % Defines the motor for ScanImage axes X Y Z.
motorAxisXYZ = [2 1 3];     % Defines the motor axis used for Scanimage axes X Y Z.
scaleXYZ = [1 -1 1];     % Defines scaling factors for axes.
backlashCompensation = [0 0 0];     % Backlash compensation in um (positive or negative)

%% scanimage.components.scan2d.RggScan (MINI2P_001)

acquisitionDeviceId = 'vDAQ0';     % RDI Device ID
acquisitionEngineIdx = 1;

resonantScanner = 'MEMS2000Hz';     % Name of the resonant scanner
xGalvo = '';     % Name of the x galvo scanner
yGalvo = 'MEMS2000Hz_slowaxis';     % Name of the y galvo scanner
beams = {'920nm AOM'};     % beam device names
fastZs = {'TLens'};     % fastZ device names
shutters = {'Laser' 'MEMS' 'PMT' 'LED'};     % shutter device names

channelsInvert = [true true false false];     % Logical: Specifies if the input signal is inverted (i.e., more negative for increased light signal)
keepResonantScannerOn = false;     % Always keep resonant scanner on to avoid drift and settling time issues

externalSampleClock = false;     % Logical: use external sample clock connected to the CLK IN terminal of the FlexRIO digitizer module
externalSampleClockRate = 8e+07;     % [Hz]: nominal frequency of the external sample clock connected to the CLK IN terminal (e.g. 80e6); actual rate is measured on FPGA
externalSampleClockMultiplier = 1;     % Multiplier to apply to external sample clock

extendedRggFov = 0;     % If true and x galvo is present, addressable FOV is combination of resonant FOV and x galvo FOV.

% Advanced/Optional
PeriodClockDebounceTime = 1e-07;     % [s] time the period clock has to be stable before a change is registered
TriggerDebounceTime = 5e-07;     % [s] time acquisition, stop and next trigger to be stable before a change is registered
reverseLineRead = 0;     % flips the image in the resonant scan axis
defaultFlybackTimePerFrame = 0.001;     % [s] default time to allow galvos to fly back after one frame is complete. overridden by cfg file
defaultFlytoTimePerScanfield = 0.001;     % [s] time to allow galvos to fly from one scanfield to the next. overridden by cfg file

% Aux Trigger Recording, Photon Counting, and I2C are mutually exclusive

% Aux Trigger Recording
auxTriggersTimeDebounce = 1e-07;     % [s] time after an edge where subsequent edges are ignored
auxTriggerLinesInvert = [false false false false];     % [logical] 1x4 vector specifying polarity of aux trigger inputs
auxTrigger1In = '';     % Digital input lines for aux trigger 1
auxTrigger2In = '';     % Digital input lines for aux trigger 2
auxTrigger3In = '';     % Digital input lines for aux trigger 3
auxTrigger4In = '';     % Digital input lines for aux trigger 4

% Signal Conditioning
disableMaskDivide = [false false false false];     % disable averaging of samples into pixels; instead accumulate samples

% I2C
i2cEnable = false;
i2cSdaPort = '';
i2cSclPort = '';
i2cAddress = 0;     % [byte] I2C address of the FPGA
i2cDebounce = 1e-07;     % [s] time the I2C signal has to be stable high before a change is registered
i2cStoreAsChar = false;     % if false, the I2C packet bytes are stored as a uint8 array. if true, the I2C packet bytes are stored as a string. Note: a Null byte in the packet terminates the string
i2cSendAck = true;     % When enabled FPGA confirms each packet with an ACK bit by actively pulling down the SDA line

% Laser Trigger
LaserTriggerPort = '';     % Digital input where laser trigger is connected.

% Trigger Outputs
frameClockOut = '/vDAQ0/D3.7';     % Output line for the frame clock
lineClockOut = '';     % Output line for the line clock
beamModifiedLineClockOut = '';     % Output line for beam clock
volumeTriggerOut = '';     % Output line for the volume clock

% Calibration data
scannerToRefTransform = [1 0 0;0 1 0;0 0 1];
virtualChannelSettings = [];
LaserTriggerDebounceTicks = 1;

enableHostPixelCorrection = false;
hostPixelCorrectionMultiplier = 500;

%% dabs.mirrorcle.ResonantAxis (MEMS2000Hz)
hAOZoom = '/vDAQ0/AO1';     % Analog output channel to be used to control resonant axis of the mirror e.g. '/vDAQ0/AO0'
hDOSync = '/vDAQ0/D1.7';     % String identifying the digital output for the sync signal e.g. '/vDAQ0/D0.1
hDOFilterX = '/vDAQ0/D3.2';     % String identifying the digital output for the X filter clock e.g. '/vDAQ0/D0.2
hDOFilterY = '/vDAQ0/D3.1';     % String identifying the digital output for the Y filter clock e.g. '/vDAQ0/D0.3

inputVoltageRange_Vpp = 8;     % Max input voltage range of the controller
angularRange_deg = 16;     % Max angular range of the device

% Default scan settings
syncPhase_deg = 100;
rampTime_s = 0;
xFilterClockFreq_Hz = 300000;
yFilterClockFreq_Hz = 150000;
xFilterClockEnable = 1;
yFilterClockEnable = 1;
nominalFrequency_Hz = 2000;

% Calibration Settings
amplitudeToLinePhaseMap = [4 -2.912e-06;4.5 -3.144e-06;5 -3.056e-06;5.333 -3.48e-06;5.714 -2.56e-06;6 -3.432e-06;6.154 -3.48e-06;6.667 -3.352e-06;7.273 -5.7912e-05;7.5 -3.416e-06;7.692 -3.504e-06;7.727 -3.416e-06;7.72727 0;8 -3.512e-06;8.182 6.3208e-05;8.333 -3.472e-06;8.5 -3.728e-06;8.636 -3.48e-06;9 -3.576e-06;9.091 -3.48e-06;9.5 -3.576e-06;10 0.00011808;11 -3.072e-06];     % translates an amplitude (degrees) to a line phase (seconds)
amplitudeLUT = zeros(0,2);     % translates a nominal amplitude (degrees) to an output amplitude (degrees)

%% dabs.generic.DigitalShutter (Laser)
DOControl = '/vDAQ0/D0.0';     % control terminal  e.g. '/vDAQ0/DIO0'
invertOutput = false;     % invert output drive signal to shutter
openTime_s = 0.1;     % settling time for shutter in seconds

%% dabs.generic.DigitalShutter (MEMS)
DOControl = '/vDAQ0/D0.1';     % control terminal  e.g. '/vDAQ0/DIO0'
invertOutput = false;     % invert output drive signal to shutter
openTime_s = 0.1;     % settling time for shutter in seconds

%% dabs.generic.DigitalShutter (PMT)
DOControl = '/vDAQ0/D0.2';     % control terminal  e.g. '/vDAQ0/DIO0'
invertOutput = false;     % invert output drive signal to shutter
openTime_s = 0.1;     % settling time for shutter in seconds

%% dabs.generic.DigitalShutter (LED)
DOControl = '/vDAQ0/D0.3';     % control terminal  e.g. '/vDAQ0/DIO0'
invertOutput = false;     % invert output drive signal to shutter
openTime_s = 0.1;     % settling time for shutter in seconds

%% dabs.generic.BeamModulatorFastAnalog (920nm AOM)
AOControl = '/vDAQ0/AO2';     % control terminal  e.g. '/vDAQ0/AO0'
AIFeedback = '';     % feedback terminal e.g. '/vDAQ0/AI0'

outputRange_V = [0 2];     % Control output range in Volts
feedbackUsesRejectedLight = false;     % Indicates if photodiode is in rejected path of beams modulator.
calibrationOpenShutters = {};     % List of shutters to open during the calibration. (e.g. {'Shutter1' 'Shutter2'}

powerFractionLimit = 1;     % Maximum allowed power fraction (between 0 and 1)

% Calibration data for the laser
powerFraction2ModulationVoltLut = [0 0;0.0157 0.2;0.0541 0.4;0.1165 0.6;0.2009 0.8;0.3047 1;0.4247 1.2;0.5583 1.4;0.7005 1.6;0.8493 1.8;1 2];
powerFraction2PowerWattLut = [0 0;1 164.6];
powerFraction2FeedbackVoltLut = zeros(0,2);
feedbackOffset_V = 0;

% Advanced Settings. Note: these settings are unused for vDAQ based systems
modifiedLineClockIn = '';     % Terminal to which external beam trigger is connected. Leave empty for automatic routing via PXI/RTSI bus
frameClockIn = '';     % Terminal to which external frame clock is connected. Leave empty for automatic routing via PXI/RTSI bus
referenceClockIn = '';     % Terminal to which external reference clock is connected. Leave empty for automatic routing via PXI/RTSI bus
referenceClockRate = 1e+07;     % if referenceClockIn is used, referenceClockRate defines the rate of the reference clock in Hz. Default: 10e6Hz

%% dabs.legacy.motor.LegacyMotor (ScopeHolder)
% Motor used for X/Y/Z motion, including stacks.

controllerType = 'PI C884/C863';     % If supplied, one of {'sutter.mp285', 'sutter.mpc200', 'thorlabs.mcm3000', 'thorlabs.mcm5000', 'scientifica', 'pi.e665', 'pi.e816', 'npoint.lc40x', 'bruker.MAMC'}.
comPort = '';     % Integer identifying COM port for controller, if using serial communication
customArgs = {};     % Additional arguments to stage controller. Some controller require a valid stageType be specified
invertDim = '$$$''---''';     % string with one character for each dimension specifying if the dimension should be inverted. '+' for normal, '-' for inverted
positionDeviceUnits = [-0.001 -0.001 -0.001];     % 1xN array specifying, in meters, raw units in which motor controller reports position. If unspecified, default positionDeviceUnits for stage/controller type presumed.
velocitySlow = [];     % Velocity to use for moves smaller than motorFastMotionThreshold value. If unspecified, default value used for controller. Specified in units appropriate to controller type.
velocityFast = [];     % Velocity to use for moves larger than motorFastMotionThreshold value. If unspecified, default value used for controller. Specified in units appropriate to controller type.
moveCompleteDelay = 0.1;     % Delay from when stage controller reports move is complete until move is actually considered complete. Allows settling time for motor
moveTimeout = '';     % Default: 2s. Fixed time to wait for motor to complete movement before throwing a timeout error
moveTimeoutFactor = '';     % (s/um) Time to add to timeout duration based on distance of motor move command

%% dabs.generic.FastZPureAnalog (TLens)
AOControl = '/vDAQ0/AO3';     % control terminal  e.g. '/vDAQ0/AO0'
AIFeedback = '';     % feedback terminal e.g. '/vDAQ0/AI0'
FrameClockIn = '';     % frame clock input terminal e.g. '/Dev1/PFI0'

parkPositionUm = 0;     % park position in micron
travelRangeUm = [-250 10];     % travel range in micron

voltsPerUm = -0.032;     % volts per micron
voltsOffset = 0;     % volts that sets actuator to zero position

% Calibration Data for uTLens
positionLUT = [-240 -267.5;-230 -250.625;-220 -233.75;-210 -217.5;-200 -205;-190 -191.25;-180 -180;-170 -168.958;-160 -159.167;-150 -150;-140 -139.375;-130 -130;-120 -121.25;-110 -113.542;-100 -104.583;-90 -96.25;-80 -86.875;-70 -80;-60 -71.925;-50 -65;-40 -56.2;-30 -46.2;-20 -34.95;-10 -21.2;0 0;10 25];     % Position LUT
feedbackVoltLUT = zeros(0,2);     % [Nx2] lut translating feedback volts into position volts

%% dabs.generic.GalvoPureAnalog (MEMS2000Hz_slowaxis)
AOControl = '/vDAQ0/AO0';     % control terminal  e.g. '/vDAQ0/AO0'
AOOffset = '';     % control terminal  e.g. '/vDAQ0/AO0'
AIFeedback = '';     % feedback terminal e.g. '/vDAQ0/AI0'

angularRange = 6;     % total angular range in optical degrees (e.g. for a galvo with -20..+20 optical degrees, enter 40)
voltsPerOpticalDegrees = 1.3;     % volts per optical degrees for the control signal
parkPosition = 0;     % park position in optical degrees
slewRateLimit = Inf;     % Slew rate limit of the analog output in Volts per second

% Calibration settings
feedbackVoltLUT = zeros(0,2);     % [Nx2] lut translating feedback volts into position volts
offsetVoltScaling = 1;     % scalar factor for offset volts

voltsOffset = -0.3;


function [segmented] = ft_volumesegment(cfg, mri)

% FT_VOLUMESEGMENT segments an anatomical MRI. The behavior depends on the output requested. It can
% return probabilistic tissue maps of gray/white/csf compartments, a skull-stripped anatomy, or
% binary masks representing the brain surface, skull, or scalp surface.
%
% Use as
%   segmented = ft_volumesegment(cfg, mri)
% where the input mri should be a single anatomical volume that was for example read with
% FT_READ_MRI. For the purpose of creating binary masks of the brain or of the skull, you can also
% provide either the anatomical volume or the already segmented volume (with the probabilistic
% tissue maps) as input.
%
% The configuration structure can contain
%   cfg.output         = string or cell-array of strings, see below (default = 'tpm')
%   cfg.spmversion     = string, 'spm2', 'spm8', 'spm12' (default = 'spm12')
%   cfg.spmmethod      = string, 'old', 'new', 'mars', the algorithm used when
%                        cfg.spmversion='spm12' (default = 'old')
%   cfg.opts           = structure  with spm-version specific options. See the
%                        code and/or the SPM-documentation for more detail.
%   cfg.template       = filename of the template anatomical MRI (default =
%                        '/spm2/templates/T1.mnc' or '/spm8/templates/T1.nii')
%   cfg.tpm            = cell-array containing the filenames of the tissue probability maps
%   cfg.name           = string for output filename
%   cfg.write          = 'no' or 'yes' (default = 'no'), writes the probabilistic tissue maps
%                        to SPM compatible analyze (spm2), or nifti (spm8 or spm12) files,
%                        with the following suffix for spm2
%                         _seg1, for the gray matter segmentation
%                         _seg2, for the white matter segmentation
%                         _seg3, for the csf segmentation
%                        or with the following prefix for spm8 and spm12 with spmmethod='old'
%                         c1, for the gray matter segmentation
%                         c2, for the white matter segmentation
%                         c3, for the csf segmentation
%                        and with spm12 with spmmethod='new' there will be 3 additional tissue types
%                         c4, for the bone segmentation
%                         c5, for the soft tissue segmentation
%                         c6, for the air segmentation
%                        When using spm12 with spmmethod='mars', the tpms will be postprocessed
%                        with the mars toolbox, yielding smoother segmentations in general.
%   cfg.brainsmooth    = 'no', or scalar, the FWHM of the gaussian kernel in voxels, (default = 5)
%   cfg.scalpsmooth    = 'no', or scalar, the FWHM of the gaussian kernel in voxels, (default = 5)
%   cfg.skullsmooth    = 'no', or scalar, the FWHM of the gaussian kernel in voxels, (default = 5)
%                        this parameter is only used when the segmentation contains 6 tisuse types,
% %                      including 'bone'
%   cfg.brainthreshold = 'no', or scalar, relative threshold value which is used to threshold the
%                        tpm in order to create a volumetric brainmask (see below), (default = 0.5)
%   cfg.scalpthreshold = 'no', or scalar, relative threshold value which is used to threshold the
%                        anatomical data in order to create a volumetric scalpmask (see below),
%                        (default = 0.1)
%   cfg.skullthreshold = 'no', or scalar, relative threshold value which is used to threshold the
%                        anatomical data in order to create a volumetric scalpmask (see below),
%                        (default = 0.5). this parameter is only used when the segmentation
%                        contains 6 tissue types, including 'bone'
%   cfg.downsample     = integer, amount of downsampling before segmentation (default = 1, which
%                        means no downsampling)
%
% The desired segmentation output is specified with cfg.output as a string or cell-array of strings
% and can contain
%   'tpm'         - tissue probability map for csf, white and gray matter
%   'brain'       - binary representation of the brain (the combination of csf, white and gray matter)
%   'skull'       - binary representation of the skull
%   'scalp'       - binary representation of the scalp
%   'skullstrip'  - anatomy with only the brain
%
% Example use:
%   cfg        = [];
%   segmented  = ft_volumesegment(cfg, mri) will segmented the anatomy and will output the
%                segmentation result as 3 probabilistic masks in gray, white and csf.
%
%   cfg        = [];
%   cfg.output = 'skullstrip';
%   segmented  = ft_volumesegment(cfg, mri) will generate a skull-stripped anatomy based on a
%                brainmask generated from the probabilistic tissue maps. The skull-stripped anatomy
%                is stored in the field segmented.anatomy.
%
%   cfg        = [];
%   cfg.output = {'brain' 'scalp' 'skull'};
%   segmented  = ft_volumesegment(cfg, mri) will produce a volume with 3 binary masks, representing
%                the brain surface, scalp surface, and skull which do not overlap.
%
%   cfg        = [];
%   cfg.output = {'scalp'};
%   segmented  = ft_volumesegment(cfg, mri) will produce a volume with a binary mask (based on the
%                anatomy), representing the border of the scalp surface (i.e., everything inside the
%                surface is also included). Such representation of the scalp is produced faster,
%                because it doesn't require to create the tissue probabilty maps prior to creating
%                the mask.
%
% It is not possible to request tissue-probability maps (tpm) in combination with binary masks
% (brain, scalp or skull) or with a skull-stripped anatomy. The output will return only the probabilistic
% maps in gray, white and csf. However, when a segmentation with the probabilistic gray, white
% and csf representations is available, it is possible to use it as input to create the brain or skull
% binary mask. For example:
%   cfg           = [];
%   cfg.output    = {'tpm'};
%   segment_tpm   = ft_volumesegment(cfg, mri);
%   cfg.output    = {'brain'};
%   segment_brain = ft_volumesegment(cfg, segment_tpm);
%
% For the SPM-based segmentation to work, the coordinate frame of the input MRI needs to be
% approximately coregistered to the templates of the probabilistic tissue maps. The templates
% are defined in SPM/MNI-space. FieldTrip attempts to do an automatic alignment based on the
% coordsys-field in the MRI, and if this is not present, based on the coordsys-field in the cfg.
% If none of them is specified the FT_DETERMINE_COORDSYS function is used to interactively
% assess the coordinate system in which the MRI is expressed.
%
% The template MRI is defined in SPM/MNI-coordinates, see also http://bit.ly/2sw7eC4
%   x-axis pointing to the right ear
%   y-axis along the acpc-line
%   z-axis pointing to the top of the head
%   origin in the anterior commissure.
% Note that the segmentation requires the template MRI to be in SPM coordinates.
%
% To facilitate data-handling and distributed computing you can use
%   cfg.inputfile   =  ...
%   cfg.outputfile  =  ...
% If you specify one of these (or both) the input data will be read from a *.mat file on disk and/or
% the output data will be written to a *.mat file. These mat files should contain only a single
% variable, corresponding with the input/output structure.
%
% See also FT_READ_MRI, FT_DETERMINE_COORDSYS, FT_PREPARE_HEADMODEL

% Copyright (C) 2007-2017, Jan-Mathijs Schoffelen, Robert Oostenveld
%
% This file is part of FieldTrip, see http://www.fieldtriptoolbox.org
% for the documentation and details.
%
%    FieldTrip 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.
%
%    FieldTrip 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 FieldTrip. If not, see <http://www.gnu.org/licenses/>.
%
% $Id$

% these are used by the ft_preamble/ft_postamble function and scripts
ft_revision = '$Id$';
ft_nargin   = nargin;
ft_nargout  = nargout;

% do the general setup of the function
ft_defaults
ft_preamble init
ft_preamble debug
ft_preamble loadvar    mri
ft_preamble provenance mri

% the ft_abort variable is set to true or false in ft_preamble_init
if ft_abort
  return
end

% this is not supported any more as of 26/10/2011
if ischar(mri)
  ft_error('please use cfg.inputfile instead of specifying the input variable as a string');
end

% check if the input data is valid for this function
mri = ft_checkdata(mri, 'datatype', 'volume', 'feedback', 'yes', 'hasunit', 'yes', 'hascoordsys', 'yes');

% ensure that old and unsupported options are not being relied on by the end-user's script
% instead of specifying cfg.coordsys, the user should specify the coordsys in the data
cfg = ft_checkconfig(cfg, 'forbidden', {'units', 'coordsys', 'inputcoord', 'inputcoordsys', 'coordinates'});
cfg = ft_checkconfig(cfg, 'renamedval', {'output', 'skin', 'scalp'});

% set the defaults
cfg.output           = ft_getopt(cfg, 'output',         'tpm');
cfg.downsample       = ft_getopt(cfg, 'downsample',     1);
cfg.spmversion       = ft_getopt(cfg, 'spmversion',     'spm12');
cfg.write            = ft_getopt(cfg, 'write',          'no');
cfg.spmmethod        = ft_getopt(cfg, 'spmmethod',      'old'); % doing old-style in case of spm12

% set default for smooth and threshold
cfg.brainsmooth      = ft_getopt(cfg, 'brainsmooth',    ''); % see also below
cfg.scalpsmooth      = ft_getopt(cfg, 'scalpsmooth',    ''); % see also below
cfg.skullsmooth      = ft_getopt(cfg, 'skullsmooth',    ''); % see also below
cfg.brainthreshold   = ft_getopt(cfg, 'brainthreshold', ''); % see also below
cfg.scalpthreshold   = ft_getopt(cfg, 'scalpthreshold', ''); % see also below

% earlier version of smooth and threshold specification
cfg.smooth           = ft_getopt(cfg, 'smooth',      '');
cfg.threshold        = ft_getopt(cfg, 'threshold',   '');

% chech whether earlier version of smooth and threshold was specified
if ~(isempty(cfg.smooth))
  if isempty(cfg.brainsmooth)
    cfg.brainsmooth = cfg.smooth;
    ft_warning('Smoothing can be specified separately for scalp and brain. User-specified smoothing will be applied for brainmask.')
  end
  if isempty(cfg.scalpsmooth)
    cfg.scalpsmooth = cfg.smooth;
    ft_warning('Smoothing can be specified separately for scalp and brain. User-specified smoothing will be applied for scalpmask.')
  end
end
if ~(isempty(cfg.threshold))
  if isempty(cfg.brainthreshold)
    cfg.brainthreshold = cfg.threshold;
    ft_warning('Threshold can be specified separately for scalp and brain. User-specified threshold will be applied for brainmask.')
  end
  if isempty(cfg.scalpthreshold)
    cfg.scalpthreshold = cfg.threshold;
    ft_warning('Threshold can be specified separately for scalp and brain. User-specified threshold will be applied for scalpmask.')
  end
end
% then set defaults again
cfg.brainsmooth      = ft_getopt(cfg, 'brainsmooth',      5);
cfg.scalpsmooth      = ft_getopt(cfg, 'scalpsmooth',      5);
cfg.skullsmooth      = ft_getopt(cfg, 'skullsmooth',      5);
cfg.brainthreshold   = ft_getopt(cfg, 'brainthreshold',   0.5);
cfg.scalpthreshold   = ft_getopt(cfg, 'scalpthreshold',   0.1);
cfg.skullthreshold   = ft_getopt(cfg, 'skullthreshold',   0.5);

% check that the preferred SPM version is on the path
ft_hastoolbox(cfg.spmversion, 1);

if ~isfield(cfg, 'name')
  if ~strcmp(cfg.write, 'yes')
    tmp = tempname;
    cfg.name = tmp;
  else
    ft_error('you must specify the output filename in cfg.name');
  end
end
[pathstr, name] = fileparts(cfg.name);
cfg.name = fullfile(pathstr, name); % remove any possible file extension, to be added later

if ~iscell(cfg.output)
  % ensure it to be cell, to allow for multiple outputs
  cfg.output = {cfg.output};
end

% check whether SPM is needed to generate tissue probability maps
if numel(cfg.output) == 1 && strcmp('scalp', cfg.output)
  needtpm = 0; % not needed for (cummulative type) scalpmask
else
  needtpm = any(ismember(cfg.output, {'tpm' 'gray' 'white' 'csf' 'brain' 'skull' 'skullstrip'}));
end

tissue  = isfield(mri, {'gray', 'white', 'csf', 'bone', 'softtissue', 'air'});
ntissue = sum(tissue);
if ntissue==6
  % this is new-style segmentation
  hastpm = ~islogical(mri.gray) && ~islogical(mri.white) && ~islogical(mri.csf);  % tpm should be probabilistic and not binary!
elseif all(tissue(1:3)==true)
  hastpm = ~islogical(mri.gray) && ~islogical(mri.white) && ~islogical(mri.csf);  % tpm should be probabilistic and not binary!
elseif any(tissue)
  ft_warning('the input seems to contain tissue probability maps, but is incomplete for this function');
  hastpm = false;
else
  hastpm = false;
end

if needtpm && ~hastpm
  % spm needs to be used for the creation of the tissue probability maps
  dotpm = 1;
else
  dotpm = 0;
end

if cfg.downsample~=1
  % optionally downsample the anatomical and/or functional volumes
  tmpcfg = keepfields(cfg, {'downsample', 'spmversion', 'showcallinfo', 'trackcallinfo', 'trackusage', 'trackdatainfo', 'trackmeminfo', 'tracktimeinfo', 'checksize'});
  tmpcfg.smooth = 'no'; % smoothing is done in ft_volumesegment itself
  mri = ft_volumedownsample(tmpcfg, mri);
  % restore the provenance information
  [cfg, mri] = rollback_provenance(cfg, mri);
end

%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
% create the tissue probability maps if needed
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
if dotpm

  if isdeployed
    % ensure that these exist in this case, otherwise deal with the defaults below
    cfg = ft_checkconfig(cfg, 'required', {'template' 'tpm'});
  end

  % remember the original transformation matrix coordinate system
  original = [];
  original.transform = mri.transform;
  original.coordsys  = mri.coordsys;
  if isfield(mri, 'unit')
    original.unit = mri.unit;
  else
    mri = ft_determine_units(mri); % guess the unit field if not present
    original.unit = mri.unit;
  end
  mri = ft_convert_units(mri, 'mm');
  if isdeployed
    mri = ft_convert_coordsys(mri, 'acpc', 2, cfg.template);
  else
    mri = ft_convert_coordsys(mri, 'acpc');
  end

  % flip and permute the 3D volume itself, so that the voxel and
  % headcoordinates approximately correspond this improves the convergence
  % of the segmentation algorithm
  [mri, permutevec, flipflags] = align_ijk2xyz(mri);

  switch lower(cfg.spmversion)
    case 'spm2'
      cfg.template = ft_getopt(cfg, 'template', fullfile(spm('Dir'), 'templates', 'T1.mnc'));
      opts          = ft_getopt(cfg, 'opts');
      opts.estimate = ft_getopt(opts, 'estimate');
      opts.write    = ft_getopt(opts, 'write');
      opts.estimate.affreg = ft_getopt(opts.estimate, 'affreg');

      VF = ft_write_mri([cfg.name, '.img'], mri.anatomy, 'transform', mri.transform, 'spmversion', cfg.spmversion, 'dataformat', 'analyze_img');

      % set the spm segmentation defaults (from /opt/spm2/spm_defaults.m script)
      opts.estimate.priors = ft_getopt(opts.estimate, 'priors', ...
        char(fullfile(spm('Dir'), 'apriori', 'gray.mnc'),...
        fullfile(spm('Dir'), 'apriori', 'white.mnc'),...
        fullfile(spm('Dir'), 'apriori', 'csf.mnc')));
      opts.estimate.reg    = ft_getopt(opts.estimate, 'reg',    0.01);
      opts.estimate.cutoff = ft_getopt(opts.estimate, 'cutoff', 30);
      opts.estimate.samp   = ft_getopt(opts.estimate, 'samp',   3);
      opts.estimate.bb     = ft_getopt(opts.estimate, 'bb',     [[-88 88]' [-122 86]' [-60 95]']);
      opts.estimate.affreg.smosrc  = ft_getopt(opts.estimate.affreg, 'smosrc',  8);
      opts.estimate.affreg.regtype = ft_getopt(opts.estimate.affreg, 'regtype', 'mni');
      opts.estimate.affreg.weight  = ft_getopt(opts.estimate.affreg, 'weight', '');
      opts.write.cleanup   = ft_getopt(opts.write, 'cleanup', 1);
      opts.write.wrt_cor   = ft_getopt(opts.write, 'wrt_cor', 1);

      % perform the segmentation
      fprintf('performing the segmentation on the specified volume\n');
      spm_segment(VF, cfg.template, opts);

      % generate the list of filenames that contains the segmented volumes
      filenames = {[cfg.name, '_seg1.img'];...
        [cfg.name, '_seg2.img'];...
        [cfg.name, '_seg3.img']};

    case 'spm8'
      cfg.tpm = ft_getopt(cfg, 'tpm');
      cfg.tpm = char(cfg.tpm(:));
      if isempty(cfg.tpm)
        cfg.tpm = char(fullfile(spm('Dir'),'tpm','grey.nii'),...
          fullfile(spm('Dir'),'tpm','white.nii'),...
          fullfile(spm('Dir'),'tpm','csf.nii'));
      end
      px.tpm = cfg.tpm;

      VF = ft_write_mri([cfg.name, '.img'], mri.anatomy, 'transform', mri.transform, 'spmversion', cfg.spmversion, 'dataformat', 'nifti_spm');

      fprintf('performing the segmentation on the specified volume\n');
      p         = spm_preproc(VF, px);
      [po, dum] = spm_prep2sn(p);

      % this writes a mat file, may be needed for Dartel, not sure yet
      save([cfg.name '_sn.mat'],'-struct','po');

      % These settings were taken from a batch
      opts     = ft_getopt(cfg, 'opts');
      opts.GM  = [0 0 1];
      opts.WM  = [0 0 1];
      opts.CSF = [0 0 1];
      opts.biascor = 1;
      opts.cleanup = 0;

      % write the segmented volumes, -> this can probably be done differently
      spm_preproc_write(po, opts);

      % generate the list of filenames that contains the segmented volumes
      [pathstr, name] = fileparts(cfg.name);
      filenames = {fullfile(pathstr,['c1', name, '.img']);...
        fullfile(pathstr,['c2', name, '.img']);...
        fullfile(pathstr,['c3', name, '.img'])};

    case 'spm12'
      addpath(fullfile(spm('Dir'),'toolbox/OldSeg'));
      if strcmp(cfg.spmmethod, 'old')
        cfg.tpm = ft_getopt(cfg, 'tpm');
        cfg.tpm = char(cfg.tpm(:));
        if isempty(cfg.tpm)
          cfg.tpm = char(fullfile(spm('Dir'),'toolbox/OldSeg','grey.nii'),...
            fullfile(spm('Dir'),'toolbox/OldSeg','white.nii'),...
            fullfile(spm('Dir'),'toolbox/OldSeg','csf.nii'));
        end
        px.tpm = cfg.tpm;

        VF = ft_write_mri([cfg.name, '.nii'], mri.anatomy, 'transform', mri.transform, 'unit', mri.unit, 'spmversion', cfg.spmversion, 'dataformat', 'nifti_spm');

        fprintf('performing the segmentation on the specified volume, using the old-style segmentation\n');
        p         = spm_preproc(VF, px);
        [po, dum] = spm_prep2sn(p);

        % this write a mat file, may be needed for Dartel, not sure yet
        save([cfg.name '_sn.mat'],'-struct','po');

        % These settings are taken from a batch
        opts     = [];
        opts.GM  = [0 0 1];
        opts.WM  = [0 0 1];
        opts.CSF = [0 0 1];
        opts.biascor = 1;
        opts.cleanup = 0;

        % write the segmented volumes, -> this can be done differently
        spm_preproc_write(po, opts);

        % generate the list of filenames that contains the segmented volumes
        [pathstr, name] = fileparts(cfg.name);
        filenames = {fullfile(pathstr,['c1', name, '.nii']);...
          fullfile(pathstr,['c2', name, '.nii']);...
          fullfile(pathstr,['c3', name, '.nii'])};

      elseif strcmp(cfg.spmmethod, 'new') || strcmp(cfg.spmmethod, 'mars')
        cfg.tpm = ft_getopt(cfg, 'tpm');
        cfg.tpm = char(cfg.tpm);
        if ~isfield(cfg, 'tpm') || isempty(cfg.tpm)
          cfg.tpm = fullfile(spm('dir'),'tpm','TPM.nii');
        end

        VF = ft_write_mri([cfg.name, '.nii'], mri.anatomy, 'transform', mri.transform, 'spmversion', cfg.spmversion, 'dataformat', 'nifti_spm');

        fprintf('performing the segmentation on the specified volume, using the new-style segmentation\n');

        % create the structure that is required for spm_preproc8
        opts          = ft_getopt(cfg, 'opts');
        opts.image    = VF;
        opts.tpm      = ft_getopt(opts, 'tpm', spm_load_priors8(cfg.tpm));
        opts.biasreg  = ft_getopt(opts, 'biasreg',  0.0001);
        opts.biasfwhm = ft_getopt(opts, 'biasfwhm', 60);
        opts.lkp      = ft_getopt(opts, 'lkp',      [1 1 2 2 3 3 4 4 4 5 5 5 5 6 6 ]);
        opts.reg      = ft_getopt(opts, 'reg',      [0 0.001 0.5 0.05 0.2]);
        opts.samp     = ft_getopt(opts, 'samp',     3);
        opts.fwhm     = ft_getopt(opts, 'fwhm',     1);

        Affine = spm_maff8(opts.image(1),3,32,opts.tpm,eye(4),'mni');
        Affine = spm_maff8(opts.image(1),3, 1,opts.tpm,Affine,'mni');
        opts.Affine = Affine;

        % run the segmentation
        p = spm_preproc8(opts);

        % this writes the 'native' segmentations
        if strcmp(cfg.spmmethod, 'new')
          spm_preproc_write8(p, [ones(6,2) zeros(6,2)], [0 0], [0 1], 1, 1, nan(2,3), nan);
        elseif strcmp(cfg.spmmethod, 'mars')
          ft_hastoolbox('mars', 1);
          if ~isfield(cfg, 'mars'), cfg.mars = []; end
          beta        = ft_getopt(cfg.mars, 'beta', 0.1);
          convergence = ft_getopt(cfg.mars, 'convergence', 0.1);
          tcm{1}      = fullfile(fileparts(which('spm_mars_mrf')), 'rTCM_BW20_S1.mat');
          p = spm_mars_mrf(p, [ones(6,2) zeros(6,2)], [0 0], [0 1], tcm, beta, convergence, 1);
        end

        % this writes a mat file, may be needed for Dartel, not sure yet
        save([cfg.name '_seg8.mat'],'-struct','p');

        [pathstr, name] = fileparts(cfg.name);
        filenames = {fullfile(pathstr,['c1', name, '.nii']);...
          fullfile(pathstr,['c2', name, '.nii']);...
          fullfile(pathstr,['c3', name, '.nii']);...
          fullfile(pathstr,['c4', name, '.nii']);...
          fullfile(pathstr,['c5', name, '.nii']);...
          fullfile(pathstr,['c6', name, '.nii'])};

      else
        ft_error('cfg.spmmethod should be either ''old'', ''new'' or ''mars''');
      end % if spmmethod is old, new or mars

    otherwise
      ft_error('unsupported SPM version');
  end % switch spmversion

  for k = 1:numel(filenames)
    Vtmp = spm_vol(filenames{k});
    dat  = spm_read_vols(Vtmp);
    Vtmp.dat = dat;
    V(k)     = Vtmp;
  end

  if strcmp(cfg.write, 'no')
    [pathstr, name] = fileparts(cfg.name);
    prefix = {'c1';'c2';'c3';'c3';'c4';'c5';'c6';'m';'y_';''};
    suffix = {'_seg1.hdr';'_seg2.hdr';'_seg3.hdr';'_seg1.img';'_seg2.img';'_seg3.img';'_seg1.mat';'_seg2.mat';'_seg3.mat';'.hdr';'.img';'.nii'};
    for k = 1:numel(prefix)
      for j = 1:numel(suffix)
        warning off; % delete is quite verbose in its warnings
        try, delete(fullfile(pathstr,[prefix{k}, name, suffix{j}])); end
        warning on;
      end
    end
  elseif strcmp(cfg.write, 'yes')
    for k= 1:numel(V)
      % I am not sure whether or why this is needed
      V(k).mat = mri.transform;
      V(k)     = spm_create_vol(V(k));
    end
  end

  % collect the results
  segmented.dim       = reshape(size(V(1).dat), 1, []); % enforce a row vector
  segmented.transform = original.transform; % use the original transform
  segmented.coordsys  = original.coordsys;  % use the original coordsys
  segmented.unit      = original.unit;      % use the original units
  segmented.gray      = V(1).dat;
  if length(V)>1, segmented.white      = V(2).dat; end
  if length(V)>2, segmented.csf        = V(3).dat; end
  if length(V)>3, segmented.bone       = V(4).dat; end
  if length(V)>4, segmented.softtissue = V(5).dat; end
  if length(V)>5, segmented.air        = V(6).dat; end
  segmented.anatomy = mri.anatomy;

  % flip the volumes back according to the changes introduced by align_ijk2xyz
  fn = fieldnames(segmented);
  fn = fn(ismember(fn, {'anatomy', 'gray', 'white', 'csf', 'bone', 'softtissue', 'air'}));
  for k = 1:3
    if flipflags(k)
      for j = 1:numel(fn)
        segmented.(fn{j}) = flipdim(segmented.(fn{j}), k);
      end
    end
  end

  if ~all(permutevec == [1 2 3])
    for j = 1:numel(fn)
      segmented.(fn{j}) = ipermute(segmented.(fn{j}), permutevec);
    end
    segmented.dim  = size(segmented.(fn{1}));
  end

else
  % rename the output data
  segmented = mri;
  clear mri
end

%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
% now the data contains the tissue probability maps
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
% create the requested output fields

remove = {'anatomy' 'csf' 'gray' 'white' 'bone' 'softtissue' 'air' 'skull' 'skullstrip' 'brain' 'scalp'}; % all possible tissues

% check if smoothing or thresholding is required

dosmooth_brain = ~strcmp(cfg.brainsmooth, 'no');
if dosmooth_brain && ischar(cfg.brainsmooth)
  ft_error('invalid value %s for cfg.brainsmooth', cfg.brainsmooth);
end
dosmooth_scalp = ~strcmp(cfg.scalpsmooth, 'no');
if dosmooth_scalp && ischar(cfg.scalpsmooth)
  ft_error('invalid value %s for cfg.scalpsmooth', cfg.scalpsmooth);
end
dosmooth_skull = ~strcmp(cfg.skullsmooth, 'no');
if dosmooth_skull && ischar(cfg.skullsmooth)
  ft_error('invalid value %s for cfg.skullsmooth', cfg.skullsmooth);
end

dothres_brain = ~strcmp(cfg.brainthreshold, 'no');
if dothres_brain && ischar(cfg.brainthreshold)
  ft_error('invalid value %s for cfg.brainthreshold', cfg.brainthreshold);
end
dothres_scalp = ~strcmp(cfg.scalpthreshold, 'no');
if dothres_scalp && ischar(cfg.scalpthreshold)
  ft_error('invalid value %s for cfg.scalpthreshold', cfg.scalpthreshold);
end
dothres_skull = ~strcmp(cfg.skullthreshold, 'no');
if dothres_skull && ischar(cfg.skullthreshold)
  ft_error('invalid value %s for cfg.skullthreshold', cfg.skullthreshold);
end

outp = cfg.output;

if ~isempty(intersect(outp, 'tpm'))
  % output: probability tissue maps
  remove = intersect(remove, {'anatomy'});
elseif  ~isempty(intersect(outp, {'white' 'gray' 'csf' 'brain' 'skull' 'scalp' 'skullstrip'}))

  createoutputs = true;
  while createoutputs
    % create scalpmask - no tpm or brainmask is required to create it
    if any(strcmp('scalp', outp))

      fprintf('creating scalpmask ... ');
      % let the softtissue mask take precedence
      if isfield(segmented, 'softtissue')
        fprintf('using the softtissue tpm for segmentation\n');
        fname   = 'softtissue';
        anatomy = segmented.softtissue;
      elseif isfield(segmented, 'anatomy')
        fprintf('using the anatomy field for segmentation\n');
        fname   = 'anatomy';
        anatomy = segmented.anatomy;
      else
        ft_error('no appropriate volume is present for the creation of a scalpmask');
      end
      if dosmooth_scalp
        anatomy = volumesmooth(anatomy, cfg.scalpsmooth, fname);
      else
        fprintf('no smoothing applied on %s for scalp segmentation\n', fname);
      end
      if dothres_scalp
        anatomy = volumethreshold(anatomy, cfg.scalpthreshold, fname);
      else
        fprintf('no threshold applied on %s for scalp segmentation\n', fname);
      end

      % fill the slices along each dimension (because using a single one is
      % just arbitrary, and behavior depends on how the voxeldata is in the
      % volume.
      a1 = volumefillholes(anatomy, 1);
      a2 = volumefillholes(anatomy, 2);
      a3 = volumefillholes(anatomy, 3);

      scalpmask = a1 | a2 | a3;
      clear anatomy a1 a2 a3

      % threshold again to remove little parts outside of head
      scalpmask = volumethreshold(scalpmask);

      % output: scalp (cummulative) (if this is the only requested output)
      if numel(outp)==1
        segmented.scalp = scalpmask;
        remove(strcmp(remove, 'scalp')) = []; % keep this
        break
      end
    end % if scalp

    % create the brain from the tpm
    fprintf('creating brainmask ... using the sum of gray, white and csf tpms\n');
    brain = segmented.gray + segmented.white + segmented.csf;
    if dosmooth_brain
      brain = volumesmooth(brain,  cfg.brainsmooth, 'brainmask');
    else
      fprintf('no smoothing applied on brainmask\n')
    end
    if dothres_brain
      brain = volumethreshold(brain, cfg.brainthreshold, 'brainmask');
    else
      fprintf('no threshold applied on brainmask\n')
    end

    % output: skullstrip
    if any(strcmp('skullstrip', outp))
      if ~isfield(segmented, 'anatomy'), ft_error('no anatomy field present'); end
      fprintf('creating skullstripped anatomy ...');
      brain_ss = cast(brain, class(segmented.anatomy));
      segmented.anatomy = segmented.anatomy.*brain_ss;
      clear brain_ss
      remove(strcmp(remove, 'skullstrip')) = []; % keep this
      remove(strcmp(remove, 'anatomy'))    = []; % keep this
      if numel(outp)==1
        break
      end
    end % if skullstrip

    % make binary mask from brain
    brainmask = brain>0;
    clear brain

    if any(strcmp(outp, 'brain'))
      % output: brain
      segmented.brain = brainmask;
      remove(strcmp(remove, 'brain')) = []; % keep this
      if numel(outp)==1
        break
      end

    elseif any(strcmp(outp, 'gray')) || any(strcmp(outp, 'white')) || any(strcmp(outp, 'csf'))
      % output: gray, white, csf
      [dum, tissuetype] = max(cat(4, segmented.csf, segmented.gray, segmented.white), [], 4);
      clear dum
      if any(strcmp(outp, 'white'))
        segmented.white = (tissuetype == 3) & brainmask;
        remove(strcmp(remove, 'white')) = []; % keep this
      end
      if any(strcmp(outp, 'gray'))
        segmented.gray = (tissuetype == 2) & brainmask;
        remove(strcmp(remove, 'gray')) = []; % keep this
      end
      if any(strcmp(outp, 'csf'))
        segmented.csf = (tissuetype == 1) & brainmask;
        remove(strcmp(remove, 'csf')) = []; % keep this
      end

    end % if brain or gray/while/csf

    if any(strcmp('skull', outp)) || any(strcmp('scalp', outp))
      % create the skull from the brain mask
      fprintf('creating skullmask ... ');
      if ~isfield(segmented, 'bone')
        fprintf('using the brainmask\n');
        braindil  = imdilate(brainmask>0, strel_bol(6)); % FIXME this should be user configurable
        skullmask = braindil & ~brainmask;
        clear braindil
      elseif isfield(segmented, 'bone')
        fprintf('using the bone tpm for segmentation\n');
        skull = segmented.bone + segmented.gray + segmented.white + segmented.csf;
        if dosmooth_skull
          skull = volumesmooth(skull, cfg.skullsmooth, 'skull');
        else
          fprintf('no smoothing applied on skull tpm for skull segmentation\n');
        end
        if dothres_skull
          skull = volumethreshold(skull, cfg.skullthreshold, 'skull');
        else
          fprintf('no threshold applied on skull tom for skull segmentation\n')
        end

        a1 = volumefillholes(skull, 1);
        a2 = volumefillholes(skull, 2);
        a3 = volumefillholes(skull, 3);

        skullmask = a1 | a2 | a3;
        skullmask = volumethreshold(skullmask);
        skullmask = skullmask & ~brainmask;

        clear a1 a2 a3
      end % if segmentation without bone

      if any(strcmp(outp, 'skull'))
        segmented.skull = skullmask;
        remove(strcmp(remove, 'skull')) = []; % keep this
        if numel(outp)==1
          break
        end
      end

      % output: scalp (exclusive type)
      if numel(outp) > 1 && any(strcmp('scalp', outp))
        scalpmask(brainmask>0)=0;
        clear brainmask
        scalpmask(skullmask>0)=0;
        clear skullmask
        segmented.scalp = scalpmask;
        remove(strcmp(remove, 'scalp')) = []; % keep this
        clear scalpmask
      end
    end

    createoutputs = false; % exit the while loop
  end % while createoutputs

else
  ft_error('unknown output %s requested\n', cfg.output{:});
end

% remove unnecessary fields
segmented = removefields(segmented, remove);

% do the general cleanup and bookkeeping at the end of the function
ft_postamble debug
ft_postamble previous   mri
ft_postamble provenance segmented
ft_postamble history    segmented
ft_postamble savevar    segmented


%kkthreshout 'Threshold Data Values Outside of the Specified Range'
% This MatLab function was automatically generated by a converter (KhorosToMatLab) from the Khoros kthreshout.pane file
%
% Parameters:
% InputFile: i 'Input ', required: 'Input file'
% OutputFile: o ' Output ', required: 'output file'
%
% Example: o = kkthreshout(i, {'i','';'o',''})
%
% Khoros helpfile follows below:
%
%  PROGRAM
% kthreshout - Threshold Data Values Outside of the Specified Range
%
%  DESCRIPTION
% The "Threshold Outside" operator generates a two-level output by
% thresholding the "Input" data object (i) outside the specified
% Lower and Upper Cutoff values (lc, uc).  Data values that are either
% less than the "Lower Cutoff Value" (lc), or greater than the \fIUpper
% Cutoff Value" (uc) are considered outside the threshold range, and are
% set to the first output value (fval).  Data values that are between, or
% equal to the cutoff values are within the threshold range, and are set to
% the second output value (tval).
%
% The following histogram defines the results of the thresholding operation.
% .KS
%
% \f(CW
%                                 |<-F->|<-T->|<-F->|
%                                 |     | :   | .   |
%                                 |    .:.:.  .:::  |
%                                 |:. .::::::.::::: |
%                                 |::::::::::::::::.|
%                                 ------|-----|------
%                                      lc     uc
%
%         F:  if value <  lc OR  value >  uc  output = fval
%         T:  if value >= lc AND value <= uc  output = tval
% "
%
% .KE
% P "Data Type" 5
% .cI $DATAMANIP/repos/shared/man/sections/value_type_1input
%
%  "Map Data" 5
% .cI $DATAMANIP/repos/shared/man/sections/map_1input
%
%  "Validity Mask" 5
% .cI $DATAMANIP/repos/shared/man/sections/mask_1input
%
%  "Explicit Location and Time Data" 5
% .cI $DATAMANIP/repos/shared/man/sections/loc_and_time_1input
%
%  "Failure Modes"
% .cI $DATAMANIP/repos/shared/man/sections/fail_1input
%
% Executing "Threshold Outside" runs the program \fIkclip\fP with the -thresh
% option set to TRUE (-thresh 1).
%
%
%
%  EXAMPLES
%
%  "SEE ALSO"
% DATAMANIP::kthreshabove, DATAMANIP::kthreshbelow, DATAMANIP::kthreshin,
% DATAMANIP::kmegathresh, DATAMANIP::kclip
%
%  RESTRICTIONS
%
%  REFERENCES
%
%  COPYRIGHT
% Copyright (C) 1993 - 1997, Khoral Research, Inc. ("KRI")  All rights reserved.
%

function varargout = kkthreshout(varargin)
if nargin ==0
  Inputs={};arglist={'',''};
elseif nargin ==1
  Inputs=varargin{1};arglist={'',''};
elseif nargin ==2
  Inputs=varargin{1}; arglist=varargin{2};
else error('Usage: [out1,..] = kkthreshout(Inputs,arglist).');
end
if size(arglist,2)~=2
  error('arglist must be of form {''ParameterTag1'',value1;''ParameterTag2'',value2}')
 end
narglist={'i', '__input';'o', '__output'};
maxval={0,0};
minval={0,0};
istoggle=[0,0];
was_set=istoggle * 0;
paramtype={'InputFile','OutputFile'};
% identify the input arrays and assign them to the arguments as stated by the user
if ~iscell(Inputs)
Inputs = {Inputs};
end
NumReqOutputs=1; nextinput=1; nextoutput=1;
  for ii=1:size(arglist,1)
  wasmatched=0;
  for jj=1:size(narglist,1)
   if strcmp(arglist{ii,1},narglist{jj,1})  % a given argument was matched to the possible arguments
     wasmatched = 1;
     was_set(jj) = 1;
     if strcmp(narglist{jj,2}, '__input')
      if (nextinput > length(Inputs))
        error(['Input ' narglist{jj,1} ' has no corresponding input!']);
      end
      narglist{jj,2} = 'OK_in';
      nextinput = nextinput + 1;
     elseif strcmp(narglist{jj,2}, '__output')
      if (nextoutput > nargout)
        error(['Output nr. ' narglist{jj,1} ' is not present in the assignment list of outputs !']);
      end
      if (isempty(arglist{ii,2}))
        narglist{jj,2} = 'OK_out';
      else
        narglist{jj,2} = arglist{ii,2};
      end

      nextoutput = nextoutput + 1;
      if (minval{jj} == 0)
         NumReqOutputs = NumReqOutputs - 1;
      end
     elseif isstr(arglist{ii,2})
      narglist{jj,2} = arglist{ii,2};
     else
        if strcmp(paramtype{jj}, 'Integer') & (round(arglist{ii,2}) ~= arglist{ii,2})
            error(['Argument ' arglist{ii,1} ' is of integer type but non-integer number ' arglist{ii,2} ' was supplied']);
        end
        if (minval{jj} ~= 0 | maxval{jj} ~= 0)
          if (minval{jj} == 1 & maxval{jj} == 1 & arglist{ii,2} < 0)
            error(['Argument ' arglist{ii,1} ' must be bigger or equal to zero!']);
          elseif (minval{jj} == -1 & maxval{jj} == -1 & arglist{ii,2} > 0)
            error(['Argument ' arglist{ii,1} ' must be smaller or equal to zero!']);
          elseif (minval{jj} == 2 & maxval{jj} == 2 & arglist{ii,2} <= 0)
            error(['Argument ' arglist{ii,1} ' must be bigger than zero!']);
          elseif (minval{jj} == -2 & maxval{jj} == -2 & arglist{ii,2} >= 0)
            error(['Argument ' arglist{ii,1} ' must be smaller than zero!']);
          elseif (minval{jj} ~= maxval{jj} & arglist{ii,2} < minval{jj})
            error(['Argument ' arglist{ii,1} ' must be bigger than ' num2str(minval{jj})]);
          elseif (minval{jj} ~= maxval{jj} & arglist{ii,2} > maxval{jj})
            error(['Argument ' arglist{ii,1} ' must be smaller than ' num2str(maxval{jj})]);
          end
        end
     end
     if ~strcmp(narglist{jj,2},'OK_out') &  ~strcmp(narglist{jj,2},'OK_in')
       narglist{jj,2} = arglist{ii,2};
     end
   end
   end
   if (wasmatched == 0 & ~strcmp(arglist{ii,1},''))
        error(['Argument ' arglist{ii,1} ' is not a valid argument for this function']);
   end
end
% match the remaining inputs/outputs to the unused arguments and test for missing required inputs
 for jj=1:size(narglist,1)
     if  strcmp(paramtype{jj}, 'Toggle')
        if (narglist{jj,2} ==0)
          narglist{jj,1} = '';
        end;
        narglist{jj,2} = '';
     end;
     if  ~strcmp(narglist{jj,2},'__input') && ~strcmp(narglist{jj,2},'__output') && istoggle(jj) && ~ was_set(jj)
          narglist{jj,1} = '';
          narglist{jj,2} = '';
     end;
     if strcmp(narglist{jj,2}, '__input')
      if (minval{jj} == 0)  % meaning this input is required
        if (nextinput > size(Inputs))
           error(['Required input ' narglist{jj,1} ' has no corresponding input in the list!']);
        else
          narglist{jj,2} = 'OK_in';
          nextinput = nextinput + 1;
        end
      else  % this is an optional input
        if (nextinput <= length(Inputs))
          narglist{jj,2} = 'OK_in';
          nextinput = nextinput + 1;
        else
          narglist{jj,1} = '';
          narglist{jj,2} = '';
        end;
      end;
     else
     if strcmp(narglist{jj,2}, '__output')
      if (minval{jj} == 0) % this is a required output
        if (nextoutput > nargout & nargout > 1)
           error(['Required output ' narglist{jj,1} ' is not stated in the assignment list!']);
        else
          narglist{jj,2} = 'OK_out';
          nextoutput = nextoutput + 1;
          NumReqOutputs = NumReqOutputs-1;
        end
      else % this is an optional output
        if (nargout - nextoutput >= NumReqOutputs)
          narglist{jj,2} = 'OK_out';
          nextoutput = nextoutput + 1;
        else
          narglist{jj,1} = '';
          narglist{jj,2} = '';
        end;
      end
     end
  end
end
if nargout
   varargout = cell(1,nargout);
else
  varargout = cell(1,1);
end
global KhorosRoot
if exist('KhorosRoot') && ~isempty(KhorosRoot)
w=['"' KhorosRoot];
else
if ispc
  w='"C:\Program Files\dip\khorosBin\';
else
[s,w] = system('which cantata');
w=['"' w(1:end-8)];
end
end
[varargout{:}]=callKhoros([w 'kclip"  -thresh'],Inputs,narglist);


function yrange = GetAxesYRangeForStimPlot(hAxes)

if ~exist('hAxes','var') || isempty(hAxes)
    hAxes = gca;
end

ylim = get(hAxes, 'ylim');

% Fill up the ylim range with the stim by adding and
% subtracting a tiny amount so that the ylim isn't
% automatically changed
d = (1e-4)*(ylim(2)-ylim(1));
% d = 0;
yrange = [ylim(1)+d, ylim(2)-d];


function [dataout,condidout] = fl_condidselecthed(data,condid,hedin,hedout);
% Uses hierarchical event description to select and rename conditions

%data is nvar x ntimes x ntrials

% hedin = '*/*/*/13,14,15,16,54,55,60,64,65,69'; %keep only conditions 13,14, etc
% hedout = '*/-/-/-'; % condidout should only have the first descriptor

%     modifier = 'animate/*/*'
%     modifier = 'animate/*/1,2,3,4,5,6'
%     modifier = 'animate/*/7,8'
%     modifier = 'inanimate/*/*/54,55,60,64,65,69'

%% split hierarchical event descriptor (hed) tag
hedinsplit = strsplit(hedin,'/');
hedoutsplit = strsplit(hedout,'/');
m = length(hedinsplit);

%% split condid tags
n = length(condid);
for i = 1:n
    condidsplit{i} = strsplit(condid{i},'/');
end
keep = ones(n,1);

%% modify condid based on hedin
for i = 1:m

    if ~strcmp(hedinsplit{i},'*')% if not '*', then a specific tag selection is given

        hedinspliti = strsplit(hedinsplit{i},','); %tags to keep (separated by comma)
        for j = 1:n
            if keep(j)
                try %just in case some events's have less elements than hed modifier
                    if ~nnz(strcmp(condidsplit{j}{i},hedinspliti)) %if requested tag does not exist
                        keep(j) = 0; %discard this item
                    end
                end
            end
        end
    end

end

%% modify condid based on hedout
for i = 1:m

    if strcmp(hedoutsplit{i},'*') %pass input to output
        continue
    elseif strcmp(hedoutsplit{i},'-') %if remove (tag '-')
        for j = 1:n
            condidsplit{j}{i} = '-';
        end
    else %if an output name is given
        for j = 1:n
            condidsplit{j}{i} = hedoutsplit{i};
        end
    end

end

%% join condid tags
for i = 1:n
    condidout{i} = strjoin(condidsplit{i},'/');
end

%% keep only data with tags sharing descriptors with hed
dataout = data(:,:,keep==1);
condidout = condidout(keep==1);

return


function [ joints ] = get_anno_joints( rect, pidxs, parts )

num_joints = length(pidxs);
joints = NaN(num_joints, 2);

points = rect.annopoints.point;
for j = 1:num_joints
    pidx = pidxs(j);
    annopoint_idxs = parts(pidx+1).pos;
    assert(annopoint_idxs(1) == annopoint_idxs(2));
    pt = util_get_annopoint_by_id(points, annopoint_idxs(1));
    if (~isempty(pt))
        joints(j, :) = [pt.x pt.y];
    end
end

end


%ASAGLOB_MEAN_ADJ Subtraction of the signal mean identifier
%   Declaring the variable ASAGLOB_MEAN_ADJ in the base workspace, for
%   example by typing at the command prompt,
%     ASAglob_mean_adj = 1;
%   will enable the ARMASA functions, ARMASEL, SIG2AR, SIG2MA and
%   SIG2ARMA to read out the value of ASAGLOB_MEAN_ADJ. A value 1 will
%   inform these functions, that the input data SIG have been level
%   adjusted using the mean of SIG. This will have a small effect on the
%   estimation of the Prediction Error, that is determined in these
%   functions.
%
%   By default the functions subtract the mean from the input data SIG
%   and ASAGLOB_MEAN_ADJ is automatically assigned. If one choses to
%   subtract the mean beforehand, or when it is known that the mean has
%   already been subtracted by some other proces, assign 1 to
%   ASAGLOB_MEAN_ADJ. To control the subtraction of the mean itself, use
%   ASAGLOB_SUBTR_MEAN. ASAGLOB_SUBTR_MEAN will NOT be effected by any
%   choice of ASAGLOB_MEAN_ADJ.
%
%   See also: ASAGLOB_SUBTR_MEAN

disp('  Variable ASAGLOB_MEAN_ADJ is currently undefined.')
disp('  Type ''help ASAglob_mean_adj'' for more information.')


% getkeyval() - get variable value from a 'key', 'val' sequence string.
%
% Usage:
%   >> val = getkeyval( keyvalstr, varname, mode, defaultval);
%
% Inputs:
%   keyvalstr  - string containing 'key', 'val' arguments
%   varname    - string for the name of the variable or index
%                of the value to retrieve (assuming arguments are
%                separated by comas).
%   mode       - if the value extracted is an integer array, the
%                'mode' variable can contain a subset of indexes to return.
%                If mode is 'present', then either 0 or 1 is returned
%                depending on wether the variable is present.
%   defaultval - default value if the varible is not found
%
% Outputs:
%   val  - a value for the variable
%
% Note: this function is helpful for finding arguments in string commands
%       stored in command history.
%
% Author: Arnaud Delorme, CNL / Salk Institute, 29 July 2002
%
% See also: gethelpvar()

% Copyright (C) 2002 arno@salk.edu, Arnaud Delorme, CNL / Salk Institute
%
% This program is free software; you can redistribute it and/or modify
% it under the terms of the GNU General Public License as published by
% the Free Software Foundation; either version 2 of the License, or
% (at your option) any later version.
%
% This program is distributed in the hope that it will be useful,
% but WITHOUT ANY WARRANTY; without even the implied warranty of
% MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
% GNU General Public License for more details.
%
% You should have received a copy of the GNU General Public License
% along with this program; if not, write to the Free Software
% Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA

function txt = getkeyval(lastcom, var, mode, default)
    % mode can be present for 0 and 1 if the variable is present
	if nargin < 1
        help getkeyval;
        return;
    end;
    if nargin < 4
		default = '';
	end;
	if isempty(lastcom)
		txt = default; return;
	end;
	if nargin < 3
		mode = '';
	end;
	if isstr(mode) & strcmp(mode, 'present')
		if ~isempty(findstr(var, lastcom))
			txt = 1; return;
		else
			txt = 0; return;
		end;
	end;
	if isnumeric(var)
		comas = findstr(lastcom, ',');
		if length(comas) >= var
			txt = lastcom(comas(var-1)+1:comas(var)-1);
            tmpval = eval( txt );
            if isempty(tmpval), txt = '';
            else txt = vararg2str( tmpval );
            end;
            return;

% 			txt = deblank(txt(end:-1:1));
% 			txt = deblank(txt(end:-1:1));
%
% 			if ~isempty(txt) & txt(end) == '}', txt = txt(2:end-1); end;
% 			if ~isempty(txt)
% 				txt = deblank(txt(end:-1:1));
% 				txt = deblank(txt(end:-1:1));
% 			end;
% 			if ~isempty(txt) & txt(end) == ']', txt = txt(2:end-1); end;
% 			if ~isempty(txt)
% 				txt = deblank(txt(end:-1:1));
% 				txt = deblank(txt(end:-1:1));
% 			end;
% 			if ~isempty(txt) & txt(end) == '''', txt = txt(2:end-1); end;
		else
			txt = default;
		end;
		%fprintf('%s:%s\n', var, txt);
		return;
	else
		comas  = findstr(lastcom, ','); % finding all comas
		comas  = [ comas  findstr(lastcom, ');') ]; % and end of lines
		varloc = findstr(lastcom, var);
		if ~isempty(varloc)
			% finding comas surrounding 'val' var in 'key', 'val' sequence
			comas = comas(find(comas >varloc(end)));
			txt = lastcom(comas(1)+1:comas(2)-1);
			txt = deblank(txt(end:-1:1));
			txt = deblank(txt(end:-1:1));
			if strcmp(mode, 'full')
				parent = findstr(lastcom, '}');
				if ~isempty(parent)
					comas = comas(find(comas >parent(1)));
					txt = lastcom(comas(1)+1:comas(2)-1);
				end;
				txt = [ '''' var ''', ' txt ];
			elseif isnumeric(mode)
				txt = str2num(txt);
				if ~isempty(mode)
					if length(txt) >= max(mode)
						if all(isnan(txt(mode))), txt = '';
						else txt = num2str(txt(mode));
						end;
					elseif length(txt) >= mode(1)
						if all(isnan(txt(mode(1)))), txt = '';
						else txt = num2str(txt(mode(1)));
						end;
					else
						txt = default;
					end;
				else
                    txt = num2str(txt);
				end;
            elseif txt(1) == ''''
                txt = txt(2:end-1); % remove quotes for text
			end;
		else
			txt = default;
		end;
	end;
	%fprintf('%s:%s\n', var, txt);


function browse_topoplotER(cfg, data)

% BROWSE_TOPOPLOTER is a simple helper function for FT_DATABROWSER and shows
% the average topography of the selected data.
%
% See also BROWSE_MOVIEPLOTER, BROWSE_TOPOPLOTER, BROWSE_MULTIPLOTER, BROWSE_TOPOPLOTVAR, BROWSE_SIMPLEFFT

% Copyright (C) 2009, Robert Oostenveld

% convert to an ERP
timelock = ft_timelockanalysis([], data);

default             = [];
default.xlim        = [min(timelock.time) max(timelock.time)];
default.marker      = 'on';
default.interactive = 'no';
cfg = mergeconfig(cfg, default);

figure;
ft_topoplotER(cfg, timelock);


function y = cvx_isconvex( x, full )
error( nargchk( 1, 2, nargin ) );
y = cvx_vexity( x );
if nargin < 2,
    y = nnz( y < 0 ) == 0;
else
    y = cvx_reshape( y >= 0, x.size_ );
end

% 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.


%
% Usage:   Y =mexBayer(X,offset);
%
% Name: mexBayer
%
% Description: mexBayer applies a Bayer pattern to an image X.
%       There are four possible offsets.
%
% Inputs: X:  double m x n matrix
%         offset: scalar, 0,1,2 or 3
%
% Output: Y: double m x m matrix
%
% Author: Julien Mairal, 2009


function disp(F)
%DISP   Display a CHEBFUN2V.
%
% See also DISPLAY.

% Copyright 2017 by The University of Oxford and The Chebfun Developers.
% See http://www.chebfun.org/ for Chebfun information.

loose = strcmp(get(0,'FormatSpacing'),'loose');

% Compact version
if ( isempty( F ) )
    fprintf('empty chebfun2v\n')
    return
end

if ( F.isTransposed )
    tString = 'Row vector';
else
    tString = 'Column vector';
end

disp(['   chebfun2v object ' '(' tString ') containing:' ])
if ( loose )
    fprintf('\n');
end

% Display its two CHEBFUN2 halves.
for j = 1:F.nComponents
    disp( F.components{j} );
end

end


%GOBJ_EXTRUDE Extrude face/geometry object.
%
%   [ GOBJ, STAT ] = GOBJ_EXTRUDE( GOBJ, D, V, FACE_WPL )
%   Extrude geometry object or face from GOBJ a distance D in the
%   direction of the vector V. FACE_WPL can in 3D indicate a face to
%   extrude or in 2D is a workplane struct defined by (p, n, t).

% Copyright 2013-2022 Precise Simulation, Ltd.


function c = char(s,varargin)
% object -> string

if check_option(varargin,'verbose')
  c = option2str([{s.pointGroup},s.alignment]);
  if ~isempty(s.mineral), c = [s.mineral ' (' c ')']; end
elseif check_option(varargin,'latex')
  c = ['$' regexprep(s.pointGroup,'-(\w)','\\bar{$1}') '$'];
elseif check_option(varargin,'compact')
  if ~isempty(s.mineral)
    c = s.mineral;
  else
    c = s.pointGroup;
  end

  if ~getMTEXpref('generatingHelpMode')
    id = pushTemp(s);
    c = ['' c ''];
  end
else
  c = ['"',s.pointGroup,'"'];
end

if check_option(varargin,'symmetryType'), c = ['  crystal symmetry : ' c]; end


function parsedGPR = GPRparser(model, getCNFSets)
% Maps the GPR rules of the model to a specified format that is used by
% the model extraction methods
%
% USAGE:
%   parsedGPR = GPRparser(model)
%
% INPUT:
%   model:       cobra model structure
%
% OPTIONAL INPUT:
%    getCNFSets:    whether to get the CNF sets (true) or DNF sets (false).
%                   DNF sets represent functional enzyme complexes, while
%                   CNF sets represent the possible subunits of a complex.
%                   (default: false , i.e. DNF sets)
%
% OUTPUT:
%   parsedGPR:   cell matrix containing parsed GPR rule
%
% AUTHORS: Thomas Pfau & Anne Richelle, May 2017

if ~exist('getCNFSets','var')
    getCNFSets = false;
end

parsedGPR = {};
fp = FormulaParser();
for i = 1:numel(model.rxns)
    if ~isempty(model.rules{i})
        head = fp.parseFormula(model.rules{i});
        currentSets = head.getFunctionalGeneSets(model.genes,getCNFSets)';
        parsedGPR{i}=currentSets;
    else
        parsedGPR{i}={''};
    end
end
parsedGPR=parsedGPR';
end


function movie_of_slice_timeseries(imgs, slicenumber, moviename, orientation)
% :Inputs:
%
%   **imgs:**
%        Image names
%
%   **slicenumber:**
%        which slice to view (in volume)
%
%   **moviename:**
%        something like: 'slice10_timeseries.avi'
%
%   **orientation:**
%        'axial' or 'sagittal'
%
% :Examples:
% ::
%
%    slicenumber = 10;
%    moviename = 'slice10_timeseries.avi';

    if(~exist('orientation', 'var') || isempty(orientation))
        orientation = 'axial';
    end

    disp('Mapping volumes.')
    V = spm_vol(imgs);

    disp('Loading data.')

    sl = timeseries_extract_slice(V, slicenumber, orientation);

    disp('Setting limits.')
    mymad = mad(sl(:));
    mymean = mean(sl(:));
    limits = [0 mymean + 3 * mymad];

    slice_fig = figure();

    nimgs = size(sl, 3);

    disp('Starting movie.')
    movlength = 60; % in seconds

    [mov, nframes, axh] = setup_movie([], movlength, moviename);

    for i = 1:nimgs
        H = gca;
        imagesc(sl(:, :, i));
        set(H, 'CLim', limits)
        colorbar
        axis image

        [dd, ff, ee] = fileparts(V(i).fname);
        title(sprintf('Image %3.0f: %s', i, ff), 'FontSize', 24)

        mov = add_a_frame(mov, H);
    end

    tmp = close(mov); %#ok;
    close(slice_fig);

    disp('Success!')
end

function [mov, nframes, axh] = setup_movie(mov, movlength, moviename)
    axh = gca;

    fps = 5;
    nframes = movlength .* fps;

    if isempty(mov)
        mov = avifile(moviename, 'Quality', 75, 'Compression', 'None', 'Fps', fps);
    end

    % add to existing
    %O = struct('add2movie', [], 'zoom', 1, 'azOffset', [], 'elOffset', [], 'timecourse', [], 'fps', 5, 'length', 6);

    axis image
end

function mov = add_a_frame(mov, H)
    drawnow

    lightRestoreSingle(H);
    try
        mov = addframe(mov, H);
    catch
        disp('Cannot write frame.  Failed to set stream format??')
        mov = close(mov);
    end
end


function [Model2] = train()
    [X] = LoadImages();
    [Y] = LoadLabels();
    [M,P] = GetMP(X,Y);

    field1 = 'M';
    field2 = 'P';
    Model2 = struct(field1,M,field2,P);
    save('Model2.mat','Model2');
end


function result = evaluate(output_dir, target_dir, task)
  ts = get_task(output_dir, target_dir, task);
  [p, s, a] = run_eval_template(ts{1,2},ts{1,3},ts{1,4},get_path(ts{1,5}),ts{1,6},ts{1,7});
  result = [ts{1,1} ' psnr,ssim,abs= ' num2str(p) ', ' num2str(s) ', ' num2str(a)];
  result
end


function [err,Info, opt] = New_HEAD (opt)
%
%   [err,Info, Opt] = New_HEAD (Opt)
%
%Purpose:
%   A function for the likes of Greg Detre.
%   It makes the creation of an AFNI dataset
%   from a 3 or 4 dimensional matrix in matlab a breeze.
%
%
%
%Input Parameters:
%   opt is an options structure with the following fields:
%     .prefix: A string containg the AFNI dataset's prefix
%              .prefix and one of .dimen or .master must
%              be used.
%     .dimen: A string or array containing the dimensions of
%             the dataset (at least 3 dimensions need be present).
%     The following four options are from 3dUndump. See 3dUndump -help
%     .view:    '+orig' (default) or '+acpc' or '+tlrc'
%               If you choose +tlrc, the resultant volume
%               will fit the Talairach box.
%     .master: Name of an existing AFNI dataset that would
%              provide the needed matrix size, orientation etc.
%              Do not mix .master with .dimen
%     .datum:  'byte', 'short' (default), or 'float'
%     .orient: Orientation of data in matrix. Default in 'RAI'
%
%     .tr: a float specifying the TR in seconds.
%          The presence of such a field necessitates a 4 dimensional
%     .scale: 0/1 This is only meaningful with 'short' data where it
%             defaults to 1. It defaults to 0 for other types. It is
%             used when storing float data as shorts to minimize disk
%             use while preserving numeric percision.
%     .Overwrite: y/[n] allow header to be created even if one with
%                 similar name is found on disk
%Output Parameters:
%   err : 0 No Problem
%       : 1  Problems
%   Info: The header structure, given the options specified
%   Opt: A modified version of the input Opt. It will be passed
%        along with the data array to WriteBrik for writing the
%        dataset to disk. (See Examples below)
%
%Examples:
%     Run New_HEAD('test') or see Test_New_HEAD.m for examples.
%
%More Info :
%     AFNI programs 3drefit and 3dAttribute are your friends
%     BrikLoad, BrikInfo, WriteBrik
%     README.attributes
%
%     The function makes heavy use of 3dUndump
%
%This function requires AFNI binaries postdating Feb. 12 2007
%
%
%     Author : Ziad Saad   saadz@mail.nih.gov
%     Date : Fri Feb 9 16:29:51 EST 2007
%     SSCC/NIMH/ National Institutes of Health, Bethesda Maryland

%Define the function name for easy referencing
FuncName = 'New_HEAD';

%Debug Flag
DBG = 1;

%initailize return variables
err = 1;
Info = [];

%check on return parameters
if (nargout == 2),
   fprintf(1, 'Notice %s:\nYou are not specifying a return argument for Opt.\n', FuncName);
   fprintf(1, ' Be aware that some fields in Opt might have been modified inside\n');
   fprintf(1, ' %s but these changes are not reflected in the Opt structure you\n', FuncName);
   fprintf(1, ' will be passing to WriteBrik.\n');
   fprintf(1, ' If this makes no sense to you, just use:\n');
   fprintf(1, '    [err, Info, Opt] = New_HEAD(Opt);\n');
end

%work options
if (ischar(opt)), %perhaps test mode
   Test_New_HEAD;
   return;
end

%standardize input
if (isfield(opt,'dimen')),
   if (ischar(opt.dimen)),
      v = str2num(opt.dimen);
      rmfield(opt, 'dimen');
      opt.dimen = v;
   end
end

%create command for -master option or non-tlrc views
if (~isfield(opt,'view') | ~strcmp(opt.view,'+tlrc') | isfield(opt,'master')),
   tmp_suf = '___NeW_hEaD_';
   sopt = '3dUndump -head_only';
   if (isfield(opt,'dimen')),
      sopt = sprintf('%s -dimen %s', sopt, num2str(opt.dimen(1:3)));
   end
   if (isfield(opt,'orient')),
      sopt = sprintf('%s -orient %s', sopt, opt.orient);
   end
   if (isfield(opt,'master')),
      [Status, mPrefix, mView] = PrefixStatus (opt.master);
      sopt = sprintf('%s -master %s', sopt, opt.master);
   else
      mView = '+orig';
   end
   if (~isfield(opt,'datum')), opt.datum = 'short'; end

   if (isfield(opt,'datum')),
      if (~strcmp(opt.datum,'short') & ~strcmp(opt.datum, 'byte') & ~strcmp(opt.datum,'float')),
         fprintf(1,'Error %s:\ndatum option must be one of ''byte'', ''short'', ''float''\nI have %s\n', FuncName, opt.datum);
         return;
      end
      sopt = sprintf('%s -datum %s', sopt, opt.datum);
   end

   if (~isfield(opt,'view')),
      opt.view = '+orig';
   end

   if (isfield(opt,'prefix')),
      [Status, Prefix, View] = PrefixStatus (opt.prefix);
      if (Status < 1 & strcmp(View,opt.view)),
         if (isfield(opt,'overwrite') & ~strcmp(opt.overwrite,'y')),
            fprintf(1,'Error %s:\nLooks like %s exists already.\n',...
                     FuncName, opt.prefix);
            return;
         end
      end
      opt.prefix = Prefix;
      ohead = sprintf('%s%s', tmp_suf, opt.prefix);
      sopt = sprintf('%s -prefix %s%s', sopt, ohead);
   else
      fprintf(1,'Error %s:\nNeed a .prefix option.\n', FuncName);
      return;
   end

   [e,w] = unix(sopt);
   if (e),
      fprintf(1,'Error %s:\nHeader creating command %s failed.\nSee this function''s help and 3dUndump -help\n3dUndump''s output was:\n%s\n', ...
               FuncName, sopt, w);
      New_HEAD_CLEAN(tmp_suf);
      return;
   end

   [err,Info]  = BrikInfo(sprintf('%s%s', ohead,mView));
   New_HEAD_CLEAN(tmp_suf);
else %have +tlrc and no master
   mView = '+tlrc';
   [e,d] = unix('which afni');
   if (e),
      fprintf(1,'Error %s:\nFailed to find afni!\n', FuncName);
      return;
   end
   [e,pt] = GetPath(d);
   templ = sprintf('%s/TT_N27+tlrc.HEAD', pt);
   [e,Info] = BrikInfo(templ);
   if (e),
      fprintf(1,'Error %s:\nFailed to get header of %s!\n', FuncName, templ);
      return;
   end
   %recalculate the origin (res. of template is 1x1x1mm)
   oOrig = Info.ORIGIN;
   oDelta = Info.DELTA;
   oDimen = Info.DATASET_DIMENSIONS;
   %Calculate dimension ratio and adjust so that volume fits in box.
   rat = oDimen(1:3)./opt.dimen(1:3);
   Info.DELTA = Info.DELTA .* rat;
   Info.DATASET_DIMENSIONS(1:3) = opt.dimen(1:3);
   %Now shift the origin so that the final volume still fits in the same box (edge to edge) of TLRC box
   dOrig = 1./2*(Info.DELTA-oDelta);
   Info.ORIGIN = Info.ORIGIN+dOrig;
   %Have to deal with datum
   if (isfield(opt,'datum')),
      if (strcmp(opt.datum,'byte')),
         Info.BRICK_TYPES(1) = 0;
      elseif (strcmp(opt.datum,'short')),
         Info.BRICK_TYPES(1) = 1;
      elseif (strcmp(opt.datum,'float')),
         Info.BRICK_TYPES(1) = 3;
      else
         fprintf(1,'Error %s: Bad data type %s\n', FuncName, opt.datum);
         return;
      end
   else
      opt.datum = 'short'
      Info.BRICK_TYPES(1) = 1;
   end
end

%the scaling option
if (isfield(opt,'scale')),
   if (opt.scale & ~strcmp(opt.datum,'short')),
      fprintf(1,'Warning %s:\n .scale option is only for ''short'' type data.\n Resetting it to 0.\n', FuncName);
      opt.scale = 0;
   end
else
   if (strcmp(opt.datum,'short')),
      opt.scale = 1;
   else
      opt.scale = 0;
   end
end

%take care of prefix business
Info.RootName = sprintf('%s%s', opt.prefix, opt.view);

%take care of view
if (strcmp(mView, opt.view) == 0), %different
   if (strcmp(opt.view,'+orig')) Info.SCENE_DATA(1) = 0;
   elseif (strcmp(opt.view,'+acpc')) Info.SCENE_DATA(1) = 1;
   elseif (strcmp(opt.view,'+tlrc')) Info.SCENE_DATA(1) = 2;
   else
      fprintf(1,'Error %s:\nBad view %s\n', FuncName, opt.view);
      return;
   end
end

%take care of 4th dimen
if (isfield(opt,'dimen')),
   if (length(opt.dimen) > 3),
      Info.DATASET_RANK(2) = opt.dimen(4);
      Info.BRICK_TYPES = Info.BRICK_TYPES(1).*ones(1,opt.dimen(4));
      Info.BRICK_FLOAT_FACS  = Info.BRICK_FLOAT_FACS(1) .*ones(1, opt.dimen(4));
   end
end

%take care of TR
if (isfield(opt,'tr')),
   Info.TAXIS_NUMS(1) = Info.DATASET_RANK(2);
   Info.TAXIS_NUMS(2) = 0; %no time offset for slices at the moment
   Info.TAXIS_NUMS(3) = 77002; %units in seconds for tr (below)

   Info.TAXIS_FLOATS(1) = 0;  %time origin 0
   Info.TAXIS_FLOATS(2) = opt.tr;   %TR in units of Info.TAXIS_NUMS(3)
   Info.TAXIS_FLOATS(3) = 0; %duration of acquisition
   Info.TAXIS_FLOATS(4) = 0; %no time offset please
   Info.TAXIS_FLOATS(5) = 0; %no time offset please

   Info.TAXIS_OFFSETS = zeros(1,Info.TAXIS_NUMS(1));  %no bloody time offset
end

err = 0;
return;

function New_HEAD_CLEAN(sss)
   unix(sprintf('rm -f %s*.HEAD >& /dev/null', sss));
return;


function mini_batch = extract_mini_batch(data_set, start_i, n_cases)
    mini_batch.inputs = data_set.inputs(:, start_i : start_i + n_cases - 1);
    mini_batch.targets = data_set.targets(:, start_i : start_i + n_cases - 1);
end


function [MAT,VARNAME,tag_contents]=xml2mat(XML)

%XML2MAT converts XML string into matlab structure variable
%Syntax: [MAT,VARNAME,tag_contents]=xml2mat(XML)
%Description
% XML is an XML formated string using rules compliant with
%     the proceedure implemented in MAT2XML.
%     It can also be a file name with MbML text.
% VARNAME is the variable name.
%     If recovering the MAT variable with the original name is desired than
%     the followinf line will do the trick:
%
%          [MAT,VARNAME]=xml2mat(XML);eval([VARNAME,'=MAT'])
%
% See Also: mat2xml
% Jonas Almeida, 20 Aug 2002, XML4MAT Tbox

if strncmp(XML,'%60;',4)  % XML provided as encoded XML string
    XML=spcharout(XML);
end

% is this a xml string or xml filename ?
if XML(1)~='<'
    XML=strrep(file2str(XML),'''','''''');
    % Remove non-content lines if they exist
    XML=regexprep(XML,'<[?!].*?>','');
end

%Analise XML line
tag_ini=find(XML=='<');
tag_end=find(XML=='>');
n=length(tag_ini); % number of enclosed tag structures

% extract tag_names properties and contents
if n>0
for i=1:n
    tag_close(i)=(XML(tag_ini(i)+1)=='/'); % 1 for closing contents and 0 for opening
    tag_contents{i,1}=XML(tag_ini(i)+1+tag_close(i):tag_end(i)-1);  % first column contains names
end
tag_path=[0]; % first name is root name
to_do=zeros(n,1); % 1 needs doing
to_do(1)=1;
tag_open=~tag_close;
i=1;tag_contents{i,2}=xml2whos(tag_contents{i,1});tag_contents{i,2}.fields=[];tag_contents{i,3}=tag_path;tag_path=[tag_path,i];
for i=2:n
    tag_contents{i,2}=xml2whos(tag_contents{i,1});tag_contents{i,2}.fields=[]; % second column contains WHO properties
    if tag_open(i)
        tag_contents{i,3}=tag_path;  % third column contains structre path
        tag_path=[tag_path,i];
        to_do(i)=1; % do this one
        to_do(tag_contents{i,3}+(tag_contents{i,3}==0))=0; % do host later
        tag_contents{tag_path(end-1),2}.fields=[tag_contents{tag_path(end-1),2}.fields,i];
    else
        tag_path(end)=[]; % move back one level
    end
end

% RECOVER DATA
todo_list=find(to_do==1)';do_i=1;
while do_i<=length(todo_list);
    i=todo_list(do_i);
    % for each case extract value
    tag_contents{i,4}=XML(tag_end(i)+1:tag_ini(i+1)-1);  % 4th column contains value as string
    w=tag_contents{i,2};
    % recover number format if appropriated
    if ~isfield(w,'class')
        w.class='char';
        tag_contents{i,4}=spcharout(tag_contents{i,4});
        w.size=size(tag_contents{i,4}); %correct size tag as well
        %tag_contents{i,2}=w;
    elseif strcmp(w.class,'char')
        tag_contents{i,4}=spcharout(tag_contents{i,4});
        w.size=size(tag_contents{i,4}); %correct size tag as well
        %tag_contents{i,2}=w;
    elseif strcmp(w.class,'struct')&(~isfield(w,'size'))
        n_fields=length(w.fields);
        for i=1:n_fields
            field_names{i}=tag_contents{w.fields(i),2}.name;
        end
        unique_names=unique(field_names);
        n_unique=length(unique_names);
        n_certo=(n_fields/n_unique);
        w.size=[1 n_certo];
    else % it is a numeric type, say "double" or "single"
        tag_contents{i,4}=str2num(tag_contents{i,4});
        if ~isfield(w,'size');
            w.size=size(tag_contents{i,4});
        end
    end
    tag_contents{i,2}=w;
    if (length(w.size>2)|(w.size(1)>1))
        iis='i1';for ii=2:length(w.size);iis=[iis,',i',num2str(ii)];end
        nn=prod(w.size); %number of elements
        eval(['[',iis,']=ind2sub(w.size,[1:nn]);']); % generation of indexes
        iis='i1(ind)';for ii=2:length(w.size);iis=[iis,',i',num2str(ii),'(ind)'];end % indexes of indexes
        for ind=1:nn
            eval(['valor(',iis,')=tag_contents{i,4}(ind);'])
        end
        if exist('valor')==1;tag_contents{i,4}=valor;clear valor;end
    end
    do_i=do_i+1;
end

% RECOVER STRUCTURE
j=1;tags=find(tag_open);
eval_i={'MAT'};to_eval={};
while j<=length(tags)
    i=tags(j);
    [to_eval,eval_i,j]=tag2eval(tag_contents,to_eval,eval_i,j,tags);
    %w=tag_contents{i,2}
    j=j+1;
end

for i=1:length(to_eval)
    %disp(to_eval{i})
    eval(to_eval{i})
end

%MAT.tag_contents=tag_contents;
VARNAME=tag_contents{1,2}.name;
else
    MAT=XML;
    VARNAME=[];
    tag_contents=[];
end


function S = pad_strn (strg,padchar,n,loc)
%	S = PAD_STRN (strg,padchar,n,loc)
%This function pad the string 'strg' with 'padchar' characters
%  such that 'S' is 'n' characters long.
% if loc = 1 the 'padchar' are added to the left of 'strg'
% if loc = -1 the 'padchar' are added to the right of 'strg'

if (~ischar(strg) | ~ischar(padchar)),
	err = ErrEval(mfilename, 'Err_First two arguments must be characters');
	S = '';
	return;
end

S = strg;
while (length(S) < n)

	if (loc == 1),
		S = sprintf ('%s%s',padchar,S);
	elseif (loc == -1),
		S = sprintf ('%s%s',S,padchar);
	end

end;

return;


%run this test case with the command
%results = runtests('importExportTests.m')
function tests = importExportTests
tests = functiontests(localfunctions);
end

function testExcelImport(testCase)
sourceDir=fileparts(fileparts(fileparts(which(mfilename))));
excelFile=fullfile(sourceDir,'tutorial','empty.xlsx');
%%Prepare test results, uncomment and run when new reference is needed
% modelExcel=importExcelModel(excelFile);
% sbmlFile=fullfile(sourceDir,'tutorial','empty.xml');
% modelSBML=importModel(sbmlFile);
% save(fullfile(sourceDir,'testing','unit_tests','test_data','importExportResults.mat'),'modelExcel','modelSBML');
evalc('model=importExcelModel(excelFile)'); % Repress warnings
load(fullfile(sourceDir,'testing','unit_tests','test_data','importExportResults.mat'), 'modelExcel');
verifyEqual(testCase,model,modelExcel)
end

function testSBMLImport(testCase)
sourceDir=fileparts(fileparts(fileparts(which(mfilename))));
sbmlFile=fullfile(sourceDir,'tutorial','empty.xml');
evalc('model=importModel(sbmlFile)'); % Repress warnings
load(fullfile(sourceDir,'testing','unit_tests','test_data','importExportResults.mat'), 'modelSBML');
verifyEqual(testCase,model,modelSBML)
end

function testExcelExport(testCase)
sourceDir=fileparts(fileparts(fileparts(which(mfilename))));
load(fullfile(sourceDir,'testing','unit_tests','test_data','ecoli_textbook.mat'), 'model');
exportToExcelFormat(model,fullfile(sourceDir,'testing','unit_tests','test_data','_test.xlsx'));
%File will not be exactly equal as it contains the current date and time,
%so md5 or similar would not work. Just check whether file is reasonably
%sized.
s = dir(fullfile(sourceDir,'testing','unit_tests','test_data','_test.xlsx'));
filesize = s.bytes;
verifyTrue(testCase,filesize>17000);
delete(fullfile(sourceDir,'testing','unit_tests','test_data','_test.xlsx'));
end

function testSBMLExport(testCase)
sourceDir=fileparts(fileparts(fileparts(which(mfilename))));
load(fullfile(sourceDir,'testing','unit_tests','test_data','ecoli_textbook.mat'), 'model');
evalc('exportModel(model,fullfile(sourceDir,''testing'',''unit_tests'',''test_data'',''_test.xml''))');
%File will not be exactly equal as it contains the current date and time,
%so md5 or similar would not work. Just check whether file is reasonably
%sized.
s = dir(fullfile(sourceDir,'testing','unit_tests','test_data','_test.xml'));
filesize = s.bytes;
verifyTrue(testCase,filesize>18500);
delete(fullfile(sourceDir,'testing','unit_tests','test_data','_test.xml'));
end


function test_homer

% WALLTIME 00:10:00
% MEM 2GB
% DEPENDENCY homer2fieldtrip fieldtrip2homer ft_write_data opto2homer homer2opto

% there are different ways that Homer data can be processed with FieldTrip
% - the way that is used in most FT tutorials is to read (original) Homer files using FT_PREPROCESSING
% - an alternative way is to read (original) Homer files using homer2fieldtrip
% - it is also possible to write FieldTrip data to a Homer file on disk

filename = dccnpath('/home/common/matlab/fieldtrip/data/test/original/nirs/homer/S1001_run01.nirs');

data1 = homer2fieldtrip(filename);
data2 = homer2fieldtrip(fieldtrip2homer(data1));

p = tempdir;
f1 = fullfile(p, 'data1.nirs');
f2 = fullfile(p, 'data2.nirs');

ft_write_data(f1, data1.trial{1}, 'header', data1.hdr)
ft_write_data(f2, data2.trial{1}, 'header', data2.hdr)

% the files written by FieldTrip should still have the same content
data1a = homer2fieldtrip(f1);
data2a = homer2fieldtrip(f2);

% reading the files using the tutorial approach with FT_DEFINETRIAL and FT_PREPROCESSING
cfg = [];
cfg.dataset = filename;
data0b = ft_preprocessing(cfg);
cfg.dataset = f1;
data1b = ft_preprocessing(cfg);
cfg.dataset = f2;
data2b = ft_preprocessing(cfg);

% clean up
delete(f1)
delete(f2)

%%

% do not compare the hdr field, it is different in hdr.orig
fn = {'time', 'trial', 'label', 'opto'};

for i=1:numel(fn)
  field = fn{i};
  % after roundtrip fieldtrip->homer->fieldtrip
  assert(isalmostequal(data1.(field), data2. (field), 'abstol', 1e-8), sprintf('%s is different between data1 and data2', field));

  % after ft_write_data
  assert(isalmostequal(data1.(field), data1a.(field), 'abstol', 1e-8), sprintf('%s is different between data1 and data1a', field));
  assert(isalmostequal(data1.(field), data2a.(field), 'abstol', 1e-8), sprintf('%s is different between data1 and data2a', field));

  % after ft_preprocessing
  assert(isalmostequal(data1.(field), data0b.(field), 'abstol', 1e-8), sprintf('%s is different between data1 and data0b', field));
  assert(isalmostequal(data1.(field), data1b.(field), 'abstol', 1e-8), sprintf('%s is different between data1 and data1b', field));
  assert(isalmostequal(data1.(field), data2b.(field), 'abstol', 1e-8), sprintf('%s is different between data1 and data2b', field));
end


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


function catalog = get_total(varargin)

%GET_TOTAL Read in the complete AEIC Total earthquake catalog
%  CATALOG = GET_TOTAL reads the entire "Total" database of AEIC
%  earthquakes. The output field CATALOG is a structure containing field
%  names that adhere fairly closely to their database definitions and
%  should be self explanatory. Origin time is given in Matlab date format.
%
% CATALOG = GET_TOTAL(DATABASE) specifies the path and name where
% the database can be found. If not specified the DATABASE name defaults to
% the location on the Seismology Linux Network. This function may work
% generically on other databases. However the table requirements and the
% preferred magnitude algorithm are tailoered specifically to the AEIC
% Total database.
%
% For each event GET_TOTAL distills the multiple possible
% magnitudes into a single creates a "preferred magnitude" based on the
% following order of preference:
%        1. Hrvd Mw
%        2. AEIC Mw
%        3. AEIC Ms
%        4. AEIC mb
%        5. AEIC ml
% Events with no magnitude are removed from the catalog. Md magnitudes are
% not currently considered (I believe all Md magnitudes also have an ml).

% Author: Michael West, Geophysical Institute, Univ. of Alaska Fairbanks
% $Date$
% $Revision$

% CHECK ARGUMENTS
if ~admin.antelope_exists
    error('This function requires Antelope');
end
if numel(varargin)>0
    dbName = varargin{1};
else
    dbName = '/Seis/catalogs/aeic/Total/Total';
end;

% LOAD EVENTS FROM NETMAG TABLE WITH Mw MAGNITUDES
db = dbopen(dbName,'r');
db = dblookup(db,'','origin','','');
db1 = dblookup(db,'','netmag','','');
db = dbjoin(db,db1);
db = dbsubset(db,'magtype==''mw''');
[mw.orid,mw.magtype,mw.magnitude,mw.auth] = dbgetv(db,'orid','magtype','magnitude','netmag.auth');
dbclose(db);

% SELECT THE PREFERRED AUTH FOR Mw WHEN MULTIPLES EXIST
% Order hrvd before aeic
mw.auth = lower(mw.auth);
% order hrvd before aeic authored solutions
[tmp index] = sort(mw.auth);
index = flipud(index);
mw.orid = mw.orid(index);
mw.magtype = mw.magtype(index);
mw.magnitude = mw.magnitude(index);
mw.auth = mw.auth(index);
% remove duplicate Mw slecting prefered author
[tmp index tmp1] = unique(mw.orid);
mw.orid = mw.orid(index);
mw.magtype = mw.magtype(index);
mw.magnitude = mw.magnitude(index);
mw.auth = mw.auth(index);

% LOAD ORIGIN TABLE CATALOG
db = dbopen(dbName,'r');
db = dblookup(db,'','origin','','');
db = dbsort(db,'orid');
[catalog.time,catalog.lat,catalog.lon,catalog.depth,catalog.orid] = dbgetv(db,'time','lat','lon','depth','orid');
[catalog.nass,catalog.ndef,catalog.etype,catalog.auth] = dbgetv(db,'nass','ndef','etype','auth');
[catalog.ml,catalog.mb,catalog.ms] = dbgetv(db,'ml','mb','ms');
dbclose(db);
catalog.time = epoch2datenum(catalog.time);
f = find(catalog.ml==-999);     catalog.ml(f) = NaN;
f = find(catalog.mb==-999);     catalog.mb(f) = NaN;
f = find(catalog.ms==-999);     catalog.ms(f) = NaN;
catalog.mw = NaN * catalog.ml;

% ADD Mw TO ORIGIN CATALOG WHEN IT EXISTS
for n = 1:numel(mw.orid)
    f = find(catalog.orid==mw.orid(n));
    if numel(f)~=1
        error('orid mismatch');
    else
        catalog.mw(f) = mw.magnitude(n);
        %disp(['Updated orid ' num2str(catalog.orid(f)) '  ' num2str(mw.orid(n)) ]);
    end
end

% CREATE A PREFERRED MAGNITUDE
catalog.prefMagType = repmat({'none'},size(catalog.ml));
catalog.prefMagnitude = NaN * catalog.ml;
% set pref magnitude as ml
f = find(~isnan(catalog.ml));
catalog.prefMagType(f) = {'ml'};
catalog.prefMagnitude(f) = catalog.ml(f);
% set pref magnitude as mb
f = find(~isnan(catalog.mb));
catalog.prefMagType(f) = {'mb'};
catalog.prefMagnitude(f) = catalog.mb(f);
% set pref magnitude as ms
f = find(~isnan(catalog.ms));
catalog.prefMagType(f) = {'ms'};
catalog.prefMagnitude(f) = catalog.ms(f);
% set pref magnitude as mw
f = find(~isnan(catalog.mw));
catalog.prefMagType(f) = {'mw'};
catalog.prefMagnitude(f) = catalog.mw(f);

% REMOVE EVENTS WITH NO MAGNITUDE
f = find(~isnan(catalog.prefMagnitude));
numEventsAll = num2str(numel(catalog.prefMagnitude));
numEventsWithMag = num2str(numel(f));
catalog.time          = catalog.time(f);
catalog.lat           = catalog.lat(f);
catalog.lon           = catalog.lon(f);
catalog.depth         = catalog.depth(f);
catalog.orid          = catalog.orid(f);
catalog.nass          = catalog.nass(f);
catalog.ndef          = catalog.ndef(f);
catalog.etype         = catalog.etype(f);
catalog.auth          = catalog.auth(f);
catalog.ml            = catalog.ml(f);
catalog.mb            = catalog.mb(f);
catalog.ms            = catalog.ms(f);
catalog.mw            = catalog.mw(f);
catalog.prefMagType   = catalog.prefMagType(f);
catalog.prefMagnitude = catalog.prefMagnitude(f);

% STATUS LINE
dateEarliest = datestr(min(catalog.time),'yyyy/mm/dd HH:MM:SS');
dateMostRecent = datestr(max(catalog.time),'yyyy/mm/dd HH:MM:SS');
disp(['  Retrieved ' numEventsWithMag ' earthquakes with magnitudes (out of ' numEventsAll ' total)']);
disp(['       Earliest:    ' dateEarliest ]);
disp(['       Most recent: ' dateMostRecent ]);
disp('');


function w = cvx( v, b )

%CVX   The CVX disciplined convex programming system.
%   CVX is a modeling framework for building, constructing, and solving
%   disciplined convex programs. CVX has online help for many functions and
%   operations, divided into several subsection:
%      cvx/commands   - Top-level commands to control CVX
%      cvx/keywords   - Keywords for declaring variables and objectives
%      cvx/builtins   - Built-in operators and functions supported in CVX models
%      cvx/functions  - Additional functions added by CVX
%      cvx/sets       - Definitions of common convex sets
%      cvx/structures - Matrix structure definitions
%   CVX also provides an extensive user guide in PDF format, which is found
%   in its top directory. This directory can be found by typing
%      cvx_where
%   at the command prompt.

global cvx___
switch nargin,
    case 2,
        w = cvx___.obj;
        switch numel( v ),
            case 2,
                w.size_ = v;
            case 1,
                w.size_ = [ v, 1 ];
            case 0,
                % w.size_ = [ 0, 1 ];
            otherwise,
                if v(end) == 1,
                    v = v(1:find(v>1,1,'last'));
                    v(1,end+1:2) = 1;
                end
                w.size_ = v;
        end
        if issparse( b )
            w.basis_ = b;
        elseif isempty( b )
            w.basis_ = sparse( 1, prod( v ) );
        else
            w.basis_ = sparse( b );
        end
    case 1,
        if isnumeric( v ),
            w = cvx___.obj;
            w.size_ = size( v );
            if issparse( v ),
                w.basis_ = reshape( v, 1, prod(s) );
            else
                w.basis_ = sparse( v(:)' );
            end
        elseif isa( v, 'cvx' ),
            w = v;
            return
        else
            w = class( v, 'cvx' );
        end
    case 0,
        w = cvx___.obj;
end
w.id_ = cvx___.id + 1;
cvx___.id = w.id_;

% Copyright 2005-2014 CVX Research, Inc.
% See the file LICENSE.txt for full copyright information.
% The command 'cvx_where' will show where this file is located.


function test_bug2336

% WALLTIME 00:30:00
% MEM 4gb
% DEPENDENCY

% script to test the integration of FEM output files created by BESA MRI.
%
% Copyright (C) 2013, BESA GmbH
%
% File name: test_bug2336.m
%
% Author: Robert Spangler
% Created: 2013-11-27

% ensure that fieldtrip/extrenal/besa is on the path
ft_hastoolbox('besa', 1);

%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%% The first part of the test script pertains to the low-level reading functions

% Specify path to data folder
strPath_Data = dccnpath('/home/common/matlab/fieldtrip/data/test/bug2336/');

% Filenames of BESA MRI output files
strPath_Leadfield         = sprintf('%sBESA_MRI_Electrode_Config_34_PB_FEM_DATA.lft', strPath_Data);
strPath_SourceSpaceNodes  = sprintf('%sBESA_MRI_Electrode_Config_34_PB_FEM_DATA.loc', strPath_Data);
strPath__ElectrodeConfig  = sprintf('%sElectrode_Config_34.sfh', strPath_Data);
strPath__SkullSurface     = sprintf('%sBESA_MRI_MRI_PB_FEM_SKULL_ACPC.srf', strPath_Data);
strPath__BrainSurface     = sprintf('%sBESA_MRI_PB_FEM_BRAIN_ACPC.srf', strPath_Data);
strPath__CSFSurface       = sprintf('%sBESA_MRI_PB_FEM_CSF_ACPC.srf', strPath_Data);
strPath__ScalpSurface     = sprintf('%sBESA_MRI_PB_FEM_SCALP_ACPC.srf', strPath_Data);

% Read leadfield
[dim lf] = readBESAlft(strPath_Leadfield);
fprintf('Number of channels: %i\n', dim(1));
fprintf('Number of nodes: %i\n', dim(2));
fprintf('Number of orientations: %i\n', dim(3));

% Read source space grid nodes
[ssg IdxNeighbour] = readBESAloc(strPath_SourceSpaceNodes);
fprintf('Number of nodes: %i\n', size(ssg, 1));
fprintf('Number of neighbours/node: %i\n', size(IdxNeighbour, 1));

% Read electrode config &  fiducials
cfg_eeg = readBESAsfh(strPath__ElectrodeConfig, 'eeg');
cfg_fid = readBESAsfh(strPath__ElectrodeConfig, 'fiducial');

% Read scalp, skull, csf & brain surface
cfg_scalp = readBESAsrf(strPath__ScalpSurface);
cfg_skull = readBESAsrf(strPath__SkullSurface);
cfg_csf   = readBESAsrf(strPath__CSFSurface);
cfg_brain = readBESAsrf(strPath__BrainSurface);

%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%% The second part of the test script pertains to the high-level FieldTrip implementation

cfg = [];
cfg.method = 'besa';
cfg.elecfile = strPath__ElectrodeConfig;
cfg.hdmfile = strPath_Leadfield;
cfg.outputfile = tempname;
cfg.smooth = 'no';
vol = ft_prepare_headmodel(cfg);

pos = ssg(1,:);
sens1 = ft_read_sens(strPath__ElectrodeConfig);
sens2 = sens1;
sens2.elecpos = sens2.elecpos+randn(size(sens2.elecpos));

[vol1, sens1] = ft_prepare_vol_sens(vol, sens1);
lf1 = ft_compute_leadfield(pos, sens1, vol1);

[vol2, sens2] = ft_prepare_vol_sens(vol, sens2);
lf2 = ft_compute_leadfield(pos, sens2, vol2);

figure
subplot(2,2,1)
ft_plot_topo3d(sens1.elecpos, lf(:,1))
subplot(2,2,2)
ft_plot_topo3d(sens1.elecpos, lf(:,2))
subplot(2,2,3)
ft_plot_topo3d(sens1.elecpos, lf(:,3))

% show 3D stuff
figure
ft_plot_dipole(pos, [0 0 1]', 'diameter', 10, 'length', 20);
ft_plot_topo3d(sens1.elecpos, lf(:,3))

[X, Y, Z] = ndgrid(1:vol.dim(1), 1:vol.dim(2), 1:vol.dim(3));
pos = ft_warp_apply(vol.transform, [X(:) Y(:) Z(:)]);
ft_plot_mesh(pos);


function varargout = subsref(pf,s)
% overide polefigure() and polefigure{}

if any(strcmp(s(1).type,{'()','{}'}))

  if strcmp(s(1).type,'{}') || iscell(s(1).subs{1}) || ...
      (ischar(s(1).subs{1}) && ~strcmp(s(1).subs{1},':')) || isa(s(1).subs{1},'Miller')

    pf = pf.select(s(1).subs);

  else

    id = false(size(pf.intensities));

    if isa(s(1).subs{1},'vector3d')
      id(find(pf.r,s(1).subs{1}))=true;
    else
      id = subsasgn(id,s(1),true);
    end

    cs = cumsum([0,cellfun('prodofsize',pf.allI)]);

    for k = 1:length(pf.allI)

      idi = id(cs(k)+1:cs(k+1));

      pf.allI{k} = pf.allI{k}(idi);
      pf.allR{k} = pf.allR{k}(idi);
    end
  end

  % is there something more to do?
  if numel(s)>1
    s = s(2:end);
  else
    varargout{1} = pf;
    return
  end
end

% maybe reference to a dynamic property
try %#ok<TRYNC>
  [varargout{1:nargout}] = subsref@dynProp(pf,s);
  return
end

% maybe reference to a dynamic option
try %#ok<TRYNC>
  [varargout{1:nargout}] = subsref@dynOption(pf,s);
  return
end

end


function [y,cl,cu] = checkIpoptConstraints(x, constraint)
    % nested function that commputes the constraints of the NLP problem
    %
    % Parameters:
    %  constraint: a structure of arrays that contains the information
    %  of all constraints

    cl = vertcat(constraint.LowerBound);
    cu = vertcat(constraint.UpperBound);
    % preallocation
    y   = zeros(constraint.Dimension,1);
    for i = 1:constraint.numFuncs
        var = cellfun(@(v)x(v(:)),constraint.DepIndices{i},'UniformOutput',false); % dependent variables

        % calculate constraints
        if isempty(constraint.AuxData{i})
            y(constraint.FuncIndices{i}) = y(constraint.FuncIndices{i}) + feval(constraint.Funcs{i}, var{:});
        else
            y(constraint.FuncIndices{i})  = y(constraint.FuncIndices{i}) + feval(constraint.Funcs{i}, var{:}, constraint.AuxData{i}{:});
        end
    end

end


% example8_4.m

pos = tritop(8,5);
net = selforgmap([8 5],'topologyFcn','tritop');
plotsomtop(net)
web -broswer http://www.ilovematlab.cn/forum-222-1.html