function proposals = genProposalsByOrientation(img, region, regionPerim, estimated_orientation, region_comp_infos)
    global param;

    if(isnan(estimated_orientation))
        proposals = zeros(0, 9);
        return
    end

    [comp_cluster_ind, ~] = compCluster(img, region_comp_infos, ...
                                                    estimated_orientation, ...
                                                    param.minCompHeightSimilarity, ...
                                                    param.maxCompOrientationDiff, ...
                                                    param.minIoUDiff);

    clusterIdx = unique(comp_cluster_ind);
    clusterCount = length(clusterIdx);
    proposals = zeros(clusterCount, 9);
    confident_idx = false(clusterCount, 1);

    for c = 1 : clusterCount
        clusterCompInfos = region_comp_infos(comp_cluster_ind == clusterIdx(c));
        if(length(clusterCompInfos) > 0)
            confident_idx(c) = true;
            proposals(c, 1 : 8) = getProposal(img, region, regionPerim, clusterCompInfos, estimated_orientation);
            proposals(c, 9) = estimated_orientation;
        end
    end

    proposals = proposals(confident_idx, :);

    %% show proposals
    if true && param.debug
        imshow(img);
        hold on;
        for i = 1 : clusterCount
            x_arr = [proposals(i, 1 : 2 : 8), proposals(i, 1)];
            y_arr = [proposals(i, 2 : 2 : 8), proposals(i, 2)];

            plot(x_arr, y_arr, 'color', rand(3,1));
        end
        hold off;
    end

    %% show clusters
    if false && param.debug
        debug_bbox_gathered = zeros(0, 4);
        color_gathered = zeros(0, 3);
        for c = 1: clusterCount
            clusterCompInfos = region_comp_infos(comp_cluster_ind == clusterIdx(c));
            debug_bbox = zeros(length(clusterCompInfos), 4);
            color = repmat(rand(1,3), length(clusterCompInfos), 1);

            for d_i = 1 : length(clusterCompInfos)
                debug_bbox(d_i,:) = clusterCompInfos{d_i}.box;
            end

            debug_bbox_gathered = cat(1, debug_bbox_gathered, debug_bbox);
            color_gathered = cat(1, color_gathered, color);
        end
        show_bbox(img, debug_bbox_gathered, color_gathered);
    end
end

function [comp_cluster_ind, clusterCount] = compCluster(img, region_comp_infos, estimated_orientation, minCompHeightSimilarity, maxCompOrientationDiff, minIoUDiff)
    global param;

    compCount = length(region_comp_infos);

    if(compCount == 0)
        comp_cluster_ind = zeros(0, 1);
        clusterCount = 0;
        return;
    end

    if(compCount == 1)
        comp_cluster_ind = ones(1,1);
        clusterCount = 1;
        return;
    end

    comp_cluster_ind = zeros(compCount, 1, 'uint16');
    clusterCount = 0;

    box4d = zeros(compCount, 4);
    heights = zeros(compCount, 1);

    boxCenter = zeros(compCount, 2);
    boxCenter_U = zeros(compCount, 2);
    boxCenter_D = zeros(compCount, 2);
    boxCenter_L = zeros(compCount, 2);
    boxCenter_R = zeros(compCount, 2);

    for i = 1 : compCount
        box4d(i, :) = region_comp_infos{i}.box;
        [rectX, rectY, ~, ~, sideLenght] = computeMergedBox(box4d(i, :));
        [~, heights(i)] = findWidthAndHeight(rectX, rectY, sideLenght, estimated_orientation);

        boxCenter(i, 2) = round(box4d(i, 1) + 0.5*box4d(i, 3));
        boxCenter(i, 1) = round(box4d(i, 2) + 0.5*box4d(i, 4));

        boxCenter_U(i, 2) = round(box4d(i, 1) + 0.5*box4d(i, 3));
        boxCenter_U(i, 1) = box4d(i, 2);

        boxCenter_D(i, 2) = round(box4d(i, 1) + 0.5*box4d(i, 3));
        boxCenter_D(i, 1) = box4d(i,2) + box4d(i,4) - 1;

        boxCenter_L(i, 2) = box4d(i,1);
        boxCenter_L(i, 1) = round(box4d(i, 2) + 0.5*box4d(i, 4));

        boxCenter_R(i, 2) = box4d(i,1) + box4d(i,3) - 1;
        boxCenter_R(i, 1) = round(box4d(i, 2) + 0.5*box4d(i, 4));
    end

    heightSimilarity = zeros(compCount);
    IoUDiff = zeros(compCount);
    orientationDiffOfBox = zeros(compCount);
    dists = zeros(compCount);

    for i = 1 : compCount

        %% Compute height similarity
        heightSimilarity(i,:) = min( ...
                                    min(box4d(i, 4), box4d(:, 4)) ./ max(box4d(i, 4), box4d(:, 4)), ...
                                    min(box4d(i, 3), box4d(:, 3)) ./ max(box4d(i, 3), box4d(:, 3)));
       %% Compute IoU diff
        intArea = rectint(box4d(i,:), box4d);
        unionArea = box4d(i,3) * box4d(i,4) + box4d(:, 3).* box4d(:, 4);
        IoUDiff(i, :) = intArea ./ unionArea';

        %% Compute orientation diff of box
        orientationDiff_U = computeOrientationDiff(boxCenter_U, boxCenter_U(i,:), estimated_orientation);
        orientationDiff_D = computeOrientationDiff(boxCenter_D, boxCenter_D(i,:), estimated_orientation);
        orientationDiff_L = computeOrientationDiff(boxCenter_L, boxCenter_L(i,:), estimated_orientation);
        orientationDiff_R = computeOrientationDiff(boxCenter_R, boxCenter_R(i,:), estimated_orientation);
        orientationDiffOfBox(i, :) = min(min(orientationDiff_U, orientationDiff_D), ...
                                    min(orientationDiff_L, orientationDiff_R));

        %% Compute dist
        dists(i, :) = ((boxCenter(:, 1) - boxCenter(i, 1)).^2 + (boxCenter(:, 2) - boxCenter(i,2)).^2).^0.5;
    end

    if true && param.debug
        imshow(img);
        for i = 1 : compCount
            rectangle('position', box4d(i, :), 'edgecolor','y');
        end
    end

    for i = 1 : compCount
        if comp_cluster_ind(i) == 0
            clusterCount = clusterCount + 1;
            current_cluster_comp_ind = false(compCount, 1);
            current_cluster_comp_ind(i) = 1;

            isUpdate = true;
            while isUpdate
                isUpdate = false;

                %% Compute boxCenter of merged bbox
                mergedBoxCenter_U = [mean(box4d(current_cluster_comp_ind, 2)), ...
                                        mean(box4d(current_cluster_comp_ind, 1) + 0.5*box4d(current_cluster_comp_ind, 3))];

                mergedBoxCenter_D = [mean(box4d(current_cluster_comp_ind, 2) + box4d(current_cluster_comp_ind, 4) - 1), ...
                                        mean(box4d(current_cluster_comp_ind, 1) + 0.5*box4d(current_cluster_comp_ind, 3))];

                mergedBoxCenter_L = [mean(box4d(current_cluster_comp_ind, 2) + 0.5*box4d(current_cluster_comp_ind, 4)), ...
                                        mean(box4d(current_cluster_comp_ind, 1))];

                mergedBoxCenter_R = [mean(box4d(current_cluster_comp_ind, 2) + 0.5*box4d(current_cluster_comp_ind, 4)), ...
                                        mean(box4d(current_cluster_comp_ind, 1) + box4d(current_cluster_comp_ind, 3) - 1)];

                %% Compute orientation diff
                orientationDiff_U = computeOrientationDiff(boxCenter_U, mergedBoxCenter_U, estimated_orientation);
                orientationDiff_D = computeOrientationDiff(boxCenter_D, mergedBoxCenter_D, estimated_orientation);
                orientationDiff_L = computeOrientationDiff(boxCenter_L, mergedBoxCenter_L, estimated_orientation);
                orientationDiff_R = computeOrientationDiff(boxCenter_R, mergedBoxCenter_R, estimated_orientation);

                orientationDiff = min(min(orientationDiff_U, orientationDiff_D), min(orientationDiff_L, orientationDiff_R))';

                heightSimilarity_rule = heightSimilarity(current_cluster_comp_ind,:) > minCompHeightSimilarity;
                orientationDiff_rule = orientationDiff < maxCompOrientationDiff;
                IoUDiff_rule = IoUDiff(current_cluster_comp_ind, :) > minIoUDiff;
                orientationDiffOfBox_rule = heightSimilarity_rule ...
                                            & (orientationDiffOfBox(current_cluster_comp_ind, :) < maxCompOrientationDiff) ...
                                            & (dists(current_cluster_comp_ind, :) < param.maxDistRatio * mean(box4d(current_cluster_comp_ind, 4)));

                spatial_rule = ((sum(heightSimilarity_rule, 1) > 0) & sum(orientationDiffOfBox_rule, 1) > 0) ...
                                | (sum(IoUDiff_rule, 1) > 0) ...
                                | (orientationDiff_rule & (sum(heightSimilarity_rule, 1) > 0));
                %spatial_rule = sum((heightSimilarity_rule & orientationDiff_rule) | IoUDiff_rule, 1) > 0;

                satisfiedComp = spatial_rule' ...
                            & (~current_cluster_comp_ind);

                satisfiedIdx = find(satisfiedComp);
                if(~isempty(satisfiedIdx))
                    isUpdate = true;
                    current_cluster_comp_ind(satisfiedIdx) = 1;
%                     x1_tmp = min(min(box4d(satisfiedIdx, 1)), ...
%                                  mergedBox(1));
%                     x2_tmp = max(max(box4d(satisfiedIdx, 1) + box4d(satisfiedIdx, 3) - 1), ...
%                                  mergedBox(1) + mergedBox(3) - 1);
%                     y1_tmp = min(min(box4d(satisfiedIdx, 2)), ...
%                                  mergedBox(2));
%                     y2_tmp = max(max(box4d(satisfiedIdx, 2) + box4d(satisfiedIdx, 4) - 1), ...
%                                  mergedBox(2) + mergedBox(4) - 1);
%                     mergedBox(1) = x1_tmp;
%                     mergedBox(2) = y1_tmp;
%                     mergedBox(3) = x2_tmp - x1_tmp + 1;
%                     mergedBox(4) = y2_tmp - y1_tmp + 1;

                    if true &&  param.debug
                        clusterCompInfos = region_comp_infos(current_cluster_comp_ind);
                        color = zeros(length(clusterCompInfos), 3);
                        color(:, 2) = 1;
                        color(1, :) = [1, 0, 0];
                        imshow(img);
                        for d_i = 1 : length(clusterCompInfos)
                           rectangle('position', clusterCompInfos{d_i}.box, 'edgecolor', color(d_i,:));
                        end
                    end
                end
            end
            comp_cluster_ind(current_cluster_comp_ind) = clusterCount;
        end
    end
end


% *************************************************************************
% Video Super-Resolution with Convolutional Neural Networks
%
% main VSRnet script, includes the interface to the caffe framework
% do not run this script directly. call it from VSRnet_demo instead
%
% Version 1.0
%
% Created by:   Armin Kappeler
% Date:         02/19/2016
%
% *************************************************************************

%% more parameters (do not change, unless you know what you are doing)

BORDERSIZE = 8; %4+2+2; %border size = sum of all zeropaddings in model def file

% parameters for LOW_MEMORY_MODE=2
Param.patchSize = 36;
Param.stride = 20;
Param.outputPatchSize = 20;
Param.zeropadding = 1;

%% Init VSRnet configuration files

if (MOTIONCOMPENSATION==false && UPSCALE_FACTOR ~= 3 && ADAPTIVEMOTIONCOMPENSATION==false)
    error('Error: MOTIONCOMPENSATION=false is only available for upscale factor 3. Please either set UPSCALEFACTOR=3 or MOTIONCOMPENSATION=true')
end
if (MOTIONCOMPENSATION==false && ADAPTIVEMOTIONCOMPENSATION==true)
    display('The MOTIONCOMPENSATION flag is ignored because ADAPTIVEMOTIONCOMPENSATION=true')
end

if MOTIONCOMPENSATION
    model_def_file_template = ['models/u' num2str(UPSCALE_FACTOR) '/superres_deploy.prototxt'];
    model_file =    ['models/u' num2str(UPSCALE_FACTOR) '/SRnet_train_iter_200000.caffemodel'];
else
    model_def_file_template = ['models/u' num2str(UPSCALE_FACTOR) '_noMotionCompensation/superres_deploy.prototxt'];
    model_file =    ['models/u' num2str(UPSCALE_FACTOR) '_noMotionCompensation/SRnet_train_iter_200000.caffemodel'];
end
model_def_file = 'models/tmp/tmp_superres_deploy.prototxt';

%% preprocess input data

TESTVIDEO_PATH
if PREPROCESSED_INPUT
    load(TESTVIDEO_PATH);

    if TESTONLY1FRAME
        input_data{1} = input_data{1}(:,:,:,TESTONLY1FRAME);
        im_gt = im_gt(:,:,:,TESTONLY1FRAME);
    end
else
    data = load(TESTVIDEO_PATH);
    if TESTONLY1FRAME
        data.frames = data.frames(:,:,TESTONLY1FRAME:TESTONLY1FRAME+4);
    end
    [input_data,idx_gt] = preprocess_frames(data.frames,UPSCALE_FACTOR,MOTIONCOMPENSATION,ADAPTIVEMOTIONCOMPENSATION);

end
im_bic = permute(input_data{1}(:,:,3,:),[2,1,3,4])*255;

%% caffe setup

batchsize = size(input_data{1},4);
imageSize = [ size(input_data{1},2), size(input_data{1},1)];
Param.inputImgSize = imageSize;

caffe.reset_all();

if USE_GPU
  caffe.set_mode_gpu();
  caffe.set_device(GPU_ID);
else
  caffe.set_mode_cpu();
end

if LOW_MEMORY_MODE==1
    imagecut = imageSize(1)/2;
    imageSize(1) = imageSize(1)/2 + BORDERSIZE;
elseif LOW_MEMORY_MODE==2
    imageSize = [Param.patchSize Param.patchSize];
end

change_caffe_image_input_size(model_def_file_template,model_def_file,imageSize,1)
net = caffe.Net(model_def_file, model_file, 'test');

%% do forward pass

tic;
output = zeros(size(im_bic,2),size(im_bic,1),size(im_bic,3),size(im_bic,4));
for imgIdx = 1:size(im_bic,4)
    display(['Superresolve frame ' num2str(imgIdx)]);
    if LOW_MEMORY_MODE==1 % divide image in two parts to reduce memory usage
        tmp1 = net.forward({input_data{1}(:,1:imagecut + BORDERSIZE,:,imgIdx)});
        tmp2 = net.forward({input_data{1}(:,imagecut+1-BORDERSIZE:end,:,imgIdx)});
        output(:,:,:,imgIdx) = cat(2,tmp1{1}(:,1:imagecut,:,:),tmp2{1}(:,BORDERSIZE+1:end,:,:));
    elseif LOW_MEMORY_MODE==2 % process the image patchwise
        input_data_new = patchify(input_data{1}(:,:,:,imgIdx), Param);
        if Param.zeropadding==1
            output_raw = zeros(size(input_data_new,1),size(input_data_new,2),1,size(input_data_new,4));
        else
            output_raw = zeros(Param.outputPatchSize,Param.outputPatchSize,1,size(input_data_new,4));
        end
        for pIdx = 1:size(input_data_new,4)
            output_raw_tmp = net.forward({input_data_new(:,:,:,pIdx)});
            output_raw(:,:,:,pIdx) = output_raw_tmp{1};
            if mod(pIdx,1000)==0
                fprintf('.');
            end
        end
        fprintf('\n');
        output(:,:,:,imgIdx) = depatchify(output_raw,Param);
    else
        tmp = net.forward({input_data{1}(:,:,:,imgIdx)});
        output(:,:,:,imgIdx) = tmp{1};
    end
end
toc;

im_SR = output;
im_SR = permute(im_SR,[2 1 3 4]);
im_SR = im_SR*255;

save(RESULTFILE_PATH,'im_SR','model_file','TESTVIDEO_PATH');


% DEMHSVARGPLVMREGRESSION A script to run deep GP regression.
%
% This is a generic demo. You can replace the data used here with your own
% data and run it (ie Ytr{1} has to be the observed data and inpX has to be
% your observed labels).
%
% To configure the deepGP used here, do the following:
%   1. If any of the fields you want to change appear in this demo in the
%   "configuring the deep gp" section, they change it directly there.
%   2. If the field you're looking for is not there, then check the available
%    configuration options in hsvargplvm_init.m. The way this works, is that
%    you just need to overwrite the corresponding workspace variables.
%    e.g. if in hsvargplvm_init.m you see a field "fixInducing", you can
%    overwrite this field by just calling this demo as:
%    >> fixInducing = true; demHsvargplvmClassification
%   3. If the field you're looking for is not in hsvargplvm_init.m, then
%   check (in this order) svargplvm_init.m and vargplvm_init.m, again
%   overwritting the configuration by specifying the variable to exist, as
%   above.
%
% SEEALSO: demHsvargplvmClassification.m
%
% COPYRIGHT: Andreas Damianou, 2014
% DEEPGP

%% ------ CONFIGURING THE DEEP GP
%--- Mandatory configurations
if ~exist('Ytr', 'var'), error('You need to specify your outputs in Ytr{1}=...'); end
if ~exist('inpX', 'var'), error('You need to specify your inputs in inpX=...'); end

%--- Optional configurations: Whatever configuration variable is not already set (ie does not exist
% as a variable in the workspace) is set to a default value.
if ~exist('experimentNo'), experimentNo = 404; end
if ~exist('K'), K = 30; end
if ~exist('Q'), Q = 6; end
if ~exist('baseKern'), baseKern = 'rbfardjit'; end % {'rbfard2','white','bias'}; end
% This is called "dynamics" and "time" for historical reasons.. It actually refers to a coupling GP in the uppermost level
if ~exist('dynamicsConstrainType'), dynamicsConstrainType = {'time'}; end
stackedOpt = [];
if exist('stackedInitVardistIters', 'var'), stackedOpt.stackedInitVardistIters=stackedInitVardistIters; end
if exist('stackedInitIters', 'var'), stackedOpt.stackedInitIters=stackedInitIters; end
if exist('stackedInitSNR', 'var'), stackedOpt.stackedInitSNR=stackedInitSNR; end
if exist('stackedInitK', 'var'), stackedOpt.stackedInitK=stackedInitK; end
if ~exist('initXOptions', 'var'), initXOptions = []; end

% Initialise script based on the above variables. This returns a struct
% "globalOpt" which contains all configuration options
hsvargplvm_init;

% Automatically calibrate initial variational covariances - better to not change that
globalOpt.vardistCovarsMult = [];

[options, optionsDyn] = hsvargplvmOptions(globalOpt, inpX);

%% ------------- Initialisation and model creation
% Initialise latent spaces, unless the user already did that
if ~(iscell(options.initX) && prod(size(options.initX{1})) > 1)
    [globalOpt, options, optionsDyn, initXOptions] = hsvargplvmRegressionInitX(globalOpt, options, optionsDyn, inpX, Ytr, stackedOpt);
end

% Create the deep GP based on the model options, global options
% (configuration) and options for initialising the latent spaces X
model = hsvargplvmModelCreate(Ytr, options, globalOpt, initXOptions);

% Since we do regression, we need to add a GP on the parent node. This GP
% couples the inputs and is parametrised by options in a struct "optionsDyn".
model = hsvargplvmAddParentPrior(model, globalOpt, optionsDyn);

%-- We have the option to not learn the inducing points and/or fix them to
% the given inputs.
% Learn inducing points? (that's different to fixInducing, ie tie them
% to X's, if learnInducing is false they will stay in their original
% values, ie they won't constitute parameters of the model).
if exist('learnInducing') && ~learnInducing
    model = hsvargplvmPropagateField(model, 'learnInducing', false);
end
%--

if globalOpt.fixInducing && globalOpt.fixInducing
    model = hsvargplvmPropagateField(model, 'fixInducing', true);
    for m=1:model.layer{end}.M % Not implemented yet for parent node
        model.layer{end}.comp{m}.fixInducing = false;
    end
end

%!!!!!!!!!!!!!!!!!!!!!!!!-----------------------
if exist('DEBUG_entropy','var') && DEBUG_entropy
    model.DEBUG_entropy = true;for itmp=1:model.H, model.layer{itmp}.DEBUG_entropy = true; end
end

params = hsvargplvmExtractParam(model);
model = hsvargplvmExpandParam(model, params);
model.globalOpt = globalOpt;
% Computations can be made in parallel, if option is activated
model.parallel = globalOpt.enableParallelism;

fprintf('# Scales after init. latent space:\n')
hsvargplvmShowScales(model,false);
%% OPTIMISATION
[model,modelPruned, modelInitVardist] = hsvargplvmOptimiseModel(model, true, true);

% If you decide to train for further iterations...
% modelOld = model; [model,modelPruned, ~] = hsvargplvmOptimiseModel(model, true, true, [], {0, [100]});


function aedat = RescaleTime(aedat, factor, packetTimeStamps, dataTimeStamps)

%{
Stretches or squeezes time by multiplying all timestamps by a factor.
This affects both data.<dataType>.timeStamp and info.packetTimeStamps,
by default, overridden by the optional flags.
%}

dbstop if error

if ~exist('packetTimeStamps', 'var') || packetTimeStamps

    if ~isfield(aedat, 'info') || ~isfield(aedat.info, 'packetTimeStamps')
        disp('No packet timestamps found')
    else
        aedat.info.packetTimeStamps = uint64(double(aedat.info.packetTimeStamps * factor));
    end
end

if ~exist('dataTimeStamps', 'var') || dataTimeStamps

    if ~isfield(aedat, 'data')
        disp('No data found')
    else

        % Special
        if isfield(aedat.data, 'special')
            aedat.data.special.timeStamp = uint64(double(aedat.data.special.timeStamp * factor));
        end

        % Polarity
        if isfield(aedat.data, 'polarity')
            aedat.data.polarity.timeStamp = uint64(double(aedat.data.polarity.timeStamp * factor));
        end

        % Frames
        % This assumes that timestamps have been simplified to aedat2 standard, if
        % they came from aedat3 file
        if isfield(aedat.data, 'frame')
            aedat.data.frame.timeStampStart = uint64(double(aedat.data.frame.timeStampStart * factor));
            aedat.data.frame.timeStampEnd = uint64(double(aedat.data.frame.timeStampEnd * factor));
        end

        % Imu6
        if isfield(aedat.data, 'imu6')
            aedat.data.imu6.timeStamp = uint64(double(aedat.data.imu6.timeStamp * factor));
        end

        if isfield(aedat.data, 'sample')
            aedat.data.sample.timeStamp = uint64(double(aedat.data.sample.timeStamp * factor));
        end

        if isfield(aedat.data, 'ear')
            aedat.data.ear.timeStamp = uint64(double(aedat.data.ear.timeStamp * factor));
        end

        if isfield(aedat.data, 'point1D')
            aedat.data.point1D.timeStamp = uint64(double(aedat.data.point1D.timeStamp * factor));
        end

        if isfield(aedat.data, 'point2D')
            aedat.data.point2D.timeStamp = uint64(double(aedat.data.point2D.timeStamp * factor));
        end

        if isfield(aedat.data, 'point3D')
            aedat.data.point3D.timeStamp = uint64(double(aedat.data.point3D.timeStamp * factor));
        end

        aedat = FindFirstAndLastTimeStamps(aedat);

        if isfield(aedat.info, 'packetTimeStamps')
            aedat.info.packetTimeStamps = uint64(double(aedat.info.packetTimeStamps * factor));
        end
    end
end


function output_info=cnn_layer_dagnn_wrapper_forward(input_info, layer, work_info_batch)

run_trn=work_info_batch.ref.run_trn;
group_info=get_current_work_group_idx(work_info_batch);

net=group_info.dag_net;

if input_info.is_group_data
    input_var_names=layer.input_var_names;
    input_num=length(input_var_names);
    input_data=cell(0);
    for v_idx=1:input_num
        one_x=input_info.data_child_groups{v_idx}.x;
        assert(~isempty(one_x));
        input_data=cat(2, input_data, {input_var_names{v_idx}, one_x});
        assert(~isempty(one_x));
    end
else
    assert(length(layer.input_var_names)==1);
    input_var_name=layer.input_var_names{1};
    input_data={input_var_name, input_info.x};
    assert(~isempty(input_info.x));
end

do_bp_run=group_info.net_info.ref.do_bp && run_trn;

if do_bp_run

    net.mode = 'normal' ;
    net.do_forward_trn(input_data);

else

    net.mode = 'test' ;
    net.eval(input_data) ;
end

output_var_names=layer.output_var_names;
output_num=length(output_var_names);
output_var_idxes=zeros(output_num,1);
for o_idx=1:output_num
    output_var_idxes(o_idx)=net.getVarIndex(output_var_names{o_idx});
end
assert(all(output_var_idxes>0));

if layer.use_single_output
    output_x = net.vars(output_var_idxes(end)).value ;

    output_info=[];
    output_info.is_group_data=false;
    output_info.x=output_x;

    assert(~isempty(output_info.x));
else

    output_num=length(output_var_idxes);
    data_child_groups=cell(output_num, 1);
    for o_idx=1:output_num
        data_child_groups{o_idx}.is_group_data=false;
        data_child_groups{o_idx}.x = net.vars(output_var_idxes(o_idx)).value;

        assert(~isempty(data_child_groups{o_idx}.x));
    end

    output_info=[];
    output_info.is_group_data=true;
    output_info.data_child_groups=data_child_groups;
end

output_info=my_init_input_info(output_info);

% do the print here, generate the network graph :

% for resnet:
% input_vars=net.getInputs;
% net.print({input_vars{1}, [400 400 3]}, 'Format', 'dot');

% for cascaded refinenets
% input_vars=net.getInputs;
% net.print({input_vars{1}, [13 13 2048], input_vars{2}, [25 25 1024], input_vars{3}, [50 50 512], input_vars{4}, [100 100 256]}, 'Format', 'dot');

end


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

    % set the initial position in the hdcell network
%     global YAW_HEIGHT_HDC_Y_DIM;
%     global YAW_HEIGHT_HDC_H_DIM;
%     curYawTheta = floor(YAW_HEIGHT_HDC_Y_DIM / 2);  % in 1:36
    curYawTheta = 1;  % in 1:36

%     curHeight = floor(YAW_HEIGHT_HDC_H_DIM / 2);  % in 1:36
    curHeight = 1;  % in 1:36
end


function model = yalmip2sdpt3(interfacedata)
[blk,A,C,b,oldKs]=sedumi2sdpt3(interfacedata.F_struc(:,1),-interfacedata.F_struc(:,2:end),-interfacedata.c,interfacedata.K,interfacedata.options.sdpt3.smallblkdim);
interfacedata.options.sdpt3.printyes=double(interfacedata.options.verbose);
interfacedata.options.sdpt3.expon=interfacedata.options.sdpt3.expon(1);

model.blk = blk;
model.A = A;
model.C = C;
model.b = b;
model.ops = interfacedata.options.sdpt3;


function [D info] = ojw_stereo(images, P, disps, sz, options)
%OJW_STEREO  Global stereo with 2nd-order smoothness prior & occlusion model
%
%   [D info] = ojw_stereo(images, P, disps, sz, options)
%
% Generates a disparity (1/depth) map for the first input image. This
% algorithm implements a "global" stereo algorithm, with asymmetrical
% occlusion modelling, using an alpha-expansion graph cuts style approach,
% but with arbitrary disparity proposals.
%
%IN:
%   images - 1xN cell array of input images, the reference image being
%            images{1}.
%   P - 3x4xN array of projection matrices for the input images, relative
%       to the output image.
%   disps - 1xM list of disparities to sample at.
%   sz - 1x2 vector of output image dimensions: [H W].
%   options - a structure containing the following input parameters:
%       col_thresh - scalar noise parameter for data likelihood.
%       occl_const - scalar occlusion cost.
%       disp_thresh - scalar disparity threshold for smoothness prior.
%       smoothness_kernel - index denoting which smoothness kernel to use.
%                           1: truncated linear; 2: truncated quadratic.
%       lambda_l - scalar smoothness prior weight for cliques crossing
%                  segmentation boundaries.
%       lambda_h - scalar smoothness prior weight for cliques not crossing
%                  segmentation boundaries.
%       seg_params - 1x3 vector of parameters for the mean-shift
%                    over-segmentation of the reference image.
%       visibility - boolean indicating whether to employ the geometrical
%                    visbility contstraint.
%       connect - scalar neighbourhood system of the graph, 4 or 8
%                 connected.
%       max_iters - scalar number of iterations to halt after, if
%                   convergence is not achieved first.
%       converge - scalar percentage decrease in energy per iteration at
%                  which optimization stops.
%       average_over - scalar number of iterations to average over when
%                      checking convergence.
%       contract - scalar number of QPBOP iterations to do.
%       improve - scalar indicating which method to use to label unlabelled
%                 nodes. 0: QPBO-F, 1: QPBOI-F, 2: QPBO-R, 3: QPBO-L,
%                 4: QPBOI-R.
%       independent - boolean indicating whether to use independent, or
%                     merely strongly-connected, regions for improve
%                     methods 2 & 4.
%
%OUT:
%   D - HxW disparity map.
%   info - structure containing other outputs from the algorithm.

% $Id: ojw_stereo.m,v 1.5 2008/11/17 11:27:35 ojw Exp $

% Crude check for a reference image
if max(abs(P([1:6 9])-[1 0 0 0 1 0 1])) > 1e-12
    error('First image must be reference image');
end

% Initialize data arrays
R = images{1}(round(P(8))+(1:sz(1)),round(P(7))+(1:sz(2)),:);
vals.I = images(2:end);
vals.P = permute(P(:,:,2:end), [2 1 3]);
vals.sz = sz;
colors = size(R, 3);
num_in = numel(images);
Rorig = uint8(R);
if colors == 1
    Rorig = repmat(Rorig, [1 1 3]);
end
vals.R = repmat(reshape(single(R), [], colors), [2 1]);
vals.d_min = disps(end);
vals.d_step = disps(1) - vals.d_min;
vals.ndisps = numel(disps);

T = reshape(uint32(1:prod(sz)), sz);
if options.planar
    % Use 2nd order smoothness prior
    SEI = [reshape(T(1:end-2,:), 1, []) reshape(T(:,1:end-2), 1, []); ...
           reshape(T(2:end-1,:), 1, []) reshape(T(:,2:end-1), 1, []); ...
           reshape(T(3:end,:), 1, []) reshape(T(:,3:end), 1, [])];
    if options.connect == 8
        SEI = [SEI [reshape(T(1:end-2,1:end-2), 1, []) reshape(T(3:end,1:end-2), 1, []); ...
                    reshape(T(2:end-1,2:end-1), 1, []) reshape(T(2:end-1,2:end-1), 1, []); ...
                    reshape(T(3:end,3:end), 1, []) reshape(T(1:end-2,3:end), 1, [])]];
    end
else
    % Use 1st order smoothness prior
    SEI = [reshape(T(1:end-1,:), 1, []) reshape(T(:,1:end-1), 1, []); ...
           reshape(T(2:end,:), 1, []) reshape(T(:,2:end), 1, [])];
    if options.connect == 8
        SEI = [SEI [reshape(T(1:end-1,1:end-1), 1, []) reshape(T(2:end,1:end-1), 1, []); ...
                    reshape(T(2:end,2:end), 1, []) reshape(T(1:end-1,2:end), 1, [])]];
    end
end
clear T

% Initialise display
vals.show_output = options.show_output;
if vals.show_output
    vals.show_output = gcf;
    set(0, 'CurrentFigure', vals.show_output);
    subplot('Position', [0 0.5 1/3 0.5]);
    sc(R, [0 255]);
end

% Segment the image using mean shift
info.segment = vgg_segment_ms(Rorig, options.seg_params(1), options.seg_params(2), options.seg_params(3));
% Find smoothness edges which don't cross segmentation boundaries
EW = reshape(~any(diff(int32(info.segment(SEI))), 1), 1, []);
EW = EW * options.lambda_h + ~EW * options.lambda_l;
EW = EW * (num_in / ((options.connect==8) + 1));
EW = reshape(repmat(EW, [4*(1+(options.planar~=0)) 1]), [], 1);

% Set up values for ibr_fuse_depths
vals.visibility = (options.visibility ~= 0) * 1e4;
vals.improve = options.improve;
vals.contract = options.contract;
vals.independent = options.independent;
vals.compress_graph = options.compress_graph;

% Set up our robust kernels
vals.ephoto = @(F) log(2) - log(exp(sum(F .^ 2, 2)*(-1/(options.col_thresh*colors)))+1);
switch options.smoothness_kernel
    case 1
        vals.esmooth = @(F) EW .* min(abs(F), options.disp_thresh);
    case 2
        EW = EW / options.disp_thresh;
        vals.esmooth = @(F) EW .* min(F.^2, options.disp_thresh^2);
    otherwise
        error('Unknown smoothness kernel specified');
end
vals.occl_val = options.occl_const + log(2);
vals.SEI = SEI;
clear T SEI EW Rorig

if nargout > 1
    % Save parameters
    info.params.disp_thresh = options.disp_thresh;
    info.params.col_thresh = options.col_thresh;
    info.params.occl_const = options.occl_const;
    info.params.lambda_l = options.lambda_l;
    info.params.lambda_h = options.lambda_h;
end

if isnumeric(options.proposal_method) && size(options.proposal_method, 1) == 1
    % Use the proposal methods:
    for a = options.proposal_method
        switch a
            case 0
                % Ordered fronto-parallel
                [D info.samedisc_optim] = ojw_stereo_optim(vals, @(n) 3, options);
                info.samedisc_optim.D = D;
            case 1
                % SameUni (random fronto-parallel)
                [D info.sameuni_optim] = ojw_stereo_optim(vals, @(n) 1, options);
                info.sameuni_optim.D = D;
            case 2
                % SegPln (prototypical segment-based stereo proposals)
                [Dproposals info.segpln_gen] = ojw_segpln(images, P, disps, R, options);
                clear R
                Dproposals = @(n) Dproposals(:,:,mod(n-1, size(Dproposals, 3))+1);
                [D info.segpln_optim] = ojw_stereo_optim(vals, Dproposals, options);
                clear Dproposals
                info.segpln_optim.D = D;
            case 3
                % Smooth*
                Dproposals = {info.segpln_optim.D, info.sameuni_optim.D, 2, 2, 2, 2};
                Dproposals = @(n) Dproposals{mod(n-1, 6)+1};
                [D info.smooth_optim] = ojw_stereo_optim(vals, Dproposals, options);
                clear Dproposals
                info.smooth_optim.D = D;
            case 4
                % Smooth
                Dproposals = {D, 2};
                Dproposals = @(n) Dproposals{(n>1)+1};
                [D info.smooth2_optim] = ojw_stereo_optim(vals, Dproposals, options);
                clear Dproposals
                info.smooth2_optim.D = D;
        end
    end
else
    % Input fixed set of proposals
    if isnumeric(options.proposal_method)
        Dproposals = @(n) options.proposal_method(:,:,mod(n-1, size(options.proposal_method, 3))+1);
    else
        Dproposals = options.proposal_method;
    end
    [D info.udprop_optim] = ojw_stereo_optim(vals, Dproposals, options);
    clear Dproposals
    info.udprop_optim.D = D;
end
return


function [cnmfeAnalysisOutput] = computeCnmfeSignalExtraction(inputMovie,varargin)
    % Wrapper function for CNMF-E, update for most recent versions.
    % Biafra Ahanonu
    % started: 2018.10.20 [16:38:24]
    % Building off of demo_large_data_1p.m in CNMF-E github repo
    % Most recent commit tested on: https://github.com/epnev/ca_source_extraction/commit/187bbdbe66bca466b83b81861b5601891a95b8d1
    % https://github.com/epnev/ca_source_extraction/blob/master/demo_script_class.m
    % inputs
        % inputMovie - a string or a cell array of strings pointing to the movies to be analyzed (recommended).
        % numExpectedComponents - number of expected components
    % outputs
        % cnmfAnalysisOutput - structure containing extractedImages and extractedSignals along with input parameters to the algorithm
    % READ BEFORE RUNNING
        % Get CVX from http://cvxr.com/cvx/doc/install.html
        % Run the below commands in Matlab after unzipping
        % cvx_setup
        % cvx_save_prefs (permanently stores settings)

    % changelog
        % 2016.06.20 - updated to keep in line with recent changes to CNMF functions
        % 2019.04.04 [11:07:21] - Updated to add many of the options to the varargin options structure for function for easier access in parent functions
        % 2021.08.08 [19:30:20] - Updated to handle CIAtah v4.0 switch to all functions inside ciapkg package.
    % TODO
        %

    import ciapkg.api.* % import CIAtah functions in ciapkg package API.

    % ========================
    % OVERALL
    % turn on parallel
    options.nonCNMF.parallel = 1;
    % Binary: 1 = run merging algorithms
    options.runMerge = 1;
    % Binary: 1 = remove false positives using CNMF-E algorithm
    options.runRemoveFalsePositives = 1;
    % ===COMPUTATION
    % Float: GB, memory space you allow to use in MATLAB
    options.memory_size_to_use = 32; %
    % Float: GB, memory space you allow to use in MATLAB
    options.memory_size_per_patch = 1.2; % 0.6
    % Int vector: patch size in pixels
    options.patch_dims = [128, 128]; % [64, 64]
    % ===SPATIAL
    % Int: pixel, gaussian width of a gaussian kernel for filtering the data. 0 means no filtering
    options.gSig = 3;
    % Int: pixel, neuron diameter
    options.gSiz = 11;
    % Int: spatial downsampling factor
    options.ssub = 1;
    % Binary: movie has dendrites?
    options.with_dendrites = true;
    % Int: expand kernel for HALS growing (default: 3) and expansion factor of ellipse (default: 3)
    options.updateA_bSiz = 5;
    % Char: hals, hals_thresh, lars, nnls
    options.spatial_algorithm = 'hals_thresh';
    % ===TEMPORAL
    % Int: temporal downsampling factor
    options.tsub = 1;
    % Int: frame rate
    options.Fs = 10;
    % Float: minimum spike size. When the value is negative, the actual threshold is abs(smin)*noise level
    options.deconv_smin = -5;
    % Int: maximum decay time (unit: frame);
    options.max_tau = 100;
    % Int: detrending the slow fluctuation. usually 1 is fine (no detrending)
    options.nk = 3;
    % ===BACKGROUND
    % Char: model of the background {'ring', 'svd'(default), 'nmf'}
    options.bg_model = 'ring';
    % Int: number of background sources for each patch (only be used in SVD and NMF model)
    options.nb = 1;
    % Int: when the ring model used, it is the radius of the ring used in the background model. otherwise, it's just the width of the overlapping area
    options.ring_radius = 18;
    % Int: downsample background for a faster speed
    options.bg_ssub = 1;
    % ===MERGING
    % Float: 0 to 1, thresholds for merging neurons; [spatial overlap ratio, temporal correlation of calcium traces, spike correlation]
    options.merge_thr = 0.65;
    % Char: method for computing neuron distances {'mean', 'max'}
    options.method_dist = 'max';
    % Int: minimum distances between two neurons. it is used together with merge_thr
    options.dmin = 5;
    % Int: merge neurons if their distances are smaller than dmin_only.
    options.dmin_only = 2;
    % Float vector: merge components with highly correlated spatial shapes (corr=0.8) and small temporal correlations (corr=0.1)
    options.merge_thr_spatial = [0.8, 0.4, -inf];
    % ===INITIALIZATION
    % Int: maximum number of neurons per patch. when K=[], take as many as possible.
    options.K = [];
    % Float: minimum local correlation for a seeding pixel
    options.min_corr = 0.8;
    % minimum peak-to-noise ratio for a seeding pixel
    options.min_pnr = 8;
    options.bd = 0;             % number of rows/columns to be ignored in the boundary (mainly for motion corrected data)
    options.use_parallel = true;    % use parallel computation for parallel computing
    options.show_init = true;   % show initialization results
    options.center_psf = true;  % set the value as true when the background fluctuation is large (usually 1p data)
    % set the value as false when the background fluctuation is small (2p)
    % ===Residual
    % Float: 0 to 1, minimum local correlation for initializing a neuron (default: 0.3)
    options.min_corr_res = 0.7;
    % Float: stands for minimum peak-to-noise ratio to look for a cell
    options.min_pnr_res = 6;
    % Char: method for initializing neurons from the residual. 'auto' or 'manual'
    options.seed_method_res = 'auto';
    % Binary: boolean, update noise level for each pixel
    options.update_sn = true;

    % get options
    options = getOptions(options,varargin);
    % ========================
    options

    % if cvx is not in the path, ask user for file
    runCvxSetup();

    % Make sure consistent
    options.bg_ssub = options.ssub;

    %% clear the workspace and select data
    % clear; clc; close all;

    %% choose data
    inputFilename = inputMovie;
    neuron = Sources2D();

    nam = get_fullname(inputFilename);          % this demo data is very small, here we just use it as an example
    nam = neuron.select_data(nam);  %if nam is [], then select data interactively

    % nams = {inputFilename};          % you can put all file names into a cell array; when it's empty, manually select files
    % nams = neuron.select_multiple_files(nams);  %if nam is [], then select data interactively

    %% parameters
    % -------------------------    COMPUTATION    -------------------------  %
    pars_envs = struct('memory_size_to_use', options.memory_size_to_use, ...   % GB, memory space you allow to use in MATLAB
        'memory_size_per_patch', options.memory_size_per_patch, ...   % GB, space for loading data within one patch
        'patch_dims', options.patch_dims);  %GB, patch size
    % pars_envs = struct('memory_size_to_use', 8, ...   % GB, memory space you allow to use in MATLAB
    %     'memory_size_per_patch', 0.5, ...   % GB, space for loading data within one patch
    %     'patch_dims', [64, 64],...  %GB, patch size
    %     'batch_frames', 1000);           % number of frames per batch

    % -------------------------      SPATIAL      -------------------------  %
    gSig = options.gSig;           % pixel, gaussian width of a gaussian kernel for filtering the data. 0 means no filtering
    gSiz = options.gSiz;          % pixel, neuron diameter
    ssub = options.ssub;           % spatial downsampling factor
    with_dendrites = options.with_dendrites;   % with dendrites or not
    if with_dendrites
        % determine the search locations by dilating the current neuron shapes
        updateA_search_method = 'dilate';  %#ok<UNRCH>
        updateA_bSiz = options.updateA_bSiz;
        updateA_dist = neuron.options.dist;
    else
        % determine the search locations by selecting a round area
        updateA_search_method = 'ellipse'; %#ok<UNRCH>
        updateA_dist = options.updateA_bSiz;
        updateA_bSiz = neuron.options.dist;
    end
    spatial_constraints = struct('connected', true, 'circular', false);  % you can include following constraints: 'circular'
    spatial_algorithm = options.spatial_algorithm;

    % -------------------------      TEMPORAL     -------------------------  %
    Fs = options.Fs;             % frame rate
    tsub = options.tsub;           % temporal downsampling factor
    deconv_options = struct('type', 'ar1', ... % model of the calcium traces. {'ar1', 'ar2'}
        'method', 'foopsi', ... % method for running deconvolution {'foopsi', 'constrained', 'thresholded'}
        'smin', options.deconv_smin, ...         % minimum spike size. When the value is negative, the actual threshold is abs(smin)*noise level
        'optimize_pars', true, ...  % optimize AR coefficients
        'optimize_b', true, ...% optimize the baseline);
        'max_tau', options.max_tau);    % maximum decay time (unit: frame);

    nk = 3;             % detrending the slow fluctuation. usually 1 is fine (no detrending)
    % when changed, try some integers smaller than total_frame/(Fs*30)
    detrend_method = 'spline';  % compute the local minimum as an estimation of trend. method for detrending {'spline', 'local_min'}

    % -------------------------     BACKGROUND    -------------------------  %
    bg_model = options.bg_model;  % model of the background {'ring', 'svd'(default), 'nmf'}
    nb = options.nb;             % number of background sources for each patch (only be used in SVD and NMF model)
    ring_radius = options.ring_radius;  % when the ring model used, it is the radius of the ring used in the background model.
    %otherwise, it's just the width of the overlapping area
    num_neighbors = []; % number of neighbors for each neuron
    bg_ssub = options.bg_ssub;        % downsample background for a faster speed

    % -------------------------      MERGING      -------------------------  %
    show_merge = false;  % if true, manually verify the merging step
    merge_thr = options.merge_thr;     % thresholds for merging neurons; [spatial overlap ratio, temporal correlation of calcium traces, spike correlation]
    method_dist = options.method_dist;   % method for computing neuron distances {'mean', 'max'}
    dmin = options.dmin;       % minimum distances between two neurons. it is used together with merge_thr
    dmin_only = options.dmin_only;  % merge neurons if their distances are smaller than dmin_only.
    merge_thr_spatial = options.merge_thr_spatial;  % merge components with highly correlated spatial shapes (corr=0.8) and small temporal correlations (corr=0.1)

    % -------------------------  INITIALIZATION   -------------------------  %
    K = options.K;             % maximum number of neurons per patch. when K=[], take as many as possible.
    min_corr = options.min_corr;     % minimum local correlation for a seeding pixel
    min_pnr = options.min_pnr;       % minimum peak-to-noise ratio for a seeding pixel
    min_pixel = gSig^2;      % minimum number of nonzero pixels for each neuron
    bd = options.bd;             % number of rows/columns to be ignored in the boundary (mainly for motion corrected data)
    frame_range = [];   % when [], uses all frames
    save_initialization = false;    % save the initialization procedure as a video.
    use_parallel = options.use_parallel;    % use parallel computation for parallel computing
    show_init = options.show_init;   % show initialization results
    choose_params = false; % manually choose parameters
    center_psf = options.center_psf;  % set the value as true when the background fluctuation is large (usually 1p data)
    % set the value as false when the background fluctuation is small (2p)

    % -------------------------  Residual   -------------------------  %
    min_corr_res = options.min_corr_res;
    min_pnr_res = options.min_pnr_res;
    seed_method_res = options.seed_method_res;  % method for initializing neurons from the residual
    update_sn = options.update_sn;

    % ----------------------  WITH MANUAL INTERVENTION  --------------------  %
    with_manual_intervention = false;

    % -------------------------  FINAL RESULTS   -------------------------  %
    save_demixed = true;    % save the demixed file or not
    kt = 3;                 % frame intervals

    % -------------------------    UPDATE ALL    -------------------------  %
    neuron.updateParams(...
        'save_intermediate',false,...
        'gSig', gSig, ...       % -------- spatial --------
        'gSiz', gSiz, ...
        'ring_radius', ring_radius, ...
        'ssub', ssub, ...
        'search_method', updateA_search_method, ...
        'bSiz', updateA_bSiz, ...
        'dist', updateA_bSiz, ...
        'spatial_constraints', spatial_constraints, ...
        'spatial_algorithm', spatial_algorithm, ...
        'tsub', tsub, ...                       % -------- temporal --------
        'deconv_options', deconv_options, ...
        'nk', nk, ...
        'detrend_method', detrend_method, ...
        'background_model', bg_model, ...       % -------- background --------
        'nb', nb, ...
        'ring_radius', ring_radius, ...
        'num_neighbors', num_neighbors, ...
        'bg_ssub', bg_ssub, ...
        'merge_thr', merge_thr, ...             % -------- merging ---------
        'dmin', dmin, ...
        'method_dist', method_dist, ...
        'min_corr', min_corr, ...               % ----- initialization -----
        'min_pnr', min_pnr, ...
        'min_pixel', min_pixel, ...
        'bd', bd, ...
        'center_psf', center_psf);
    neuron.Fs = Fs;

    %% distribute data and be ready to run source extraction
    neuron.getReady(pars_envs);
    % neuron.getReady_batch(pars_envs);

    %% initialize neurons from the video data within a selected temporal range
    if choose_params
        % change parameters for optimized initialization
        [gSig, gSiz, ring_radius, min_corr, min_pnr] = neuron.set_parameters();
    end

    [center, Cn, PNR] = neuron.initComponents_parallel(K, frame_range, save_initialization, use_parallel);
    neuron.compactSpatial();
    if show_init
        figure();
        ax_init= axes();
        imagesc(Cn, [0, 1]); colormap gray;
        hold on;
        plot(center(:, 2), center(:, 1), '.r', 'markersize', 10);
    end
    subfxnDisplayState();

    %% estimate the background components
    neuron.update_background_parallel(use_parallel);
    neuron_init = neuron.copy();
    subfxnDisplayState();

    if options.runMerge==1
        %%  merge neurons and update spatial/temporal components
        neuron.merge_neurons_dist_corr(show_merge);
        neuron.merge_high_corr(show_merge, merge_thr_spatial);
        subfxnDisplayState();
    end

    %% update spatial components

    %% pick neurons from the residual
    [center_res, Cn_res, PNR_res] = neuron.initComponents_residual_parallel([], save_initialization, use_parallel, min_corr_res, min_pnr_res, seed_method_res);
    if show_init
        axes(ax_init);
        plot(center_res(:, 2), center_res(:, 1), '.g', 'markersize', 10);
    end
    neuron_init_res = neuron.copy();
    subfxnDisplayState();

    %% udpate spatial&temporal components, delete false positives and merge neurons
    % update spatial
    if update_sn
        neuron.update_spatial_parallel(use_parallel, true);
        udpate_sn = false;
    else
        neuron.update_spatial_parallel(use_parallel);
    end
    subfxnDisplayState();
    if options.runMerge==1
        % merge neurons based on correlations
        neuron.merge_high_corr(show_merge, merge_thr_spatial);
        subfxnDisplayState();
    end

    for m=1:2
        % update temporal
        neuron.update_temporal_parallel(use_parallel);

        if options.runRemoveFalsePositives==1
            % delete bad neurons
            neuron.remove_false_positives();
        end
        subfxnDisplayState();
        if options.runMerge==1
            % merge neurons based on temporal correlation + distances
            neuron.merge_neurons_dist_corr(show_merge);
            subfxnDisplayState();
        end
    end

    %% add a manual intervention and run the whole procedure for a second time
    neuron.options.spatial_algorithm = 'nnls';
    if with_manual_intervention
        show_merge = true;
        neuron.orderROIs('snr');   % order neurons in different ways {'snr', 'decay_time', 'mean', 'circularity'}
        neuron.viewNeurons([], neuron.C_raw);
        if options.runMerge==1
            % merge closeby neurons
            neuron.merge_close_neighbors(true, dmin_only);
        end

        % delete neurons
        tags = neuron.tag_neurons_parallel();  % find neurons with fewer nonzero pixels than min_pixel and silent calcium transients
        ids = find(tags>0);
        if ~isempty(ids)
            neuron.viewNeurons(ids, neuron.C_raw);
        end
        subfxnDisplayState();
    end
    %% run more iterations
    neuron.update_background_parallel(use_parallel);
    neuron.update_spatial_parallel(use_parallel);
    neuron.update_temporal_parallel(use_parallel);
    subfxnDisplayState();

    K = size(neuron.A,2);
    % find neurons with fewer nonzero pixels than min_pixel and silent calcium transients
    tags = neuron.tag_neurons_parallel();

    if options.runRemoveFalsePositives==1
        neuron.remove_false_positives();
        subfxnDisplayState();
    end
    if options.runMerge==1
        neuron.merge_neurons_dist_corr(show_merge);
        neuron.merge_high_corr(show_merge, merge_thr_spatial);
        subfxnDisplayState();
    end

    if K~=size(neuron.A,2)
        neuron.update_spatial_parallel(use_parallel);
        neuron.update_temporal_parallel(use_parallel);
        if options.runRemoveFalsePositives==1
            neuron.remove_false_positives();
        end
        subfxnDisplayState();
    end

    %%
    % Get the folder path string
    [PATHSTR,NAME,EXT] = fileparts(inputFilename);
    [~,folderName,~] = fileparts(PATHSTR);

    results = neuron.obj2struct();
    cnmfeAnalysisOutput.success = 1;
    cnmfeAnalysisOutput.params = results.options;
    cnmfeAnalysisOutput.inputOptions = options;
    cnmfeAnalysisOutput.movieList = inputFilename;
    cnmfeAnalysisOutput.extractedImages = reshape(full(results.A),[neuron.options.d1 neuron.options.d2 size(results.C,1)]);
    % cnmfeAnalysisOutput.extractedImages = reshape(full(results.A),[size(results.P.sn) size(results.C,1)]);
    cnmfeAnalysisOutput.extractedSignals = results.C;
    cnmfeAnalysisOutput.extractedSignalsEst = results.C_raw;
    cnmfeAnalysisOutput.extractedPeaks = results.S;
    cnmfeAnalysisOutput.Cn = results.Cn;
    cnmfeAnalysisOutput.P = results.P;
    % save([PATHSTR filesep folderName '_cnmfeAnalysis.mat'],'cnmfeAnalysisOutput');

    % cnmfAnalysisOutput = cnmfeAnalysisOutput;
    % save([PATHSTR filesep folderName '_cnmfAnalysis.mat'],'cnmfAnalysisOutput');

    %% save the workspace for future analysis
    neuron.orderROIs('snr');
    try
        cnmfe_path = neuron.save_workspace();
    catch err
        display(repmat('@',1,7))
        disp(getReport(err,'extended','hyperlinks','on'));
        display(repmat('@',1,7))
    end
    %% show neuron contours
    % Coor = neuron.show_contours(0.6);

    %% create a video for displaying the
    % amp_ac = 140;
    % range_ac = 5+[0, amp_ac];
    % multi_factor = 10;
    % range_Y = 1300+[0, amp_ac*multi_factor];

    % avi_filename = neuron.show_demixed_video(save_demixed, kt, [], amp_ac, range_ac, range_Y, multi_factor);

    %% save neurons shapes
    % neuron.save_neurons();
    function subfxnDisplayState()
        disp(['A (space):' num2str(size(neuron.A)) ' | C (time): ' num2str(size(neuron.C)) ' | b (background): ' num2str(size(neuron.b))])
    end
end


function gX = whitefixedKernGradX(kern, X, X2)

% WHITEFIXEDKERNGRADX Gradient of WHITEFIXED kernel with respect to a point x.
% FORMAT
% DESC computes the gradient of the fixed parameter white noise
% kernel with respect to the input positions.
% ARG kern : kernel structure for which gradients are being
% computed.
% ARG x : locations against which gradients are being computed.
% RETURN g : the returned gradients. The gradients are returned in
% a matrix which is numData x numInputs x numData. Where numData is
% the number of data points and numInputs is the number of input
% dimensions in X.
%
% FORMAT
% DESC computes the gradident of the fixed parameter white noise
% kernel with respect to the input positions where both the row
% positions and column positions are provided separately.
% ARG kern : kernel structure for which gradients are being
% computed.
% ARG x1 : row locations against which gradients are being computed.
% ARG x2 : column locations against which gradients are being computed.
% RETURN g : the returned gradients. The gradients are returned in
% a matrix which is numData2 x numInputs x numData1. Where numData1 is
% the number of data points in X1, numData2 is the number of data
% points in X2 and numInputs is the number of input
% dimensions in X.
%
% SEEALSO whitefixedKernParamInit, kernGradX, whitefixedKernDiagGradX
%
% COPYRIGHT : Nathaniel J. King, 2006

% KERN

gX = zeros(size(X2, 1), size(X2, 2), size(X, 1));


% batch
totaltime = tic; %#ok<NASGU>
isFullData = 1;
data_masterdir = GetCurrentDataDir();

M_stimrange = GetStimRange();

range_fish =  8:18; % range_fish = GetFishRange();

%% custom params here:
% numK1 = 20;
masterthres = 0.7;

%%
M_regthres = {0.7,0.5};
M_place = {1,2,3,1,4,5,6,7};
M_stimname = {'4x4','PT','OMR','defS','Spt','DF','Lm','Dot'};
%%
for i_count = 1,%%%%%%%%%
    masterthres = M_regthres{i_count};
%     clusParams = struct('merge',masterthres,'cap',masterthres,'reg1',masterthres,...
%         'reg2',masterthres,'minSize',10,'k1',numK1);

    for i_stimrange = 1:8,
        if i_stimrange == 1,
            M_stimrange = GetStimRange('5');
        elseif i_stimrange == 2,
            M_stimrange = GetStimRange('P');
        elseif i_stimrange == 3,
            M_stimrange = GetStimRange('O');
        elseif i_stimrange == 4,
            M_stimrange = GetStimRange('M');
        elseif i_stimrange == 5,
            M_stimrange = GetStimRange('S');
        elseif i_stimrange == 6,
            M_stimrange = GetStimRange('D');
        elseif i_stimrange == 7,
            M_stimrange = GetStimRange('L');
        elseif i_stimrange == 8,
            M_stimrange = GetStimRange('Y');
        end

        for i = 1:length(range_fish),
            i_fish = range_fish(i);
            disp(i_fish);

            % check this loop
            stimrange = M_stimrange{i_fish};
            if isempty(stimrange),
                continue;
            end

            % Load fish
            LoadFullFish(hfig,i_fish,isFullData);

            %% 1.
            % setup
            absIX = getappdata(hfig,'absIX');

            i_ClusGroup = 2;
            i_Cluster = 1;

            % Load cluster data
            [cIX_load,gIX] = LoadCluster_Direct(i_fish,i_ClusGroup,i_Cluster,absIX);

            %% partitions for CV
            timelists = getappdata(hfig,'timelists');
            timelists_names = getappdata(hfig,'timelists_names');
            periods = getappdata(hfig,'periods');

            M_stim = M_stimrange{i_fish};

            timelistsCV_raw = cell(length(M_stim),2);
            timelistsCV = cell(1,2);

            for k_stim = 1:length(M_stim), % :3
                i_stim = M_stim(k_stim);
                TL = timelists{i_stim};
                period = periods(i_stim);
                nrep = size(TL,2)/periods(i_stim); % integer
                n = floor(nrep/2);
                if n>0,
                    timelistsCV_raw{k_stim,1} = TL(1:n*period);
                    timelistsCV_raw{k_stim,2} = TL(1+n*period:2*n*period);% before 12/5/16: TL(1+n*period):TL(2*n*period);
                else % for spont, only one period
                    halfperiod = floor(period/2);
                    timelistsCV_raw{k_stim,1} = TL(1:halfperiod);
                    timelistsCV_raw{k_stim,2} = TL(1+halfperiod:2*halfperiod);
                end
            end
            timelistsCV{1} = horzcat(timelistsCV_raw{:,1});
            timelistsCV{2} = horzcat(timelistsCV_raw{:,2});
            assert(length(timelistsCV{1})==length(timelistsCV{2}));

            %%
            for k = 1:2,% CV halves
                tIX = timelistsCV{k};
                M = GetTimeIndexedData_Default_Direct(hfig,cIX_load,tIX);
                M_0 = GetTimeIndexedData_Default_Direct(hfig,[],tIX,'isAllCells');

                % ------custom code here---------
                isWkmeans = true;
                isMakeFoxels = true;

                [cIX,gIX] = AutoClustering(cIX_load,gIX,M_0,cIX_load,isWkmeans,[],...
                    isMakeFoxels,masterthres);

                % save cluster
                name = ['Auto_',M_stimname{i_stimrange},'_M',num2str(masterthres),'_CV',num2str(k)];
                clusgroupID = 3+k; % 4 and 5
                clusIDoverride = M_place{i_stimrange};
                SaveCluster_Direct(cIX,gIX,absIX,i_fish,name,clusgroupID,clusIDoverride);
            end
        end
    end
end
SaveVARwithBackup();
totaltime = toc;
disp(totaltime);


function [TorF, vstr, rdate] = have_feature_ktrlink()
%HAVE_FEATURE_KTRLINK  Detect availability/version info for KTRLINK
%
%   Feature detection function implementing 'ktrlink' tag for HAVE_FEATURE
%   to detect availability/version of Artelys Knitro prior to version 9.0.0,
%   which required the MATLAB Optimization Toolbox.
%
%   See also HAVE_FEATURE, HAVE_FEATURE_KNITRO, KTRLINK.

%   MP-Opt-Model
%   Copyright (c) 2004-2020, Power Systems Engineering Research Center (PSERC)
%   by Ray Zimmerman, PSERC Cornell
%
%   This file is part of MP-Opt-Model.
%   Covered by the 3-clause BSD License (see LICENSE file for details).
%   See https://github.com/MATPOWER/mp-opt-model for more info.

%% ktrlink for pre-Knitro 9.0, requires Optim Toolbox
TorF = exist('ktrlink', 'file');
vstr = '';
rdate = '';
if TorF
    try
        str = evalc(['[x fval] = ktrlink(@(x)1,1);']);
    end
    TorF = exist('fval', 'var') && fval == 1;
    if TorF
        pat = 'KNITRO ([^\s]+)\n|Knitro ([^\s]+)\n';
        [s,e,tE,m,t] = regexp(str, pat);
        if ~isempty(t)
            vstr = t{1}{1};
        end
    end
end


function show_mov(in, in2)
    % ZMAP script show_map.m. Creates Dialog boxes for Z-map calculation
    % does the calculation and makes displays the map
    % stefan wiemer 11/94
    %
    % make dialog interface and call maxzlta
    %
    % turned into function by Celso G Reyes 2017

    ZG=ZmapGlobal.Data; % used by get_zmap_globals

    % Input Rubberband
    %
    report_this_filefun();

    if in2 ~= 'calma'

        %initial values
        nustep = 10;
        ZG.compare_window_dur_v3 = years(1.5);
        it = t0b +1;
        figure(mess);
        clf
        set(gca,'visible','off')
        set(gcf,'Units','pixel','NumberTitle','off','Name','Input Parameters');

        set(gcf,'pos',[ ZG.welcome_pos, ZG.welcome_len +[200, -50]]);

        % creates a dialog box to input some parameters
        %

        inp2_field=uicontrol('Style','edit',...
            'Position',[.80 .80 .18 .15],...
            'Units','normalized','String',num2str(nustep),...
            'callback',@callbackfun_001);

        txt2 = text(...
            'Position',[0. 0.9 0 ],...
            'FontWeight','bold',...
            'FontSize',ZmapGlobal.Data.fontsz.m ,...
            'String','Please input Number of Frames:');

        if in == 'rub' | in == 'lta'

            txt3 = text(...
                'Position',[0. 0.65 0 ],...
                'FontWeight','bold',...
                'FontSize',ZmapGlobal.Data.fontsz.m ,...
                'String','Please input window length in years (e.g. 1.5):');
            inp3_field=uicontrol('Style','edit',...
                'Position',[.80 .575 .18 .15],...
                'Units','normalized','String',num2str(years(ZG.compare_window_dur)),...
                'callback',@callbackfun_002);

        end   % if in = rub

        close_button=uicontrol('Style','Pushbutton',...
            'Position', [.60 .05 .15 .15 ],...
            'Units','normalized','Callback',@(~,~)close(),'String','Cancel');

        go_button=uicontrol('Style','Pushbutton',...
            'Position',[.25 .05 .15 .15 ],...
            'Units','normalized',...
            'callback',@callbackfun_003,...
            'String','Go');

        set(gcf,'visible','on');watchoff

        % do the calculations:
        %

    else     % if in2 ~=calma

        % check if time are with limits
        %

        % initial parameter
        winlen_days = ZG.compare_window_dur/ZG.bin_dur;
        ti = (it -t0b)/days(ZG.bin_dur);
        var1 = zeros(1,ncu);
        var2 = zeros(1,ncu);
        mean1 = zeros(1,ncu);
        mean2 = zeros(1,ncu);
        as = zeros(1,ncu);
        [len, ncu] = size(cumuall); len = len-2;
        len = len -2;
        step = len/nustep;

        % loop over all frames

        j = 0;
        figure
        rect = [0.10 0.30 0.55 0.50 ];
        rect1 = rect;
        axes('position',rect1)
        axis('off')
        m = moviein(length(1:step:len-winlen_days));
        for ti = winlen_days:step:len-winlen_days
            j = j+1;
            var1 = zeros(1,ncu);
            var2 = zeros(1,ncu);
            mean1 = zeros(1,ncu);
            mean2 = zeros(1,ncu);
            as = zeros(1,ncu);

            % loop over all grid points for percent
            %
            %
            if in =='per'

                for i = 1:ncu
                    mean1(i) = mean(cumuall(1:ti,i));
                    mean2(i) = mean(cumuall(ti:len,i));
                end    %for i
                as = -((mean1-mean2)./mean1)*100;

                strib = 'Change in Percent';
                stri2 = ['ti=' num2str(ti*days(ZG.bin_dur) + t0b)  ];

            end  % if in = = per

            % loop over all point for rubber band
            %
            if in =='rub'

                for i = 1:ncu
                    mean1(i) = mean(cumuall(1:ti,i));
                    mean2(i) = mean(cumuall(ti+1:ti+winlen_days,i));
                    var1(i) = cov(cumuall(1:ti,i));
                    var2(i) = cov(cumuall(ti+1:ti+winlen_days,i));
                end %  for i ;
                as = (mean1 - mean2)./(sqrt(var1/ti+var2/winlen_days));

            end % if in = rub

            % make the AST function map
            if in =='ast'
                for i = 1:ncu
                    mean1(i) = mean(cumuall(1:ti,i));
                    var1(i) = cov(cumuall(1:ti,i));
                    mean2(i) = mean(cumuall(ti+1:len,i));
                    var2(i) = cov(cumuall(ti+1:len,i));
                end    %for i
                as = (mean1 - mean2)./(sqrt(var1/ti+var2/(len-ti)));
            end % if in = ast

            if in =='lta'
                disp('Calculate LTA')
                %cu = [cumuall(1:ti-1,:) ; cumuall(ti+winlen_days+1:len,:)];
                mean1 = mean([cumuall(1:ti-1,:) ; cumuall(ti+winlen_days+1:len,:)]);
                mean2 = mean(cumuall(ti:ti+winlen_days,:));
                for i = 1:ncu
                    var1(i) = cov([cumuall(1:ti-1,i) ; cumuall(ti+winlen_days+1:len,i)]);
                    var2(i) = cov(cumuall(ti:ti+winlen_days,i));
                end     % for i
                as = (mean1 - mean2)./(sqrt(var1/(len-winlen_days)+var2/winlen_days));
            end % if in = lta

            normlap1=nan(length(tmpgri(:,1)),1)
            normlap2=nan(length(tmpgri(:,1)),1)
            normlap2(ll)= as(:);
            %construct a matrix for the color plot
            valueMap=reshape(normlap2,length(yvect),length(xvect));

            %plot imge
            % set values gretaer ZG.tresh_km = nan
            %
            re4 = valueMap;
            [len, ncu] = size(cumuall);
            [n1, n2] = size(cumuall);
            s = cumuall(n1,:);
            normlap2(ll)= s(:);
            r=reshape(normlap2,length(yvect),length(xvect));
            re4(r > ZG.tresh_km) = nan;

            orient landscape
            set(gcf,'PaperPosition',[ 0.1 0.1 8 6])
            axes('position',rect1)
            set(gca,'NextPlot','add')
            pco1 = pcolor(gx,gy,re4);
            caxis([ZG.minc ZG.maxc]);
            axis([ s2_west s1_east s4_south s3_north])
            set(gca,'NextPlot','add')
            %overlay
            if in == 'ast'
                tx2 = text(0.07,0.85 ,['AS; t=' num2str(ti*days(ZG.bin_dur)+t0b)  ] ,...
                    'Units','Norm','FontSize',ZmapGlobal.Data.fontsz.m,'Color','k','FontWeight','bold');
            end

            if in == 'lta'
                tx2 = text(0.07,0.85 ,['LTA; t=' num2str(ti*days(ZG.bin_dur)+t0b)  ] ,...
                    'Units','Norm','FontSize',ZmapGlobal.Data.fontsz.m,'Color','k','FontWeight','bold');
            end

            if in == 'rub'
                tx2 = text(0.07,0.85 ,['RUB; t=' num2str(ti*days(ZG.bin_dur)+t0b)  ] ,...
                    'Units','Norm','FontSize',ZmapGlobal.Data.fontsz.m,'Color','k','FontWeight','bold');
            end

            set(gca,'FontSize',ZmapGlobal.Data.fontsz.m,'FontWeight','bold',...
                'FontWeight','bold','LineWidth',1.5,...
                'Box','on','SortMethod','childorder')

            shading interp
            has = gca;
            disp('now getting frame...')
            m(:,j) = getframe(has);
            delete(gca);
            delete(gca);
            delete(gca)
            fs_m = get(gcf,'pos');

        end  % loop over frames

        close(gcf)

        showmovi
    end   % if calma ~| in2

    function callbackfun_001(mysrc,myevt)

        callback_tracker(mysrc,myevt,mfilename('fullpath'));
        nustep=str2double(inp2_field.String);
        inp2_field.String=num2str(nustep);
    end

    function callbackfun_002(mysrc,myevt)

        callback_tracker(mysrc,myevt,mfilename('fullpath'));
        ZG.compare_window_dur=years(str2double(mysrc.String));
    end

    function callbackfun_003(mysrc,myevt)

        callback_tracker(mysrc,myevt,mfilename('fullpath'));
        nustep=str2num(inp2_field.String);
        ZG.compare_window_dur=years(str2num(inp3_field.String));
        watchon;
        drawnow;
        in2 = 'calma';
        fixaxmo;
    end

end


function model = ivmEpUpdateM(model, index)

% IVMEPUPDATEM Update matrix M, L, varSigma and mu for EP.
% FORMAT
% DESC performs an EP update on the IVM model's represenations for
% a given point.
% ARG model : the mode for which the update will be done.
% ARG index : the index of the point for which the update will take
% place.
%
% SEEALSO : ivmEpUpdatePoint, ivmDowndateSites
%
% COPYRIGHT : Neil D. Lawrence, 2006

% IVM

d = length(model.I);
k = find(model.I == index);
if k == d % This point has just been included so EP update is irrelevant.
  return;
end
kvector = model.kern.Kstore(:, k);
for c = 1:length(model.Sigma)
  % Compute the kth row of  Sigma
  a = model.Sigma(c).M(:, index);
  s = kvector' - a'*model.Sigma(c).M;

  v = model.Sigma(c).Linv(k:end, k);
  sLambda_k = rocholhFactorise(v);

  % Update M
  model.Sigma(c).M(k:end, :) = ...
      rocholForeSub(sLambda_k, ...
		    model.Sigma(c).M(k:end, :));
  model.Sigma(c).M(k:end-1) = model.Sigma(c).M(k+1:end);

  % Update L
  t2 = model.Sigma(c).Linv(k, 1:k);
  slambda_11 = sLambda_k.u(1)*sLambda_k.v(1);
  slambda_21 = sLambda_k.v*sLambda_k.u(1);
  slambda_21(1) = [];
  sLambda_22 = sLambda_k;
  sLambda_22.s(1) = [];
  sLambda_22.u(1) = [];
  sLambda_22.v(1) = [];
  sLambda_22.n = sLambda_22.n-1;
  T3prime =  rocholForeSub(sLambda_22, model.Sigma(c).Linv(k+1:end, : ...
                                                    ));
  T3prime(:, 1:k) = T3prime(:, 1:k) ...
      - rocholForeSub(sLambda_22, slambda_21*1/slambda_11)*t2;
  v = T3prime(:, k+1:end)\T3prime(:, k);
  sVtilde = rocholFactorise(v);
  V = rocholTransMultiply(sVtilde, T3prime(:, k+1:end)')';
  T33inv = rocholTransMultiply(sLambda_22, model.Sigma(c).L(k+1:end, ...
                                                    k+1:end)')';
  invV = rocholForeSub(sVtilde, T33inv);
  model.Sigma(c).Linv(k:end-1, 1:end-1) = [T3prime(:, 1:k-1) V];
  model.Sigma(c).L(k:end-1, 1:end-1) = [-invV*T3prime(:, 1:k-1)* ...
                      model.Sigma(c).L(1:k-1, 1:k-1) invV];
  %/~
  oldVarSigma = model.varSigma;
  %~/
  model.varSigma(:, c) = model.varSigma(:, c) + ((model.nu(index, c)*s).*s)';
  %/~
  if any(model.varSigma(:, c)<0)
    warning('Variance less than zero')
  end
  %~/
  model.mu(:, c) = model.mu(:, c) + model.g(index, c)*s';

end
if length(model.Sigma)==1 & size(model.y, 2)>1
  for c = 2:size(model.y, 2)
    model.varSigma(:, c) = model.varSigma(:, c) ...
        - ((model.nu(index, c)*s).*s)';
    model.mu(:, c) = model.mu(:, c) + model.g(index, c)*s';
    %/~
    if any(model.varSigma(:, c)<0)
      warning('Variance less than zero')
    end
    %~/
  end
end

%model = ivmDowndateSites(model, index);
%model.J = [model.J index];

% Ensure nu and g now accurately reflect mu and varsigma.
model = ivmUpdateNuG(model, index);
% Update the site parameter.
model = ivmUpdateSites(model, index);
d = model.d;

% Compute the values of M for the new point
for c = 1:length(model.Sigma)
  a = model.Sigma(c).M(1:end-1, index);
  s = kvector' - a'*model.Sigma(c).M(1:end-1, ...
                                                    :);
  lValInv = sqrt(model.nu(index, c));
  %/~
  % If Nu is so low then the included data-point isn't really useful.
  if lValInv < 1e-16
    warning(['Square root of nu is ' num2str(lValInv)])
  end
  %~/
  model.Sigma(c).M(end, :) = lValInv*s;
  ainv = (-a*lValInv)'/tril(model.Sigma(c).L(1:end-1, 1:end-1));
  model.Sigma(c).L(end, :) = [a' 1/lValInv];
  model.Sigma(c).Linv(end, :) = [ainv lValInv];
  % make sure Matlab knows they are lower triangular.
  model.Sigma(c).L = tril(model.Sigma(c).L);
  model.Sigma(c).Linv = tril(model.Sigma(c).Linv);
  %/~
  oldVarSigma = model.varSigma(:, c);
  if any(model.varSigma(:, c)<0)
    warning('Variance less than zero')
  end
  %~/
  model.varSigma(:, c) = model.varSigma(:, c) - ((model.nu(index, c)*s).*s)';
  %/~
  if any(model.varSigma(:, c)<0)
    warning('Variance less than zero')
  end
  %~/
  model.mu(:, c) = model.mu(:, c) + model.g(index, c)*s';
end
if length(model.Sigma)==1 & size(model.y, 2)>1
  for c = 2:size(model.y, 2)
    model.varSigma(:, c) = model.varSigma(:, c) ...
        - ((model.nu(index, c)*s).*s)';
    model.mu(:, c) = model.mu(:, c) + model.g(index, c)*s';
    %/~
    if any(model.varSigma(:, c)<0)
      warning('Variance less than zero')
    end
    %~/
  end
end
% Swap the columns of the kernel matrix about.
model.kern.Kstore(:, k:end-1) = model.kern.Kstore(:, k+1:end);
model.kern.Kstore(:, end) = kvector;

% Move point to end of active set.
model.I(k:end-1) = model.I(k+1:end);
model.I(end) = index;


%% Load the data into MATLAB from a binary log file
% Usage: >> [datapoints, numpoints] = readdata('datafile.log')
% Header information format:
%           String "MWLOGV##"
%           Time/Date 4 bytes (time())
%           Number of Signals per record Logged 1 bytes (256 max)
%           Data Type of Signals Logged  1 bytes (1-10)
%           Number of bytes per record 2 (65535 max)
% Plot Data Example: plot([1:numpoints], datapoints(1,:), [1:numpoints], datapoints(2,:))
% MathWorks Pilot Engineering 2015
% Steve Kuznicki
function [datapts, numpts] = px4_read_binary_file(dataFile)
%%
datapts = 0;
numpts = 0;

if nargin == 0
    dataFile = 'data.bin';
end

fid = fopen(dataFile, 'r');
% load the header information
hdrToken = fread(fid, 8, 'char');
if strncmp(char(hdrToken),'MWLOGV',6) == true
    logTime = uint32(fread(fid, 1, 'uint32'));
    numflds = double(fread(fid, 1, 'uint8'));
    typefld = uint8(fread(fid, 1, 'uint8'));
    recSize = uint16(fread(fid, 1, 'uint16'));
    fieldTypeStr = get_elem_type(typefld);
    datapts = fread(fid, double([numflds, Inf]), fieldTypeStr);
    fclose(fid);
    numpts = size(datapts,2);
end

end

%% get the element type string
function [dtypeStr] = get_elem_type(dtype)
    switch(dtype)
        case 1
            dtypeStr = 'double';
        case 2
            dtypeStr = 'single';
        case 3
            dtypeStr = 'int32';
        case 4
            dtypeStr = 'uint32';
        case 5
            dtypeStr = 'int16';
        case 6
            dtypeStr = 'uint16';
        case 7
            dtypeStr = 'int8';
        case 8
            dtypeStr = 'uint8';
        case 9
            dtypeStr = 'logical';
        case 10
            dtypeStr = 'embedded.fi';
    end
end


classdef m_45_prms_18p_7s < MARRMoT_model
% Class for hydrologic conceptual model: PRMS

% Copyright (C) 2019, 2021 Wouter J.M. Knoben, Luca Trotter
% This file is part of the Modular Assessment of Rainfall-Runoff Models
% Toolbox (MARRMoT).
% MARRMoT is a free software (GNU GPL v3) and distributed WITHOUT ANY
% WARRANTY. See <https://www.gnu.org/licenses/> for details.

% Model reference
% Leavesley, G. H., R. Lichty, B. Troutman, and L. Saindon (1983),
% Precipitation-Runo Modeling System: User's Manual. U.S. Geological
% Survey, Water-Resources Investigations Report 83-4238, 207
%
% Markstrom, S. L., S. Regan, L. E. Hay, R. J. Viger, R. M. T. Webb, R. A.
% Payn, and J. H. LaFontaine (2015), PRMS-IV, the Precipitation-Runoff
% Modeling System, Version 4. In U.S. Geological Survey Techniques and
% Methods, book 6, chap. B7, 158. doi: http://dx.doi.org/10.3133/tm6B7

    properties
        % model-specific attributes
    end
    methods

        % creator method
        function obj = m_45_prms_18p_7s()
            obj.numStores = 7;                                             % number of model stores
            obj.numFluxes = 25;                                            % number of model fluxes
            obj.numParams = 18;

            obj.JacobPattern  = [1,0,0,0,0,0,0;
                                 0,1,0,0,0,0,0;
                                 1,0,1,0,0,0,0;
                                 1,1,1,1,0,0,0;
                                 1,1,1,1,1,0,0;
                                 1,1,1,1,1,1,0;
                                 1,1,1,1,1,1,1];                           % Jacobian matrix of model store ODEs

            obj.parRanges = [-3,  5;         % tt, Temperature threshold for snowfall and melt [oC]
                              0, 20;         % ddf,  Degree-day factor for snowmelt [mm/oC/d]
                              0,  1;         % alpha, Fraction of rainfall on soil moisture going to interception [-]
                              0,  1;         % beta, Fraction of catchment where rain goes to soil moisture [-]
                              0,  5;         % stor, Maximum interception capcity [mm]
                              0, 50;         % retip, Maximum impervious area storage [mm]
                              0,  1;         % fscn, Fraction of SCX where SCN is located [-]
                              0,  1;         % scx, Maximum contributing fraction area to saturation excess flow [-]
                              0.005, 0.995;  % flz, Fraction of total soil moisture that is the lower zone [-]
                              1, 2000;       % stot, Total soil moisture storage [mm]: REMX+SMAX
                              0, 20;         % cgw, Constant drainage to deep groundwater [mm/d]
                              1, 300;        % resmax, Maximum flow routing reservoir storage (used for scaling only, there is no overflow) [mm]
                              0,  1;         % k1, Groundwater drainage coefficient [d-1]
                              1,  5;         % k2, Groundwater drainage non-linearity [-]
                              0,  1;         % k3, Interflow coefficient 1 [d-1]
                              0,  1;         % k4, Interflow coefficient 2 [mm-1 d-1]
                              0,  1;         % k5, Baseflow coefficient [d-1]
                              0,  1];        % k6, Groundwater sink coefficient [d-1]

            obj.StoreNames = {"S1", "S2" "S3" "S4" "S5" "S6" "S7"};         % Names for the stores
            obj.FluxNames  = {"ps",   "pr",  "pim", "psm", "pby"...
                              "pin",  "ptf", "m",   "mim", "msm"...
                              "sas",  "sro", "inf", "pc",  "excs"...
                              "qres", "sep", "gad", "ras", "bas"...
                              "snk",  "ein", "eim", "ea",  "et"};          % Names for the fluxes

            obj.FluxGroups.Ea = [22 23 24 25];                             % Index or indices of fluxes to add to Actual ET
            obj.FluxGroups.Q  = [11 12 19 20];                             % Index or indices of fluxes to add to Streamflow
            obj.FluxGroups.Sink  = 21;                                     % index of sink fluxes

        end

        % INITialisation function
        function obj = init(obj)
        end

        % MODEL_FUN are the model governing equations in state-space formulation
        function [dS, fluxes] = model_fun(obj, S)
            % parameters
            theta = obj.theta;
            tt      = theta(1);     % Temperature threshold for snowfall and melt [oC]
            ddf     = theta(2);     % Degree-day factor for snowmelt [mm/oC/d]
            alpha   = theta(3);     % Fraction of rainfall on soil moisture going to interception [-]
            beta    = theta(4);     % Fraction of catchment where rain goes to soil moisture [-]
            stor    = theta(5);     % Maximum interception capcity [mm]
            retip   = theta(6);     % Maximum impervious area storage [mm]
            fscn    = theta(7);     % Fraction of SCX where SCN is located [-]
            scx     = theta(8);     % Maximum contributing fraction area to saturation excess flow [-]
            scn     = fscn*scx;     % Minimum contributing fraction area to saturation excess flow [-]
            flz     = theta(9);     % Fraction of total soil moisture that is the lower zone [-]
            stot    = theta(10);    % Total soil moisture storage [mm]: REMX+SMAX
            remx    = (1-flz)*stot; % Maximum upper soil moisture storage [mm]
            smax    = flz*stot;     % Maximum lower soil moisture storage [mm]
            cgw     = theta(11);    % Constant drainage to deep groundwater [mm/d]
            resmax  = theta(12);    % Maximum flow routing reservoir storage (used for scaling only, there is no overflow) [mm]
            k1      = theta(13);    % Groundwater drainage coefficient [d-1]
            k2      = theta(14);    % Groundwater drainage non-linearity [-]
            k3      = theta(15);    % Interflow coefficient 1 [d-1]
            k4      = theta(16);    % Interflow coefficient 2 [mm-1 d-1]
            k5      = theta(17);    % Baseflow coefficient [d-1]
            k6      = theta(18);    % Groundwater sink coefficient [d-1]

            % delta_t
            delta_t = obj.delta_t;

            % stores
            S1 = S(1);
            S2 = S(2);
            S3 = S(3);
            S4 = S(4);
            S5 = S(5);
            S6 = S(6);
            S7 = S(7);

            % climate input
            t = obj.t;                             % this time step
            climate_in = obj.input_climate(t,:);   % climate at this step
            P  = climate_in(1);
            Ep = climate_in(2);
            T  = climate_in(3);

            % fluxes functions
            flux_ps  = snowfall_1(P,T,tt);
            flux_pr  = rainfall_1(P,T,tt);
            flux_pim = split_1(1-beta,flux_pr);
            flux_psm = split_1(beta,flux_pr);
            flux_pby = split_1(1-alpha,flux_psm);
            flux_pin = split_1(alpha,flux_psm);
            flux_ptf = interception_1(flux_pin,S2,stor);
            flux_m   = melt_1(ddf,tt,T,S1,delta_t);
            flux_mim = split_1(1-beta,flux_m);
            flux_msm = split_1(beta,flux_m);
            flux_sas = saturation_1(flux_pim+flux_mim,S3,retip);
            flux_sro = saturation_8(scn,scx,S4,remx,flux_msm+flux_ptf+flux_pby);
            flux_inf = effective_1(flux_msm+flux_ptf+flux_pby,flux_sro);
            flux_pc  = saturation_1(flux_inf,S4,remx);
            flux_excs= saturation_1(flux_pc,S5,smax);
            flux_sep = recharge_7(cgw,flux_excs);
            flux_qres= effective_1(flux_excs,flux_sep);
            flux_gad = recharge_2(k2,S6,resmax,k1);
            flux_ras = interflow_4(k3,k4,S6);
            flux_bas = baseflow_1(k5,S7);
            flux_snk = baseflow_1(k6,S7);
            flux_ein = evap_1(S2,beta*Ep,delta_t);
            flux_eim = evap_1(S3,(1-beta)*Ep,delta_t);
            flux_ea  = evap_7(S4,remx,Ep-flux_ein-flux_eim,delta_t);
            flux_et  = evap_15(Ep-flux_ein-flux_eim-flux_ea,S5,smax,S4,Ep-flux_ein-flux_eim,delta_t);

            % stores ODEs
            dS1 = flux_ps  - flux_m;
            dS2 = flux_pin - flux_ein - flux_ptf;
            dS3 = flux_pim + flux_mim - flux_eim - flux_sas;
            dS4 = flux_inf - flux_ea  - flux_pc;
            dS5 = flux_pc  - flux_et  - flux_excs;
            dS6 = flux_qres- flux_gad - flux_ras;
            dS7 = flux_sep + flux_gad - flux_bas - flux_snk;

            % outputs
            dS = [dS1 dS2 dS3 dS4 dS5 dS6 dS7];
            fluxes = [flux_ps,   flux_pr,  flux_pim, flux_psm, flux_pby...
                      flux_pin,  flux_ptf, flux_m,   flux_mim, flux_msm...
                      flux_sas,  flux_sro, flux_inf, flux_pc,  flux_excs...
                      flux_qres, flux_sep, flux_gad, flux_ras, flux_bas...
                      flux_snk,  flux_ein, flux_eim, flux_ea,  flux_et];
        end

        % STEP runs at the end of every timestep.
        function obj = step(obj)
        end
    end
end


function varargout=ceil(varargin)
%FLOOR (overloaded)

switch class(varargin{1})

    case 'sdpvar' % Overloaded operator for SDPVAR objects. Pass on args and save them.

        x = varargin{1};
        [n,m] = size(x);
        x = reshape(x,n*m,1);
        y = [];
        for i = 1:n*m
            y = [y;yalmip('addextendedvariable',mfilename,extsubsref(x,i))];
        end
        y = reshape(y,n,m);
        varargout{1} = y;

    case 'char' % YALMIP send 'graph' when it wants the epigraph or hypograph
        switch varargin{1}
            case {'milp','graph'}
                % Description using epigraphs
                t = varargin{2};
                X = varargin{3};

                c = intvar(1,1);
                F = (x-1 <= c <= x);

                varargout{1} = F;
                varargout{2} = struct('convexity','milp','monotonicity','milp','definiteness','milp');
                varargout{3} = X;

            otherwise
                error('SDPVAR/SORT called with CHAR argument?');
        end
    otherwise
        error('Strange type on first argument in SDPVAR/SORT');
end


function mrk= convert_markers(mrk_old)

mrk= rmfield(mrk_old, {'pos','fs'});

mrk.time= mrk_old.pos*1000/mrk_old.fs;
mrk.event= struct;
if isfield(mrk_old, 'toe'),
  mrk.event.desc= mrk_old.toe(:);
  mrk= rmfield(mrk, {'toe'});
end

if isfield(mrk, 'indexedByEpochs'),
  mrk= rmfield(mrk, setdiff(mrk.indexedByEpochs, 'time'));
  mrk= rmfield(mrk, 'indexedByEpochs');
  nEvents= length(mrk.time);
  for Fld= mrk_old.indexedByEpochs,
    fld= Fld{1};
    fieldvar= mrk_old.(fld);
    sz= size(fieldvar);
    eventdim= find(sz==nEvents);
    if isempty(eventdim),
      error('no event information found in field %s', fld);
    end
    if length(eventdim)>1,
      error('cannot decide event dimension in field %s', fld);
    end
    if eventdim~=1,
      % permute dimensions to make the first one index events
      dimorder= [eventdim setdiff(1:length(sz), eventdim)];
      fieldvar= permute(fieldvar, dimorder);
    end
    mrk.event= setfield(mrk.event, fld, fieldvar);
  end
end


function [hdr] = read_bucn_nirshdr(filename)

% READ_BUCN_NIRSHDR reads the header information of ASCII-formatted NIRS
% data acquired with the UCL-BIRKBECK machine and postprocessed by the
% Paris group. The first line contains the channel labels and the rest of
% the file contains per line a time sample. The first column specifies the
% time axis.
%
% Use as
%   [hdr] = read_bucn_nirshdr(filename)
%
% See also READ_BUCN_NIRSDATA, READ_BUCN_NIRSEVENT

% Copyright (C) 2011, Jan-Mathijs Schoffelen
%
% This file is part of FieldTrip, see http://www.fieldtriptoolbox.org
% for the documentation and details.
%
%    FieldTrip is free software: you can redistribute it and/or modify
%    it under the terms of the GNU General Public License as published by
%    the Free Software Foundation, either version 3 of the License, or
%    (at your option) any later version.
%
%    FieldTrip is distributed in the hope that it will be useful,
%    but WITHOUT ANY WARRANTY; without even the implied warranty of
%    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
%    GNU General Public License for more details.
%
%    You should have received a copy of the GNU General Public License
%    along with FieldTrip. If not, see <http://www.gnu.org/licenses/>.
%
% $Id: read_bucn_nirshdr.m$

fid = fopen_or_error(filename, 'r');

% read the first line
line1 = textscan(fid, '%[^\n]',1);

% field delimiter can be space or tab
labelspc = textscan(line1{1}{1}, '%[^ ]');
labeltab = textscan(line1{1}{1}, '%[^\t]');

% let tab as a delimiter prevail
if numel(labeltab{1})>1
  label = labeltab{1};
else
  label = labelspc{1};
end
nchan = numel(label);
Fs    = str2num(strtok(strtok(label{1},'#Time.'),'Hz'));

% test whether the channel labels are non-numeric
labelnumber = cellfun(@str2num, label, 'UniformOutput', false);
labelstring = cellfun(@isempty, labelnumber, 'UniformOutput', true);
if ~any(labelstring)
  ft_error('channel labels were not found in the first line of the file');
end

% read the rest
dat = textscan(fid, '%f');
fclose(fid);

dat  = reshape(dat{1}, nchan, []);
nsmp = size(dat,2);

% create the output
hdr          = [];
hdr.Fs       = Fs;
hdr.label    = label;
hdr.nTrials  = 1;
hdr.nSamples = nsmp;
hdr.nSamplesPre = 0;
hdr.nChans   = nchan;
hdr.time     = dat(1,:); % events in the raw event file have both a sample and a time stamp


function x = vec( x )

% VEC   CVX implementation of vec

s = x.size_;
n = prod(s);
if s(1) ~= n,
	x = cvx( [ n, 1 ], x.basis_ );
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.