function[labelImage] = imageInsertBlobLabels(labelImage, labelMap, labelNames, varargin)
% [labelImage] = imageInsertBlobLabels(labelImage, labelMap, labelNames, varargin)
%
% Uses insertText (from Vision Toolbox) to insert a cell of strings into
% the image. Each label is positioned at the center of mass of its blob.
%
% Test case (should output a red 'c' on a white image):
% labelImage = ones(256, 256, 3);
% labelMap = zeros(256, 256);
% labelMap(100, 100) = 3;
% labelMap(101, 100) = 3;
% labelNames = {'a', 'b', 'c'};
% outImage = imageInsertBlobLabels(labelImage, labelMap, labelNames, 'fontColor', [255, 0, 0], 'minComponentSize', 1);
% imshow(outImage);
%
% Copyright by Holger Caesar, 2016

% Parse input
p = inputParser;
addParameter(p, 'fontSize', 15);
addParameter(p, 'fontWidth', 8);
addParameter(p, 'fontColor', [26, 232, 222]);
addParameter(p, 'minComponentSize', 100); % at least 2px
addParameter(p, 'skipLabelInds', []); % labels that are ignored
parse(p, varargin{:});

fontSize = p.Results.fontSize;
fontWidth = p.Results.fontWidth;
fontColor = p.Results.fontColor;
minComponentSize = p.Results.minComponentSize;
skipLabelInds = p.Results.skipLabelInds;

% Check inputs
assert(~isa(labelMap, 'gpuArray'));

% Get unique list of labels
labelList = double(unique(labelMap(:)));
labelList(labelList == 0) = [];
labelListCount = numel(labelList);
if labelListCount == 0
    % Don't do anything if there are no labels
    return;
end

% Init
pixelIdxLists = cell(labelListCount, 1);
pixelIdxLabels = cell(labelListCount, 1);
usedMap = false(size(labelMap));

% Get the indices for all blobs
for labelMapUnIdx = 1 : labelListCount
    labelIdx = labelList(labelMapUnIdx);

    % Get connected components of that label
    components = bwconncomp(labelMap == labelIdx);
    pixelIdxList = components.PixelIdxList(:);
    sel = cellfun(@(x) numel(x), pixelIdxList) >= minComponentSize;
    pixelIdxList = pixelIdxList(sel);
    pixelIdxLabels{labelMapUnIdx} = ones(numel(pixelIdxList), 1) .* labelIdx;
    pixelIdxLists{labelMapUnIdx} = pixelIdxList;
end

% Convert cell to matrix
pixelIdxLists = flattenCellArray(pixelIdxLists);
pixelIdxLabels = cell2mat(pixelIdxLabels);
assert(numel(pixelIdxLists) == numel(pixelIdxLabels));
compCount = numel(pixelIdxLists);

% Sort by size
[~, sortOrder] = sort(cellfun(@numel, pixelIdxLists), 'descend');
pixelIdxLists = pixelIdxLists(sortOrder);
pixelIdxLabels = pixelIdxLabels(sortOrder);

for compIdx = 1 : compCount
    labelIdx = pixelIdxLabels(compIdx);
    if ismember(labelIdx, skipLabelInds)
        continue;
    end
    labelName = labelNames{labelIdx};

    % Get list of relevant pixels
    pixInds = pixelIdxLists{compIdx};
    pixInds = setdiff(pixInds, find(usedMap(:)));
    if isempty(pixInds)
        continue;
    end

    % Compute center of mass
    [y, x] = ind2sub(size(labelMap), pixInds);
    yCenter = median(y);
    xCenter = median(x);

    height = fontSize;
    width = fontWidth * numel(labelName);
    yStart = max(1, round(yCenter - height / 2));
    xStart = max(1, round(xCenter - width / 2));
    yEnd = min(yStart + height - 1, size(usedMap, 1));
    xEnd = min(xStart + width  - 1, size(usedMap, 2));

    if any(any(usedMap(yStart:yEnd, xStart:xEnd)))
        continue;
    end

    % Place label here
    labelImage = insertText(labelImage, [xStart, yStart], labelName, 'Font',  'LucidaSansDemiBold', 'FontSize', fontSize, 'TextColor', fontColor, 'BoxOpacity', 0.0, 'AnchorPoint', 'LeftTop');

    % Mark those pixels as used
    usedMap(yStart:yEnd, xStart:xEnd) = true;
end;


% Change to your downloaded location
clear
addpath('C:\liblinear\matlab')
addpath('../training_code/');
addpath('../utilities/');
addpath('../../data extraction/');

%% load shared definitions and AU data
all_dataset_aus = [1, 2, 4, 5, 6, 7, 9, 10, 12, 14, 15, 17, 20, 23, 25, 26, 28, 45];

% Set up the hyperparameters to be validated
hyperparams.c = 10.^(-7:0.5:1);
hyperparams.e = 10.^(-3);

hyperparams.validate_params = {'c', 'e'};

% Set the training function
svm_train = @svm_train_linear;

% Set the test function (the first output will be used for validation)
svm_test = @svm_test_linear;

BP4D_aus = [1, 2, 4, 6, 7, 10, 12, 14, 15, 17, 23];
SEMAINE_aus = [2, 12, 17, 25, 28, 45];
FERA2011_aus = [1, 2, 4, 6, 7, 10, 12, 15, 17, 25, 26];
UNBC_aus = [6, 7, 9, 12, 25, 26];
DISFA_aus = [1, 2, 4, 5, 6, 9, 12, 15, 17, 20, 25, 26];
Bosphorus_aus = [1, 2, 4, 5, 6, 7, 9, 10, 12, 14, 15, 17, 20, 23, 25, 26, 45];

for a=1:numel(all_dataset_aus)

    au = all_dataset_aus(a);

    train_samples = [];
    valid_samples = [];

    train_labels = [];
    valid_labels = [];

    % Keeping track which validation sample came from which dataset, as we
    % will be validating based on which hyperparam leads to best
    % performance on all datasets (mean F1)
    eval_ids = [];
    dataset_ids = {};

    if(~isempty(find(BP4D_aus == au, 1)))
        op = cd('../BP4D/');
        rest_aus = setdiff(BP4D_aus, au);
        shared_defs;
        % load the training and testing data for the current fold
        [train_samples_bp4d, train_labels_bp4d, valid_samples_bp4d, valid_labels_bp4d, ~, PC, means, scaling] = Prepare_HOG_AU_data_generic_dynamic(train_recs, devel_recs, au, BP4D_dir, hog_data_dir);

        train_samples = cat(1, train_samples, train_samples_bp4d);
        valid_samples = cat(1, valid_samples, valid_samples_bp4d);

        train_labels = cat(1, train_labels, train_labels_bp4d);
        valid_labels = cat(1, valid_labels, valid_labels_bp4d);

        if(isempty(eval_ids))
           eval_ids = ones(size(valid_labels_bp4d,1), 1);
        end

        clear 'train_samples_bp4d' 'train_labels_bp4d' 'valid_samples_bp4d' 'valid_labels_bp4d'

        dataset_ids = cat(1, dataset_ids, {'BP4D'});

        cd(op);

    end

    if(~isempty(find(FERA2011_aus == au, 1)))
        op = cd('../FERA2011/');
        rest_aus = setdiff(FERA2011_aus, au);
        shared_defs;
        all_recs = cat(2, train_recs, devel_recs);
        [users_train, users_valid_fera] = get_balanced_fold(FERA2011_dir, all_recs, au, 1/3, 1);

        % load the training and testing data for the current fold
        [train_samples_f2011, train_labels_f2011, valid_samples_f2011, valid_labels_f2011, ~, PC, means, scaling] = Prepare_HOG_AU_data_generic_dynamic(users_train, users_valid_fera, au, rest_aus, FERA2011_dir, features_dir);

        train_samples = cat(1, train_samples, train_samples_f2011);
        valid_samples = cat(1, valid_samples, valid_samples_f2011);

        train_labels = cat(1, train_labels, train_labels_f2011);
        valid_labels = cat(1, valid_labels, valid_labels_f2011);

        if(isempty(eval_ids))
           eval_ids = ones(size(valid_labels_f2011,1), 1);
        else
           eval_ids = cat(1, eval_ids, (eval_ids(end)+1)*ones(size(valid_labels_f2011,1), 1));
        end

        clear 'train_samples_f2011' 'train_labels_f2011' 'valid_samples_f2011' 'valid_labels_bp4d'

        dataset_ids = cat(1, dataset_ids, {'FERA2011'});

        cd(op);

    end

    if(~isempty(find(SEMAINE_aus == au, 1)))
        op = cd('../SEMAINE/');
        rest_aus = setdiff(SEMAINE_aus, au);
        shared_defs;
        % load the training and testing data for the current fold
        [train_samples_sem, train_labels_sem, valid_samples_sem, valid_labels_sem, ~, PC, means, scaling] = Prepare_HOG_AU_data_generic_dynamic(train_recs, devel_recs, au, rest_aus, SEMAINE_dir, hog_data_dir);

        train_samples = cat(1, train_samples, train_samples_sem);
        valid_samples = cat(1, valid_samples, valid_samples_sem);

        train_labels = cat(1, train_labels, train_labels_sem);
        valid_labels = cat(1, valid_labels, valid_labels_sem);

        if(isempty(eval_ids))
           eval_ids = ones(size(valid_labels_sem,1), 1);
        else
           eval_ids = cat(1, eval_ids, (eval_ids(end)+1)*ones(size(valid_labels_sem,1), 1));
        end

        clear 'train_samples_sem' 'train_labels_sem' 'valid_samples_sem' 'valid_labels_sem'
        dataset_ids = cat(1, dataset_ids, {'SEMAINE'});
        cd(op);

    end

    if(~isempty(find(Bosphorus_aus == au, 1)))
        op = cd('../Bosphorus/');
        rest_aus = setdiff(DISFA_aus, au);
        shared_defs;

        % make sure validation data's labels are balanced
        [users_train, users_valid_bosph] = get_balanced_fold(Bosphorus_dir, all_recs, au, 1/3, 1);

        % need to split the rest
        [train_samples_bosph, train_labels_bosph, valid_samples_bosph, valid_labels_bosph, ~, PC, means, scaling, valid_ids, valid_success] = Prepare_HOG_AU_data_dynamic(users_train, users_valid_bosph, au, rest_aus, Bosphorus_dir, hog_data_dir);

        train_labels_bosph(train_labels_bosph > 1) = 1;
        valid_labels_bosph(valid_labels_bosph > 1) = 1;

        % As there are only a few Bosphorus images (it being an image dataset)
        % we oversample it quite a bit
        train_samples_bosph = repmat(train_samples_bosph, 10, 1);
        train_labels_bosph = repmat(train_labels_bosph, 10, 1);

        train_samples = cat(1, train_samples, train_samples_bosph);
        valid_samples = cat(1, valid_samples, valid_samples_bosph);

        train_labels = cat(1, train_labels, train_labels_bosph);
        valid_labels = cat(1, valid_labels, valid_labels_bosph);

        if(isempty(eval_ids))
           eval_ids = ones(size(valid_labels_bosph, 1), 1);
        else
           eval_ids = cat(1, eval_ids, (eval_ids(end)+1)*ones(size(valid_labels_bosph, 1), 1));
        end

        clear 'train_samples_bosph' 'train_labels_bosph' 'valid_samples_bosph' 'valid_labels_bosph'
        dataset_ids = cat(1, dataset_ids, {'Bosphorus'});
        cd(op);

    end

    if(~isempty(find(DISFA_aus == au, 1)))
        op = cd('../DISFA/');
        rest_aus = setdiff(DISFA_aus, au);
        shared_defs;

        % make sure validation data's labels are balanced
        [users_train, users_valid_disfa] = get_balanced_fold(DISFA_dir, users, au, 1/3, 1);

        % need to split the rest
        [train_samples_disf, train_labels_disf, valid_samples_disf, valid_labels_disf, ~, PC, means, scaling, valid_ids, valid_success] = Prepare_HOG_AU_data_generic_dynamic(users_train, users_valid_disfa, au, rest_aus, DISFA_dir, hog_data_dir);

        train_labels_disf(train_labels_disf > 1) = 1;
        valid_labels_disf(valid_labels_disf > 1) = 1;

        train_samples = cat(1, train_samples, train_samples_disf);
        valid_samples = cat(1, valid_samples, valid_samples_disf);

        train_labels = cat(1, train_labels, train_labels_disf);
        valid_labels = cat(1, valid_labels, valid_labels_disf);

        if(isempty(eval_ids))
           eval_ids = ones(size(valid_labels_disf,1), 1);
        else
           eval_ids = cat(1, eval_ids, (eval_ids(end)+1)*ones(size(valid_labels_disf,1), 1));
        end

        clear 'train_samples_disf' 'train_labels_disf' 'valid_samples_disf' 'valid_labels_disf'
        dataset_ids = cat(1, dataset_ids, {'DISFA'});
        cd(op);

    end

    if(~isempty(find(UNBC_aus == au, 1)))
        op = cd('../UNBC/');
        rest_aus = setdiff(UNBC_aus, au);
        shared_defs;

        [users_train, users_valid_unbc] = get_balanced_fold(UNBC_dir, all_recs, au, 1/3, 1);

        % load the training and testing data for the current fold
        [train_samples_unbc, train_labels_unbc, valid_samples_unbc, valid_labels_unbc, ~, PC, means, scaling] = Prepare_HOG_AU_data_dynamic(users_train, users_valid_unbc, au, rest_aus, UNBC_dir, features_dir);

        % Binarizing the data
        train_labels_unbc(train_labels_unbc > 1) = 1;
        valid_labels_unbc(valid_labels_unbc > 1) = 1;

        train_samples = cat(1, train_samples, train_samples_unbc);
        valid_samples = cat(1, valid_samples, valid_samples_unbc);

        train_labels = cat(1, train_labels, train_labels_unbc);
        valid_labels = cat(1, valid_labels, valid_labels_unbc);

        if(isempty(eval_ids))
           eval_ids = ones(size(valid_labels_unbc,1), 1);
        else
           eval_ids = cat(1, eval_ids, (eval_ids(end)+1)*ones(size(valid_labels_unbc,1), 1));
        end

        clear 'train_samples_unbc' 'train_labels_unbc' 'valid_samples_unbc' 'valid_labels_unbc'
        dataset_ids = cat(1, dataset_ids, {'UNBC'});
        cd(op);

    end

    train_samples = sparse(train_samples);
    dataset_ids
    %% Cross-validate here
    hyperparams.eval_ids = eval_ids;
    [ best_params, ~ ] = validate_grid_search_no_par(svm_train, svm_test, false, train_samples, train_labels, valid_samples, valid_labels, hyperparams);
    model = svm_train(train_labels, train_samples, best_params);

    model.eval_ids = eval_ids;

    [~, predictions_all] = svm_test(valid_labels, valid_samples, model);

    name = sprintf('mat_models/AU_%d_dynamic.mat', au);

    eval_ids_uq = unique(eval_ids)';
    F1s = [];
    for i=eval_ids_uq
        F1s = cat(2, F1s, compute_F1(valid_labels(eval_ids==i), predictions_all(eval_ids==i)));
    end

    meanF1 = mean(F1s);

    save(name, 'model', 'F1s', 'meanF1', 'predictions_all', 'valid_labels', 'eval_ids', 'dataset_ids');

    % Write out the model
    name = sprintf('classifiers/AU_%d_dynamic.dat', au);

    pos_lbl = model.Label(1);
    neg_lbl = model.Label(2);

    w = model.w(1:end-1)';
    b = model.w(end);

    svs = bsxfun(@times, PC, 1./scaling') * w;

    write_lin_dyn_svm(name, means, svs, b, pos_lbl, neg_lbl);

    clear 'train_samples' 'train_labels' 'valid_samples' 'valid_labels'
end


function info = cnn_imagenet_evaluate(varargin)
% CNN_IMAGENET_EVALUATE   Evauate MatConvNet models on ImageNet

run(fullfile(fileparts(mfilename('fullpath')), ...
  '..', '..', 'matlab', 'vl_setupnn.m')) ;

opts.dataDir = fullfile('data', 'ILSVRC2012') ;
opts.expDir = fullfile('data', 'imagenet12-eval-vgg-f') ;
opts.imdbPath = fullfile(opts.expDir, 'imdb.mat');
opts.modelPath = fullfile('data', 'models', 'imagenet-vgg-f.mat') ;
opts.networkType = [] ;
opts.lite = false ;
opts.numFetchThreads = 12 ;
opts.train.batchSize = 128 ;
opts.train.numEpochs = 1 ;
opts.train.gpus = [] ;
opts.train.prefetch = true ;
opts.train.expDir = opts.expDir ;

opts = vl_argparse(opts, varargin) ;
display(opts);

% -------------------------------------------------------------------------
%                                                   Database initialization
% -------------------------------------------------------------------------

if exist(opts.imdbPath)
  imdb = load(opts.imdbPath) ;
else
  imdb = cnn_imagenet_setup_data('dataDir', opts.dataDir, 'lite', opts.lite) ;
  mkdir(opts.expDir) ;
  save(opts.imdbPath, '-struct', 'imdb') ;
end

% -------------------------------------------------------------------------
%                                                    Network initialization
% -------------------------------------------------------------------------

net = load(opts.modelPath) ;
if isfield(net, 'net') ;
  net = net.net ;
end
% Cannot use isa('dagnn.DagNN') because it is not an object yet
isDag = isfield(net, 'params') ;

if isDag
  opts.networkType = 'dagnn' ;
  net = dagnn.DagNN.loadobj(net) ;
  trainfn = @cnn_train_dag ;

  % Drop existing loss layers
  drop = arrayfun(@(x) isa(x.block,'dagnn.Loss'), net.layers) ;
  for n = {net.layers(drop).name}
    net.removeLayer(n) ;
  end

  % Extract raw predictions from softmax
  sftmx = arrayfun(@(x) isa(x.block,'dagnn.SoftMax'), net.layers) ;
  predVar = 'prediction' ;
  for n = {net.layers(sftmx).name}
    % check if output
    l = net.getLayerIndex(n) ;
    v = net.getVarIndex(net.layers(l).outputs{1}) ;
    if net.vars(v).fanout == 0
      % remove this layer and update prediction variable
      predVar = net.layers(l).inputs{1} ;
      net.removeLayer(n) ;
    end
  end

  % Add custom objective and loss layers on top of raw predictions
  net.addLayer('objective', dagnn.Loss('loss', 'softmaxlog'), ...
               {predVar,'label'}, 'objective') ;
  net.addLayer('top1err', dagnn.Loss('loss', 'classerror'), ...
               {predVar,'label'}, 'top1err') ;
  net.addLayer('top5err', dagnn.Loss('loss', 'topkerror', ...
                                     'opts', {'topK',5}), ...
               {predVar,'label'}, 'top5err') ;

  % Make sure that the input is called 'input'
  v = net.getVarIndex('data') ;
  if ~isnan(v)
    net.renameVar('data', 'input') ;
  end

  % Swtich to test mode
  net.mode = 'test' ;
else
  opts.networkType = 'simplenn' ;
  net = vl_simplenn_tidy(net) ;
  trainfn = @cnn_train ;
  net.layers{end}.type = 'softmaxloss' ; % softmax -> softmaxloss
end

% Synchronize label indexes used in IMDB with the ones used in NET
imdb = cnn_imagenet_sync_labels(imdb, net);

% Run evaluation
[net, info] = trainfn(net, imdb, getBatchFn(opts, net.meta), ...
                      opts.train, ...
                      'train', NaN, ...
                      'val', find(imdb.images.set==2)) ;

% -------------------------------------------------------------------------
function fn = getBatchFn(opts, meta)
% -------------------------------------------------------------------------
useGpu = numel(opts.train.gpus) > 0 ;
bopts = meta.normalization ;
bopts.numThreads = opts.numFetchThreads ;

% Most networks are trained by resizing images to 256 pixels and then
% cropping a slightly smaller subarea. Reproduce this effect (center
% crop) for a more accurate evaluation (it also avoids resizing the
% images if these have been pre-processed to be of this size, which
% accelerates everything).

bopts.border = 256 - meta.normalization.imageSize ;

switch lower(opts.networkType)
  case 'simplenn'
    fn = @(x,y) getSimpleNNBatch(bopts,x,y) ;
  case 'dagnn'
    fn = @(x,y) getDagNNBatch(bopts,useGpu,x,y) ;
end

% -------------------------------------------------------------------------
function [im,labels] = getSimpleNNBatch(opts, imdb, batch)
% -------------------------------------------------------------------------
images = strcat([imdb.imageDir filesep], imdb.images.name(batch)) ;
im = cnn_imagenet_get_batch(images, opts, ...
                            'prefetch', nargout == 0) ;
labels = imdb.images.label(batch) ;

% -------------------------------------------------------------------------
function inputs = getDagNNBatch(opts, useGpu, imdb, batch)
% -------------------------------------------------------------------------
images = strcat([imdb.imageDir filesep], imdb.images.name(batch)) ;
im = cnn_imagenet_get_batch(images, opts, ...
                            'prefetch', nargout == 0) ;
if nargout > 0
  if useGpu
    im = gpuArray(im) ;
  end
  inputs = {'input', im, 'label', imdb.images.label(batch)} ;
end


function isodoseClosedContour = getBeamCrossSection()
%isodoseClosedContour50 = getBeamCrossSection()
%
%Output: isodoseClosedContour - representation of beam contour
%dimension (3xN). 1st, 2nd and 3rd row represent x, y and z-coords of the
%contour respectively. It is assumed that the ray starts at (0,0,0) and
%moves along +(ve) x-axis. If collimatorType does not match the list, an
%empty isodoseClosedContour50 is returned.
%
%APA 01/21/09
%
% Copyright 2010, Joseph O. Deasy, on behalf of the CERR development team.
%
% This file is part of The Computational Environment for Radiotherapy Research (CERR).
%
% CERR development has been led by:  Aditya Apte, Divya Khullar, James Alaly, and Joseph O. Deasy.
%
% CERR has been financially supported by the US National Institutes of Health under multiple grants.
%
% CERR is distributed under the terms of the Lesser GNU Public License.
%
%     This version of CERR is free software: you can redistribute it and/or modify
%     it under the terms of the GNU General Public License as published by
%     the Free Software Foundation, either version 3 of the License, or
%     (at your option) any later version.
%
% CERR is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
% without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
% See the GNU General Public License for more details.
%
% You should have received a copy of the GNU General Public License
% along with CERR.  If not, see <http://www.gnu.org/licenses/>.

% Get a 10x10 section at 100cm distance. In future, these points should
% come from Leaf-sequences or beamlet-fluence map.
isodoseClosedContour(3,:) = [-10 10 10 -10 -10]/2;
isodoseClosedContour(2,:) = [-10 -10 10 10 -10]/2;
isodoseClosedContour(1,:) = [100 100 100 100 100];
return


function varargout = process_mne_maxwell( varargin )
% PROCESS_MNE_MAXWELL: MNE-Python call to mne.preprocessing.maxwell_filter: Maxwell filtering / SSS /tSSS
%
% USAGE:   sProcess = process_mne_maxwell('GetDescription')
%            sInput = process_mne_maxwell('Run', sProcess, sInput, method=[])

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

eval(macro_method);
end

%% ===== GET DESCRIPTION =====
function sProcess = GetDescription() %#ok<DEFNU>
    % Description the process
    sProcess.Comment     = 'MNE-Python: maxwell_filter (SSS/tSSS)';
    sProcess.FileTag     = 'sss';
    sProcess.Category    = 'File';
    sProcess.SubGroup    = 'Pre-process';
    sProcess.Index       = 85;
    % Definition of the input accepted by this process
    sProcess.InputTypes  = {'raw'};
    sProcess.OutputTypes = {'raw'};
    sProcess.nInputs     = 1;
    sProcess.nMinFiles   = 1;
    sProcess.processDim  = [];    % Do not split matrix
    sProcess.Description = 'https://www.nmr.mgh.harvard.edu/mne/stable/generated/mne.preprocessing.maxwell_filter.html';
    % Definition of the options
    % Help
    sProcess.options.help.Comment = 'mne.preprocessing.maxwell_filter
For information about the parameters, click on "Online tutorial"

';
    sProcess.options.help.Type    = 'label';
    % int_order: Order of internal component of spherical expansion
    sProcess.options.int_order.Comment = 'int_order (default=8): ';
    sProcess.options.int_order.Type    = 'value';
    sProcess.options.int_order.Value   = {8,'',0};
    % ext_order: Order of external component of spherical expansion
    sProcess.options.ext_order.Comment = 'ext_order (default=3): ';
    sProcess.options.ext_order.Type    = 'value';
    sProcess.options.ext_order.Value   = {3,'',0};
    % origin: Origin of internal and external multipolar moment space in meters
    sProcess.options.origin.Comment = 'origin (auto or 3D point): ';
    sProcess.options.origin.Type    = 'text';
    sProcess.options.origin.Value   = 'auto';
    % coord_frame: Origin of internal and external multipolar moment space in meters
    sProcess.options.coord_frame.Comment = {'head', 'meg', 'coord_frame (default=head): '; ...
                                            'head', 'meg', ''};
    sProcess.options.coord_frame.Type    = 'radio_linelabel';
    sProcess.options.coord_frame.Value   = 'head';
    % destination: The destination location for the head.
    sProcess.options.destination.Comment = 'destination (empty or 3D-point):';
    sProcess.options.destination.Type    = 'value';
    sProcess.options.destination.Value   = {[], 'list', 3};
    % regularize
    sProcess.options.regularize.Comment = 'regularize (default=on)';
    sProcess.options.regularize.Type    = 'checkbox';
    sProcess.options.regularize.Value   = 1;
    % ignore_ref
    sProcess.options.ignore_ref.Comment = 'ignore_ref (default=off)';
    sProcess.options.ignore_ref.Type    = 'checkbox';
    sProcess.options.ignore_ref.Value   = 0;
    % st_duration: tSSS
    sProcess.options.st_duration.Comment = 'st_duration (0=disable tSSS, default=10): ';
    sProcess.options.st_duration.Type    = 'value';
    sProcess.options.st_duration.Value   = {0,'s',3};
    % st_correlation
    sProcess.options.st_correlation.Comment = 'st_correlation (default=0.98): ';
    sProcess.options.st_correlation.Type    = 'value';
    sProcess.options.st_correlation.Value   = {0.98,'',2};
    % st_fixed
    sProcess.options.st_fixed.Comment = 'st_fixed (default=on)';
    sProcess.options.st_fixed.Type    = 'checkbox';
    sProcess.options.st_fixed.Value   = 1;
    % st_only
    sProcess.options.st_only.Comment = 'st_only (default=off)';
    sProcess.options.st_only.Type    = 'checkbox';
    sProcess.options.st_only.Value   = 0;
    % mag_scale
    sProcess.options.mag_scale.Comment = 'mag_scale (default=100): ';
    sProcess.options.mag_scale.Type    = 'value';
    sProcess.options.mag_scale.Value   = {100,'',4};
    % skip_by_annotation
    sProcess.options.skip_by_annotation.Comment = 'skip_by_annotation: ';
    sProcess.options.skip_by_annotation.Type    = 'text';
    sProcess.options.skip_by_annotation.Value   = 'edge, bad_acq_skip';
    % fine_calibration_file (site specific)
    sProcess.options.calibration.Comment = 'fine-calibration file:';
    sProcess.options.calibration.Type    = 'filename';
    sProcess.options.calibration.Value = {...
        '', ...                               % Filename
        '', ...                               % FileFormat
        'open', ...                           % Dialog type: {open,save}
        'Import fine-calibration file...', ...     % Window title
        'ImportData', ...                     % LastUsedDir: {ImportData,ImportChannel,ImportAnat,ExportChannel,ExportData,ExportAnat,ExportProtocol,ExportImage,ExportScript}
        'single', ...                         % Selection mode: {single,multiple}
        'files', ...                          % Selection mode: {files,dirs,files_and_dirs}
        {'.dat', 'fine-calibration file (*.dat)', 'calibration'}, ... % Specify file type
        'DataIn'};                          % DefaultFormats: {ChannelIn,DataIn,DipolesIn,EventsIn,MriIn,NoiseCovIn,ResultsIn,SspIn,SurfaceIn,TimefreqIn
    % cross_talk_file (site specific)
    sProcess.options.ctc.Comment = 'cross-talk file:';
    sProcess.options.ctc.Type    = 'filename';
    sProcess.options.ctc.Value   = {...
        '', ...                               % Filename
        '', ...                               % FileFormat
        'open', ...                           % Dialog type: {open,save}
        'Import cross-talk file...', ...     % Window title
        'ImportData', ...                     % LastUsedDir: {ImportData,ImportChannel,ImportAnat,ExportChannel,ExportData,ExportAnat,ExportProtocol,ExportImage,ExportScript}
        'single', ...                         % Selection mode: {single,multiple}
        'files', ...                          % Selection mode: {files,dirs,files_and_dirs}
        {'.fif', 'cross-talk file (*.fif)', 'ctc'}, ... % Specify file type
        'DataIn'};                          % DefaultFormats: {ChannelIn,DataIn,DipolesIn,EventsIn,MriIn,NoiseCovIn,ResultsIn,SspIn,SurfaceIn,TimefreqIn
end

%% ===== RUN =====
function OutputFile = Run(sProcess, sInput) %#ok<DEFNU>
    OutputFile = process_mne_maxwell_py('Run', sProcess, sInput);
end


function [ bx, ndim ] = cvx_sparsify( bx, tt, mode )

global cvx___
ox = isa( bx, 'cvx' );
if ox,
    sx = size( bx );
    bx = cvx_basis( bx );
end
if isempty( tt ),
    by = bx;
elseif ~any( tt ),
    return
else
    by = bx( :, tt );
end
if isempty( mode ),
    by = bx;
else
    [ xR, by ] = cvx_bcompress( by, mode, 0 );
end
nx = size( by, 2 );
ndim = cvx_newvar( nx, cvx_classify_mex( by, cvx___.classes ) );
bz = sparse( ndim, 1 : nx, 1 );
nz = size(bz,1);
by( nz, end ) = 0;
cvx_newcnstr( by - bz, true );
if ~isempty( mode ),
    bz = bz * xR;
end
if isempty( tt ),
    bx = bz;
else
    bx( 1:nz, tt ) = bz;
end
if ox,
    bx = cvx( sx, bx );
end

% 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 STResNet_stage1(varargin)

if ~isempty(gcp('nocreate'))
    delete(gcp)
end

opts.train.gpus = [ 1 ] ;
opts = cnn_setup_environment(opts);

addpath('network_surgery');
opts.dataSet = 'ucf101';
opts.inputdim  = [ 224,  224, 20] ;
initMethod = 'sumAB';
opts.dropOutRatio = 0;
opts.dataDir = fullfile(opts.dataPath, opts.dataSet) ;
opts.splitDir = [opts.dataSet '_splits'];
opts.train.fuseInto = 'spatial'; opts.train.fuseFrom = 'temporal';
opts.train.removeFuseFrom = 0;
opts.backpropFuseFrom = 1;
opts.nSplit = 1 ;
opts.addConv3D = 1 ;
opts.addPool3D  = 0 ;
opts.doSum = 1 ;
opts.doScale = 0 ;
opts.doBiDirectional = 0 ;
opts.nFrames = 5 ;
opts.singleSoftMax = 0;

opts.train.learningRate =  1*[ 1e-3*ones(1,3) 1e-4*ones(1,3)  1e-5*ones(1,3) 1e-6*ones(1,3)]  ;
opts.train.augmentation = 'multiScaleRegular';
opts.train.augmentation = 'f25noCtr';
opts.train.epochFactor = 10 ;
opts.train.batchSize = 128  ;
opts.train.numSubBatches = 32 ;
opts.train.cheapResize = 0 ;
opts.train.fusionLayer = {'res2a_relu', 'res2a'; 'res3a_relu', 'res3a'; 'res4a_relu', 'res4a'; ...
  'res5a_relu', 'res5a'; };

model = ['ST-ResNet50-split=' num2str(opts.nSplit)];
opts.train.numSubBatches =  ceil(opts.train.numSubBatches / max(numel(opts.train.gpus),1));
opts.train.memoryMapFile = fullfile(tempdir, 'ramdisk', ['matconvnet' num2str(opts.nSplit ) '.bin']) ;

opts.modelA = fullfile(opts.modelPath, [opts.dataSet '-img-resnet50-split' num2str(opts.nSplit) '-dr0.mat']) ;
opts.modelB = fullfile(opts.modelPath, [opts.dataSet '-resnet50-split' num2str(opts.nSplit) '-dr0.8.mat']) ;

opts.expDir = fullfile(opts.dataDir, [opts.dataSet '-' model]) ;

opts.train.startEpoch = 1 ;
opts.train.epochStep = 1 ;
opts.train.numEpochs = 8 ;
[opts, varargin] = vl_argparse(opts, varargin) ;

opts.imdbPath = fullfile(opts.dataDir, [opts.dataSet '_split' num2str(opts.nSplit) 'imdb.mat']);

opts.train.saveAllPredScores = 1;
opts.train.denseEval = 1;
opts.train.plotDiagnostics = 0 ;
opts.train.continue = 1 ;
opts.train.prefetch = 1 ;
opts.train.expDir = opts.expDir ;
opts.train.numAugments = 1;
opts.train.frameSample = 'random';
opts.train.nFramesPerVid = 1;

opts = vl_argparse(opts, varargin) ;
% -------------------------------------------------------------------------
%                                                   Database initialization
% -------------------------------------------------------------------------
if exist(opts.imdbPath)
  imdb = load(opts.imdbPath) ;
  imdb.flowDir = opts.flowDir;
else
  imdb = cnn_setup_data(opts) ;
  save(opts.imdbPath, '-struct', 'imdb', '-v6') ;
end
nClasses = length(imdb.classes.name);

% -------------------------------------------------------------------------
%                                                    Network initialization
% -------------------------------------------------------------------------
for model = {opts.modelA opts.modelB}
  model = model{:};
  if ~exist(model,'file')
    [~, baseModel] = fileparts(model);
    fprintf('Downloading base model file: %s ...\n', baseModel);
    mkdir(fileparts(model)) ;
    urlwrite(...
    ['http://ftp.tugraz.at/pub/feichtenhofer/st-res/ts-base/' baseModel '.mat'], ...
      model) ;
  end
end
netA = load(opts.modelA) ;
netB = load(opts.modelB) ;
if isfield(netA, 'net'), netA=netA.net;end
if isfield(netB, 'net'), netB=netB.net;end

if ~isfield(netA, 'meta')
  netA = update_legacy_net(netA);
  netA = dagnn.DagNN.fromSimpleNN(netA) ;
  netA = netA.saveobj() ;
end
if ~isfield(netB, 'meta'),    netB = dagnn.DagNN.fromSimpleNN(netB) ; netB = netB.saveobj() ; end;

if ~isfield(opts.train, 'fusionLayer');
  sum_layersA = find(strcmp({netA.layers(:).type},'dagnn.Sum')) + 1 ; % +1 for relu
  sum_layersB = find(strcmp({netB.layers(:).type},'dagnn.Sum')) + 1 ;
  opts.train.fusionLayer = {netA.layers(sum_layersA).name; netB.layers(sum_layersB).name};
  opts.train.fusionLayer = reshape({opts.train.fusionLayer{:}},2,[])';
end

f = find(strcmp({netA.layers(:).type}, 'dagnn.Loss'));
netA.layers(f(1)-1).name = 'prediction';
f = find(strcmp({netB.layers(:).type}, 'dagnn.Loss'));
netB.layers(f(1)-1).name = 'prediction';

fusionLayerA = []; fusionLayerB = [];
if ~isempty(opts.train.fusionLayer)
  for i=1:numel(netA.layers)
   if isfield(netA.layers(i),'name') && any(strcmp(netA.layers(i).name,opts.train.fusionLayer(:,1)))
     fusionLayerA = [fusionLayerA i];
   end
  end
  for i=1:numel(netB.layers)
   if  isfield(netB.layers(i),'name') && any(strcmp(netB.layers(i).name,opts.train.fusionLayer(:,2)))
     fusionLayerB = [fusionLayerB i];
   end
  end
end

netNormalization = netB.meta.normalization;
netA.meta.normalization.averageImage = mean(mean(netA.meta.normalization.averageImage, 1), 2);
netB.meta.normalization.averageImage = mean(mean(netB.meta.normalization.averageImage, 1), 2);

netB.meta.normalization.averageImage = gather(cat(3,netB.meta.normalization.averageImage, netA.meta.normalization.averageImage));

% rename layers, params and vars
for x=1:numel(netA.layers)
  if isfield(netA.layers(x), 'name'), netA.layers(x).name = [netA.layers(x).name '_spatial'] ;  end
end
for x=1:numel(netB.layers)
  if isfield(netB.layers(x), 'name'), netB.layers(x).name = [netB.layers(x).name '_temporal']; end
end

netA =  dagnn.DagNN.loadobj(netA);
for i = 1:numel(netA.vars),  if~strcmp(netA.vars(i).name,'label'), netA.renameVar(netA.vars(i).name, [netA.vars(i).name '_spatial']); end; end;
for i = 1:numel(netA.params),  netA.renameParam(netA.params(i).name, [netA.params(i).name '_spatial']); end;

netB =  dagnn.DagNN.loadobj(netB);
for i = 1:numel(netB.vars), if~strcmp(netB.vars(i).name,'label'), netB.renameVar(netB.vars(i).name, [netB.vars(i).name '_temporal']); end;end;
for i = 1:numel(netB.params),  netB.renameParam(netB.params(i).name, [netB.params(i).name '_temporal']); end;
if opts.addConv3D & any(~cellfun(@isempty,(strfind(opts.train.fusionLayer, 'prediction'))))
  if strcmp(opts.train.fuseInto,'temporal')
    [ netB ] = insert_conv_layers( netB, fusionLayerB(end), 'initMethod', initMethod, 'batchNormalization', bnormFusion, 'dropOutRatio', 0  );
  else
    [ netA ] = insert_conv_layers( netA, fusionLayerA(end), 'initMethod', initMethod, 'batchNormalization', bnormFusion, 'dropOutRatio', 0  );
  end
end
if ~opts.addConv3D && ~opts.doSum
  if strcmp(opts.train.fuseInto,'temporal')
    [ netB ] = insert_conv_layers( netB, fusionLayerB, 'initMethod', initMethod, 'batchNormalization', bnormFusion, 'dropOutRatio', 0  );
  else
    [ netA ] = insert_conv_layers( netA, fusionLayerA, 'initMethod', initMethod, 'batchNormalization', bnormFusion, 'dropOutRatio', 0  );
  end
end

if opts.train.removeFuseFrom,
  switch opts.train.fuseFrom
    case 'spatial'
      netA.layers = netA.layers(1:fusionLayerA(end)); netA.rebuild;
    case'temporal'
      netB.layers = netB.layers(1:fusionLayerB(end)); netB.rebuild;
  end
end

netA = netA.saveobj() ;
netB = netB.saveobj() ;

net.layers = [netA.layers netB.layers] ;
net.params =  [netA.params netB.params] ;
net.meta = netB.meta;
net = dagnn.DagNN.loadobj(net);

net = dagnn.DagNN.setLrWd(net, 'convFiltersLRWD', [1 1], 'convBiasesLRWD', [2 0], ...
  'fusionFiltersLRWD', [1 1], 'fusionBiasesLRWD', [2 0], ...
  'filtersLRWD' , [1 1], 'biasesLRWD' , [2 0] ) ;

clear netA netB;
if opts.doBiDirectional, nFuse = 2; else nFuse=1; end;
for s=1:nFuse
  if s==2
    [opts.train.fuseInto, opts.train.fuseFrom] = deal(opts.train.fuseFrom, opts.train.fuseInto);
  end
  for i = 1:size(opts.train.fusionLayer,1)
    if strcmp(opts.train.fuseInto,'spatial')
      i_fusion = find(~cellfun('isempty', strfind({net.layers.name}, ...
        [opts.train.fusionLayer{i,1} '_' opts.train.fuseInto])));
    else
        i_fusion = find(~cellfun('isempty', strfind({net.layers.name}, ...
        [opts.train.fusionLayer{i,2} '_' opts.train.fuseInto])));
    end

    if opts.doSum
      inputVars =  net.layers(strcmp({net.layers.name},[opts.train.fusionLayer{i,1}, ...
          '_' opts.train.fuseFrom])).outputs;

      if opts.doScale
        name = [net.layers(i_fusion(end)).name '_scale'];

        block = dagnn.Scale() ;
        for j = i_fusion(end):-1:1
          p_from = net.layers(j).params;
          if numel(p_from) == 1 ||  numel(p_from) == 2, break; end;
        end

        block.size = [1 1 size(net.params(net.getParamIndex(p_from{1})).value,4)];

        pars = {[name '_f'], [name '_b']} ;
        net.addLayerAt(i_fusion(end), name, ...
          block, ...
          inputVars, ...
          name, ...
          pars) ;
         params = block.initParams(0.1);
        [net.params(net.getParamIndex(pars)).value] = deal(params{:}) ;

        inputVars = {name};
        i_fusion(end) = i_fusion(end)+1;
      end

      name = [net.layers(i_fusion(end)).name '_sum'];

      block = dagnn.Sum() ;

      inputVars = [inputVars{:} net.layers(strcmp({net.layers.name},[opts.train.fusionLayer{i,2}, ...
          '_' opts.train.fuseInto])).outputs];
      net.addLayerAt(i_fusion(end), name, block, ...
                 inputVars, ...
                  name) ;
        % next line is for disabling ReLUshortcut
        net.layers(cellfun(@(x) any(isequal(x,net.getVarIndex(inputVars(end)))), {net.layers.inputIndexes} )).block.useShortCircuit = 0;

    else
      name = [net.layers(i_fusion(end)).name '_concat'];
      block = dagnn.Concat() ;
      net.addLayerAt(i_fusion(end), name, block, ...
                 [net.layers(strcmp({net.layers.name},[opts.train.fusionLayer{i,1} '_spatial'])).outputs ...
                  net.layers(strcmp({net.layers.name},[opts.train.fusionLayer{i,2} '_temporal'])).outputs], ...
                  name) ;
    end

    net.layers(i_fusion(end)+2).inputs{1} = name;

  end
end

net.addVar('input_flow')
net.vars(net.getVarIndex('input_flow')).fanout = net.vars(net.getVarIndex('input_flow')).fanout + 1 ;

% set input for conv layers
i_conv1= find(~cellfun('isempty', strfind({net.layers.name},'temporal')));
net.layers(i_conv1(1)).inputs = {'input_flow'};

net.renameVar(net.vars(1).name, 'input');

if opts.addConv3D
    conv_layers = find(arrayfun(@(x) isa(x.block,'dagnn.Conv') && isequal(x.block.size(1),1) ...
      && (~isempty(strfind(x.name,'b_branch2a')) || ~isempty(strfind(x.name,'b_branch2c'))) && isequal(x.block.stride(1),1), net.layers ))

    for l=conv_layers
       disp(['converting ' net.layers(l).name ' to ConvTime'])
       block = dagnn.ConvTime() ;   block.net = net ;

       kernel = net.params(net.getParamIndex(net.layers(l).params{1})).value;
       sz = size(kernel);
       kernel = cat(2, kernel/3, kernel/3, kernel/3  );

       net.params(net.getParamIndex(net.layers(l).params{1})).value = kernel;
       pads = size(kernel); pads = ceil(pads(1:2) / 2) - 1;

       block.pad = [pads(1),pads(1), pads(2),pads(2)] ;
       block.size = size(kernel);
       block.hasBias = net.layers(l).block.hasBias;

       block.stride(1) =  net.layers(l).block.stride(1)*net.layers(l).block.stride(2);
       net.layers(l).block = block;
    end
end
if opts.addPool3D

  poolLayers = {'pool5'; };

  for j=1:numel(poolLayers)
    for s = {'spatial', 'temporal'}
      i_pool = find(strcmp({net.layers.name},[poolLayers{j} '_' char(s)]));
      block = dagnn.PoolTime() ;
      block.poolSize = [1 opts.nFrames ];
      block.pad = [0 0 0 0];
      block.stride = [1 1];
      block.method = 'avg';
      nPool = 1 ;
      if opts.addPool3D == 2
        block.method = 'max';
      end

      name = {};
      outputVars = {};
      inputVars = net.layers(i_pool).outputs;
      for k=1:nPool
        name{end+1} = [poolLayers{j} '_pool_' char(s) num2str(k)];
        disp(['injecting ' name{end} ' as PoolTime'])
        net.addLayerAt(i_pool, name{end}, block, ...
                      [inputVars], {name{end}}) ;
      end

      % chain input of l that has layer as input
      for l = 1:numel(net.layers)
          if ~strcmp(net.layers(l).name, name)
            sel = find(strcmp(net.layers(l).inputs, net.layers(i_pool).outputs{1})) ;
            if any(sel)
                net.layers(l).inputs{sel} = inputVars;
            end
          end
      end

    end
  end
end % add pool3d

net = dagnn.DagNN.insertLossLayers(net, 'numClasses', nClasses) ;

opts.train.augmentation = 'f25noCtr';
opts.train.frameSample = 'temporalStrideRandom';
opts.train.nFramesPerVid = opts.nFrames * 1;
opts.train.temporalStride = 5:15;

opts.train.valmode = 'temporalStrideRandom';
opts.train.numValFrames = 25 ;
opts.train.saveAllPredScores = 1 ;
opts.train.denseEval = 1;
opts.train.opts.nFramestack = opts.nFrames;

net.meta.normalization.rgbVariance = [];
opts.train.train = find(ismember(imdb.images.set, [1])) ;
opts.train.train = repmat(opts.train.train,1,opts.train.epochFactor);

% opts.train.train = NaN; % for testing only
opts.train.denseEval = 1;

%%
zero_drs =  find(arrayfun(@(x) isa(x.block,'dagnn.DropOut') && x.block.rate == 0, net.layers)) ;
net.removeLayer({net.layers(zero_drs).name}, true);

if ~isnan(opts.dropOutRatio)
  dr_layers = find(arrayfun(@(x) isa(x.block,'dagnn.DropOut'), net.layers)) ;
  if opts.dropOutRatio > 0
    net.layers(dr_layers).block.rate = opts.dropOutRatio;
  else
    net.removeLayer({net.layers(dr_layers).name}, true);
  end
end

if opts.singleSoftMax
  pred_layers = [];
  for l=1:numel(net.layers)
    if isempty( net.layers(l).params ), continue; end;
    if size(net.params(net.getParamIndex(net.layers(l).params{1})).value,4) == nClasses || ...
        size(net.params(net.getParamIndex(net.layers(l).params{1})).value,5) == nClasses % 3D FC layer
          pred_layers = [pred_layers l];
          net.vars(net.layers(l).outputIndexes).precious = 1;
    end
  end
  pred_layers = fliplr(pred_layers) ; % remove the spatial layer
  paramsIdx1 = net.getParamIndex(net.layers(pred_layers(1)).params);
  paramsIdx2 = net.getParamIndex(net.layers(pred_layers(2)).params);
  for p = 1:numel(paramsIdx1)
    sz = size(net.params(paramsIdx1(p)).value);
    if numel(sz) > 2
      net.params(paramsIdx1(p)).value = cat(3,net.params(paramsIdx1(p)).value, net.params(paramsIdx2(p)).value);
    else
      net.params(paramsIdx1(p)).value = net.params(paramsIdx1(p)).value + net.params(paramsIdx2(p)).value;
    end
  end
   block = dagnn.Concat() ;
   newName = ['opts.singleSoftMaxConcat'];
   net.addLayer(newName, block, ...
                 [net.layers(pred_layers).inputs], ...
                 newName) ;
  net.layers(pred_layers(1)).inputs =    newName ;
  % remove layers of the second prediction path
  for l = numel(net.layers):-1:1
    for f = net.layers(pred_layers(2)).outputs
       sel = find(strcmp(f, net.layers(l).inputs )) ;
       if ~isempty(sel)
         fprintf('removing ayer %s \n', net.layers(l).name);
         net.removeLayer({net.layers(l).name});
       end
    end
  end
  net.removeLayer({net.layers(pred_layers(2)).name});
end

net.layers(~cellfun('isempty', strfind({net.layers(:).name}, 'err'))) = [] ;
net.rebuild() ;
opts.train.derOutputs = {} ;
for l=1:numel(net.layers)
  if isa(net.layers(l).block, 'dagnn.Loss') && isempty(strfind(net.layers(l).block.loss, 'err'))
    if opts.backpropFuseFrom || ~isempty(strfind(net.layers(l).name, opts.train.fuseInto ))
      fprintf('setting derivative for layer %s \n', net.layers(l).name);
      opts.train.derOutputs = [opts.train.derOutputs, net.layers(l).outputs, {1}] ;
    end
    net.addLayer(['err1_' net.layers(l).name(end-7:end) ], dagnn.Loss('loss', 'classerror'), ...
             net.layers(l).inputs, 'error') ;
  end
end

net.conserveMemory = 1 ;
fn = getBatchWrapper_rgbflow(net.meta.normalization, opts.numFetchThreads, opts.train) ;
[info] = cnn_train_dag(net, imdb, fn, opts.train) ;


function [varargout] = minDose(planC, varargin)
%Calculate a minDose metric.
%Stand alone metric :       minDose(planC, structNum, doseNum, 'Percent' or 'Absolute');
%Request m object   :       minDose(planC, 'getnewmetric');
%Evaluate m object  :       minDose(planC, m, 'evaluate');
%LM:  4 Jan 06, JOD: changed interface.
%
% Copyright 2010, Joseph O. Deasy, on behalf of the CERR development team.
%
% This file is part of The Computational Environment for Radiotherapy Research (CERR).
%
% CERR development has been led by:  Aditya Apte, Divya Khullar, James Alaly, and Joseph O. Deasy.
%
% CERR has been financially supported by the US National Institutes of Health under multiple grants.
%
% CERR is distributed under the terms of the Lesser GNU Public License.
%
%     This version of CERR is free software: you can redistribute it and/or modify
%     it under the terms of the GNU General Public License as published by
%     the Free Software Foundation, either version 3 of the License, or
%     (at your option) any later version.
%
% CERR is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
% without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
% See the GNU General Public License for more details.
%
% You should have received a copy of the GNU General Public License
% along with CERR.  If not, see <http://www.gnu.org/licenses/>.

indexS = planC{end};
optS = planC{indexS.CERROptions};

if(nargin > 1)
    call = varargin{end};
else
    warning('Incorrect Usage, try: minDose(planC, structNum, doseNum, ''Percent'' or ''Absolute'');');
    return;
end

switch upper(call)
    case 'GETNEWMETRIC'
        m.name = 'minDose';
        m.valueV = [];
        m.description = 'Returns the min dose in specified structure';
        m.functionName = @minDose;
        m.note = '';
        m.params(1).name = 'Structure';
        m.params(1).type = 'DropDown';
        m.params(1).list = {planC{indexS.structures}.structureName};
        m.params(1).value = 1;
        m.params(2).name = 'IsTarget?';
        m.params(2).type = 'DropDown';
        m.params(2).list ={'Target', 'Not Target'};
        m.params(2).value = 2;
        m.units = [];
        m.range = [0 inf];
        m.doseSets = [1];
        varargout = {planC,m};
    return;

    case 'EVALUATE'
        m = varargin{1};
        structName = planC{indexS.structures}(m.params(1).value).structureName;
        m.note = structName;
        m.valueV = [];

        maxD = -inf;
		for i=1:length(m.doseSets)
            [planC, doseBinsV, volsHistV] = getDVHMatrix(planC, m.params(1).value, m.doseSets(i));
            ans = calc_minDose(doseBinsV, volsHistV, m.params(2).value);
            m.valueV = [m.valueV ans];
            doseArray = getDoseArray(planC{indexS.dose}(m.doseSets(i)));
            maxD = max(maxD, max(doseArray(:)));
        end
        if m.params(2).value == 1
            %Is target, high dose is best.
            m.range = [0 max(m.valueV)];
        elseif m.params(2).value == 2;
            m.range = [maxD min(m.valueV)];
        end
        m.units = getDoseUnitsStr(i,planC);
        varargout = {planC,m};
        return;

    otherwise  %No specific call has been made, assume user just wants raw metric.
        if(nargin > 3)
            structNum = varargin{1};
            doseNum = varargin{2};
            volumeTypeString = varargin{3};
            if(strcmp(upper(volumeTypeString), 'ABSOLUTE'))
                volumeType = 2;
            else
                volumeType = 1;
            end
            [planC, doseBinsV, volsHistV] = getDVHMatrix(planC, structNum, doseNum);
            varargout = {calc_minDose(doseBinsV, volsHistV, volumeType)};
        else
            error('Not enough parameters, try: minDose(planC, structNum, doseNum, ''Percent'' or ''Absolute'');')
            return;
        end
end


% reref() - convert common reference EEG data to some other common reference
%           or to average reference
% Usage:
%   >> Dataout = reref(data);  % convert all channels to average reference
%   >> [Dataout Chanlocs] = reref(data, refchan, 'key', 'val');
%                              % convert data to new reference with options
% Inputs:
%   data - 2-D or 3-D data matrix (chans,frames*epochs)
%   refchan  - reference channel number(s). There are three possibilities:
%          1) [] -  compute average reference
%          2) [X]: re-reference to channel X
%          2) [X Y Z ...]: re-reference to the average of channel X Y Z ...
%
% Optional inputs:
%   'exclude'    - [integer array] channel indices to exclude from re-referencing
%                  (e.g., event marker channels, etc.)
%   'keepref'    - ['on'|'off'] keep reference channel in output (only usable
%                  when there are several references).
%   'elocs'      - Current data electrode location structure (e.g., EEG.chanlocs).
%   'refloc'     - Reference channel location single element structure or cell array
%                  {'label' theta radius} containing the name and polar coordinates
%                  of the current channel. Including this entry means that
%                  this channel will be included (reconstructed) in the
%                  output.
%
% Outputs:
%   Dataout     - Input data converted to the new reference
%   Chanlocs    - Updated channel locations structure
%
% Notes: 1) The average reference calculation implements two methods
%           (see www.egi.com/Technotes/AverageReference.pdf)
%            V'i = (Vi-Vref) - sum(Vi-Vref)/number_of_electrodes
%
% Authors: Arnaud Delorme, SCCN/INC/UCSD, La Jolla, 2009-
%          previous version: Arnaud Delorme & Scott Makeig, 1999-2002

% Deprecated inputs:
% These inputs are still accepted but not processed. The function returns
% accurate results irrespective of the entry of these options.
%   'refstate  ' - ['common'|'averef'|[indices]] Current reference condition,
%                  ('averef') = average reference; ('common' or 0) = common
%                  reference. [indices] designate the current reference channel
%                  or channels if present in the data {default: 'common'}
%   'method'     - ['standard'|'withref'] Do not ('standard') or do ('withref')
%                  include reference channel data in output {def: 'standard'}.
%                  Note: Option 'withref' not possible when multiple ref channel
%                  indices are given as argument to 'refstate' (below).
%
% ICA inputs:
% These inputs are still accepted but not the ICA conversion is now
% performed from within pop_reref()
%   'icaweights' - ICA weight matrix. Note: If this is ICA weights*sphere,
%                  then the 'icasphere' input below should be [] or identity.
%   'icasphere'  - ICA sphere matrix (if any)
%   'icachansind' - Indices of the channels used in ICA decomposition
%
% Outputs:
%   Wout        - ICA weight matrix (former icaweights*icasphere)
%                 converted to new data reference
%   Sout        - ICA sphere matrix converted to an identity matrix
%   ICAinds     - New indices of channels used in ICA decomposition
%   meandata    - (1,dataframes) means removed from each data point
%
%        2) In conversion of the weight matrix to a new reference
%           where WS = Wts*Sph  and  ica_act = WS*data, then
%              data = inv(WS)*ica_act;
%           If R*data are the re-referenced data,
%              R*data= R*inv(WS)*ica_act;
%           And Wout = inv(R*inv(WS));
%           Now, Sout = eye(length(ICAinds));
%           The re-referenced ICA component maps are now the
%           columns of inv(Wout), and the icasphere matrix, Sout,
%           is an identity matrix. Note: inv() -> pinv() when
%           PCA dimension reduction is used during ICA decomposition.

% Copyright (C) 1999 Scott Makeig, SCCN/INC/UCSD, scott@sccn.ucsd.edu
%
% 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

% 12/16/99 Corrected denomiator on the suggestion of Ian Nimmo-Smith, Cambridge UK
% 01-25-02 reformated help & license -ad

function [data, Elocs, morechans, W, S, icachansind, meandata] = reref(data, ref, varargin)

if nargin<1
  help reref
  return
end
if nargin < 2
    ref = [];
end;

% check inputs
% ------------
g = finputcheck(varargin, { 'icaweight'   'real'    []          [];
                            'icaweights'  'real'    []          [];
                            'icasphere'   'real'    []          [];
                            'icachansind' 'integer'    []       [];
                            'method'     'string'  { 'standard' 'withref' }  'standard';
                            'refstate'   { 'string' 'integer' } { { 'common' 'averef' } [1 size(data,1)] }     'common'; % ot used but kept for backward compatib.
                            'exclude'    'integer' [1 size(data,1)]          [];
                            'refloc'     { 'cell' 'struct' }  { [] [] }   {};
                            'keepref'    'string'  {'on' 'off' }             'off';
                            'elocs'      {'integer' 'struct'}  []            [] });
if isstr(g), error(g); end;
if ~isempty(g.icaweight)
    g.icaweights = g.icaweight;
end;
if ~isempty(g.icaweights)
    if isempty(g.icachansind),
        g.icachansind = [1:size(g.icaweights,2)];
        disp('Warning: reref() output has changed slightly since EEGLAB 5.02');
        disp('         the 4th output argument is the indices of channels used for ICA instead');
        disp('         of the mean reference value (which is now output argument 5)');
    end;
end;

if ~isempty(ref)
    if ref > size(data,1)
        error('reference channel index out of range');
    end;
end;

[dim1 dim2 dim3] = size(data);
data = reshape(data, dim1, dim2*dim3);

% single reference not present in the data
% add it as blank data channel at the end
% ----------------------------------------
if ~isempty(g.refloc) == 1
    if ~isempty(g.elocs)
        if iscell(g.refloc)
            data(end+1,:) = 0;
            g.elocs(end+1).labels = g.refloc{1};
            g.elocs(end  ).theta  = g.refloc{2};
            g.elocs(end  ).radius = g.refloc{3};
        else
            data(end+length(g.refloc),:) = 0;
            for iLocs = 1:length(g.refloc)
                g.elocs(end+1).labels = g.refloc(iLocs).labels;
                fieldloc = fieldnames(g.refloc);
                for ind = 1:length(fieldloc)
                    g.elocs(end) = setfield(g.elocs(end), fieldloc{ind}, getfield(g.refloc(iLocs), fieldloc{ind}));
                end;
            end;
        end;
    end;
    [dim1 dim2 dim3] = size(data);
end;

% exclude some channels
% ---------------------
chansin   = setdiff([1:dim1], g.exclude);
nchansin  = length(chansin);

% return mean data
% ----------------
if nargout > 4
    meandata = sum(data(chansin,2))/nchansin;
end;

% generate rereferencing matrix
% -----------------------------
if 0 % alternate code - should work exactly the same
    if isempty(ref)
        ref=chansin; % average reference
    end % if
    chansout=chansin;
    data(chansout,:)=data(chansout,:)-ones(nchansin,1)*mean(data(ref,:),1);
else
    if ~isempty(ref) % not average reference
        refmatrix = eye(nchansin); % begin with identity matrix
        tmpref = ref;
        for index = 1:length(g.exclude)
            tmpref(find(g.exclude(index) < tmpref)) = tmpref(find(g.exclude(index) < tmpref))-1;
        end;
        for index = 1:length(tmpref)
            refmatrix(:,tmpref(index)) = refmatrix(:,tmpref(index))-1/length(tmpref);
        end;
    else % compute average reference
        refmatrix = eye(nchansin)-ones(nchansin)*1/nchansin;
    end;
    chansout = chansin;
    data(chansout,:) = refmatrix*data(chansin,:);
end;

% change reference in elocs structure
% -----------------------------------
if ~isempty(g.elocs)
    if isempty(ref)
        for ind = chansin
            g.elocs(ind).ref = 'average';
        end;
    else
        reftxt = { g.elocs(ref).labels };
        if length(reftxt) == 1, reftxt = reftxt{1};
        else
            reftxt = cellfun(@(x)([x ' ']), reftxt, 'uniformoutput', false);
            reftxt = [ reftxt{:} ];
        end;
        for ind = chansin
            g.elocs(ind).ref = reftxt;
        end;
    end;
end;

% remove reference
% ----------------
morechans = [];
if strcmpi(g.keepref, 'off')
    data(ref,:) = [];
    if ~isempty(g.elocs)
        morechans = g.elocs(ref);
        g.elocs(ref) = [];
    end;
end;

data = reshape(data, size(data,1), dim2, dim3);

% treat optional ica parameters
% -----------------------------
W = []; S = []; icachansind = [];
if ~isempty(g.icaweights)
    disp('Warning: This function does not process ICA array anymore, use the pop_reref function instead');
end;
Elocs = g.elocs;


function outputImage = perform_binary_operation(this, otherImage, ...
    functionHandle)
% Performs binary operation (i.e. 2 inputs) on this and a second image
% for given dimension and returns a new output image
%
% NOTE: If voxel dimensions of 2nd image do not match - or a scalar is
% given as 2nd argument - data in the 2nd argument is automatically
% replicated to match this image geometry.
%
%   Y = MrDataNd()
%   outputImage = perform_binary_operation(this, otherImage, ...
%   functionHandle)
%
% This is a method of class MrDataNd.
%
% IN
%   otherImage              2nd operand for binary operation
%   functionHandle          handle of function to be applied to images (e.g.
%                           @plus, @minus, @times and @rdivide for the 4
%                           arithmetic operations )
%
% OUT
%   outputImage             new MrDataNd with possibly new image dimensions,
%                           output of binary operation performed on this
%                           and otherImage
% EXAMPLE
%
%   % Compute difference of 2 images
%		Y = MrDataNd();
%		Z = MrDataNd();
%		X = Y.perform_binary_operation(Z, @minus);
%
%	% Scale image (multiply) by a factor of 3
%		Y = MrDataNd();
%		Y = Y.perform_binary_operation(3, @mult)
%
%	% Compute ratio of 2 images
%		Y 			= MrDataNd();
%		Z 			= MrDataNd();
%		ratioYZ 	= Y.perform_binary_operation(Z, @rdivide);
%
%
%
%   See also MrDataNd perform_unary_operation

% Author:   Saskia Bollmann & Lars Kasper
% Created:  2014-11-13
% Copyright (C) 2014 Institute for Biomedical Engineering
%                    University of Zurich and ETH Zurich
%
% This file is part of the TAPAS UniQC Toolbox, which is released
% under the terms of the GNU General Public Licence (GPL), version 3.
% You can redistribute it and/or modify it under the terms of the GPL
% (either version 3 or, at your option, any later version).
% For further details, see the file COPYING or
%  <http://www.gnu.org/licenses/>.
%

% binary operation with scalar etc. => make MrDataNd first
if ~isa(otherImage, 'MrDataNd')
    otherData = otherImage;
    otherName = 'dataMatrix';
    % Create image from data matrix with similar dimInfo
    % TODO: include proper dimInfo-adaptation (right now, res is assumed
    % the same, not FOV!)
    nSamplesOther = size(otherData);
    nSamplesOther(end+1:this.dimInfo.nDims) = 1; % avoid singleton dim error!
    dimInfoOther = this.dimInfo.copyobj;
    dimInfoOther.nSamples = nSamplesOther;

    otherImage = this.copyobj();
    otherImage.dimInfo = dimInfoOther;
    otherImage.data = otherData;
    otherImage.name = otherName;
end

%% TODO: FOV first, then adapt matrix sizes?
% TODO: Check FOVs first, if they don't match crop or zero-fill otherImage

outputImage = otherImage.resize(this.dimInfo);
outputImage.name = this.name;

%% Perform computation and store!
outputImage.data 	= functionHandle(this.data, outputImage.data);

outputImage.info{end+1,1} = sprintf('%s( %s, %s )', func2str(functionHandle), ...
    outputImage.name, otherImage.name);


% Copyright (C) 2018  Symeon Symeonidis, Stefanos Tsantilas, Stelios Mitilineos
% simos421@gmail.com, steftsantilas@gmail.com, smitil@gmail.com
% This program is free software: you can redistribute it and/or modify
% it under the terms of the GNU General Public License as published by
% the Free Software Foundation, either version 3 of the License, or
% (at your option) any later version.
%
% This program is distributed in the hope that it will be useful,
% but WITHOUT ANY WARRANTY; without even the implied warranty of
% MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
% GNU General Public License for more details.

function CstFR4lossy(mws)

%'@ define material: FR-4 (lossy)

material = invoke(mws,'material');
invoke(material,'Reset');
invoke(material,'Name','FR-4 (lossy)');
invoke(material,'FrqType','all');
invoke(material,'Type','Normal');
invoke(material,'SetMaterialUnit','GHz','mm');
invoke(material,'Epsilon','4.3');
invoke(material,'Mue','1.0');
invoke(material,'Kappa','0.0');
invoke(material,'TanD','0.025');
invoke(material,'TanDFreq','10.0');
invoke(material,'TanDGiven','True');
invoke(material,'TanDModel','ConstTanD');
invoke(material,'KappaM','0.0');
invoke(material,'TanDM','0.0');
invoke(material,'TanDMFreq','0.0');
invoke(material,'TanDMGiven','False');
invoke(material,'TanDMModel','ConstKappa');
invoke(material,'DispModelEps','None');
invoke(material,'DispModelMue','None');
invoke(material,'DispersiveFittingSchemeEps','General 1st');
invoke(material,'DispersiveFittingSchemeMue','General 1st');
invoke(material,'UseGeneralDispersionEps','False');
invoke(material,'UseGeneralDispersionMue','False');
invoke(material,'Rho','0.0');
invoke(material,'ThermalType','Normal');
invoke(material,'ThermalConductivity','0.3');
invoke(material,'SetActiveMaterial','all');
invoke(material,'Colour','0.94','0.82','0.76');
invoke(material,'Wireframe','False');
invoke(material,'Transparency','0');
invoke(material,'Create');
release(material);
end


function [image, imageCha, objOut] = CS_reconstruction(path, para)
% CS_RECONSTRUCTION main function to select the appropriate Compressed
% Sensing reconstruction
%
% input:
% path      - path to file without specifying file extension
%           - path to directory containing files
%           - empty (for file dialog)
%           - kSpace to be reconstructed with dimensionalities:
%             cell array: NSlice x NChannels x NRepetitions x NAverages
%             each cell: 2D: yPhase x xFreq x (nTime/nPhases)
%                        3D: yPhase x xFreq x zPhase
%                        4D: yPhase x xFreq x zPhase x nTime/nPhases
% para      - struct containing to be modified reconstruction parameters
%           and/or struct with handover parameter
%           - path to parameter file
%
%
% output:
% image     reconstructed and sum-of-squared channel combined image
% imageCha  reconstructed individual coil images
% objOut    reconstruction parameters
%
%
% (c) copyright 2012 - 2016 under BSD license
% Thomas Kuestner, University of Tuebingen and University of Stuttgart, Germany
% (thomas.kuestner@{med.uni-tuebingen.de,iss.uni-stuttgart.de})
%
% Please see license files (./licenses) for accompanied codes (which also
% include own modifications) of:
% - ESPIRiT v0.1.8  in @ESPIRiT, utils/utils_ESPIRiT     under LICENSE_ESPIRiT
% - bart v0.2.09    in utils/utils_BART                  under LICENSE_BART
% - SPIRiT v0.3     in @SPIRiT, utils/utils_GRAPPA,
%                   utils/utils_SPIRiT                   under LICENSE_SPIRiT
% - sparseMRI v0.2  in @sparseMRI, @p2DFT, @A_operator,
%                   @TVOP                                under LICENSE_SPARSEMRI
% - L1Magic v1.11   in @L1_Magic                         under LICENSE_L1MAGIC
% - GIST            in utils/utils_Proximal/GIST         under LICENSE_GIST
% - Wavelab850      in @Wavelet, utils/utils_Wavelet     under LICENSE_WAVELAB
% - Rice Wavelet v3.0 in utils/utils_WaveletRice         under LICENSE_WAVELETRICE
% - Curvelab v2.1.3 in utils/utils_TRAFO/CurveLab-2.1.3  under LICENSE_CURVELAB
% - NUFFT           in @NUFFT, utils/utils_NUFFT         under LICENSE_NUFFT
% - DTCWT           in utils/utils_TRAFO/DTCWT           under LICENSE_DTCWT
% - Shearlet        in utils/utils_TRAFO/Shearlet        under LICENSE_SHEARLET
% - Denoising       in utils/utils_Proximal/Denoising    under LICENSE_DENOISING

warning('off','MATLAB:dispatcher:nameConflict');
warning('off','MATLAB:mat2cell:TrailingUnityVectorArgRemoved');

% global prop

% prepare m-files
currpath = fileparts(mfilename('fullpath'));
addpath(genpath([currpath,filesep,'utils']));
addpath(genpath([currpath,filesep,'io']));
addpath(genpath([currpath,filesep,'preproc']));
addpath(genpath([currpath,filesep,'postproc']));

% load ADCs
if(nargin == 0 || ~exist('path','var') || isempty(path))
    if(strcmp(getenv('computername'),'M123PC'))
        defpath = 'K:\Compressed Sensing\Rohdaten\3D';
    else
        defpath = 'S:\Rohdaten\Thomas\ktFOCUSS\3D';
    end
    [file, path] = uigetfile({'*.mat;*.dat;', 'ADC measdata (*.mat, *.dat)'; '*.h5', 'ISMRMD (*.h5)'} ,'Select measdata file', 'MultiSelect', 'off', defpath);
    if(isequal(file,0))
        error('CS_reconstruction(): User Termination');
    end
    [~,filename,ext] = fileparts(file);
    lReadFromFile = true;
    % in general: [dData, iLC] = fMeasRead(datapath, 'Set', 0, 'Smp', [21 inf]);
else
    if(ischar(path))
        if(isdir(path))
            [file, path] = uigetfile({'*.mat;*.dat;', 'ADC measdata (*.mat, *.dat)'; '*.h5', 'ISMRMD (*.h5)'} ,'Select measdata file', 'MultiSelect', 'off', path);
            if(isequal(file,0))
                error('CS_reconstruction(): User Termination');
            end
            [~,filename,ext] = fileparts(file);
        else
            [path, filename, ext] = fileparts(path);
        end
        lReadFromFile = true;
    else
        lReadFromFile = false;
    end
end

% read inputs
if(lReadFromFile)
    if(strcmp(ext,'h5')) % ISMRMD
        data = h5read([path,filesep,filename,ext],'dataset/data');
        % convert to processable kSpace
        [ kSpace, measPara ] = convertKSpace_main( data );
    else % ADC measdata (Siemens)
        if(exist(fullfile(path,[filename,'.mat']),'file'))
            matfile = whos('-file', fullfile(path,[filename,'.mat']));
        end
        if(exist(fullfile(path,[filename,'.mat']),'file') && ~ismember('iLC', {matfile.name}))
            % load mat file to check if it contains iLC/iSP or something else
            data = load(fullfile(path,[filename,'.mat']));
            kSpace = data.kSpace;
            measPara.dim = zeros(1,5);
            measPara.LCall = zeros(1,4);
            dimNames = {'y (phase)', 'x (frequency)', 'z (phase)', 't (time)', 'channels'};
            LCallNames = {'slices', 'acquisitions', 'echos', 'repetitions'};
            dimDefault = ones(1,5);
            LCallDefault = [size(kSpace,1), size(kSpace,4), size(kSpace,5), size(kSpace,3)];
            tmp = size(kSpace{1});
            if(LCallDefault(1) > 1 && length(tmp) > 2)
                dimDefault(1:2) = tmp(1:2);
                dimDefault(4) = tmp(3);
            else
                dimDefault(1:length(tmp)) = tmp;
            end
            dimDefault(5) = size(kSpace,2);
            if(isfield(data,'dim') && isfield(data,'LCall'))
                measPara.dim = data.dim;
                measPara.LCall = data.LCall;
            elseif(isfield(data,'dim') && ~isfield(data,'LCall'))
                measPara.dim = data.dim;
                fprintf('Please specify amount of:\n');
                for i=1:length(measPara.LCall)
                    helper = input(sprintf('%s [%d]: ',LCallNames{i}, LCallDefault(i)),'s');
                    if(isempty(helper)), helper = LCallDefault(i); end;
                    measPara.LCall(i) = helper;
                end

            elseif(~isfield(data,'dim') && isfield(data,'LCall'))
                measPara.LCall = data.LCall;
                fprintf('Please specify dimensions:\n');
                for i=1:length(measPara.dim)
                    helper = input(sprintf('%s [%d]: ',dimNames{i}, dimDefault(i)),'s');
                    if(isempty(helper)), helper = dimDefault(i); end;
                    measPara.dim(i) = helper;
                end

            else
                fprintf('Please specify dimensions:\n');
                for i=1:length(measPara.dim)
                    helper = input(sprintf('%s [%d]: ',dimNames{i}, dimDefault(i)),'s');
                    if(isempty(helper)), helper = dimDefault(i); end;
                    measPara.dim(i) = helper;
                end
                fprintf('Please specify amount of:\n');
                for i=1:length(measPara.LCall)
                    helper = input(sprintf('%s [%d]: ',LCallNames{i}, LCallDefault(i)),'s');
                    if(isempty(helper)), helper = LCallDefault(i); end;
                    measPara.LCall(i) = helper;
                end
            end
            clear 'LCallDefault' 'dimDefault';
            loadedVars = {'dimension', 'oversampling', 'measPara', 'iLC', 'iLCPositions', 'drecksMDH'};
            for i=1:length(loadedVars)
                if(isfield(data,loadedVars{i}))
                    if(any(strcmp(loadedVars{i},{'dimension','oversampling'})))
                        eval(sprintf('measPara.%s = data.%s;', loadedVars{i}, loadedVars{i}));
                    else
                        eval(sprintf('%s = data.%s;', loadedVars{i}, loadedVars{i}));
                    end
                else
                    if(strcmp(loadedVars{i},'measPara'))
                        continue;
                    end
                    eval(sprintf('%s = [];', loadedVars{i}));
                end
            end
            clear 'data';
        else
            [dData, iLC, iEvalInfoMask, drecksMDH, iLCPositions] = fMeas_main(fullfile(path, [filename, ext]));
            measPara = [];
        end
    end
else
    % kSpace was directly handed over
    kSpace = path;
    path = currpath; % for compatibility later
    filename = '';
    if(isstruct(para))
        loadedVars = {'measPara', 'dimension', 'oversampling', 'iLC', 'iLCPositions', 'drecksMDH', 'savePath'};
        for i=1:length(loadedVars)
            if(isfield(para,loadedVars{i}))
                if(any(strcmp(loadedVars{i},{'dimension','oversampling'})))
                    eval(sprintf('measPara.%s = para.%s;', loadedVars{i}, loadedVars{i}));
                else
                    eval(sprintf('%s = para.%s;', loadedVars{i}, loadedVars{i}));
                end
                eval(sprintf('para = rmfield(para,''%s'');', loadedVars{i}));
            else
                eval(sprintf('%s = [];', loadedVars{i}));
            end
        end
    end
end

%% save output
prop.flagSave = false;

%% show output in imagine
prop.flagPlot = true;

%% display output
prop.disp.names = {'Repetitions', 'Averages', 'Slices', 'Channels', 'Time', 'Frequency', 'Extracting K-Space', 'Phase Correction', 'GRAPPA calibration', 'FOCUSS', 'CG', 'ESPReSSo', 'Trafo', 'POCS', 'MC', 'Line Search', 'Log barrier', 'Newton', 'Proximal Average', 'ADMM', 'SENSE - Slice', 'SENSE - Time', 'SENSE - Calibration', 'SENSE - Kernel', 'SENSE - Concatenate'};
if(usejava('jvm') && ~feature('ShowFigureWindows'))
    % use text-based alternative
    prop.flagDisp = false;
    prop.flagPlot = prop.flagPlot & false;

    % initialize some console variables
    prop.maxvals = zeros(1,length(prop.disp.names));
    prop.lastOut = '';
else
    % use GUI dialogs
    prop.flagDisp = true;
    prop.flagPlot = prop.flagPlot & true;

    % initialize some GUI variables
    prop.disp.openBar = false(1,size(prop.disp.names,2));
    prop.disp.colors = colorGradient(rgb('DarkRed'),rgb('ForestGreen'),100);
    prop.disp.ppm = cell(1,length(prop.disp.names));
    % initialize some console variables
    prop.maxvals = zeros(1,length(prop.disp.names));
    prop.lastOut = '';
end

%% parallel computing
prop.flagParallel = false;
prop.openPool = false;
helper = ver;
lFound = false;
for i=1:length(helper)
    if(strcmp(helper(i).Name,'Parallel Computing Toolbox'))
        lFound = true;
        prop.flagParallel = prop.flagParallel & true;
        if(verLessThan('matlab','8.4'))
            if(matlabpool('size') > 0)
    %             matlabpool close
                prop.openPool = true;
            end
        else
            if(~isempty(gcp('nocreate')))
                prop.openPool = true;
            end
        end
        break;
    end
end
if(~lFound), prop.flagParallel = false; end

%% load reconstruction parameter
if(nargin > 1 && exist('para', 'var') && ischar(para))
    [pathPara, filenamePara, ~] = fileparts(para);
    cd(pathPara);
    eval([filenamePara,';']);
    cd(currpath);
else
    % load default parameter set
    eval('parameters_default;');
end

%% replace parameters (if necessary)
if(nargin > 1 && exist('para', 'var') && isstruct(para))
    names = fieldnames(para);
    for i=1:length(names)
        if(isstruct(para.(names{i})))
            innerNames = fieldnames(para.(names{i}));
            for j=1:length(innerNames)
                eval(sprintf('%s.(innerNames{j}) = para.(names{i}).(innerNames{j});',names{i}));
                if(strcmp(innerNames{j},'trafodim') && ~any(strcmp(innerNames,'scrambledim')))
                    eval(sprintf('%s.scrambledim = para.(names{i}).(innerNames{j})(1,:);',names{i}));
                end
            end
            clear 'innerNames'
        else
            eval(sprintf('%s = para.%s;',names{i},names{i}));
        end
    end
    clear 'names'
end
clear 'para';
% save MC parameters
if(exist('savePath','var'))
    mc.savePath = savePath;
else
    mc.savePath = '';
end
% check for missing necessary parameters
loadedVars = {'measPara', 'iLC', 'iLCPositions', 'drecksMDH'};
for iI=1:length(loadedVars)
    if(eval(sprintf('~exist(''%s'',''var'')',loadedVars{iI})))
        eval(sprintf('%s = [];', loadedVars{iI}));
    end
end

%% initialize dispProgress
dispProgress('InitDispProgress',prop);

%% get data dimension and loop counters
[measPara, espresso, postproc] = extractMeasPara( iLC, measPara, espresso, postproc, flagOversampling, drecksMDH, iLCPositions );

%% check variable consistency and existence
allPara = { cstype,   measPara.dimension,   measPara.dim,   iNOUTER,   iNINNER,   p,   lambda,   epsilon,   measPara.oversampling,   lambdaCalib,   calibTyk,   reconTyk,   kernelSize,   calibSize,   opt_problem,   postproc,   trafo,   FFTwindow,   espresso,   measPara.LCall, lbtol,   tvmu,   cgtol,   cgmaxiter,   flagToolbox,   flagZeropadding,  measPara.aniso,  measPara.precision, reconDIM,   flags,   lambdaGroup,   lambdaNLTV,   lambdaTV;...
           'cstype', 'dimension',           'dim',         'iNOUTER', 'iNINNER', 'p', 'lambda', 'epsilon', 'oversampling',          'lambdaCalib', 'calibTyk', 'reconTyk', 'kernelSize', 'calibSize', 'opt_problem', 'postproc', 'trafo', 'FFTwindow', 'espresso', 'LCall',        'lbtol', 'tvmu', 'cgtol', 'cgmaxiter', 'flagToolbox', 'flagZeropadding', 'aniso',        'precision',        'reconDIM', 'flags', 'lambdaGroup', 'lambdaNLTV', 'lambdaTV'}; %#ok<*NODEF>

[consExist, msg, msgWarn, kernelSize, calibSize, FFTwindow, trafo, flagToolbox, measPara.precision, flags, reconDIM] = checkConsExist(allPara);
if(~consExist)
    error('CS_reconstruction:checkConsExist','%s', msg);
end
if(~isempty(msgWarn))
    warning('CS_reconstruction:checkConsExist\n%s', msgWarn);
end
clear 'allPara' 'msg' 'msgWarn' 'consExist';

%% initialize recon objects
if(strcmp(cstype,'FOCUSS'))
    obj = FOCUSS(iNOUTER, iNINNER, p, lambda, epsilon, measPara, lambdaCalib, lambdaTV, lambdaESPReSSo, lambdaMC, kernelSize, calibTyk, calibSize, flagZeropadding, FFTwindow, trafo, espresso, sScaling, mc, lSense);

elseif(strcmp(cstype,'SPIRiT_CG') || strcmp(cstype,'SPIRiT_POCS'))
    obj = SPIRiT_Wrapper(cstype(8:length(cstype)), iNINNER, measPara, lambda, kernelSize, calibTyk, reconTyk, trafo, espresso, FFTwindow, calibSize); %#ok<*COLND>

elseif(strcmp(cstype,'ESPIRiT_CG') || strcmp(cstype,'ESPIRiT_L1'))
    obj = ESPIRiT_Wrapper(cstype(9:length(cstype)), iNINNER, iNIterSplit, measPara, kernelSize, calibTyk, reconTyk, eigThresh_k, eigThresh_im, n_maps, splitWeight, trafo, flagToolbox, path, espresso, FFTwindow, calibSize);

elseif(strcmp(cstype,'BART'))
    obj = BART_Wrapper(lambda, lambdaCalib, lambdaTV, lambdaMC, measPara, kernelSize, n_maps, trafo, espresso, FFTwindow, currpath, mc, calibSize);

elseif(strcmp(cstype,'sparseMRI'))
    obj = sparseMRI(iNOUTER, iNINNER, measPara, lambda, lambdaTV, lambdaESPReSSo, p, trafo, espresso, FFTwindow, l1Smooth, lineSearchItnlim, lineSearchAlpha, lineSearchBeta, lineSearchT0, gradToll);

elseif(strcmp(cstype,'L1_Magic_TV') || strcmp(cstype,'L1_Magic_L1') || strcmp(cstype,'L1_Magic_TVDantzig') || strcmp(cstype,'L1_Magic_L1Dantzig'))
    obj = L1_Magic(cstype(10:length(cstype)), measPara, epsilon, lbtol, tvmu, cgtol, cgmaxiter, pdmaxiter, espresso);

elseif(strcmp(cstype,'Zero'))
    obj = Zero(measPara, espresso);

elseif(strcmp(cstype,'FCSA_WaTMRI') || strcmp(cstype,'FCSA_SLEP') || strcmp(cstype,'FCSA_proxA') || strcmp(cstype,'BFCSA_proxA') || strcmp(cstype,'ADMM_proxA') || strcmp(cstype,'SB_proxA') || ...
        strcmp(cstype,'A_PFISTA') || strcmp(cstype,'A_TDIHT') || strcmp(cstype,'A_ADMM_L1') || strcmp(cstype,'A_ADMM_L0') || strcmp(cstype,'A_ADMM_SCAD') || strcmp(cstype,'A_ADMM_MCP') || strcmp(cstype,'A_ADMM_ATAN') || strcmp(cstype,'A_ADMM_PSHRINK'))
    obj = Proximal(cstype, iNINNER, itrNLTV, iNOUTER, measPara, trafo, lambda, lambdaTV, lambdaGroup, lambdaNLTV, lambdaNLTV_h, mue, regularizerWeights, flags, reconDIM, espresso);

else
    error('CS_reconstruction(): Undefined reconstruction cstype');
end

%% optimize fft command
if(prop.flagOptim)
    optimizeFFT(measPara.dimension, measPara.dim, kernelSize, fft_planner_method, trafo.fftdim, lambdaCalib, flagZeropadding, measPara.precision);
end

%% extract kSpace data from measurement file
if(exist('iLC','var') && ~isempty(iLC) && ~exist('kSpace', 'var'))
    [obj.kSpace, evalMask] = extractKSpace_main(dData, iLC, iEvalInfoMask, measPara);
else
    obj.kSpace = kSpace;
    clear 'kSpace';
end

%% correct phase perturbations (echo alignment)
if(isfield(measPara,'sequenceName') && strcmp(measPara.sequenceName, 'CS_EPI'))
    obj.kSpace = alignEchos(obj.kSpace, evalMask, measPara, dData, iLC, iEvalInfoMask);
end

% clear all unnecessary variables
clear 'dData' 'iLC' 'dDataRep' 'iLCRep' 'dDataSli' 'iLCSli' 'drecksMDH' 'iLCPositions' 'evalMask' 'helper' 'espresso' 'trafo' 'flagOversampling' 'mc';
sCallingStack = dbstack;
if(strcmp(sCallingStack(end).name,'fRetroGateAndRecon') || strcmp(sCallingStack(end).name,'MotionCorrection')) % for 4D CS_Retro
    evalin('caller', 'clear ''kSpace'';'); % ''para''
end
clear 'sCallingStack';

%% start reconstruction
cs_time = tic;
imageCha = cell(size(obj.kSpace));

if(lAutoCheck && ( ((strcmp(measPara.dimension,'3D') || strcmp(measPara.dimension,'4D')) && nnz(obj.kSpace{1,1}) >= 0.95*prod(measPara.dim(1:4))) || ...
        (strcmp(measPara.dimension,'2D') && nnz(obj.kSpace{1,1}) >= 0.95*prod(measPara.dim([1:2,4]))) || ...
        (obj.espresso.state && ~isempty(regexp(filename,'\w*x1\D\w*','once'))) || (obj.espresso.state && isfield(measPara, 'CSAcceleration') && measPara.CSAcceleration == 1)))
    % check for acceleration factor == 1 ==> full acquisition
    if(strcmp(measPara.dimension,'2D'))
        fftdim = 1:2;
        pfdim = [3 1 2];
        subs = {':', ':', ':', ':'}; % y-x-cha
        subsid = 4;
        if(measPara.dim(4) > 1)
            pfdim = [4 1 2 3];
            subs = {':', ':', ':', ':'}; % y-x-t-cha
            subsid = 3;
        end
    elseif(strcmp(measPara.dimension,'3D'))
        fftdim = 1:3;
        pfdim = [4 1 2 3];
        subs = {':', ':', ':', ':', ':'}; % y-x-z-cha
        subsid = 5;
    elseif(strcmp(measPara.dimension,'4D'))
        fftdim = 1:3;
        pfdim = [5 1 2 3 4];
        subs = {':', ':', ':', ':', ':'}; % y-x-z-t-cha
        subsid = 4;
    end
    totalCount = measPara.LCall(2)*measPara.LCall(4)*measPara.LCall(1)*measPara.dim(4);
    dispProgress('Repetitions', 0, measPara.LCall(4));
    dispProgress('Averages', 0, totalCount);
    dispProgress('Time', 0, totalCount);
    for iRep=1:measPara.LCall(4)
        for iAvg=1:measPara.LCall(2)
            if(obj.espresso.state)
                for iSli=1:measPara.LCall(1)
                    kSpaceTmp = squeeze(cell2mat(shiftdim(obj.kSpace(iSli,:,iRep,iAvg),-2)));
                    imgTmp = zeros(size(kSpaceTmp));
                    for iTime=1:measPara.dim(4)
                        subs{subsid} = iTime;
                        imgTmp(subs{:}) = ipermute(espresso_recon(permute(kSpaceTmp(subs{:}),pfdim), obj.espresso.iter, false),pfdim);
                        dispProgress('Time', ((iRep-1)*measPara.LCall(2)*measPara.LCall(1)*measPara.dim(4) + (iAvg-1)*measPara.LCall(1)*measPara.dim(4) + (iSli-1)*measPara.dim(4) +iTime)/totalCount);
                    end
                    if(strcmp(measPara.dimension,'2D') && measPara.dim(4) == 1) % 2D
                        imageCha(iSli,:,iRep,iAvg) = shiftdim(squeeze(mat2cell(imgTmp, size(obj.kSpace{1,1},1),size(obj.kSpace{1,1},2),ones(1,measPara.dim(5)))),-1);
                    else % 2Dt, 3D, 4D
                        imageCha(iSli,:,iRep,iAvg) = shiftdim(squeeze(mat2cell(imgTmp, size(obj.kSpace{1,1},1),size(obj.kSpace{1,1},2),size(obj.kSpace{1,1},3),ones(1,measPara.dim(5)))),-1);
                    end
                    clear 'imgTmp' 'kSpaceTmp';
                end
            else
                imageCha(:,:,iRep,iAvg) = cellfun(@(x) ifftnshift(x,fftdim), obj.kSpace(:,:,iRep,iAvg), 'UniformOutput', false);
            end
            dispProgress('Averages', ((iRep-1)*measPara.LCall(2)*measPara.LCall(1)*measPara.dim(4) + iAvg*measPara.LCall(1)*measPara.dim(4))/totalCount);
        end
        dispProgress('Repetitions', iRep/measPara.LCall(4));
    end
    dispProgress('Time','Close');
else
    % Compressed Sensing reconstruction
    dispProgress('Repetitions', 0, measPara.LCall(4));
    dispProgress('Averages', 0, measPara.LCall(4)*measPara.LCall(2));
    for iRep=1:measPara.LCall(4)
        for iAvg=1:measPara.LCall(2)
            imageCha(:,:,iRep,iAvg) = obj.recon_main(iRep,iAvg); % obj.kSpace(:,:,iRep,iAvg)
            dispProgress('Averages', ((iRep-1)*measPara.LCall(2) + iAvg)/(measPara.LCall(4)*measPara.LCall(2)));
        end
        dispProgress('Repetitions', iRep/measPara.LCall(4));
    end
end
if(exist('cutOutMask','var')), imageCha = imageCha(cutOutMask); end;
dispProgress('Averages', 'Close');
dispProgress('Repetitions', 'Close');
obj.kSpace = []; % clear kSpace variable

cs_time = toc(cs_time);
dRecontime(1) = mod(cs_time,60);
dRecontime(2) = mod((cs_time - dRecontime(1))/60,60);
dRecontime(3) = mod(((cs_time - dRecontime(1))/60 - dRecontime(2))/60, 24);
if(cs_time >= 3600)
    fprintf('Execution time: %.2dh %.2dmin %.2ds\n', dRecontime(3), dRecontime(2), round(dRecontime(1)));
elseif(cs_time >= 60)
    fprintf('Execution time: %.2dmin %.2ds\n', dRecontime(2), round(dRecontime(1)));
else
    fprintf('Execution time: %.2ds\n', round(dRecontime(1)));
end
obj.dRecontime = dRecontime;

%% postprocessing
if(isempty(obj.kernelSize))
    obj.kernelSize = kernelSize;
end

image = cell(1,measPara.LCall(4));
for iRep=1:measPara.LCall(4)
    imageAvg = cell(1,measPara.LCall(2));
    for iAvg=1:measPara.LCall(2)
        % each element: 2D (y-x + one slice), 3D (y-x-t + one slice, y-x + several slices, y-x-z) or
        % 4D (y-x-t + several slices, y-x-z-t)
        imageAvg{1,iAvg} = postproc_main(obj, imageCha(:,:,iRep,iAvg), postproc);
    end
    image{iRep} = squeeze(mean(cell2mat(shiftdim(imageAvg,-4)),6));
end
image = squeeze(cell2mat(shiftdim(image,-3)));

% % average over repetitions
% image = squeeze(mean(cell2mat(shiftdim(image,-3)),5));

%% delete fftw_wisdom variable
if(prop.flagOptim)
    evalin('base', 'clear ''fftw_wisdom''');
end

%% save image
if(nargout > 2 || prop.flagSave)
    % convert obj->struct and reduce size
    objProp = properties(obj);
    for iObj = 1:numel(objProp)
        if(any(strcmp(objProp{iObj},{'kernel','kernelImg','kCalib','A','kSpace'})))
            continue;
        end
        eval(['objOut.',objProp{iObj},' = obj.',objProp{iObj},';']);
    end
end
if(prop.flagSave)
    if(exist('filename','var') && ~isempty(filename))
        savename = [filename,'_',cstype,'_',transformation];
    else
        savename = [cstype,'_',transformation];
    end
    dirContent = dir(path);
    occurence = 0;
    for i=1:length(dirContent)
        if(dirContent(i).isdir)
            continue;
        end
        tmp = regexp(dirContent(i).name,[savename,'[_]*\d*'],'once');
%         if(strcmpi(dirContent(i).name,savename))
        if(~isempty(tmp))
            occurence = occurence + 1;
        end
    end
    if(occurence > 0)
         savename = [savename,'_',num2str(occurence)];
    end
%     save([path,filesep,savename,'.mat'], 'image', 'imageCha', 'objOut');
    save([path,filesep,savename,'.mat'], 'image', 'objOut', '-v7.3');
end

%% plot resulting image
if(prop.flagPlot && exist('imagine','file'))
    if(iscell(image))
        imagePlot = cell2mat(shiftdim(image,-1));
    else
        imagePlot = image;
    end

    % set displayed name
    figname = [cstype,'_',transformation];
    tmp = functions(FFTwindow.type);
    if(~strcmp(tmp.function,'rectwin'))
        figname = [figname,'_',tmp.function];
    end
    if(obj.espresso.state)
        figname = [figname,'_espresso'];
    end
    figname = [figname,'_',postproc.type];

    % if imagine is already open, add new image in same window
    hfig = findobj('type','figure','name','IMAGINE 2.0 Belly Jeans');
    if(length(hfig) > 1)
        hfig = max(hfig);
    end

    if(~isempty(hfig) && ishandle(hfig))
        fh = get(hfig,'userdata');
        data = fh();

        oldImage = cell(1,size(data,2));
        oldTitle = oldImage;
        cmd = '';
        for i=1:size(data,2)
            oldImage{i} = data(i).dImg;
            oldTitle{i} = data(i).sName;
            cmd = [cmd, sprintf('oldImage{%d},''Name'',oldTitle{%d},',i,i)];
        end

        close(hfig);
        cmd = ['imagine(',cmd, 'imagePlot,''Name'',figname);'];
        eval(cmd);
        clear oldImage oldTitle cmd hfig;
    else
        imagine(imagePlot,'Name',figname);
    end
end

end


function rtk=udclk_ppp(rtk)

global glc
opt=rtk.opt; VAR_CLK=60^2; CLIGHT=glc.CLIGHT; tt=abs(rtk.tt);
navsys=opt.navsys; mask=rtk.mask; prn=0;

% for single-system except GPS
if strcmp(navsys,'R')
    dtr=rtk.sol.dtr(2);
    if abs(dtr)<=1e-16,dtr=1e-16;end
    rtk=initx(rtk,CLIGHT*dtr,VAR_CLK,rtk.ic+2);

    % for GLONASS icb
    if opt.gloicb==glc.GLOICB_LNF
        if rtk.x(rtk.iicb+1)==0
            rtk=initx(rtk,0.1,VAR_CLK,rtk.iicb+1);
        end
    elseif opt.gloicb==glc.GLOICB_QUAD
        if rtk.x(rtk.iicb+1)==0
            rtk=initx(rtk,0.1,VAR_CLK,rtk.iicb+1);
        end
        if rtk.x(rtk.iicb+2)==0
            rtk=initx(rtk,0.1,VAR_CLK,rtk.iicb+2);
        end
    end
    return
elseif strcmp(navsys,'E')
    dtr=rtk.sol.dtr(3);
    if abs(dtr)<=1e-16,dtr=1e-16;end
    rtk=initx(rtk,CLIGHT*dtr,VAR_CLK,rtk.ic+3);
    return
elseif strcmp(navsys,'C')
    dtr=rtk.sol.dtr(4);
    if abs(dtr)<=1e-16,dtr=1e-16;end
    rtk=initx(rtk,CLIGHT*dtr,VAR_CLK,rtk.ic+4);
    return
elseif strcmp(navsys,'J')
    dtr=rtk.sol.dtr(5);
    if abs(dtr)<=1e-16,dtr=1e-16;end
    rtk=initx(rtk,CLIGHT*dtr,VAR_CLK,rtk.ic+5);
    return
end

% for GPS or multi-system
dtr=rtk.sol.dtr(1);
if abs(dtr)<=1e-16,dtr=1e-16;end
rtk=initx(rtk,CLIGHT*dtr,VAR_CLK,rtk.ic+1);
for i=2:glc.NSYS
    if mask(i)==0,continue;end
    if i==glc.SYS_GLO
        dtr=rtk.sol.dtr(2);
        if rtk.x(rtk.ic+2)==0
            if abs(dtr)<=1e-16,dtr=1e-16;end
            rtk=initx(rtk,CLIGHT*dtr,VAR_CLK,rtk.ic+2);
        else
            rtk.P(rtk.ic+i,rtk.ic+i)=rtk.P(rtk.ic+i,rtk.ic+i)+prn^2*tt;
        end
        % for GLONASS icb
        if opt.gloicb==glc.GLOICB_LNF
            if rtk.x(rtk.iicb+1)==0
                rtk=initx(rtk,0.1,VAR_CLK,rtk.iicb+1);
            end
        elseif opt.gloicb==glc.GLOICB_QUAD
            if rtk.x(rtk.iicb+1)==0
                rtk=initx(rtk,0.1,VAR_CLK,rtk.iicb+1);
            end
            if rtk.x(rtk.iicb+2)==0
                rtk=initx(rtk,0.1,VAR_CLK,rtk.iicb+2);
            end
        end
    else
        dtr=rtk.sol.dtr(i);
        if rtk.x(rtk.ic+i)==0
            if abs(dtr)<=1e-16,dtr=1e-16;end
            rtk=initx(rtk,CLIGHT*dtr,VAR_CLK,rtk.ic+i);
        else
            rtk.P(rtk.ic+i,rtk.ic+i)=rtk.P(rtk.ic+i,rtk.ic+i)+prn^2*tt;
        end
    end
end

return


function cluster_length = save_declus(catalog)

    ZG=ZmapGlobal.Data; % used by get_zmap_globals
    global cluslength %[OUT]
    %FIXME: this is torn to shreds by the updated catalog format
    report_this_filefun();
    storedcat=a;
    hodis = fullfile(hodi, 'external');
    cd(hodis);

    str = [];

    s = [  ZG.primeCatalog.Date.Year  ZG.primeCatalog.Date.Month  ZG.primeCatalog.Date.Day ZG.primeCatalog.Date.Hour ZG.primeCatalog.Date.Minute ZG.primeCatalog.Magnitude   ZG.primeCatalog.Latitude  ZG.primeCatalog.Longitude  ZG.primeCatalog.Depth   ];
    fid = fopen(['data'],'w') ;
    fprintf(fid,'%4.0f%2.0f%2.0f%2.0f%2.0f  %3.1fmb%7.3f%8.3f%5.1fA\n',s');
    fclose(fid);
    clear s

    s = [taumin*60*24 taumax*60*24 P xk xmeff rfact err derr ];
    fid = fopen(['para.dat'],'w') ;
    fprintf(fid,'%5.0f  %5.0f  %5.3f  %5.3f  %5.3f  %5.3f  %5.3f  %5.3f\n',s');
    fclose(fid);
    clear s

    % This executes the clus.exe FORTRAN code
    unix(['.' filesep 'myclus ']);

    %open datafile
    fid = 'outf.clu';

    try
        format = ['%12c %3f %f %f %f %d'];
        %[dat,mag,lat,lon,dep,clu] = textread(fid,format,'whitespace',' \b\r\t\n mb A ');
        C = textscan(fid, format, 'Whitespace',' \b\r\t\n mb A ');
        dat=C{1}; mag=C{2}; lat = C{3}; lon=C{4}; dep = C{5}; clu = C{6};
    catch ME
        l=ME.message;
        l1 = strfind(l,',');
        anz = str2double(l(53:l1-1));
        %[dat,mag,lat,lon,dep,clu] = textread(fid,format,anz-1,'whitespace',' \b\r\t\n mb A ');
        C = textscan(fid, format, anz-1, 'Whitespace',' \b\r\t\n mb A ');
        dat=C{1}; mag=C{2}; lat = C{3}; lon=C{4}; dep = C{5}; clu = C{6};

        disp(['Error in Line ' num2str(anz) ' read only lines  1 - ' num2str(anz-1) ]);

    end

    %transform data to ZMAP format
    watchon;
    disp('Reloading data ...')

    yr = str2double(dat(:,1:4));
    mo=  str2double(dat(:,5:6));
    da=  str2double(dat(:,7:8));
    hr=  str2double(dat(:,9:10));
    mi=  str2double(dat(:,11:12));

    replaceMainCatalog([lon lat ZG.primeCatalog.Date mo da mag storedcat.Depth hr mi clu]);

    cluslength=[];
    n=0;
    k1=max(clu);
    for j=1:k1                         %for all clusters
        cluslength(j)=length(find(clu==j));  %length of each clusters
    end

    tmp=find(cluslength);      %numbers of clusters that are not empty

    %cluslength,bg,mbg only for events which are not zero
    cluslength=cluslength(tmp);

    clustnumbers=(1:length(tmp));    %stores numbers of clusters
    l = a(:,10) > 0;
    clus = ZG.primeCatalog.subset(l);
    ZG.primeCatalog(l,:) = [];

    % plot the results
    zmap_update_displays();
    set(gca,'NextPlot','add')
    plot(clus(:,1),clus(:,2),'m+');

    st1 = [' The declustering found ' num2str(max(clu)) ' clusters of earthquakes, a total of '...
        ' ' num2str(length(clus(:,1))) ' events (out of ' num2str(storedcat.Count) '). '...
        ' The map window now display the declustered catalog containing ' num2str(ZG.primeCatalog.Count) ' events . The individual clusters are displayed as magenta o in the map. ' ];

    msgbox(st1,'Declustering Information')
    watchoff;
end


function dx = pendulumSystem(x,A,P,grid,dyn)
% dx = pendulumSystem(x,A,P,pendulum)
%
% This function computes the closed loop dynamics of the pendulum, using
% the optimal controller from the MDP solve
%

th = x(1,:);
w = x(2,:);

u = pendulumController(x,A,P,grid);
dw = pendulumDynamics(th,w,u,dyn);

dx = [w;dw];

end