% Set-up script for ISCE processing to TRAIN.
%
%     Copyright (C) 2016  Bekaert David
%     davidbekaert.com
%
%     This program is free software; you can redistribute it and/or modify
%     it under the terms of the GNU General Public License as published by
%     the Free Software Foundation; either version 2 of the License, or
%     (at your option) any later version.
%
%     This program is distributed in the hope that it will be useful,
%     but WITHOUT ANY WARRANTY; without even the implied warranty of
%     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
%     GNU General Public License for more details.
%
%     You should have received a copy of the GNU General Public License along
%     with this program; if not, write to the Free Software Foundation, Inc.,
%     51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
%
% By David Bekaert
% modifications:
% DB    20/12/2012      Include loading and storing of the IFG's too for
%                       phase-based methods

close all
clear all
clc

%% SETUP SCRIPT compatible with InsarApp.py
% inputs from user
% IFG folders are "date1-date2" or "date1_date2".
% How are date1 and date2 defined?
date_format = 'yyyymmdd';           % this needs to be recognized by matlab.
                                    % mmm for jan format, MM is min two digit,
                                    % while hh is hour 2 digit. You can
                                    % also include - or / if needed. e.g.
                                    % 'yyyy-mmm-dd'

% MASK file. In case there is a file called "MASK" with the same
% size of the data then it will be applied.
% in addtion, nodata in the lonlat data can be masked as well.
nodata_lonlat =0;                   % either a number of [] to ignore

% also save the phase data in a stamps-like format which allows to use plotting
% functionality from stamps.
save_data = 'y';                    % string either 'y' or 'n'

% radar or geo-coordinates
process_type = 'geo';               % a string either 'radar' or 'geo'

% satellite UTC time
UTC_time = '14:30';                 % a string defined as 'HH:MM'

% full path to your DEM file. Easiest is if this is a grd.
DEMfile = '/Volumes/Bekaert_disk2/Projects2/DEM/Taiwan/dem.grd';

% TRAIN directory (best not to change such it remains consistent between programs)
TRAIN_dir = 'aps_train';            % the location where the TRAIN dir will be set-up

% plot debug figures
plot_debug = 'y';                   % string either 'y' or 'n'

% filename of the unwrapped data
unw_filename = 'filt_topophase.unw';    % note the '.geo' string is added automatically if needed

%% CHECK if the DEM file exist
if exist(DEMfile,'file')~=2
    error([DEMfile ' does not exist']);
end

%% check if the type is correct
geo_str = '';
if strcmpi(process_type,'geo')
    geo_str = '.geo';
end
if ~strcmpi(process_type,'geo') && ~strcmpi(process_type,'radar')
    error(['process_type can only be ''geo'' or ''radar'''])
end

%% check on the filenames if needed
[temp1,temp2,temp3] =fileparts(unw_filename);
if strcmpi(geo_str,'.geo') && ~strcmpi(temp3,'.geo')
    fprintf(['Looks like you want to run train in .geo mode\nYour unw_filename does not have a ".geo" extension\n'])
    fprintf(['***You can ignore this if you do not plan to run the TRAIN phase-based correction methods.***\n'])
    % Check if action is needed
    repeat=1;
    while repeat==1
        action_flag= input('Do you want to update it to .geo? [y/n] ','s');
        if strcmpi(action_flag,'y')
            repeat=0;
        elseif strcmpi(action_flag,'n')
            repeat=0;
        end
    end
    if strcmpi(action_flag,'y')
        unw_filename = [unw_filename '.geo'];
    else
        repeat=1;
        while repeat==1
            action_flag= input('Do you want to continue? [y/n] ','s');
            if strcmpi(action_flag,'y')
                repeat=0;
            elseif strcmpi(action_flag,'n')
                repeat=0;
            end
        end
        if strcmpi(action_flag,'n')
           error('Abord by user. Update the unw_filename')
        end
    end
end

%% generate output directory to save along the way data
TRAIN_dir = [pwd filesep TRAIN_dir filesep 'SMALL_BASELINES' filesep];
if exist(TRAIN_dir,'dir')~=7
    mkdir(TRAIN_dir)
else
    error(['Directory exist: remove and rerun: ' TRAIN_dir])
end

%% GENERATE a list of IFG COMBINATIONS
list1 = dir('1*');      % get all the dir pre 2000
list2 = dir('2*');      % get all the dir post 2000
list = [list1 ;list2];  % combine the lists
clear list1 list2

% location of the lon and lat file
latfile = [];
latxmlfile = [];
lonfile = [];
lonxmlfile = [];
losfile = [];
losxmlfile = [];
hgtfile = [];
hgtxmlfile = [];
unwfile = [];
% information on the sensor
insarappxmlfile = [];
% extracting the ifg combinations
for k = 1:length(list)
    ifgday(k,:) = list(k).name;

    % search for a lon, lat and xml file
    if exist([ ifgday(k,:) filesep 'lon.rdr' geo_str],'file')==2 && exist([ ifgday(k,:) filesep 'lat.rdr' geo_str],'file')==2 && exist([ ifgday(k,:) filesep 'lon.rdr' geo_str '.xml'],'file')==2 && exist([ ifgday(k,:) filesep 'lat.rdr' geo_str '.xml'],'file')==2 && isempty(lonfile)
        lonfile = [ ifgday(k,:) filesep 'lon.rdr' geo_str];
        lonxmlfile = [ ifgday(k,:) filesep 'lon.rdr' geo_str '.xml'];
        latfile = [ ifgday(k,:) filesep 'lat.rdr' geo_str];
        latxmlfile = [ ifgday(k,:) filesep 'lat.rdr' geo_str '.xml'];
    end
    % search for the los file
    if exist([ ifgday(k,:) filesep 'los.rdr' geo_str],'file')==2 && exist([ ifgday(k,:) filesep 'los.rdr' geo_str '.xml'],'file')==2 && isempty(losfile)
        losfile = [ ifgday(k,:) filesep 'los.rdr' geo_str];
        losxmlfile = [ ifgday(k,:) filesep 'los.rdr' geo_str '.xml'];
    end
    % search for the hgt file
    if exist([ ifgday(k,:) filesep 'z.rdr' geo_str],'file')==2 && exist([ ifgday(k,:) filesep 'z.rdr' geo_str '.xml'],'file')==2 && isempty(hgtfile)
        hgtfile = [ ifgday(k,:) filesep 'z.rdr' geo_str];
        hgtxmlfile = [ ifgday(k,:) filesep 'z.rdr' geo_str '.xml'];
    end
    % search for the InSAR app xml file
    if exist([ ifgday(k,:) filesep 'insarApp.xml'],'file')==2 && isempty(insarappxmlfile)
        insarappxmlfile = [ ifgday(k,:) filesep 'insarApp.xml'];
    end
    % search for the unwrapped interferogram files
    if exist([ ifgday(k,:) filesep unw_filename],'file')==2
        unwfile{k} = [ifgday(k,:) filesep unw_filename];
    else
        unwfile{k} = [];
    end
end
clear list
% removing the separation between folders
if length(ifgday)<2*length(date_format)
    error('You folder names are not of format "DATE1[-/_/ /]DATE2')
end
ifgday1 = ifgday(:,1:length(date_format));
ifgday2 = ifgday(:,end-length(date_format)+1:end);
clear ifgday

% converting the dates in numerical dates
ifgday = [str2num(datestr(datenum(ifgday1,date_format),'yyyymmdd')) str2num(datestr(datenum(ifgday2,date_format),'yyyymmdd')) ];
clear ifgday1 ifgday2
ifgday = [datenum(num2str(ifgday(:,1)),'yyyymmdd') datenum(num2str(ifgday(:,2)),'yyyymmdd')];
day = unique(ifgday);
n_ifg = size(ifgday,1);
ifgday_ix = [];
for k=1:n_ifg
   ifgday_ix(k,1) = find(ifgday(k,1)==day);
   ifgday_ix(k,2) = find(ifgday(k,2)==day);
end
master_ix = 1;
master_day = day(master_ix);

%% GET LONLAT coordinates
if isempty(lonfile) || isempty(latfile) || isempty(latxmlfile)
    error('Could not file lon.rdr, lat.rdr, or lat.rdr.xml file')
end

% getting the file WIDTH's
[latwidth] = get_parm_xml(latxmlfile,'width');
[lonwidth] = get_parm_xml(lonxmlfile,'width');
[loswidth] = get_parm_xml(losxmlfile,'width');
if latwidth~=lonwidth || latwidth~=loswidth
    error(['Width of the lon, lat and los are not consistent'])
else
    WIDTH = latwidth;
    clear latwidth lonwidth lonwidth;
end
fprintf(['Width is ' num2str(WIDTH) '\n'])

% loading the lonlat information
% loading lon
LON = load_isce(lonfile);
if strcmpi(plot_debug,'y')
    figure('name','LON');
    imagesc(LON)
    axis equal; axis tight; colorbar; axis xy
end

% loading lat
LAT = load_isce(latfile);
if strcmpi(plot_debug,'y')
    figure('name','LAT');
    imagesc(LAT)
    axis equal; axis tight; colorbar; axis xy
end

% check if the lonlat needs to be masked
MASKED_flag = 'n';
if ~isempty(nodata_lonlat)
    MASK = ~((LON==nodata_lonlat) | (LAT==nodata_lonlat));        % mask of points to keep;
    MASKED_flag = 'y';
else
    MASK = logical(ones(size(LON)));
end

% check if a MASK file exist
if exist('MASK','file')==2
    MASK_temp = load_isce(MASK);
    fprintf('Need to write piece of code which combines these MASK files together \n ')
    MASKED_flag = 'y';

    keyboard
end

% combining
lonlat = [LON(MASK) LAT(MASK)];
%lonlat = [reshape(LON,[],1) reshape(LAT,[],1)];
n_ps = size(lonlat,1);
clear LON LAT

% getting a position file that relates a vector to matrix position
[LENGTH] = get_parm_xml(latxmlfile,'length');
[J,I] = meshgrid([1:LENGTH],[1:WIDTH]);
IND = sub2ind([WIDTH LENGTH], I(MASK), J(MASK));
%IND = sub2ind([WIDTH LENGTH], reshape(I,[],1), reshape(J,[],1));
clear I J
% generate template xml for aps file
templatexmlfile = lonxmlfile;
aps_save([TRAIN_dir 'isce2train.mat'],IND,geo_str,WIDTH,LENGTH,MASKED_flag,templatexmlfile)

%% getting the heights if found
phase_based_good = 0;
if ~isempty(hgtfile)
    fprintf('Found heights and will store...\n')
    HGT = load_isce(hgtfile);
    hgt = HGT(MASK);
    clear HGT;
    aps_save([TRAIN_dir 'hgt2.mat'],hgt)
    phase_based_good = 1;
end

%% getting the unwrapped interferograms if found
if ~isempty(unwfile)
    fprintf('Found unwrapped IFGs, will store...\n')
    % try and allocate the memory in advance
    ph_uw = zeros([n_ps n_ifg]);
    for k=1:length(unwfile)
        if exist(unwfile{k},'file')==2
            try
                [DATA] = load_isce(unwfile{k});
                DATA = DATA(:,:,2);                 % first band is amplitude, second band is unwrapped phase
                % apply the mask and store the data
                ph_uw(:,k) = DATA(MASK);
                clear DATA
            catch
                keyboard
            end
        end
    end
    phase_based_good = phase_based_good+1;
    aps_save([TRAIN_dir 'phuw_sb2.mat'],ph_uw)
end

if phase_based_good==2
   fprintf('Found all the information to run phase-based TRAIN corrections\n')
   phase_based_good = 'y';
else
    phase_based_good = 'n';
end
aps_save([TRAIN_dir 'isce2train.mat'],phase_based_good)

%% getting the incidence angle
[TEMP] = load_isce(losfile);
INC = TEMP(:,:,1);
HEADING = TEMP(:,:,2);
clear TEMP
if strcmpi(plot_debug,'y')
    figure('name','INC');
    imagesc(INC)
    axis equal; axis tight; colorbar; axis xy
    figure('name','HEADING');
    imagesc(HEADING)
    axis equal; axis tight; colorbar; axis xy
end
la = INC(MASK)./180*pi;
%la = reshape(INC,[],1)./180*pi;
clear INC
heading = nanmean(HEADING(MASK));
clear HEADING

%% getting the sensor information
% getting the file WIDTH
[SENSOR] = get_parm_xml(insarappxmlfile,'Sensor name');
fprintf(['Sensor is ' num2str(SENSOR) '\n'])

% getting the wavelength hard-coded
if strcmpi(SENSOR,'alos')
    lambda = 23.6;
elseif strcmpi(SENSOR,'radarsat2') || strcmpi(SENSOR,'radarsat') || strcmpi(SENSOR,'rsat') || strcmpi(SENSOR,'rsat2') ||   strcmpi(SENSOR,'envisat') || strcmpi(SENSOR,'ers') || strcmpi(SENSOR,'env') || strcmpi(SENSOR,'ers1')  || strcmpi(SENSOR,'ers2')
    lambda = 5.6;
else
   error('Sensor wavelength not yet hard-coded')
end
% convert to m
lambda =lambda./100;

%% saving the data
% stamps-like format
psver =2;
save([TRAIN_dir 'psver.mat'],'psver')
aps_save([TRAIN_dir 'ps2.mat'],lonlat,n_ifg,n_ps,day,ifgday_ix,ifgday,master_day,master_ix)
aps_save([TRAIN_dir 'la2.mat'],la)
dlmwrite([TRAIN_dir 'lambda.1.in'],lambda)
dlmwrite([TRAIN_dir 'heading.1.in'],heading)
dlmwrite([TRAIN_dir 'WIDTH.txt'],WIDTH)
fid = fopen([TRAIN_dir 'processor.txt'],'w');
fprintf(fid,'isce');
fclose(fid)
% will make few dummy directories
ERA_dir = [TRAIN_dir 'ERA'];
MERRA_dir = [TRAIN_dir 'MERRA'];
MODIS_dir = [TRAIN_dir 'MODIS'];
MERIS_dir = [TRAIN_dir 'MERIS'];
if exist([ERA_dir],'dir')~=7
    mkdir(ERA_dir)
end
if exist([MERRA_dir],'dir')~=7
    mkdir(MERRA_dir)
end
if exist([MERIS_dir],'dir')~=7
    mkdir(MERIS_dir)
end
if exist([MODIS_dir],'dir')~=7
    mkdir(MODIS_dir)
end
cd(TRAIN_dir)
% setting the stamps parameters
getparm                                 % this is for PS
setparm('small_baseline_flag','y')      % change to SB
setparm('percent_rand',[],-1)           % resetting all PS to SB variables
setparm('weed_standard_dev',[],-1)
setparm('scla_drop_index',[],-1)
setparm('unwrap_method',[],-1)
setparm('merge_resample_size',[],-1)
getparm                                 % now this will be for SB
% setting the TRAIN parameters
getparm_aps
setparm_aps('UTC',UTC_time)
setparm_aps('era_datap',ERA_dir)
setparm_aps('merra_datap',MERRA_dir)
setparm_aps('meris_datap',MERIS_dir)
setparm_aps('modis_datap',MODIS_dir)
setparm_aps('demfile',DEMfile)


function [model] = createPeriplasmaticSpace(model,microbeID,infoFile)
% Part of the DEMETER pipeline. This function creates a periplasmatic space
% for refined reconstructions if it is appropriate for the organism. The
% periplasmatic space is created by by retrieving all extracellular
% metabolites and adding a third compartment.
%
% USAGE
%       [model] = createPeriplasmaticSpace(model,microbeID,infoFile)
%
% INPUT
% model             COBRA model structure
% microbeID:        ID of the reconstructed microbe that serves as the
%                   reconstruction name and to identify it in input tables
% infoFile:         Table with taxonomic and gram staining information on
%                   microbes to reconstruct
%
% OUTPUT
% model             COBRA model structure
%
% AUTHOR:
%       - Almut Heinken, 03/2020

% get the information on taxonomy and gram staining to find out if a periplasmatic space
% should be added
phylCol=find(strcmp(infoFile(1,:),'Phylum'));
if ~isempty(find(strcmp(infoFile(:,1),microbeID)))
    phylum=infoFile{find(strcmp(infoFile(:,1),microbeID)),phylCol};
    genCol=find(strcmp(infoFile(1,:),'Genus'));
    genus=infoFile{find(strcmp(infoFile(:,1),microbeID)),genCol};

    [~,gramCol,~]=intersect(infoFile(1,:),{'Gram Staining','Gram_Staining'});
    gramStatus=infoFile(find(strcmp(infoFile(:,1),microbeID)),gramCol);
    if length(gramStatus)>1
        gramStatus = gramStatus{1};
    end
        if (strcmp(gramStatus,'Gram-') || strcmp(phylum,'Deinococcus-Thermus')) && ~any(strcmp(phylum,{'Euryarchaeota','Crenarchaeota','Thaumarchaeota','Tenericutes','Chloroflexi','Chloroflexota'})) && ~any(strcmp(genus,{'Acidaminobacter','Gracilibacter','Intestinibacillus','Mageeibacillus','Massiliomicrobiota','Flavonifractor','Pseudoflavonifractor'}))

            % get all extracellular metabolites
            exMets=model.mets(find(contains(model.mets,'[e]')));

            % Add periplasmatic metabolites, metNames and metFormulas
            metNames = {};
            metFormulas = {};
            metCharges = [];

            for i=1:length(exMets)
                pMets{i} = strrep(exMets{i},'[e]','[p]');
                metNames{i} = model.metNames{find(strcmp(model.mets,exMets{i}))};
                metFormulas{i} = model.metFormulas{find(strcmp(model.mets,exMets{i}))};
                metCharges(i) = model.metCharges(find(strcmp(model.mets,exMets{i})));
            end

            modelNew=model;
            % Add all new periplasmatic metabolites
            pMets=setdiff(pMets,model.mets);
            for i=1:length(pMets)
                modelNew = addMetabolite(modelNew, pMets{i}, 'metName', metNames{i}, 'metFormula', metFormulas{i}, 'Charge', metCharges(i));
            end

            % Get all transport reactions associated with the exchange metabolites
            rxnsToAdd = {};
            rxnNames = {};
            rxnFormulas = {};
            rxnLB = [];
            rxnUB = [];
            rxnSubsystem = {};

            % convert extracellular transport reactions to transport reactions from
            % periplasmatic space to cytosol
            for i=1:length(exMets)
                transpRxns = findRxnsFromMets(model,exMets{i});
                % remove exchange reactions
                transpRxns(find(strncmp(transpRxns,'EX_',3)))=[];
                for j=1:length(transpRxns)
                    rxnsToAdd{end+1} = [transpRxns{j} 'pp'];
                    rxnNames{end+1} = [model.rxnNames{find(strcmp(model.rxns,transpRxns{j}))} ', periplasmatic'];
                    rxnLB(end+1) = model.lb(find(strcmp(model.rxns,transpRxns{j})));
                    rxnUB(end+1) = model.ub(find(strcmp(model.rxns,transpRxns{j})));
                    form = printRxnFormula(model,transpRxns{j});
                    rxnFormulas{end+1} = strrep(form{1},'[e]','[p]');
                    rxnSubsystem{end+1} = 'Transport, periplasmatic';
                end
                modelNew = removeRxns(modelNew,transpRxns, 'metFlag', false);
            end

            % add transport reactions to transport reactions from
            % extracellular to periplasmatic space
            for i=1:length(exMets)
                rxnsToAdd{end+1} = [upper(strrep(exMets{i},'[e]','')) 'tex'];
                rxnNames{end+1} = [model.metNames{find(strcmp(model.mets,exMets{i}))} ' diffusion extracellular to periplasm'];
                rxnLB(end+1) = -1000;
                rxnUB(end+1) = 1000;
                rxnFormulas{end+1} = [exMets{i} ' <=> ' strrep(exMets{i},'[e]','[p]')];
                rxnSubsystem{end+1} = 'Transport, extracellular';
            end

            % add all new reactions
            for i=1:length(rxnsToAdd)
                modelNew = addReaction(modelNew,rxnsToAdd{i},'reactionName',rxnNames{i},...
                    'reactionFormula',rxnFormulas{i},'lowerBound',rxnLB(i),'upperBound',rxnUB(i),'subSystem',rxnSubsystem{i});
            end

            model = convertOldStyleModel(modelNew);
        end
    end
end


function dtiWriteFibersPdb(fg, xformToAcpc, pdbFname)
%
% dtiWriteFibersPdb([fg=uigetfile], [xformToAcpc=eye(4)], [[pdbFname=uiputfile])
%
% Writes the fiber group to disk in the specified file using the PDB format
% recognized by CINCH.
% * Note that .pdb extension will be added to pdbFname.
%
% Example usage:
% dtiWriteFibersPdb(fg,dt.xformToAcpc,fullfile(fiberDir,'Lfibers'));
%
% Note that CINCH doesn't use the xformToAcpc, so you can safely skip it.
%
%
% HISTORY:
% 2008.07.02 LMP: wrote it.
% 2011.01.27 LMP: Now just uses mtrExport fibers.
%
%
disp([mfilename ' is now obsolete -- wrapping your inputs for mtrExportFibers...']);

if(~exist('fg','var')||isempty(fg))
    [fg,fgName] = dtiReadFibers;
    [p,f,e] = fileparts(fgName);
    fgName = fullfile(p,[f '.pdb']);
else
    fgName = fullfile(pwd,'fibers.pdb');
end

if(~exist('xformToAcpc','var')||isempty(xformToAcpc))
    xformToAcpc = [];
end

if(~exist('pdbFname','var')||isempty(pdbFname))
    [f,p] = uiputfile(fgName,'Save pdb file as...');
    if(isequal(f,0)), disp('user canceled.'); return; end
    pdbFname = fullfile(p,[f '.pdb']);
end
mtrExportFibers(fg, pdbFname);

return

% if(~exist('fg','var')||isempty(fg))
%     [fg,fgName] = dtiReadFibers;
%     [p,f,e] = fileparts(fgName);
%     fgName = fullfile(p,[f '.pdb']);
% else
%     fgName = fullfile(pwd,'fibers.pdb');
% end
%
% if(~exist('xformToAcpc','var')||isempty(xformToAcpc))
%     xform = eye(4);
% else
%     % The xform that CINCH/dtiQuery wants assumes 1mm voxels:
%     [t,r,s,k] = affineDecompose(xformToAcpc);
%     xform = affineBuild(t,r,sign(s),k);
% end
%
% if(~exist('pdbFname','var')||isempty(pdbFname))
%     [f,p] = uiputfile(fgName,'Save pdb file as...');
%     if(isequal(f,0)), disp('user canceled.'); return; end
%     pdbFname = fullfile(p,f);
% end
%
% % add the .pdb file extension
% if(~strcmpi(pdbFname(end-3:end),'.pdb'))
%     pdbFname = [pdbFname,'.pdb'];
% end
%
% dtiWritePDBHeader(xform, pdbFname);
% offsets = dtiAppendPathwaysToPDB(fg, pdbFname);
% dtiAppendFileOffsetsToPDB(offsets, pdbFname);
%
% return


function C = times(A, B)
%*    CHEBOP multiplication.
%   C = A.*B, where ones of a A or B is a CHEBOP and the other a scalar
%   is equivalent to A*B.
%
%   All other instances returns an error.
%
% See also CHEBOP/MTIMES.

% Copyright 2017 by The University of Oxford and The Chebfun Developers.
% See http://www.chebfun.org/ for Chebfun information.

if ( isnumeric(A) || isnumeric(B) )
    C = mtimes(A, B);
else
    error('CHEBOP:TIMES:NotSupported', '%s.*%s is not supported.', ...
        class(A), class(B));
end

end


%kkpad 'Pad Data with a Constant Value'
% This MatLab function was automatically generated by a converter (KhorosToMatLab) from the Khoros kpad.pane file
%
% Parameters:
% InputFile: i 'Input ', required: 'Input data file'
% Integer: wsize 'Padded Width ', default: 512: 'Size of width dimension after padding'
% Integer: hsize 'Padded Height ', default: 512: 'Size of height dimension after padding'
% Integer: dsize 'Padded Depth ', default: 1: 'Size of depth dimension after padding'
% Integer: tsize 'Padded Time Size ', default: 1: 'Size of time dimension after padding'
% Integer: esize 'Padded Element Size', default: 1: 'Size of element dimension after padding'
% Integer: woff 'Width Offset ', default: 0: 'Offset of original object in width dimension'
% Integer: hoff 'Height Offset ', default: 0: 'Offset of original object in height dimension'
% Integer: doff 'Depth Offset ', default: 0: 'Offset of original object in depth dimension'
% Integer: toff 'Time Offset ', default: 0: 'Offset of original object in time dimension'
% Integer: eoff 'Element Offset ', default: 0: 'Offset of original object in elements dimension'
% Toggle: wrap 'Fill Outside Data Regions by WRAPPING', default: 0: 'fill outside data regions by WRAPPING'
% OutputFile: o 'Output', required: 'Resulting output file'
%
% Example: o = kkpad(i, {'i','';'wsize',512;'hsize',512;'dsize',1;'tsize',1;'esize',1;'woff',0;'hoff',0;'doff',0;'toff',0;'eoff',0;'wrap',0;'o',''})
%
% Khoros helpfile follows below:
%
%  PROGRAM
% kpad - Pad Data with a Constant Value
%
%  DESCRIPTION
% "Pad Object" (kpad) performs the padding of a data object using the pad
% values defined by the Real and Imaginary padding value options.
%
%  "Size"
% The output data object will be the size specified by the final
% padded size parameters, Padded Width, Padded Height, etc (wsize,
% hsize, dsize, tsize, esize).
%
%  "Offset Values"
% The offset parameters (woff, hoff, doff, toff, eoff) define where the
% origin of the source object will lie with respect to the output object.
% Specifying an offset greater than zero can be used to generate a border
% around the original data.  Negative offset values will result in
% truncation of data lying in the region (0-woff, 0-hoff, 0-doff, 0-toff,
% 0-eoff).  For example, if an offset of (-1,-1,0,0,0) is specified, the
% object will effectively be shifted by -1 in the width and height dimensions,
% and that data truncated in the destination object.  If the offset plus
% the original data size is greater than the specified destination size,
% truncation of the source data will occur.
% If the input object is larger than the final padded size specified,
% the output data object will be truncated to the specified size.
%
%  "Pad Values"
% The Real Pad Value (real) specifies the pad value that will be assigned
% to the real component of a complex pair, and the Imaginary Pad Value
% (imag) specifies the imaginary component of the pair.
% If the input data object type is not complex, the imaginary pad value
% will be ignored.  For input data objects that are not of type double,
% the specified pad values are cast to the same type as the input data object.
%
%  "Wrapping"
% The regions outside the original data bounds can be filled also by wrapping
% data from the opposite side of the dataset by specifying the Wrap flag.
% This will override the Pad Value functionality.
%
%  "Mask Data & Validity Option"
% The validity mask corresponding to padded data will be zero if
% the user specifies that padded data added by this program be marked
% as invalid (valid FALSE).  Likewise, if the user specifies that padded
% data is valid (valid TRUE), the mask corresponding to padded data will
% be non-zero.  In the first case (invalid), if no mask exists in the
% source object, on will be created.  In the valid case, no mask will be
% created.  Validity mask data corresponding to the original source object
% data is transferred to the destination unaltered.
%
%  "Location & Time Data"
% If curvilinear or rectilinear time or location data
% exist, it is unclear how to alter the dimensionality,
% so the pad operation will fail.  If uniform location data exist
% padding occurs, but the location information is not altered in
% any way.
%
%  "Map Data"
% The pad operator does not modify map data.
%
%  "Failure Modes"
% The input object must contain value or mask data.
%
%
%
%  EXAMPLES
%
% kpad -i input_file -o output_file- Pad Data with a Constant Value
% Will create a zero padded output object, using the default
% size and zero offset.
%
% kpad -i input_file -o output_file -wsize 512 -hsize 256 -real 200 -imag 100- Pad Data with a Constant Value
% This padding operation will produce an output object with a
% width of 512 and height of 256.  If the input data is complex,
% padding for the real component will be 200, and 100 for the
% imaginary component.   If the data is not complex, the imaginary
% value is ignored.
%
%  "SEE ALSO"
%
%  RESTRICTIONS
% kpad will fail if the source object contains curvilinear or rectilinear
% location or time data.  If uniform time or location data exist, it is
% transferred, but not modified.
%
%  REFERENCES
%
%  COPYRIGHT
% Copyright (C) 1993 - 1997, Khoral Research, Inc. ("KRI")  All rights reserved.
%

function varargout = kkpad(varargin)
if nargin ==0
  Inputs={};arglist={'',''};
elseif nargin ==1
  Inputs=varargin{1};arglist={'',''};
elseif nargin ==2
  Inputs=varargin{1}; arglist=varargin{2};
else error('Usage: [out1,..] = kkpad(Inputs,arglist).');
end
if size(arglist,2)~=2
  error('arglist must be of form {''ParameterTag1'',value1;''ParameterTag2'',value2}')
 end
narglist={'i', '__input';'wsize', 512;'hsize', 512;'dsize', 1;'tsize', 1;'esize', 1;'woff', 0;'hoff', 0;'doff', 0;'toff', 0;'eoff', 0;'wrap', 0;'o', '__output'};
maxval={0,2,2,2,2,2,0,0,0,0,0,0,0};
minval={0,2,2,2,2,2,0,0,0,0,0,0,0};
istoggle=[0,1,1,1,1,1,1,1,1,1,1,1,0];
was_set=istoggle * 0;
paramtype={'InputFile','Integer','Integer','Integer','Integer','Integer','Integer','Integer','Integer','Integer','Integer','Toggle','OutputFile'};
% identify the input arrays and assign them to the arguments as stated by the user
if ~iscell(Inputs)
Inputs = {Inputs};
end
NumReqOutputs=1; nextinput=1; nextoutput=1;
  for ii=1:size(arglist,1)
  wasmatched=0;
  for jj=1:size(narglist,1)
   if strcmp(arglist{ii,1},narglist{jj,1})  % a given argument was matched to the possible arguments
     wasmatched = 1;
     was_set(jj) = 1;
     if strcmp(narglist{jj,2}, '__input')
      if (nextinput > length(Inputs))
        error(['Input ' narglist{jj,1} ' has no corresponding input!']);
      end
      narglist{jj,2} = 'OK_in';
      nextinput = nextinput + 1;
     elseif strcmp(narglist{jj,2}, '__output')
      if (nextoutput > nargout)
        error(['Output nr. ' narglist{jj,1} ' is not present in the assignment list of outputs !']);
      end
      if (isempty(arglist{ii,2}))
        narglist{jj,2} = 'OK_out';
      else
        narglist{jj,2} = arglist{ii,2};
      end

      nextoutput = nextoutput + 1;
      if (minval{jj} == 0)
         NumReqOutputs = NumReqOutputs - 1;
      end
     elseif isstr(arglist{ii,2})
      narglist{jj,2} = arglist{ii,2};
     else
        if strcmp(paramtype{jj}, 'Integer') & (round(arglist{ii,2}) ~= arglist{ii,2})
            error(['Argument ' arglist{ii,1} ' is of integer type but non-integer number ' arglist{ii,2} ' was supplied']);
        end
        if (minval{jj} ~= 0 | maxval{jj} ~= 0)
          if (minval{jj} == 1 & maxval{jj} == 1 & arglist{ii,2} < 0)
            error(['Argument ' arglist{ii,1} ' must be bigger or equal to zero!']);
          elseif (minval{jj} == -1 & maxval{jj} == -1 & arglist{ii,2} > 0)
            error(['Argument ' arglist{ii,1} ' must be smaller or equal to zero!']);
          elseif (minval{jj} == 2 & maxval{jj} == 2 & arglist{ii,2} <= 0)
            error(['Argument ' arglist{ii,1} ' must be bigger than zero!']);
          elseif (minval{jj} == -2 & maxval{jj} == -2 & arglist{ii,2} >= 0)
            error(['Argument ' arglist{ii,1} ' must be smaller than zero!']);
          elseif (minval{jj} ~= maxval{jj} & arglist{ii,2} < minval{jj})
            error(['Argument ' arglist{ii,1} ' must be bigger than ' num2str(minval{jj})]);
          elseif (minval{jj} ~= maxval{jj} & arglist{ii,2} > maxval{jj})
            error(['Argument ' arglist{ii,1} ' must be smaller than ' num2str(maxval{jj})]);
          end
        end
     end
     if ~strcmp(narglist{jj,2},'OK_out') &  ~strcmp(narglist{jj,2},'OK_in')
       narglist{jj,2} = arglist{ii,2};
     end
   end
   end
   if (wasmatched == 0 & ~strcmp(arglist{ii,1},''))
        error(['Argument ' arglist{ii,1} ' is not a valid argument for this function']);
   end
end
% match the remaining inputs/outputs to the unused arguments and test for missing required inputs
 for jj=1:size(narglist,1)
     if  strcmp(paramtype{jj}, 'Toggle')
        if (narglist{jj,2} ==0)
          narglist{jj,1} = '';
        end;
        narglist{jj,2} = '';
     end;
     if  ~strcmp(narglist{jj,2},'__input') && ~strcmp(narglist{jj,2},'__output') && istoggle(jj) && ~ was_set(jj)
          narglist{jj,1} = '';
          narglist{jj,2} = '';
     end;
     if strcmp(narglist{jj,2}, '__input')
      if (minval{jj} == 0)  % meaning this input is required
        if (nextinput > size(Inputs))
           error(['Required input ' narglist{jj,1} ' has no corresponding input in the list!']);
        else
          narglist{jj,2} = 'OK_in';
          nextinput = nextinput + 1;
        end
      else  % this is an optional input
        if (nextinput <= length(Inputs))
          narglist{jj,2} = 'OK_in';
          nextinput = nextinput + 1;
        else
          narglist{jj,1} = '';
          narglist{jj,2} = '';
        end;
      end;
     else
     if strcmp(narglist{jj,2}, '__output')
      if (minval{jj} == 0) % this is a required output
        if (nextoutput > nargout & nargout > 1)
           error(['Required output ' narglist{jj,1} ' is not stated in the assignment list!']);
        else
          narglist{jj,2} = 'OK_out';
          nextoutput = nextoutput + 1;
          NumReqOutputs = NumReqOutputs-1;
        end
      else % this is an optional output
        if (nargout - nextoutput >= NumReqOutputs)
          narglist{jj,2} = 'OK_out';
          nextoutput = nextoutput + 1;
        else
          narglist{jj,1} = '';
          narglist{jj,2} = '';
        end;
      end
     end
  end
end
if nargout
   varargout = cell(1,nargout);
else
  varargout = cell(1,1);
end
global KhorosRoot
if exist('KhorosRoot') && ~isempty(KhorosRoot)
w=['"' KhorosRoot];
else
if ispc
  w='"C:\Program Files\dip\khorosBin\';
else
[s,w] = system('which cantata');
w=['"' w(1:end-8)];
end
end
[varargout{:}]=callKhoros([w 'kpad"  '],Inputs,narglist);


function[imdb] = setupImdbClassification(trainName, testName, net)
% [imdb] = setupImdbClassification(trainName, testName, net)

global DATAopts;

% Setup the Imdb
% Get images and labels
set = trainName;
[trainIms, ~] = textread(sprintf(DATAopts.imgsetpath,set),'%s %d'); %#ok<DTXTRD>
trainLabs = zeros(length(trainIms), DATAopts.nclasses);

% Get all testlabels
if ~strcmp(set,'test') || DATAopts.year == 2007
    for classIdx = 1 : DATAopts.nclasses
        class = DATAopts.classes{classIdx};
        [~, trainLabs(:,classIdx)] = textread(sprintf(DATAopts.clsimgsetpath, class, set), '%s %d'); %#ok<DTXTRD>
    end

    trainLabs(trainLabs == 0) = -1;
end

set = testName;
[testIms, ~] = textread(sprintf(DATAopts.imgsetpath,set),'%s %d'); %#ok<DTXTRD>
testLabs = zeros(length(testIms), DATAopts.nclasses);

% Get all testlabels
if ~strcmp(set,'test') || DATAopts.year == 2007
    for classIdx = 1 : DATAopts.nclasses
        class = DATAopts.classes{classIdx};
        [~, testLabs(:, classIdx)] = textread(sprintf(DATAopts.clsimgsetpath, class, set), '%s %d'); %#ok<DTXTRD>
    end

    testLabs(testLabs == -1) = 0;
end

% Make train, val, and test set.
numValIms = 500;
allIms = cat(1, trainIms, testIms);
allLabs = cat(1, trainLabs, testLabs);
datasetIdx{1} = (1 : length(trainIms) - numValIms)';  % Last numValIms are val set
datasetIdx{2} = (length(trainIms) - numValIms + 1 : length(trainIms))';
datasetIdx{3} = (length(trainIms) + 1 : length(allIms))';

% Setup the classification imdb
imdb = ImdbClassification(DATAopts.imgpath(1:end-6), ...        % path
    DATAopts.imgpath(end-3:end), ...      % image extension
    allIms, ...                           % all images
    allLabs, ...                          % all labels
    datasetIdx, ...                       % division into train/val/test
    net.meta.normalization.averageImage, ...   % average image used to pretrain network
    20);                                  % num classes

% Store lists for use in eval
imdb.misc.trainName = trainName;
imdb.misc.testName  = testName;
imdb.misc.trainIms  = trainIms;
imdb.misc.trainLabs = trainLabs;
imdb.misc.testIms   = testIms;
imdb.misc.testLabs  = testLabs;


function d = testing(a,d)

  d=set_x(d,feval('get_kernel',a,d,a.dat));


classdef TargetParameters < handle

    properties (Access = public)
        constr_tol
        optimality_tol
        Vfrac
        epsilon
        epsilon_velocity
        epsilon_perimeter
        epsilon_isotropy
        stressNormExponent
        iStep
    end

end


function ft_realtime_downsample(cfg)

% FT_REALTIME_DOWNSAMPLE reads realtime data from one buffer and writes it after downsampling
% to another buffer.
%
% Use as
%   ft_realtime_downsample(cfg)
% with the following configuration options
%   cfg.channel              = cell-array, see FT_CHANNELSELECTION (default = 'all')
%   cfg.decimation           = integer, downsampling factor (default = 1, no downsampling)
%   cfg.order                = interger, order of butterworth lowpass filter (default = 4)
%   cfg.cutoff               = double, cutoff frequency of lowpass filter (default = 0.8*Nyquist-freq.)
%
% The source of the data is configured as
%   cfg.source.dataset       = string
% or alternatively to obtain more low-level control as
%   cfg.source.datafile      = string
%   cfg.source.headerfile    = string
%   cfg.source.eventfile     = string
%   cfg.source.dataformat    = string, default is determined automatic
%   cfg.source.headerformat  = string, default is determined automatic
%   cfg.source.eventformat   = string, default is determined automatic
%
% The target to write the data to is configured as
%   cfg.target.datafile      = string, target destination for the data (default = 'buffer://localhost:1972')
%   cfg.target.dataformat    = string, default is determined automatic
%
% To stop this realtime function, you have to press Ctrl-C

% Copyright (C) 2008, Robert Oostenveld
% Copyright (C) 2010, Stefan Klanke
%
% 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$

% set the defaults
if ~isfield(cfg, 'source'),               cfg.source = [];                                  end
if ~isfield(cfg, 'target'),               cfg.target = [];                                  end
if ~isfield(cfg.source, 'headerformat'),  cfg.source.headerformat = [];                     end % default is detected automatically
if ~isfield(cfg.source, 'dataformat'),    cfg.source.dataformat = [];                       end % default is detected automatically
if ~isfield(cfg.target, 'headerformat'),  cfg.target.headerformat = [];                     end % default is detected automatically
if ~isfield(cfg.target, 'dataformat'),    cfg.target.dataformat = [];                       end % default is detected automatically
if ~isfield(cfg.target, 'datafile'),      cfg.target.datafile = 'buffer://localhost:1972';  end
if ~isfield(cfg, 'minblocksize'),         cfg.minblocksize = 0;                             end % in seconds
if ~isfield(cfg, 'maxblocksize'),         cfg.maxblocksize = 1;                             end % in seconds
if ~isfield(cfg, 'channel'),              cfg.channel = 'all';                              end

if ~isfield(cfg, 'decimation'),           cfg.decimation = 1;                               end
if ~isfield(cfg, 'order'),                cfg.order = 4;                                    end

if cfg.decimation < 1 || cfg.decimation~=round(cfg.decimation)
  error 'Decimation factor must be integer quantity >= 1';
end

% translate dataset into datafile+headerfile
cfg.source = ft_checkconfig(cfg.source, 'dataset2files', 'yes');
cfg.target = ft_checkconfig(cfg.target, 'dataset2files', 'yes');
ft_checkconfig(cfg.source, 'required', {'datafile' 'headerfile'});
ft_checkconfig(cfg.target, 'required', {'datafile' 'headerfile'});

% ensure that the persistent variables related to caching are cleared
clear ft_read_header
% read the header for the first time
hdr = ft_read_header(cfg.source.headerfile);
fprintf('updating the header information, %d samples available\n', hdr.nSamples*hdr.nTrials);

targethdr = hdr;
targethdr.Fs = targethdr.Fs/cfg.decimation;

% Calculate cutoff frequency expressed in Nyquist freq of original signal
if ~isfield(cfg, 'cutoff')
  cutoff = 0.8/cfg.decimation;
else
  cutoff = cfg.cutoff / (0.5*hdr.Fs);
  if cutoff >= 1
    ft_error('Cutoff frequency too high');
  end
end
[B,A] = butter(cfg.order, cutoff, 'low');

% define a subset of channels for reading
cfg.channel = ft_channelselection(cfg.channel, hdr.label);
chanindx    = match_str(hdr.label, cfg.channel);
nchan       = length(chanindx);
if nchan==0
  ft_error('no channels were selected');
end

minblocksmp = round(cfg.minblocksize*hdr.Fs);
minblocksmp = max(minblocksmp, 1);
maxblocksmp = round(cfg.maxblocksize*hdr.Fs);
prevSample  = 0;
count       = 0;

% create filter model and downsampling model
FM = online_filter_init(B, A, zeros(nchan, 1));
DM = online_downsample_init(cfg.decimation);

%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
% this is the general BCI loop where realtime incoming data is handled
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
while true

  % determine number of samples available in buffer
  hdr = ft_read_header(cfg.source.headerfile, 'cache', true);

  % see whether new samples are available
  newsamples = (hdr.nSamples*hdr.nTrials-prevSample);

  if newsamples>=minblocksmp

    % determine the samples to copy from source to target
    begsample = prevSample+1;
    endsample = prevSample + min(newsamples, maxblocksmp);

    % remember up to where the data was read
    prevSample  = endsample;
    count       = count + 1;
    fprintf('processing segment %d from sample %d to %d\n', count, begsample, endsample);

    % read data segment
    dat = ft_read_data(cfg.source.datafile, 'dataformat', cfg.source.dataformat, 'begsample', begsample, 'endsample', endsample, 'chanindx', chanindx, 'checkboundary', false);

    %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
    % from here onward it is specific to the downsampling
    %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%

    [FM, dat] = online_filter_apply(FM, dat);
    [DM, xd] = online_downsample_apply(DM, dat);

    if count==1
      % flush the file, write the header and subsequently write the data segment
      ft_write_data(cfg.target.datafile, dat, 'header', targethdr, 'dataformat', cfg.target.dataformat, 'chanindx', chanindx, 'append', false);
    else
      % write the data segment
      ft_write_data(cfg.target.datafile, dat, 'header', targethdr, 'dataformat', cfg.target.dataformat, 'chanindx', chanindx, 'append', true);
    end

  end % if enough new samples
end % while true


function new_padding_value = MimRemovePaddingValues(image_wrapper, metadata, reporting)

    new_padding_value = [];
    padding_indices = [];

    % Replace padding value with zero
    if (isfield(metadata, 'PixelPaddingValue'))
        padding_value = metadata.PixelPaddingValue;

        padding_indices = find(image_wrapper.RawImage == padding_value);
    end

    % Check for unspecified padding value in GE images
    if isfield(metadata, 'Manufacturer')
        if strcmp(metadata.Manufacturer, 'GE MEDICAL SYSTEMS')
            padding_indices = find(image_wrapper.RawImage == -2000);
        end
    end

    if ~isempty(padding_indices)
        image_wrapper.RawImage(padding_indices) = max(image_wrapper.RawImage(:));
        new_padding_value = min(image_wrapper.RawImage(:)) - 1;
        image_wrapper.RawImage(padding_indices) = new_padding_value;
    end
end


function exesuff=getexeext()
%
% exesuff=getexeext()
%
% get meshing external tool extension names for the current platform
%
% author: Qianqian Fang (fangq<at> nmr.mgh.harvard.edu)
%
% output:
%     exesuff: file extension for iso2mesh tool binaries
%
% -- this function is part of iso2mesh toolbox (http://iso2mesh.sf.net)
%

exesuff='.exe';
if(isunix)
	exesuff=['.',mexext];
end
if(isoctavemesh)
   if(~ispc)
      if(~ismac)
	   if(isempty(regexp(computer,'86_64')))
	      exesuff='.mexglx';
	   else
              exesuff='.mexa64';
	   end
      else
           if(isempty(regexp(computer,'86_64')))
              exesuff='.mexmaci';
           else
              exesuff='.mexmaci64';
           end
      end
   else
      exesuff='.exe';
   end
end


function run_REDaddon_sourcery(db, ops0)
ops = build_ops3(db, ops0);
% red channel addon to already processed data
mimgG = [];

if sum(ismember(ops.expts, ops.expred))>0
    mimgR = regRedChannelExpts(ops);
else
    if ops.nchannels_red==2
        % return green mean image from short red/green recording
        [mimgR, mimgG] = regRedGreenChannel(ops);
    else
        mimgR = regRedChannelOnly(ops);
    end
end

save(fullfile(ops.ResultsSavePath,'redchannel.mat'), 'mimgR','mimgG');

add_red_channel_sourcery(ops);


function [params]=get_parameterSRC
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%
% Example: params=get_parameter
%
% This function contains all the parameters needed for sr_startZ.m,
% sr_calcZ.m, etc.
%
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%
% Author:
% van Stiphout, Thomas, vanstiphout@sed.ethz.ch
%
% Created on 16.08.2007
%
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%

disp('~/zmap/src/thomas/seismicrates/get_parameterSRC');

params.sFile='08041405-NoDeclus.mat'; %ilename for result matrix
% params.sFile='08041401-Nodeclus.mat'; %ilename for result matrix
params.nLimit=500;
params.rContainer='rContainer';
% load catalog to work with (can also be selected later
params.sFilename='anss-1975-19923-Mc18-Landers-declus.mat';
eval(sprintf('load %s', params.sFilename));
if ~exist('mCatalog')
    mCatalog=a; clear a;
end
params.mCatalog=mCatalog;
params.mCatRef=params.mCatalog;
% params.mDeltaHypo=[params.mCatalog(:,11) params.mCatalog(:,11) params.mCatalog(:,12)] ;
% params.mDeltaMag=[params.mCatalog(:,13)];
params.fMc=2.0;

% params.mDeltaMag=params.mCatalog(:,13);

%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
params.nSynCat=1;       % 0: Real Catalog (no synsthetic catalog calculated
                        % 1: Synthetic Catalog of background rate
                        % 2: Synthetic Catalog with ETAS

params.bHypo=false ; % performing simulation for  hypocenter uncertainties?
%params.mDeltaHypo=[params.mCatalog(:,11) params.mCatalog(:,11) params.mCatalog(:,12)] ;
params.mDeltaHypo=[];
if isempty(params.mDeltaHypo)
    params.mHypo=[1 1 3];
end
params.bMag=true ;  % performing sumulation for magnitude uncertainties
%params.mDeltaMag=[params.mCatalog(:,13)];
params.mDeltaMag=[];
if isempty(params.mDeltaMag)
    params.mMag=[0.5];
end

params.nMCS=1000;               % number of simulation for hypocenter and/or magnitude and/or declustering

params.nMode=1;              % 0:Declustering, 1: only Rates, 2:Declustering and Rates
params.nSimul=1;              % No of Simulation for MCS - have to be 1 at the moment
params.nDeclusMode=4;   % Applied declustering algorithm
                        % 1: Reasenberg Matlab
                        % 2: Gardner Knopoff
                        % 3: Stochastic
                        % 4: Reasenberg Cluster2000 (fortran)
                        % 5: Marsan
                        % 6: cluster GK written by Annemarie
                        % 7: cluster Uhrhammer written by Annemarie
                        % 8: cluster Utsu written by Annemarie

if params.nMode~=1
        % parameter range for reasenberg declustering (nDeclusMode=4)
    % Taumin, Taumax, P1, Xk, Xmeff, Rfact, Err, Derr
%    params.mReasenParam=[[1 1];[10 10];[0.95 0.95];[0.5 0.5];...
%        [1.8 1.8];[10 10];[2 2];[4 4]];
    params.mReasenParam=[[0.5 2.5];[03 15];[0.90 0.99];[0.0 1.0];...
        [1.8 2.0];[05 20];[2 2];[4 4]];
end

%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
% parameter for rate change calculation
params.fTstart=1981;            %  Start Time for z-Value calculation
params.fT=1992.3;                 % Time cut of years
% time window length in years
% params.vTw=[4]';
params.vTw = [4 ]';

%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
% Sampling
% Time steps in days
params.vTbin=[floor((params.fT-params.fTstart)*365/100)]';
% No of Events per sample
params.vN=[200];
params.nMinimumNumber=100;        % Minimum Number of events if working with
                                 % constant radius
params.fRadius=25;               % Radius (if working with constant radius
params.fResolution=0;           % Max km if N, min N if R
params.fBinning=0.1;             % Bin size for magnitude binning
params.fTimePeriod=365;          % Period lengths to be compared in days

%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
% Gridding
params.bMap=1;                             % working in map view
params.nGriddingMode=1;            % 0:Constant number,1:Constant radius,2:Rectangle mode
params.bGridEntireArea=1;       % Grid entire region (1) or no (0)
params.fSpacingHorizontal=[];  % Grid spacing latitude
params.fSpacingDepth=[];       % Grid spacing longitude
params.fSizeRectHorizontal=[];  % Rectangular selection instead radius params.fRadius
params.fSizeRectDepth=[];       % Rectangular selection instead radius params.fRadius

%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
% for Synthetic catalog
if params.nSynCat~=0
    params.mSynCatRef=params.mCatalog;
    params.nSynCatSize=10000;
    params.nMaxCatSize=100000; % limit for calculation of z-values
    params.nSynMode=1;     % type of synthetic catalog background rate 0: homogeneously distributed
    % hypocenters; 1: take real catalog and permute time % and location
    % (+/-5km) 2: permute hypocenters and create new focal Time,Mag

    params.bPSQ=true;  % with or without PSQ
    % nPSQtype (1=N nearest events, 2=poly, 3=fixed radius (km)), Tw, T, Reduction of earthquakes
    %  (0.75 = 75% reduction)
    params.vPSQ=[1 4 1992.3 0];
    if params.vPSQ(1)==1
        % lon, lat, volume
        params.mPSQ=[-116.4 34.3 500];
    elseif params.vPSQ(1)==2
        % size of polygon (if nPSQtype=2, give Polygon)
        params.mPSQ=  [   [-116.5 34.25];
                         [-116.5 34.42];
                         [-116.3 34.42];
                         [-116.3 34.25]];
%[[-116.5000   34.1200];
%                      [-116.7000   34.2500];
%                      [-116.4000   34.4000];
%                      [-116.3000   34.3000]];
    else disp('PSQ Type is not correct!');
    end
    % Vektor with contraints on synthetic catalog
    % 1-4: fMinLon fMaxLon fMinLat fMaxLat in degree
    % 5-6: fMinDepth fMaxDepth  in km
    % 7-8: fMinTime fMaxTime (duration of catalog)
    % 9: fRate Reduction of earthquakes for entire catalog (0.75 = 25%
    % reduction) in period (fT-fTw) - fT
    % 10:  fBValue           b-value of the catalog
    % 11:  fMc Magnitude of Completness (minimum Magnitude in Catalog)
    % 12:  fIncMagnitude increment steps
    params.vSynCat=[-118.2, -114.5, 32.1, 36.1, 0 40, ...
        params.fTstart-(params.fT-params.fTstart)/2, params.fT,...  %
        1, 1, params.fMc, 0.1]';

    % Definition/Constraints for Aftershocks
    % 1: Mmin: Minimum earthquake magnitude to report and simulate
    % 2: MminR: Minimum earthquake magnitude for reporting in the output
    % catalog
    % 3: maxm: Maximum earthquake magnitude
    % 4: DMax: Maximum distance for aftershocks
    % 5: magb: Cutoff magnitude for the point source vs. plane source
    %representation of the mainshock
    params.vAfter=[params.vSynCat(11), params.vSynCat(11), 8, 100, 5];

    % Parameters for ETAS : [CX, P, A] standard =[0.095, 1.34, 0.008]
    params.vEtas=[0.095, 1.34, 0.008];
end


%% Example using ESS for the BCIT to resample
ess2Dir = 'D:\TestData\LargData\NCTU\NCTU_DAS\Level2';
levelDerivedDir = 'D:\TestData\LargData\NCTU\NCTU_DAS\Level2_256Hz';

% ess2Dir = 'D:\TestData\BCITV2\Data\STDL2\ARL_BCIT_CalibrationDriving_Dataset_level_2';
% levelDerivedDir = 'D:\TestData\BCITV2\Data\STDL2_256Hz\ARL_BCIT_CalibrationDriving_Dataset_level_2';

% ess2Dir = 'D:\TestData\BCITV2\Data\STDL2\ARL_BCIT_TrafficComplexity_Dataset_level_2';
% levelDerivedDir = 'D:\TestData\BCITV2\Data\STDL2_256Hz\ARL_BCIT_TrafficComplexity_Dataset_level_2';

% ess2Dir = 'D:\TestData\LargData\VEP\ARL_VEP_v1.1.0_Level2';
% levelDerivedDir = 'D:\TestData\LargData\VEP\ARL_VEP_v1.1.0_Level2_256Hz';

% ess2Dir = 'D:\TestData\LargData\UCSD_RSVP\Level_2';
% levelDerivedDir = 'D:\TestData\LargData\UCSD_RSVP\Level_2_256Hz';

%% Check to make sure level 2 study validates
ess2File = [ess2Dir filesep 'studyLevel2_description.xml'];
obj1 = level2Study('level2XmlFilePath', ess2File);
obj1.validate();

%% Create a level 2 derived study
obj = levelDerivedStudy('parentStudyXmlFilePath', ess2File);
callbackAndParameters = {@resampleAndDealias, {'resampleOff', false, ...
                        'resampleFrequency', 256, 'lowPassFrequency', 100}};
obj = obj.createLevelDerivedStudy(callbackAndParameters, ...
     'filterDescription', 'Downsample and then low pass to remove alias', ...
     'filterLabel', 'resample', 'levelDerivedFolder', levelDerivedDir);


classdef MimPluginLabelEditBox < GemLabelEditBox
    % MimPluginLabelEditBox. Part of the gui for the TD MIM Toolkit.
    %
    %     This class is used internally within the TD MIM Toolkit to help
    %     build the user interface.
    %
    %     MimPluginLabelEditBox is used to build an edit box which
    %     interacts with the MIM GUI
    %
    %
    %     Licence
    %     -------
    %     Part of the TD MIM Toolkit. https://github.com/tomdoel
    %     Author: Tom Doel, Copyright Tom Doel 2014.  www.tomdoel.com
    %     Distributed under the MIT licence. Please see website for details.
    %

    properties (Access = private)
        GuiApp
        Tool
        FixToInteger = true
    end

    methods
        function obj = MimPluginLabelEditBox(parent, tool, icon, gui_app)
            obj = obj@GemLabelEditBox(parent, tool.ButtonText, tool.ToolTip, class(tool));
            obj.GuiApp = gui_app;
            obj.Tool = tool;

            [value_instance_handle, value_property_name, limits_instance_handle, limits_property_name] = tool.GetHandleAndProperty(gui_app);
            value = value_instance_handle.(value_property_name);

            if ~isempty(limits_property_name)
                limits = limits_instance_handle.(limits_property_name);
            end

            obj.EditBoxPosition = tool.EditBoxPosition;
            obj.EditBoxWidth = tool.EditBoxWidth;

            if ~isempty(obj.EditBox)
                obj.EditBox.SetText(num2str(value, '%.6g'));
            end

            obj.AddPostSetListener(value_instance_handle, value_property_name, @obj.PropertyChangedCallback);

            if ~isempty(limits_property_name)
                obj.AddPostSetListener(limits_instance_handle, limits_property_name, @obj.PropertyLimitsChangedCallback);
            end
        end

        function enabled = UpdateToolEnabled(obj, gui_app)
            enabled = obj.Tool.IsEnabled(gui_app);
        end
    end

    methods (Access = protected)
        function EditBoxCallback(obj, hObject, arg2)
            EditBoxCallback@GemLabelEditBox(obj, hObject, arg2);

            [instance_handle, value_property_name, ~, ~] = obj.Tool.GetHandleAndProperty(obj.GuiApp);

            % Get the current textbox contents
            value = str2double(obj.EditBox.Text);

            % If it's a number then update the property value
            if ~isnan(value)
                if obj.FixToInteger
                    new_value = round(value);
                else
                    new_value = value;
                end
                instance_handle.(value_property_name) = new_value;
            end

            % Get the current property value. If we didn't update the
            % property value, this should be the old value. If we did
            % update it, the property set method may have modified the
            % value.
            adjusted_value = instance_handle.(value_property_name);

            % In either case we want to update the text box to reflect the
            % actual value of the property
            if adjusted_value ~= value
                obj.EditBox.SetText(num2str(adjusted_value, '%.6g'));
            end
        end

        function PropertyChangedCallback(obj, ~, ~, ~)
            [instance_handle, value_property_name, ~, ~] = obj.Tool.GetHandleAndProperty(obj.GuiApp);
            value = instance_handle.(value_property_name);
            obj.EditBox.SetText(num2str(value, '%.6g'));
        end

        function PropertyLimitsChangedCallback(obj, ~, ~, ~)
            [~, ~, limits_instance_handle, limits_property_name] = obj.Tool.GetHandleAndProperty(obj.GuiApp);
            limits = limits_instance_handle.(limits_property_name);
            range = limits(2) - limits(1);
            if abs(range) >= 100
                obj.FixToInteger = true;
            else
                obj.FixToInteger = false;
            end
        end

    end
end


function expressions( varargin )

%EXPRESSIONS Declares one or more CVX expression holders.
%   EXPRESSIONS x1 x2 x3 ..., where x1, x2, x3, etc. are valid
%   variable names, declares multiple cvx expression holders. It is
%   exactly equivalent to issuing a separate EXPRESSION command
%   for each x1, x2, x3, ...
%
%   EXPRESSIONS allows the declaration of vector, matrix, and
%   array variables.
%
%   For more information about expression holders, see the help for
%   EXPRESSION or the CVX user guide.
%
%   Examples:
%      expressions x y z
%
%   See also EXPRESSION.

if nargin < 1,
    error( 'Incorrect syntax for EXPRESSIONS. Type HELP EXPRESSIONS for details.' );
elseif ~iscellstr( varargin ),
    error( 'All arguments must be strings.' );
end
for k = 1 : nargin,
    evalin( 'caller', [ 'expression ', varargin{k} ] );
end

% Copyright 2005-2016 CVX Research, Inc.
% See the file LICENSE.txt for full copyright information.
% The command 'cvx_where' will show where this file is located.


function bits_per_pixel = fmf_get_bits_per_pixel( data_format )

if strcmp(data_format,'MONO8'),
  bits_per_pixel = 8;
elseif strcmp(data_format,'YUV422'),
  bits_per_pixel = 16;
else,
  error( 'Only MONO8 supported for now' );
end


classdef PTKSaveADCAnalysisResults < PTKPlugin
    % PTKSaveADCAnalysisResults.
    %
    %     This is a plugin for the Pulmonary Toolkit. Plugins can be run using
    %     the gui, or through the interfaces provided by the Pulmonary Toolkit.
    %     See PTKPlugin.m for more information on how to run plugins.
    %
    %     Plugins should not be run directly from your code.
    %
    %
    %     Licence
    %     -------
    %     Part of the TD Pulmonary Toolkit. https://github.com/tomdoel/pulmonarytoolkit
    %     Author: Tom Doel, 2014.  www.tomdoel.com
    %     Distributed under the GNU GPL v3 licence. Please see website for details.
    %

    properties
        ButtonText = 'Mean ADC'
        ToolTip = 'Computes mean ADC over lung regions'
        Category = 'Multi-modal'
        Mode = 'Analysis'

        Context = PTKContextSet.LungROI
        AllowResultsToBeCached = true
        AlwaysRunPlugin = true
        PluginType = 'DoNothing'
        HidePluginInDisplay = false
        FlattenPreviewImage = false
        PTKVersion = '2'
        ButtonWidth = 6
        ButtonHeight = 2
        GeneratePreview = false
        Location = 22
    end

    methods (Static)
        function results = RunPlugin(dataset, context, reporting)
            image_info = dataset.GetImageInfo;
            uid = image_info.ImageUid;
            template = dataset.GetTemplateImage(PTKContext.LungROI);
            patient_name = dataset.GetPatientName;

            contexts = {PTKContextSet.Lungs, PTKContextSet.SingleLung, PTKContextSet.Lobe};
            results = dataset.GetResult('PTKADCAnalysis', contexts);

            table = PTKConvertMetricsToTable(results, patient_name, uid, reporting);

            dataset.SaveTableAsCSV('PTKSaveADCAnalysisResults', 'ADC analysis', 'ADCResults', 'Mean ADC', table, MimResultsTable.PatientDim, MimResultsTable.ContextDim, MimResultsTable.MetricDim, []);
        end

        function enabled = IsEnabled(gui_app)
            enabled = gui_app.IsDatasetLoaded() && gui_app.IsGasMRI() && gui_app.IsLinkedDataset('CT') && gui_app.IsLinkedDataset('MR') && gui_app.IsLinkedDataset('XeDiff0')  && gui_app.IsLinkedDataset('XeDiff1');
        end
    end
end


function analyzeMgPipeResults(infoFilePath,resPath,varargin)
% This function takes simulation results generated by mgPipe as the input
% and determines which computed fluxes and reaction abundances are
% significantly different between groups. Also creates violin plots of the
% simulation results. Requires a file with sample information (e.g.,
% disease group, age) for the microbiome models that were generated and
% interrogated through mgPipe.
%
% USAGE:
%
%    analyzeMgPipeResults(infoFilePath,resPath,varargin)
%
% REQUIRED INPUTS:
% infoFilePath:         Path to text file or spreadsheet with information
%                       on analyzed samples including group classification
%                       with sample IDs as rows
% resPath:              char with path of directory where simulation
%                       results are saved
%
% OPTIONAL INPUTS
% statPath:             char with path of directory where results of
%                       statistical analysis are saved
% violinPath:           char with path of directory where violin plots are
%                       saved
% sampleGroupHeaders    list of one or more column headers in file with the
%                       sample information that should be analyzed
%                       (e.g., disease status, age). If not provided, the
%                       second column will be used.
%
% .. Author: Almut Heinken, 12/2020

parser = inputParser();
parser.addRequired('infoFilePath', @ischar);
parser.addRequired('resPath', @ischar);
parser.addParameter('statPath', [pwd filesep 'Statistics'], @ischar);
parser.addParameter('violinPath', [pwd filesep 'ViolinPlots'], @ischar);
parser.addParameter('sampleGroupHeaders', '', @iscellstr);

parser.parse(infoFilePath, resPath, varargin{:});

infoFilePath = parser.Results.infoFilePath;
resPath = parser.Results.resPath;
statPath = parser.Results.statPath;
violinPath = parser.Results.violinPath;
sampleGroupHeaders = parser.Results.sampleGroupHeaders;

% create the folders
mkdir(statPath)
mkdir(violinPath)

% Read in the file with sample information
infoFile = readInputTableForPipeline(infoFilePath);

% get all spreadsheet files in results folder
dInfo = dir(resPath);
fileList={dInfo.name};
fileList=fileList';
fileList(~contains(fileList(:,1),{'.csv','.txt'}))=[];
fileList(contains(fileList(:,1),{'ModelStat'}))=[];
fileList(contains(fileList(:,1),{'GrowthRates'}))=[];

% analyze data in spreadsheets
for i=1:length(fileList)
    sampleData = readInputTableForPipeline([resPath filesep fileList{i}]);

    % merge columns for shadow price results
    if strcmp(sampleData{1,2},'Source')
        for j=2:size(sampleData,1)
            sampleData{j,1}=[sampleData{j,1} '_' sampleData{j,2}];
        end
        sampleData(:,2)=[];
    end
    if strcmp(sampleData{1,3},'Source')
        for j=2:size(sampleData,1)
            sampleData{j,2}=[sampleData{j,2} '_' sampleData{j,3}];
        end
        sampleData(:,2:3)=[];
    end
    if strcmp(sampleData{1,2},'Objective')
        for j=2:size(sampleData,1)
            sampleData{j,1}=[sampleData{j,1} '_' sampleData{j,2}];
        end
        sampleData(:,2)=[];
    end

    sampleData(1,2:end)=strrep(sampleData(1,2:end),'microbiota_model_samp_','');
    sampleData(1,2:end)=strrep(sampleData(1,2:end),'microbiota_model_diet_','');
    sampleData(1,2:end)=strrep(sampleData(1,2:end),'microbiota_model_pDiet_','');
    sampleData(1,2:end)=strrep(sampleData(1,2:end),'microbiota_model_rich_','');
    sampleData(1,2:end)=strrep(sampleData(1,2:end),'host_microbiota_model_samp_','');

    % remove entries not in data
    [C,IA]=intersect(infoFile(2:end,1),sampleData(1,2:end));
    if length(C)<length(sampleData(1,2:end))
        error('Some sample IDs are not found in the file with sample information!')
    end

    % perform statistical analysis
    if ~isempty(sampleGroupHeaders)
        for j=1:length(sampleGroupHeaders)
            [Statistics,significantFeatures] = performStatisticalAnalysis(sampleData,infoFile,'stratification',sampleGroupHeaders{j});

            % Print the results as a text file
            filename = strrep(fileList{i},'.csv','');
            filename = strrep(filename,'.txt','');
            writetable(cell2table(Statistics),[statPath filesep filename '_' sampleGroupHeaders{j} '_Statistics'],'FileType','text','WriteVariableNames',false,'Delimiter','tab');
            if size(significantFeatures,2)>1
                writetable(cell2table(significantFeatures),[statPath filesep filename '_' sampleGroupHeaders{j} '_SignificantFeatures'],'FileType','text','WriteVariableNames',false,'Delimiter','tab');
            end

            % create violin plots
            currentDir=pwd;
            cd(violinPath)

            % create violin plots for net uptake and secretion files
            if any(contains(fileList{i,1},{'net_uptake_fluxes.csv','net_secretion_fluxes.csv'}))
                makeViolinPlots(sampleData, infoFile, 'stratification',sampleGroupHeaders{j}, 'plottedFeature', filename, 'unit', 'mmol/person/day')
            end
            cd(currentDir)
        end
    else
        [Statistics,significantFeatures] = performStatisticalAnalysis(sampleData,infoFile);

        % Print the results as a text file
        filename = strrep(fileList{i},'.csv','');
        filename = strrep(filename,'.txt','');
        writetable(cell2table(Statistics),[statPath filesep filename '_Statistics'],'FileType','text','WriteVariableNames',false,'Delimiter','tab');
        if size(significantFeatures,2)>1
            writetable(cell2table(significantFeatures),[statPath filesep filename '_SignificantFeatures'],'FileType','text','WriteVariableNames',false,'Delimiter','tab');
        end

        % create violin plots
        currentDir=pwd;
        cd(violinPath)

        % create violin plots for net uptake and secretion files
        if any(strcmp(fileList{i,1},{'net_uptake_fluxes.csv','net_secretion_fluxes.csv','Objectives.txt'}))
            makeViolinPlots(sampleData, infoFile, 'plottedFeature', filename, 'unit', 'mmol/person/day')
        end
        cd(currentDir)
    end

end


function docking = ma_createDocking(name, oScId, undockTime, lineColor, lineStyle, lineWidth, massLoss)
%ma_createDocking Summary of this function goes here
%   Detailed explanation goes here

    docking = struct();

    docking.id          = rand(1);
    docking.type        = 'Docking';
    docking.name        = name;
    docking.oScId       = oScId;
    docking.undockTime	= undockTime;
    docking.lineColor   = lineColor;
    docking.lineStyle   = lineStyle;
    docking.lineWidth   = lineWidth;
    docking.massloss	= massLoss;
end


function [datapt, unitStr] = lvd_ElectricalPowerSinkTasks(stateLogEntry, subTask, pwrSink)
%lvd_ElectricalPowerSinkTasks Summary of this function goes here
%   Detailed explanation goes here
    stageStates = stateLogEntry.stageStates;

    pwrSinkStates = AbstractLaunchVehicleElectricalPowerSnkState.empty(1,0);
    for(i=1:length(stageStates)) %#ok<*NO4LP>
        pwrSinkStates = horzcat(pwrSinkStates, stageStates(i).powerSinkStates); %#ok<AGROW>
    end

    pwrSinks = AbstractLaunchVehicleElectricalPowerSrcSnk.empty(1,0);
    for(i=1:length(pwrSinkStates))
        pwrSinks = horzcat(pwrSinks, pwrSinkStates(i).getEpsSinkComponent()); %#ok<AGROW>
    end

    pwrSinkInd = find(pwrSinks == pwrSink,1,'first');
    pwrSinkState = pwrSinkStates(pwrSinkInd);

    switch subTask
        case 'active'
            if(not(isempty(pwrSinkState)))
                pwrSinkState = pwrSinkState(1);
                datapt = pwrSinkState.getActiveState();

                if(isempty(datapt))
                    datapt = -1;
                end

                unitStr = '';
            else
                datapt = -1;
                unitStr = '';
            end

        case 'dischargeRate'
            if(not(isempty(pwrSinkState)))
                pwrSinkState = pwrSinkState(1);

                elemSet = stateLogEntry.getCartesianElementSetRepresentation();
                steeringModel = stateLogEntry.steeringModel;
                datapt = pwrSinkState.getElectricalPwrRate(elemSet, steeringModel, [], [], []);

                if(isempty(datapt))
                    datapt = -1;
                end

                unitStr = 'EC/s';
            else
                datapt = -1;
                unitStr = 'EC/s';
            end

        otherwise
            error('Unknow EPS sink task: %s', subTask);
    end
end


classdef MCMC < BetterHandle
    %%MCMC Simple MH and Gibbs moves for the MotorProgram Class
    %%
    %%   This class provides some simple moves for sampling from
    %%   some variables, with fixed dimension. It does not provide
    %%   a sampler for the entire joint space.
    %%
    properties

       debug_full_score = false;

       %% book-keeping to count the number of times
       %% a move is accepted

       %% parameters that don't call the image evaluation
       accept_shape_type = 0;
       n_shape_type = 0;
       accept_scale_type = 0;
       n_scale_type = 0;
       accept_gpos = 0;
       n_gpos = 0;
       accept_seval = 0;
       n_seval = 0;
       accept_seval_token = 0;
       n_seval_token = 0;
       accept_sid = 0;
       n_sid = 0;
       accept_r = 0;
       n_r = 0;

       %% parameters that call the image evaluation function
       accept_shape_token = 0;
       n_shape_token = 0;
       accept_scale_token = 0;
       n_scale_token = 0;
       accept_pos_token = 0;
       n_pos_token = 0;

    end

    methods

        function this = MCMC(debug_full_score)
            if exist('debug_full_score','var')
                this.debug_full_score = debug_full_score;
            end
        end

        %% print the percent of times various moves are accepted
        function acceptance_ratios(this)
           fprintf(1,'Acceptance ratios\n');
           fprintf(1,' shape type: %s%% (of %d)\n',num2str(this.accept_shape_type/this.n_shape_type*100,3),this.n_shape_type);
           fprintf(1,' scale type: %s%% (of %d)\n',num2str(this.accept_scale_type/this.n_shape_type*100,3),this.n_scale_type);
           fprintf(1,' global pos: %s%% (of %d)\n',num2str(this.accept_gpos/this.n_gpos*100,3),this.n_gpos);
           if this.n_seval > 0
               fprintf(1,' seval type: %s%% (of %d)\n',num2str(this.accept_seval/this.n_seval*100,3),this.n_seval);
               fprintf(1,' seval tokn: %s%% (of %d)\n',num2str(this.accept_seval_token/this.n_seval_token*100,3),this.n_seval_token);
           end
           fprintf(1,' sub-ids   : %s%% (of %d)\n',num2str(this.accept_sid/this.n_sid*100,3),this.n_sid);
           fprintf(1,' R         : %s%% (of %d)\n',num2str(this.accept_r/this.n_r*100,3),this.n_r);

           fprintf(1,' scale tokn: %s%% (of %d)\n',num2str(this.accept_scale_token/this.n_scale_token*100,3),this.n_scale_token);
           fprintf(1,' shape tokn: %s%% (of %d)\n',num2str(this.accept_shape_token/this.n_shape_token*100,3),this.n_shape_token);
           fprintf(1,' pos   tokn: %s%% (of %d)\n',num2str(this.accept_pos_token/this.n_pos_token*100,3),this.n_pos_token);
        end

        %% SHAPE TYPE MOVE
        function [val_new,accept] = mh_shape_type(this,sid,bid,M,lib)
            %% sid: stroke index
            %% bid: sub-stroke index

            %% make proposal
            curr_shape_type = M.S{sid}.shapes_type(:,:,bid);
            prop_shape_type = propose_shape_type(curr_shape_type,M.parameters);

            %% score proposal
            curr_score = score_shape_type(M,sid,bid,lib,M.parameters);
            if this.debug_full_score
               curr_score2 = score_shape_type(M,sid,bid,lib,M.parameters,true);
            end
            M.S{sid}.shapes_type(:,:,bid) = prop_shape_type;
            prop_score = score_shape_type(M,sid,bid,lib,M.parameters);

            if this.debug_full_score %% debug to make sure full-score matches
                prop_score2 = score_shape_type(M,sid,bid,lib,M.parameters,true);
                if ~isinf(prop_score)
                    assert(aeq(prop_score-curr_score,prop_score2-curr_score2));
                    fprintf(1,'DEBUG: MH Shape type passed score test\n');
                end
            end

            %% accept or reject
            accept = mh_accept(prop_score,curr_score);
            if ~accept
                M.S{sid}.shapes_type(:,:,bid) = curr_shape_type;
            end
            val_new = M.S{sid}.shapes_type(:,:,bid);

            this.accept_shape_type = this.accept_shape_type + accept;
            this.n_shape_type = this.n_shape_type + 1;

            if isinf(scoreMP(M,lib))
               error('score should not be negative');
            end
        end

        %% SHAPE TOKEN MOVE
        function [val_new,accept] = mh_shape_token(this,sid,bid,M,lib)
            %% sid: stroke index
            %% bid: sub-stroke index

            %% make proposal
            curr_shape_token = M.S{sid}.shapes_token(:,:,bid);
            prop_shape_token = propose_shape_token(curr_shape_token,M.parameters);

            %% score proposal
            curr_score = score_shape_token(M,sid,bid,lib,M.parameters);
            if this.debug_full_score
               curr_score2 = score_shape_token(M,sid,bid,lib,M.parameters,true);
            end
            M.S{sid}.shapes_token(:,:,bid) = prop_shape_token;
            prop_score = score_shape_token(M,sid,bid,lib,M.parameters);

            if this.debug_full_score %% debug to make sure full-score matches
                prop_score2 = score_shape_token(M,sid,bid,lib,M.parameters,true);
                if ~isinf(prop_score)
                    assert(aeq(prop_score-curr_score,prop_score2-curr_score2));
                    fprintf(1,'DEBUG: MH Shape token passed score test\n');
                end
            end

            %% accept or reject
            accept = mh_accept(prop_score,curr_score);
            if ~accept
                M.S{sid}.shapes_token(:,:,bid) = curr_shape_token;
            end
            val_new = M.S{sid}.shapes_token(:,:,bid);

            this.accept_shape_token = this.accept_shape_token + accept;
            this.n_shape_token = this.n_shape_token + 1;

            if isinf(scoreMP(M,lib))
               error('score should not be negative');
            end
        end

        %% SCALE TYPE MOVE
        function [val_new,accept] = mh_scale_type(this,sid,bid,M,lib)
            %% sid: stroke index
            %% bid: sub-stroke index

            %% make proposal
            curr_invscale_type = M.S{sid}.invscales_type(bid);
            prop_invscale_type = propose_scale_type(curr_invscale_type,M.parameters);

            %% score proposal
            curr_score = score_scale_type(M,sid,bid,lib,M.parameters);
            if this.debug_full_score
                curr_score2 = score_scale_type(M,sid,bid,lib,M.parameters,true);
            end
            M.S{sid}.invscales_type(bid) = prop_invscale_type;
            prop_score = score_scale_type(M,sid,bid,lib,M.parameters);

            if this.debug_full_score %% debug to make sure full-score matches
                prop_score2 = score_scale_type(M,sid,bid,lib,M.parameters,true);
                if ~isinf(prop_score)
                    assert(aeq(prop_score-curr_score,prop_score2-curr_score2));
                    fprintf(1,'DEBUG: MH Scale type passed score test\n');
                end
            end

            %% accept or reject
            accept = mh_accept(prop_score,curr_score);
            if ~accept
               M.S{sid}.invscales_type(bid) = curr_invscale_type;
            end
            val_new = M.S{sid}.invscales_type(bid);

            this.accept_scale_type = this.accept_scale_type + accept;
            this.n_scale_type = this.n_scale_type + 1;

        end

        %% SCALE TOKEN MOVE
        function [val_new,accept] = mh_scale_token(this,sid,bid,M,lib)
            %% sid: stroke index
            %% bid: sub-stroke index

            %% make proposal
            curr_invscale_token = M.S{sid}.invscales_token(bid);
            prop_invscale_token = propose_scale_token(curr_invscale_token,M.parameters);

            %% score proposal
            curr_score = score_scale_token(M,sid,bid,lib,M.parameters);
            if this.debug_full_score
                curr_score2 = score_scale_token(M,sid,bid,lib,M.parameters,true);
            end
            M.S{sid}.invscales_token(bid) = prop_invscale_token;
            prop_score = score_scale_token(M,sid,bid,lib,M.parameters);

            if this.debug_full_score %% debug to make sure full-score matches
                prop_score2 = score_scale_token(M,sid,bid,lib,M.parameters,true);
                if ~isinf(prop_score)
                    assert(aeq(prop_score-curr_score,prop_score2-curr_score2));
                    fprintf(1,'DEBUG: MH Scale token passed score test\n');
                end
            end

            %% accept or reject
            accept = mh_accept(prop_score,curr_score);
            if ~accept
               M.S{sid}.invscales_token(bid) = curr_invscale_token;
            end
            val_new = M.S{sid}.invscales_token(bid);

            this.accept_scale_token = this.accept_scale_token + accept;
            this.n_scale_token = this.n_scale_token + 1;

        end

        %% GLOBAL POSITION FOR UNIHIST RELATION
        function [val_new,accept] = mh_gobal_position(this,sid,M,lib)

            %% sid: stroke index
            assert(strcmp(M.S{sid}.R.type,'unihist'));

            %% make proposal
            curr_gpos = M.S{sid}.R.gpos;
            prop_gpos = propose_global_position(curr_gpos,M.parameters);

            %% score proposal
            curr_score = score_global_position(M,sid,lib);
            if this.debug_full_score
               curr_score2 = score_global_position(M,sid,lib,true);
            end
            M.S{sid}.R.gpos = prop_gpos;
            prop_score = score_global_position(M,sid,lib);

            if this.debug_full_score %% debug to make sure full-score matches
                prop_score2 = score_global_position(M,sid,lib,true);
                if ~isinf(prop_score)
                    assert(aeq(prop_score-curr_score,prop_score2-curr_score2));
                    fprintf(1,'DEBUG: MH position passed score test\n');
                end
            end

            %% accept or reject
            accept = mh_accept(prop_score,curr_score);
            if ~accept
                M.S{sid}.R.gpos = curr_gpos;
            end
            val_new = M.S{sid}.R.gpos;

            this.accept_gpos = this.accept_gpos + accept;
            this.n_gpos = this.n_gpos + 1;

        end

        %% POSITION FOR A STROKE
        function [val_new,accept] = mh_token_position(this,sid,M,lib)
            %% sid: stroke index

            %% make proposal
            curr_pos_token = M.S{sid}.pos_token;
            prop_pos_token = propose_local_position(curr_pos_token,M.parameters);

            %% score proposal
            curr_score = score_local_position(M,sid,lib);
            if this.debug_full_score
               curr_score2 = score_local_position(M,sid,lib,true);
            end
            M.S{sid}.pos_token = prop_pos_token;
            prop_score = score_local_position(M,sid,lib);

            if this.debug_full_score %% debug to make sure full-score matches
                prop_score2 = score_local_position(M,sid,lib,true);
                if ~isinf(prop_score)
                    assert(aeq(prop_score-curr_score,prop_score2-curr_score2));
                    fprintf(1,'DEBUG: MH token position passed score test\n');
                end
            end

            %% accept or reject
            accept = mh_accept(prop_score,curr_score);
            if ~accept
                M.S{sid}.pos_token = curr_pos_token;
            end
            val_new = M.S{sid}.pos_token;

            this.accept_pos_token = this.accept_pos_token + accept;
            this.n_pos_token = this.n_pos_token + 1;
        end

        %% EVAL-SPOT TYPE
        function [val_new,accept] = mh_eval_spot_type(this,sid,M,lib)
            %% sid: stroke index
            assert(strcmp(M.S{sid}.R.type,'mid'));

            %% make proposal
            curr_eval_spot_type = M.S{sid}.R.eval_spot_type;
            assert(~isempty(curr_eval_spot_type));
            prop_eval_spot_type = propose_eval_spot(curr_eval_spot_type,M.parameters);

            %% score proposal
            curr_score = score_eval_spot_type(M,sid,lib,M.parameters);
            if this.debug_full_score
                curr_score2 = score_eval_spot_type(M,sid,lib,M.parameters,true);
            end
            M.S{sid}.R.eval_spot_type = prop_eval_spot_type;
            prop_score = score_eval_spot_type(M,sid,lib,M.parameters);

            if this.debug_full_score %% debug to make sure full-score matches
               prop_score2 = score_eval_spot_type(M,sid,lib,M.parameters,true);
               if ~isinf(prop_score)
                    assert(aeq(prop_score-curr_score,prop_score2-curr_score2));
                    fprintf(1,'DEBUG: MH eval spot type passed score test\n');
                end
            end

            %% accept or reject
            accept = mh_accept(prop_score,curr_score);
            if ~accept
                M.S{sid}.R.eval_spot_type = curr_eval_spot_type;
            end
            val_new = M.S{sid}.R.eval_spot_type;

            this.accept_seval = this.accept_seval + accept;
            this.n_seval = this.n_seval + 1;

        end

        function [val_new,accept] = mh_eval_spot_token(this,sid,M,lib)
            %% sid: stroke index
            assert(strcmp(M.S{sid}.R.type,'mid'));

            %% make proposal
            curr_eval_spot_token = M.S{sid}.R.eval_spot_token;
            prop_eval_spot_token = propose_eval_spot(curr_eval_spot_token,M.parameters);

            %% score proposal
            curr_score = score_eval_spot_token(M,sid,lib,M.parameters);
            if this.debug_full_score
                curr_score2 = score_eval_spot_token(M,sid,lib,M.parameters,true);
            end
            M.S{sid}.R.eval_spot_token = prop_eval_spot_token;
            prop_score = score_eval_spot_token(M,sid,lib,M.parameters);

            if this.debug_full_score %% debug to make sure full-score matches
               prop_score2 = score_eval_spot_token(M,sid,lib,M.parameters,true);
               if ~isinf(prop_score)
                    assert(aeq(prop_score-curr_score,prop_score2-curr_score2));
                    fprintf(1,'DEBUG: MH eval spot token passed score test\n');
                end
            end

            %% accept or reject
            accept = mh_accept(prop_score,curr_score);
            if ~accept
                M.S{sid}.R.eval_spot_token = curr_eval_spot_token;
            end
            val_new = M.S{sid}.R.eval_spot_token;

            this.accept_seval_token = this.accept_seval_token + accept;
            this.n_seval_token = this.n_seval_token + 1;

        end

        %% SUB-STROKE IDS
        function [val_new,accept] = gibbs_substroke_id(this,sid,bid,M,lib)
            % sid: stroke index
            % bid: sub-stroke index
            curr_id = M.S{sid}.ids(bid);
            nclust = lib.N;
            score = score_all_subid(M,sid,bid,lib);

            if this.debug_full_score
                score2 = zeros(nclust,1);
                for c=1:nclust
                    M.S{sid}.ids(bid) = c;
                    score2(c) = scoreMP(M,lib);
                end
                v1 = score-logsumexp(score(:));
                v2 = score2-logsumexp(score2(:));
                v1(isinf(v1)) = [];
                v2(isinf(v2)) = [];
                assert( aeq(v1,v2) );
                fprintf(1,'DEBUG: Gibbs sub-stroke ids passed score test\n');
            end

            %% normalize probability distribution
            score = score - logsumexp(score);
            pvec = exp(score);
            assert(aeq(sum(pvec),1));
            pvec = pvec ./ sum(pvec);

            %% sample the new id
            vr = mnrnd(1,pvec);
            assert(~any(isnan(vr)));
            new_id = find(vr);
            M.S{sid}.ids(bid) = new_id;
            accept = new_id ~= curr_id;

            val_new = M.S{sid}.ids(bid);

            this.accept_sid  = this.accept_sid + accept;
            this.n_sid = this.n_sid + 1;

        end

        %% RELATION (WITH TOKEN PARAMETER FOR ATTACHMENT)
        function [val_new,accept] = mh_relation(this,sid,M,lib)

            %% make proposal
            PM = defaultps;
            curr_R = M.S{sid}.R;
            prop_R = propose_relation(M.S{sid}.pos_token,M.S(1:sid-1),lib,PM);

            %% score proposal
            curr_score = score_relation(M,sid,lib);
            g_prop_to_curr = pp_relation(M,sid,lib,PM);
            if this.debug_full_score
                curr_score2 = score_relation(M,sid,lib,true);
            end
            M.S{sid}.R = prop_R;
            prop_score = score_relation(M,sid,lib);

            g_curr_to_prop = pp_relation(M,sid,lib,PM);
            if this.debug_full_score
               prop_score2 = score_relation(M,sid,lib,true);
               if ~isinf(prop_score)
                    assert(aeq(prop_score-curr_score,prop_score2-curr_score2));
                    fprintf(1,'DEBUG: MH relation passed score test\n');
                end
            end

            %% accept or reject
            accept = mh_accept(prop_score,curr_score,g_curr_to_prop,g_prop_to_curr);
            if ~accept
                M.S{sid}.R = curr_R;
            end
            val_new = M.S{sid}.R;

            %% record keeping
            this.accept_r = this.accept_r + accept;
            this.n_r = this.n_r + 1;

        end

    end
end

%% general MH acceptance function
%%
%% Input
%%  prop_score: log-probability of model with proposal
%%  curr_score: log-probability of current model
%%  g_curr_to_prop: log-prob. of transition from current to proposal model
%%  g_prop_to_curr: reverse log-prob
function accept = mh_accept(prop_score,curr_score,g_curr_to_prop,g_prop_to_curr)
    if exist('g_curr_to_prop','var')
        lr = prop_score - curr_score + g_prop_to_curr - g_curr_to_prop;
    else
        lr = prop_score - curr_score;
    end

    if isinf(prop_score)
       accept = false;
       return
    end

    r = min(1,exp(lr));
    assert(~isinf(curr_score));
    accept = rand < r;
end

function R = propose_relation(pos_token,prev_strokes,lib,PM)
    %% Propose new relation by sampling from prior, except the global
    %% position is sampled from near the token position
    R = CPD.sample_relation_type(lib,prev_strokes);
    if strcmp(R.type,'mid')
        R.eval_spot_token = CPD.sample_relation_token(lib,R.eval_spot_type);
    elseif strcmp(R.type,'unihist')
        R.gpos(1) = pos_token(1) + PM.mcmc_prop_relpos_mlty*lib.rel.sigma_x*randn;
        R.gpos(2) = pos_token(2) + PM.mcmc_prop_relpos_mlty*lib.rel.sigma_y*randn;
    end
end

function ll = pp_relation(M,sid,lib,PM)
    %% The probability of proposing relation M.S{sid}.R
    ll = CPD.score_relation_type(lib,M.S{sid}.R);
    if strcmp(M.S{sid}.R.type,'mid')
       ll = ll + CPD.score_relation_token(lib,M.S{sid}.R.eval_spot_token,...
                                              M.S{sid}.R.eval_spot_type);
    elseif strcmp(M.S{sid}.R.type,'unihist')
       gpos = M.S{sid}.R.gpos;
       pos_token = M.S{sid}.pos_token;
       ll = ll - lib.Spatial.score(gpos,sid); %% since this sample was not used
       ll = ll + mvnormpdfln(gpos(1),pos_token(1),PM.mcmc_prop_relpos_mlty*lib.rel.sigma_x);
       ll = ll + mvnormpdfln(gpos(2),pos_token(2),PM.mcmc_prop_relpos_mlty*lib.rel.sigma_y);
    end
end

%% RELATIONS

function ll = score_relation(M,sid,lib,fullscore)
    if ~exist('fullscore','var')
       fullscore = false;
    end
    if fullscore
        ll = scoreMP(M,lib);
        return
    end

    ll = CPD.score_relation_type(lib,M.S{sid}.R);
    if strcmp(M.S{sid}.R.type,'mid')
       ll = ll + CPD.score_relation_token(lib,M.S{sid}.R.eval_spot_token,...
                                              M.S{sid}.R.eval_spot_type);
    end
    pos = M.S{sid}.pos_token;
    ll = ll + CPD.score_position(lib,pos,M.S{sid}.R,M.S(1:sid-1));
end

%% SHAPE

function shape_type = propose_shape_type(shape_type,PM)
    [~,dim,n] = size(shape_type);
    assert(dim==2 && n==1);
    shape_type = shape_type + PM.mcmc.prop_shape_sd .* randn(size(shape_type));
end

function shape_token = propose_shape_token(shape_token,PM)
    shape_token = propose_shape_type(shape_token,PM);
end

function score = score_shape_type(M,sid,bid,lib,~,fullscore)
    if ~exist('fullscore','var')
       fullscore = false;
    end
    if fullscore
        score = scoreMP(M,lib);
        return
    end
    shape_type = M.S{sid}.shapes_type(:,:,bid);
    shape_token = M.S{sid}.shapes_token(:,:,bid);
    id = M.S{sid}.ids(bid);
    lp = CPD.score_shape_type(lib,shape_type,id);
    ll = CPD.score_shape_token(lib,shape_token,shape_type);
    score = lp + ll;
end

function [score,out] = score_shape_token(M,sid,bid,lib,~,fullscore)
    if ~exist('fullscore','var')
       fullscore = false;
    end
    if fullscore
        [score,out] = scoreMP(M,lib);
        return
    end
    shape_type = M.S{sid}.shapes_type(:,:,bid);
    shape_token = M.S{sid}.shapes_token(:,:,bid);

    %% account for future positions, which this parameter may influence
    ll_next_pos = 0;
    for i=sid+1:M.ns
       nextS = M.S{i};
       ll_next_pos = ll_next_pos + CPD.score_position(lib,nextS.pos_token,nextS.R,M.S(1:i-1));
    end

    %% sum up scores
    score = ll_next_pos + CPD.score_image(M.I,M.pimg) + CPD.score_shape_token(lib,shape_token,shape_type);
end

%% SCALE

function invscales_type = propose_scale_type(invscales_type,PM)
    assert(isscalar(invscales_type));
    invscales_type = invscales_type + PM.mcmc.prop_scale_sd .* randn(size(invscales_type));
end

function invscales_token = propose_scale_token(invscales_token,PM)
    invscales_token = propose_scale_type(invscales_token,PM);
end

function score = score_scale_type(M,sid,bid,lib,~,fullscore)
    if ~exist('fullscore','var')
       fullscore = false;
    end
    if fullscore
        score = scoreMP(M,lib);
        return
    end
    scales_type = M.S{sid}.invscales_type(bid);
    scales_token = M.S{sid}.invscales_token(bid);
    id = M.S{sid}.ids(bid);
    lp = CPD.score_invscale_type(lib,scales_type,id);
    ll = CPD.score_invscale_token(lib,scales_token,scales_type);
    score = lp + ll;
end

function score = score_scale_token(M,sid,bid,lib,~,fullscore)
    if ~exist('fullscore','var')
       fullscore = false;
    end
    if fullscore
        score = scoreMP(M,lib);
        return
    end
    scales_type = M.S{sid}.invscales_type(bid);
    scales_token = M.S{sid}.invscales_token(bid);

    %% account for future positions, which this parameter may influence
    ll_next_pos = 0;
    for i=sid+1:M.ns
       nextS = M.S{i};
       ll_next_pos = ll_next_pos + CPD.score_position(lib,nextS.pos_token,nextS.R,M.S(1:i-1));
    end

    score = ll_next_pos + CPD.score_image(M.I,M.pimg) + CPD.score_invscale_token(lib,scales_token,scales_type);
end

%% POSITION

function pos = propose_local_position(pos,PM)
    pos = propose_global_position(pos,PM);
end

function gpos = propose_global_position(gpos,PM)
    gpos = gpos + PM.mcmc.prop_gpos_sd .* randn(size(gpos));
end

function score = score_global_position(M,sid,lib,fullscore)
    if ~exist('fullscore','var')
       fullscore = false;
    end
    if fullscore
        score = scoreMP(M,lib);
        return
    end
    R = M.S{sid}.R;
    lp = CPD.score_relation_type(lib,R);
    ll = CPD.score_position(lib,M.S{sid}.pos_token,R,M.S(1:sid-1));
    score = lp + ll;
end

function score = score_local_position(M,sid,lib,fullscore)
    if ~exist('fullscore','var')
       fullscore = false;
    end
    if fullscore
        score = scoreMP(M,lib);
        return
    end
    R = M.S{sid}.R;
    ll = CPD.score_position(lib,M.S{sid}.pos_token,R,M.S(1:sid-1));

    %% account for future positions, which this parameter may influence
    ll_next_pos = 0;
    for i=sid+1:M.ns
       nextS = M.S{i};
       ll_next_pos = ll_next_pos + CPD.score_position(lib,nextS.pos_token,nextS.R,M.S(1:i-1));
    end

    score = CPD.score_image(M.I,M.pimg) + ll + ll_next_pos;
end

%% EVALUATION SPOT RELATION

function eval_spot_type = propose_eval_spot(eval_spot_type,PM)
    eval_spot_type = eval_spot_type + PM.mcmc.prop_relmid_sd .* randn;
end

function score = score_eval_spot_type(M,sid,lib,~,fullscore)
    if ~exist('fullscore','var')
       fullscore = false;
    end
    if fullscore
        score = scoreMP(M,lib);
        return
    end
    R = M.S{sid}.R;
    lp = CPD.score_relation_type(lib,R);
    ll = CPD.score_relation_token(lib,R.eval_spot_token,R.eval_spot_type);
    score = lp + ll;
end

function score = score_eval_spot_token(M,sid,lib,~,fullscore)
    if ~exist('fullscore','var')
       fullscore = false;
    end
    if fullscore
        score = scoreMP(M,lib);
        return
    end
    R = M.S{sid}.R;
    lp = CPD.score_relation_token(lib,R.eval_spot_token,R.eval_spot_type);
    ll = CPD.score_position(lib,M.S{sid}.pos_token,R,M.S(1:sid-1));
    score = lp + ll;
end


function updateGeoScatter(obj,geoIndex)

    %-----------------------------------------------------------------------------%

    %-INTIALIZATIONS-%

    axIndex = obj.getAxisIndex(obj.State.Plot(geoIndex).AssociatedAxis);
    geoData = get(obj.State.Plot(geoIndex).Handle);
    axisData = geoData.Parent;
    [xSource, ~] = findSourceAxis(obj,axIndex);

    %-------------------------------------------------------------------------%

    %-set trace-%
    if strcmpi(obj.PlotOptions.geoRenderType, 'geo')
        obj.data{geoIndex}.geo = sprintf('geo%d', xSource+1);
        obj.data{geoIndex}.type = 'scattergeo';

    elseif strcmpi(obj.PlotOptions.geoRenderType, 'mapbox')
        obj.data{geoIndex}.subplot = sprintf('mapbox%d', xSource+1);
        obj.data{geoIndex}.type = 'scattermapbox';
    end

    obj.data{geoIndex}.mode = 'markers+text';

    %-------------------------------------------------------------------------%

    %-set trace data-%
    obj.data{geoIndex}.lat = geoData.LatitudeData;
    obj.data{geoIndex}.lon = geoData.LongitudeData;

    %-------------------------------------------------------------------------%

    %-set trace marker-%
    marker = extractGeoMarker(geoData, axisData);

    if strcmpi(obj.PlotOptions.geoRenderType, 'mapbox')
        marker.allowoverlap = true;
        marker = rmfield(marker, 'symbol');

        if strcmp(marker.color, 'rgba(0,0,0,0)') && isfield(marker, 'line')
            marker.color = marker.line.color;
        end
    end

    obj.data{geoIndex}.marker = marker;

    %-------------------------------------------------------------------------%
end


function [y,fs]=readflac(filename,mode)
%READWAV  Read a .FLAC format sound file [Y,FS]=(FILENAME,MODE)
%
% Input Parameters:
%
%	FILENAME gives the name of the file (with optional .WAV extension) or alternatively
%                 can be the FIDX output from a previous call to READWAV
%	MODE		specifies the following (*=default):
%
%    Scaling: 's'    Auto scale to make data peak = +-1
%             'r'    Raw unscaled data (integer values)
%             'q'    Scaled to make 0dBm0 be unity mean square
%             'p' *	 Scaled to make +-1 equal full scale
%             'o'    Scale to bin centre rather than bin edge (e.g. 127 rather than 127.5 for 8 bit values)
%                     (can be combined with n+p,r,s modes)
%             'n'    Scale to negative peak rather than positive peak (e.g. 128.5 rather than 127.5 for 8 bit values)
%                     (can be combined with o+p,r,s modes)
%
% FLAC (Free lossless audio codec) is a compressed audio file format described here:
% http://flac.sourceforge.net/

%      Copyright (C) Mike Brookes 2008
%      Version: $Id: readflac.m,v 1.1 2009/09/13 15:52:23 dmb Exp $
%
%   VOICEBOX is a MATLAB toolbox for speech processing.
%   Home page: http://www.ee.ic.ac.uk/hp/staff/dmb/voicebox/voicebox.html
%
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%   This program is free software; you can redistribute it and/or modify
%   it under the terms of the GNU General Public License as published by
%   the Free Software Foundation; either version 2 of the License, or
%   (at your option) any later version.
%
%   This program is distributed in the hope that it will be useful,
%   but WITHOUT ANY WARRANTY; without even the implied warranty of
%   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
%   GNU General Public License for more details.
%
%   You can obtain a copy of the GNU General Public License from
%   http://www.gnu.org/copyleft/gpl.html or by writing to
%   Free Software Foundation, Inc.,675 Mass Ave, Cambridge, MA 02139, USA.
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
if nargin<2
    mode='p';
else
    mode = [mode(:).' 'p'];
end
dirt=voicebox('dir_temp');
[fnp,fnn,fne,fnv]=fileparts(filename);
filetemp=fullfile(dirt,[fnn '.wav' fnv]);
doscom=['"' voicebox('flac') '"' ' -d -f -o "' filetemp '" "' filename '"'];
%                     fprintf(1,'Executing: %s\n',doscom);
[doss,dosr]=dos(doscom); % run the program
if doss % test for errors
    error(sprintf('Error running DOS command: %s',doscom));
end
if exist(filetemp)~=2
    error(sprintf('No output file from: %s',doscom));
end
[y,fs]=readwav(filetemp,mode);
doscom=['del /f "' filetemp '"'];
if dos(doscom) % run the program
    error(sprintf('Error running DOS command: %s',doscom));
end