function organizeRFexperiments_OldMitaineWithAerts(pathWORK,pathExperimentTextures,pathRF)

% IMPORTANT! CETTE FONCTION DOIT ABSOLUMENT ETRE AUTOMATISEE!!!

startpath = pwd;

cd(pathWORK)
load('clinical')
load('subTypes')

% LOADING VARIABLES
cd(pathExperimentTextures)
load('permTrain'), load('permTest')
trainText = load('training'); trainText = struct2cell(trainText); trainText = trainText{1};
testText = load('testing'); testText = struct2cell(testText); testText = testText{1};
PT_loco = load('testResultsModels_PET_Locoregional'); PT_loco = struct2cell(PT_loco); PT_loco = PT_loco{1};
CT_loco = load('testResultsModels_CT_Locoregional'); CT_loco = struct2cell(CT_loco); CT_loco = CT_loco{1};
PT_distant = load('testResultsModels_PET_Distant'); PT_distant = struct2cell(PT_distant); PT_distant = PT_distant{1};
CT_distant = load('testResultsModels_CT_Distant'); CT_distant = struct2cell(CT_distant); CT_distant = CT_distant{1};
PT_death = load('testResultsModels_PET_Death'); PT_death = struct2cell(PT_death); PT_death = PT_death{1};
CT_death = load('testResultsModels_CT_Death'); CT_death = struct2cell(CT_death); CT_death = CT_death{1};

% ORGANIZING OUTCOMES
training.outcomes.Locoregional = trainText.Locoregional.outcome;
training.outcomes.Distant = trainText.Distant.outcome;
training.outcomes.Death = trainText.Death.outcome;
testing.outcomes.Locoregional = testText.Locoregional.outcome;
testing.outcomes.Distant = testText.Distant.outcome;
testing.outcomes.Death = testText.Death.outcome;
training.timeToEvents.Locoregional = trainText.Locoregional.timeToEvent;
training.timeToEvents.Distant = trainText.Distant.timeToEvent;
training.timeToEvents.Death = trainText.Death.timeToEvent;
testing.timeToEvents.Locoregional = testText.Locoregional.timeToEvent;
testing.timeToEvents.Distant = testText.Distant.timeToEvent;
testing.timeToEvents.Death = testText.Death.timeToEvent;

% ORGANIZING CLINICAL DATA
age_train = [clinical.HGJ.Age;clinical.CHUS.Age]; age_test = [clinical.HMR.Age;clinical.CHUM.Age];
subType_train = [subTypes.HGJ;subTypes.CHUS]; subType_test = [subTypes.HMR;subTypes.CHUM];
tStage_train = [clinical.HGJ.T_stage;clinical.CHUS.T_stage]; tStage_test = [clinical.HMR.T_stage;clinical.CHUM.T_stage];
nStage_train = [clinical.HGJ.N_stage;clinical.CHUS.N_stage]; nStage_test = [clinical.HMR.N_stage;clinical.CHUM.N_stage];
tnmStage_train = [clinical.HGJ.TNM_stage;clinical.CHUS.TNM_stage]; tnmStage_test = [clinical.HMR.TNM_stage;clinical.CHUM.TNM_stage];
age_train = age_train(permTrain); age_test = age_test(permTest);
subType_train = subType_train(permTrain); subType_test = subType_test(permTest);
tStage_train = tStage_train(permTrain); tStage_test = tStage_test(permTest);
nStage_train = nStage_train(permTrain); nStage_test = nStage_test(permTest);
tnmStage_train = tnmStage_train(permTrain); tnmStage_test = tnmStage_test(permTest);

Age = age_train; SubType = subType_train; T_Stage = tStage_train; N_Stage = nStage_train; TNM_Stage = tnmStage_train;
training.clinical.table = table(Age,SubType,T_Stage,N_Stage,TNM_Stage);
training.clinical.categories = [0,1,1,1,1];
Age = age_test; SubType = subType_test; T_Stage = tStage_test; N_Stage = nStage_test; TNM_Stage = tnmStage_test;
testing.clinical.table = table(Age,SubType,T_Stage,N_Stage,TNM_Stage);
testing.clinical.categories = [0,1,1,1,1];

% ORGANIZING TEXTURES (change names if necessary)

% For Locoregional
PET_GLV = PT_loco.trainData.data(:,1); PET_GLN = PT_loco.trainData.data(:,2); PET_LGRE = PT_loco.trainData.data(:,3);
training.textures.Locoregional.PET = table(PET_GLV,PET_GLN,PET_LGRE);
PET_GLV = PT_loco.testData.data(:,1); PET_GLN = PT_loco.testData.data(:,2); PET_LGRE = PT_loco.testData.data(:,3);
testing.textures.Locoregional.PET = table(PET_GLV,PET_GLN,PET_LGRE);

CT_LGZE = CT_loco.trainData.data(:,1); CT_Correlation = CT_loco.trainData.data(:,2); CT_Busyness = CT_loco.trainData.data(:,3);
training.textures.Locoregional.CT = table(CT_LGZE,CT_Correlation,CT_Busyness);
CT_LGZE = CT_loco.testData.data(:,1); CT_Correlation= CT_loco.testData.data(:,2); CT_Busyness = CT_loco.testData.data(:,3);
testing.textures.Locoregional.CT = table(CT_LGZE,CT_Correlation,CT_Busyness);

PET_GLV = PT_loco.trainData.data(:,1); PET_GLN = PT_loco.trainData.data(:,2); PET_LGRE = PT_loco.trainData.data(:,3);
CT_LGZE = CT_loco.trainData.data(:,1); CT_Correlation = CT_loco.trainData.data(:,2); CT_Busyness = CT_loco.trainData.data(:,3);
training.textures.Locoregional.PETCT = table(PET_GLV,PET_GLN,PET_LGRE,CT_LGZE,CT_Correlation,CT_Busyness);
PET_GLV = PT_loco.testData.data(:,1); PET_GLN = PT_loco.testData.data(:,2); PET_LGRE = PT_loco.testData.data(:,3);
CT_LGZE = CT_loco.testData.data(:,1); CT_Correlation= CT_loco.testData.data(:,2); CT_Busyness = CT_loco.testData.data(:,3);
testing.textures.Locoregional.PETCT = table(PET_GLV,PET_GLN,PET_LGRE,CT_LGZE,CT_Correlation,CT_Busyness);

% For Distant
PT_SRHGE = PT_distant.trainData.data(:,1); PT_SUVmax = PT_distant.trainData.data(:,2); PT_ZSV = PT_distant.trainData.data(:,3);
training.textures.Distant.PET = table(PT_SRHGE,PT_SUVmax,PT_ZSV);
PT_SRHGE = PT_distant.testData.data(:,1); PT_SUVmax = PT_distant.testData.data(:,2); PT_ZSV = PT_distant.testData.data(:,3);
testing.textures.Distant.PET = table(PT_SRHGE,PT_SUVmax,PT_ZSV);

CT_LRHGE = CT_distant.trainData.data(:,1); CT_ZSV = CT_distant.trainData.data(:,2); CT_ZSN = CT_distant.trainData.data(:,3);
training.textures.Distant.CT = table(CT_LRHGE,CT_ZSV,CT_ZSN);
CT_LRHGE = CT_distant.testData.data(:,1); CT_ZSV = CT_distant.testData.data(:,2); CT_ZSN = CT_distant.testData.data(:,3);
testing.textures.Distant.CT = table(CT_LRHGE,CT_ZSV,CT_ZSN);

PT_SRHGE = PT_distant.trainData.data(:,1); PT_SUVmax = PT_distant.trainData.data(:,2); PT_ZSV = PT_distant.trainData.data(:,3);
CT_LRHGE = CT_distant.trainData.data(:,1); CT_ZSV = CT_distant.trainData.data(:,2); CT_ZSN = CT_distant.trainData.data(:,3);
training.textures.Distant.PETCT = table(PT_SRHGE,PT_SUVmax,PT_ZSV,CT_LRHGE,CT_ZSV,CT_ZSN);
PT_SRHGE = PT_distant.testData.data(:,1); PT_SUVmax = PT_distant.testData.data(:,2); PT_ZSV = PT_distant.testData.data(:,3);
CT_LRHGE = CT_distant.testData.data(:,1); CT_ZSV = CT_distant.testData.data(:,2); CT_ZSN = CT_distant.testData.data(:,3);
testing.textures.Distant.PETCT = table(PT_SRHGE,PT_SUVmax,PT_ZSV,CT_LRHGE,CT_ZSV,CT_ZSN);

% For Death
PT_SZLGE = PT_death.trainData.data(:,1); PT_LGZE = PT_death.trainData.data(:,2); PT_Contrast = PT_death.trainData.data(:,3);
training.textures.Death.PET = table(PT_SZLGE,PT_LGZE,PT_Contrast);
PT_SZLGE = PT_death.testData.data(:,1); PT_LGZE = PT_death.testData.data(:,2); PT_Contrast = PT_death.testData.data(:,3);
testing.textures.Death.PET = table(PT_SZLGE,PT_LGZE,PT_Contrast);

CT_GLN = CT_death.trainData.data(:,1); CT_SZE = CT_death.trainData.data(:,2); CT_Energy = CT_death.trainData.data(:,3);
training.textures.Death.CT = table(CT_GLN,CT_SZE,CT_Energy);
CT_GLN = CT_death.testData.data(:,1); CT_SZE = CT_death.testData.data(:,2); CT_Energy = CT_death.testData.data(:,3);
testing.textures.Death.CT = table(CT_GLN,CT_SZE,CT_Energy);

PT_SZLGE = PT_death.trainData.data(:,1); PT_LGZE = PT_death.trainData.data(:,2); PT_Contrast = PT_death.trainData.data(:,3);
CT_GLN = CT_death.trainData.data(:,1); CT_SZE = CT_death.trainData.data(:,2); CT_Energy = CT_death.trainData.data(:,3);
training.textures.Death.PETCT = table(PT_SZLGE,PT_LGZE,PT_Contrast,CT_GLN,CT_SZE,CT_Energy);
PT_SZLGE = PT_death.testData.data(:,1); PT_LGZE = PT_death.testData.data(:,2); PT_Contrast = PT_death.testData.data(:,3);
CT_GLN = CT_death.testData.data(:,1); CT_SZE = CT_death.testData.data(:,2); CT_Energy = CT_death.testData.data(:,3);
testing.textures.Death.PETCT = table(PT_SZLGE,PT_LGZE,PT_Contrast,CT_GLN,CT_SZE,CT_Energy);

% For Death (Aerts signature)
PT_death = load('testResultsAerts_PET_Death'); PT_death = struct2cell(PT_death); PT_death = PT_death{1};
CT_death = load('testResultsAerts_CT_Death'); CT_death = struct2cell(CT_death); CT_death = CT_death{1};

PT_Energy = PT_death.trainData.data(:,1); PT_Compactness = PT_death.trainData.data(:,2); PT_GLN = PT_death.trainData.data(:,3); PT_GLN_HLH = PT_death.trainData.data(:,4);
training.textures.DeathSign.PET = table(PT_Energy,PT_Compactness,PT_GLN,PT_GLN_HLH);
PT_Energy = PT_death.testData.data(:,1); PT_Compactness = PT_death.testData.data(:,2); PT_GLN = PT_death.testData.data(:,3); PT_GLN_HLH = PT_death.testData.data(:,4);
testing.textures.DeathSign.PET = table(PT_Energy,PT_Compactness,PT_GLN,PT_GLN_HLH);

CT_Energy = CT_death.trainData.data(:,1); CT_Compactness = CT_death.trainData.data(:,2); CT_GLN = CT_death.trainData.data(:,3); CT_GLN_HLH = CT_death.trainData.data(:,4);
training.textures.DeathSign.CT = table(CT_Energy,CT_Compactness,CT_GLN,CT_GLN_HLH);
CT_Energy = CT_death.testData.data(:,1); CT_Compactness = CT_death.testData.data(:,2); CT_GLN = CT_death.testData.data(:,3); CT_GLN_HLH = CT_death.testData.data(:,4);
testing.textures.DeathSign.CT = table(CT_Energy,CT_Compactness,CT_GLN,CT_GLN_HLH);

PT_Energy = PT_death.trainData.data(:,1); PT_Compactness = PT_death.trainData.data(:,2); PT_GLN = PT_death.trainData.data(:,3); PT_GLN_HLH = PT_death.trainData.data(:,4);
CT_Energy = CT_death.trainData.data(:,1); CT_Compactness = CT_death.trainData.data(:,2); CT_GLN = CT_death.trainData.data(:,3); CT_GLN_HLH = CT_death.trainData.data(:,4);
training.textures.DeathSign.PETCT = table(PT_Energy,PT_Compactness,PT_GLN,PT_GLN_HLH,CT_Energy,CT_Compactness,CT_GLN,CT_GLN_HLH);
PT_Energy = PT_death.testData.data(:,1); PT_Compactness = PT_death.testData.data(:,2); PT_GLN = PT_death.testData.data(:,3); PT_GLN_HLH = PT_death.testData.data(:,4);
CT_Energy = CT_death.testData.data(:,1); CT_Compactness = CT_death.testData.data(:,2); CT_GLN = CT_death.testData.data(:,3); CT_GLN_HLH = CT_death.testData.data(:,4);
testing.textures.DeathSign.PETCT = table(PT_Energy,PT_Compactness,PT_GLN,PT_GLN_HLH,CT_Energy,CT_Compactness,CT_GLN,CT_GLN_HLH);

% SAVING ORGANIZED DATA
cd(pathRF)
save('training','training'), save('testing','testing')
save('permTrain','permTrain'), save('permTest','permTest')

cd(startpath)
end


% SPM5 UPDATE 17/12/06
% UPDATE 27/01/05
% Sets the default values for the FieldMap toolbox
%
% FORMAT pm_defaults_Allegra_eFoV
%_______________________________________________________________________
%
% This file is intended for use with the Siemens fieldmap sequence
% on the Allegra scanner at the FIL and the new EPI sequence with
% extended  FOV, and PE blips=-1:
% nw_mepi_v3d_efov, nw_mepi_v3d_Amy,
% nw_mepi_v3d_Hippoc, nw_mepi_v3d_OFC_Amy.
%_______________________________________________________________________
% Copyright (C) 2008 Wellcome Trust Centre for Neuroimaging

% Chloe Hutton and Jesper Andersson
% $Id: pm_defaults_Allegra_eFoV.m 5015 2012-10-24 13:40:07Z guillaume $

global pm_def;

% Defaults for creating field map. (See pm_make_fieldmap.m and
%                                   FieldMap.man for more info.)
%=======================================================================
pm_def.INPUT_DATA_FORMAT = 'PM';      % 'RI' = load two real and
                                      % imaginary image pairs
                                      % 'PM' = load one or two
                                      % phase and magnitude image
                                      % pairs.
pm_def.SHORT_ECHO_TIME = 10.0;        % Short echo time in ms for Allegra
pm_def.LONG_ECHO_TIME = 12.46;        % Long echo time in ms for Allegra
pm_def.MASKBRAIN = 1;                 % Do brain masking (1 or 0,
                      % 0 for EPI fieldmaps)

% Defaults for unwrapping options. (See pm_make_fieldmap.m and
%                                   FieldMap.man for more info.)
%=======================================================================
pm_def.UNWRAPPING_METHOD = 'Mark3D';  % Unwrapping options are:
                                      % 'Huttonish', 'Mark3D' or 'Mark2D'
pm_def.FWHM = 10;                     % FWHM of Gaussian filter used to
                                      % implement weighted smoothing of
                                      % unwrapped maps.
pm_def.PAD = 0;                       % Size of padding kernel if required.
pm_def.WS = 1;                        % Weighted or normal smoothing.

% Flags for brain extraction
%=======================================================================
pm_def.MFLAGS.TEMPLATE = fullfile(spm('Dir'),'toolbox','FieldMap','T1.nii');
pm_def.MFLAGS.FWHM = 5;     % In mm
pm_def.MFLAGS.NERODE = 2;   % In voxels
pm_def.MFLAGS.NDILATE = 4;  % In voxels
pm_def.MFLAGS.THRESH = 0.5;
pm_def.MFLAGS.REG = 0.02;   % A larger value helps segmentation to converge
pm_def.MFLAGS.GRAPHICS = 0; % A larger value helps segmentation to converge

% Defaults for converting field map to voxel displacement map.
%=======================================================================
pm_def.EPI_BASED_FIELDMAPS = 0;         % EPI=1, other=0.
pm_def.K_SPACE_TRAVERSAL_BLIP_DIR = -1; % +ve k-space = 1, -ve = -1.
pm_def.TOTAL_EPI_READOUT_TIME = 23.76;   % Allegra EPI RO time (330E-6*72)

% Defaults for Unwarping.
%=======================================================================
pm_def.DO_JACOBIAN_MODULATION = 0;    % Do jacobian modulation to adjust
                                      % for compression or stretching
                                      % No = 0, Yes = 1


function blockwrite(f)
%BLOCKWRITE  Append block to an existing file
%   Usage: blockwrite(f);
%
%   Input parameters:
%      f    : Block stream input.
%
%   Function appends *f* to a existing file. The file must have been
%   explicitly defined as the 'outfile' parameter of |block| prior
%   calling this function. If not, the function does nothing.
%
%   The function expect exactly the same format of *f* as is returned by
%   |blockread|.
%
%   See also: block

% Authors: Bjoern Ohl, Zdenek Prusa

complainif_notenoughargs(nargin,1,'BLOCKWRITE');

filestruct = block_interface('getOutFile');

if isempty(filestruct)
   % Do nothing if the file was not setup in block.
   return;
   %error('%s: Output file was not specified in block function.',...
   %      upper(mfilename));
end

filename = filestruct.filename;

% Reformat f if necessary
f = comp_sigreshape_pre(f,'BLOCKPLAY',0);

[L, W] = size(f);

Wread = filestruct.Nchan;

if Wread ~= W
    error(['%s: %s was initialized to work with %i channels but', ...
           ' only %i provided. '],upper(mfilename),filename,Wread,W);
end

if W>2
    error('%s: Cannot work with more than 2 channels.',upper(mfilename));
end

% prepare data depending on mono/stereo:
if W == 2           % stereo
  f = f.';
  f = f(:);
end

% flength = dlength + 36;
% We need to read one field from the header and
% update two.
fid = fopen(filename,'r+');

fseek(fid,40,-1);
dataLenInBytes = fread(fid,1,'uint32');
dataLenInBytes = dataLenInBytes + filestruct.alignment*L;
fileLenInBytes = dataLenInBytes + 36;

try
    if fseek(fid,4,-1) ~= 0
        error('d');
    end
    if fwrite(fid,fileLenInBytes,'uint32')<=0
        error('d');
    end

    if fseek(fid,40,-1)~=0
         error('d');
    end
    if fwrite(fid,dataLenInBytes,'uint32') <=0
         error('d');
    end
catch
    % We have to check whether the header was modified properly.
    error(['%s: An error has ocurred when modifying header of the ',...
          ' wav file. The file might be unreadable. Consider',...
          ' starting over.'],upper(mfilename));

end
fclose(fid);

% And now we can append the actual data
fid = fopen(filename,'a');
%write data into file (amplified by 2^15 to suit int16-range (from -2^15 to +2^15):

maxval = 1-(1/2^16);
minval = -1;

% Allow clipping since it is hard to do some sensible normalization.
f(f >= maxval)  = maxval;
f(f <= minval)  = minval;

% clipping check:
%if (max(tempvec) >= maxval) || (min(tempvec) <= minval)
    %We have no way how to find out how to properly normalize in blocks
    %warning('Clipping! Audio data limited to [-1, +1)');
%end

fwrite(fid, f*2^15, 'int16');
fclose(fid);    %close file


clear all; close all; clc
%%
M_dir = GetFishDirectories();
data_masterdir = GetNestedDataDir();
save_masterdir = GetCurrentDataDir();
%%
tiffname = 'C:\Janelia2015\Elavl3-H2BRFP_6dpf_MeanImageOf10Fish.tif';
info = imfinfo(tiffname,'tiff');
nPlanes = length(info);
s1 = info(1).Height;
s2 = info(1).Width;
anat_stack_norm = zeros(s1,s2,nPlanes);
for i=1:nPlanes,
    anat_stack_norm(:,:,i) = imread(tiffname,i);
end
%%
% im = max(anat_stack_norm,[],3);
% out=imNormalize99(im);
% anat_yx_norm = repmat(out,[1 1 3]);
%
% % y-z view
% im = squeeze(max(anat_stack_norm,[],2));
% out=imNormalize99(im);
% anat_yz_norm = repmat(out,[1 1 3]);
%
% % x-z view
% im = squeeze(max(anat_stack_norm,[],1));
% out=imNormalize99(im);
% out = flipud(out'); %%%% empirically necessary...
% anat_zx_norm = repmat(out,[1 1 3]);
%%
range_fish = 2:11;

for i_fish = range_fish,
    tic
    disp(['i_fish = ', num2str(i_fish)]);

    data_dir = fullfile(data_masterdir,['subject_' num2str(i_fish)]);
%     save_dir = fullfile(save_masterdir,['subject_' num2str(i_fish)]);

    load(fullfile(data_dir,'OptionalInfo.mat'));
%     load(fullfile(save_dir,'data.mat'));
%     absIX = data.absIX;
%     absIX = (1:data.numcell_full)';

%     filename = fullfile(save_dir,'TimeSeries.h5');
%     h5create(filename,'/absIX',size(absIX));
%     h5write(filename,'/absIX',absIX);

%     CellXYZ = data.CellXYZ;
%     CellXYZ_ref = data.CellXYZ_ref;
%
%     load(fullfile(save_dir,'data.mat'));
%
%     data.CellXYZ = CellXYZ;
%     data.CellXYZ_ref = CellXYZ_ref;

%%
filename = fullfile('C:\Janelia2015\norm cell coord',['F' num2str(i_fish) '_XYZ_norm.txt']);
delimiter = ' ';
formatSpec = '%f%f%f%s%[^\n\r]';
fileID = fopen(filename,'r');
dataArray = textscan(fileID, formatSpec, 'Delimiter', delimiter, 'MultipleDelimsAsOne', true, 'EmptyValue' ,NaN, 'ReturnOnError', false);
fclose(fileID);

VarName1 = dataArray{:, 1};
VarName2 = dataArray{:, 2};
VarName3 = dataArray{:, 3};
FAILED = dataArray{:, 4};

temp = zeros(length(FAILED),1);
for i = 1:length(FAILED),
    temp(i) = length(FAILED{i});
end
IX_inval_norm = find(temp~=0);

Y = round(VarName1/0.798);
X = round(VarName2/0.798);
Z = round(VarName3/2);
CellXYZ_norm = horzcat(X,Y,Z);

    %%

    save(fullfile(data_dir,'OptionalInfo.mat'),'Behavior_raw','CellXYZ_norm','IX_inval','numcell_full','IX_inval_norm');%,'anat_stack_norm'

    toc
end

%%
range_fish = 2:11;
for i_fish = range_fish,
    %% load data
    disp(['load fish ' num2str(i_fish) '...']);
    save_dir = fullfile(save_masterdir,['subject_' num2str(i_fish)]);
    load(fullfile(save_dir,'data_full.mat'),'data'); % struct with many fields
    %%
    data_full = data;
    names = fieldnames(data_full); % cell of strings
    for i = 1:length(names),
        eval([names{i} ' = data_full.' names{i} ';']);
    end

    data_dir = fullfile(data_masterdir,['subject_' num2str(i_fish)]);
    load(fullfile(data_dir,'OptionalInfo.mat'));

    %%
    data = [];
    names = {'periods','timelists_names','stimuluskey_raw','CellXYZ','anat_stack','fpsec',...
        'Behavior_raw','numcell_full','CellXYZ_norm','IX_inval_norm','IX_inval_anat',...
        'anat_yx','anat_yz','anat_zx',...
        'timelists','stim_full','stimAvr','Behavior_full','BehaviorAvr'};
%         'absIX'};
    if length(timelists_names)>1, % M_stimset(i_fish) > 1,
        names = [names,{'stimset'}];
    end

    for i = 1:length(names), % use loop to save variables into fields of 'data'
        eval(['data.',names{i},'=', names{i},';']);
    end

    save(fullfile(save_dir,'data_full.mat'),'data');
end
%%
filename = fullfile(save_dir,'TimeSeries.h5');
fileattrib(filename,'+w');
h5writeatt(filename,'/','absIX',absIX);
h5disp(filename);

%%
% srcFile = fullfile(matlabroot,'toolbox','matlab','demos','example.h5');
copyfile(filename,'myfile.h5','f');
fileattrib('myfile.h5','+w');
h5writeatt('myfile.h5','/','creation_date',datestr(now));

h5writeatt('myfile.h5','/','absIX',absIX(1:10));

%%
filename = fullfile(save_dir,'TimeSeries_full.h5');
%%
tic
CellResp = h5read(filename,'/CellResp');
CellRespZ = h5read(filename,'/CellRespZ');
CellRespAvr = h5read(filename,'/CellRespAvr');
CellRespAvrZ = h5read(filename,'/CellRespAvrZ');
toc
%%
tic
CellResp_ = CellResp(absIX,:);
CellRespZ_ = CellRespZ(absIX,:);
CellRespAvr_ = CellRespAvr(absIX,:);
CellRespAvrZ_ = CellRespAvrZ(absIX,:);
toc

%%
absIX = (1:data.numcell_full)';

filename = fullfile(save_dir,'TimeSeries_full.h5');
h5create(filename,'/CellResp',size(CellResp),'Datatype','single','ChunkSize',[1000 100]);
h5write(filename,'/CellResp',CellResp);

h5create(filename,'/CellRespZ',size(CellRespZ),'Datatype','single','ChunkSize',[1000 100]);
h5write(filename,'/CellRespZ',CellRespZ);

h5create(filename,'/CellRespAvr',size(CellRespAvr),'Datatype','single','ChunkSize',[1000 100]);
h5write(filename,'/CellRespAvr',CellRespAvr);

h5create(filename,'/CellRespAvrZ',size(CellRespAvrZ),'Datatype','single','ChunkSize',[1000 100]);
h5write(filename,'/CellRespAvrZ',CellRespAvrZ);

h5create(filename,'/absIX',size(absIX));
h5write(filename,'/absIX',absIX);

%% need to delete 'absIX' from data_full.mat


function [eventLog] = ma_executeCoast_nBody_goto_soi_trans(initialState, eventNum, forceModel, soiSkipIds, massLoss, maxPropTime, events, celBodyData)
%ma_executeCoast_nBody_goto_soi_trans Summary of this function goes here
%   Detailed explanation goes here

    eventLog = ma_executeCoast_nBody_goto_dt(maxPropTime, initialState, eventNum, forceModel, true, soiSkipIds, massLoss, maxPropTime, events, false, celBodyData);
end


function ir = compensate_headphone(ir,conf)
%COMPENSATE_HEADPHONE applies a headphone compensation to an impulse response
%
%   Usage: ir = compensate_headphone(ir,conf)
%
%   Input parameters:
%       ir      - Impulse response to which the compensation should be applied
%       conf    - configuration struct (see SFS_config)
%
%   Output:
%       ir      - Impulse response which is compensated for the given headphone
%
%   COMPENSATE_HEADPHONE(ir,conf) applies a headphone compensation to the
%   given impulse response. Which headphone compensation it should use is
%   mentioned in the conf struct. The compensation filter can be a one-channel
%   (same filter for left and right) or two-channel signal (1st signal: left,
%   2nd signal: right) with signals stored as columns in a matrix.
%   The compensation is only applied, if the conf.ir.usehcomp value is not false.
%
%   See also: ir_wfs, ir_point_source, ir_generic

%*****************************************************************************
% The MIT License (MIT)                                                      *
%                                                                            *
% Copyright (c) 2010-2019 SFS Toolbox Developers                             *
%                                                                            *
% Permission is hereby granted,  free of charge,  to any person  obtaining a *
% copy of this software and associated documentation files (the "Software"), *
% to deal in the Software without  restriction, including without limitation *
% the rights  to use, copy, modify, merge,  publish, distribute, sublicense, *
% and/or  sell copies of  the Software,  and to permit  persons to whom  the *
% Software is furnished to do so, subject to the following conditions:       *
%                                                                            *
% The above copyright notice and this permission notice shall be included in *
% all copies or substantial portions of the Software.                        *
%                                                                            *
% THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR *
% IMPLIED, INCLUDING BUT  NOT LIMITED TO THE  WARRANTIES OF MERCHANTABILITY, *
% FITNESS  FOR A PARTICULAR  PURPOSE AND  NONINFRINGEMENT. IN NO EVENT SHALL *
% THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER *
% LIABILITY, WHETHER  IN AN  ACTION OF CONTRACT, TORT  OR OTHERWISE, ARISING *
% FROM,  OUT OF  OR IN  CONNECTION  WITH THE  SOFTWARE OR  THE USE  OR OTHER *
% DEALINGS IN THE SOFTWARE.                                                  *
%                                                                            *
% The SFS Toolbox  allows to simulate and  investigate sound field synthesis *
% methods like wave field synthesis or higher order ambisonics.              *
%                                                                            *
% https://sfs.readthedocs.io                            sfstoolbox@gmail.com *
%*****************************************************************************

%% ===== Checking of input  parameters ==================================
nargmin = 2;
nargmax = 2;
narginchk(nargmin,nargmax);
isargmatrix(ir);
isargstruct(conf);

%% ===== Configuration ===================================================
usehcomp = conf.ir.usehcomp;

%% ===== Computation =====================================================
if(usehcomp)
    lenir = size(ir,1);
    % Read headphone compensation filter
    hcomp = audioread(conf.ir.hcompfile);
    % Check if the IR has the right length for the filter
    if lenir<length(hcomp)
        warning(['The length of the used IR is shorter than the headphone ', ...
            'compensation filter.']);
    end
    % Apply filter
    ir = convolution(hcomp,ir);
    ir = fix_length(ir,lenir);
end


function [c, r, t, cpulse, acq_codes] = tapas_physio_read_physlogfiles_philips(log_files, cardiac_modality)
% reads out physiological time series and timing vector depending on the
% MR scanner vendor and the modality of peripheral cardiac monitoring (ECG
% or pulse oximetry)
%
%   [c, r, t, cpulse] = tapas_physio_read_physlogfiles_philips(logfile, vendor, cardiac_modality)
%
% IN
%   log_files                   tapas.log_files; see also tapas_physio_new
%           .respiratory
%           .cardiac
%           .sampling_interval
%           .relative_start_acquisition
%   cardiac_modality
%                       'ecg1_filtered'     filtered 1st ECG channel signal
%                                           (Default)
%                       'ecg2_filtered'     filteered 2nd ECG channel
%                                           (sometimes less gradient artifacts)
%                       'ecg1_raw'          raw 1st ECG channel
%                       'ecg2_raw'          raw 2nd ECG channel
%                       'OXY'/'PPU'         pulse plethysmographic unit
%                                           (PPU) signal
%
%                       Note: for ECG, append '_wifi'
%                       for adjusted sampling rate in
%                       wireless Ingenia Scanners
%
%
% OUT
%   c                   cardiac time series (ECG or pulse oximetry)
%   r                   respiratory time series
%   t                   vector of time points (in seconds)
%   cpulse              time events of R-wave peak in cardiac time series (seconds)
%   acq_codes           slice/volume start events marked by number <> 0
%                       for time points in t
%                       10/20 = scan start/end;
%                       1 = ECG pulse; 2 = OXY max; 4 = Resp trigger;
%                       8 = scan volume trigger
%
% EXAMPLE
%   [ons_secs.cpulse, ons_secs.rpulse, ons_secs.t, ons_secs.c] =
%   tapas_physio_read_physlogfiles(logfile, vendor, cardiac_modality);
%
%   See also tapas_physio_main_create_regressors

% Author: Lars Kasper
% Created: 2013-02-16
% Copyright (C) 2013, Institute for Biomedical Engineering, ETH/Uni Zurich.
%
% This file is part of the PhysIO toolbox, which is released under the terms of the GNU General Public
% Licence (GPL), version 3. You can redistribute it and/or modify it under the terms of the GPL
% (either version 3 or, at your option, any later version). For further details, see the file
% COPYING or <http://www.gnu.org/licenses/>.

%% read out values
hasCardiac  = ~isempty(log_files.cardiac);
hasResp     = ~isempty(log_files.respiration);

if hasCardiac
    logfile = log_files.cardiac;
else
    logfile = log_files.respiration;
end

if hasCardiac || hasResp
    y = tapas_physio_read_physlogfiles_philips_matrix(logfile);
    acq_codes   = y(:,10);
else
    y = [];
    acq_codes = [];
end

Nsamples    = size(y,1);

dt          = log_files.sampling_interval;

%default: 500 Hz sampling frequency
isWifi      = regexpi(cardiac_modality, '_wifi');

if isWifi
    cardiac_modality = regexprep(cardiac_modality, '_wifi', '', 'ignorecase');
end

if isempty(dt)
    if isWifi
        dt = 1/496;
    else
        dt = 2e-3;
    end
end

t= -log_files.relative_start_acquisition + ((0:(Nsamples-1))*dt)';

% column 3 = ECG, 5 = PPU, 6 = resp,
% 10 = scanner signal: 10/20 = scan start/end; 1 = ECG pulse; 2 = OXY max; 8 = scan event TODO: what is 3 and 9???
% columns 7,8,9: Grad-strengh x,y,z

cpulse = find(acq_codes==1);
if ~isempty(cpulse)
    cpulse = t(cpulse);
end;

if hasResp
    r = y(:,6);
else
    r = [];
end

if hasCardiac

    useDefaultEcgModality = strcmpi(cardiac_modality, 'ecg');

    if useDefaultEcgModality
        cardiacModalityArray = ...
            {'ecg1_filtered', 'ecg2_filtered', 'ecg1_raw', 'ecg2_raw', 'ppu'};
    else
        cardiacModalityArray = {cardiac_modality};
    end

    hasValidCardiacReadout = false;
    iModality = 0;

    % cycle through modalities until non-zero cardiac column found
    while ~hasValidCardiacReadout
        iModality = iModality + 1;
        cardiac_modality = cardiacModalityArray{iModality};
        switch lower(cardiac_modality)
            case {'ecg_raw', 'ecg1_raw'}
                c = y(:,1);
            case {'ecg2_raw'}
                c = y(:,2);
            case {'ecg1', 'ecg_filtered', 'ecg1_filtered'}
                c = y(:,3);
            case { 'ecg2', 'ecg2_filtered'}
                c = y(:,4);
            case {'oxy','oxyge', 'ppu'}
                c = y(:,5);
        end

        hasValidCardiacReadout = any(c);

    end
else
    c = [];
    cpulse = [];
end

end


function [phd_trimmed, cphd_nb, meta] = ExtractChipPhaseHistory(cphd_filename,SRP_new,img_support_size,channel)
% EXTRACTCHIPPHASEHISTORY extracts user-specified area from phase history
%   data = ExtractChipPhaseHistory(cphd_filename,img_offset,img_width,channel)
%   filters the input phase history to produce a reduced size phase history
%   that supports full resolution imaging of a user specified image chip
%   (slant plane rectangular area of dimensions IMG_SUPPORT_SIZE centered
%   on SRP_NEW.)
%
%   Separable 1-D range and 1-D azimuth processing, range first, azimuth
%   second, because of memory constraints.
%
% ASSUMPTIONS:
%   1) Assumes a spotlight collect, since it is assumed all points on the
%   ground are equally illuminated by all pulses.
%   2) Assumes a (nearly) monostatic collect.
%   3) This code assumes that the full phase history might not fit into
%   memory, but that the range trimmed phase history must be able to fit
%   into memory.
%   4) Also currently assumes that all pulses have common bandwidths and
%   frequency sampling.  If this is not the case, things become messy.
%   Azimuth filtering becomes difficult/impossible for pulses with
%   arbitrarily different frequency content.  Furthermore, its not clear
%   what the Fx0/F_SS of the resulting decimated pulses would be.
%
% INPUTS:
%   cphd_filename    : string : input phase history file
%   SRP_new          : [1x3]  : ECEF coordinates of new scene reference
%                               point.
%   img_support_size : If scalar, this is the radius of a sphere around the
%                      SRP to extract.
%                      If [1x2], this is the image chip extent in meters
%                      [azimuth_extent range_extent]  (in the slant plane).
%   channel          : scalar : Channel in the phase history file to chip.
%                               (Default = 1).
%
% OUTPUTS:
%   phd_trimmed : Phase history trimmed as requested with pulses in columns
%   cphd_nb     : CPHD formatted per pulse narrowband data for phd_trimmed
%   meta        : SICD-like meta structure
%
% Dan Hack, AFIT/ENG, 09AUG11
% Tim Cox, NRL, 19JUL12 - Modifications to bring to CPHD "X" format.
% Wade Schwartzkopf, NGA/IDT, 01DEC12 - Documentation and code clean up.
%
% //////////////////////////////////////////
% /// CLASSIFICATION: UNCLASSIFIED       ///
% //////////////////////////////////////////

%%%%%%%%%%%%%%%%%%
% Constants      %
%%%%%%%%%%%%%%%%%%
c = 299792458; % Speed of light (m/s)
% Algorithm parameters
show_waitbar = true;
pBlockSize = 2000;
verification_pulse = 0; % Pulse number (or set to zero for no verification plots)

%%%%%%%%%%%%%%%%%%
% Pre-processing %
%%%%%%%%%%%%%%%%%%

% Default input parameters
if ~exist('channel','var')
    channel = 1; % Default
end
% Get the narrowband data
reader_obj = open_ph_reader(cphd_filename);
meta = reader_obj.get_meta();
N = double(meta.Data.Channel(channel).NumVectors);
M = double(meta.Data.Channel(channel).NumSamples);  % num_samples per pulse
[ignore, all_nb] = reader_obj.read_cphd(1:N,[],1);
all_nb.ARP = (all_nb.TxPos + all_nb.RcvPos)/2; % Aperture reference position (nearly monostatic assumption)
% This function assumes spotlight data.
if isfield(meta, 'CollectionInfo') && isfield(meta.CollectionInfo, 'RadarMode') && ...
        isfield(meta.CollectionInfo.RadarMode, 'ModeType') && ...
        ~strcmpi(meta.CollectionInfo.RadarMode.ModeType,'SPOTLIGHT')
    error('EXTRACTCHIPPHASEHISTORY:NON_SPOTLIGHT_DATA',...
        'ExtractChipPhaseHistory function requires spotlight data.');
end
% Determine some collection parameters
[resolution, extent, delta_azimuth, total_azimuth] = pulse_info_to_resolution_extent(...
    all_nb.ARP([1 end],:) - all_nb.SRPPos([1 end],:), ... % Line-of-sight vector between ARP and SRP
    max(all_nb.SC0  + (all_nb.SCSS * (M-1))),... % Highest frequency sample (which has the least azimuth extent, so most conservative)
    max(all_nb.SCSS),... % Largest sample spacing (which has the least range extent)-- although we don't use it here
    [],... % This parameter should be bandwidth, but we don't need it here, since we aren't using resolution.
    N);

%%%%%%%%%%%%%%%%%%%%%%%
% 1:  Range Windowing %
%%%%%%%%%%%%%%%%%%%%%%%

% Slice out the required range bins from each pulse.

% First we determine how much range distance we need to cut out of each
% pulse.
if isscalar(img_support_size) % A sphere around the SRP, the easiest.
    image_span_distance = img_support_size;
elseif numel(img_support_size)==2
    % Extracting range/azimuth oriented rectangle in the slant plane of
    % dimensions img_support_size ([azimuth, range]).
    %
    % In theory, since the geometry (and potentially frequency content) of
    % each pulse varies, each pulse could require a (potentially
    % drammatically) different set of range bins to exactly span our slant
    % plane rectangle. For the selected range bins to cover all corners of
    % the slant plane rectangle, including geometry and range curvature
    % contraints, the required distance span around the SRP for a single
    % pulse is:
    %    image_span_distance = 2*(sqrt(...
    %         (SRP_range*cos(theta) + (img_support_size(2)/2)).^2 + ...
    %         (SRP_range*abs(sin(theta)) + (img_support_size(1)/2)).^2) - ...
    %         SRP_range)
    % where
    %    theta is the angle of a given pulse off of the reference range
    %       direction for which our range/azimuth slant plane rectangle is
    %       defined.
    %    SRP_range is the distance from the ARP to SRP.
    %
    % Although the above equation may be exact per pulse, this distance
    % likely equates to a different number of range bins for each pulse,
    % and in MATLAB we prefer to work with rectangular arrays.  So for the
    % purposes of simplifying the computation, we pick the minimum distance
    % that spans our slant plane rectangle for all pulses.  This is not
    % optimum from the standpoint of the minimum amount of information
    % required to describe the requested image area, but it is required to
    % keep the computations tractable in MATLAB.
    % For simplicity, we only need to evaluate the above
    % image_span_distance equation with the pulse geometries at the ends of
    % the collect (when the theta angle, and thus the require range, is the
    % greatest) and with the minimum range to SRP for all pulses (since
    % that is when range curvature is at its greatest).
    min_SRP_range = min(sqrt(sum((all_nb.ARP - all_nb.SRPPos).^2,2)));
    image_span_distance = 2*(sqrt(...
        (min_SRP_range*cos(total_azimuth/2) + (img_support_size(2)/2)).^2 + ...
        (min_SRP_range*sin(total_azimuth/2) + (img_support_size(1)/2)).^2) - ...
        min_SRP_range);
    % Do we need some small amount of buffer on top of this?
else % For other areas (or volumes), this computation would have to change.
    error('EXTRACTCHIPPHASEHISTORY:UNRECOGNIZED_IMG_SUPPORT_SIZE',...
        'Unrecognized IMG_SUPPORT_SIZE format.');
end

% Determine range parameters
range_extent = c/(2*max(all_nb.SCSS));  % range profile extent (for pulse with the least extent)
rc_vec = fft_bin_pos_vec(M) * range_extent;  % Distance of each range bin from SRP
rc_ndx = find(abs(rc_vec) <= image_span_distance/2);  % range extraction indices
% These indices extract at least the range width needed to cover the
% requested area for all pulses.

% Allocate storage.  We assume this entire array of range-trimmed phase
% history can fit into memory.
M_new = length(rc_ndx); % Number of frequency samples after decimating
phd_trimmed_rangeonly = zeros(M_new,N);

% This is a vectorized implementation in which a block of pulses is
% processed on each iteration.  We process in blocks because it is likely
% that the entire untrimmed phase history cannot fit into memory.
%
% This loop processes all pulses in the phase history file because we
% assume a spotlight collect where all pulses equally affect our new
% reference point.  For non-spotlight collects, we should limit this loop
% to only pulses for which our new reference point fall in their beam.
% This would further reduce computation.

if show_waitbar
  wb = waitbar(0); tic
end

NumBlocks = ceil(N/pBlockSize); % Determine number of blocks.
for pbDx = 1:NumBlocks
    % Calculate pulse indices for this block
    pDx = ( ((pbDx-1)*pBlockSize+1):min(pbDx*pBlockSize,N) );

    % Read all samples from a block of pulses
    ph = reader_obj.read_cphd(pDx, 1:M, channel);

    % Calculate differential ranges (difference of range to current SRP and
    % range to desired SRP)
    delR = sqrt(sum((all_nb.ARP(pDx,:).' - repmat(SRP_new(:),[1 numel(pDx)])).^2)) - ...
           sqrt(sum((all_nb.ARP(pDx,:).' - all_nb.SRPPos(pDx,:).').^2));

    % Calculate frequency vector for each pulse: Fx0+Fx_SS*(0:M-1)
    f_orig = bsxfun(@plus,all_nb.SC0(pDx).',(0:M-1).'*all_nb.SCSS(pDx).');
    k_orig = 2*pi*f_orig/c;

    % Adjust phase reference (re-mocomp to new scene reference point)
    % This is currently just a linear shift based on difference in range
    % between the old and new reference points.  This is the 99% solution.
    % Might be some other higher-order components like tropospheric
    % adjustment.
    ph = ph.*exp(1i*2*bsxfun(@times,k_orig,delR));

    % Form range profile (IFFT)
    rc = ifft(ph,[],1);

    % Apply range gate and convert back to spatial freq domain
    phd_trimmed_rangeonly(:,pDx) = fft(rc(rc_ndx,:),[],1);

    % Generate plot comparisons for data from a single pulse
    if (verification_pulse ~= 0) && any(pDx == verification_pulse)
        % Recompute so we are using Fx_SS of this specific pulse, not max(Fx_SS)
        range_extent_orig = c/(2*all_nb.SCSS(verification_pulse));
        rc_vec_orig = fft_bin_pos_vec(M) * range_extent_orig;
        % Compute extent and range profile of trimmed pulse
        range_extent_new = c/(2*all_nb.SCSS(verification_pulse)*M/M_new);
        rc_vec_new = fft_bin_pos_vec(M_new) * range_extent_new;
        rc_new = ifft(phd_trimmed_rangeonly(:,verification_pulse));
        % Compare pre- and post- trimming
        figure;
        plot(fftshift(rc_vec_orig), fftshift(abs(rc(:,pDx==verification_pulse))), 'b', ...
            fftshift(rc_vec_new), fftshift(abs(rc_new)), 'r');
        set(gca,'xlim',[min(rc_vec) max(rc_vec)]);
        legend({'Original' 'Windowed'});
        xlabel('Range (m)'); ylabel('Magnitude');
        title(['Range Profile Comparison, Pulse ' num2str(verification_pulse)]);
    end

    if show_waitbar
        % Determine remaining execution time and display
        t_sofar = toc;
        t_est = (t_sofar*NumBlocks/pbDx)-t_sofar;
        wb_message=sprintf('Range Filtering, Time remaining: %s',datestr(datenum(0,0,0,0,0,t_est),13));
        waitbar(pbDx/NumBlocks,wb,wb_message);
    end

end

%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
% 2:  Azimuth (Doppler) Windowing %
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%

% Due to re-mocomping to new reference point in the range processing step,
% the desired scene center is already at zero Doppler.
%
% Range filtering is exact.  Azimuth filtering (as implemented below) is
% approximate:
%
% 1) Pulses might not have uniform angular sampling. Since the FFT (and
% most filters) assume uniform sampling, this could be a point of concern.
% For now we assume that spacing is "close enough" to uniform, and that any
% distortions from the FFTing of non-uniform data will be somewhat undone
% with the inverse transform.  Also when we interpolate to new ARP
% positions later, we will retain this non-uniformity by interpolating with
% reference to pulse number rather than time.
% 2) Since we are filtering (at least roughly) across frequency sample
% here, there are some "polar formatting" approximations going on here.
%
% Note that if pulses have signficantly different Fx0 and/or Fx_SS, this
% step probably doesn't make any sense.

if show_waitbar
    waitbar(0,wb,'Azimuth Filtering');
end

% Azimuth profile vector
ac_vec = fft_bin_pos_vec(N)*extent(2); % extent(2) is azimuth extent

% Azimuth extraction indices
ac_ndx = find(abs(ac_vec) <= 1.1 * img_support_size(1)/2); % 10% extra buffer since our filtering is inexact

% Number of azimuth frequency samples after decimating
N_new = length(ac_ndx);

if show_waitbar
    waitbar(0.33,wb,'Azimuth Filtering');
end

% Azimuth compression (IFFT)
ac = ifft(phd_trimmed_rangeonly,[],2);

if show_waitbar
    waitbar(0.66,wb,'Azimuth Filtering');
end

% Window and azimuth uncompress (FFT)
phd_trimmed = fft(ac(:,ac_ndx),[],2);

if show_waitbar
    waitbar(1,wb,'Azimuth Filtering');
    pause(0.25);
    close(wb);
end

%%%%%%%%%%%%%%%%%%%%%%%
% Form pulse metadata %
%%%%%%%%%%%%%%%%%%%%%%%

% Generate output data structure.  Generic structure that reflects CPHD
% format metadata.

% Interpolate aperture reference position (ARP) -- assuming that
% interpolating the original trajectory in time will maintain phase
% coherency with respect to decimated pulses.
ARP_interp = interp1(1:N,all_nb.ARP,linspace(1,N,N_new),'spline');
% Time is really irrelevant in CPHD, but we compute it anyway.
time_ref = (all_nb.TxTime + all_nb.RcvTime)/2; % Monostatic approximation
time_interp = interp1(1:N,time_ref,linspace(1,N,N_new).','spline');

cphd_nb.TxTime = time_interp;
cphd_nb.TxPos = ARP_interp;
cphd_nb.RcvTime = time_interp;
cphd_nb.RcvPos = ARP_interp;
cphd_nb.SRPPos = repmat(SRP_new(:).',[N_new 1]);
% Interpolation along Fx probably isn't valid if Fx values jitter.
cphd_nb.SC0 = interp1(1:N,all_nb.SC0,linspace(1,N,N_new).','spline');
cphd_nb.SCSS = interp1(1:N,all_nb.SCSS*(M/M_new),linspace(1,N,N_new).','spline');
cphd_nb.FX1 = interp1(1:N,all_nb.FX1,linspace(1,N,N_new).','spline');
cphd_nb.FX2 = interp1(1:N,all_nb.FX2,linspace(1,N,N_new).','spline');

end

% Compute a vector of the positions of the bins in an FFT'd vector.
% Output is in normalized units (1 is Nyquist).  Need to multiply by extent
% to convert to real units like meters (or Hz).
function bin_pos_norm = fft_bin_pos_vec(Nfft)
    bin_pos_norm = (0:(Nfft-1))/Nfft; % Normalized units (no sampling frequency used)
    ind_to_flip = (floor((Nfft-1)/2)+2):Nfft; % These positions are 0.5 or above.  Should be negative units.
    bin_pos_norm(ind_to_flip) = bin_pos_norm(ind_to_flip) - 1;
end

% //////////////////////////////////////////
% /// CLASSIFICATION: UNCLASSIFIED       ///
% //////////////////////////////////////////


function events = in_events_nicolet(sFile, EventFile)
% IN_EVENTS_NICOLET: Open a text file with events exported from the Nicolet viewer.

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

% Open and read file
fid = fopen(EventFile,'r');
% Markers list
Markers = {};
isMarkerSection = 0;
% Read file line by line
while 1
    % Read one line
    newLine = fgetl(fid);
    if ~ischar(newLine)
        break;
    end
    % Lines to skip
    if isempty(newLine)
        continue;
    elseif ~isempty(strfind(newLine, 'Name')) && ~isempty(strfind(newLine, 'Time')) && ~isempty(strfind(newLine, 'Duration'))
        isMarkerSection = 1;
        continue
    elseif ~isempty(strfind(newLine, 'Exam Start')) || (nnz(newLine == 9) >= 2)    % Lines with tabs = events
        isMarkerSection = 1;
    elseif ~isMarkerSection
        continue;
    end
    % Split with tabs (ASCII #9): Name, Time, Duration
    splitLine = str_split(newLine, char(9), 0);
    if (length(splitLine) ~= 3) || any(cellfun(@isempty, splitLine))
        continue;
    end
    % Get the time and duration
    try
        vecStart = datevec(splitLine{2}, 'HH:MM:SS');
        tStart = vecStart(4)*3600 + vecStart(5)*60 + vecStart(6);
        vecDuration = datevec(splitLine{3}, 'MM:SS');
        tDuration = vecDuration(5)*60 + vecDuration(6);
    catch
        continue;
    end
    % Add markers entry: {name, type, start, length}
    Markers(end+1,:) = {splitLine{1}, tStart, tDuration};
end
% Close file
fclose(fid);

% List of events
if isempty(Markers)
    uniqueEvt = [];
else
    uniqueEvt = unique(Markers(:,1)');
end
% Initialize returned structure
events = repmat(db_template('event'), [1, length(uniqueEvt)]);
% Create events list
for iEvt = 1:length(uniqueEvt)
    % Find all the occurrences of event #iEvt
    iMrk = find(strcmpi(Markers(:,1)', uniqueEvt{iEvt}));
    % Add event structure
    events(iEvt).label   = uniqueEvt{iEvt};
    events(iEvt).epochs  = ones(1, length(iMrk));
    times = [Markers{iMrk,2}];
    if any([Markers{iMrk,3}] > 0)
        times(2,:) = [Markers{iMrk,2}] + [Markers{iMrk,3}];
    end
    events(iEvt).times      = round(times .* sFile.prop.sfreq) ./ sFile.prop.sfreq;
    events(iEvt).reactTimes = [];
    events(iEvt).select     = 1;
    events(iEvt).channels   = [];
    events(iEvt).notes      = [];
end


function [sourcemodel, cfg] = ft_prepare_leadfield(cfg, data)

% FT_PREPARE_LEADFIELD computes the forward model for many dipole locations
% on a regular 2D or 3D sourcemodel and stores it for efficient inverse modelling
%
% Use as
%   [sourcemodel] = ft_prepare_leadfield(cfg, data)
%
% It is necessary to input the data on which you want to perform the inverse
% computations, since that data generally contain the gradiometer information and
% information about the channels that should be included in the forward model
% computation. The data structure can be either obtained from FT_PREPROCESSING,
% FT_FREQANALYSIS or FT_TIMELOCKANALYSIS. If the data is empty, all channels will be
% included in the forward model.
%
% The configuration should contain
%   cfg.channel            = Nx1 cell-array with selection of channels (default = 'all'),
%                            see FT_CHANNELSELECTION for details
%
% The positions of the sources can be specified as a regular 3-D
% sourcemodel that is aligned with the axes of the head coordinate system
%   cfg.xgrid      = vector (e.g. -20:1:20) or 'auto' (default = 'auto')
%   cfg.ygrid      = vector (e.g. -20:1:20) or 'auto' (default = 'auto')
%   cfg.zgrid      = vector (e.g.   0:1:20) or 'auto' (default = 'auto')
%   cfg.resolution = number (e.g. 1 cm) for automatic sourcemodel generation
%
% Alternatively the position of a few sources at locations of interest can
% be specified, for example obtained from an anatomical or functional MRI
%   cfg.sourcemodel.pos        = N*3 matrix with position of each source
%   cfg.sourcemodel.inside     = N*1 vector with boolean value whether sourcemodel point is inside brain (optional)
%   cfg.sourcemodel.dim        = [Nx Ny Nz] vector with dimensions in case of 3-D sourcemodel (optional)
%
% The volume conduction model of the head should be specified as
%   cfg.headmodel     = structure with volume conduction model, see FT_PREPARE_HEADMODEL
%
% The EEG or MEG sensor positions can be present in the data or can be specified as
%   cfg.elec          = structure with electrode positions or filename, see FT_READ_SENS
%   cfg.grad          = structure with gradiometer definition or filename, see FT_READ_SENS
%
% Optionally, you can modify the leadfields by reducing the rank (i.e. remove the
% weakest orientation), or by normalizing each column.
%   cfg.reducerank      = 'no', or number (default = 3 for EEG, 2 for MEG)
%   cfg.backproject     = 'yes' or 'no',  determines when reducerank is applied whether the
%                         lower rank leadfield is projected back onto the original linear
%                         subspace, or not (default = 'yes')
%   cfg.normalize       = 'yes' or 'no' (default = 'no')
%   cfg.normalizeparam  = depth normalization parameter (default = 0.5)
%   cfg.weight          = number or Nx1 vector, weight for each dipole position to compensate
%                         for the size of the corresponding patch (default = 1)
%
% Depending on the type of headmodel, some additional options may be
% specified.
%
% For OPENMEEG based headmodels:
%   cfg.openmeeg.batchsize    = scalar (default 1e4), number of dipoles
%                               for which the leadfield is computed in a
%                               single call to the low-level code. Trades off
%                               memory efficiency for speed.
%   cfg.openmeeg.dsm          = 'no'/'yes', reuse existing DSM if provided
%   cfg.openmeeg.keepdsm      = 'no'/'yes', option to retain DSM (no by default)
%   cfg.openmeeg.nonadaptive  = 'no'/'yes'
%
% For SINGLESHELL based headmodels:
%   cfg.singleshell.batchsize = scalar or 'all' (default 1), number of dipoles
%                               for which the leadfield is computed in a
%                               single call to the low-level code. Trades off
%                               memory efficiency for speed.
%
% 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_SOURCEANALYSIS, FT_DIPOLEFITTING, FT_PREPARE_HEADMODEL, FT_PREPARE_SOURCEMODEL

% Undocumented local options:
% cfg.feedback
% cfg.sel50p      = 'no' (default) or 'yes'
% cfg.lbex        = 'no' (default) or a number that corresponds with the radius
% cfg.mollify     = 'no' (default) or a number that corresponds with the FWHM

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

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

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

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

% the data can be passed as input arguments or can be read from disk
hasdata = exist('data', 'var');

if ~hasdata
  % the data variable will be passed to the prepare_headmodel function below
  % where it would be used for channel selection
  data = [];
else
  % check if the input data is valid for this function
  data = ft_checkdata(data);
end

% check if the input cfg is valid for this function
cfg = ft_checkconfig(cfg, 'forbidden',  {'channels'}); % prevent accidental typos, see issue 1729
cfg = ft_checkconfig(cfg, 'renamed',    {'hdmfile',   'headmodel'});
cfg = ft_checkconfig(cfg, 'renamed',    {'vol',       'headmodel'});
cfg = ft_checkconfig(cfg, 'renamed',    {'grid',      'sourcemodel'});
cfg = ft_checkconfig(cfg, 'renamed',    {'om',        'openmeeg'});
cfg = ft_checkconfig(cfg, 'renamed',    {'elecfile',  'elec'});
cfg = ft_checkconfig(cfg, 'renamed',    {'gradfile',  'grad'});
cfg = ft_checkconfig(cfg, 'renamed',    {'optofile',  'opto'});
cfg = ft_checkconfig(cfg, 'deprecated', {'patchindx', 'patchsize'});

% set the defaults
cfg.lbex           = ft_getopt(cfg, 'lbex',      'no');
cfg.sel50p         = ft_getopt(cfg, 'sel50p',    'no');
cfg.feedback       = ft_getopt(cfg, 'feedback',  'text');
cfg.mollify        = ft_getopt(cfg, 'mollify',   'no');
cfg.patchsvd       = ft_getopt(cfg, 'patchsvd',  'no');

cfg = ft_checkconfig(cfg, 'renamed', {'tightgrid',   'tight'});  % this is moved to cfg.sourcemodel.tight by the subsequent createsubcfg
cfg = ft_checkconfig(cfg, 'renamed', {'sourceunits', 'unit'});   % this is moved to cfg.sourcemodel.unit by the subsequent createsubcfg

% put the low-level options pertaining to the sourcemodel in their own field
cfg = ft_checkconfig(cfg, 'createsubcfg', {'sourcemodel'});
% move some fields from cfg.sourcemodel back to the top-level configuration
cfg = ft_checkconfig(cfg, 'createtopcfg', {'sourcemodel'});

% this code expects the inside to be represented as a logical array
cfg.sourcemodel = ft_checkconfig(cfg.sourcemodel, 'renamed',  {'pnt' 'pos'});
cfg = ft_checkconfig(cfg, 'inside2logical', 'yes');

if strcmp(cfg.sel50p, 'yes') && strcmp(cfg.lbex, 'yes')
  ft_error('subspace projection with either lbex or sel50p is mutually exclusive');
end

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

% collect and preprocess the electrodes/gradiometer and head model
[headmodel, sens, cfg] = prepare_headmodel(cfg, data);

% construct the sourcemodel for which the leadfield will be computed
tmpcfg           = keepfields(cfg, {'sourcemodel', 'mri', 'headshape', 'symmetry', 'smooth', 'threshold', 'spheremesh', 'inwardshift', 'xgrid' 'ygrid', 'zgrid', 'resolution', 'tight', 'warpmni', 'template', 'showcallinfo', 'trackcallinfo', 'trackusage', 'trackdatainfo', 'trackmeminfo', 'tracktimeinfo', 'checksize'});
tmpcfg.headmodel = headmodel;
if ft_senstype(sens, 'eeg')
  tmpcfg.elec = sens;
elseif ft_senstype(sens, 'meg')
  tmpcfg.grad = sens;
end
sourcemodel = ft_prepare_sourcemodel(tmpcfg);

% find the indices of all sourcemodel points that are inside the brain
insideindx = find(sourcemodel.inside);

% check whether units are equal (NOTE: this was previously not required,
% this check can be removed if the underlying bug is resolved. See
% http://bugzilla.fieldtriptoolbox.org/show_bug.cgi?id=2387
if ~isfield(headmodel, 'unit') || ~isfield(sourcemodel, 'unit') || ~isfield(sens, 'unit')
  ft_warning('cannot determine the units of all geometric objects required for leadfield computation (headmodel, sourcemodel, sensor configuration). THIS CAN LEAD TO WRONG RESULTS! (refer to http://bugzilla.fieldtriptoolbox.org/show_bug.cgi?id=2387)');
else
  if ~strcmp(headmodel.unit, sourcemodel.unit) || ~strcmp(sourcemodel.unit, sens.unit)
    ft_error('geometric objects (headmodel, sourcemodel, sensor configuration) are not expressed in the same units (this used to be allowed, and will be again in the future, but for now there is a bug which prevents a correct leadfield from being computed; see http://bugzilla.fieldtriptoolbox.org/show_bug.cgi?id=2387)');
  end
end

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

% construct the low-level options for the leadfield computation as key-value pairs, these are passed to FT_COMPUTE_LEADFIELD
leadfieldopt = {};
leadfieldopt = ft_setopt(leadfieldopt, 'reducerank',     ft_getopt(cfg, 'reducerank'));
leadfieldopt = ft_setopt(leadfieldopt, 'backproject',    ft_getopt(cfg, 'backproject'));
leadfieldopt = ft_setopt(leadfieldopt, 'normalize',      ft_getopt(cfg, 'normalize'));
leadfieldopt = ft_setopt(leadfieldopt, 'normalizeparam', ft_getopt(cfg, 'normalizeparam'));
leadfieldopt = ft_setopt(leadfieldopt, 'weight',         ft_getopt(cfg, 'weight'));

if ft_headmodeltype(headmodel, 'openmeeg')

  ft_hastoolbox('openmeeg', 1);  % add to path (if not yet on path)

  cfg.openmeeg = ft_getopt(cfg, 'openmeeg', []);
  batchsize    = ft_getopt(cfg.openmeeg, 'batchsize', 1e4);  % number of voxels per DSM batch; set to e.g. 1000 if not much RAM available
  keepdsm      = ft_getopt(cfg.openmeeg, 'keepdsm', 'no');   % retain DSM

  leadfieldopt = ft_setopt(leadfieldopt, 'dsm',         ft_getopt(cfg.openmeeg, 'dsm')); % reuse existing DSM if provided
  leadfieldopt = ft_setopt(leadfieldopt, 'nonadaptive', ft_getopt(cfg.openmeeg, 'nonadaptive', 'no'));

  % repeated system calls to the openmeeg executable makes it rather slow, calling it once is much more efficient
  fprintf('calculating leadfield for %d positions at a time, this may take a while...\n', batchsize);

  % a dsm in the input cfg currently assumes that the 'content' of the dsm matches
  % exactly the positions that were passed in sourcemodel.pos. This is not guaranteed
  % of course. If anything, it would make sense to represent the dsm in the input
  % sourcemodel, so that the pos, and dsm are bound together. Still no guarantee, but
  % better than nothing. This means that the cfg.openmeeg.dsm option should be
  % deprecated

  ndip       = length(insideindx);
  numchunks  = ceil(ndip/batchsize);
  dippos     = sourcemodel.pos(insideindx,:);

  if(numchunks > 1)
    if istrue(keepdsm)
      ft_warning('Keeping DSM output not supported when the computation is split into batches')
    end
    keepdsm = false;
  end

  % DSM computation is computationally intensive: As it can be reused with same voxel
  % sourcemodel (i.e. if voxels are defined in MRI coordinates rather than MEG
  % coordinates), optionally save result. Dense voxel grids may require several
  % gigabytes of RAM, so optionally split into smaller batches
  dsm = ft_getopt(leadfieldopt, 'dsm');
  if istrue(keepdsm) && ~isempty(dsm)
    % dsm needs to be computed outside ft_compute_leadfield, because it needs to be passed on in the output
    dsm          = ft_sysmat_openmeeg(dippos, headmodel, sens, ft_getopt(leadfieldopt, 'nonadaptive'));
    leadfieldopt = ft_setopt(leadfieldopt, 'dsm', dsm);
  end

  sourcemodel.leadfield = cell(size(sourcemodel.pos,1),1);
  ft_progress('init', cfg.feedback, 'computing leadfield');
  for k = 1:numchunks
    ft_progress(k/numchunks, 'computing leadfield %d/%d\n', k, numchunks);
    diprange = (((k-1)*batchsize + 1):(min(k*batchsize,ndip)));
    tmp      = ft_compute_leadfield(dippos(diprange,:), sens, headmodel, leadfieldopt{:});
    % distribute the columns of the leadfield matrix over the individual dipole positions
    % avoid using the options reducerank and backproject, see https://github.com/fieldtrip/fieldtrip/issues/1410#issuecomment-646994620
    [m, n] = size(tmp);
    sourcemodel.leadfield(insideindx(diprange)) = mat2cell(tmp, m, repmat(n/numel(diprange), 1, numel(diprange)));
  end
  ft_progress('close');

  if istrue(keepdsm)
    % retain DSM in cfg if desired -> FIXME this should not be kept in
    % the cfg. If anything, it is sourcemodel specific, so it should be
    % retained in the output sourcemodel
    cfg.openmeeg.dsm = dsm;
  end

elseif ft_headmodeltype(headmodel, 'singleshell')
  cfg.singleshell = ft_getopt(cfg, 'singleshell', []);
  batchsize       = ft_getopt(cfg.singleshell, 'batchsize', 1);
  if ischar(batchsize) && strcmp(batchsize, 'all')
    batchsize = length(insideindx);
  end

  dippos     = sourcemodel.pos(insideindx,:);
  ndip       = length(insideindx);
  numchunks  = ceil(ndip/batchsize);

  sourcemodel.leadfield = cell(size(sourcemodel.pos,1),1);
  ft_progress('init', cfg.feedback, 'computing leadfield');
  for k = 1:numchunks
    ft_progress(k/numchunks, 'computing leadfield %d/%d\n', k, numchunks);
    diprange = (((k-1)*batchsize + 1):(min(k*batchsize,ndip)));
    tmp      = ft_compute_leadfield(dippos(diprange,:), sens, headmodel, leadfieldopt{:});
    % distribute the columns of the leadfield matrix over the individual dipole positions
    % avoid using the options reducerank and backproject, see https://github.com/fieldtrip/fieldtrip/issues/1410#issuecomment-646994620
    [m, n] = size(tmp);
    sourcemodel.leadfield(insideindx(diprange)) = mat2cell(tmp, m, repmat(n/numel(diprange), 1, numel(diprange)));
  end
  ft_progress('close');

elseif ft_headmodeltype(headmodel, 'duneuro')
%   ft_hastoolbox('duneuro', 1); %does not look necessary here? check
  % repeated system calls to the duneuro executable makes it rather slow
  % calling it once for all dipoles is much more efficient

  % find the indices of all grid points that are inside the brain
  insideindx = find(sourcemodel.inside);

  ft_progress('init', cfg.feedback, 'computing leadfield');
  % compute the leadfield on all grid positions inside the brain
  lf = ft_compute_leadfield(sourcemodel.pos(insideindx,:), sens, headmodel, 'reducerank', cfg.reducerank, 'normalize', cfg.normalize, 'normalizeparam', cfg.normalizeparam, 'backproject', cfg.backproject);
  lf = mat2cell(lf, size(lf,1), repmat(3,1,size(lf,2)/3));
  sourcemodel.leadfield(sourcemodel.inside) = lf;
  for i=1:length(insideindx)
    thisindx = insideindx(i);
    if isfield(cfg, 'grid') && isfield(cfg.grid, 'mom')
      % multiply with the normalized dipole moment to get the leadfield in the desired orientation
      sourcemodel.leadfield{thisindx} = sourcemodel.leadfield{thisindx} * sourcemodel.mom(:,thisindx);
    end
  end % for all grid locations inside the brain

elseif ft_headmodeltype(headmodel, 'interpolate')

  lf = ft_compute_leadfield(sourcemodel.pos(insideindx,:), sens, headmodel, leadfieldopt{:});
  sourcemodel.leadfield(insideindx) = mat2cell(lf, 3, 3.*ones(1,numel(insideindx)));

else
  ft_progress('init', cfg.feedback, 'computing leadfield');
  for i=1:length(insideindx)
    % compute the leadfield on all sourcemodel positions inside the brain
    ft_progress(i/length(insideindx), 'computing leadfield %d/%d\n', i, length(insideindx));
    thisindx = insideindx(i);
    sourcemodel.leadfield{thisindx} = ft_compute_leadfield(sourcemodel.pos(thisindx,:), sens, headmodel, leadfieldopt{:});
  end % for all sourcemodel locations inside the brain
  ft_progress('close');
end

if isfield(cfg, 'sourcemodel') && isfield(cfg.sourcemodel, 'mom')
  for i=1:length(insideindx)
    % multiply with the normalized dipole moment to get the leadfield in the desired orientation
    % FIXME mom and ori seem to be mixed up here, see https://github.com/fieldtrip/fieldtrip/issues/1399
    thisindx = insideindx(i);
    sourcemodel.leadfield{thisindx} = sourcemodel.leadfield{thisindx} * sourcemodel.mom(:,thisindx);
  end
end

% represent the leadfield for positions outside the brain as empty array
sourcemodel.leadfield(~sourcemodel.inside) = {[]};

% add the label of the channels
sourcemodel.label           = sens.label;
sourcemodel.leadfielddimord = '{pos}_chan_ori';

% mollify the leadfields
if ~isequal(cfg.mollify, 'no')
  sourcemodel = mollify(cfg, sourcemodel);
end

% combine leadfields in patches and do an SVD on them
if ~isequal(cfg.patchsvd, 'no')
  sourcemodel = patchsvd(cfg, sourcemodel);
end

% compute the 50 percent channel selection subspace projection
if ~isequal(cfg.sel50p, 'no')
  sourcemodel = sel50p(cfg, sourcemodel, sens);
end

% compute the local basis function expansion (LBEX) subspace projection
if ~isequal(cfg.lbex, 'no')
  sourcemodel = lbex(cfg, sourcemodel);
end

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

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