function msg = mhe_init()

s = 'http://byu.apmonitor.com';
b = 'mhe';

apm(s,b,'clear all');

% load model and data
apm_load(s,b,'model.apm');
csv_load(s,b,'mhe.csv');

% configure MV / CV
apm_info(s,b,'FV','U');
apm_info(s,b,'FV','tau');
apm_info(s,b,'FV','a1');
apm_info(s,b,'FV','a2');
apm_info(s,b,'MV','Q1');
apm_info(s,b,'MV','Q2');
apm_info(s,b,'SV','TH1');
apm_info(s,b,'SV','TH2');
apm_info(s,b,'CV','TC1');
apm_info(s,b,'CV','TC2');

% tune FVs
apm_option(s,b,'U.dmax',1.0);
apm_option(s,b,'U.lower',5);
apm_option(s,b,'U.upper',15);

apm_option(s,b,'tau.dmax',1.0);
apm_option(s,b,'tau.lower',4.0);
apm_option(s,b,'tau.upper',8.0);

apm_option(s,b,'a1.dmax',0.001);
apm_option(s,b,'a1.lower',0.003);
apm_option(s,b,'a1.upper',0.03);

apm_option(s,b,'a2.dmax',0.001);
apm_option(s,b,'a2.lower',0.002);
apm_option(s,b,'a2.upper',0.02);

% turn on FVs as degrees of freedom, later
apm_option(s,b,'U.status',0);
apm_option(s,b,'tau.status',0);
apm_option(s,b,'a1.status',0);
apm_option(s,b,'a2.status',0);

apm_option(s,b,'U.fstatus',0);
apm_option(s,b,'tau.fstatus',0);
apm_option(s,b,'a1.fstatus',0);
apm_option(s,b,'a2.fstatus',0);

% read Q, don't let optimize use MV
apm_option(s,b,'Q1.status',0);
apm_option(s,b,'Q1.fstatus',1);

apm_option(s,b,'Q2.status',0);
apm_option(s,b,'Q2.fstatus',1);

% include CV in objective function
apm_option(s,b,'TC1.status',1);
apm_option(s,b,'TC1.fstatus',1);
%apm_option(s,b,'TC1.meas_gap',0.5);

apm_option(s,b,'TC2.status',1);
apm_option(s,b,'TC2.fstatus',1);
%apm_option(s,b,'TC2.meas_gap',0.5);

% web-viewer option, update every second
apm_option(s,b,'apm.web_plot_freq',3);

% dynamic estimation
apm_option(s,b,'apm.imode',5);
apm_option(s,b,'apm.ev_type',2);
apm_option(s,b,'apm.nodes',3);
apm_option(s,b,'apm.solver',3);
apm_option(s,b,'apm.coldstart',1);

msg = 'initialization complete';

end


function X=brutepersp(X,t,y)

X.basis = [zeros(size(X.basis,1),1) X.basis];
X.lmi_variables = [t y];
[i,j] = sort(X.lmi_variables);
X.basis = X.basis(:,[1 1+j]);
X.lmi_variables = i;
X.conicinfo = [0 0];


classdef (Abstract) math_model_cpf_acc < mp.math_model_cpf
%MP.MATH_MODEL_CPF_ACC  MATPOWER mathematical model for continuation power flow (CPF) problem.
%   ?
%
%   MP.MATH_MODEL_CPF_ACC ... power flow ...
%
%   Properties
%       ? - ?
%
%   Methods
%       ?

%   MATPOWER
%   Copyright (c) 2021-2022, Power Systems Engineering Research Center (PSERC)
%   by Ray Zimmerman, PSERC Cornell
%
%   This file is part of MATPOWER.
%   Covered by the 3-clause BSD License (see LICENSE file for details).
%   See https://matpower.org for more info.

%     properties
%     end

    methods
        %% constructor
        function obj = math_model_cpf_acc()
            obj@mp.math_model_cpf();
            obj.element_classes = { @mp.mme_bus_pf_acc, @mp.mme_gen_pf_ac, ...
                @mp.mme_branch_pf_ac, @mp.mme_load_cpf, @mp.mme_shunt_cpf };
        end
    end     %% methods
end         %% classdef


function [vSel, vM]=misd(mCat)
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
% Example: vMain=misd(mCat)
% Author: van Stiphout, Thomas
% Email: vanstiphout@sed.ethz.ch
% Created: 14. Feb. 2007
% Changed: -
%
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
% Variables:
% mCat              Catalog to be declustered
% iYr1                Starting year (read from mCat)
% iYr2                Ending year (read from mCat)
% fXmeff            Magnitude cutoff
% fRfact             rfact
% fTau0              Tau0 (is equal fTaumin)
% fTaumin          Taumin
% fTaumax          Taumax
% fP1                  P1
% fXk                  xk
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%

% prepare variables
% fTaumin=fTaumin*24*60;
% fTau0=fTaumin;
% fTaumax=fTaumax*24*60;
% sYr1=num2str(floor(min(mCat(:,3))));
% sYr2=num2str(ceil(max(mCat(:,3))));
% sYr1=sYr1(3:4);
% sYr2=sYr2(3:4);
%
% % does catalog contain 12 columns?
% if (size(mCat,2)<12)
%     mTmp=nan(size(mCat,1),(12-size(mCat,2)));
%     mCat=[mCat mTmp];
% end
!rm ~/zmap/src/thomas/decluster/marsan/*.out
!rm ~/zmap/src/thomas/decluster/marsan/misd_input.dat
!rm ~/zmap/src/thomas/decluster/marsan/CORRECT.DAT
% !rm ~/zmap/src/thomas/decluster/marsan/misdMcorr.dat
% export to readalbe format for tmp
export4misd(mCat,'misd_input.dat');
!mv misd_input.dat  ~/zmap/src/thomas/decluster/marsan/.
calc_misdMcorr(mCat,'CORRECT.DAT');
!mv CORRECT.DAT  ~/zmap/src/thomas/decluster/marsan/.
% calc_misdMcorr(mCat,'misdMcorr.dat');
% !mv misdMcorr.dat  ~/zmap/src/thomas/decluster/marsan/.
% save ~/zmap/src/thomas/decluster/marsan/misd_input.dat mCat -ascii

% write input file (input.cmn)
% infile=fopen('input.cmn','w');
% fprintf(infile,'CA.hypo71\n4\n%2s\n%2s\n%3.1f\n%06.3f\n%08.3f\n%010.2f\n%010.2f\n%05.2f\n%05.2f',...
%     sYr1,sYr2,fXmeff,fRfact,fTau0,fTaumin,fTaumax,fP1,fXk);
% fclose(infile);
% run misd algorithm of Marsan2007
sPath=pwd;
cd ~/zmap/src/thomas/decluster/marsan
tic
unix('./misd inputmisd.in');
toc
cd(sPath);
% extract vector with 1 and 0's of events in declustered catalog
% unix(['awk -f ~/zmap/src/thomas/decluster/reasen/clu2list.awk cluster.ano > v.dat ' ]);
% import vector
vM=load('~/zmap/src/thomas/decluster/marsan/W0.out');
vSel=(vM>rand(size(vM,1),1));
% % clean up
% !rm cluster.*


%CALCOPTICALFLOWFARNEBACK  Computes a dense optical flow using the Gunnar Farneback's algorithm
%
%     flow = cv.calcOpticalFlowFarneback(prevImg, nextImg)
%     flow = cv.calcOpticalFlowFarneback(prevImg, nextImg, 'OptionName',optionValue, ...)
%
% ## Input
% * __prevImg__ First 8-bit single-channel input image.
% * __nextImg__ Second input image of the same size and the same type as
%   `prevImg`.
%
% ## Output
% * __flow__ Computed flow image that has the same size as `prevImg` and
%   `single` type (2-channels). Flow for `(x,y)` is stored in the third
%   dimension.
%
% ## Options
% * __InitialFlow__ Initial flow approximation. Not set by default.
% * __PyrScale__ Parameter specifying the image scale (`<1`) to build pyramids
%   for each image. `PyrScale=0.5` means a classical pyramid, where each next
%   layer is twice smaller than the previous one. default 0.5.
% * __Levels__ Number of pyramid layers including the initial image.
%   `Levels=1` means that no extra layers are created and only the original
%   images are used. default 5.
% * __WinSize__ Averaging window size. Larger values increase the algorithm
%   robustness to image noise and give more chances for fast motion detection,
%   but yield more blurred motion field. default 13.
% * __Iterations__ Number of iterations the algorithm does at each pyramid
%   level. default 10.
% * __PolyN__ Size of the pixel neighborhood used to find polynomial expansion
%   in each pixel. Larger values mean that the image will be approximated with
%   smoother surfaces, yielding more robust algorithm and more blurred motion
%   field. Typically, `PolyN` is 5 or 7. default 5.
% * __PolySigma__ Standard deviation of the Gaussian that is used to smooth
%   derivatives used as a basis for the polynomial expansion. For `PolyN=5`,
%   you can set `PolySigma = 1.1`. For `PolyN=7`, a good value would be
%   `PolySigma = 1.5`. default 1.1.
% * __Gaussian__ Use the Gaussian `WinSize x WinSize` filter instead of a box
%   filter of the same size for optical flow estimation. Usually, this option
%   gives z more accurate flow than with a box filter, at the cost of lower
%   speed. Normally, `WinSize` for a Gaussian window should be set to a larger
%   value to achieve the same level of robustness. default false.
%
% The function finds an optical flow for each `prevImg` pixel using the
% [Farneback2003] alorithm so that:
%
%     prevImg(y,x) ~ nextImg(y + flow(y,x,2), x + flow(y,x,1))
%
% ## References
% [Farneback2003]:
% > Gunnar Farneback. "Two-frame motion estimation based on polynomial
% > expansion". In Image Analysis, pages 363-370. Springer, 2003.
%
% See also: cv.FarnebackOpticalFlow, cv.calcOpticalFlowPyrLK, opticalFlowLK,
%  opticalFlowHS, opticalFlowFarneback, vision.OpticalFlow, vision.BlockMatcher
%


function mv = mv_exportAmplitudeMap(mv);
%
% mv = mv_exportAmplitudeMap(mv);
%
% Create multiple parameter maps, with the amplitude for
% each selected condition in a multivoxel UI.
%
%
% ras, 09/2006.
if notDefined('mv'), mv = get(gcf, 'UserData'); end

% get amplitudes for all selected conditions
amps = mv_amps(mv);
nConds = size(amps, 2);
selConds = find(tc_selectedConds(mv));

% initialize a view to get parameters about the
% map volume
fn = sprintf('getSelected%s',mv.roi.viewType);
view = eval(fn);
if isempty(view)
    % no selected view of the proper type -- make a hidden one
    mrGlobals; loadSession; saveFlag = 1;
    fn = sprintf('initHidden%s',roi.viewType); view = eval(fn);
end
mapdims = viewGet(view,'dataSize');
nScans = viewGet(view,'numScans');
scan = mv.params.scans(1);

for c = 1:nConds
    % plug in the values to the map volume:
    mapvol = zeros(mapdims);
    ind = roiIndices(view,mv.coords);
    mapvol(ind) = amps(:,c);

    % save map
    mapName = sprintf('Amplitudes_%s_%s_%s', mv.params.ampType, ...
                       mv.trials.condNames{selConds(c)}, mv.roi.name);
    mapPath = fullfile(dataDir(view),mapName);
    if exist(mapPath,'dir')
        load(mapPath,'map','mapName');
        map{scan} = mapvol;
    else
        map = cell(1, nScans);
    end
    map{scan} = mapvol;
    save(mapPath,'map','mapName');
    fprintf('Saved map %s.\n',mapPath);
end

% plug the map volume into the view
fprintf('Assigning %s data to param map for scan %i\n',mapName,scan);
map = cell(1,nScans);
map{scan} = mapvol;
if ~isequal(view.name,'hidden')
    view = setParameterMap(view,map,mapName);
    refreshScreen(view);
end

% evaluate this in the workspace, so the view
% itself is updated
assignin('base','map',map);
evalin('base',sprintf('%s=setParameterMap(%s,map,''%s'');',...
    view.name,view.name,mapName));

return


% READELP - read electrode locations from an .elp (electrode positions)
%             file as generated, for example, by a Polhemus tracking device
% Usage:
%   >> [eloc, elocnames, X, Y, Z] = readelp(filename);
%
% Inputs:
%   filename - name of the .elp file containing cartesian (XYZ) electrode
%              locations
% Outputs:
%   eloc      - structure containing the names and locations of the channels
%   elocnames - cell array containing the names of the electrodes
%   X,Y,Z     - vectors containing the xyz locations of the electrodes
%
% Author: Arnaud Delorme, CNL / Salk Institute, 28 Feb 2002
%
% Note: ignores comments and the sensor type field
% Note: convert output XYZ locations to polar coordinates using CART2POL
%
% See also: READLOCS, SNAPREAD, FLOATREAD, CART2POL

% Copyright (C) Arnaud Delorme, CNL / Salk Institute, 28 Feb 2002
%
% This file is part of EEGLAB, see http://www.eeglab.org
% for the documentation and details.
%
% Redistribution and use in source and binary forms, with or without
% modification, are permitted provided that the following conditions are met:
%
% 1. Redistributions of source code must retain the above copyright notice,
% this list of conditions and the following disclaimer.
%
% 2. Redistributions in binary form must reproduce the above copyright notice,
% this list of conditions and the following disclaimer in the documentation
% and/or other materials provided with the distribution.
%
% THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
% AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
% IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
% ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
% LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
% CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
% SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
% INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
% CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
% ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
% THE POSSIBILITY OF SUCH DAMAGE.

function [eloc, names, x, y, z] = readelp( filename );

if nargin < 1
	help readelp;
	return;
end

% open file
% ---------
fid = fopen(filename, 'r');
if fid == -1
  disp('Cannot open file'); return;
end

index = 1;
countfid  = 1;
fidlabels = { 'Nz' 'LPA' 'RPA' };

needToReadNumbers = 0;
tmpstr = fgetl(fid);

while 1
    if needToReadNumbers==1 % Has sparsed $N.
        if (~isempty(str2num(tmpstr)))
            tmp = sscanf(tmpstr, '%f');

            eloc(index).X  = tmp(1); x(index) = tmp(1);
            eloc(index).Y  = tmp(2); y(index) = tmp(2);
            eloc(index).Z  = tmp(3); z(index) = tmp(3);
            eloc(index).type = 'EEG';

            index = index + 1;
            needToReadNumbers = 0;
        end
    elseif tmpstr(1) == '%'
        if tmpstr(2) == 'F' % fiducial
            tmp = sscanf(tmpstr(3:end), '%f');

            eloc(index).labels = fidlabels{countfid};
            eloc(index).X  = tmp(1); x(index) = tmp(1);
            eloc(index).Y  = tmp(2); y(index) = tmp(2);
            eloc(index).Z  = tmp(3); z(index) = tmp(3);
            eloc(index).type = 'FID';

            index     = index    + 1;
            countfid  = countfid + 1;

        elseif tmpstr(2) == 'N' % regular channel
            nm = strtok(tmpstr(3:end));
            if ~(strcmp(nm, 'Name') || strcmp(nm, 'Status'))
                eloc(index).labels = nm;
                needToReadNumbers = 1;
            end
        end
    end

    % Get the next line
    tmpstr = fgetl(fid);
    while isempty(tmpstr)
        tmpstr = fgetl(fid);
        if ~ischar(tmpstr) && tmpstr == -1
            break;
        end;
    end

    if ~ischar(tmpstr) && tmpstr == -1
        break;
    end;
end;

names = { eloc.labels };

fclose(fid);    % close the file


function ts = spcalib(varargin)
% function t = spcalib()
% function t = spcalib('auto', n) % autocalibration n time, n=3 by default
% function t = spcalib('reset') % Recover the timing set during the session
% function t = spcalib(newT) % Set the new timing
%
% Return the typical running time of each atomic task (mostly sparse
% access) for the specific computer. Make sure no other program do not run
% at the same time
%
% Author Bruno Luong <brunoluong@yahoo.com>
% Last update: 11-Apil-2009
%              13-Nov-2010, move mexing to build_spidxmex

global TREF;

if nargin>=1
    v1 = varargin{1};
    if isstruct(v1)
        TREF = v1;
    elseif ischar(v1) && ~isempty(strmatch(lower(v1),'auto'))

        ntest = 3;
        if nargin>=2
            v2 = varargin{2};
            if isnumeric(v2) && isscalar(v2) && v2>=1
                ntest = floor(v2);
            end
        end

        % Prompt user to save the customize time
        msg='Compile mexfile get/setspvalmex?';
        ButtonName = questdlg(msg, 'SPcalib', 'Yes', 'No', 'No');
        if strcmp(ButtonName,'Yes')
            try
                build_spidxmex();
            catch
                warning('Could not compile mex file');
            end
        end

        msg='Make sure the computer is not loaded by other applications';
        questdlg(msg, 'SPcalib', 'OK', 'OK');
        drawnow;

        fprintf('Auto calibration in progess, please be patient...\n');

        n=1e5;
        nz=1e6;
        i=ceil(n*rand(1,nz));
        j=ceil(n*rand(1,nz));
        iminmax=min(maxlinind([n n]),n*n);
        ilin=ceil(iminmax*rand(1,nz));
        s=rand(size(i));

        % Allocate time arrays
        tfind=zeros(1,ntest);
        tcreate=zeros(1,ntest);
        treadlin=zeros(1,ntest);
        treadfor=zeros(1,ntest);
        twritefor=zeros(1,ntest);
        tadd=zeros(1,ntest);
        tsetval=zeros(1,ntest);
        tgetval=zeros(1,ntest);
        tinsert=zeros(1,ntest);
        tremove=zeros(1,ntest);
        tismember=zeros(1,ntest);

        for l=1:ntest

            % ismember
            tic
            ismember([i j],[i j],'rows');
            tismember(l)=toc/numel(i);
            fprintf('.');

            % create sparse
            tic
            S=sparse(i,j,s,n,n);
            tcreate(l)=toc/nnz(S);
            fprintf('.')

            % find
            tic
            [I J v]=find(S); %#ok
            tfind(l)=toc/nnz(S);
            fprintf('.');

            % read with linear indexes
            tic
            v=S(ilin); %#ok
            treadlin(l)=toc/numel(ilin);
            fprintf('.');

            % read with for loop
            tic
            nloop=min(length(i),Inf);
            for k=1:nloop
                s(k) = S(i(k),j(k));
            end
            treadfor(l)=toc/nloop;
            fprintf('.');

            % write with for loop
            tic
            nloop=min(length(i),10000);
            for k=1:nloop
                S(i(k),j(k)) = s(k);
            end
            twritefor(l)=toc/nloop;
            fprintf('.');

            % add large sparse matrices to a small one
            S=sparse([],[],[],n,n);
            tic
            Sadd = sparse(i,j,s,n,n);
            S = S + Sadd;
            tadd(l)=toc/nnz(S);
            fprintf('.');

            % getspvalmex
            [i j]=find(S);
            tic
            s = getspvalmex(S,i(:),j(:));
            tgetval(l)=toc/numel(i)/max(log2(nnz(S)),7);
            fprintf('.');

            % setspvalmex
            [i j s]=find(S);
            tic
            S = setspvalmex(S,i(:),j(:),s(:));
            tsetval(l)=toc/numel(s)/max(log2(nnz(S)),7);
            fprintf('.');

            % insert new elements
            S=sparse([],[],[],n,n,nz);
            tic
            nloop=min(length(i),10000);
            for k=1:nloop
                S(i(k),j(k)) = s(k);
            end
            tinsert(l)=toc/nloop;
            fprintf('.');

            % remove existing elements
            % Use the same n-loop
            % nloop=min(length(i),10000);
            tic
            for k=1:nloop
                S(i(k),j(k)) = 0;
            end
            tremove(l)=toc/nloop;
            fprintf('.');
        end

        fprintf('\n');

        clear S i j s

        TREF = struct('factory', false, ...
            'tcreate', median(tcreate), ...
            'tfind', median(tfind), ...
            'treadlin',  median(treadlin), ...
            'tismember', median(tismember), ...
            'treadfor',  median(treadfor), ...
            'twritefor',  median(twritefor), ...,
            'tadd',  median(tadd), ...
            'tgetval',  median(tgetval), ...
            'tsetval',  median(tsetval), ...
            'tinsert',  median(tinsert), ...
            'tremove',  median(tremove));

        fprintf('\n');

        disp(TREF);

        % Prompt user to save the customize time
        msg='Save the calibration permanently?';
        ButtonName = questdlg(msg, 'SPcalib', 'Yes', 'No', 'No');

        % Write to a file
        if strcmp(ButtonName,'Yes')
            path = mfilename('fullpath');
            path = fileparts(path);
            fid = fopen([path filesep 'defaultTref.m'], 'w');
            if fid>0
                contains = {
                    'function tref = defaultTref'
                    '%'
                    '% Return the typical running time of each task'
                    '% This must be customized for each specific computer'
                    '% The structure here is the same as output returned by calling'
                    '% SPCALIB(''auto'')'
                    '%'
                    '% Do not change here'
                    '% Reference factory, obtained from 2007 Sony laptop '
                    '%  tref = struct( ...'
                    '%      ''factory'', true, ...'
                    '%      ''tcreate'', 7.8671e-00, ...'
                    '%      ''tfind'', 5.088857e-008, ...'
                    '%      ''treadlin'', 1.1566e-007, ...'
                    '%      ''tismember'', 1.716785e-007, ...'
                    '%      ''treadfor'', 3.4761e-006, ...'
                    '%      ''twritefor'', 7.439304e-006, ...'
                    '%      ''tadd'', 1.0071e-007, ...'
                    '%      ''tgetval'', 1.2649e-008, ...'
                    '%      ''tsetval'', 1.1009e-008, ...'
                    '%      ''tinsert'', 6.796743e-005, ...'
                    '%      ''tremove'', 5.114582e-005);'
                    sprintf('%% Create date: %s', datestr(now))
                    ''
                    ' tref = struct( ...'
                            '     ''factory'', false, ...'
                    sprintf('     ''tcreate'', %e, ...', TREF.tcreate)
                    sprintf('     ''tfind'', %e, ...', TREF.tfind)
                    sprintf('     ''treadlin'', %e, ...', TREF.treadlin)
                    sprintf('     ''tismember'', %e, ...', TREF.tismember)
                    sprintf('     ''treadfor'', %e, ...', TREF.treadfor)
                    sprintf('     ''twritefor'', %e, ...', TREF.twritefor)
                    sprintf('     ''tadd'', %e, ...', TREF.tadd)
                    sprintf('     ''tgetval'', %e, ...', TREF.tgetval)
                    sprintf('     ''tsetval'', %e, ...', TREF.tsetval)
                    sprintf('     ''tinsert'', %e, ...', TREF.tinsert)
                    sprintf('     ''tremove'', %e);', TREF.tremove)
                    ''
                    'end'
                    };
                count = fprintf(fid, '%s\n',contains{:});
                if count<sum(cellfun(@length,contains)+1)
                    error('Could not save defaultTref.m');
                end
            else
                error('Could not save defaultTref.m');
            end
            fclose(fid);
            drawnow;
        end

    else
        TREF = [];
    end

end

% Factory tune
if isempty(TREF)
    TREF = defaultTref();
end

ts = TREF;

end


%% OpenMAS MONTE-CARLO SIMULATION SETUP (monteCarlo_setup.m) %%%%%%%%%%%%%%
% This function is designed to build a monte-carlo style analysis of a
% given scenario.

% Author: James A. Douthwaite 26/03/18

% ADD THE PROGRAM PATHS
clear all; close all;
addpath('environment');
addpath('objects');
addpath('scenarios');
addpath('toolboxes/Intlab_V7.1');

%If intlab needs to be reloaded
try
    wrkDir = pwd;
    test = infsup(0,1);
    clearvars test
    IntDir = strcat(pwd,'\Intlab_V7.1\startupJD.m');
catch
    run('startup.m');
    cd(wrkDir)
end

%% //////////////////// AGENT & SCENARIO PARAMETERS ///////////////////////
fprintf('[SETUP]\tInitialising Monte-Carlo setup script.\n');

%% SIMULATION PARAMETERS
[~, userdir]   = system('echo %USERPROFILE%'); % Get desktop path
sim_outputPath = strcat(userdir,'\desktop\OpenMAS_data');
sim_warningDistance = 10;
sim_threadPool = 0;
sim_maxDuration = 30;
sim_timeStep = 0.25;    % RVO timestep (0.25s)
sim_vebosity = 1;
% sim_figureSet ={'all'};
sim_figureSet = {'plan','closest','inputs','gif'}; %{'fig','gif','inputs','separations'};

% SCENARIO PARAMETERS
sim_plotScenario = 1;
sim_agentNumber = 8;    % TOTAL NUMBER OF AGENTS
sim_agentOrbit  = 10;
sim_waypointOrbit = 10;
sim_agentVelocity = 0;
sim_noiseSigma = 0.2;

% ////////////////////////// INITIALISE AGENTS ////////////////////////////
fprintf('[SETUP]\tAssigning agent definitions:\n');
for index = 1:sim_agentNumber
    % BASIC CLASSES
%     agentIndex{index} = agent_VO();
%     agentIndex{index} = agent_RVO();
%     agentIndex{index} = agent_HRVO();
%     agentIndex{index} = agent_vectorSharing();
%     agentIndex{index} = agent_vectorSharing_interval();

%     agentIndex{index} = agent_2D_VO();
    agentIndex{index} = agent_2D_RVO();
%     agentIndex{index} = agent_2D_HRVO();
%     agentIndex{index} = agent_2D_RVO2();
%     agentIndex{index} = agent_2D_vectorSharing();
%     agentIndex{index} = agent_2D_vectorSharing_interval();
end

fprintf('[SETUP]\t Intialising the agents in the given scenario.\n');
% CALL THE FUNCTION THAT GENERATES THE UKACC SCENARIO
[ objectIndex ] = getScenario_UKACC_concentric('agents',agentIndex,'agentOrbit',sim_agentOrbit,'agentVelocity',sim_agentVelocity,'waypointOrbit',sim_waypointOrbit,'offsetAngle',pi/2,'plot',sim_plotScenario);

% ////////////// INITIALISE THE SIMULATION WITH THE OBJECT INDEX /////////////////
[DATA,META] = OMAS_initialise('objects',objectIndex,...
                             'duration',sim_maxDuration,...
                                   'dt',sim_timeStep,...
                              'figures',sim_figureSet,...
                      'warningDistance',sim_warningDistance,...
                            'verbosity',sim_vebosity,...
                           'threadPool',sim_threadPool,...
                           'outputPath',sim_outputPath);

clearvars -except DATA META
load(strcat(META.outputPath,'META.mat'));
load(strcat(META.outputPath,'EVENTS.mat'));

% ===================== MONTE-CARLO SIMULATION ============================
run_monteCarlo = false;
if ~run_monteCarlo
   return
end

fprintf('[SETUP]\tInitialising Monte-Carlo setup script.\n');

% /////////////////// AGENT & SCENARIO PARAMETERS /////////////////////////
sim_agentOrbit  = 30;       % [FIXED]
sim_agentVelocity = 0;      % [FIXED]
sim_waypointOrbit = 35;     % [FIXED]

% //////////////////////// OMAS CONFIGURATION /////////////////////////////
sim_warningDistance = 10;   % [FIXED]
sim_maxDuration = 120;      % [FIXED]
sim_timeStep = 0.25;     	% [FIXED]
sim_verbosity = 0;          % [FIXED]

% ///////////////////// MONTE-CARLO CONFIGURATION /////////////////////////
monteCarlo_algs = {'agent_2D_VO',...
                   'agent_2D_RVO',...
                   'agent_2D_HRVO',...
                   'agent_2D_RVO2'};
% monteCarlo_algs = {'agent_2D_RVO2'};
monteCarlo_agentN = [2,5,10,20];
monteCarlo_noiseSigma = 0.2;
monteCarlo_outputDir = strcat(pwd,'\data\UKACC_realisticSensing');
monteCarlo_cycles = 1000;   % [FIXED]
monteCarlo_parallel = 1;
monteCarlo_offOnComplete = 0;

% FOR EACH NUMBER OF AGENTS IN THE GIVEN SCENARIO
for n = 1:numel(monteCarlo_agentN)                                         % Differing agent numbers
    % FOR EACH ALGORITHM TO BE EVALUATED
    for index = 1:numel(monteCarlo_algs)                                   % Differing agent algorithms
        % CREATE THE AGENT SET
        agentVector = cell(1,monteCarlo_agentN(n));                        % Agent container
        for i = 1:monteCarlo_agentN(n)
            agentVector{1,i} = eval(monteCarlo_algs{index});               % Assign agents
        end

        % ///////////////////// SCENARIO CONFIGURATION ////////////////////
        initialisedObjects = getScenario_UKACC(...                         % Initialise the objects in the UKACC scenario
            'agents',agentVector,...
            'agentOrbit',sim_agentOrbit,...
            'agentVelocity',sim_agentVelocity,...
            'waypointOrbit',sim_waypointOrbit,...
            'offsetAngle',0);
        clear agentVector

        % UNIQUE OUTPUT FILE
        studyOutputDir = strcat(monteCarlo_outputDir,...
                                '\',monteCarlo_algs{index});

        % ///////////////// DEFINE THE MONTE-CARLO INSTANCE ///////////////
        fprintf('[SETUP]\t Defining Monte-Carlo Simulation Series...\n');
        [monteCarlo] = OMAS_monteCarlo(...
                        'objects',initialisedObjects,...
                        'duration',sim_maxDuration,...
                        'dt',sim_timeStep,...
                        'warningDistance',sim_warningDistance,...
                        'verbosity',sim_verbosity,...
                        'outputPath',studyOutputDir,...
                        'positionSigma',monteCarlo_noiseSigma,...
                        'threadPool',monteCarlo_parallel,...
                        'shutDownOnComplete',monteCarlo_offOnComplete,...
                        'cycles',monteCarlo_cycles);

        % ///////////////// EXECUTE CYCLE EVALUATION //////////////////////
        [summaryData,monteCarlo] = monteCarlo.evaluateCycles();            % Process the defined cycles
        clear summaryData monteCarlo
    end
end


% TRAIN_CNNSKETCH2IMAGERETRIEVAL Code to train the methods presented in the paper:
% F. Radenovic, G. Tolias, O. Chum, Deep Shape Matching, ECCV 2018
%
% Note: The method has been re-coded since our ECCV 2018 paper and minor differences in performance might appear.
%
% Authors: F. Radenovic, G. Tolias, O. Chum. 2018.

clear;

%-------------------------------------------------------------------------------
% Set data folder
%-------------------------------------------------------------------------------

% Set data folder, change if you have downloaded the data somewhere else
data_root = fullfile(get_root_cnnimageretrieval(), 'data');
% Check, and, if necessary, download train data (db with edgemaps), and pre-trained imagenet networks
download_train_sketch(data_root);

%-------------------------------------------------------------------------------
% Reproduce training from ECCV18 paper: Deep Shape Matching ...
%-------------------------------------------------------------------------------

% Set architecture and initialization parameters
opts.init.model = 'VGG'; % (ALEX | VGG | GOOGLENET | RESNET101)
opts.init.modelDir = fullfile(data_root, 'networks', 'imagenet');
opts.init.method = 'edgefilter_mac';
opts.init.objectiveType = {'contrastiveloss', 0.7};
opts.init.errorType = {'batchmap'};
opts.init.averageImageScale = 0;
opts.init.imageChannels = 1;

% Set train parameters
opts.train.dbPath = fullfile(data_root, 'train', 'dbs', 'retrieval-SfM-30k-edgemap.mat');
opts.train.batchSize = 20;
opts.train.numSubBatches = 4;
opts.train.numEpochs = 20;
opts.train.learningRate = 0.001 .* exp(-(0:99)*0.1);
opts.train.numNegative = 5;
opts.train.numRemine = 3;
opts.train.gpus = [1];

opts.train.augment.jitterFlip = true;
opts.train.augment.jitterQueryBinarize = true;

% Trial name (to name a save directory)
trialName = 'test';

% Export directory expDir named after model, method and trialName
opts.init.method = [opts.init.method, '_', trialName];
opts.train.expDir = fullfile(data_root, 'networks', 'exp', [lower(opts.init.model) '_' lower(opts.init.method)]);
if ~exist(opts.train.expDir); mkdir(opts.train.expDir); end % create folder if its not there

% Load opts by respecting added opts
opts = load_opts_train(opts);

% Initialize and train the network
fprintf('>> Experiment folder is set to %s\n', opts.train.expDir);
net = init_network(opts.init);
[net, state, stats] = train_network(net, @(o,i,n,b,s,m,e) get_batch(o,i,n,b,s,m,e), opts.train);


function G = myLinearize(BlockData)
%Copyright 2013 The MathWorks, Inc.

% assignin('base','BlockData',BlockData)
[x,u] = findop(BlockData.Parameters.Value,'snapshot',2,ones(1000,1));
G = linearize(BlockData.Parameters.Value,u,x);

end


function [cData3M, xLim, yLim] = CERRDoseColorWash(hAxis, dose2M, doseXVals, doseYVals, offset, CT2M, CTXVals, CTYVals, scanSet)
% function CERRDoseColorWash"
% Create dose display as a colorwash in axis hAxis, using dose2M as
% defined at doseXVals, doseYVals. CT2M is a B&W CT image defined at
% CTXVals, CTYVals that will have dose interpolated to it and displayed.
%
% CT2M, CTXvals, and CTYVals are optional--if they do not exist, the
% dose is displayed using its own x,y values.
%
% Created: 24 Nov 02, JOD.
%  LM: 03 Dec 02.
%      29 Dec 02, test for 'trans' view before assigning old dose matrix;
%                  also added 'axes commands' to assure correct GUI behavior; JOD.
%      05 Jan 03, JOD.
%      06 Jan 03, CZ (fixed problem of having colorbar marks showing which are larger than maximum dose.)
%      13 Jan 03, CZ visualRef changes
%      13 Jan 03, JOD, minor colorbar marks off.
%      16 Jan 03, JOD, don't use dose size to get CT size ever.
%      20 Jan 03, JOD, visual ref dose isn't show if over dose max.
%      23 Feb 03, JOD, fixed colorbar labels over 100 Gy.
%      07 Apr 03, JOD, adjusted display of strings.
%      09 Apr 03, JOD, fix bug associated with empty levelsV.
%      23 May 03, JRA, added code to draw washes with offset values, and deal with colorbar+labels:May 25, also added hatchpattern
%                       For further changes, see CVS logs.
%
%Usage:
%   [cData3M, xLim, yLim] = CERRDoseColorWash(hAxis, dose2M, doseXVals, doseYVals, offset, CT2M, CTXVals, CTYVals)
%
% 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/>.

global stateS planC
indexS = planC{end};

if strcmpi(get(hAxis,'tag'),'doseCompareAxes')
    colorbarFrameMin = stateS.colorbarFrameMinCompare;
    colorbarFrameMax = stateS.colorbarFrameMaxCompare;
    colorbarRange    = stateS.colorbarRangeCompare;
    doseDisplayRange = stateS.doseDisplayRangeCompare;
else
    colorbarFrameMin = stateS.colorbarFrameMin;
    colorbarFrameMax =  stateS.colorbarFrameMax;
    colorbarRange    = stateS.colorbarRange;
    doseDisplayRange = stateS.doseDisplayRange;
end

if stateS.imageRegistration
    if ~isempty(stateS.doseFusionColormap)
        c = CERRColorMap(stateS.doseFusionColormap);
    else
        c = CERRColorMap(stateS.optS.doseColormap);
    end
else
    c = CERRColorMap(stateS.optS.doseColormap);
end

if stateS.optS.doubleSidedColorbar
    c = [flipud(c);c];
end

[n, m] = size(dose2M);

noCT = 0;

%Get CT data
if ~exist('CT2M','var') || (isempty(CT2M) && isempty(CTXVals))
    CT2M = zeros(size(dose2M));
    CTXVals = doseXVals;
    CTYVals = doseYVals;
    minCol = 1;
    maxCol = m;
    maxRow = n;
    minRow = 1;
    noCT = 1;
else
    dose2M = finterp2(doseXVals, doseYVals, dose2M, CTXVals, CTYVals, 1, 0);

    % get row/col for clipping the dose grid
    minCol = findnearest(CTXVals,min(doseXVals));
    maxCol = findnearest(CTXVals,max(doseXVals));
    maxRow = findnearest(CTYVals,min(doseYVals));
    minRow = findnearest(CTYVals,max(doseYVals));

    % Swap min/max based on the order of x/v vectors for trans/sag/cor views
    minColTmp = min(minCol,maxCol);
    maxCol = max(minCol,maxCol);
    minCol = minColTmp;
    minRowTmp = min(minRow,maxRow);
    maxRow = max(minRow,maxRow);
    minRow = minRowTmp;

%     %% for DDM : Use Kriging to fit dose
%     [CTXValsM, CTYValsM] = meshgrid(CTXVals, CTYVals);
%     [xUnifV, yUnifV, jnk] = getUniformScanXYZVals(planC{indexS.scan}(1));
%     [jnk1, jnk2, zCTV] = getScanXYZVals(planC{indexS.scan}(1));
%     %structureNameAnalyzeC =  {'MMR', 'MML', 'TMR', 'TML', 'PMR', 'PML', 'PLR', 'PLL'};
%     structureNameAnalyzeC =  {'All_Muscles_plus_2cm'};
%     allStructureNames = {planC{indexS.structures}.structureName};
%     structNum = [];
%     for strIndex = 1:length(structureNameAnalyzeC)
%         structNum = [structNum find(strcmpi(structureNameAnalyzeC{strIndex}, allStructureNames))];
%     end
%
%     viewStr = getAxisInfo(hAxis,'view');
%     coord = getAxisInfo(hAxis,'coord');
%     switch lower(viewStr)
%         case 'transverse'
%             dim = 3;
%             sliceNum = findnearest(zCTV,coord);
%
%             [segs, planC, isError] = getRasterSegments(structNum(1), planC, sliceNum);
%             for structNumMask = structNum(2:end)
%                 segsTmp = getRasterSegments(structNumMask, planC, sliceNum);
%                 segs = [segs; segsTmp];
%             end
%
%             maskM = rasterToMask(segs, 1,planC);
%
%         case 'sagittal'
%             dim = 1;
%             sliceNum = findnearest(xUnifV,coord);
%             maskM = getStructureMask(structNum(1), sliceNum, dim, planC);
%             for structNumMask = structNum(2:end)
%                 maskM = maskM | getStructureMask(structNumMask, sliceNum, dim, planC);
%             end
%
%         case 'coronal'
%             dim = 2;
%             sliceNum = findnearest(yUnifV,coord);
%             maskM = getStructureMask(structNum(1), sliceNum, dim, planC);
%             for structNumMask = structNum(2:end)
%                 maskM = maskM | getStructureMask(structNumMask, sliceNum, dim, planC);
%             end
%     end
%     %[iV,jV] =  find(~isnan(dose2M));
%     %dmodelDose = dacefit([doseXVals(jV)' doseYVals(iV)'], dose2M(sub2ind(size(dose2M),iV,jV)), @regpoly0, @correxp, 10, 1e-1, 20);
%     % DoseKrigV = predictor([CTXValsM(:) CTYValsM(:)], dmodelDose);
%
%     [xVals, yVals, zVals] = getDoseXYZVals(planC{indexS.dose}(2));
%     dose3M = planC{indexS.dose}(2).doseArray;
%     [iV,jV,kV] =  find3d(~isnan(dose3M));
%     dataV = dose3M(sub2ind(size(dose3M),iV,jV,kV));
%     dmodelDose = dacefit([xVals(jV)' yVals(iV)' zVals(kV)'], double(dataV(:)), @regpoly0, @correxp, 10, 1e-1, 20);
%
%     CTXValsEval = CTXValsM(maskM);
%     CTYValsEval = CTYValsM(maskM);
%     if dim == 3
%         DoseKrigV = predictor([CTXValsEval(:) CTYValsEval(:) coord*ones(length(CTXValsEval(:)),1)], dmodelDose);
%     elseif dim == 1
%         DoseKrigV = predictor([coord*ones(length(CTXValsEval(:)),1) CTXValsEval(:) CTYValsEval(:)], dmodelDose);
%     else % dim = 2
%         DoseKrigV = predictor([CTXValsEval(:) coord*ones(length(CTXValsEval(:)),1) CTYValsEval(:)], dmodelDose);
%     end
%     dose2M = zeros(size(CTXValsM));
%     dose2M(maskM) = DoseKrigV;

end

ctSize = [size(CT2M,1), size(CT2M,2)];
%
%Mask of pixels w/dose above the cutoff.
lowerBound = doseDisplayRange(1);
upperBound = doseDisplayRange(2);

if(offset)
    negativeMask = [dose2M < offset];
    maskM = [dose2M <= (upperBound+offset) & dose2M >= (lowerBound+offset)];
else
    maskM = [dose2M <= upperBound & dose2M >= lowerBound];
end

if stateS.optS.transparentZeroDose
    %     if offset == 0  %cuts-off dose=0
    %         maskM(dose2M <= offset) = 0;
    %     end
    if offset
        maskM(dose2M == offset) = 0;
    else
        maskM(dose2M == 0) = 0;
    end
end

if stateS.optS.calcDoseInsideSkinOnly
    [structNum,isSkinUniform] = getStructureIndex(hAxis,'skin',planC);
    if isSkinUniform
        skinMaskM = getSkinMask(hAxis,structNum,planC);
        maskM = maskM & skinMaskM;
        %dose2M(skinMaskM) = 0;
    end
end

% Clip dose grid
maskTmpM = maskM;
maskM = false(size(maskM));
maskM(minRow:maxRow,minCol:maxCol) = maskTmpM(minRow:maxRow,minCol:maxCol);

%Fit dose to colormap, but first replace full dose with only dose values that will be displayed.
lowerBound = colorbarRange(1);
upperBound = colorbarRange(2);
if ~(lowerBound == 0 && upperBound == 0) && ~(lowerBound == upperBound)
    percentBelow = (colorbarRange(1) - colorbarFrameMin) / (colorbarRange(2) - colorbarRange(1));
    percentAbove = (colorbarFrameMax - colorbarRange(2)) / (colorbarRange(2) - colorbarRange(1));
    nElements = size(c, 1);
    lowVal = c(1,:);
    hiVal = c(end,:);

    c = [repmat(lowVal, [round(percentBelow*nElements),1]);c;repmat(hiVal, [round(percentAbove*nElements),1])];
end

partialDose2M = dose2M(maskM);

partialDose =((partialDose2M-(colorbarFrameMin+offset))/(colorbarFrameMax - colorbarFrameMin)) * (size(c,1) + 0.5);

roundPartialDose = round(partialDose);
partialDoseClip = clip(roundPartialDose,1,size(c,1),'limits');

%build RGB Matrix by indexing into colormap.
cData3M = c(partialDoseClip, 1:3);

%Temporarily out of commission: doesnt matter since we no longer use texture heavily.
if(offset) && stateS.optS.negativeTexture
    textureMap = [];
    if isempty(textureMap)
        thin = 1; %intensity values for thin and thick bars
        thick = 0.95;
        [sizeX,sizeY] = size(dose2M);
        textureMap = repmat([thin, thin, thick, thick;
            thick, thin, thin, thick;
            thick, thick, thin, thin;
            thin, thick, thick, thin], ceil(sizeX/4), ceil(sizeY/4));

        %resize texturemap to fit the size of the dose.
        textureMap = textureMap(1:sizeX, 1:sizeY);
    end

    negativeValues = negativeMask;
    negativeValuesM = repmat(negativeValues, [1 1 3]);
    textureM = repmat(textureMap, [1 1 3]);
    mask3M = repmat(maskM, [1 1 3]);
    cData3M(negativeValuesM(mask3M)) = cData3M(negativeValuesM(mask3M)) .* (textureM(negativeValuesM & mask3M));
end

CTBackground3M = [];

if stateS.CTToggle == 1 && ~noCT %Don't show very low doses

    CTOffset = planC{indexS.scan}(scanSet(1)).scanInfo(1).CTOffset;

    scanUID = ['c',repSpaceHyp(planC{indexS.scan}(scanSet).scanUID(max(1,end-61):end))];

    colorCT = CERRColorMap(stateS.scanStats.Colormap.(scanUID));
    CTLevel     = stateS.scanStats.CTLevel.(scanUID) + CTOffset;
    CTWidth     = stateS.scanStats.CTWidth.(scanUID);
    CTLow       = CTLevel - CTWidth/2;
    CTHigh      = CTLevel + CTWidth/2;

    %CT2M = clip(CT2M, CTLow, CTHigh, 'limits');

    % Get Min/max of CT2M scan to scale accordingly.
    %minCT = min(CT2M(:));
    %maxCT = max(CT2M(:));
    %scanMin = stateS.scanStats.minScanVal.(scanUID);
    %scanMax = stateS.scanStats.maxScanVal.(scanUID);
    %CTLow = max(CTLow,scanMin);
    %CTHigh = max(CTLow,min(CTHigh,scanMax));

    CT2M = clip(CT2M, CTLow, CTHigh, 'limits');

    %This is a trick for speed.  Map the CT data from 1...N+1 bins, which
    %results (only) the maxValue exceeding N after floored.  Replicate
    %the colorCT last element to display the maxValue correctly.
    if CTLow ~= CTHigh
        ctScaled = (CT2M - CTLow) / ((CTHigh - CTLow) / size(colorCT,1)) + 1;
        %ctScaled = (CT2M - minCT) / ((maxCT - minCT) / size(colorCT,1)) + 1; % bug
        ctClip = uint16(ctScaled);
        colorCT(end+1,:) = colorCT(end,:);
    else
        ctClip = ones(size(CT2M));
    end
    %ctClip = ctClip(1:ctSize(1),1:ctSize(2));

    %colorCT = (1-stateS.doseAlphaValue.trans)*colorCT; % APA comment

    %build CT background by indexing into CTcolormap. Optimal mtd for speed.
    %CTBackground3M = reshape((1-stateS.doseAlphaValue.trans)*colorCT(ctClip,1:3),ctSize(1),ctSize(2),3);
    CTBackground3M = colorCT(ctClip(:),1:3);

    %Check status of transparency value.
    if ~isfield(stateS, 'doseAlphaValue')
        stateS.doseAlphaValue.trans = stateS.optS.initialTransparency;
    end

    %Build 3 layer mask of dose pixel locations.
    %mask3M = repmat(maskM, [1 1 3]);
    mask3M = repmat(maskM(:), [1 3]);

    %Add dose to the CT, merging it with CT values @mask3M based on alpha.
    if ~isempty(cData3M(:))
        % CTBackground3M(mask3M) = (cData3M(:) .* stateS.doseAlphaValue.trans) + (CTBackground3M(mask3M) .* (1-stateS.doseAlphaValue.trans));
        if stateS.imageRegistration
            CTBackground3M(mask3M) = [cData3M(:) CTBackground3M(mask3M)] * [stateS.doseFusionAlpha 1-stateS.doseFusionAlpha]';
        else
            %CTBackground3M(mask3M) = [cData3M(:) CTBackground3M(mask3M)] * [stateS.doseAlphaValue.trans 1-stateS.doseAlphaValue.trans]';
            CTBackground3M(mask3M) = (1-stateS.doseAlphaValue.trans)*CTBackground3M(mask3M) + cData3M(:)*stateS.doseAlphaValue.trans;
        end
    end
    CTBackground3M = reshape(CTBackground3M,ctSize(1),ctSize(2),3);
    cData3M = CTBackground3M;
end

if ~isempty(CTBackground3M)
    cData3M = CTBackground3M;
else
    CTBackground3M = zeros(ctSize(1), ctSize(2), 3);
    mask3M = repmat(maskM, [1 1 3]);
    CTBackground3M(mask3M) = cData3M(:);
    cData3M = CTBackground3M;
end

% If in print mode, replace area outside of skin with white. OR dose
% outside skin is set to zero. the code repeats so just take the same code
if stateS.printMode % | stateS.optS.calcDoseInsideSkinOnly

    %     structNum = strmatch('skin',lower({planC{indexS.structures}.structureName}),'exact');
    %     [assocScan, relStructNum] = getStructureAssociatedScan(structNum, planC);
    %     isSkinUniform = any(bitget(planC{indexS.structureArray}(assocScan).bitsArray,relStructNum));

    %%%%%%%%%%% DK replace above two lines with the following code to get
    %%%%%%%%%%% the actual structure number in case there are multiple
    %%%%%%%%%%% structures with the same name.
%     aI = get(hAxis,'userdata');
%
%     scanSet = aI.scanSets;
%
%     assocScansV = getStructureAssociatedScan(1:length(planC{indexS.structures}), planC);
%
%     indXStr = find(assocScansV == scanSet);
%
%     allStructureNames = {planC{indexS.structures}(indXStr).structureName};
%
%     structNum = find(strcmpi('skin', allStructureNames));
%
%     if structNum <= 52
%         bitsArray = planC{indexS.structureArray}(scanSet(1)).bitsArray;
%         isSkinUniform = any(bitget(bitsArray,structNum));
%     else
%         cellNum = ceil((structNum-52)/8)+1;
%         bitsArray = planC{indexS.structureArrayMore}(scanSet(1)).bitsArray{cellNum-1};
%         isSkinUniform = any(bitget(bitsArray,structNum-52-(cellNum-2)*8));
%     end
%
%     if ~isSkinUniform
%         if ~isempty(structNum)
%             CERRStatusString('Skin structure is not uniformized. Unable to turn dose off outside skin.')
%         end
%         structNum = [];
%     end

    [structNum,isSkinUniform] = getStructureIndex(hAxis,'skin',planC);

    %%%%%%%%%%%%++++++++++++++++++++++++++++++++++++++++%%%%%%%%%%%%%%%%%%%

%     %obtain x,y and z-vals
%     [xUnifV, yUnifV, jnk] = getUniformScanXYZVals(planC{indexS.scan}(scanSet));
%     [jnk1, jnk2, zCTV] = getScanXYZVals(planC{indexS.scan}(scanSet));

    if ~isempty(structNum)

%         viewStr = getAxisInfo(hAxis,'view');
%         coord = getAxisInfo(hAxis,'coord');
%         switch lower(viewStr)
%             case 'transverse'
%                 dim = 3;
%                 sliceNum = findnearest(zCTV,coord);
%
%                 [segs, planC, isError] = getRasterSegments(structNum, planC, sliceNum);
%
%                 maskM = rasterToMask(segs, scanSet,planC);
%
%             case 'sagittal'
%                 dim = 1;
%                 sliceNum = findnearest(xUnifV,coord);
%                 maskM = getStructureMask(structNum, sliceNum, dim, planC);
%
%
%             case 'coronal'
%                 dim = 2;
%                 sliceNum = findnearest(yUnifV,coord);
%                 maskM = getStructureMask(structNum, sliceNum, dim, planC);
%
%         end

        maskM = getSkinMask(hAxis,structNum,planC);

        mask3M = repmat(maskM, [1 1 3]);

        if ((isSkinUniform && dim~=3) || dim==3) & stateS.printMode
            set(hAxis,'color',[1 1 1])

            if strcmp(class(cData3M),'uint8')
                cData3M(~mask3M) = 255;
            elseif stateS.printMode
                cData3M(~mask3M) = 1;
            end
        end

%         if stateS.optS.calcDoseInsideSkinOnly && ~stateS.printMode && ((isSkinUniform && dim~=3) || dim==3)
%             cData3M(~mask3M) = 0;
%         end
    end
end

%hold on
set(hAxis, 'nextPlot', 'add');

xLim = CTXVals([1 end]);
yLim = CTYVals([1 end]);

return;

function maskM = getSkinMask(hAxis,structNum,planC)

indexS = planC{end};

%aI = get(hAxis,'userdata');
scanSet = getAxisInfo(hAxis,'scanSets');
viewStr = getAxisInfo(hAxis,'view');
coord = getAxisInfo(hAxis,'coord');

%obtain x,y and z-vals
[xUnifV, yUnifV, jnk] = getUniformScanXYZVals(planC{indexS.scan}(scanSet));
[jnk1, jnk2, zCTV] = getScanXYZVals(planC{indexS.scan}(scanSet));

switch lower(viewStr)
    case 'transverse'
        dim = 3;
        sliceNum = findnearest(zCTV,coord);

        [segs, planC, isError] = getRasterSegments(structNum, planC, sliceNum);

        maskM = rasterToMask(segs, scanSet,planC);

    case 'sagittal'
        dim = 1;
        sliceNum = findnearest(xUnifV,coord);
        maskM = getStructureMask(structNum, sliceNum, dim, planC);

    case 'coronal'
        dim = 2;
        sliceNum = findnearest(yUnifV,coord);
        maskM = getStructureMask(structNum, sliceNum, dim, planC);

end
return;

function [structNum,isSkinUniform] = getStructureIndex(hAxis,structName,planC)

indexS = planC{end};

aI = getAxisInfo(hAxis);

scanSet = aI.scanSets;
assocScansV = getStructureAssociatedScan(1:length(planC{indexS.structures}), planC);

indXStr = find(assocScansV == scanSet);

allStructureNames = {planC{indexS.structures}(indXStr).structureName};

structNum = find(strcmpi(structName, allStructureNames));

if structNum <= 52
    bitsArray = planC{indexS.structureArray}(scanSet(1)).bitsArray;
    isSkinUniform = any(bitget(bitsArray,structNum));
else
    cellNum = ceil((structNum-52)/8)+1;
    bitsArray = planC{indexS.structureArrayMore}(scanSet(1)).bitsArray{cellNum-1};
    isSkinUniform = any(bitget(bitsArray,structNum-52-(cellNum-2)*8));
end

if ~isSkinUniform
    if ~isempty(structNum)
        CERRStatusString([structName, ' structure is not uniformized. Unable to turn dose off outside ',structName])
    end
    structNum = [];
end
return;


imageFile = 'data/einstein.png';
lipschitzConstant = 8;
totalVariationWeigth = 10;
noiseAmplitud = 100;
maxIter = 10;
optimizer = 'AcceleratedForwardBackward';


% run_simSteamShaped_fast.m
% Jamie Near, Sunnybrook Research Institute 2022.
%
% USAGE:
% out=run_simSteamShaped_fast(spinSys);
%
% DESCRIPTION:
% This script simulates a STEAM experiment with fully shaped RF
% pulses. Coherence order filtering is employed to eliminate unwanted
% coherences.  Furthermore, simulations are run at various locations in
% space to account for the within-voxel spatial variation of the metabolite
% signal.  Summation across spatial positions is performed. The MATLAB
% parallel computing toolbox (parfor loop) was used to accelerate the
% simulations.  Acceleration is currently performed in the direction of the
% slice selective pulse along the x-direction, but this can be changed.  Up
% to a factor of 12 acceleration can be achieved using this approach.  If
% the parallel processing toolbox is not available, then replace
% the "parfor" loop with a "for" loop.
%
% INPUTS:
% To run this script, there is technically only one input argument:
% spinSys           = spin system to simulate
%
% However, the user should also edit the following parameters as
% desired before running the function:
% RFWaveform        = name of rf pulse waveform used for both (2nd & 3rd) selective 90 degree pulses.
% Tp                = duration of rf pulses[ms]
% Bfield            = Magnetic field strength in [T]
% Npts              = number of spectral points
% sw                = spectral width [Hz]
% Bfield            = magnetic field strength [Tesla]
% lw                = linewidth of the output spectrum [Hz]
% thkX              = slice thickness of x refocusing pulse [cm]
% thkY              = slice thickness of y refocusing pulse [cm]
% fovX              = full simulation FOV in the x direction [cm]
% fovY              = full simulation FOV in the y direction [cm]
% nX                = number of spatial grid points to simulate in x-direction
% nY                = number of spatial grid points to simulate in y-direction
% taus              = vector of pulse sequence timings  [ms]
%
% OUTPUTS:
% out               = Simulation results, summed over all space.

function out=run_simSteamShaped_fast(sys)
tic
% ************INPUT PARAMETERS**********************************
rfWaveform='ex40.b4_384_14.pta'; %name of RF pulse waveform.
Tp=1.920; %duration of RF pulses[ms]
flipAngle=90;  %Flip Angle of the RF pulses [degrees]
Npts=8192; %number of spectral points
sw=6000; %spectral width [Hz]
Bfield=2.89; %magnetic field strength [Tesla]
lw=1; %linewidth of the output spectrum [Hz]
thkX=2.5; %slice thickness of x RF pulse [cm]
thkY=2.5; %slice thickness of y RF pulse [cm]
fovX=5; %size of the full simulation Field of View in the x-direction [cm]
fovY=5; %size of the full simulation Field of View in the y-direction [cm]
nX=48; %Number of grid points to simulate in the x-direction
nY=48; %Number of grid points to simulate in the y-direction
tau1=6; %TE for STEAM sequence [ms]
tau2=32; %TM for STEAM sequence [ms]
centreFreq=2.3; %Centre frequency of simulation [ppm]
% ************END OF INPUT PARAMETERS**********************************

%set up spatial grid
x=linspace(-fovX/2,fovX/2,nX); %X positions to simulate [cm]
y=linspace(-fovY/2,fovY/2,nY); %y positions to simulate [cm]

%Load RF waveform
RF=io_loadRFwaveform(rfWaveform,'exc',0);

gamma=42577000; %gyromagnetic ratio

%Load spin systems
%load spinSystems
%sys=eval(['sys' spinSys]);

%If length of RF pulse is >200 pts, resample to 100 pts to reduce
%computational workload
if size(RF.waveform,1)>200
    RF=rf_resample(RF,100);
end

Gx=(RF.tbw/(Tp/1000))/(gamma*thkX/10000); %[G/cm]
Gy=(RF.tbw/(Tp/1000))/(gamma*thkY/10000); %[G/cm]

%Initialize structures:
d_temp=cell(1,1);
d=cell(1,1);

%loop through space: If you are using the parfor loops below, and you are
%using an older version of MATLAB (e.g.R2012), don't forget to initialize
%the parallel processing toolbox workers using 'matlabpool open N' (for N
%workers, 12 max).  I don't think this is necessary for newer versions of
%MATLAB.

%First loop through all x-positions, simulating only the first refocusing
%pulse.
%First loop through x direction (first refoc pulse only);

%for X=1:length(x)  %Use this if you don't have the MATLAB parallel processing toolbox
parfor X=1:length(x)  %Use this if you have the MATLAB parallel processing toolbox
        disp(['Executing X-position ' num2str(X) ' of ' num2str(length(x)) '!!!']);
        d_temp{X}=sim_steam_shaped_fastRF1(Bfield,sys,tau1,tau2,RF,Tp,x(X),Gx,flipAngle,centreFreq);
end

%calculate the average density matrix (Doing this inside a separate for
%loop because I couldn't figure out how to do this inside the parfor loop):
for X=1:length(x)
        d{1}=sim_dAdd(d{1},d_temp{X});
end

% %Initialize structures:
out_temp=cell(length(y),1);
out=struct([]);

%Now loop through y direction (second refoc pulse only);
%for Y=1:length(y) %Use this if you don't have the MATLAB parallel processing toolbox
parfor Y=1:length(y) %Use this if you do have the MATLAB parallel processing toolbox
%            disp(['Executing Y-position ' num2str(Y) ' of ' num2str(length(y)) '!!!']);
            out_temp{Y}=sim_steam_shaped_fastRF2(d{1},Npts,sw,Bfield,lw,sys,tau1,tau2,...
                RF,Tp,y(Y),Gy,flipAngle,centreFreq);
end

%Now combine the outputs;  Again, doing this inside a separate for loop
%becuase I can't figure out how to do this inside the parfor loop:
for Y=1:length(y)
            out=op_addScans(out,out_temp{Y});
end

%For consistent scaling across different shaped simulations, we need to :
%1.  Scale down by the total number of simulations run (since these were
%    all added together.
numSims=(nX*nY);
out=op_ampScale(out,1/numSims);

%2.  Scale by the total size of the simulated region, relative to the size
%    of the voxel.
voxRatio=(thkX*thkY)/(fovX*fovY);
out=op_ampScale(out,1/voxRatio);

toc
end

%Nested Function #1
function d = sim_steam_shaped_fastRF1(Bfield,sys,TE,TM,RF,tp,dx,Gx,flipAngle,centreFreq)
%
% USAGE:
% d = sim_steam_shaped_fastRF1(Bfield,sys,TE,TM,RF,tp,dx,Gx,flipAngle,centreFreq)
%
% DESCRIPTION:
% This function simulates only the first bit of the STEAM experiment, up to
% the beginning of the third RF pulse.  The excitation is
% simulated as an instantaneous rotation, and the refocusing pulse is
% simulated as a shaped rotation.
%
% This code is designed to be used in highly-accelerated shaped simulations,
% using the method described by Yan Zhang et al. Med Phys 2017;44(8):
% 4169-78.
%
% This code employs coherence order filtering to select only desired
% signal.  Finally, this code simulates the spectrum at a given point in
% space (x), given the values of the slice selection gradient (Gx).  In
% order to fully simulate the STEAM experiment, you have to run this
% simulation many times at various points in space (x), followed by
% sim_steam_shaped_fastRF2.m, at all points in space (y).
%
% INPUTS:
% Bfield    = main magnetic field strength in [T]
% sys       = spin system definition structure
% TE        = echo time in [ms].
% TM        = mixing time in [ms].
% RF        = RF pulse definition structure for RF pulses (obtain using 'io_loadRFwaveform.m')
% tp        = RF pulse duration in [ms]
% dx        = position offset in x-direction (corresponding to 2nd STEAM pulse) [cm]
% Gx        = gradient strength for 2nd STEAM pulse [G/cm]
% flipAngle = flip angle of refocusing pulses [degrees] (Optional.  Default = 90 deg)
%
% OUTPUTS:
% out       = simulated spectrum, in FID-A structure format, using STEAM
%             sequence.
if nargin<10
    centreFreq=2.3;
    if nargin<9
        flipAngle=90;
    end
end

%In the steam sequence, it can be common to use an asymmetric RF pulse for the
%90-degree pulse waveform.  In this case, it is conventional for the 2nd
%and 3rd rf pulses to be time-reversed versions of eachother, with the 2nd
%pulse (RF1) being a max-phase pulse, and the 3rd pulse (RF2) being a
%min-phase pulse (i.e. the long tails of both pulse occurring during the TM
%period so that the TE is minimized).  Here, check if the RF pulse is
%asymmetric and if so, make sure that the 2nd and 3rd pulses are max-phase
%and min-phase, respectively:
if RF.rfCentre>0.5
    RF1=rf_timeReverse(RF);
    RF2=RF;
else
    RF1=RF;
    RF2=rf_timeReverse(RF);
end

%Check that the TE and TM values are not too short
if TE<(RF1.rfCentre*tp*2)
    error('ERROR:  TE cannot be less than duration of RF pulse! ABORTING!!');
end
if TM<(RF2.rfCentre*tp*2)
    error('ERROR:  TM cannot be less than duration of RF pulse! ABORTING!!');
end

%Set centre frequency
for k=1:length(sys)
    sys(k).shifts=sys(k).shifts-centreFreq;
end

%Calculate Hamiltonian matrices and starting density matrix.
[H,d]=sim_Hamiltonian(sys,Bfield);

%Calculate new delays by subtracting the pulse duration from tau1 and tau2;
delays=zeros(2);
delays(1)=TE-(RF1.rfCentre*tp*2);
delays(2)=TM-(RF2.rfCentre*tp*2);
if sum(delays<0)
    error(['ERROR! The following taus are too short: ' num2str(find(delays<0)) '.']);
end

%BEGIN PULSE SEQUENCE************
d=sim_excite(d,H,'x');                                    %EXCITE
d=sim_COF(H,d,1);                                       %Keep only +1-order coherences
d=sim_evolve(d,H,delays(1)/2000);                         %Evolve by delays(1)/2
d=sim_gradSpoil(d,H,[Gx,0,0],[dx,0,0],tp*RF1.rfCentre);     %Prewind gradient for 2nd 90 degree pulse (Not sure why, but this only works when Gx is positive.  Intiutively, Gx amplitude should be the opposite of the slice select gradient (i.e. -Gx), but this does not seem to work).
d=sim_shapedRF(d,H,RF1,tp,flipAngle,90,dx,Gx);             %1st shaped 90 degree selective pulse
d=sim_COF(H,d,0);                                       %Keep only 0-order coherences
d=sim_evolve(d,H,(delays(2))/1000);                       %Evolve by delays(2)
%END PULSE SEQUENCE**************

%After running this many times along x, the density matrices should be
%averaged, and then the average density matrix should be passed through
%'sim_press_shaped_fastRef2' at various different y-positions.

end

%Nested Function #2
function out = sim_steam_shaped_fastRF2(d,n,sw,Bfield,linewidth,sys,TE,TM,RF,tp,dy,Gy,flipAngle,centreFreq)
%
% USAGE:
% out = sim_steam_shaped_fastRF(d,n,sw,Bfield,linewidth,sys,TE,TM,RF,tp,dy,Gy,flipAngle,centreFreq)
%
% DESCRIPTION:
% This function simulates only the last bit of the STEAM experiment, from the
% the beginning of the third STEAM pulse, to the end.  The RF
% pulse is simulated as a shaped rotation.
%
% This code is designed to be used in highly-accelerated shaped simulations,
% using the method described by Yan Zhang et al. Med Phys 2017;44(8):
% 4169-78.

% This code employs coherence order filtering to select only desired
% signal.
%
% Finally, this code simulates the spectrum at a given point in space (y),
% given the values of the slice selection gradient (Gy).  In order
% to fully simulate the STEAM experiment, you have to first run
% sim_steam_shaped_fastRF1.m at all points in space (x), followed by
% this code, at all points in space (y).
%
% INPUTS:
% d         = starting density matrix (obtained using 'sim_steam_shaped_fastRF1.m')
% n         = number of points in fid/spectrum
% sw        = desired spectral width in [Hz]
% Bfield    = main magnetic field strength in [T]
% linewidth = linewidth in [Hz]
% sys       = spin system definition structure
% TE        = echo time in [ms].
% TM        = mixing time in [ms].
% RF        = RF pulse definition structure for selective RF pulses (obtain using 'io_loadRFwaveform.m')
% tp        = RF pulse duration in [ms]
% dx        = position offset in x-direction (corresponding to first refocusing pulse) [cm]
% dy        = position offset in y-direction (corresponding to second refocusing pulse) [cm]
% Gx        = gradient strength for 2nd STEAM RF pulse [G/cm]
% Gy        = gradient strength for 3rd STEAM RF pulse [G/cm]
% flipAngle = flip angle of RF pulses [degrees] (Optional.  Default = 90 deg)
%
% OUTPUTS:
% out       = simulated spectrum, in FID-A structure format, using STEAM
%             sequence.

if nargin<14
    centreFreq=2.3;
    if nargin<13
        flipAngle=90;
    end
end

%In the steam sequence, it can be common to use an asymmetric RF pulse for the
%90-degree pulse waveform.  In this case, it is conventional for the 2nd
%and 3rd rf pulses to be time-reversed versions of eachother, with the 2nd
%pulse (RF1) being a max-phase pulse, and the 3rd pulse (RF2) being a
%min-phase pulse (i.e. the long tails of both pulse occurring during the TM
%period so that the TE is minimized).  Here, use the asymmetry factor of
%the pulse to make sure that the 2nd and 3rd pulses are max-phase and
%min-phase, respectively:
if RF.rfCentre>0.5
    RF1=rf_timeReverse(RF);
    RF2=RF;
else
    RF1=RF;
    RF2=rf_timeReverse(RF);
end

%Check that the TE and TM values are not too short
if TE<(RF1.rfCentre*tp*2)
    error('ERROR:  TE cannot be less than duration of RF pulse! ABORTING!!');
end
if TM<(RF2.rfCentre*tp*2)
    error('ERROR:  TM cannot be less than duration of RF pulse! ABORTING!!');
end

%Set centre frequency
for k=1:length(sys)
    sys(k).shifts=sys(k).shifts-centreFreq;
end

%Calculate Hamiltonian matrices and starting density matrix.
[H]=sim_Hamiltonian(sys,Bfield);

%Calculate new delays by subtracting the pulse duration from TE and TM;
delays=zeros(2);
delays(1)=TE-(RF1.rfCentre*tp*2);
delays(2)=TM-(RF2.rfCentre*tp*2);
if sum(delays<0)
    error(['ERROR! The following delays are too short: ' num2str(find(delays<0)) '.']);
end

%BEGIN PULSE SEQUENCE************
d=sim_shapedRF(d,H,RF2,tp,flipAngle,90,dy,Gy);          %2nd shaped 90 degree selective pulse
d=sim_gradSpoil(d,H,[0,Gy,0],[0,dy,0],tp*RF1.rfCentre);   %Rewind gradient for 3rd 90 degree pulse (Not sure why, but this only works when Gy is positive.  Intiutively, Gx amplitude should be the opposite of the slice select gradient (i.e. -Gy), but this does not seem to work).
d=sim_COF(H,d,-1);                                      %Keep only -1 coherences
d=sim_evolve(d,H,delays(1)/2000);                            %Evolve by delays(1)/2
[out,~]=sim_readout(d,H,n,sw,linewidth,90);      %Readout along y (90 degree phase);
%END PULSE SEQUENCE**************

%Correct the ppm scale:
out.ppm=out.ppm-(4.65-centreFreq);

%Fill in structure header fields:
out.seq='steam';
out.te=TE;
out.tm=TM;
out.sim='shaped';

%Additional fields for compatibility with FID-A processing tools.
out.sz=size(out.specs);
out.date=date;
out.dims.t=1;
out.dims.coils=0;
out.dims.averages=0;
out.dims.subSpecs=0;
out.dims.extras=0;
out.averages=1;
out.rawAverages=1;
out.subspecs=1;
out.rawSubspecs=1;
out.flags.writtentostruct=1;
out.flags.gotparams=1;
out.flags.leftshifted=0;
out.flags.filtered=0;
out.flags.zeropadded=0;
out.flags.freqcorrected=0;
out.flags.phasecorrected=0;
out.flags.averaged=1;
out.flags.addedrcvrs=1;
out.flags.subtracted=1;
out.flags.writtentotext=0;
out.flags.downsampled=0;
out.flags.isFourSteps=0;

end


%% Sample execution for Baseline-conv5 (improved Siam-FC)
% hyper-parameters reported in Supp.material for CVPR'17, Table 2 for arXiv version
tracker_par.join.method = 'xcorr';
tracker_par.net = 'baseline-conv5_e55.mat';
tracker_par.net_gray = 'baseline-conv5_gray_e100.mat';
tracker_par.scaleStep = 1.0470;
tracker_par.scalePenalty = 0.9825;
tracker_par.scaleLR = 0.68;
tracker_par.wInfluence = 0.175;
tracker_par.zLR = 0.0102;

[~,~,dist,overlap,~,~,~,~] = run_tracker_evaluation('all', tracker_par);


function varargout = process_psth_per_channel( varargin )
% PROCESS_PSTH_PER_CHANNEL: Computes the PSTH per channel.

% It displays the binned firing rate on each channel (of only the first
% neuron on each channel if multiple have been detected). This can be nicely
% visualized on the cortical surface if the positions of the electrodes
% have been set, and show real time firing rate.

% @=============================================================================
% 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: Konstantinos Nasiotis, 2018-2019
%          Francois Tadel, 2022

eval(macro_method);
end

%% ===== GET DESCRIPTION =====
function sProcess = GetDescription()
    % Description the process
    sProcess.Comment     = 'PSTH per channel';
    sProcess.FileTag     = 'raster';
    sProcess.Category    = 'File';
    sProcess.SubGroup    = 'Electrophysiology';
    sProcess.Index       = 1229;
    sProcess.Description = 'https://neuroimage.usc.edu/brainstorm/e-phys/functions';
    % Definition of the input accepted by this process
    sProcess.InputTypes  = {'data'};
    sProcess.OutputTypes = {'data'};
    sProcess.nInputs     = 1;
    sProcess.nMinFiles   = 1;
    % Options: Bin size
    sProcess.options.binsize.Comment = 'Bin size: ';
    sProcess.options.binsize.Type    = 'value';
    sProcess.options.binsize.Value   = {0.05, 'ms', 1};
end

%% ===== FORMAT COMMENT =====
function Comment = FormatComment(sProcess)
    Comment = sProcess.Comment;
end

%% ===== RUN =====
function OutputFiles = Run(sProcess, sInput)
    % Initialize returned values
    OutputFiles = {};

    % ==== OPTIONS =====
    % Bin size
    if isfield(sProcess.options, 'binsize') && ~isempty(sProcess.options.binsize) && ~isempty(sProcess.options.binsize.Value) && iscell(sProcess.options.binsize.Value) && sProcess.options.binsize.Value{1} > 0
        bin_size = sProcess.options.binsize.Value{1};
    else
        bst_report('Error', sProcess, sInput, 'Positive bin size required.');
        return;
    end

    % ===== LOAD INPUT FILES =====
    % Load data file
    DataMat = in_bst_data(sInput.FileName, 'Time', 'Events', 'Comment', 'Device', 'ChannelFlag', 'History');
    sampling_rate = round(abs(1. / (DataMat.Time(2) - DataMat.Time(1))));
    % Load channel file
    ChannelMat = in_bst_channel(sInput.ChannelFile);

    % ===== COMPUTE BINNING =====
    % Define bins
    nBins = floor(length(DataMat.Time) / (bin_size * sampling_rate));
    bins = linspace(DataMat.Time(1), DataMat.Time(end), nBins+1);
    single_file_binning = zeros(length(ChannelMat.Channel), nBins);
    % Process channel by channel
    for iChan = 1:length(ChannelMat.Channel)
        for iEvent = 1:size(DataMat.Events,2)

            % Bin ONLY THE FIRST NEURON'S SPIKES if there are multiple neurons!
            if panel_spikes('IsSpikeEvent', DataMat.Events(iEvent).label) ...
                    && panel_spikes('IsFirstNeuron', DataMat.Events(iEvent).label) ...
                    && strcmp(ChannelMat.Channel(iChan).Name, panel_spikes('GetChannelOfSpikeEvent', DataMat.Events(iEvent).label))

                outside_up = DataMat.Events(iEvent).times >= bins(end); % This snippet takes care of some spikes that occur outside of the window of Time due to precision incompatibility.
                DataMat.Events(iEvent).times(outside_up) = bins(end) - 0.001; % Make sure it is inside the bin. Add 1ms offset
                outside_down = DataMat.Events(iEvent).times <= bins(1);
                DataMat.Events(iEvent).times(outside_down) = bins(1) + 0.001; % Make sure it is inside the bin. Add 1ms offset

                [tmp, bin_it_belongs_to] = histc(DataMat.Events(iEvent).times, bins);

                unique_bin = unique(bin_it_belongs_to);
                occurences = [unique_bin; histc(bin_it_belongs_to, unique_bin)];

                single_file_binning(iChan,occurences(1,:)) = occurences(2,:)/bin_size; % The division by the bin_size gives the Firing Rate
                break
            end
        end

    end

    % Events have to be converted to the sampling rate of the binning
    convertedEvents = DataMat.Events;
    for iEvent = 1:length(DataMat.Events)
        [tmp, bin_it_belongs_to] = histc(DataMat.Events(iEvent).times, bins);
        bin_it_belongs_to(bin_it_belongs_to==0) = 1;
        convertedEvents(iEvent).times   = bins(bin_it_belongs_to);
    end
    Events = convertedEvents;

    % ===== SAVE RESULTS =====
    % Prepare output file structure
    FileMat = db_template('datamat');
    FileMat.F           = single_file_binning;
    FileMat.Time        = diff(bins(1:2))/2+bins(1:end-1);
    FileMat.Comment     = ['PSTH: ' DataMat.Comment];
    FileMat.DataType    = 'recordings';
    FileMat.ChannelFlag = DataMat.ChannelFlag;
    FileMat.Device      = DataMat.Device;
    FileMat.Events      = Events;
    FileMat.nAvg        = 1;
    FileMat.History     = DataMat.History;

    % Add history field
    FileMat = bst_history('add', FileMat, 'ptsh', ['PSTH per electrode: ' num2str(bin_size) ' ms']);
    FileMat = bst_history('add', FileMat, 'ptsh', ['Input file: ' sInput.FileName]);
    % Output filename
    FileName = bst_process('GetNewFilename', bst_fileparts(sInput.FileName), 'data_psth');
    OutputFiles = {FileName};
    % Save output file and add to database
    bst_save(FileName, FileMat, 'v6');
    db_add_data(sInput.iStudy, FileName, FileMat);
end


function mv = mv_plotVoxData(mv,dims);
%
%  mv = mv_plotVoxData(mv,dims);
%
% MultiVoxel UI:
% Plot voxel data along 2-3 dimensions,
% averaging across the others.
%
% ras, 04/05.
if ieNotDefined('mv')
    mv = get(gcf,'UserData');
end

if ieNotDefined('dims')
    dims = [2 3];
end

dimNames = {'Trial' 'Voxel' 'Condition'};
selConds = find(tc_selectedConds(mv));
condNames = mv.trials.condNames(selConds); % ignore null
nConds = length(condNames);

if length(dims) < 3
    nSubplots = 1;
else
    nSubplots = size(mv.voxAmps,dims(3));
end

if nSubplots==1
    fontsz = mv.params.fontsz;
else
    fontsz = mv.params.fontsz - 3;
end

% get data to plot; take mean across
% any non-specified dimensions
data = mv.voxData(:,:,:,selConds-1);
avgAcrossDims = setdiff(1:4,dims);
if ~isempty(avgAcrossDims)
    for i = 1:length(avgAcrossDims)
        data = nanmeanDims(data,avgAcrossDims(i));
    end
end

% permute to plotting order
data = permute(data,[dims avgAcrossDims]);

% normalize to fit in the selected color map
cmap = mv.params.cmap;
data = double(normalize(data,1,size(cmap,1)));

% delete existing axes
other = findobj('Type','axes','Parent',gcf);
delete(other);

nrows = ceil(sqrt(nSubplots));
ncols = ceil(nSubplots/nrows);

for z = 1:nSubplots
    subplot(nrows,ncols,z);
    image(data(:,:,z));
    colormap(cmap);

    % check for conditions labeling:
    % we'll treat that specially, labeling
    % each condition separately
    if dims(1)==3
        set(gca,'YTick',1:nConds,'YTickLabel',condNames);
    else
        ylabel(dimNames{dims(1)},'FontName',mv.params.font,...
                'FontSize',fontsz);
    end

    if length(dims)>=2 & dims(2)==3
        set(gca,'XTick',1:nConds,'XTickLabel',condNames);
    else
        xlabel(dimNames{dims(2)},'FontName',mv.params.font,...
                'FontSize',fontsz);
    end

    if length(dims)==3 & dims(3)==3
        title(condNames{z},'FontName',mv.params.font,...
            'FontSize',fontsz+2);
    end
end

return


function spm_srender(job)
% A function for rendering surfaces
% FORMAT spm_srender(job)
% job - a job structure (see tbx_cfg_render.m)
%__________________________________________________________________________
% Copyright (C) 2008-2018 Wellcome Trust Centre for Neuroimaging

% John Ashburner
% $Id: spm_srender.m 7381 2018-07-25 10:27:54Z guillaume $

fg  = spm_figure('GetWin','Graphics');
ren = get(fg,'Renderer');
clf(fg);
set(fg,'Renderer','OpenGL');
ax = axes('Parent',fg,'DeleteFcn',['rotate3d off; set(gcf,''Renderer'',''' ren ''');']);

try
    set(fg,'CurrentAxes',ax);
    cameratoolbar(fg);
    drawnow;
end

for i=1:numel(job.Object)
     obj = job.Object(i);
     for j=1:numel(obj.SurfaceFile)
         FVo = struct(gifti(obj.SurfaceFile{j}));
         FV  = struct('faces',FVo.faces,'vertices',FVo.vertices);
         p   = patch(FV, 'Parent',ax,...
             'FaceColor', [obj.Color.Red,obj.Color.Green, obj.Color.Blue],...
             'FaceVertexCData',  [],...
             'EdgeColor',        'none',...
             'FaceLighting',     'gouraud',...
             'EdgeLighting',     'gouraud',...
             'SpecularStrength', obj.SpecularStrength,...
             'AmbientStrength',  obj.AmbientStrength,...
             'DiffuseStrength',  obj.DiffuseStrength,...
             'SpecularExponent', obj.SpecularExponent,...
             'FaceAlpha',        obj.FaceAlpha);
    end
end
for i=1:numel(job.Light)
    obj = job.Light(i);
    l   = light('Parent',ax,...
        'Position',obj.Position,...
        'Color',[obj.Color.Red,obj.Color.Green, obj.Color.Blue]);
end

%set(0,'CurrentFigure',fg);
set(fg,'CurrentAxes',ax);
axis image equal off;
drawnow;


classdef math_model_opf_acps_legacy < mp.math_model_opf_acps & mp.mm_shared_opf_legacy
%MP.MATH_MODEL_OPF_ACPS_LEGACY  MATPOWER mathematical model for AC optimal power flow (OPF) problem.
%   ?
%
%   MP.MATH_MODEL_OPF_ACPS_LEGACY ... power flow ...
%
%   Properties
%       ? - ?
%
%   Methods
%       ?

%   MATPOWER
%   Copyright (c) 2021-2022, Power Systems Engineering Research Center (PSERC)
%   by Ray Zimmerman, PSERC Cornell
%
%   This file is part of MATPOWER.
%   Covered by the 3-clause BSD License (see LICENSE file for details).
%   See https://matpower.org for more info.

%     properties
%     end

    methods
        %% constructor
        function obj = math_model_opf_acps_legacy()
            obj@mp.math_model_opf_acps();
            if nargin > 0 && isstruct(mpc)
                obj.mpc = mpc;
            end

            %% Due to a bug related to inheritance in constructors in
            %% Octave 5.2 and earlier (https://savannah.gnu.org/bugs/?52614),
            %% INIT_SET_TYPES() cannot be called directly in the
            %% MP_IDX_MANAGER constructor, as desired.
            %%
            %% WORKAROUND:  INIT_SET_TYPES() is called explicitly as needed
            %%              (if om.var is empty) in ADD_VAR(), DISPLAY() and
            %%              INIT_INDEXED_NAME(), after object construction,
            %%              but before object use.
        end

        function obj = add_named_set(obj, varargin)
            % call parent method (also checks for valid type for named set)
            add_named_set@mp.math_model_opf_acps(obj, varargin{:});
            obj.add_named_set_legacy(varargin{:});
        end

        function obj = def_set_types(obj)
            obj.def_set_types_legacy();
        end

        function obj = init_set_types(obj)
            init_set_types@mp.math_model_opf_acps(obj);
            obj.init_set_types_legacy();
        end

        function obj = build(obj, nm, dm, mpopt)
            obj.mpc = dm.source;
            build@mp.math_model_opf_acps(obj, nm, dm, mpopt);
            obj.build_legacy(nm, dm, mpopt);
        end

        function obj = add_vars(obj, nm, dm, mpopt)
            add_vars@mp.math_model_opf_acps(obj, nm, dm, mpopt);    %% call parent

            %% legacy user-defined variables
            if isfield(dm.userdata, 'legacy_opf_user_mods')
                obj.add_legacy_user_vars(nm, dm, mpopt);
            end
        end

        function add_system_costs(obj, nm, dm, mpopt)
            add_system_costs@mp.math_model_opf_acps(obj, nm, dm, mpopt);    %% call parent

            %% legacy user-defined costs
            if isfield(dm.userdata, 'legacy_opf_user_mods')
                obj.add_legacy_user_costs(nm, dm, 0);
            end
        end

        function obj = add_system_constraints(obj, nm, dm, mpopt)
            %% call parent
            add_system_constraints@mp.math_model_opf_acps(obj, nm, dm, mpopt);

            %% legacy user-defined constraints
            if isfield(dm.userdata, 'legacy_opf_user_mods')
                obj.add_legacy_user_constraints_ac(nm, dm, mpopt);
            end
        end

        function names = legacy_user_var_names(obj)
            names = {'Va', 'Vm', 'Pg', 'Qg'};
        end
    end     %% methods
end         %% classdef


function planC = findAndSetMinCTSpacing(planC, minSpacing, maxSpacing, alternateSpacing, scanNumV)
%"findAndSetMinCTSpacing"
%   Finds the minimum spacing in a CT scan and records the superior and inferior slice numbers.
%   minSpacing should be the same as optS.smallestUniformCTSliceSpacing.
%
%VHC 23 Aug 02
%
%Latest modifications:
% 25 Sept 02, JOD.
% 19 Feb 03, JOD, Change the specification of smallest CT such that a range is given:
%                 optS.lowerLimitUniformCTSliceSpacing to optS.upperLimitUniformCTSliceSpacing.
%                 Given a set of CT values, we choose the largest block which CT slice spacing which
%                 falls within these limits.  Otherwise we create a set with a spacing equal to
%                 optS.alternateUniformCTSliceSpacing.  Rewritten using blockS structure.
% 29 Apr 03, JOD, If slice thicknesses are not available, they are assigned by using the zValues.
%  8 May 03, JOD, only deduce slice thicknesses if thicknesses are not already present.
%  9 May O3, JOD, corrected faulty indexing in determining slice block to keep.
% 20 May 03, ES,  changed < to <= in block recognition loop.
% 20 May 03, JOD, corrected bug in assigning slice thicknesses to blocks of slices.
%
%Usage:
%   function planC = findAndSetMinCTSpacing(planC, minSpacing, maxSpacing, alternateSpacing)
%
% 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/>.

accuracy = 0.001; %this value seems to work best for CT scans.  This is how much different the slice spacing
                     %can be and still be considered as approximately the same slice spacing.

%get scan info
indexS = planC{end};

% Get scan indices
if ~exist('scanNumV','var')
    scanNumV = 1:length(planC{indexS.scan});
end

for scanNum = scanNumV

	thicknessV = deduceSliceWidths(planC,scanNum);
	CERRStatusString('Using zValues to compute voxel thicknesses.')

    for i = 1 : length(thicknessV)  %put back into planC
        planC{indexS.scan}(scanNum).scanInfo(i).sliceThickness = thicknessV(i);
    end

	%Get all blocks of the CT scan which have constant slice spacing
	%and store their characteristics.
	slice = 1;
	blockNum = 1;
    blockS = struct('');
	while slice <= length(thicknessV) - 1

        start = slice;
        finish  = slice;

        same = 1;

      go = 0;
      while same && (slice <= length(thicknessV) - 1)      %changed < to <=, ES.
        go = 1;
        if (abs(thicknessV(slice + 1) - thicknessV(slice)) < accuracy)
          slice = slice + 1;
          finish = slice;
        else
          slice = slice + 1;
          same = 0;
        end
      end

      %store block information
      blockS(blockNum).start = start;
      blockS(blockNum).finish = finish;
      blockS(blockNum).width = finish - start + 1;
      blockS(blockNum).spacing = thicknessV(start);
      blockNum = blockNum + 1;
      if go == 0
        slice = slice + 1;
      end

	end

	numSlices = length(thicknessV);

	%Choose which blocks have thicknesses fulfilling the criteria:

	okV = [];
	for i = 1 : length(blockS)
      if blockS(i).spacing <= maxSpacing &&  blockS(i).spacing >= minSpacing
        okV = [okV, i];
      end
	end

	if ~isempty(okV)
      %Of those, which has the largest number of consecutive slices?
      widthV = [blockS(okV).width];

      indV = find(max(widthV) == widthV);
      ind = indV(1);

      ind2 = okV(ind);

      sliceThickness = blockS(ind2).spacing;
      sliceNumSup = blockS(ind2).start;
      sliceNumInf = blockS(ind2).finish;

	else

      sliceThickness = alternateSpacing;
      sliceNumMiddle = floor(numSlices/2);
      sliceNumSup = sliceNumMiddle;
      sliceNumInf = sliceNumMiddle;

	end

	uniformScanInfo = planC{indexS.scan}(scanNum).scanInfo(1);
	uniformScanInfo.sliceNumSup = sliceNumSup;
	uniformScanInfo.sliceNumInf = sliceNumInf;
	uniformScanInfo.sliceThickness = sliceThickness;
	uniformScanInfo.supInfScansCreated = 0; %scans not created yet, but the field is initialized
    scanArray = getScanArray(planC{indexS.scan}(scanNum));
	uniformScanInfo.minCTValue = double(min(scanArray(:)));
	uniformScanInfo.maxCTValue = double(max(scanArray(:)));

	optS = planC{indexS.CERROptions};

    if ~isfield(optS, 'uniformizedDataType')
        try
            if planC{indexS.scan}(scanNum).uniformScanInfo.bytesPerPixel == 1
                optS.uniformizedDataType = 'uint8';
            else
                optS.uniformizedDataType = 'uint16';
            end
        catch
            optFromFile = opts4Exe([getCERRPath,'CERROptions.json']);
            optS.uniformizedDataType = optFromFile.uniformizedDataType;
        end
        planC{indexS.CERROptions} = optS;
    end

	switch optS.uniformizedDataType

      case 'uint8'

        uniformScanInfo.bytesPerPixel = 1;

      case 'uint16'

        uniformScanInfo.bytesPerPixel = 2;

      otherwise

        error('Error determining CT uniformized data type.')

	end

	%Remove unneeded holdover fields copied from scanInfo(1).
	if isfield(uniformScanInfo, 'imageNumber')
        uniformScanInfo = rmfield(uniformScanInfo, 'imageNumber');
	end
	if isfield(uniformScanInfo, 'zValue')
        uniformScanInfo = rmfield(uniformScanInfo, 'zValue');
	end
	if isfield(uniformScanInfo, 'voxelThickness')
        uniformScanInfo = rmfield(uniformScanInfo, 'voxelThickness');
	end

	planC{indexS.scan}(scanNum).uniformScanInfo = uniformScanInfo;

end


function z = minus( x, y, cheat )

%   Disciplined convex programming information for MINUS:
%      Terms in a difference must have opposite curvature. Real affine
%      expressions are both convex and concave, so they can be involved
%      in a difference with any nonlinear expression. Complex affine (or
%      constant) expressions, however, are neither, so they can only be
%      involved in differences with other affine expressions. So, for
%      example, the following differences are valid:
%         {convex}-{concave}   {concave}-{convex}   {affine}-{affine}
%      The following are not:
%         {convex}-{concave}  {convex}-{complex constant}
%      For vectors, matrices, and arrays, these rules are verified
%      independently for each element.
%
%   Disciplined geometric programming information for MINUS:
%      Non-constant expressions (log-convex or log-concave) may not be
%      involved in a subtraction in disciplined geometric programs.

if nargin < 3, cheat = false; end
z = plus( x, y, true, cheat );

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