%Script to run Dose-recomputation using QIB
%
%APA, 03/27/2009
%
% 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 planC
indexS = planC{end};

% --------------------------------- Option to Downsample CT
ButtonName = questdlg('Do you wish to downsample CT by factor of 2?');
if strcmpi(ButtonName,'yes')
    planC = getplanCDownSample(planC, planC{indexS.CERROptions}, 2);
end

% --------------------------------- Target Struture used to Scale dose (D98)
ptvStructNum = 13;

% --------------------------------- Clinical Dose used to Scale dose
clinicDoseNum = 1;

% --------------------------------- Name IMRTP
imrtpName = 'Leaf Seq 2';

%% --------------------------------- Inputs for QIB
MCsolver = 3;
scatterThreshold = 0.1;
structNumsV = [5 6 7]; %Structure indices where dose needs to be calculated.
sampleRateV = [4 2 2];   %NOTE: Skin can be sampled at rate of 8, whereas targets and critical
%                          structures can be sampled at rate of 2. This helps speed-up calculation
%                          while maintaining dose accuracy for important structures. Same length as structNumsV

%% --------------------------------- Inputs for DPM
% MCsolver = 1; %1:DPM, 2:VMC++
% scatterThreshold = 11.2; %DPM
% structNumsV = []; %leave structure number empty since DPM computes dose over entire body
% sampleRateV = []; %leave empty for DPM calculation

%Change nhist and batch
nhist = 1e5; %per cm^2, use 1000000 for testing; %1M is 2% uncertainty, 4M is 1%
batch = 101; %must be unique for each calculation
planC_File = ''; %Leave empty since it is global.
leak = 0.032;
spectrum_File = '6MV10x10MDA.spectrum';
OutputError = 0; %not working for 1
whichBeam = 1;  %redefined later
PBMaxWidth = 10; %
gradsense = 25;
% MCsolver = 1; %1:DPM, 2:VMC++
saveIM = 0;
sourceModel = 0; %1 to use source model
doseToWater = 0;
fillWater = 0;
useWedge = 0;
inputPB = 0;
inputIM = 1;
Softening = 1;
UseFlatFilter = 1;
MLC = 0; %1?
TongueGroove = 0;
interactiveMode = 1;
LS_flag = 0;
K = 1;
% scatterThreshold = 11.2; %DPM
% structNumsV = []; %leave structure number empty since DPM computes dose over entire body
% sampleRateV = []; %leave empty for DPM calculation

% % --------------------------------- Inputs for QIB
% MCsolver = 3;
% scatterThreshold = 0.1;
% structNumsV = [2 1 5 6 11]; %Structure indices where dose needs to be calculated.
% sampleRateV = [8 2 2 2 2]; %NOTE: Skin can be sampled at rate of 8, whereas targets and critical
% %                           structures can be sampled at rate of 2. This helps speed-up calculation
% %                           while maintaining dose accuracy for important structures
%
% structNumsV = [11 12 9 6];
% sampleRateV = [2 2 2 2]; %same length as structNumsV

%% --------------------------------- Call dose calculation engine
try
    numBeams = planC{indexS.beams}(1).FractionGroupSequence.Item_1.NumberofBeams;
catch
    numBeams = planC{indexS.beams}(1).FractionGroupSequence.Item_1.NumberOfBeams;
end
beamletWeightC = {};
for whichBeam = 1:numBeams
    %IMwDPM = beam2MCdose(leak, spectrum_File, planC_File, nhist, OutputError, whichBeam, PBMaxWidth, gradsense, MCsolver, saveIM, sourceModel, doseToWater, fillWater, useWedge, inputPB, inputIM, Softening, UseFlatFilter, MLC, TongueGroove, batch, interactiveMode, LS_flag, K, scatterThreshold);
    [IMwQIB(whichBeam), beamletWeightC{whichBeam}] = beam2MCdose_with_QIB(leak, spectrum_File, planC_File, nhist, OutputError, whichBeam, PBMaxWidth, gradsense, MCsolver, saveIM, sourceModel, doseToWater, fillWater, useWedge, inputPB, inputIM, Softening, UseFlatFilter, MLC, TongueGroove, batch, interactiveMode, LS_flag, K, scatterThreshold, structNumsV, sampleRateV);
end

if MCsolver == 1 %DPM
    % --------------------------------- Read dose from disk and apply Meter-Set
    [dose3Dsum] = calcDoseByBeamMeterset(planC, nhist, batch);
    doseName = 'DPM reCalc';

elseif MCsolver == 3 %QIB

    planC{indexS.IM}(1).IMDosimetry.beams = [IMwQIB.beams];
    planC{indexS.IM}.IMDosimetry.goals = IMwQIB(1).goals;
    planC{indexS.IM}.IMDosimetry.params = IMwQIB(1).params;
    clear IMwQIB
    planC{indexS.IM}.IMDosimetry.isFresh = 1;
    planC{indexS.IM}.IMDosimetry.name = imrtpName;
    planC{indexS.IM}.IMDosimetry.solutions = [];
    planC{indexS.IM}.IMDosimetry.assocScanUID = planC{indexS.scan}(1).scanUID;
    planC{indexS.IM}.IMDosimetry.solutions = [beamletWeightC{:}];
    [dose3D] = getIMDose(planC{indexS.IM}(end).IMDosimetry, [beamletWeightC{:}], structNumsV);
    doseName = 'QIB reCalc';
end

%% --------------------------------- Scale to clinical dose
doseNum = length(planC{indexS.dose});

%Scale based on PTV D98
reCalc_metric   = Dx(planC, ptvStructNum, doseNum, 98);
Clinical_metric = Dx(planC, ptvStructNum, clinicDoseNum, 98);

%Scale based on PTV meanDose
reCalc_metric   = meanDose(planC, ptvStructNum, doseNum, 'Absolute');
Clinical_metric = meanDose(planC, ptvStructNum, clinicDoseNum, 'Absolute');

planC{indexS.dose}(doseNum).doseArray = planC{indexS.dose}(doseNum).doseArray*Clinical_metric/reCalc_metric;

%Show dose in CERR
showIMDose(dose3D,doseName)


% Get the mask defining the points where the reconstructions should be
% computed.
function [ mask, lat, lon ] = metoffice_get_mask( dataset )

% filename from dataset
switch dataset
case {'hadsst2d1','hadsst2d2','mohsst5d1','mohsst5d2'}
    maskfile = 'mask';
case {'aari','aari8'}
    maskfile = 'mask_seaice';
otherwise
    error(sprintf('Unknown dataset %s',dataset));
end

% path from system
datapath = metoffice_get_path();

% load mask
if nargout == 3
    load( [ datapath, maskfile ], 'mask', 'lat', 'lon' )
elseif nargout == 1
    load( [ datapath, maskfile ], 'mask' )
end

%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%

function m = metoffice_get_mask_old(maskfile)

if nargin == 0
  warning('Give the maskfile');
  maskfile = 'mask';
end

os = system_dependent('getos');

if ~isempty(strfind(os,'Ubuntu'))
  % Finland
  maskfile = [ '/share/climate/data/UK_Met_Office/RecTest/DATASETS/' maskfile ];
elseif ~isempty(strfind(os,'Linux'))
  % ICS GridEngine
  maskfile = [ '/share/climate/data/UK_Met_Office/RecTest/DATASETS/' maskfile ];
else
  % MetOffice
  maskfile = [ '/net/home/h03/hadia/data/RecTest/' maskfile ];
end

S = load(maskfile);
m = S.mask(:)~=0;


function [r,a] =  training(a,d)

  if isa(d,'group') & strcmp(d.group,'one_for_each') & length(d.child)==length(a.child)

        %% pass only nth data object into nth algorithm

    r=[];
    for i=1:length(a.child)
      [res,a.child{i}]=train(a.child{i},d.child{i}); r{i}=res;
    end

  else  %% standard method

    r=[];
    for i=1:length(a.child)
      [res,a.child{i}]=train(a.child{i},d); r{i}=res;
    end
  end

  if length(r)==1 r=r{1}; else r=group(r); end;
  if isa(r,'group') r.group=a.group; end;


function [cfg, artifact] = ft_artifact_clip(cfg, data)

% FT_ARTIFACT_CLIP scans the data segments of interest for channels that clip. These
% artifacts are detected by the signal being completely flat for a given amount of
% time.
%
% Use as
%   [cfg, artifact] = ft_artifact_clip(cfg)
% with the configuration options
%   cfg.dataset     = string with the filename
% or
%   cfg.headerfile  = string with the filename
%   cfg.datafile    = string with the filename
% and optionally
%   cfg.headerformat
%   cfg.dataformat
%
% Alternatively you can use it as
%   [cfg, artifact] = ft_artifact_clip(cfg, data)
% where the input data is a structure as obtained from FT_PREPROCESSING.
%
% In both cases the configuration should also contain
%   cfg.artfctdef.clip.channel       = Nx1 cell-array with selection of channels, see FT_CHANNELSELECTION for details
%   cfg.artfctdef.clip.pretim        = 0.000;  pre-artifact rejection-interval in seconds
%   cfg.artfctdef.clip.psttim        = 0.000;  post-artifact rejection-interval in seconds
%   cfg.artfctdef.clip.timethreshold = number, minimum duration in seconds of a datasegment with consecutive identical samples to be considered as 'clipped'
%   cfg.artfctdef.clip.amplthreshold = number, minimum amplitude difference in consecutive samples to be considered as 'clipped' (default = 0)
%                                      string, percent of the amplitude range considered as 'clipped' (i.e. '1%')
%   cfg.continuous                   = 'yes' or 'no' whether the file contains continuous data
%
% The output argument "artifact" is a Nx2 matrix comparable to the
% "trl" matrix of FT_DEFINETRIAL. The first column of which specifying the
% beginsamples of an artifact period, the second column contains the
% endsamples of the artifactperiods.
%
% To facilitate data-handling and distributed computing you can use
%   cfg.inputfile   =  ...
% If you specify this option the input data will be read from a *.mat
% file on disk. This mat files should contain only a single variable named 'data',
% corresponding to the input structure.
%
% See also FT_REJECTARTIFACT, FT_ARTIFACT_CLIP, FT_ARTIFACT_ECG, FT_ARTIFACT_EOG,
% FT_ARTIFACT_JUMP, FT_ARTIFACT_MUSCLE, FT_ARTIFACT_THRESHOLD, FT_ARTIFACT_ZVALUE

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

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

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

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

% check if the input cfg is valid for this function
cfg = ft_checkconfig(cfg, 'renamed',    {'datatype', 'continuous'});
cfg = ft_checkconfig(cfg, 'renamed',    {'artfctdef.clip.thresh', 'artfctdef.clip.timethreshold'});
cfg = ft_checkconfig(cfg, 'renamedval', {'continuous', 'continuous', 'yes'});

% set default rejection parameters for clip artifacts if necessary.
if ~isfield(cfg, 'artfctdef'),                    cfg.artfctdef                    = [];    end
if ~isfield(cfg.artfctdef, 'clip'),               cfg.artfctdef.clip               = [];    end
if ~isfield(cfg.artfctdef.clip, 'channel'),       cfg.artfctdef.clip.channel       = 'all'; end
if ~isfield(cfg.artfctdef.clip, 'timethreshold'), cfg.artfctdef.clip.timethreshold = 0.010; end
if ~isfield(cfg.artfctdef.clip, 'amplthreshold'), cfg.artfctdef.clip.amplthreshold = 0.000; end
if ~isfield(cfg.artfctdef.clip, 'pretim'),        cfg.artfctdef.clip.pretim        = 0.000; end
if ~isfield(cfg.artfctdef.clip, 'psttim'),        cfg.artfctdef.clip.psttim        = 0.000; end
if ~isfield(cfg, 'headerformat'),                cfg.headerformat                 = [];    end
if ~isfield(cfg, 'dataformat'),                  cfg.dataformat                   = [];    end

% for backward compatibility
if isfield(cfg.artfctdef.clip, 'sgn')
  cfg.artfctdef.clip.channel = cfg.artfctdef.clip.sgn;
  cfg.artfctdef.clip         = rmfield(cfg.artfctdef.clip, 'sgn');
end

% start with an empty artifact list
artifact = [];

% the data is either passed into the function by the user or read from file with cfg.inputfile
hasdata = exist('data', 'var');

if ~hasdata
  cfg = ft_checkconfig(cfg, 'dataset2files', 'yes');
  cfg = ft_checkconfig(cfg, 'required', {'headerfile', 'datafile'});
  hdr = ft_read_header(cfg.headerfile, 'headerformat', cfg.headerformat);
  trl = cfg.trl;
else
  data = ft_checkdata(data, 'hassampleinfo', 'yes');
  cfg  = ft_checkconfig(cfg, 'forbidden', {'dataset', 'headerfile', 'datafile'});
  hdr  = ft_fetch_header(data);
  if isfield(data, 'sampleinfo')
    trl = data.sampleinfo;
    for k = 1:numel(data.trial)
      trl(k,3) = time2offset(data.time{k}, data.fsample);
    end
  else
    ft_error('the input data does not contain a valid description of the sampleinfo');
  end
end

% set default cfg.continuous
if ~isfield(cfg, 'continuous')
  if hdr.nTrials==1
    cfg.continuous = 'yes';
  else
    cfg.continuous = 'no';
  end
end

% find the channel labels present in the data and their indices
label = ft_channelselection(cfg.artfctdef.clip.channel, hdr.label);
sgnindx = match_str(hdr.label, label);

% make a local copy for convenience
artfctdef = cfg.artfctdef.clip;

ntrl = size(trl,1);
nsgn = length(sgnindx);
for trlop=1:ntrl
  fprintf('searching for clipping artifacts in trial %d\n', trlop);
  % read the data of this trial
  if hasdata
    dat = ft_fetch_data(data,        'header', hdr, 'begsample', trl(trlop,1), 'endsample', trl(trlop,2), 'chanindx', sgnindx);
  else
    dat = ft_read_data(cfg.datafile, 'header', hdr, 'begsample', trl(trlop,1), 'endsample', trl(trlop,2), 'chanindx', sgnindx, 'checkboundary', strcmp(cfg.continuous, 'no'), 'dataformat', cfg.dataformat);
  end
  % get time
  if size(trl,2)>=3
    time = offset2time(trl(trlop,3), hdr.Fs, size(dat,2));
  elseif hasdata
    time = data.time{trlop};
  end
  datflt = preproc(dat, label, time, artfctdef);

  %check if cfg.artfctdef.clip.amplthreshold is an string indicating percentage (e.g. '10%')
  if ~isempty(cfg.artfctdef.clip.amplthreshold) && ischar(cfg.artfctdef.clip.amplthreshold) && cfg.artfctdef.clip.amplthreshold(end)=='%'
    ratio = sscanf(cfg.artfctdef.clip.amplthreshold, '%f%%');
    ratio = ratio/100;
    identical = abs(datflt(:,1:(end-1))-datflt(:,2:end));
    r = range(identical,2);
    for sgnlop=1:length(sgnindx);
      identical(sgnlop,:) = (identical(sgnlop,:)/r(sgnlop))*100;
    end
    identical = identical <= ratio;
  else
    % detect all samples that have the same value as the previous sample
    identical = abs(datflt(:,1:(end-1))-datflt(:,2:end))<=cfg.artfctdef.clip.amplthreshold;
  end

  % ensure that the number of samples does not change
  identical = [identical zeros(nsgn,1)];

  % determine the number of consecutively identical samples
  clip = zeros(size(dat));
  for sgnlop=1:length(sgnindx)
    up = find(diff([0 identical(sgnlop,:)], 1, 2)== 1);
    dw = find(diff([identical(sgnlop,:) 0], 1, 2)==-1);
    for k=1:length(up)
      clip(sgnlop,up(k):dw(k)) = dw(k)-up(k);
    end
  end
  % collapse over cannels
  clip = max(clip,[],1);

  % detect whether there are intervals in which the number of consecutive
  % identical samples is larger than the threshold
  thresh = (clip>=artfctdef.timethreshold*hdr.Fs);

  % remember the thresholded parts as artifacts
  artup = find(diff([0 thresh])== 1) + trl(trlop,1) - 1;
  artdw = find(diff([thresh 0])==-1) + trl(trlop,1) - 1;
  for k=1:length(artup)
    artifact(end+1,:) = [artup(k) artdw(k)];
  end
end

if ~isempty(artifact)
  % add the pretim and psttim to the detected artifacts
  artifact(:,1) = artifact(:,1) - artfctdef.pretim * hdr.Fs;
  artifact(:,2) = artifact(:,2) + artfctdef.psttim * hdr.Fs;
end

% remember the details that were used here
cfg.artfctdef.clip          = artfctdef;
cfg.artfctdef.clip.label    = label;
cfg.artfctdef.clip.trl      = trl;
cfg.artfctdef.clip.artifact = artifact;

% do the general cleanup and bookkeeping at the end of the function
ft_postamble provenance
ft_postamble previous data
ft_postamble savevar


function hplstat(HPL,HPE,HAL,src_name)
% HPL(1xN) - Horizontal protection level
% HPE(Nx1) - Horizontal position error = (easting.^2, northing.^2).^0.5
% HAL - Horizontal alert limit (define how large is the area for Normal operation
%       [the line between white and yellow])
% src_name = label of vertical axis which will go as subscript after 'HPL'

%*     Copyright c 1998 The board of trustees of the Leland Stanford     *
%*                      Junior University. All rights reserved.          *
%*     This script file may be distributed and used freely, provided     *
%*     this copyright notice is always kept with it.                     *
%*                                                                       *
%*     Questions and comments should be directed to Todd Walter at:      *
%*     walter@relgyro.stanford.edu                                       *
%HPLSTAT
%   HPLSTAT(FNAME, HAL, PATH) reads the given file of TMS Horizontal
%   Protection Limit statistics and plots the color coded histogram.
%   In addition the regions of integrity failures and unavailability
%   are shown.  The optional HAL argument is given in meters (default 30m).
%   See also : TMSSTAT, TRSNAMES, VERTSTAT, VPLSTAT
%   Example code for generating the file is included at the bottom of hplstat.m
%
%   NOTE: To plot on a non-color printer type:
%                 colormap('gray')
% % new colormap for colorbar (HPL and HPE plot)
 color_bar =[
     0.6980    0.6980    0.6980;
    0.6905    0.6905    0.6905;
     0.6830    0.6830    0.6830;
     0.6754    0.6754    0.6754;
     0.6679    0.6679    0.6679;
     0.6604    0.6604    0.6604;
     0.6528    0.6528    0.6528;
     0.6453    0.6453    0.6453;
     0.6378    0.6378    0.6378;
     0.6302    0.6302    0.6302;
     0.6227    0.6227    0.6227;
     0.6152    0.6152    0.6152;
     0.6076    0.6076    0.6076;
     0.6001    0.6001    0.6001;
     0.5926    0.5926    0.5926;
     0.5850    0.5850    0.5850;
     0.5775    0.5775    0.5775;
     0.5700    0.5700    0.5700;
     0.5624    0.5624    0.5624;
     0.5549    0.5549    0.5549;
     0.5474    0.5474    0.5474;
     0.5398    0.5398    0.5398;
     0.5323    0.5323    0.5323;
     0.5247    0.5247    0.5247;
     0.5172    0.5172    0.5172;
     0.5097    0.5097    0.5097;
     0.5021    0.5021    0.5021;
     0.4946    0.4946    0.4946;
     0.4871    0.4871    0.4871;
    0.4795    0.4795    0.4795;
     0.4720    0.4720    0.4720;
     0.4645    0.4645    0.4645;
     0.4569    0.4569    0.4569;
     0.4494    0.4494    0.4494;
     0.4419    0.4419    0.4419;
     0.4343    0.4343    0.4343;
     0.4268    0.4268    0.4268;
     0.4193    0.4193    0.4193;
     0.4117    0.4117    0.4117;
     0.4042    0.4042    0.4042;
     0.3967    0.3967    0.3967;
     0.3891    0.3891    0.3891;
     0.3816    0.3816    0.3816;
     0.3741    0.3741    0.3741;
     0.3665    0.3665    0.3665;
     0.3590    0.3590    0.3590;
     0.3515    0.3515    0.3515;
     0.3439    0.3439    0.3439;
     0.3364    0.3364    0.3364;
     0.3289    0.3289    0.3289;
     0.3213    0.3213    0.3213;
     0.2966    0.2966    0.2966;
     0.2719    0.2719    0.2719;
    0.2472    0.2472    0.2472;
     0.2225    0.2225    0.2225;
     0.1977    0.1977    0.1977;
     0.1730    0.1730    0.1730;
     0.1483    0.1483    0.1483;
     0.1236    0.1236    0.1236;
     0.0989    0.0989    0.0989;
     0.0742    0.0742    0.0742;
     0.0494    0.0494    0.0494;
     0.0247    0.0247    0.0247;
          0         0         0];
 colormap(color_bar)

% other colors used in the plot
%color1 = [134/255 134/255 134/255]; % - dark gray
color1 = [1 0.1 0.1];              % - red (original)

%color2 = [174/255 174/255 174/255]; % - middle gray
color2 = [1 0.55 0.55];            % - pink (original)

%color3 = [222/255 222/255 222/255]; % - light gray
color3 = [1 1 0.5];                % - yellow (original)

%color4 = color2;                    % - middle gray
color4 = [1 .55 0.3];              % - orange (original)

set(0,'DefaultTextFontName','Times');
set(0,'DefaultAxesFontName','Times');
set(0,'DefaultTextFontSize',18);
set(0,'DefaultAxesFontSize',18);

if nargin < 2
    error('Must input HPL and HPE!');
end
if nargin < 3
    HAL = 30;
end

% size of VPL, which should be the same for VPE as well
n = size(HPL,2);

% HPE
j = floor(2.0*abs(HPE))+1;
j(find(j>100)) = 100;
% HPL
k = floor(2.0*abs(HPL))+1;
k(find(k>100)) = 100;

% initialize hpl_stat
data     = zeros(100,100);
diagonal = zeros(100,1);
for i = 1:n
    % statistics
    data(k(i),j(i)) = data(k(i),j(i))+1;
    % diagonal
    if((k(i) == j(i)) && (abs(HPE(i,1)) < abs(HPL(1,i))))
        diagonal(k(i),1) = diagonal(k(i),1)+1;
    end
end

c = 1;
colors = 'brygcmw';
clf

err_bin  = 0.25:0.5:49.75;
sig_bin  = 0.25:0.5:49.75;

seconds  = n;
sec_available = n;
diag_cnt = sum(diagonal);

% determine the number of points and axis ranges
n_pts = sum(sum(data));
if sec_available == 1
    epochs = seconds;
else
    epochs = n_pts;
end

d_err_bin = mean(diff(err_bin));
x_lo_bnd  = min(err_bin) - d_err_bin/2;
x_up_bnd  = max(err_bin) + d_err_bin/2;

d_sig_bin = mean(diff(sig_bin));
y_lo_bnd  = min(sig_bin) - d_sig_bin/2;
y_up_bnd  = max(sig_bin) + d_sig_bin/2;

z_lo_bnd  = 1;
z_up_bnd  = max(max(data));

% clear plot
clf;

% plot each data point as a pixel
[i,j]=find(data);
face_mat=[[1 2 6 5]' [2 3 7 6]' [3 4 8 7]' ...
          [4 1 5 8]' [1 2 3 4]' [5 6 7 8]']';
colors=colormap;
for idx = 1:length(i)
  z = log10(data(i(idx),j(idx)));
  vtx_mat = [err_bin(j(idx))+[-0.5 0.5 0.5 -0.5 -0.5 0.5 0.5 -0.5]'*d_err_bin ...
             sig_bin(i(idx))+[-0.5 -0.5 0.5 0.5 -0.5 -0.5 0.5 0.5]'*d_sig_bin ...
             [0 0 0 0 z z z z]'];
  c_idx = ceil(63*(log10(data(i(idx),j(idx)))/log10(z_up_bnd))) + 1;
  patch('Vertices',  vtx_mat, ...
        'Faces',     face_mat, ...
        'FaceColor', colors(c_idx,:), ...
        'EdgeColor', 'none');
end

% determine availability and # of integrity failures
i_diag1 = find(err_bin == HAL);
i_diag2 = find(err_bin < HAL);
i_diag3 = find(err_bin > HAL);

i_fail1 = find(err_bin(j) >= HAL & sig_bin(i) < HAL);
n_fail1 = sum(sum(diag(data(i(i_fail1),j(i_fail1)))))...
         - sum(diagonal(i_diag1));
i_fail2 = find(err_bin(j)./sig_bin(i) >=1.0 & err_bin(j) < HAL);
n_fail2 = sum(sum(diag(data(i(i_fail2),j(i_fail2)))))...
         - sum(diagonal(i_diag2));
i_fail3 = find(err_bin(j)./sig_bin(i) >=1.0 & sig_bin(i) >= HAL);
n_fail3 = sum(sum(diag(data(i(i_fail3),j(i_fail3)))))...
         - sum(diagonal(i_diag3));
i_cont  = find(sig_bin(i) >= HAL);
n_cont  = sum(sum(diag(data(i(i_cont),j(i_cont)))));
%i_avail = find(err_bin(j) < HAL & sig_bin(i) < HAL);
i_avail = find(err_bin(j)./sig_bin(i) < 1.0 & sig_bin(i) < HAL);
n_avail = sum(sum(diag(data(i(i_avail),j(i_avail)))))...
         + sum(diagonal(i_diag2));

% set the axes limits and color values
set(gca,'XLim',[x_lo_bnd x_up_bnd]);
set(gca,'YLim',[y_lo_bnd y_up_bnd]);
set(gca,'CLim',[z_lo_bnd z_up_bnd]);

% show the region of normal operation
HT=text(0.37*(HAL - x_lo_bnd) + x_lo_bnd, ...
     0.93*(HAL - y_lo_bnd) + y_lo_bnd, ...
     0.25*sqrt(z_up_bnd*z_lo_bnd), ...
     '{\fontsize{14pt}Normal Operation}');
pos = get(HT, 'Position');
pos = pos + [.05 -0.05 0];
set(HT, 'Position', pos);
set(HT, 'Color', [1 1 1]); % white
text(0.37*(HAL - x_lo_bnd) + x_lo_bnd, ...
     0.93*(HAL - y_lo_bnd) + y_lo_bnd, ...
     0.25*sqrt(z_up_bnd*z_lo_bnd), ...
     '{\fontsize{14pt}Normal Operation}');
if n_avail/epochs >= .999995
  HT = text(0.33*(HAL - x_lo_bnd) + x_lo_bnd, ...
            0.86*(HAL - y_lo_bnd) + y_lo_bnd, ...
            0.25*sqrt(z_up_bnd*z_lo_bnd), ...
            '> 99.999%');
  pos = get(HT, 'Position');
  pos = pos + [.05 -0.05 0];
  set(HT, 'Position', pos);
  set(HT, 'Color', [1 1 1]); % white
  set(HT, 'FontSize', 14);
  HT = text(0.33*(HAL - x_lo_bnd) + x_lo_bnd, ...
            0.86*(HAL - y_lo_bnd) + y_lo_bnd, ...
            0.25*sqrt(z_up_bnd*z_lo_bnd), ...
            '> 99.999%');
  set(HT, 'FontSize', 14);
else
  HT = text(0.37*(HAL - x_lo_bnd) + x_lo_bnd, ...
            0.86*(HAL - y_lo_bnd) + y_lo_bnd, ...
            0.25*sqrt(z_up_bnd*z_lo_bnd), ...
            [num2str(100.0*n_avail/epochs,'%6.3f'), '%']);
  pos = get(HT, 'Position');
  pos = pos + [.05 -0.05 0];
  set(HT, 'Position', pos);
  set(HT, 'Color', [1 1 1]); % white
  set(HT, 'FontSize', 14);
  HT = text(0.37*(HAL - x_lo_bnd) + x_lo_bnd, ...
            0.86*(HAL - y_lo_bnd) + y_lo_bnd, ...
            0.25*sqrt(z_up_bnd*z_lo_bnd), ...
            [num2str(100.0*n_avail/epochs,'%6.3f'), '%']);
  set(HT, 'FontSize', 14);
end

% outline the region of integrity failures
patch([HAL HAL x_up_bnd x_up_bnd], ...
      [y_lo_bnd HAL HAL y_lo_bnd], ...
      -[0.5 0.5 0.5 0.5], ...
      color1);
HT = text(0.50*(x_up_bnd - HAL) + HAL, ...
          0.55*(HAL - y_lo_bnd) + y_lo_bnd, ...
          0.25*sqrt(z_up_bnd*z_lo_bnd), ...
          'HMI');
set(HT, 'FontSize', 14);
set(HT,'HorizontalAlignment','Center');
pos = get(HT, 'Position');
pos = pos + [.05 -0.05 0];
set(HT, 'Position', pos);
set(HT, 'Color', color1);
HT = text(0.50*(x_up_bnd - HAL) + HAL, ...
          0.55*(HAL - y_lo_bnd) + y_lo_bnd, ...
          0.25*sqrt(z_up_bnd*z_lo_bnd), ...
          'HMI');
set(HT, 'FontSize', 14);
set(HT,'HorizontalAlignment','Center');
HT = text(0.50*(x_up_bnd - HAL) + HAL, ...
          0.45*(HAL - y_lo_bnd) + y_lo_bnd, ...
          0.25*sqrt(z_up_bnd*z_lo_bnd), ...
          ['epochs: ', int2str(n_fail1)]);
set(HT, 'FontSize', 14);
set(HT,'HorizontalAlignment','Center');
pos = get(HT, 'Position');
pos = pos + [.05 -0.05 0];
set(HT, 'Position', pos);
set(HT, 'Color', color1);
HT = text(0.50*(x_up_bnd - HAL) + HAL, ...
          0.45*(HAL - y_lo_bnd) + y_lo_bnd, ...
          0.25*sqrt(z_up_bnd*z_lo_bnd), ...
          ['epochs: ', int2str(n_fail1)]);
set(HT, 'FontSize', 14);
set(HT,'HorizontalAlignment','Center');

% outline the region of HPL failures
patch([x_lo_bnd HAL HAL], ...
      [y_lo_bnd HAL y_lo_bnd], ...
      -[0.5 0.5 0.5], ...
      color2);
HT = text(0.67*(HAL - x_lo_bnd) + x_lo_bnd, ...
          0.35*(HAL - y_lo_bnd) + y_lo_bnd, ...
          0.25*sqrt(z_up_bnd*z_lo_bnd), ...
          'MI');
set(HT, 'FontSize', 14);
set(HT,'HorizontalAlignment','Center');
pos = get(HT, 'Position');
pos = pos + [.05 -0.05 0];
set(HT, 'Position', pos);
set(HT, 'Color', color2);
HT = text(0.67*(HAL - x_lo_bnd) + x_lo_bnd, ...
          0.35*(HAL - y_lo_bnd) + y_lo_bnd, ...
          0.25*sqrt(z_up_bnd*z_lo_bnd), ...
          'MI');
set(HT, 'FontSize', 14);
set(HT,'HorizontalAlignment','Center');
HT = text(0.67*(HAL - x_lo_bnd) + x_lo_bnd, ...
          0.25*(HAL - y_lo_bnd) + y_lo_bnd, ...
          0.25*sqrt(z_up_bnd*z_lo_bnd), ...
          ['epochs: ', int2str(n_fail2)]);
set(HT, 'FontSize', 14);
set(HT,'HorizontalAlignment','Center');
pos = get(HT, 'Position');
pos = pos + [.05 -0.05 0];
set(HT, 'Position', pos);
set(HT, 'Color', color2);
HT = text(0.67*(HAL - x_lo_bnd) + x_lo_bnd, ...
          0.25*(HAL - y_lo_bnd) + y_lo_bnd, ...
          0.25*sqrt(z_up_bnd*z_lo_bnd), ...
          ['epochs: ', int2str(n_fail2)]);
set(HT, 'FontSize', 14);
set(HT,'HorizontalAlignment','Center');

% outline the region of unavailability
patch([x_lo_bnd x_up_bnd x_up_bnd x_lo_bnd], ...
      [HAL HAL y_up_bnd y_up_bnd], ...
      -[0.5 0.5 0.5 0.5], ...
      color3);
HT = text(0.50*(x_up_bnd - x_lo_bnd) + x_lo_bnd, ...
          0.70*(y_up_bnd - HAL) + HAL, ...
          0.25*sqrt(z_up_bnd*z_lo_bnd), ...
          '{\fontsize{14pt}System Unavailable}');
set(HT,'HorizontalAlignment','Center');
pos = get(HT, 'Position');
pos = pos + [.05 -0.05 0];
set(HT, 'Position', pos);
set(HT, 'Color', color3);
HT = text(0.50*(x_up_bnd - x_lo_bnd) + x_lo_bnd, ...
          0.70*(y_up_bnd - HAL) + HAL, ...
          0.25*sqrt(z_up_bnd*z_lo_bnd), ...
          '{\fontsize{14pt}System Unavailable}');
set(HT,'HorizontalAlignment','Center');
HT = text(0.50*(x_up_bnd - x_lo_bnd) + x_lo_bnd, ...
          0.55*(y_up_bnd - HAL) + HAL, ...
          0.25*sqrt(z_up_bnd*z_lo_bnd), ...
          ['Alarm Epochs: ', int2str(n_cont)]);
set(HT, 'FontSize', 14);
set(HT,'HorizontalAlignment','Center');
pos = get(HT, 'Position');
pos = pos + [.05 -0.05 0];
set(HT, 'Position', pos);
set(HT, 'Color', color3);
HT = text(0.50*(x_up_bnd - x_lo_bnd) + x_lo_bnd, ...
          0.55*(y_up_bnd - HAL) + HAL, ...
          0.25*sqrt(z_up_bnd*z_lo_bnd), ...
          ['Alarm Epochs: ', int2str(n_cont)]);
set(HT, 'FontSize', 14);
set(HT,'HorizontalAlignment','Center');

% outline the region where integrity failures and unavailability overlap
patch([HAL x_up_bnd x_up_bnd], ...
      [HAL y_up_bnd HAL], ...
      -z_lo_bnd*[0.45 0.45 0.45], ...
      color4);
HT = text(0.70*(x_up_bnd - HAL) + HAL, ...
          0.325*(y_up_bnd - HAL) + HAL, ...
          0.25*sqrt(z_up_bnd*z_lo_bnd), ...
          'MI');
set(HT, 'FontSize', 14);
set(HT,'HorizontalAlignment','Center');
pos = get(HT, 'Position');
pos = pos + [.05 -0.05 0];
set(HT, 'Position', pos);
set(HT, 'Color', color4);
HT = text(0.70*(x_up_bnd - HAL) + HAL, ...
          0.325*(y_up_bnd - HAL) + HAL, ...
          0.25*sqrt(z_up_bnd*z_lo_bnd), ...
          'MI');
set(HT, 'FontSize', 14);
set(HT,'HorizontalAlignment','Center');
HT = text(0.70*(x_up_bnd - HAL) + HAL, ...
          0.175*(y_up_bnd - HAL) + HAL, ...
          0.25*sqrt(z_up_bnd*z_lo_bnd), ...
          ['epochs: ', int2str(n_fail3)]);
set(HT, 'FontSize', 14);
set(HT,'HorizontalAlignment','Center');
pos = get(HT, 'Position');
pos = pos + [.05 -0.05 0];
set(HT, 'Position', pos);
set(HT, 'Color', color4);
HT = text(0.70*(x_up_bnd - HAL) + HAL, ...
          0.175*(y_up_bnd - HAL) + HAL, ...
          0.25*sqrt(z_up_bnd*z_lo_bnd), ...
          ['epochs: ', int2str(n_fail3)]);
set(HT, 'FontSize', 14);
set(HT,'HorizontalAlignment','Center');

hold on;
grid off;
% make the grid visible over the patch regions (integrity, unavailability)
ytick  = get(gca,'YTick');
xtick  = get(gca,'XTick');
nytick = length(ytick);
nxtick = length(xtick);
for i = 1:nytick
    plot3([x_lo_bnd x_up_bnd], ytick(i)*[1 1], [0.6 0.6], 'k:');
end
for i = 1:nxtick
    plot3(xtick(i)*[1 1], [y_lo_bnd y_up_bnd], [0.6 0.6], 'k:');
end

% label the axes and add a title
xlabel('{\fontsize{16pt}Error [m]}');
set(get(gca,'XLabel'),'Position', ...
    [ 0.50*(x_up_bnd - x_lo_bnd) + x_lo_bnd, ...
     -0.05*(y_up_bnd - y_lo_bnd) + y_lo_bnd, ...
     z_lo_bnd]);

ylabel(['{\fontsize{16pt}HPL_{',src_name,'} [m]}']);
set(get(gca,'YLabel'),'Position', ...
    [-0.06*(x_up_bnd - x_lo_bnd) + x_lo_bnd, ...
      0.50*(y_up_bnd - y_lo_bnd) + y_lo_bnd z_lo_bnd]);

title (['Horizontal Performance [',int2str(seconds),' seconds]']);

set(get(gca,'Title'),'FontSize',14);
set(get(gca,'Title'),'Position', ...
    [0.50*(x_up_bnd - x_lo_bnd) + x_lo_bnd, ...
     1.02*(y_up_bnd - y_lo_bnd) + y_lo_bnd, ...
     z_lo_bnd]);

% put the sigma_H_major scale on the right hand y-axis
% K_h_pa = 6.18;
% for i = ceil(y_lo_bnd/K_h_pa):floor(y_up_bnd/K_h_pa)
%   if abs(i*K_h_pa - (0.5*(y_up_bnd - y_lo_bnd) + y_lo_bnd)) > ...
%      0.05*(y_up_bnd - y_lo_bnd)
%     plot3([.99*(x_up_bnd - x_lo_bnd) + x_lo_bnd x_up_bnd], ...
%           i*K_h_pa*[1 1], ...
%           [0.65 0.65], ...
%           'k');
%     text(1.02*(x_up_bnd - x_lo_bnd) + x_lo_bnd, i*K_h_pa, 0.65, int2str(i));
%   end
% end
% HT = text(1.04*(x_up_bnd - x_lo_bnd) + x_lo_bnd, ...
%           0.50*(y_up_bnd - y_lo_bnd) + y_lo_bnd, ...
%           0.65, ...
%           '{\fontsize{14pt}\sigma}_{H_{major}} (m)');
% set(HT,'HorizontalAlignment','Center');
% set(HT,'Rotation',90);

% put the color scale up on the right hand side
H = colorbar('vert');
set(get(H,'Ylabel'),'String','{\fontsize{14pt}Number of Points per Pixel}');
%set(H,'YScale','log');
set(H,'YLim',[z_lo_bnd z_up_bnd]);
%set(H,'CLim', [z_lo_bnd z_up_bnd]);

if sec_available == 1
    display (['EGNOS differential for ', ...
              num2str(n_pts), ...
              ' out of ', ...
              num2str(seconds), ...
              ' seconds']);
end

set(H, 'linewidth',.8);
hold off
set(gca,'Fontsize',18);

%print -deps env_HPL

%%%%%%%%%%%% end hplstat.m  %%%%%%%%%%%%%%%%%%%%


function tutorial_fem(tutorial_dir)
% TUTORIAL_FEM: Script that reproduces the online tutorial "FEM tutorial: MEG/EEG Median nerve stimulation"
%
% REFERENCE:
%     https://neuroimage.usc.edu/brainstorm/Tutorials/FemMedianNerve
%
% INPUTS:
%     tutorial_dir: Directory where the sample_fem.zip file has been unzipped

% @=============================================================================
% 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.
% =============================================================================@
%
% Author: Francois Tadel, 2021

% ===== FILES TO IMPORT =====
% You have to specify the folder in which the tutorial dataset is unzipped
if (nargin == 0) || isempty(tutorial_dir) || ~file_exist(tutorial_dir)
    error('The first argument must be the full path to the tutorial dataset folder.');
end
% Build the path of the files to import
T1Nii  = fullfile(tutorial_dir, 'sample_fem', 'sub-fem01', 'ses-mri', 'anat', 'sub-fem01_ses-mri_T1w.nii.gz');
T2Nii  = fullfile(tutorial_dir, 'sample_fem', 'sub-fem01', 'ses-mri', 'anat', 'sub-fem01_ses-mri_T2w.nii.gz');
DwiNii = fullfile(tutorial_dir, 'sample_fem', 'sub-fem01', 'ses-mri', 'dwi', 'sub-fem01_ses-mri_dwi.nii.gz');
DwiBval = fullfile(tutorial_dir, 'sample_fem', 'sub-fem01', 'ses-mri', 'dwi', 'sub-fem01_ses-mri_dwi.bval');
DwiBvec = fullfile(tutorial_dir, 'sample_fem', 'sub-fem01', 'ses-mri', 'dwi', 'sub-fem01_ses-mri_dwi.bvec');
FifFile = fullfile(tutorial_dir, 'sample_fem', 'sub-fem01', 'ses-meg', 'meg', 'sub-fem01_ses-meg_task-mediannerve_run-01_proc-tsss_meg.fif');
% Check if the folder contains the required files
if ~file_exist(T1Nii) || ~file_exist(FifFile)
    error(['The folder ' tutorial_dir ' does not contain the folder from the file sample_fem.zip.']);
end
% Subject name
SubjectName = 'Subject01';
% Latency of interest
Latency = 0.022;

% ===== CHECK SOFTWARE DEPENDENCIES =====
% Start brainstorm without the GUI
if ~brainstorm('status')
    brainstorm nogui
end
% SimNIBS
status = system('headreco --version');
if (status ~= 0)
    error('SimNIBS is not installed or not added to the system path: the command "headreco" could not be found.');
end
% BrainSuite
if ~file_exist(bst_fullfile(bst_get('BrainSuiteDir'), 'bin'))
    error('BrainSuite is not configured in the Brainstorm preferences.');
end
% SPM12
[isInstalled, errMsg] = bst_plugin('Install', 'spm12', 0);
if ~isInstalled
    error(['Could not install plugin: spm12' 10 errMsg]);
end
% CAT12
[isInstalled, errMsg] = bst_plugin('Install', 'cat12', 0);
if ~isInstalled
    error(['Could not install plugin: cat12' 10 errMsg]);
end
% Iso2mesh
[isInstalled, errMsg] = bst_plugin('Install', 'iso2mesh', 0);
if ~isInstalled
    error(['Could not install plugin: iso2mesh' 10 errMsg]);
end

% ===== CREATE PROTOCOL =====
% The protocol name has to be a valid folder name (no spaces, no weird characters...)
ProtocolName = 'TutorialFem';
% Delete existing protocol
gui_brainstorm('DeleteProtocol', ProtocolName);
% Create new protocol
gui_brainstorm('CreateProtocol', ProtocolName, 0, 1);
% Start a new report
bst_report('Start');

%% ===== IMPORT ANATOMY =====
% ===== IMPORT MRI VOLUMES =====
% Create subject
[sSubject, iSubject] = db_add_subject(SubjectName, [], 0, 0);
% Import T1 MRI
T1File = import_mri(iSubject, T1Nii, 'ALL', 0, 0);
% Compute the MNI normalization
bst_normalize_mni(T1File);
% Import T2 MRI
T2File = import_mri(iSubject, T2Nii, 'ALL', 0, 0);
% Volumes are not registered: Register with SPM
mri_coregister(T2File, T1File, 'spm', 1);
% Delete the non-registered T2
file_delete(file_fullpath(T2File), 1);
db_reload_subjects(iSubject);

% ===== IMPORT DTI =====
% Process: Convert DWI to DTI (BrainSuite)
bst_process('CallProcess', 'process_dwi2dti', [], [], ...
    'subjectname', SubjectName, ...
    'dwifile',     {DwiNii, 'DWI-NII'}, ...
    'bvalfile',    {DwiBval, 'DWI-BVAL'}, ...
    'bvecfile',    {DwiBvec, 'DWI-BVEC'});

% ===== RUN SIMNIBS =====
% Process: Generate FEM mesh
bst_process('CallProcess', 'process_fem_mesh', [], [], ...
    'subjectname',   SubjectName, ...
    'method',        'simnibs', ...  % SimNIBS:Call SimNIBS to segment and mesh the T1 (and T2) MRI.
    'vertexdensity', 0.5, ...
    'nvertices',     15000, ...
    'zneck',         0);
% Select default cortex: Low-resolution
[sSubject, iSubject, iCortex] = bst_get('SurfaceFile', bst_fullfile(SubjectName, 'tess_cortex_pial_low.mat'));
db_surface_default(iSubject, 'Cortex', iCortex);

% ===== REMESH WITH ISO2MESH =====
% Part skipped because:
% 1) Not needed: DUNEuro works with cavities in this case
% 2) No process call for: Extract surfaces (import_femlayers)
% 3) Remeshing with iso2mesh doesn't work...

% ===== COMPUTE FEM TENSORS =====
% Process: Compute FEM tensors
bst_process('CallProcess', 'process_fem_tensors', [], [], ...
    'subjectname', SubjectName, ...
    'femcond',     struct(...
         'FemCond',         [0.14, 0.33, 1.79, 0.008, 0.43], ...
         'isIsotropic',     [0, 1, 1, 1, 1], ...
         'AnisoMethod',     'ema+vc', ...
         'SimRatio',        10, ...
         'SimConstrMethod', 'wolters'));

% ===== COMPUTE BEM SURFACES =====
% Process: Generate BEM surfaces
bst_process('CallProcess', 'process_generate_bem', [], [], ...
    'subjectname', SubjectName, ...
    'nscalp',      1922, ...
    'nouter',      1922, ...
    'ninner',      1922, ...
    'thickness',   4);

%% ===== ACCESS THE RECORDINGS =====
% Process: Create link to raw file
sFilesRaw = bst_process('CallProcess', 'process_import_data_raw', [], [], ...
    'subjectname',    SubjectName, ...
    'datafile',       {FifFile, 'FIF'}, ...
    'channelreplace', 0, ...
    'channelalign',   1, ...    % Automatic registration with digitized head points
    'evtmode',        'value');

% Process: Events: Read from channel
sFilesRaw = bst_process('CallProcess', 'process_evt_read', sFilesRaw, [], ...
    'stimchan',  'STI101', ...
    'trackmode', 1, ...  % Value: detect the changes of channel value
    'zero',      0);

% Process: Project electrodes on scalp
bst_process('CallProcess', 'process_channel_project', sFilesRaw, []);

% Process: Snapshot: Sensors/MRI registration
bst_process('CallProcess', 'process_snapshot', sFilesRaw, [], ...
    'target',   1, ...  % Sensors/MRI registration
    'modality', 1, ...  % MEG (All)
    'orient',   1, ...  % left
    'Comment',  'MEG/MRI Registration');
% Process: Snapshot: Sensors/MRI registration
bst_process('CallProcess', 'process_snapshot', sFilesRaw, [], ...
    'target',   1, ...  % Sensors/MRI registration
    'modality', 4, ...  % EEG
    'orient',   1, ...  % left
    'Comment',  'EEG/MRI Registration');

%% ===== PRE-PROCESSING =====
% Process: Power spectrum density (Welch)
sFilesPsd = bst_process('CallProcess', 'process_psd', sFilesRaw, [], ...
    'timewindow',  [18, 148.999], ...
    'win_length',  5, ...
    'win_overlap', 50, ...
    'units',       'physical', ...  % Physical: U2/Hz
    'sensortypes', 'MEG, EEG', ...
    'win_std',     0, ...
    'edit',        struct(...
         'Comment',         'Power', ...
         'TimeBands',       [], ...
         'Freqs',           [], ...
         'ClusterFuncTime', 'none', ...
         'Measure',         'power', ...
         'Output',          'all', ...
         'SaveKernel',      0));

% Process: Snapshot: Frequency spectrum
bst_process('CallProcess', 'process_snapshot', sFilesPsd, [], ...
    'target',   10, ...  % Frequency spectrum
    'Comment',  'Power spectrum density');

% Process: Band-pass:20Hz-250Hz
sFilesBand = bst_process('CallProcess', 'process_bandpass', sFilesRaw, [], ...
    'sensortypes', 'MEG, EEG', ...
    'highpass',    20, ...
    'lowpass',     250, ...
    'tranband',    0, ...
    'attenuation', 'strict', ...  % 60dB
    'ver',         '2019', ...  % 2019
    'mirror',      0, ...
    'read_all',    0);

% Process: Notch filter: 60Hz 120Hz 180Hz
sFilesClean = bst_process('CallProcess', 'process_notch', sFilesBand, [], ...
    'sensortypes', 'MEG, EEG', ...
    'freqlist',    [60, 120, 180], ...
    'cutoffW',     2, ...
    'useold',      0, ...
    'read_all',    0);

% Process: Delete selected files
bst_process('CallProcess', 'process_delete', [sFilesRaw, sFilesBand], [], ...
    'target', 2);  % Delete selected folders

% Process: Re-reference EEG
bst_process('CallProcess', 'process_eegref', sFilesClean, [], ...
    'eegref',      'AVERAGE', ...
    'sensortypes', 'EEG');

%% ===== IMPORT RECORDINGS =====
% Process: Import MEG/EEG: Events
sFilesEpochs = bst_process('CallProcess', 'process_import_data_event', sFilesClean, [], ...
    'subjectname', SubjectName, ...
    'condition',   '', ...
    'eventname',   '2', ...
    'timewindow',  [18, 148.999], ...
    'epochtime',   [-0.1, 0.2], ...
    'createcond',  0, ...
    'ignoreshort', 1, ...
    'usectfcomp',  1, ...
    'usessp',      1, ...
    'freq',        [], ...
    'baseline',    []);

% Process: Average: By trial group (folder average)
sFilesAvg = bst_process('CallProcess', 'process_average', sFilesEpochs, [], ...
    'avgtype',       5, ...  % By trial group (folder average)
    'avg_func',      1, ...  % Arithmetic average:  mean(x)
    'weighted',      0, ...
    'keepevents',    0);

% Process: Snapshot: Recordings time series
bst_process('CallProcess', 'process_snapshot', sFilesAvg, [], ...
    'target',   5, ...  % Recordings time series
    'modality', 4, ...  % EEG
    'Comment',  'EEG ERP');
% Process: Snapshot: Recordings topography (contact sheet)
bst_process('CallProcess', 'process_snapshot', sFilesAvg, [], ...
    'target',   6, ...  % Recordings topography (ont time)
    'modality', 4, ...  % EEG
    'time',     Latency, ...
    'Comment',  'EEG ERP');
% Process: Snapshot: Recordings time series
bst_process('CallProcess', 'process_snapshot', sFilesAvg, [], ...
    'target',   5, ...  % Recordings time series
    'modality', 1, ...  % MEG (All)
    'Comment',  'MEG ERF');
% Process: Snapshot: Recordings topography (contact sheet)
bst_process('CallProcess', 'process_snapshot', sFilesAvg, [], ...
    'target',   6, ...  % Recordings topography (ont time)
    'modality', 1, ...  % MEG (All)
    'time',     Latency, ...
    'Comment',  'MEG ERF');

%% ===== NOISE COVARIANCE =====
% Process: Compute covariance (noise or data)
bst_process('CallProcess', 'process_noisecov', sFilesEpochs, [], ...
    'baseline',       [-0.1, -0.01], ...
    'sensortypes',    'MEG, EEG', ...
    'target',         1, ...  % Noise covariance     (covariance over baseline time window)
    'dcoffset',       1, ...  % Block by block, to avoid effects of slow shifts in data
    'replacefile',    1);  % Replace

%% ===== FORWARD: FEM EEG DTI =====
% Process: Compute head model
bst_process('CallProcess', 'process_headmodel', sFilesAvg, [], ...
    'Comment',     'DUNEuro FEM EEG DTI', ...
    'sourcespace', 1, ...  % Cortex surface
    'meg',         1, ...  %
    'eeg',         4, ...  % DUNEuro FEM
    'ecog',        1, ...  %
    'seeg',        1, ...  %
    'duneuro',     struct(...
         'FemCond',             [], ...
         'FemSelect',           [1, 1, 1, 1, 1], ...
         'UseTensor',           1, ...
         'Isotropic',           1, ...
         'SrcShrink',           0, ...
         'SrcForceInGM',        0, ...
         'FemType',             'fitted', ...
         'SolverType',          'cg', ...
         'GeometryAdapted',     0, ...
         'Tolerance',           1e-08, ...
         'ElecType',            'normal', ...
         'MegIntorderadd',      0, ...
         'MegType',             'physical', ...
         'SolvSolverType',      'cg', ...
         'SolvPrecond',         'amg', ...
         'SolvSmootherType',    'ssor', ...
         'SolvIntorderadd',     0, ...
         'DgSmootherType',      'ssor', ...
         'DgScheme',            'sipg', ...
         'DgPenalty',           20, ...
         'DgEdgeNormType',      'houston', ...
         'DgWeights',           1, ...
         'DgReduction',         1, ...
         'SolPostProcess',      1, ...
         'SolSubstractMean',    0, ...
         'SolSolverReduction',  1e-10, ...
         'SrcModel',            'venant', ...
         'SrcIntorderadd',      0, ...
         'SrcIntorderadd_lb',   2, ...
         'SrcNbMoments',        3, ...
         'SrcRefLen',           20, ...
         'SrcWeightExp',        1, ...
         'SrcRelaxFactor',      6, ...
         'SrcMixedMoments',     1, ...
         'SrcRestrict',         1, ...
         'SrcInit',             'closest_vertex', ...
         'BstSaveTransfer',     0, ...
         'BstEegTransferFile',  'eeg_transfer.dat', ...
         'BstMegTransferFile',  'meg_transfer.dat', ...
         'BstEegLfFile',        'eeg_lf.dat', ...
         'BstMegLfFile',        'meg_lf.dat', ...
         'UseIntegrationPoint', 1, ...
         'EnableCacheMemory',   0, ...
         'MegPerBlockOfSensor', 0), ...
    'channelfile', '');
% Process: Compute sources [2018]
sSrcEegFemDti = bst_process('CallProcess', 'process_inverse_2018', sFilesAvg, [], ...
    'output',  1, ...  % Kernel only: shared
    'inverse', struct(...
         'Comment',        'Dipoles: EEG FEM DTI', ...
         'InverseMethod',  'gls', ...
         'InverseMeasure', 'performance', ...
         'SourceOrient',   {{'free'}}, ...
         'Loose',          0.2, ...
         'UseDepth',       1, ...
         'WeightExp',      0.5, ...
         'WeightLimit',    10, ...
         'NoiseMethod',    'median', ...
         'NoiseReg',       0.1, ...
         'SnrMethod',      'rms', ...
         'SnrRms',         1e-06, ...
         'SnrFixed',       3, ...
         'ComputeKernel',  1, ...
         'DataTypes',      {{'EEG'}}));
% Process: Dipole scanning
sDipEegFemDti = bst_process('CallProcess', 'process_dipole_scanning', sSrcEegFemDti, [], ...
    'timewindow', [Latency, Latency], ...
    'scouts',     {});

%% ===== FORWARD: FEM MEG DTI =====
% Process: Compute head model
bst_process('CallProcess', 'process_headmodel', sFilesAvg, [], ...
    'Comment',     'DUNEuro FEM MEG DTI', ...
    'sourcespace', 1, ...  % Cortex surface
    'meg',         5, ...  % DUNEuro FEM
    'eeg',         1, ...  %
    'ecog',        1, ...  %
    'seeg',        1, ...  %
    'duneuro',     struct(...
         'FemCond',             [], ...
         'FemSelect',           [1, 1, 1, 0, 0], ...
         'UseTensor',           1, ...
         'Isotropic',           1, ...
         'SrcShrink',           0, ...
         'SrcForceInGM',        0, ...
         'FemType',             'fitted', ...
         'SolverType',          'cg', ...
         'GeometryAdapted',     0, ...
         'Tolerance',           1e-08, ...
         'ElecType',            'normal', ...
         'MegIntorderadd',      0, ...
         'MegType',             'physical', ...
         'SolvSolverType',      'cg', ...
         'SolvPrecond',         'amg', ...
         'SolvSmootherType',    'ssor', ...
         'SolvIntorderadd',     0, ...
         'DgSmootherType',      'ssor', ...
         'DgScheme',            'sipg', ...
         'DgPenalty',           20, ...
         'DgEdgeNormType',      'houston', ...
         'DgWeights',           1, ...
         'DgReduction',         1, ...
         'SolPostProcess',      1, ...
         'SolSubstractMean',    0, ...
         'SolSolverReduction',  1e-10, ...
         'SrcModel',            'venant', ...
         'SrcIntorderadd',      0, ...
         'SrcIntorderadd_lb',   2, ...
         'SrcNbMoments',        3, ...
         'SrcRefLen',           20, ...
         'SrcWeightExp',        1, ...
         'SrcRelaxFactor',      6, ...
         'SrcMixedMoments',     1, ...
         'SrcRestrict',         1, ...
         'SrcInit',             'closest_vertex', ...
         'BstSaveTransfer',     0, ...
         'BstEegTransferFile',  'eeg_transfer.dat', ...
         'BstMegTransferFile',  'meg_transfer.dat', ...
         'BstEegLfFile',        'eeg_lf.dat', ...
         'BstMegLfFile',        'meg_lf.dat', ...
         'UseIntegrationPoint', 1, ...
         'EnableCacheMemory',   0, ...
         'MegPerBlockOfSensor', 0), ...
    'channelfile', '');
% Process: Compute sources [2018]
sSrcMegFemDti = bst_process('CallProcess', 'process_inverse_2018', sFilesAvg, [], ...
    'output',  1, ...  % Kernel only: shared
    'inverse', struct(...
         'Comment',        'Dipoles: MEG FEM DTI', ...
         'InverseMethod',  'gls', ...
         'InverseMeasure', 'performance', ...
         'SourceOrient',   {{'free'}}, ...
         'Loose',          0.2, ...
         'UseDepth',       1, ...
         'WeightExp',      0.5, ...
         'WeightLimit',    10, ...
         'NoiseMethod',    'median', ...
         'NoiseReg',       0.1, ...
         'SnrMethod',      'rms', ...
         'SnrRms',         1e-06, ...
         'SnrFixed',       3, ...
         'ComputeKernel',  1, ...
         'DataTypes',      {{'MEG GRAD', 'MEG MAG'}}));
% Process: Dipole scanning
sDipMegFemDti = bst_process('CallProcess', 'process_dipole_scanning', sSrcMegFemDti, [], ...
    'timewindow', [Latency, Latency], ...
    'scouts',     {});

%% ===== FORWARD: FEM EEG ISO =====
% Get updated subject structure
sSubject = bst_get('Subject', iSubject);
% Get FEM file
FemFile = file_fullpath(sSubject.Surface(sSubject.iFEM).FileName);
% Remove tensors
process_fem_tensors('ClearTensors', FemFile);
% Process: Compute head model
bst_process('CallProcess', 'process_headmodel', sFilesAvg, [], ...
    'Comment',     'DUNEuro FEM EEG ISO', ...
    'sourcespace', 1, ...  % Cortex surface
    'meg',         1, ...  %
    'eeg',         4, ...  % DUNEuro FEM
    'ecog',        1, ...  %
    'seeg',        1, ...  %
    'duneuro',     struct(...
         'FemCond',             [0.14, 0.33, 1.79, 0.008, 0.43], ...
         'FemSelect',           [1, 1, 1, 1, 1], ...
         'UseTensor',           0, ...
         'Isotropic',           1, ...
         'SrcShrink',           0, ...
         'SrcForceInGM',        0, ...
         'FemType',             'fitted', ...
         'SolverType',          'cg', ...
         'GeometryAdapted',     0, ...
         'Tolerance',           1e-08, ...
         'ElecType',            'normal', ...
         'MegIntorderadd',      0, ...
         'MegType',             'physical', ...
         'SolvSolverType',      'cg', ...
         'SolvPrecond',         'amg', ...
         'SolvSmootherType',    'ssor', ...
         'SolvIntorderadd',     0, ...
         'DgSmootherType',      'ssor', ...
         'DgScheme',            'sipg', ...
         'DgPenalty',           20, ...
         'DgEdgeNormType',      'houston', ...
         'DgWeights',           1, ...
         'DgReduction',         1, ...
         'SolPostProcess',      1, ...
         'SolSubstractMean',    0, ...
         'SolSolverReduction',  1e-10, ...
         'SrcModel',            'venant', ...
         'SrcIntorderadd',      0, ...
         'SrcIntorderadd_lb',   2, ...
         'SrcNbMoments',        3, ...
         'SrcRefLen',           20, ...
         'SrcWeightExp',        1, ...
         'SrcRelaxFactor',      6, ...
         'SrcMixedMoments',     1, ...
         'SrcRestrict',         1, ...
         'SrcInit',             'closest_vertex', ...
         'BstSaveTransfer',     0, ...
         'BstEegTransferFile',  'eeg_transfer.dat', ...
         'BstMegTransferFile',  'meg_transfer.dat', ...
         'BstEegLfFile',        'eeg_lf.dat', ...
         'BstMegLfFile',        'meg_lf.dat', ...
         'UseIntegrationPoint', 1, ...
         'EnableCacheMemory',   0, ...
         'MegPerBlockOfSensor', 0), ...
    'channelfile', '');
% Process: Compute sources [2018]
sSrcEegFemIso = bst_process('CallProcess', 'process_inverse_2018', sFilesAvg, [], ...
    'output',  1, ...  % Kernel only: shared
    'inverse', struct(...
         'Comment',        'Dipoles: EEG FEM ISO', ...
         'InverseMethod',  'gls', ...
         'InverseMeasure', 'performance', ...
         'SourceOrient',   {{'free'}}, ...
         'Loose',          0.2, ...
         'UseDepth',       1, ...
         'WeightExp',      0.5, ...
         'WeightLimit',    10, ...
         'NoiseMethod',    'median', ...
         'NoiseReg',       0.1, ...
         'SnrMethod',      'rms', ...
         'SnrRms',         1e-06, ...
         'SnrFixed',       3, ...
         'ComputeKernel',  1, ...
         'DataTypes',      {{'EEG'}}));
% Process: Dipole scanning
sDipEegFemIso = bst_process('CallProcess', 'process_dipole_scanning', sSrcEegFemIso, [], ...
    'timewindow', [Latency, Latency], ...
    'scouts',     {});

%% ===== FORWARD: FEM MEG ISO =====
% Process: Compute head model
bst_process('CallProcess', 'process_headmodel', sFilesAvg, [], ...
    'Comment',     'DUNEuro FEM MEG ISO', ...
    'sourcespace', 1, ...  % Cortex surface
    'meg',         5, ...  % DUNEuro FEM
    'eeg',         1, ...  %
    'ecog',        1, ...  %
    'seeg',        1, ...  %
    'duneuro',     struct(...
         'FemCond',             [0.14, 0.33, 1.79, 0.008, 0.43], ...
         'FemSelect',           [1, 1, 1, 0, 0], ...
         'UseTensor',           0, ...
         'Isotropic',           1, ...
         'SrcShrink',           0, ...
         'SrcForceInGM',        0, ...
         'FemType',             'fitted', ...
         'SolverType',          'cg', ...
         'GeometryAdapted',     0, ...
         'Tolerance',           1e-08, ...
         'ElecType',            'normal', ...
         'MegIntorderadd',      0, ...
         'MegType',             'physical', ...
         'SolvSolverType',      'cg', ...
         'SolvPrecond',         'amg', ...
         'SolvSmootherType',    'ssor', ...
         'SolvIntorderadd',     0, ...
         'DgSmootherType',      'ssor', ...
         'DgScheme',            'sipg', ...
         'DgPenalty',           20, ...
         'DgEdgeNormType',      'houston', ...
         'DgWeights',           1, ...
         'DgReduction',         1, ...
         'SolPostProcess',      1, ...
         'SolSubstractMean',    0, ...
         'SolSolverReduction',  1e-10, ...
         'SrcModel',            'venant', ...
         'SrcIntorderadd',      0, ...
         'SrcIntorderadd_lb',   2, ...
         'SrcNbMoments',        3, ...
         'SrcRefLen',           20, ...
         'SrcWeightExp',        1, ...
         'SrcRelaxFactor',      6, ...
         'SrcMixedMoments',     1, ...
         'SrcRestrict',         1, ...
         'SrcInit',             'closest_vertex', ...
         'BstSaveTransfer',     0, ...
         'BstEegTransferFile',  'eeg_transfer.dat', ...
         'BstMegTransferFile',  'meg_transfer.dat', ...
         'BstEegLfFile',        'eeg_lf.dat', ...
         'BstMegLfFile',        'meg_lf.dat', ...
         'UseIntegrationPoint', 1, ...
         'EnableCacheMemory',   0, ...
         'MegPerBlockOfSensor', 0), ...
    'channelfile', '');
% Process: Compute sources [2018]
sSrcMegFemIso = bst_process('CallProcess', 'process_inverse_2018', sFilesAvg, [], ...
    'output',  1, ...  % Kernel only: shared
    'inverse', struct(...
         'Comment',        'Dipoles: MEG FEM ISO', ...
         'InverseMethod',  'gls', ...
         'InverseMeasure', 'performance', ...
         'SourceOrient',   {{'free'}}, ...
         'Loose',          0.2, ...
         'UseDepth',       1, ...
         'WeightExp',      0.5, ...
         'WeightLimit',    10, ...
         'NoiseMethod',    'median', ...
         'NoiseReg',       0.1, ...
         'SnrMethod',      'rms', ...
         'SnrRms',         1e-06, ...
         'SnrFixed',       3, ...
         'ComputeKernel',  1, ...
         'DataTypes',      {{'MEG GRAD', 'MEG MAG'}}));
% Process: Dipole scanning
sDipMegFemIso = bst_process('CallProcess', 'process_dipole_scanning', sSrcMegFemIso, [], ...
    'timewindow', [Latency, Latency], ...
    'scouts',     {});

%% ===== FORWARD: BEM EEG =====
% Process: Compute head model
bst_process('CallProcess', 'process_headmodel', sFilesAvg, [], ...
    'Comment',     'OpenMEEG BEM EEG', ...
    'sourcespace', 1, ...  % Cortex surface
    'meg',         1, ...  %
    'eeg',         3, ...  % OpenMEEG BEM
    'ecog',        1, ...  %
    'seeg',        1, ...  %
    'openmeeg',    struct(...
         'BemSelect',    [1, 1, 1], ...
         'BemCond',      [1, 0.0125, 1], ...
         'BemNames',     {{'Scalp', 'Skull', 'Brain'}}, ...
         'BemFiles',     {{}}, ...
         'isAdjoint',    0, ...
         'isAdaptative', 1, ...
         'isSplit',      0, ...
         'SplitLength',  4000), ...
    'channelfile', '');
% Process: Compute sources [2018]
sSrcEegBem = bst_process('CallProcess', 'process_inverse_2018', sFilesAvg, [], ...
    'output',  1, ...  % Kernel only: shared
    'inverse', struct(...
         'Comment',        'Dipoles: EEG BEM', ...
         'InverseMethod',  'gls', ...
         'InverseMeasure', 'performance', ...
         'SourceOrient',   {{'free'}}, ...
         'Loose',          0.2, ...
         'UseDepth',       1, ...
         'WeightExp',      0.5, ...
         'WeightLimit',    10, ...
         'NoiseMethod',    'median', ...
         'NoiseReg',       0.1, ...
         'SnrMethod',      'rms', ...
         'SnrRms',         1e-06, ...
         'SnrFixed',       3, ...
         'ComputeKernel',  1, ...
         'DataTypes',      {{'EEG'}}));
% Process: Dipole scanning
sDipEegBem = bst_process('CallProcess', 'process_dipole_scanning', sSrcEegBem, [], ...
    'timewindow', [Latency, Latency], ...
    'scouts',     {});

%% ===== FORWARD: OS MEG =====
% Process: Compute head model
bst_process('CallProcess', 'process_headmodel', sFilesAvg, [], ...
    'Comment',     'OS MEG', ...
    'sourcespace', 1, ...  % Cortex surface
    'meg',         3, ...  % Overlapping spheres
    'eeg',         1, ...  %
    'ecog',        1, ...  %
    'seeg',        1, ...  %
    'channelfile', '');
% Process: Compute sources [2018]
sSrcMegOs = bst_process('CallProcess', 'process_inverse_2018', sFilesAvg, [], ...
    'output',  1, ...  % Kernel only: shared
    'inverse', struct(...
         'Comment',        'Dipoles: MEG OS', ...
         'InverseMethod',  'gls', ...
         'InverseMeasure', 'performance', ...
         'SourceOrient',   {{'free'}}, ...
         'Loose',          0.2, ...
         'UseDepth',       1, ...
         'WeightExp',      0.5, ...
         'WeightLimit',    10, ...
         'NoiseMethod',    'median', ...
         'NoiseReg',       0.1, ...
         'SnrMethod',      'rms', ...
         'SnrRms',         1e-06, ...
         'SnrFixed',       3, ...
         'ComputeKernel',  1, ...
         'DataTypes',      {{'MEG GRAD', 'MEG MAG'}}));
% Process: Dipole scanning
sDipMegOs = bst_process('CallProcess', 'process_dipole_scanning', sSrcMegOs, [], ...
    'timewindow', [Latency, Latency], ...
    'scouts',     {});

%% ===== MERGE DIPOLES =====
% sDipEegFemDti, sDipMegFemDti, sDipEegFemIso, sDipMegFemIso, sDipEegBem, sDipMegOs
% FEM DTI: EEG vs MEG
% sDipFemDti = dipoles_merge({sDipEegFemDti.FileName, sDipMegFemDti.FileName});

% Save and display report
ReportFile = bst_report('Save', []);
bst_report('Open', ReportFile);


function a2hbc_examples()
%%%%%%%%%%%%%%%%%%%%%%%%
% Examples using a2hbc %
%%%%%%%%%%%%%%%%%%%%%%%%
%
a2hbc_root_path = [fileparts(mfilename('fullpath')) filesep];

% Here you have several examples using a2hbc from the command line.

%% MIT format

% To warm up you can start using the automatic mode.

a2hbc( ...
    'recording_name', [ a2hbc_root_path '..' filesep 'example recordings' filesep '208.dat'], ...
    'recording_format', 'MIT', ...
    'op_mode', 'auto');

keyboard

% then you can try the semi-assisted mode, the algorithm only ask you for
% help when it doubts about a cluster label.

a2hbc( ...
    'recording_name', [ a2hbc_root_path '..' filesep 'example recordings' filesep '208.dat'], ...
    'recording_format', 'MIT', ...
    'op_mode', 'slightly-assisted');   % <----

keyboard

% or the assisted mode. In this case, the algorithms always ask you to
% label each cluster found.

a2hbc( ...
    'recording_name', [ a2hbc_root_path '..' filesep 'example recordings' filesep '208.dat'], ...
    'recording_format', 'MIT', ...
    'op_mode', 'assisted');           % <----

keyboard

% if you want you can control some parameters of the algorithm, as the
% number of clusters to look for.

a2hbc( ...
    'recording_name', [ a2hbc_root_path '..' filesep 'example recordings' filesep '208.dat'], ...
    'recording_format', 'MIT', ...
    'NumOfClusters', 3, ...          % <----
    'op_mode', 'assisted');

keyboard

% After the processing if you want to continue tunning up some parameters
% you can try this in order to use the GUI.

a2hbc( ...
    'recording_name', [ a2hbc_root_path '..' filesep 'example recordings' filesep '208.dat'], ...
    'recording_format', 'MIT', ...
    'NumOfClusters', 3, ...
    'InteractiveMode', true, ...      % <----
    'op_mode', 'assisted');

keyboard

%% Other formats, ISHNE

%% Other formats, AHA


function camd_make
%CAMD_MAKE to compile camd for use in MATLAB
%
% Example:
%   camd_make
%
% See also camd.

% Copyright 1994-2007, Tim Davis, University of Florida,
% Patrick R. Amestoy, Iain S. Duff, and Yanqing Chen.

details = 0 ;	    % 1 if details of each command are to be printed

d = '' ;
if (~isempty (strfind (computer, '64')))
    d = '-largeArrayDims' ;
end

i = sprintf ('-I..%sInclude -I..%s..%sUFconfig', filesep, filesep, filesep) ;
cmd = sprintf ('mex -O %s -DDLONG -output camd %s camd_mex.c', d, i) ;
files = {'camd_order', 'camd_dump', 'camd_postorder', ...
    'camd_aat', 'camd_2', 'camd_1', 'camd_defaults', 'camd_control', ...
    'camd_info', 'camd_valid', 'camd_global', 'camd_preprocess' } ;
for i = 1 : length (files)
    cmd = sprintf ('%s ..%sSource%s%s.c', cmd, filesep, filesep, files {i}) ;
end
if (details)
    fprintf ('%s\n', cmd) ;
end
eval (cmd) ;

fprintf ('CAMD successfully compiled.\n') ;


function v = subSet(v,ind)
% subindex vector3d

v.x = v.x(ind);
v.y = v.y(ind);
v.z = v.z(ind);

end


function out = ne( a,b )
%ne (~=) for nested cell arrays
%
% (c) Thomas Kuestner
% ---------------------------------------------------------------------

% determine input types
inType = {class(a), class(b)};
if(strcmp(inType{1},'TRAFO') && strcmp(inType{2},'TRAFO'))
    [outA, idx] = flattenCellMatrix(a.data);
    [outB, idxB] = flattenCellMatrix(b.data);
    meta = a.meta;
    meta_b = b.meta;
    clear 'a' 'b'
    out = false;

    if(~all(cellfun(@(x,y) isequal(x,y), idx, idxB)))
        error('TRAFO::ne: Nested cells must have the same size');
    end
    if (iscell(meta) && iscell(meta_b))
        if(~isempty(meta) && ~isempty(meta_b)) % unequal reconstruction information can happen -> this is what we are interested in to check
            if(iscell(meta{1}) && iscell(meta_b{1}))
                if(~all(cellfun(@(x,y) isequal(x,y), flattenCellMatrix(meta), flattenCellMatrix(meta_b))))
                    out = true;
    %                 error('TRAFO::ne: Unequal reconstruction information');
                end
            else
                if(~all(cellfun(@(x,y) isequal(x,y), meta, meta_b)))
                    out = true;
    %                 error('TRAFO::ne: Unequal reconstruction information');
                end
            end
        end
        out = all(cellfun(@(x,y) ~isequal(x,y), outA, outB)) | out;
    else
        if(~isequal(meta, meta_b))
            out = true; % can not be the same, because the size of the original image stored as meta info is different
        else
            out = all(cellfun(@(x,y) ~isequal(x,y), outA, outB)) | out; %check if entries are the same
        end
    end

elseif(strcmp(inType{1},'TRAFO')) % assume b is double/uint/int
    [out, ~] = flattenCellMatrix(a.data);
%     meta = a.meta;
    clear 'a'

    out = all(cellfun(@(x) ~isequal(x,b), out));

elseif(strcmp(inType{2},'TRAFO'))
    [out, ~] = flattenCellMatrix(b.data);
%     meta = b.meta;
    clear 'b'

    out = all(cellfun(@(x) ~isequal(a,x), out));

else
    error('TRAFO::ne: Impossible constellation!');
end

end


%% Read the images.

% J = load('/home/mayank/Work/FlyBowl/newfeatures_walk_2.jab','-mat');
%
% count = zeros(1,2);
% for ndxx = 1:numel(J.x.labels.t0s)
%   for bout = 1:numel(J.x.labels.t0s{ndxx})
%     if J.x.labels.t1s{ndxx}(bout)>1000, continue;end
%     fly = J.x.labels.flies(ndxx);
%     frames = J.x.labels.t0s{ndxx}(bout):J.x.labels.t1s{ndxx}(bout)-1;
%     bothim = {};
%     for tt = 1:2
%       if tt ==1
%         expdir = '/home/mayank/Work/FlySpaceTime/walkMovies/SS03500_test';
%         ftrname = 'DSs';
%       else
%         expdir = '/home/mayank/Work/FlySpaceTime/walkMovies/SS03500';
%         ftrname = 'hs_sups';
%       end

%%
clear tt;
expdir = '/home/mayank/Work/FlySpaceTime/walkMovies/SS03500_test';
ftrname = 'DSs';
% fly = 2;
% frames = 51:200;
fly = 4;
frames = 3342:3353;
% frames = 3532:3543;
% selftrs = [6 7 1; 2 4 1; 6 3 1];
selftrs = [3 7 1; 6 5 1; 3 3 1];
savefigure = false;

%% params.
params = getParams;
npatches = params.npatches;
psize = params.psize;
nbins = params.nbins;
patchsz = params.patchsz;
scale = params.scale;

optflowwinsig = params.optflowwinsig ;
optflowsig = params.optflowsig ;
optreliability = params.optreliability ;

maxflow = 5;
fly_thres = 90;
flow_thres = sqrt(2)/4;

[~,expname] = fileparts(expdir);
moviefilestr = 'movie.ufmf';
moviefile = fullfile(expdir,moviefilestr);
trxfilestr = 'trx.mat';
trxfile = fullfile(expdir,trxfilestr);

[readframe,nframes] = get_readframe_fcn(moviefile);
td = load(trxfile);
tracks = td.trx;
dx = []; dy = [];
theta = [];
rdx = [];rdy = [];
im1 = []; im2 = []; im3 = [];
for i = 1:numel(frames),
  curf = readframe(frames(i));
  nextf = readframe(frames(i)+1);

  trackndx = frames(i) - tracks(fly).firstframe + 1;
  locy = round(tracks(fly).y(trackndx));
  locx = round(tracks(fly).x(trackndx));
  curpatch = extractPatch(curf,...
    locy,locx,tracks(fly).theta(trackndx),patchsz);
  locy = round(tracks(fly).y(trackndx+1));
  locx = round(tracks(fly).x(trackndx+1));
  curpatch2 = extractPatch(nextf,...
    locy,locx,tracks(fly).theta(trackndx+1),patchsz);

  curpatch3 = extractPatch(nextf,...
    locy,locx,tracks(fly).theta(trackndx),patchsz);

  im1(:,:,i) = curpatch;
  im2(:,:,i) = curpatch2;
  im3(:,:,i) = curpatch3;
  dx(i) = round(tracks(fly).x(trackndx+1))-round(tracks(fly).x(trackndx));
  dy(i) = round(tracks(fly).y(trackndx+1))-round(tracks(fly).y(trackndx));
  rdx(i) = tracks(fly).x(trackndx+1)-tracks(fly).x(trackndx)-dx(i);
  rdy(i) = tracks(fly).y(trackndx+1)-tracks(fly).y(trackndx)-dy(i);
  dtheta(i) = tracks(fly).theta(trackndx+1)-tracks(fly).theta(trackndx);
  theta(i) = tracks(fly).theta(trackndx);
end

[nr,nc,~] = size(im1);
%
% figure out the histogram bins
tmptheta = (0:179)*pi/180;
res = nan(nbins,numel(tmptheta));
m = single(ones(10,10));
o = single(zeros(10,10));
for i = 1:numel(tmptheta),
%   fprintf('i = %d, theta = %f\n',i,tmptheta(i));
  o(:) = single(tmptheta(i));
  rescurr = gradientHist(m,o,1,nbins,1);
  res(:,i) = rescurr(1,1,:);
end

bincenters = nan(1,nbins);
for i = 1:nbins,
  bincenters(i) = tmptheta(argmax(res(i,:)));
end

% this seems to be what the centers correspond to
bincenters = linspace(0,pi,nbins+1);
bincenters = bincenters(1:nbins);

% mayank divides by 2
bincenters2 = bincenters*2;
dt = mean(diff(bincenters2));
binedges2 = [bincenters2(1)-dt/2,(bincenters2(1:end-1)+bincenters2(2:end))/2,bincenters2(end)+dt/2];

%% Read the features;

ftrVal = [];
for ndx = 1:size(selftrs,1)
  curname = sprintf('%s_%02d_%02d_%d.mat',ftrname,...
    selftrs(ndx,1),selftrs(ndx,2),selftrs(ndx,3));
  Q = load(fullfile(expdir,'perframe',curname));
  startndx = frames(1)-tracks(fly).firstframe+1;
  endndx  = frames(end)-tracks(fly).firstframe+1;
  ftrVal(ndx,:) = Q.data{fly}(startndx:endndx);
end
maxval = 2;
ftrVal(ftrVal>maxval) = maxval;
%% Visualize

minImg = min(im1,[],3);

nftrs = size(selftrs,1);
padsz = 50; margin = 4;
tsz = (padsz-2*margin)/nftrs;
padImg = padgrab(minImg,255,1,nc+padsz,1,nr,1,size(minImg,3));

if exist('tt','var')
  ff = figure(104+tt);
else
  ff = figure;
end
imshow(uint8(imresize(padImg,scale)));hold on;

xidx = linspace(margin,nc-margin,numel(frames));
cc = hsv(nftrs);
for ndx = 1:nftrs
  ybase = nc + (padsz-margin)/nftrs*ndx;

  plot(xidx*scale,(ybase-ftrVal(ndx,:)*tsz/maxval)*scale,'Color',cc(ndx,:));
  px = [0 psize psize 0 0] + (selftrs(ndx,2)-1)*psize;
  py = [0 0 psize psize 0] + (selftrs(ndx,1)-1)*psize;
  patch(px*scale,py*scale,cc(ndx,:),'FaceColor',cc(ndx,:),'FaceAlpha',0.075,'LineStyle','none');
end

for ndx = 1:npatches-1
  plot([0.5 nr*scale+0.5],[ndx*psize ndx*psize]*scale,'y');
  plot([ndx*psize ndx*psize]*scale,[0.5 nr*scale+0.5],'y');

end

% fd = getframe(ff);
% bothim{tt} = fd.cdata;
%%
%     end
%
%     if savefigure,
%       outimgname = sprintf('%s_%s_Fly%d_From%dTo%d_%s.png',...
%         J.x.labels.names{ndxx}{bout},...
%         expname,fly,frames(1),frames(end),...
%         datestr(now,'yyyymmdd'));
%       outname = fullfile('..','figures',outimgname);
%       imwrite(cat(2,bothim{1},bothim{2}),outname);
%     end
%
%   end
% end


function output = vbmc_output(vp,optimState,msg,stats,idx_best,vbmc_version)
%VBMC_OUTPUT Create OUTPUT struct for VBMC.

output.function = func2str(optimState.fun);
if all(isinf(optimState.LB)) && all(isinf(optimState.UB))
    output.problemtype = 'unconstrained';
else
    output.problemtype = 'boundconstraints';
end
output.iterations = optimState.iter;
output.funccount = optimState.funccount;
output.bestiter = idx_best;
output.trainsetsize = stats.Neff(idx_best);
output.components = vp.K;
output.rindex = stats.rindex(idx_best);
if stats.stable(idx_best)
    output.convergencestatus = 'probable';
else
    output.convergencestatus = 'no';
end
output.overhead = NaN;
output.rngstate = rng;
output.algorithm = 'Variational Bayesian Monte Carlo';
output.version = vbmc_version;
output.message = msg;

output.elbo = vp.stats.elbo;
output.elbo_sd = vp.stats.elbo_sd;

end


function [keypointsAll, imgidxs_missing]= det2keypointsImgMulticutBBoxMulti(expidx,parts,annolist_bbox,bDisjoint)

fprintf('det2keypointsImgMulticutBBoxMulti()\n');

if (nargin < 4)
    bDisjoint = false;
end

p = exp_params(expidx);

multicutDir = p.multicutDir;
cidxs = p.cidxs;
keypointsAll = [];

if (isfield(p,'nPeopleMax'))
    nPeopleMax = p.nPeopleMax;
else
    nPeopleMax = inf;
end

if (isfield(p,'nPeopleMin'))
    nPeopleMin = p.nPeopleMin;
else
    nPeopleMin = 0;
end

load(p.testGT,'annolist');

assert(length(annolist) == length(annolist_bbox));

nmissing = 0;
bVis = false;
imgidxs_missing = [];

for imgidx = 1:length(annolist_bbox)

    fprintf('.');
    fname = [multicutDir '/imgidx_' padZeros(num2str(imgidx),4) '_cidx_' num2str(cidxs(1)) '_' num2str(cidxs(end))];

    try
        assert(length(annolist(imgidx).annorect) >= nPeopleMin && ...
            length(annolist(imgidx).annorect) <= nPeopleMax);
        load(fname,'unLab','unPos','unProb');
    catch
        for i = 1:length(p.pidxs)
            pidx = p.pidxs(i);
            jidx = parts(pidx+1).pos(1);
            keypointsAll(imgidx).det{1}{jidx+1} = [];
        end
        imgidxs_missing = [imgidxs_missing; imgidx];
        nmissing = nmissing + 1;
        if (~mod(imgidx,100))
            fprintf(' %d/%d\n',imgidx,length(annolist_bbox));
        end
        continue;
    end

    for ridx = 1:length(annolist_bbox(imgidx).annorect)

        bbox = annolist_bbox(imgidx).annorect(ridx).bbox;
        if (~isempty(bbox))
            idxs = find((unPos(:,1) >= bbox(1) & unPos(:,2) >= bbox(2) & ...
                unPos(:,1) <= bbox(3) & unPos(:,2) <= bbox(4)));

            for i = 1:length(p.pidxs)
                pidx = p.pidxs(i);
                assert(parts(pidx+1).pos(1) == parts(pidx+1).pos(2));
                jidx = parts(pidx+1).pos(1);
                det = [];
                id = find(cidxs == i);
                if (~isempty(id))
                    [val,idx] = max(unProb(idxs,id));
                    det = [unPos(idxs(idx),:) val];
                    if (bDisjoint)
                        unProb(idxs(idx),:) = -inf;
                    end
                end
                keypointsAll(imgidx).det{ridx}{jidx+1} = det;
            end
        else
            for i = 1:length(p.pidxs)
                pidx = p.pidxs(i);
                assert(parts(pidx+1).pos(1) == parts(pidx+1).pos(2));
                jidx = parts(pidx+1).pos(1);
                keypointsAll(imgidx).det{ridx}{jidx+1} = [];
            end
        end
    end

    if (bVis)
        colors = {'r','g','b','c','m','y'};
        markers = {'+','o','s'}; %,'x','.','-','s','d'
        img = imread(annolist_bbox(imgidx).image.name);
        figure(100); clf; imagesc(img); axis equal; hold on;
        for j = 1:length(keypointsAll(imgidx).det)
            labels = cell(0);
            n = 0;
            points = zeros(1,2);
            for i = 1:length(p.pidxs)
                pidx = p.pidxs(i);
                jidx = parts(pidx+1).pos(1);
                pp = keypointsAll(imgidx).det{j}{jidx+1};
                if (~isempty(pp))
                    n = n  + 1;
                    labels{n} = num2str(i);
%                     labels{n} = sprintf('%1.2f',pp(3));
                    points(n,:) = pp(1:2);
                end
            end
            lp = j;
            if (lp <= 5)
                m = markers{1};
            elseif (lp > 5 && lp <= 11)
                m = markers{2};
            else
                m = markers{3};
            end
            plot(points(:,1),points(:,2),[colors{mod(lp,6)+1} m],'MarkerSize',5);
            text(points(:,1)+10,points(:,2),labels,'FontSize',6,'BackgroundColor','w');
            axis off;
        end
    end

    if (~mod(imgidx, 100))
        fprintf(' %d/%d\n',imgidx,length(annolist_bbox));
    end
end
fprintf(' done\n');
fprintf('nmissing: %d\n',nmissing);

end


function test_suite = test_dim_rename()
% tests for cosmo_dim_rename
%
% #   For CoSMoMVPA's copyright information and license terms,   #
% #   see the COPYING file distributed with CoSMoMVPA.           #
    try % assignment of 'localfunctions' is necessary in Matlab >= 2016
        test_functions=localfunctions();
    catch % no problem; early Matlab versions can use initTestSuite fine
    end
    initTestSuite

function test_dim_rename_basics
    ds=cosmo_synthetic_dataset();

    % simple rename
    ds2=cosmo_dim_rename(ds,'j','jj');
    assertEqual(ds2.a.fdim.labels{2},'jj');
    assertEqual(ds2.a.fdim.values,ds.a.fdim.values);
    assertEqual(ds2.samples,ds.samples);
    assertEqual(ds2.sa,ds.sa);

    fa=ds.fa;
    fa.jj=fa.j;
    fa=rmfield(fa,'j');
    assertEqual(ds2.fa,fa);

    % if raise=false, input is same as output
    ds3=cosmo_dim_rename(ds,'xxx','jj',false);
    assertEqual(ds,ds3,ds);

    aet=@(varargin)assertExceptionThrown(@()...
                        cosmo_dim_rename(varargin{:}),'');
    aet(ds,'xxx','jj');
    aet(ds,'xxx','jj',true);


function [planC] = dicomrt_dicomrt2cerr(plan,xmesh,ymesh,zmesh,ct,ct_xmesh,ct_ymesh,ct_zmesh,voi,optName)
% dicomrt_dicomrt2CERR(dose,xmesh,ymesh,zmesh,ct,ct_xmesh,ct_ymesh,ct_zmesh,voi)
%
% Convert DICOMRT-TOOLBOX data in CERR format
%
% Copyright (C) 2002 Emiliano Spezi (emiliano.spezi@physics.org)

% Check number of argument and set-up some parameters and variables
error(nargchk(9,10,nargin))

if exist('optName')==0
    optName='CERROptions.m';
end

%Create CERR data Container & templates for certain cells.
planInitC       = initializeCERR;
indexS          = planInitC{end};
headerInitS     = planInitC{indexS.header};
commentInitS    = planInitC{indexS.comment};
scanInitS       = initializeScanInfo;
structureInitS  = planInitC{indexS.structures};
beamsInitS      = planInitC{indexS.beams};
doseInitS       = planInitC{indexS.dose};

tagMapS = initTagMapS;
tags = dicomrt_d2c_rtogtags;

% Load options
optS=opts4Exe(optName);

% Initialize planC
planC = planInitC;
nCells = length(planInitC);
tags.nimages = 0;

% Convert header
disp('(+) Converting DICOM headers');
if isempty(plan)==0
    headerInitS=dicomrt_d2c_header(headerInitS,plan);
    disp('(+) Fetching data from RTPLAN');

    % Convert beam geometry
    disp('(+) Converting DICOM beam geometry');
    [tmp_beam,tags]=dicomrt_d2c_beam(beamsInitS,indexS,plan,tags);
    disp('(=) Conversion DICOM beam geometry completed.');

    % Convert dose
    disp('(+) Converting DICOM dose');
    [tmp_dose,tags]=dicomrt_d2c_dose(doseInitS,indexS,plan,xmesh,ymesh,zmesh,tags);
    disp('(=) Conversion DICOM dose completed.');

    % Store header info
    planC{indexS.header} = headerInitS;

    % Store beams
    planC{indexS.beams}=tmp_beam;

    % Store dose
    planC{indexS.dose}=tmp_dose;
elseif isempty(plan)==1 & isempty(ct)==0
    headerInitS=dicomrt_d2c_header(headerInitS,ct);
    disp('(+) Fetching data from CT scan');
else
    headerInitS=dicomrt_d2c_header(headerInitS,voi);
    disp('(+) Fetching data from RTSTRUCT');
end
disp('(=) Conversion DICOM headers completed.');

% Convert comments
% commentInitS

% Convert scans
if isempty(ct)==0
    disp('(+) Converting DICOM scans');
    [tmp_scan,tags]=dicomrt_d2c_scan(scanInitS,indexS,ct,ct_xmesh,ct_ymesh,ct_zmesh,tags);
    disp('(=) Conversion DICOM scans completed.');

    % Store scan
    planC{indexS.scan}=tmp_scan;
else
    disp('(=) CT scan not available.');
end

% Validating and converting structures
% Validation
if isempty(voi)==0
    voitype=dicomrt_checkvoitype(voi);
    if isequal(voitype,'3D')
        voi=dicomrt_3dto2dVOI(voi);
    end

    if isempty(ct)==0
        disp('(+) Fitting DICOM structures to CT scans to comply with RTOG format');
        voi=dicomrt_fitvoi2ct(voi,ct_zmesh,ct);
        disp('(=) Fitting DICOM structures completed.');

        disp('(+) Validating DICOM structures');
        [voi]=dicomrt_validatevoi(voi,ct_xmesh,ct_ymesh,ct_zmesh);
        [newvoi]=dicomrt_closevoi(voi);
        disp('(=) Validation DICOM structures completed.');

        % Conversion
        disp('(+) Converting DICOM structures');
        [tmp_str,tags]=dicomrt_d2c_voi(structureInitS,indexS,newvoi,ct_xmesh,ct_ymesh,ct_zmesh,tags);
        disp('(=) Conversion DICOM structures completed.');

    else
        % Conversion
        disp('(+) Converting DICOM structures');
        [tmp_str,tags]=dicomrt_d2c_voi(structureInitS,indexS,voi,ct_xmesh,ct_ymesh,ct_zmesh,tags);
        disp('(=) Conversion DICOM structures completed.');
    end

    % Store structures
    planC{indexS.structures}=tmp_str;
else
    disp('(=) RTSTRUCT not available.');
end

% Convert digital films
nfilms=0;

% Convert DVH
% N/A

% Convert seed geometry

% Store options and indexS
planC{indexS.CERROptions} = optS;
planC{indexS.indexS} = indexS;

% Post processing actions

if isempty(ct)==0
    % Determine voxel thicknesses
    planC=dicomrt_d2c_setVoxelThicknesses(planC,indexS);
end

if isempty(ct)==0 & isempty(voi)==0
    % Get structure scan segments
    planC =  getRasterSegs(planC, optS);

    % Get any dose surface points
    planC =  getDSHPoints(planC, indexS, optS);
end

if isempty(ct)==0
    % Create uniformized datasets
    planC=dicomrt_d2c_uniformizescan(planC,optS);
end

% Save plan
save_planC(planC,optS);


function y = apply( func, x )
y = do_apply( func, x.value_ );

function y = do_apply( func, x )
global cvx___
switch class( x ),
    case 'struct',
        y = cell2struct( do_apply( func, struct2cell( x ) ), fieldnames( x ), 1 );
    case 'cell',
        if cvx___.hcellfun,
            y = cellfun( func, x, 'UniformOutput', false );
        else
            sx = size( x );
            y = cell( sx );
            for k = 1 : prod( sx ),
                y{k} = feval( func, x{k} );
            end
        end
    otherwise,
        y = feval( func, x );
end

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


% This files adds a coastline from an existing data set
global coastline faults mainfault main
report_this_filefun(mfilename('fullpath'));

%aa = a;
[file1,path1] = uigetfile( '*.mat',' Earthquake Datafile'); %disabled window position
loadpath = [path1 file1];

new_data = load(loadpath);

loaded=false;
if isfield(new_data,'coastline')
    if ~isempty(new_data.coastline)
        loaded=true;
        coastline=new_data.coastline;
    end
end

if isfield(new_data,'faults')
    if ~isempty(new_data.faults)
        loaded=true;
        faults=new_data.faults;
    end
end

if isfield(new_data,'mainfault')
    if ~isempty(new_data.mainfault)
        loaded=true;
        mainfault=new_data.mainfault;
    end
end

if isfield(new_data,'main')
    if ~isempty(new_data.main)
        loaded=true;
        main=new_data.main;
    end
end

if ~loaded
    disp('Error lodaing data! Are they in the right *.mat format??')
end
whos
%a = aa;
%clear aa
update(mainmap())


% This M file creates the "LossSpec_Diode_Library.mat " file
% containing loss and thermal diode models provided in the
% "LossModelib.mdl' libray.
% Diode specifications are saved in the "LossSpec_Diode" structure.
%
% Data provided below for three different commercial
% IGBT/Diode half-bridge packs are extracted from manufacturer data sheets
% (see pdf files provided in the same directory).

% Pierre Giroux, Hydro-Quebec (IREQ), March 2012

%% How to to add your own diode specifications
% -------------------------------------------
%   1)  Open the "LossModelib.mdl' library
%   2)  Duplicate a cell containing specifications of one existing IGBT
%       and insert it at the end of this file
%       (see "Add your own specifications here" cell)
%   3)  Modify this new set of data according to your specifications
%   4)  Run this script file in order to update the "LossSpec_Diode_Library.mat " file
%   5)  In the "LossModelib.mdl' library
%            - select the IGBT or half-bridge model to update
%            - open the Mask Editor
%            - select "Diode_Type" parameter
%            - In the "Popups" window, enter a new description
%              after existing diode descriptions
%   6) Save the "LossModelib.mdl' library.
% Note: Future release of SPS will provide an easy-to-use GUI to add or
% edit device characteristics.

% Pierre Giroux, Hydro-Quebec (IREQ), March 2012

% If=  Forward current (A)
% Vf= Forward voltage (V)
% Erec= Reverse recovery energy (mJ)
% Tj= Junction temperature (degrees Celsius)
% Vcc= Supply voltage (V)
% Note1: Reverse recovery energy (Erec)is function of Vcc, If and Tj
% Note2: Diode on-state losses = Vf (function of If and Tj) * If
%+++++++++++++++++++++++++++++++++++++++++++++++++++++++++
clear all

%% Fuji Electric - Diode, IGBT Module, 2 in one-package, 600V, 150A

Type         = 'Diode';
Manufacturer = 'Fuji Electric';
PartNo       = '2MBI150U2A 060';
Description  = 'Diode, IGBT Module, 2 in one-package, 600V, 150A';

% Typical reverse recovery energy (Erec) vs If
Vcc_Erec = 300;
Tj_Erec  = [ 25 125 ];
If_Erec  = [ 0  25    50    75    100   125   150   175   200    225  ];
Erec     = [ 0  0.27  0.48  0.62  0.69  0.73  0.75  0.77  0.795  0.81
             0  0.48  0.82  1.07  1.23  1.37  1.47  1.58  1.67   1.79 ];
%
% Diode - Typical on-state characteristics
Tj_OnState=  [ 25 125 ];
If_OnState = [ 0  0.1  3     10    30    70    111   167   240   300  ];
Vf_OnState = [ 0  0.43 0.78  0.92  1.11  1.31  1.47  1.66  1.89  2.07
               0  0.42 0.55  0.70  0.96  1.23  1.47  1.72  2.02  2.25 ];
%-------------------------------------------------------------------------
%
% Thermal Impedance:
%
Rth_jc=0.46; % Junction-to-Case thermal resistance(K/W)
% Based on transient thermal impedance vs. time curve
Cth_j=0.13;    % Junction thermal capacitance (Joule/Kelvin)
%
%-------------------------------------------------------------------------
LossSpec_Diode(1)= struct('Type',Type, 'Manufacturer',Manufacturer, 'PartNo',PartNo, ...
    'Description',Description, 'Vcc_Erec',Vcc_Erec, ...
    'Tj_Erec',Tj_Erec, 'If_Erec',If_Erec, 'Erec',Erec, ...
    'Tj_OnState',Tj_OnState, 'If_OnState',If_OnState, 'Vf_OnState',Vf_OnState, ...
    'Rth_jc',Rth_jc, 'Cth_j',Cth_j);
%
clear Vcc_Erec Tj_Erec If_Erec Erec Tj_OnState ...
      If_OnState Vf_OnState Manufacturer PartNo Description Type ...
      Rth_jc Cth_j
%=========================end of specifications===========================

%% ABB - Diode, IGBT Module, ABB HiPak, 1700V, 800A
Type='Diode';
Manufacturer= 'ABB';
PartNo= '5SNE 0800M170100';
Description= 'Diode, IGBT Module, ABB HiPak, 1700V, 800A';

% For Tj=25 deg. C, manufacturer specifications provide Erec at only one current (800 A).
% The Erec values for Tj=25 deg. C and Tj=125 deg. C, 800 A specified below
% are used to deduce the Erec(Ic) curve @ Tj=25 deg. C from the Erec(Ic) curve @ Tj=125 deg. C
% assuming that Erec stays proportionnal to its value  @ Tj= 125 deg. C

Tj_800A=   [ 25   125 ]; % Junction temperature (C)
Erec_800A= [ 150  270];  % Reverse recovery energy  at Tj_800A (mJ) for Ic=800A
%
% Typical reverse recovery energy (Erec) vs If
Vcc_Erec= 900;
Tj_Erec=  [ 25 125 ];
If_Erec=   [ 0 101  196  301  500  703  800 902  1100 1300 1500 1600 ];
% Erec @ 125 C (per data sheet curves)
Erec(2,:)= [ 0 82.0 115  145  201  245  270 282  309  330  340  342  ];
% Eon @ 25 C (calculated using data sheet spec at 25 C)
Erec(1,:)=Erec_800A(1)/Erec_800A(2) * Erec(2,:);
%
% Diode - Typical on-state characteristics
Tj_OnState=  [ 25 125 ];
If_OnState = [ 0  0.01  96.4 142  195  259  365  500  669  900  1100 1400 1500];
Vf_OnState = [ 0  0.80  1.09 1.17 1.23 1.29 1.38 1.48 1.58 1.71 1.83 2.00 2.06
               0  0.50  0.86 0.97 1.06 1.15 1.28 1.43 1.58 1.78 1.94 2.18 2.26 ];
%-------------------------------------------------------------------------
%
% Thermal Impedance:
%
Rth_jc=0.036; % Junction-to-Case thermal resistance(K/W)
% Based on transient thermal impedance vs. time curve
Cth_j=3.729;    % Junction thermal capacitance (Joule/Kelvin)
%
%-------------------------------------------------------------------------
LossSpec_Diode(2)= struct('Type',Type, 'Manufacturer',Manufacturer, 'PartNo',PartNo, ...
    'Description',Description, 'Vcc_Erec',Vcc_Erec, ...
    'Tj_Erec',Tj_Erec, 'If_Erec',If_Erec, 'Erec',Erec, ...
    'Tj_OnState',Tj_OnState, 'If_OnState',If_OnState, 'Vf_OnState',Vf_OnState, ...
    'Rth_jc',Rth_jc, 'Cth_j',Cth_j);
%
clear Vcc_Erec Tj_Erec If_Erec Erec Tj_OnState ...
      If_OnState Vf_OnState Manufacturer PartNo Description Type ...
      Rth_jc Cth_j Tj_800A Erec_800A
%=========================end of specifications===========================

%% ABB - Diode, Half-bridge IGBT Module, 3300V, 250A;
Type='Diode';
Manufacturer= 'ABB';
PartNo= '5SNG 0250P330300';
Description= 'Half-bridge IGBT Module, 3300V, 250A';

% For Tj=25 deg. C, manufacturer specifications provide Erec at only one current (250 A).
% The Erec values for Tj=25 deg. C and Tj=125 deg. C, 250 A specified below
% are used to deduce the Erec(Ic) curve @ Tj=25 deg. C from the Erec(Ic) curve @ Tj=125 deg. C
% assuming that Erec stays proportionnal to its value  @ Tj= 125 deg. C

Tj_250A=   [ 25   125 ];  % Junction temperature (C)
Erec_250A= [ 165  280 ];  % Reverse recovery energy at Tj_250A (mJ) for If=250A
%
% Typical reverse recovery energy (Erec) vs If
Vcc_Erec= 1800;
Tj_Erec=  [ 25 125 ];
If_Erec=   [ 0  26.2  48.9  99   150  199  250  299  350  400  450  ];
% Erec @ 125 C (per data sheet curves)
Erec(2,:)= [ 0  85.9  113   165  211  248  280  306  325  336  340  ];
% Eon @ 25 C (calculated using data sheet spec at 25 C)
Erec(1,:)=Erec_250A(1)/Erec_250A(2) * Erec(2,:);
%
% Diode - Typical on-state characteristics
Tj_OnState=  [ 25 125 ];
If_OnState = [ 0  0.01  14.0  43    66.5  101  162   250   401   500  ];
Vf_OnState = [ 0  0.75  1.13  1.40  1.53  1.65 1.81  2.00  2.25  2.39
               0  0.50  0.90  1.20  1.37  1.55 1.81  2.11  2.50  2.71 ];
%-------------------------------------------------------------------------
%
% Thermal Impedance:
%
Rth_jc=0.102; % Junction-to-Case thermal resistance(K/W)
% Based on transient thermal impedance vs. time curve
Cth_j=1.3235;    % Junction thermal capacitance (Joule/Kelvin)
%
%-------------------------------------------------------------------------
LossSpec_Diode(3)= struct('Type',Type, 'Manufacturer',Manufacturer, 'PartNo',PartNo, ...
    'Description',Description, 'Vcc_Erec',Vcc_Erec, ...
    'Tj_Erec',Tj_Erec, 'If_Erec',If_Erec, 'Erec',Erec, ...
    'Tj_OnState',Tj_OnState, 'If_OnState',If_OnState, 'Vf_OnState',Vf_OnState, ...
    'Rth_jc',Rth_jc, 'Cth_j',Cth_j);
%
clear Vcc_Erec Tj_Erec If_Erec Erec Tj_OnState ...
      If_OnState Vf_OnState Manufacturer PartNo Description Type ...
      Rth_jc Cth_j Tj_250A Erec_250A
%=========================end of specifications===========================

%% Add your own specifications here
% Type='Diode';
% Manufacturer= 'My Manufacturer';
% PartNo= 'XXX';
% Description= 'My Module, YYY V, ZZZ A;
% ....

%% Save diode thermal data structure "LossSpec_Diode" in "LossSpec_Diode_Library.mat" file
save LossSpec_Diode_Library LossSpec_Diode
%


function [tests,pass,perf]=test_wfdbtime(varargin)

inputs={'verbose'};
verbose=0;
for n=1:nargin
    if(~isempty(varargin{n}))
        eval([inputs{n} '=varargin{n};']);
    end
end

%Test the examples
test_string={'[timeStamp,dateStamp]=wfdbtime(''challenge/2013/set-a/a01'',[1 10 30]);'};
[tests,pass,perf]=test_wrapper(test_string,[],verbose);


classdef testPrintingInputFileForFem < testNotShowingError

    properties (Access = private)
        fileName
        gmsFile
        resultsDir
        fullFileName
    end

    methods (Access = public)

        function obj = testPrintingInputFileForFem()
            obj.init();
            g  = obj.gmsFile;
            oD = obj.resultsDir;
            oF = obj.fullFileName;
            c = GmsFile2SwanFileConverter(g,oD,oF);
            c.convert();
        end

    end

    methods (Access = protected)

        function hasPassed = hasPassed(obj)
            sF = fullfile('tests','PrintingTests',['test',obj.fileName],['test',obj.fileName,'.m']);
            oF = obj.fullFileName;
            hasChanged = FileComparator().areFilesDifferent(sF,oF);
            hasPassed = ~hasChanged;
        end

    end

    methods (Access = private)

        function init(obj)
            obj.fileName = 'InputFileForFem';
            obj.gmsFile  = 'testReadingGmsh.msh';
            obj.resultsDir   = fullfile('Output',obj.fileName);
            obj.fullFileName = fullfile(obj.resultsDir,[obj.fileName,'.m']);
        end

    end

end