classdef ADRV9009Tests < HardwareTests

    properties
        uri = 'ip:analog';
        SamplingRateRX = 245.76e6;
        author = 'ADI';
    end

    methods(TestClassSetup)
        % Check hardware connected
        function CheckForHardware(testCase)
            Device = @()adi.ADRV9009.Rx;
            testCase.CheckDevice('ip',Device,testCase.uri(4:end),false);
        end
    end

    methods (Static)
        function estFrequency(data,fs)
            nSamp = length(data);
            FFTRxData  = fftshift(10*log10(abs(fft(data))));
            df = fs/nSamp;  freqRangeRx = (-fs/2:df:fs/2-df).'/1000;
            plot(freqRangeRx, FFTRxData);
        end
    end

    methods (Test)

        function testADRV9009Rx(testCase)
            % Test Rx DMA data output
            rx = adi.ADRV9009.Rx('uri',testCase.uri);
            rx.EnabledChannels = 1;
            [out, valid] = rx();
            rx.release();
            testCase.verifyTrue(valid);
            testCase.verifyGreaterThan(sum(abs(double(out))),0);
        end

        function testADRV9009RxCustomProfile1(testCase)
            % Test Rx custom profiles
            rx = adi.ADRV9009.Rx('uri',testCase.uri);
            rx.EnabledChannels = 1;
            rx.EnableCustomProfile = true;
            rx.CustomProfileFileName = ...
                'Tx_BW200_IR245p76_Rx_BW200_OR245p76_ORx_BW200_OR245p76_DC245p76.txt';
            [out, valid] = rx();
            rxSampleRate = rx.getAttributeLongLong('voltage0',...
                'sampling_frequency',false);
            txSampleRate = rx.getAttributeLongLong('voltage0',...
                'sampling_frequency',true);
            rx.release();
            testCase.verifyTrue(valid);
            testCase.verifyGreaterThan(sum(abs(double(out))),0);
            testCase.verifyEqual(rxSampleRate,int64(245.76e6),...
                'Invalid sample rate after profile write');
            testCase.verifyEqual(txSampleRate,int64(245.76e6),...
                'Invalid sample rate after profile write');
        end

        function testADRV9009RxCustomProfile2(testCase)
            % Test Rx custom profiles
            rx = adi.ADRV9009.Rx('uri',testCase.uri);
            rx.EnabledChannels = 1;
            rx.EnableCustomProfile = true;
            rx.CustomProfileFileName = ...
                'Tx_BW400_IR491p52_Rx_BW200_OR245p76_ORx_BW400_OR491p52_DC245p76.txt';
            [out, valid] = rx();
            rxSampleRate = rx.getAttributeLongLong('voltage0',...
                'sampling_frequency',false);
            txSampleRate = rx.getAttributeLongLong('voltage0',...
                'sampling_frequency',true);
            rx.release();
            testCase.verifyTrue(valid);
            testCase.verifyGreaterThan(sum(abs(double(out))),0);
            testCase.verifyEqual(rxSampleRate,int64(245.76e6),...
                'Invalid sample rate after profile write');
            testCase.verifyEqual(txSampleRate,int64(245.76e6*2),...
                'Invalid sample rate after profile write');
        end
%
%         function testADRV9009RxCustomProfileZC706(testCase)
%             % Test Rx custom profiles
%             rx = adi.ADRV9009.Rx('uri',testCase.uri);
%             rx.EnabledChannels = 1;
%             rx.EnableCustomProfile = true;
%             rx.CustomProfileFileName = ...
%                 'Tx_BW100_IR122p88_Rx_BW100_OR122p88_ORx_BW100_OR122p88_DC122p88.txt';
%             [out, valid] = rx();
%             rxSampleRate = rx.getAttributeLongLong('voltage0',...
%                 'sampling_frequency',false);
%             rx.release();
%             testCase.verifyTrue(valid);
%             testCase.verifyGreaterThan(sum(abs(double(out))),0);
%             testCase.verifyEqual(rxSampleRate,int64(122880000),...
%                 'Invalid sample rate after profile write');
%         end

        function testADRV9009RxWithTxDDS(testCase)
            % Test DDS output
            tx = adi.ADRV9009.Tx('uri',testCase.uri);
            tx.DataSource = 'DDS';
            toneFreq = 30e6;
            tx.DDSFrequencies = repmat(toneFreq,2,4);
            tx.AttenuationChannel0 = -10;
            tx.EnableCustomProfile = true;
            tx.CustomProfileFileName = ...
                'Tx_BW200_IR245p76_Rx_BW200_OR245p76_ORx_BW200_OR245p76_DC245p76.txt';
            tx();
            pause(1);
            rx = adi.ADRV9009.Rx('uri',testCase.uri);
            rx.EnabledChannels = 1;
            rx.kernelBuffersCount = 1;
            for k=1:10
                valid = false;
                while ~valid
                    [out, valid] = rx();
                end
            end

            rxSampleRate = rx.getAttributeLongLong('voltage0',...
                'sampling_frequency',false);

            rx.release();

%             plot(real(out));
%             testCase.estFrequency(out,testCase.SamplingRateRX);
            freqEst = meanfreq(double(real(out)),rxSampleRate);

            testCase.verifyTrue(valid);
            testCase.verifyGreaterThan(sum(abs(double(out))),0);
            testCase.verifyEqual(freqEst,toneFreq,'RelTol',0.01,...
                'Frequency of DDS tone unexpected')

        end

        function testADRV9009RxWithTxDDSTwoChan(testCase)
            % Test DDS output
            tx = adi.ADRV9009.Tx('uri',testCase.uri);
            tx.DataSource = 'DDS';
            toneFreq1 = 30e6;
            toneFreq2 = 85e6;

            tx.DDSFrequencies = [toneFreq1,toneFreq1,toneFreq2,toneFreq2;...
                0,0,0,0];
            tx.DDSScales = [1,1,1,1;...
                0,0,0,0];
            tx.DDSPhases = [90000,0,90000,0;...
                0,0,0,0];

            tx.AttenuationChannel0 = -10;
            tx.EnableCustomProfile = true;
            tx.CustomProfileFileName = ...
                'Tx_BW200_IR245p76_Rx_BW200_OR245p76_ORx_BW200_OR245p76_DC245p76.txt';
            tx();
            pause(1);
            rx = adi.ADRV9009.Rx('uri',testCase.uri);
            rx.EnabledChannels = [1,2];
            rx.kernelBuffersCount = 1;
            for k=1:10
                valid = false;
                while ~valid
                    [out, valid] = rx();
                end
            end

            rxSampleRate = rx.getAttributeLongLong('voltage0',...
                'sampling_frequency',false);

            rx.release();

%             plot(real(out));
%             testCase.estFrequency(out,rxSampleRate);
            freqEst = meanfreq(double(real(out)),rxSampleRate);

            testCase.verifyTrue(valid);
            testCase.verifyGreaterThan(sum(abs(double(out))),0);
            testCase.verifyEqual(freqEst(1),toneFreq1,'RelTol',0.01,...
                'Frequency of DDS tone unexpected')
            testCase.verifyEqual(freqEst(2),toneFreq2,'RelTol',0.01,...
                'Frequency of DDS tone unexpected')
        end

        function testADRV9009RxWithTxData(testCase)
            % Test Tx DMA data output
            amplitude = 2^15; frequency = 20e6;
            swv1 = dsp.SineWave(amplitude, frequency);
            swv1.ComplexOutput = true;
            swv1.SamplesPerFrame = 2^20;
            swv1.SampleRate = 245.76e6;
            y = swv1();

            tx = adi.ADRV9009.Tx('uri',testCase.uri);
            tx.DataSource = 'DMA';
            tx.EnableCyclicBuffers = true;
            tx.AttenuationChannel0 = -10;
            tx.EnableCustomProfile = true;
            tx.CustomProfileFileName = ...
                'Tx_BW200_IR245p76_Rx_BW200_OR245p76_ORx_BW200_OR245p76_DC245p76.txt';
            tx(y);
            rx = adi.ADRV9009.Rx('uri',testCase.uri);
            rx.EnabledChannels = 1;
            rx.kernelBuffersCount = 1;
            for k=1:20
                valid = false;
                while ~valid
                    [out, valid] = rx();
                end
            end

            rxSampleRate = rx.getAttributeLongLong('voltage0',...
                'sampling_frequency',false);

            rx.release();

%             plot(real(out));
%             testCase.estFrequency(out,testCase.SamplingRateRX);
            freqEst = meanfreq(double(real(out)),rxSampleRate);

            testCase.verifyTrue(valid);
            testCase.verifyGreaterThan(sum(abs(double(out))),0);
            testCase.verifyEqual(freqEst,frequency,'RelTol',0.01,...
                'Frequency of ML tone unexpected')
        end
    end

end


function res = spp_test(spp_model, imdb, roidb, feat_cache, suffix, fast, evaluate)
% res = spp_test(spp_model, imdb, roidb, feat_cache, suffix, fast, evaluate)
%   Compute test results using the trained spp_model on the
%   image database specified by imdb. Results are saved
%   with an optional suffix.
%
% Adapted from spp code written by Ross Girshick
% AUTORIGHTS
% ---------------------------------------------------------
% Copyright (c) 2014, Shaoqing Ren
%
% This file is part of the SPP code and is available
% under the terms of the Simplified BSD License provided in
% LICENSE. Please retain this notice and LICENSE if you use
% this file (or any portion of it) in your project.
% ---------------------------------------------------------
% Copyright (c) 2014, Ross Girshick
%
% This file is part of the R-CNN code and is available
% under the terms of the Simplified BSD License provided in
% LICENSE. Please retain this notice and LICENSE if you use
% this file (or any portion of it) in your project.
% ---------------------------------------------------------

if nargin < 5
    suffix = '';
end

if nargin < 6
    fast = false;
end

if nargin < 7
    evaluate = true;
end

t_start = tic();

conf = spp_config('sub_dir', fullfile(spp_model.cache_name, imdb.name));
image_ids = imdb.image_ids;

% assume they are all the same
feat_opts = spp_model.training_opts;
feat_opts.feat_cache = feat_cache;
num_classes = length(spp_model.classes);
rois = roidb.rois;

if conf.use_gpu
    spp_model.cnn.layers = spp_layers_in_gpu(spp_model.cnn.layers);
end

if ~exist('suffix', 'var') || isempty(suffix)
  suffix = '';
else
  suffix = ['_' suffix];
end

try
  aboxes = cell(num_classes, 1);
  for i = 1:num_classes
    load([conf.cache_dir spp_model.classes{i} '_boxes_' imdb.name suffix]);
    aboxes{i} = boxes;
  end
catch
  aboxes = cell(num_classes, 1);
  box_inds = cell(num_classes, 1);
  for i = 1:num_classes
    aboxes{i} = cell(length(image_ids), 1);
    box_inds{i} = cell(length(image_ids), 1);
  end

  max_per_set = 5 * length(image_ids);
  max_per_image = 100;
  top_scores = cell(num_classes, 1);
  thresh = -1.5*ones(num_classes, 1);

  if ~isfield(spp_model, 'folds')
    folds{1} = 1:length(image_ids);
  else
    folds = spp_model.folds;
  end

  count = 0;
  for f = 1:length(folds)
    for i = folds{f}
      count = count + 1;
      fprintf('%s: test (%s) %d/%d ', procid(), imdb.name, count, length(image_ids));
      th = tic;
      d = rois(i);
      d.feat = spp_load_cached_poolX_features(spp_model.spp_pooler, feat_opts.feat_cache, ...
          imdb.name, image_ids{i}, d.boxes);
      if isempty(d.feat)
        continue;
      end
      d.feat = spp_poolX_to_fcX(d.feat, feat_opts.layer, spp_model, conf.use_gpu);
      d.feat = spp_scale_features(d.feat, feat_opts.feat_norm_mean);
      zs = bsxfun(@plus, spp_model.detectors(f).W * d.feat, spp_model.detectors(f).B)';

      for j = 1:num_classes
        boxes = d.boxes;
        scores = zs(:,j);
        I = find(~d.gt & scores > thresh(j));
        keep = nms(cat(2, single(boxes(I,:)), single(scores(I))), 0.3);
        I = I(keep);
        if ~isempty(I)
          [~, ord] = sort(scores(I), 'descend');
          ord = ord(1:min(length(ord), max_per_image));
          I = I(ord);
          boxes = boxes(I,:);
          scores = scores(I);
          aboxes{j}{i} = cat(2, single(boxes), single(scores));
          box_inds{j}{i} = I;
        else
          aboxes{j}{i} = zeros(0, 5, 'single');
          box_inds{j}{i} = [];
        end
      end

      if mod(count, 1000) == 0
          [aboxes{j}, box_inds{j}, thresh(j)] = ...
             keep_top_k(aboxes{j}, box_inds{j}, i, max_per_set, thresh(j));
      end
      fprintf(' time: %.3fs\n', toc(th));
      if mod(count, 1000) == 0
        disp(thresh);
      end

    end
  end

  for i = 1:num_classes

    top_scores{i} = sort(top_scores{i}, 'descend');
    if (length(top_scores{i}) > max_per_set)
        thresh(i) = top_scores{i}(max_per_set);
    end

    % go back through and prune out detections below the found threshold
    for j = 1:length(image_ids)
      if ~isempty(aboxes{i}{j})
        I = find(aboxes{i}{j}(:,end) < thresh(i));
        aboxes{i}{j}(I,:) = [];
        box_inds{i}{j}(I,:) = [];
      end
    end

    save_file = [conf.cache_dir spp_model.classes{i} '_boxes_' imdb.name suffix];
    boxes = aboxes{i};
    inds = box_inds{i};
    save(save_file, 'boxes', 'inds');
    clear boxes inds;
  end
end

fprintf('spp_test_spm in %f seconds.\n', toc(t_start));

% ------------------------------------------------------------------------
% Peform AP evaluation
% ------------------------------------------------------------------------
if ~evaluate
    res = [];
    return;
end

if isequal(imdb.eval_func, @imdb_eval_voc)
    if fast
        classes = spp_model.classes;
        cache_name = spp_model.cache_name;
        parfor model_ind = 1:num_classes
          cls = classes{model_ind};
          res(model_ind) = imdb.eval_func(cls, aboxes{model_ind}, imdb, cache_name, suffix, fast);
        end
    else
        for model_ind = 1:num_classes
          cls = spp_model.classes{model_ind};
          res(model_ind) = imdb.eval_func(cls, aboxes{model_ind}, imdb, spp_model.cache_name, suffix, fast);
        end
    end
else
% ilsvrc
    res = imdb.eval_func(aboxes, imdb, spp_model.cache_name, suffix, fast);
end

if ~isempty(res)
    fprintf('\n~~~~~~~~~~~~~~~~~~~~\n');
    fprintf('Results:\n');
    aps = [res(:).ap]' * 100;
    disp(aps);
    disp(mean(aps));
    fprintf('~~~~~~~~~~~~~~~~~~~~\n');
end

% ------------------------------------------------------------------------
function [boxes, box_inds, thresh] = keep_top_k(boxes, box_inds, end_at, top_k, thresh)
% ------------------------------------------------------------------------
% Keep top K
X = cat(1, boxes{1:end_at});
if isempty(X)
  return;
end
scores = sort(X(:,end), 'descend');
thresh = scores(min(length(scores), top_k));
for image_index = 1:end_at
  bbox = boxes{image_index};
  keep = find(bbox(:,end) >= thresh);
  boxes{image_index} = bbox(keep,:);
  box_inds{image_index} = box_inds{image_index}(keep);
end


function TS_ConvertToTable(hctsaFile)
% TS_ConvertToTable     Converts a file using the old structure array format -> table
%
%---INPUTS:
% hctsaFile, an hctsa file to convert

% ------------------------------------------------------------------------------
% Copyright (C) 2020, Ben D. Fulcher <ben.d.fulcher@gmail.com>,
% <http://www.benfulcher.com>
%
% If you use this code for your research, please cite the following two papers:
%
% (1) B.D. Fulcher and N.S. Jones, "hctsa: A Computational Framework for Automated
% Time-Series Phenotyping Using Massive Feature Extraction, Cell Systems 5: 527 (2017).
% DOI: 10.1016/j.cels.2017.10.001
%
% (2) B.D. Fulcher, M.A. Little, N.S. Jones, "Highly comparative time-series
% analysis: the empirical structure of time series and their methods",
% J. Roy. Soc. Interface 10(83) 20130048 (2013).
% DOI: 10.1098/rsif.2013.0048
%
% This work is licensed under the Creative Commons
% Attribution-NonCommercial-ShareAlike 4.0 International License. To view a copy of
% this license, visit http://creativecommons.org/licenses/by-nc-sa/4.0/ or send
% a letter to Creative Commons, 444 Castro Street, Suite 900, Mountain View,
% California, 94041, USA.
% ------------------------------------------------------------------------------

if nargin < 1
    hctsaFile = 'HCTSA.mat';
end

[~,TimeSeries,Operations,whatDataFile] = TS_LoadData(hctsaFile,false);
MasterOperations = TS_GetFromData(whatDataFile,'MasterOperations');

% Convert the three structure arrays to tables:
if isstruct(TimeSeries)
    TimeSeries = struct2table(TimeSeries);
end
if isstruct(Operations)
    Operations = struct2table(Operations);
end
if isstruct(MasterOperations)
    MasterOperations = struct2table(MasterOperations);
end

% Save back to file
fprintf(1,'Converted TimeSeries, Operations, and MasterOperations to table, saving back to %s...',whatDataFile);
save(whatDataFile,'TimeSeries','Operations','MasterOperations','-append')
fprintf(1,'Saved.\n');

end


% PURPOSE: subroutine for pop_continuousartdet.m
%
% Author: Javier Lopez-Calderon
% Center for Mind and Brain
% University of California, Davis,
% Davis, CA
% 2011

function [WinRej chanrej] = movesegments(WinRej, chanrej, winoffsetsam, pnts)
fprintf('\nWARNING: Marked segments will be displaced in %g samples.\n\n', winoffsetsam);
WinRej = WinRej + winoffsetsam;
WinRej(WinRej<1) = 1;
WinRej(WinRej>pnts) = pnts;
[WinRej chanrej] = discardshortsegments(WinRej, chanrej, 0, 0);


function setup_convnet_burden()
%SETUP_CONVNET_BURDEN Sets up convnet-burden, by adding its folders
% to the Matlab path
%
% Copyright (C) 2017 Samuel Albanie
% Licensed under The MIT License [see LICENSE.md for details]

  check_dependency('mcnExtraLayers') ;
  root = fileparts(mfilename('fullpath')) ;
  addpath(root, [root '/matlab'], [root '/core']) ;

% -----------------------------------
function check_dependency(moduleName)
% -----------------------------------

  name2path = @(name) strrep(name, '-', '_') ;
  setupFunc = ['setup_', name2path(moduleName)] ;
  if exist(setupFunc, 'file')
    vl_contrib('setup', moduleName) ;
  else
    % try adding the module to the path, supressing the warning
    warning('off', 'MATLAB:dispatcher:pathWarning') ;
    addpath(fullfile(vl_rootnn, 'contrib', moduleName)) ;
    warning('on', 'MATLAB:dispatcher:pathWarning') ;

    if exist(setupFunc, 'file')
      vl_contrib('setup', moduleName) ;
    else
      waiting = true ;
      msg = ['module %s was not found on the MATLAB path. Would you like ' ...
             'to install it now? (y/n)\n'] ;
      prompt = sprintf(msg, moduleName) ;
      while waiting
        str = input(prompt,'s') ;
        switch str
          case 'y'
            vl_contrib('install', moduleName) ;
            vl_contrib('compile', moduleName) ;
            vl_contrib('setup', moduleName) ;
            return ;
          case 'n'
            throw(exception) ;
          otherwise
            fprintf('input %s not recognised, please use `y` or `n`\n', str) ;
        end
      end
    end
  end


% STD_READERSP - load ERSP measures for data channels or  for all
%                  components of a specified cluster. This function is
%                  also being used to read ITC and ERPimage data.
% Usage:
%   >> [STUDY, erspdata, times, freqs, erspbase] = ...
%                   std_readersp(STUDY, ALLEEG, varargin);
% Inputs:
%       STUDY - studyset structure containing some or all files in ALLEEG
%      ALLEEG - vector of loaded EEG datasets
%
% Optional inputs:
%  'design'    - [integer] read files from a specific STUDY design. Default
%                is empty (use current design in STUDY.currentdesign).
%  'channels'  - [cell] list of channels to import {default: none}
%  'clusters'  - [integer] list of clusters to import {[]|default: all but
%                the parent cluster (1) and any 'NotClust' clusters}
%  'singletrials' - ['on'|'off'] load single trials spectral data (if
%                available). Default is 'off'.
%  'forceread' - ['on'|'off'] Force rereading data from disk.
%                Default is 'off'.
%  'subject'   - [string] select a specific subject {default:all}
%  'component' - [integer] select a specific component in a cluster.
%                This is the index of the component in the cluster not the
%                component number {default:all}
%  'datatype'  - {'ersp'|'itc'|'erpim'} This function is used to read all
%                2-D STUDY matrices stored on disk (not only ERSP). It may
%                read ERSP ('ersp' option), ITC ('itc' option) or ERPimage
%                data ('erpim' option).
%
% ERSP specific options:
%  'timerange' - [min max] time range {default: whole measure range}
%  'freqrange' - [min max] frequency range {default: whole measure range}
%  'subbaseline' - ['on'|'off'] subtract the ERSP baseline for paired
%                conditions. The conditions for which baseline is removed
%                are indicated on the command line. See help
%                std_studydesign for more information about paired and
%                unpaired variables.
%
% ERPimage specific option:
%   This function is used to read all 2-D STUDY matrices stored on disk
%   (this includes ERPimages). It therefore takes as input specific
%   ERPimage options. Note that the 'singletrials' optional input is
%   irrelevant for ERPimages (which are always stored as single trials).
%   'concatenate' - ['on'|'off'] read concatenated ERPimage data ('on') or
%                   stacked ERPimage data. See help std_erpimage for more
%                   information.
%   'timerange'   - [min max] time range {default: whole measure range}
%   'trialrange'  - [min max] read only a specific range of the ERPimage
%                   output trials {default: whole measure range}
% Output:
%  STUDY    - updated studyset structure
%  erspdata - [cell array] ERSP data (the cell array size is
%             condition x groups). This may also be ITC data or ERPimage
%             data (see above).
%  times    - [float array] array of time points
%  freqs    - [float array] array of frequencies. For ERPimage this
%             contains trial indices.
%  erspbase - [cell array] baseline values
%  events   - [cell array] events (ERPimage only).
%
% Author: Arnaud Delorme, CERCO, 2006-

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

function [STUDY, erspdata, alltimes, allfreqs, erspbase, events, unitPower] = std_readersp(STUDY, ALLEEG, varargin)

if nargin < 2
    help std_readersp;
    return;
end
events = {};
unitPower = 'dB';
erspbase = [];

disp('This function is obsolete and only partially backward compatible use std_readdata instead');
[STUDY, erspdata, alltimes, allfreqs, events] = std_readdata(STUDY, ALLEEG, 'datatype', 'ersp', varargin{:});


function fg = fgCreate(varargin)
% Create a fiber group structure with default values
%
%   fg = fgCreate;
%
% Fields that can be set are
%   name = 'FG-1';
%   thickness = -0.5;        % Means ...
%   visibleFlag = 1;
%   colorRgb = [20 90 200];
%   seeds = [];
%   seedRadius = 0;
%   seedVoxelOffsets = [];
%   params = {};
%   fibers = fibers;
%   query_id = -1;
%   coordspace = struct('acpc', eye(4), 'img', [], 'mni', []);
%
% Example:
%   fg = fgCreate;
%   fg = fgCreate('name','myGroup');
%   fg = fgCreate('name','myGroup','colorRgb',[255 255 255]);
%   fg(2) = fgCreate;
%
% See also: fgSet, fgGet
%
% (c) Stanford VISTA Team

%% Set up the defaults
name = 'FG-1';
type = 'fibergroup';

thickness = -0.5;
visibleFlag = 1;
color = [20 90 200];
fibers = {};

fg.name = name;
fg.type = type;
fg.colorRgb = color;
fg.thickness = thickness;
fg.visible = visibleFlag;
fg.seeds = [];
fg.seedRadius = 0;
fg.seedVoxelOffsets = [];
fg.params = {};
fg.fibers = fibers;
fg.query_id = -1;

% Identifiers for the fibers in fg.fibers
% This is a list of possible names (e.g., arcuate, optic radiation) for
% each of the fibers in the cell array, fg.fibers{ii}.  There might be
% something like 20 different names when it is the Mori groups, for
% example.
fg.fiberNames = [];

% A numerical index, normally of the same length as fg.fibers, where each
% index points to the name associated with that fiber.  So, for the ith
% fiber cell array, fg.fibers{ii}, the index is fg.fiberNumbers(ii) and the
% name is fg.fiberNames(fg.fiberIndex(ii));
% The fiberIndex normally has the same length as fg.fibers.  There should
% be a smaller number of fiberNames.  To indicate that you don't know which
% group a fiber belongs to, use a non positive integer value, say -1.
fg.fiberIndex = [];

% Which space are the fiber coordinates represented in?
% Image space ('img') are basically indices into the data voxels.
% ACPC ('acpc') space is relative to the middle of the acpc.
% MNI ('mni') space is another option.
% This struct contains the transformations required to get from the
% fiber coordinates to the requested coordinate space (if this xform is
% known). If the fiber coordinates are given in a particular coordinate
% space. That matrix for that coordspace will be the identity matrix.
% Unknown transformations (that have not been set in any way) will be set
% to an empty matrix. The default space is 'acpc':
fg.coordspace = struct('acpc', eye(4), 'img', [], 'mni', []);

% If the user has set some inputs, overwrite the defaults here
fg = mrVarargin(fg,varargin);

return


function h = disp_cubes(cubes, img, mode)

% cubes = drop_thin_cuboids(cubes, vp);

if nargin<3
    mode = 1;
end

if ~isempty(img)
    figure; imshow(img); hold on;
end

h = [];
for i = 1:length(cubes)
    h = [h disp_cube_2(cubes(i))];
    if mode==3
        pause; delete(h); h = [];
    elseif mode==2
        pause(0.01); delete(h); h = [];
    end
end

%%
function h = disp_cube_2(cube)

% color = rand(1,3);
color = [1 0.5 0];
% color = [1 1 0];
linewidth = 5;

h = zeros(1,12);
h(1) = plotline(cube.junc3(1).pt, cube.junc3(2).pt, color, linewidth);
h(2) = plotline(cube.junc3(1).pt, cube.junc3(3).pt, color, linewidth);
h(3) = plotline(cube.junc3(1).pt, cube.junc3(5).pt, color, linewidth);
h(4) = plotline(cube.junc3(2).pt, cube.junc3(4).pt, color, linewidth);
h(5) = plotline(cube.junc3(2).pt, cube.junc3(6).pt, color, linewidth);
h(6) = plotline(cube.junc3(3).pt, cube.junc3(4).pt, color, linewidth);
h(7) = plotline(cube.junc3(3).pt, cube.junc3(7).pt, color, linewidth);
h(8) = plotline(cube.junc3(4).pt, cube.junc3(8).pt, color, linewidth);
h(9) = plotline(cube.junc3(5).pt, cube.junc3(6).pt, color, linewidth);
h(10) = plotline(cube.junc3(5).pt, cube.junc3(7).pt, color, linewidth);
h(11) = plotline(cube.junc3(6).pt, cube.junc3(8).pt, color, linewidth);
h(12) = plotline(cube.junc3(7).pt, cube.junc3(8).pt, color, linewidth);

% for j = 1:8
%     h(12+j) = text(cube.junc3(j).pt(1), cube.junc3(j).pt(2), num2str(j), 'Color', [1 0 0]);
% end


% this code is inspired by VOCevaldet in the PASVAL VOC devkit
% Note: this function has been significantly optimized since ILSVRC2013
function [ap recall precision] = eval_detection(predict_file,gtruth_dir,meta_file,...
                                                eval_file,blacklist_file,optional_cache_file)
% Evaluate detection
% - predict_file: each line is a single predicted object in the
%   format
%    <image_id> <ILSVRC2014_DET_ID> <confidence> <xmin> <ymin> <xmax> <ymax>
% - gtruth_dir: a path to the directory of ground truth information,
%   e.g., ILSVRC2014_DET_bbox_val/
% - meta_file: information about the synsets
% - eval_file: list of images to evaluate on
% - blacklist_file: list of image/category pairs which aren't
%    considered in evaluation
% - optional_cache_file: to save the ground truth data and avoid
%    loading from scratch again

if nargin < 3
    meta_file = '../data/meta_det.mat';
end
if nargin < 4
    eval_file = '../data/det_lists/val.txt';
end
if nargin < 5
    blacklist_file = '../data/ILSVRC2014_det_validation_blacklist.txt';
end
if nargin < 6
    optional_cache_file = '';
end

defaultIOUthr = 0.5;
pixelTolerance = 10;

load(meta_file);
hash = make_hash(synsets);

bLoadXML = true;
if ~isempty(optional_cache_file) && exist(optional_cache_file,'file')
    fprintf('eval_detection :: loading cached ground truth\n');
    t = tic;
    load(optional_cache_file);
    fprintf('eval_detection :: loading cached ground truth took %0.1f seconds\n',toc(t));
    if exist('gt_obj_img_ids','var')
        fprintf(['eval_detection :: loaded cache from 2014, ' ...
                 'recomputing\n']);
    else
        bLoadXML = false;
    end
end
if bLoadXML
    fprintf('eval_detection :: loading ground truth\n');
    t = tic;

    [img_basenames gt_img_ids] = textread(eval_file,'%s %d');

    num_imgs = length(img_basenames);
    gt_obj_labels = cell(1,num_imgs);
    gt_obj_bboxes = cell(1,num_imgs);
    gt_obj_thr = cell(1,num_imgs);
    num_pos_per_class = [];
    tic
    for i=1:num_imgs
        if toc > 60
            fprintf('              :: on %i of %i\n',...
                    i,num_imgs);
            tic;
        end
        rec = VOCreadxml(sprintf('%s/%s.xml',gtruth_dir, ...
                                 img_basenames{i}));
        if ~isfield(rec.annotation,'object')
            continue;
        end
        for j=1:length(rec.annotation.object)
            obj = rec.annotation.object(j);
            c = get_class2node(hash, obj.name);
            gt_obj_labels{i}(j) = c;
            if length(num_pos_per_class) < c
                num_pos_per_class(c) = 1;
            else
                num_pos_per_class(c) = num_pos_per_class(c) + 1;
            end
            b = obj.bndbox;
            bb = str2double({b.xmin b.ymin b.xmax b.ymax});
            gt_obj_bboxes{i}(:,j) = bb;
        end

        bb = gt_obj_bboxes{i};
        gt_w = bb(4,:)-bb(2,:)+1;
        gt_h = bb(3,:)-bb(1,:)+1;
        thr = (gt_w.*gt_h)./((gt_w+pixelTolerance).*(gt_h+pixelTolerance));
        gt_obj_thr{i} = min(defaultIOUthr,thr);
    end
    fprintf('eval_detection :: loading ground truth took %0.1f seconds\n',toc(t));

    if ~isempty(optional_cache_file)
        fprintf('eval_detection :: saving cache in %s\n',optional_cache_file);
        save(optional_cache_file,'gt_img_ids','gt_obj_labels',...
             'gt_obj_bboxes','gt_obj_thr','num_pos_per_class');
    end
end

blacklist_img_id = [];
blacklist_label = [];
if ~isempty(blacklist_file) && exist(blacklist_file,'file')
    [blacklist_img_id wnid] = textread(blacklist_file,'%d %s');
    blacklist_label = zeros(length(wnid),1);
    for i=1:length(wnid)
        blacklist_label(i) = get_class2node(hash,wnid{i});
    end
    fprintf('eval_detection :: blacklisted %i image/object pairs\n',length(blacklist_label));
else
    fprintf('eval_detection :: no blacklist\n');
end

fprintf('eval_detection :: loading predictions\n');
t = tic;
[img_ids obj_labels obj_confs xmin ymin xmax ymax] = ...
        textread(predict_file,'%d %d %f %f %f %f %f');
obj_bboxes = [xmin ymin xmax ymax]';
fprintf('eval_detection :: loading predictions took %0.1f seconds\n',toc(t));

fprintf('eval_detection :: sorting predictions\n');
t = tic;
[img_ids ind] = sort(img_ids);
obj_confs = obj_confs(ind);
obj_labels = obj_labels(ind);
obj_bboxes = obj_bboxes(:,ind);

num_imgs = max(max(gt_img_ids),max(img_ids));
obj_labels_cell = cell(1,num_imgs);
obj_confs_cell = cell(1,num_imgs);
obj_bboxes_cell = cell(1,num_imgs);
start_i = 1;
id = img_ids(1);
tic
for i=1:length(img_ids)
    if toc > 60
        fprintf('               :: on %0.2fM of %0.2fM\n',...
                i/10^6,length(img_ids)/10^6);
        tic
    end
    if (i == length(img_ids)) || (img_ids(i+1) ~= id)
        % i is the last element of this group
        obj_labels_cell{id} = obj_labels(start_i:i)';
        obj_confs_cell{id} = obj_confs(start_i:i)';
        obj_bboxes_cell{id} = obj_bboxes(:,start_i:i);
        if i < length(img_ids)
            % start next group
            id = img_ids(i+1);
            start_i = i+1;
        end
    end
end

for i=1:num_imgs
    [obj_confs_cell{i} ind] = sort(obj_confs_cell{i},'descend');
    obj_labels_cell{i} = obj_labels_cell{i}(ind);
    obj_bboxes_cell{i} = obj_bboxes_cell{i}(:,ind);
end
tp_cell = cell(1,num_imgs);
fp_cell = cell(1,num_imgs);

fprintf('eval_detection :: sorting predictions took %0.1f seconds\n', ...
        toc(t));

fprintf('eval_detection :: accumulating\n');

num_classes = length(num_pos_per_class);

t = tic;
tic;
% iterate over images
for i=1:length(gt_img_ids)
    if toc > 60
        fprintf('               :: on %i of %i\n',...
                i,length(gt_img_ids));
        tic;
    end

    id = gt_img_ids(i);
    gt_labels = gt_obj_labels{i};
    gt_bboxes = gt_obj_bboxes{i};
    gt_thr = gt_obj_thr{i};
    num_gt_obj = length(gt_labels);
    gt_detected = zeros(1,num_gt_obj);

    bSameImg = blacklist_img_id == id;
    blacklisted_obj = blacklist_label(bSameImg);

    labels = obj_labels_cell{id};
    bboxes = obj_bboxes_cell{id};

    num_obj = length(labels);
    tp = zeros(1,num_obj);
    fp = zeros(1,num_obj);
    for j=1:num_obj
        if any(labels(j) == blacklisted_obj)
            continue; % just ignore this detection
        end
        bb = bboxes(:,j);
        ovmax = -inf;
        kmax = -1;
        for k=1:num_gt_obj
            if labels(j) ~= gt_labels(k)
                continue;
            end
            if gt_detected(k) > 0
                continue;
            end
            bbgt = gt_bboxes(:,k);
            bi=[max(bb(1),bbgt(1)) ; max(bb(2),bbgt(2)) ; min(bb(3),bbgt(3)) ; min(bb(4),bbgt(4))];
            iw=bi(3)-bi(1)+1;
            ih=bi(4)-bi(2)+1;
            if iw>0 & ih>0
                % compute overlap as area of intersection / area of union
                ua=(bb(3)-bb(1)+1)*(bb(4)-bb(2)+1)+...
                   (bbgt(3)-bbgt(1)+1)*(bbgt(4)-bbgt(2)+1)-...
                   iw*ih;
                ov=iw*ih/ua;
                % makes sure that this object is detected according
                % to its individual threshold
                if ov >= gt_thr(k) && ov > ovmax
                    ovmax=ov;
                    kmax=k;
                end
            end
        end
        if kmax > 0
            tp(j) = 1;
            gt_detected(kmax) = 1;
        else
            fp(j) = 1;
        end
    end

    % put back into global vector
    tp_cell{id} = tp;
    fp_cell{id} = fp;

    for k=1:num_gt_obj
        label = gt_labels(k);
        % remove blacklisted objects from consideration as positive examples
        if any(label == blacklisted_obj)
            num_pos_per_class(label) = num_pos_per_class(label)-1;
        end
    end
end
fprintf('eval_detection :: accumulating took %0.1f seconds\n', ...
        toc(t));

fprintf('eval_detection :: computing ap\n');
t = tic;
tp_all = [tp_cell{:}];
fp_all = [fp_cell{:}];
obj_labels = [obj_labels_cell{:}];
confs = [obj_confs_cell{:}];

[confs ind] = sort(confs,'descend');
tp_all = tp_all(ind);
fp_all = fp_all(ind);
obj_labels = obj_labels(ind);

for c=1:num_classes
    % compute precision/recall
    tp = cumsum(tp_all(obj_labels==c));
    fp = cumsum(fp_all(obj_labels==c));
    recall{c}=(tp/num_pos_per_class(c))';
    precision{c}=(tp./(fp+tp))';
    ap(c) =VOCap(recall{c},precision{c});
end

fprintf('eval_detection :: computing ap took %0.1f seconds\n', ...
        toc(t));


function esvm_show_M(models, M)
% Show the M calibration matrix which, as the co-activation matrix, is
% a type of visual memex matrix.
%
% Copyright (C) 2011-12 by Tomasz Malisiewicz
% All rights reserved.
%
% This file is part of the Exemplar-SVM library and is made
% available under the terms of the MIT license (see COPYING file).
% Project homepage: https://github.com/quantombone/exemplarsvm

for i = 1:length(models)

  [aa,bb] = sort(M.w{i},'descend');

  figure(1)
  clf
  subplot(4,4,1)
  imagesc(esvm_get_exemplar_icon(models,i))
  axis image
  axis off
  title(sprintf('Source exemplar %d',i))

  for q = 1:15
    %if aa(q) <= 1
    %  break
    %end
    subplot(4,4,q+1)

    flipper = 0;
    if bb(q) > length(models)
      bb(q) = bb(q) - length(models);
      flipper = 1;
      I=flip_image(esvm_get_exemplar_icon(models,bb(q)));
    else
      I=esvm_get_exemplar_icon(models,bb(q));
    end
    imagesc(I)
    axis image
    axis off
    title(sprintf('%d F=%d %.2f',bb(q),flipper,aa(q)))
  end

  pause
end


% This file contains a list of metabolites required by the AGORA microbial
% reconstructions to grow.

AGORAessential ={'EX_12dgr180[u]'
'EX_26dap_M[u]'
'EX_2obut[u]'
'EX_3mop[u]'
'EX_4hbz[u]'
'EX_ac[u]'
'EX_acgam[u]'
'EX_acmana[u]'
'EX_ade[u]'
'EX_adn[u]'
'EX_adocbl[u]'
'EX_ala_D[u]'
'EX_ala_L[u]'
'EX_arab_D[u]'
'EX_arg_L[u]'
'EX_asn_L[u]'
'EX_btn[u]'
'EX_ca2[u]'
'EX_cbl1[u]'
'EX_cgly[u]'
'EX_chor[u]'
'EX_chsterol[u]'
'EX_cit[u]'
'EX_cl[u]'
'EX_cobalt2[u]'
'EX_csn[u]'
'EX_cu2[u]'
'EX_cys_L[u]'
'EX_dad_2[u]'
'EX_dcyt[u]'
'EX_ddca[u]'
'EX_dgsn[u]'
'EX_fe2[u]'
'EX_fe3[u]'
'EX_fol[u]'
'EX_for[u]'
'EX_gal[u]'
'EX_glc_D[u]'
'EX_glu_L[u]'
'EX_gly[u]'
'EX_glyc3p[u]'
'EX_glyc[u]'
'EX_gthox[u]'
'EX_gua[u]'
'EX_h2s[u]'
'EX_h[u]'
'EX_his_L[u]'
'EX_hxan[u]'
'EX_ile_L[u]'
'EX_k[u]'
'EX_lanost[u]'
'EX_leu_L[u]'
'EX_lys_L[u]'
'EX_met_L[u]'
'EX_mg2[u]'
'EX_mn2[u]'
'EX_mqn7[u]'
'EX_mqn8[u]'
'EX_nac[u]'
'EX_ncam[u]'
'EX_nmn[u]'
'EX_ocdca[u]'
'EX_ocdcea[u]'
'EX_orn[u]'
'EX_phe_L[u]'
'EX_pheme[u]'
'EX_pi[u]'
'EX_pnto_R[u]'
'EX_pro_L[u]'
'EX_ptrc[u]'
'EX_pydx[u]'
'EX_pydxn[u]'
'EX_q8[u]'
'EX_rib_D[u]'
'EX_ribflv[u]'
'EX_ser_L[u]'
'EX_sheme[u]'
'EX_so4[u]'
'EX_spmd[u]'
'EX_thm[u]'
'EX_thr_L[u]'
'EX_thymd[u]'
'EX_trp_L[u]'
'EX_ttdca[u]'
'EX_tyr_L[u]'
'EX_ura[u]'
'EX_val_L[u]'
'EX_xan[u]'
'EX_xyl_D[u]'
'EX_zn2[u]'
% new
'EX_arg_L[u]'
'EX_ca2[u]'
'EX_cgly[u]'
'EX_cl[u]'
'EX_cobalt2[u]'
'EX_cu2[u]'
'EX_fe2[u]'
'EX_fol[u]'
'EX_k[u]'
'EX_mg2[u]'
'EX_mn2[u]'
'EX_mqn7[u]'
'EX_ocdca[u]'
'EX_pheme[u]'
'EX_ribflv[u]'
'EX_so4[u]'
'EX_spmd[u]'
'EX_thm[u]'
'EX_trp_L[u]'
'EX_zn2[u]'
'EX_pnto_R[u]'
'EX_sheme[u]'
'EX_thymd[u]'
'EX_pydx[u]'
'EX_26dap_M[u]'
'EX_ala_L[u]'
'EX_fe3[u]'
'EX_pi[u]'
'EX_ttdca[u]'
'EX_mqn8[u]'
'EX_q8[u]'
'EX_2dmmq8[u]'
'EX_btn[u]'
'EX_nmn[u]'
'EX_asn_L[u]'
'EX_adpcbl[u]'
'EX_hxan[u]'
'EX_gthrd[u]'
'EX_4hbz[u]'
'EX_12dgr180[u]'
'EX_nac[u]'
'EX_gthox[u]'
'EX_ptrc[u]'
'EX_ura[u]'
'EX_ddca[u]'
'EX_lys_L[u]'
'EX_ala_D[u]'
'EX_arab_D[u]'
'EX_4abz[u]'
'EX_ile_L[u]'
'EX_met_L[u]'
'EX_ocdcea[u]'
'EX_tyr_L[u]'
'EX_val_L[u]'
'EX_his_L[u]'
'EX_leu_L[u]'
'EX_pro_L[u]'
'EX_cit[u]'
'EX_phe_L[u]'
'EX_thr_L[u]'
'EX_adn[u]'
'EX_3mop[u]'
'EX_cys_L[u]'
'EX_gal[u]'
'EX_ser_L[u]'
'EX_orn[u]'
'EX_h2s[u]'
'EX_xyl_D[u]'
'EX_2obut[u]'
'EX_lanost[u]'
'EX_rib_D[u]'
'EX_dcyt[u]'
'EX_glu_L[u]'
'EX_ac[u]'
'EX_ncam[u]'
'EX_cytd[u]'
'EX_amet[u]'
'EX_no2[u]'
'EX_cbl1[u]'
'EX_gly[u]'
'EX_gln_L[u]'
'EX_acgam[u]'
'EX_dad_2[u]'
'EX_ade[u]'
'EX_gua[u]'
'EX_for[u]'
'EX_h[u]'
'EX_pydxn[u]'
'EX_dgsn[u]'
'EX_malt[u]'
'EX_fald[u]'
'EX_amp[u]'
'EX_chor[u]'
'EX_glyc[u]'
'EX_glyc3p[u]'
'EX_h2o[u]'
'EX_chsterol[u]'
'EX_acmana[u]'
'EX_xan[u]'
'EX_gsn[u]'};

AGORAessential = unique(AGORAessential);


function deploy_each_dagnet(epoch, datapath)

for i = 1:epoch
    fileName = strcat('net-epoch-',num2str(i),'.mat');
    fileName = fullfile(datapath,fileName);
    [net, info] = loadState_deploy(fileName);
    net = net_deploy(net,1) ;
    deployname = strcat('net-deployed-',num2str(i),'.mat');
    save(fullfile(datapath, 'fine-tuned-model', deployname), 'net', 'info', '-v7.3');
end


function nfgWriteConTrackParams(ctrparamsFile, binDir, wmFile, roiFile, pdfFile, nMinNodes, nMaxNodes, fStepSizeMm, nSamples)
%Write the parameters file for ConTrack programs
%
%   nfgWriteConTrackParams(ctrparamsFile, binDir, wmFile, roiFile, pdfFile,
%   nMinNodes, nMaxNodes, fStepSizeMm, nSamples)
%
%   contrack_gen and contrack_score require this file to run.
%   ctrparamsFile : Filename to write.
%   binDir : Directory to find images.
%   wmFile : White matter mask relative to binDir.
%   roiFile : ROI mask relative to binDir.
%   pdfFile : PDF image relative to binDir.
%
% AUTHORS:
%   2009.08.05 : AJS wrote it
%
% NOTES:

if ieNotDefined('nSamples'); nSamples = 50000; end

ctr = ctrCreate();
ctr=ctrSet(ctr,'image_directory',binDir);
ctr=ctrSet(ctr,'fa_filename',wmFile);
ctr=ctrSet(ctr,'mask_filename',roiFile);
ctr=ctrSet(ctr,'pdf_filename',pdfFile);
ctr=ctrSet(ctr,'max_nodes', nMaxNodes);
ctr=ctrSet(ctr,'min_nodes', nMinNodes);
ctr=ctrSet(ctr,'step_size', fStepSizeMm);
ctr=ctrSet(ctr,'desired_samples', nSamples);
ctrSave(ctr,ctrparamsFile);

return;


function chanlist = ie_readchans(chanfile)
%IE_READCHANS Read and parse station/channel list from file
% CHANLIST = IE_READCHANS(CHANFILE) returns a string cell array of stations
% and their associated channels, read from comma-delimited input filename CHANFILE.
% Each line of CHANFILE should contain up to four fields: a station name in
% the first column, then either one or three channel names in the
% subsequent columns.  Lines beginning with the percent sign % are ignored.
%
% IE_READCHANS performs some basic error checking on the input file, but
% does not compare against any database or other listing of station data.
% This is left up to the user.
%
% EXAMPLE
%
% Suppose CHANFILE points to the following file:
%
% % Stations and channels of interest in Uturuncu data set
% UTCA,SHZ,SHN,SHE
% UTCM,SHZ,,
% %UTKH,BHZ,BHN,BHE
% %UTLA2,SHZ,SHN,SHE
% UTSW,SHZ,SHN,SHE
%
% Then IE_READCHANS will return:
%
% ans =
%     'UTCA'    'SHZ'    'SHN'    'SHE'
%     'UTCM'    'SHZ'       ''       ''
%     'UTSW'    'SHZ'    'SHN'    'SHE'
%
% Author: Christopher Bruton, Geophysical Institute, University of Alaska Fairbanks
% $Date$
% $Revision$

	[fp, message] = fopen(chanfile,'r'); % Open the file

	if fp < 0 % Could not open the file
		error(['Could not open file ' chanfile ': ' message]);
	end

	% The following seems to be the best way to read a CSV file of text.
	% csvread() can only handle numeric data.
	filecontents = textscan(fp,'%s %s %s %s','Delimiter',',','ReturnOnError',false,'CommentStyle','%');

	fclose(fp); % Close file handle

	% Concatenate into one cell array
	chanlist = cat(2,filecontents{:});

	% Run some mechanical checks

	for n = 1:size(chanlist,1)
		% Empty station?
		if isempty(chanlist{n,1})
			error(['Empty station on line ' num2str(n) ' of input file ' chanfile]);
		end

		% Number of empty channels
		n_empty = 0;
		for c = 2:4
			if isempty(chanlist{n,c})
				n_empty = n_empty + 1;
			end
		end

		% Error if we have wrong number of empty channel names
		if (n_empty ~= 2) && (n_empty ~= 0)
			error(['Incorrect number of channels specified on line ' num2str(n) ' of input file ' chanfile '.  Please specify either 1 or 3 channel names.']);
		end

		% All channels must have unique names
		if length(unique(chanlist(n,2:4))) ~= (3-(n_empty>0))
			error(['Nonunique channel names specified on line ' num2str(n) ' of input file ' chanfile]);
		end
	end

	% All stations must have unique names
	if length(unique(chanlist(:,1))) ~= length(chanlist(:,1))
		error(['Nonunique station names specified in input file ' chanfile]);
	end

end


function img=ssimReadImg(imgName,parms)
% Read an image, and converts it into appropriate
% channels depending on the parameters

img=imread(imgName);
if parms.nChannels==3
  if(size(img,3)==1)
    img(:,:,2)=img(:,:,1);img(:,:,3)=img(:,:,1);
  end;
elseif parms.nChannels==1
  if(size(img,3)==3)
    img=rgb2gray(img);
  end;
else
  error('Invalid number of image channels\n');
end

img=double(img);


function FindMother(j)
global uLINK

if j ~= 0
    if j == 1
        uLINK(j).mother = 0;
    end
    if uLINK(j).child ~= 0
        uLINK(uLINK(j).child).mother = j;
        FindMother(uLINK(j).child);
    end
    if uLINK(j).sister ~= 0
        uLINK(uLINK(j).sister).mother = uLINK(j).mother;
        FindMother(uLINK(j).sister);
    end
end


function [endpointsAll,bboxAll] = backprojectSpatialImg(expidx,firstidx,nImgs,bSave)

fprintf('backprojectSpatialImg()\n');

if (ischar(expidx))
    expidx = str2double(expidx);
end

if (ischar(firstidx))
    firstidx = str2double(firstidx);
end

if (ischar(nImgs))
    nImgs = str2double(nImgs);
end

if (nargin < 4)
    bSave = true;
elseif (ischar(bSave))
    bSave = str2double(bSave);
end

% load annolist with full size images
[annolistOrig, imgidxs] = getAnnolist(expidx);
for imgidx = 1:length(annolistOrig)
    annolistOrig(imgidx).annorect = [];
end

lastidx = firstidx + nImgs - 1;
if (lastidx > length(imgidxs))
    lastidx = length(imgidxs);
end

p = rcnn_exp_params(expidx);

if (isfield(p,'nms_thresh_det'))
    nms_thresh_det = p.nms_thresh_det;
else
    nms_thresh_det = 0.5;
end

fprintf('expidx: %d\n',expidx);
fprintf('firstidx: %d\n',firstidx);
fprintf('nImgs: %d\n',nImgs);
fprintf('nms_thresh: %1.1f\n',nms_thresh_det);

load(p.testGT);
if (~exist('annolist','var'))
    annolist = single_person_annolist;
end
annolist_crops = annolist;

[~,parts] = util_get_parts24();

saveTo = [fileparts(p.evalTest) '/pred_pairwise_backproj'];
if (~exist(saveTo,'dir'))
    mkdir(saveTo);
end

conf = rcnn_config('sub_dir', '/cachedir/test', 'exp_dir', [p.expDir '/' p.shortName]);
predPairwiseDir = [conf.cache_dir '/pred-pairwise'];

for imgidx = firstidx:lastidx
    endpointsAll(imgidx).imgname = annolistOrig(imgidxs(imgidx)).image.name;
    endpointsAll(imgidx).det = cell(length(p.spatidxs)+1,1);
end

sticksMap = [0 2; 2 4; 7 5; 9 7; nan nan; 22 23; 12 14; 14 16; 19 17; 21 19; 16 22; 17 22; 4 22; 5 22];

bVis = true;

ii = 1;
for i = firstidx:lastidx
    fprintf('.');

    [~,name] = fileparts(annolist_crops(ii).image.name);
    imgidx_crop = str2double(name(3:7));
    while (imgidx_crop ~= imgidxs(i))
        ii = ii + 1;
        [~,name] = fileparts(annolist_crops(ii).image.name);
        imgidx_crop = str2double(name(3:7));
    end

    % load bboxes
    while (imgidx_crop == imgidxs(i))

        fname = [predPairwiseDir '/imgidx_' padZeros(num2str(ii-1),5) '_nms'];
        load(fname,'det_nms_union_07_all','idxs_nms_union_07_all');
        det_spatial = det_nms_union_07_all;
        idxs_spatial = idxs_nms_union_07_all;

%         load(fname,'det_nms_inters_03_all','idxs_nms_inters_03_all');
%         det_spatial = det_nms_inters_03_all;
%         idxs_spatial = idxs_nms_inters_03_all;

%         load(fname,'det_nms_inters_05_all','idxs_nms_inters_05_all');
%         det_spatial = det_nms_inters_05_all;
%         idxs_spatial = idxs_nms_inters_05_all;

        % transformation matrix
        load([fileparts(p.testGT) '/T_' name(3:end)],'T');
        for j = 1:length(p.spatidxs)

            spatidxs = p.spatidxs{j};

            % backproject det
            det = det_spatial{j}(:,1:5);
            detNew1 = ([det(:,1:2) ones(size(det,1),1)]*T');
            detNew2 = ([det(:,3:4) ones(size(det,1),1)]*T');
            det(:,1:4) = [detNew1(:,1:2) detNew2(:,1:2)];

            idxStick = find(sum(abs(repmat(spatidxs,length(sticksMap),1)-sticksMap),2) == 0 | ...
                        sum(abs(repmat(spatidxs([2 1]),length(sticksMap),1)-sticksMap),2)==0);

            pidx1 = sticksMap(idxStick,1);
            pidx2 = sticksMap(idxStick,2);

            class_ids(1) = find(pidx1 == p.pidxs);
            class_ids(2) = find(pidx2 == p.pidxs);

            idx1 = find(idxs_spatial{j}(1,1:2) == class_ids(1));
            idx2 = find(idxs_spatial{j}(1,1:2) == class_ids(2));
            if (idx1 == 2 && idx2 == 1)
                det(:,1:4) = det(:,[3:4 1:2]);
            end

            % add to detections
            endpointsAll(i).det{idxStick} = [endpointsAll(i).det{idxStick}; det];
        end
%         x2y2 = (endpointsAll(i).det{11}(:,1:2) + endpointsAll(i).det{12}(:,1:2))/2;
%         x1y1 = (endpointsAll(i).det{13}(:,1:2) + endpointsAll(i).det{14}(:,1:2))/2;
%         endpointsAll(i).det{5} = [x1y1 x2y2 endpointsAll(i).det{11}(:,5)];
        ii = ii + 1;
        if (ii > length(annolist_crops))
            break;
        end
        [~,name] = fileparts(annolist_crops(ii).image.name);
        imgidx_crop = str2double(name(3:7));
    end

    if (bVis)
        clf; imagesc(imread(endpointsAll(i).imgname));axis equal;hold on;
        for j = 1:length(endpointsAll(i).det)
            det = endpointsAll(i).det{j};
            if (~isempty(det))
                [val,idx] = sort(det(:,end),'descend');
                plot(det(idx(1),[1 3]),det(idx(1),[2 4]),'r-','lineWidth',3);
%                 text(double(det(idx(1),1)) + 30,double(det(idx(1),2)),sprintf('%1.1f',det(idx(1),end)),'BackgroundColor','w','verticalalignment','top','horizontalalignment','left','fontSize',14);

                plot(det(idx(1),1),det(idx(1),2),'bo','MarkerSize',10,'MarkerFaceColor','b','MarkerEdgeColor','k');
                plot(det(idx(1),3),det(idx(1),4),'go','MarkerSize',10,'MarkerFaceColor','g','MarkerEdgeColor','k');
            end
        end
    end

    if (bSave)
        fname = [saveTo '/keypoints_' padZeros(num2str(imgidxs(i)),5)];
        keypoints = endpointsAll(i);
        save(fname,'keypoints');

        fname = [saveTo '/bboxes_' padZeros(num2str(imgidxs(i)),5)];
        bboxes = bboxAll(i);
        save(fname,'bboxes');
    end

    if (~mod(i, 100))
        fprintf(' %d/%d\n',i,length(imgidxs));
    end
end

fprintf(' done\n');

if (~exist('endpointsAll','var'))
    endpointsAll = [];
    bboxAll = [];
end
% path = fileparts(p.evalTest);
% fnameKeypoints = [path '/keypointsAll'];
% save(fnameKeypoints, 'keypointsAll');
%
% fnameBBox = [path '/bboxAll'];
% save(fnameBBox, 'bboxAll');
end


classdef ProbeClass < FileLoadSaveClass

    properties
        wavelengths
        wavelengthsEmission
        sourcePos2D
        detectorPos2D
        landmarkPos2D
        landmarkPos3D
        sourcePos3D
        detectorPos3D
        frequencies
        timeDelays
        timeDelayWidths
        momentOrders
        correlationTimeDelays
        correlationTimeDelayWidths
        sourceLabels
        detectorLabels
        landmarkLabels
    end

    properties (Access = private)
        scaling
    end

    methods

        % -------------------------------------------------------
        function obj = ProbeClass(varargin)
            % Set class properties not part of the SNIRF format
            obj.SetFileFormat('hdf5');
            obj.scaling = 1;

            % Set SNIRF fomat properties
            if nargin>0
                if isstruct(varargin{1})
                    n = NirsClass(varargin{1});
                    SD = n.SD;
                    obj.wavelengths = SD.Lambda;
                    obj.wavelengthsEmission  = [];
                    if isfield(SD,'SrcPos2D') &&  ~isempty(SD.SrcPos2D)
                        obj.sourcePos2D  = SD.SrcPos2D;
                    else
                        obj.sourcePos2D  = SD.SrcPos;
                    end
                    if isfield(SD,'DetPos2D') && ~isempty(SD.DetPos2D)
                        obj.detectorPos2D  = SD.DetPos2D;
                    else
                        obj.detectorPos2D  = SD.DetPos;
                    end
                    if isfield(SD,'SrcPos3D') && ~isempty(SD.SrcPos3D)
                        obj.sourcePos3D  = SD.SrcPos3D;
                    else
                        obj.sourcePos3D  = SD.SrcPos;
                    end
                    if isfield(SD,'DetPos3D') && ~isempty(SD.DetPos3D)
                        obj.detectorPos3D  = SD.DetPos3D;
                    else
                        obj.detectorPos3D  = SD.DetPos;
                    end
                    if isfield(SD,'Landmarks3D')
                        obj.landmarkPos3D = SD.Landmarks3D.pos;
                        obj.landmarkLabels = SD.Landmarks3D.labels;
                        if isfield(SD,'Landmarks2D')
                            obj.landmarkPos2D = SD.Landmarks2D.pos;
                        end
                    else
                        obj.landmarkPos3D = SD.DummyPos;
                        obj.landmarkLabels = SD.Landmarks3D.labels;
                    end
                    obj.frequencies  = 1;
                    obj.timeDelays  = 0;
                    obj.timeDelayWidths  = 0;
                    obj.momentOrders = [];
                    obj.correlationTimeDelays = 0;
                    obj.correlationTimeDelayWidths = 0;
                    for ii=1:size(SD.SrcPos)
                        obj.sourceLabels{ii} = ['S',num2str(ii)];
                    end
                    for ii=1:size(SD.DetPos)
                        obj.detectorLabels{ii} = ['D',num2str(ii)];
                    end
                elseif ischar(varargin{1})
                    obj.SetFilename(varargin{1});
                    obj.Load(varargin{1});
                end
            else
                obj.wavelengths          = [];
                obj.wavelengthsEmission  = [];
                obj.sourcePos2D  = [];
                obj.detectorPos2D  = [];
                obj.sourcePos3D  = [];
                obj.detectorPos3D  = [];
                obj.frequencies  = 1;
                obj.timeDelays  = 0;
                obj.timeDelayWidths  = 0;
                obj.momentOrders = [];
                obj.correlationTimeDelays = 0;
                obj.correlationTimeDelayWidths = 0;
                obj.sourceLabels = {};
                obj.detectorLabels = {};
            end
        end

        % -------------------------------------------------------
        function ForwardCompatibility(obj)
            if size(obj.sourcePos2D,2)<3
                obj.sourcePos2D       = [obj.sourcePos2D, zeros(size(obj.sourcePos2D,1), 1)];
            end
            if size(obj.detectorPos2D,2)<3
                obj.detectorPos2D     = [obj.detectorPos2D, zeros(size(obj.detectorPos2D,1), 1)];
            end
        end

        % -------------------------------------------------------
        function BackwardCompatibility(obj)
            if isempty(obj.sourcePos2D)
                obj.sourcePos2D   = HDF5_DatasetLoad(gid, 'sourcePos', [], '2D');
            end
            if isempty(obj.detectorPos2D)
                obj.detectorPos2D = HDF5_DatasetLoad(gid, 'detectorPos', [], '2D');
            end
            if isempty(obj.landmarkPos2D)
                obj.landmarkPos2D = HDF5_DatasetLoad(gid, 'landmarkPos', [], '2D');
            end
        end

        % ----------------------------------------------
        function isValid = isValidLandmarkLabels(obj)
            isValid = 1;
            refpts_labels = {'T7','T8','Oz','Fpz','Cz','C3','C4','Pz','Fz'};
            for u = 1:length(refpts_labels)
                label = refpts_labels{u};
                idx = ismember(obj.landmarkLabels, label);
                if sum(idx) == 0
                    isValid = 0;
                    return
                end
            end
        end

        % -------------------------------------------------------
        function Project_3D_to_2D(obj)
            if isempty(obj.sourcePos2D) && isempty(obj.detectorPos2D)
                if isempty(obj.landmarkPos3D) || ~obj.isValidLandmarkLabels()
                    nSource = size(obj.sourcePos3D,1);
                    optodePos3D = [obj.sourcePos3D; obj.detectorPos3D];

                    optodePos2D = project_3D_to_2D(optodePos3D);
                    if ~isempty(optodePos2D)
                        if nSource ~= 0
                            obj.sourcePos2D = optodePos2D(1:nSource,:);
                        end
                        if size(optodePos3D,1) > nSource
                            obj.detectorPos2D = optodePos2D(nSource+1:end,:);
                        end
                    end
                else
                     if ~isempty(obj.sourcePos3D) && ~isempty(obj.detectorPos3D)
                        [sphere.label, sphere.theta, sphere.phi, sphere.r, sphere.xc, sphere.yc, sphere.zc] = textread('10-5-System_Mastoids_EGI129.csd','%s %f %f %f %f %f %f','commentstyle','c++');
                        % ref pt labels used for affine transformation
                        refpts_labels = {'T7','T8','Oz','Fpz','Cz','C3','C4','Pz','Fz'};

                        % get positions for refpts_labels from both sphere and probe ref pts
                        for u = 1:length(refpts_labels)
                            label = refpts_labels{u};

                            idx = ismember(obj.landmarkLabels, label);
                            if isempty(idx)
                                return
                            end
                            probe_refps_pos(u,:) = obj.landmarkPos3D(idx,:);
                            idx = ismember(sphere.label, label);
                            sphere_refpts_pos(u,:) = [sphere.xc(idx) sphere.yc(idx) sphere.zc(idx)];
                        end

                        % get affine transformation
                        % probe_refps*T = sphere_refpts
                        probe_refps_pos = [probe_refps_pos(:,1:3) ones(size(probe_refps_pos,1),1)];
                        T = probe_refps_pos\sphere_refpts_pos;

                        % tranform optode positions onto unit sphere.
                        % opt_pos = probe.optpos_reg;
                        % opt_pos = [opt_pos ones(size(opt_pos,1),1)];
                        % sphere_opt_pos = opt_pos*T;
                        % sphere_opt_pos_norm = sqrt(sum(sphere_opt_pos.^2,2));
                        % sphere_opt_pos = sphere_opt_pos./sphere_opt_pos_norm ;
                        %
                        % get 2D circular refpts for current selecetd reference point system
                        probe_refpts_idx =  ismember(sphere.label, obj.landmarkLabels);

                        % refpts_2D.pos = [sphere_xc(probe_refpts_idx) sphere_yc(probe_refpts_idx) sphere_zc(probe_refpts_idx)];
                        refpts_2D.label = sphere.label(probe_refpts_idx);
                        %
                        refpts_theta =  sphere.theta(probe_refpts_idx);
                        refpts_phi = 90 - sphere.phi(probe_refpts_idx); % elevation angle from top axis

                        refpts_theta = (2 * pi * refpts_theta) / 360; % convert to radians
                        refpts_phi = (2 * pi * refpts_phi) / 360;
                        [x,y] = pol2cart(refpts_theta, refpts_phi);      % get plane coordinates
                        xy = [x y];

                        %
                        norm_factor = max(max(xy));
                        xy = xy/norm_factor;               % set maximum to unit length
                        refpts_2D.pos = xy;
                        obj.landmarkPos2D = refpts_2D.pos;

                        %
                        obj.sourcePos2D = convert_optodepos_to_circlular_2D_pos(obj.sourcePos3D, T, norm_factor);
                        obj.detectorPos2D = convert_optodepos_to_circlular_2D_pos(obj.detectorPos3D, T, norm_factor);
                    end
                end
            end
        end

        % -------------------------------------------------------
        function err = LoadHdf5(obj, fileobj, location, LengthUnit)
            err = 0;

            % Arg 1
            if ~exist('fileobj','var') || (ischar(fileobj) && ~exist(fileobj,'file'))
                fileobj = '';
            end

            % Arg 2
            if ~exist('location', 'var') || isempty(location)
                location = '/nirs/probe';
            elseif location(1)~='/'
                location = ['/',location];
            end

            % Arg3
            if exist('LengthUnit','var')
                % Figure out the scaling factor to multiple by to get the coorinates to be in mm units
                if strcmpi(LengthUnit,'m')  % meter units
                    obj.scaling = 1000;
                elseif strcmpi(LengthUnit,'cm')  % centimeter units
                    obj.scaling = 10;
                end
            end

            % Error checking
            if ~isempty(fileobj) && ischar(fileobj)
                obj.SetFilename(fileobj);
            elseif isempty(fileobj)
                fileobj = obj.GetFilename();
            end
            if isempty(fileobj)
               err = -1;
               return;
            end

            try
                % Open group
                [gid, fid] = HDF5_GroupOpen(fileobj, location);

                % Load datasets
                obj.wavelengths               = HDF5_DatasetLoad(gid, 'wavelengths');
                obj.wavelengthsEmission       = HDF5_DatasetLoad(gid, 'wavelengthsEmission');
                obj.sourcePos2D               = HDF5_DatasetLoad(gid, 'sourcePos2D', [], '2D') * obj.scaling;
                obj.detectorPos2D             = HDF5_DatasetLoad(gid, 'detectorPos2D', [], '2D') * obj.scaling;
                obj.landmarkPos2D             = HDF5_DatasetLoad(gid, 'landmarkPos2D', [], '2D') * obj.scaling;
                obj.sourcePos3D               = HDF5_DatasetLoad(gid, 'sourcePos3D', [], '3D') * obj.scaling;
                obj.detectorPos3D             = HDF5_DatasetLoad(gid, 'detectorPos3D', [], '3D') * obj.scaling;
                obj.landmarkPos3D             = HDF5_DatasetLoad(gid, 'landmarkPos3D', [], '2D') * obj.scaling;
                obj.frequencies               = HDF5_DatasetLoad(gid, 'frequencies');
                obj.timeDelays                 = HDF5_DatasetLoad(gid, 'timeDelays');
                obj.timeDelayWidths            = HDF5_DatasetLoad(gid, 'timeDelayWidths');
                obj.momentOrders               = HDF5_DatasetLoad(gid, 'momentOrders');
                obj.correlationTimeDelays      = HDF5_DatasetLoad(gid, 'correlationTimeDelays');
                obj.correlationTimeDelayWidths = HDF5_DatasetLoad(gid, 'correlationTimeDelayWidths');
                obj.sourceLabels              = HDF5_DatasetLoad(gid, 'sourceLabels', obj.sourceLabels);
                obj.detectorLabels            = HDF5_DatasetLoad(gid, 'detectorLabels', obj.detectorLabels);
                obj.landmarkLabels            = HDF5_DatasetLoad(gid, 'landmarkLabels', obj.landmarkLabels);

                obj.Project_3D_to_2D();

                % Close group
                HDF5_GroupClose(fileobj, gid, fid);

                assert(obj.IsValid())

            catch
                err = -1;
                return;
            end

            % Call method to change future current and future versions of
            % SNIRF data to Homer3 compatible structure
            obj.ForwardCompatibility();

            % for Homer3 usage, add 3D positions if they are empty
            if isempty(obj.sourcePos3D)
                obj.sourcePos3D = obj.sourcePos2D;
                if size(obj.sourcePos3D,2)<3
                    obj.sourcePos3D(:,3) = 0;
                end
            end

            if isempty(obj.detectorPos3D)
                obj.detectorPos3D = obj.detectorPos2D;
                if size(obj.detectorPos3D,2)<3
                    obj.detectorPos3D(:,3) = 0;
                end
            end
            obj.SetError(err);
        end

        % -------------------------------------------------------
        function SaveHdf5(obj, fileobj, location)
            % Arg 1
            if ~exist('fileobj', 'var') || isempty(fileobj)
                error('Unable to save file. No file name given.')
            end

            % Arg 2
            if ~exist('location', 'var') || isempty(location)
                location = '/nirs/probe';
            elseif location(1)~='/'
                location = ['/',location];
            end

            if ~exist(fileobj, 'file')
                fid = H5F.create(fileobj, 'H5F_ACC_TRUNC', 'H5P_DEFAULT', 'H5P_DEFAULT');
                H5F.close(fid);
            end

            % Multiple all coordinates by reciprocal of scaling factor when saving to get the
            % coordinates back to original.
            obj.sourcePos2D    = obj.sourcePos2D / obj.scaling;
            obj.detectorPos2D  = obj.detectorPos2D / obj.scaling;
            obj.landmarkPos2D  = obj.landmarkPos2D / obj.scaling;
            obj.sourcePos3D    = obj.sourcePos3D / obj.scaling;
            obj.detectorPos3D  = obj.detectorPos3D / obj.scaling;
            obj.landmarkPos3D  = obj.landmarkPos3D / obj.scaling;

            % Now save
            hdf5write_safe(fileobj, [location, '/wavelengths'], obj.wavelengths, 'array');
            hdf5write_safe(fileobj, [location, '/wavelengthsEmission'], obj.wavelengthsEmission, 'array');
            hdf5write_safe(fileobj, [location, '/sourcePos2D'], obj.sourcePos2D, 'array');
            hdf5write_safe(fileobj, [location, '/detectorPos2D'], obj.detectorPos2D, 'array');
            hdf5write_safe(fileobj, [location, '/landmarkPos2D'], obj.landmarkPos2D, 'array');
            hdf5write_safe(fileobj, [location, '/sourcePos3D'], obj.sourcePos3D, 'array');
            hdf5write_safe(fileobj, [location, '/detectorPos3D'], obj.detectorPos3D, 'array');
            hdf5write_safe(fileobj, [location, '/landmarkPos3D'], obj.landmarkPos3D, 'array');
            hdf5write_safe(fileobj, [location, '/frequencies'], obj.frequencies, 'array');
            hdf5write_safe(fileobj, [location, '/timeDelays'], obj.timeDelays, 'array');
            hdf5write_safe(fileobj, [location, '/timeDelayWidths'], obj.timeDelayWidths, 'array');
            hdf5write_safe(fileobj, [location, '/momentOrders'], obj.momentOrders, 'array');
            hdf5write_safe(fileobj, [location, '/correlationTimeDelays'], obj.correlationTimeDelays, 'array');
            hdf5write_safe(fileobj, [location, '/correlationTimeDelayWidths'], obj.correlationTimeDelayWidths, 'array');
            hdf5write_safe(fileobj, [location, '/sourceLabels'], obj.sourceLabels, 'array');
            hdf5write_safe(fileobj, [location, '/detectorLabels'], obj.detectorLabels, 'array');
            hdf5write_safe(fileobj, [location, '/landmarkLabels'], obj.landmarkLabels, 'array');
        end

        % ---------------------------------------------------------
        function wls = GetWls(obj)
            wls = obj.wavelengths;
        end

        % ---------------------------------------------------------
        function srcpos = GetSrcPos(obj,flag2d)
            if ~exist('flag2d','var')
                flag2d = 0;
            end
            if flag2d==0
                srcpos = obj.sourcePos3D;
            else
                srcpos = obj.sourcePos2D;
            end
        end

        % ---------------------------------------------------------
        function detpos = GetDetPos(obj,flag2d)
            if ~exist('flag2d','var')
                flag2d = 0;
            end
            if flag2d==0
                detpos = obj.detectorPos3D;
            else
                detpos = obj.detectorPos2D;
            end
        end

        % -------------------------------------------------------
        function B = eq(obj, obj2)
            B = false;
            if isempty(obj) && ~isempty(obj2)
                return;
            end
            if isempty(obj) && ~isempty(obj2)
                return;
            end
            if ~isempty(obj) && isempty(obj2)
                return;
            end
            if isempty(obj) && isempty(obj2)
                b = true;
                return;
            end
            if ~all(obj.wavelengths(:)==obj2.wavelengths(:))
                return;
            end
            if ~all(obj.wavelengthsEmission(:)==obj2.wavelengthsEmission(:))
                return;
            end
            if ~all(obj.sourcePos2D(:)==obj2.sourcePos2D(:))
                return;
            end
            if ~all(obj.detectorPos2D(:)==obj2.detectorPos2D(:))
                return;
            end
            if ~all(obj.sourcePos3D(:)==obj2.sourcePos3D(:))
                return;
            end
            if ~all(obj.detectorPos3D(:)==obj2.detectorPos3D(:))
                return;
            end
            if ~all(obj.frequencies(:)==obj2.frequencies(:))
                return;
            end
            if ~all(obj.timeDelays(:)==obj2.timeDelays(:))
                return;
            end
            if ~all(obj.timeDelayWidths(:)==obj2.timeDelayWidths(:))
                return;
            end
            if ~all(obj.momentOrders(:)==obj2.momentOrders(:))
                return;
            end
            if ~all(obj.correlationTimeDelays(:)==obj2.correlationTimeDelays(:))
                return;
            end
            if ~all(obj.correlationTimeDelayWidths(:)==obj2.correlationTimeDelayWidths(:))
                return;
            end
            if length(obj.sourceLabels)~=length(obj2.sourceLabels)
                return;
            end
            for ii=1:length(obj.sourceLabels)
                if ~strcmp(obj.sourceLabels{ii}, obj2.sourceLabels{ii})
                    return;
                end
            end
            if length(obj.detectorLabels)~=length(obj2.detectorLabels)
                return;
            end
            for ii=1:length(obj.detectorLabels)
                if ~strcmp(obj.detectorLabels{ii}, obj2.detectorLabels{ii})
                    return;
                end
            end
            B = true;
        end

        % ----------------------------------------------------------------------------------
        function nbytes = MemoryRequired(obj)
            nbytes = 0;
            fields = properties(obj);
            for ii=1:length(fields)
                nbytes = nbytes + eval(sprintf('sizeof(obj.%s)', fields{ii}));
            end
        end

        % ----------------------------------------------------------------------------------
        function b = IsEmpty(obj)
            b = true;
            if isempty(obj.wavelengths)
                return;
            end
            if isempty(obj.sourcePos2D) && isempty(obj.detectorPos2D) && ...
                    isempty(obj.sourcePos3D) && isempty(obj.detectorPos3D)
                return;
            end
            b = false;
        end

        % ----------------------------------------------------------------------------------
        function b = IsValid(obj)
            b = false;
            if obj.IsEmpty()
                return;
            end
            if iscolumn(obj.sourcePos2D)
                return;
            end
            if length(obj.sourcePos2D)>4
                if size(obj.sourcePos2D,2) > size(obj.sourcePos2D,1)
                    return;
                end
            end
            if iscolumn(obj.detectorPos2D)
                return;
            end
            if length(obj.detectorPos2D)>4
                if size(obj.detectorPos2D,2) > size(obj.detectorPos2D,1)
                    return;
                end
            end
            b = true;
        end

        % ---------------------------------------------------------
        function bbox = GetSdgBbox(obj)
            bbox = [];

            optpos = [obj.GetSrcPos('2D'); obj.GetDetPos('2D')];
            if isempty(optpos)
                return
            end

            xmax = max(optpos(:,1));
            ymax = max(optpos(:,2));

            xmin = min(optpos(:,1));
            ymin = min(optpos(:,2));

            width = xmax-xmin;
            height = ymax-ymin;

            if width==0
                width = 1;
            end
            if height==0
                height = 1;
            end

            px = width * 0.05;
            py = height * 0.05;

            bbox = [xmin-px, xmax+px, ymin-py, ymax+py];
        end

        % ---------------------------------------------------------
        function val = GetScaleFactor(obj)
            val = obj.scaling;
        end

    end

end


function s = ismatch(x, y)

% ISMATCH returns true if x is a member of array y, regardless of the class
% of x and y, if y is a string, or a cell-array of strings, it can contain
% the wildcard '*'

if isempty(x) || isempty(y)
  s = false;
elseif ischar(x) && ischar(y)
  y = sprintf('%s%s%s', '^', regexptranslate('wildcard',y), '$');
  s = ~isempty(regexp(x, y, 'once'));
elseif isnumeric(x) && isnumeric(y)
  s = ismember(x, y);
elseif ischar(x) && iscell(y)
  y = y(strcmp(class(x), cellfun(@class, y, 'UniformOutput', false)));
  s = ismember(x, y);

  % one or more of the elements in y can contain a wildcard, only proceed if
  % s=false
  if ~s && any(contains(y, '*'))
    y = y(contains(y, '*'));
    for i = 1:numel(y)
      tmpy = sprintf('%s%s%s', '^', regexptranslate('wildcard',y{i}), '$');
      s = ~isempty(regexp(x, tmpy, 'once'));
      if s, return; end
    end
  end
elseif isnumeric(x) && iscell(y) && all(cellfun(@isnumeric, y))
  s = false;
  for i=1:numel(y)
    s = s || ismember(x, y{i});
  end
else
  s = false;
end


function move_obj(arg)
% callback function for draggable objects
% Any object can be made draggable via
%   set(obj, 'ButtonDownFcn', 'move_obj(1)');

% using deltas allows us to drag big objects
persistent last_pos;
persistent windowbuttonmotionfcn;
persistent windowbuttonupfcn;

% handle events
switch arg
  case 2    % button motion
    pos = get(gca, 'CurrentPoint');
    pos = pos(1,:);

    switch get(gco, 'type')
      case 'text', obj_pos = get(gco, 'Pos')';
      case 'line',
	obj_pos(1,:) = get(gco,'xdata');
	obj_pos(2,:) = get(gco,'ydata');
      otherwise error(['cannot handle type ' get(gco,'type')])
    end
    % if the scale is logarithmic then the delta is a ratio
    if strcmp(get(gca,'xscale'), 'log')
      new_pos(1,:) = obj_pos(1,:) * (pos(1)/last_pos(1));
    else
      new_pos(1,:) = obj_pos(1,:) + (pos(1)-last_pos(1));
    end
    if strcmp(get(gca,'yscale'), 'log')
      new_pos(2,:) = obj_pos(2,:) * (pos(2)/last_pos(2));
    else
      new_pos(2,:) = obj_pos(2,:) + (pos(2)-last_pos(2));
    end
    switch get(gco, 'type')
      case 'text', set(gco, 'Pos', new_pos);
      case 'line',
	set(gco, 'xdata', new_pos(1,:), ...
	         'ydata', new_pos(2,:));
    end
    last_pos = pos;
  case 1    % buttondown
    % start moving
    % dragging looks better with double buffering on
    set(gcf, 'DoubleBuffer', 'on');
    last_pos = get(gca,'CurrentPoint');
    last_pos = last_pos(1,:);
    % set callbacks
    fig = gcf;
    %set(fig, 'pointer', 'fleur');
    windowbuttonmotionfcn = get(fig,'windowbuttonmotionfcn');
    windowbuttonupfcn = get(fig,'windowbuttonupfcn');
    set(fig, 'windowbuttonmotionfcn', ['move_obj(2);' windowbuttonmotionfcn]);
    set(fig, 'windowbuttonupfcn', ['move_obj(3);' windowbuttonupfcn]);
  case 3    % button up
    % finished moving
    % clear callbacks
    fig = gcf;
    %set(fig, 'pointer', 'arrow');
    set(fig, 'windowbuttonmotionfcn', windowbuttonmotionfcn);
    set(fig, 'windowbuttonupfcn', windowbuttonupfcn);
  otherwise
    error('invalid argument')
end


function fnames = findfiles(extension,directory,recurse)
% Finds all files with the specified extension in the current directory and
% subdirectories (recursive). Returns a cell array with the fully specified
% file names.
%
%    files = findfiles( ext )
%       searches in the current directory and subdirectories.
%
%    files = findfiles( ext, directory)
%       starts search in directory specified.
%
%    files = findfiles( ext, directory, searchSubdirectories )
%       If searchSubdirectories == 0, the function will not descend
%       subdirectories. The default is that searchSubdirectories ~= 0.
%
% Note: if this function causes your recursion limit to be exceeded, then
% it is most probably trying to follow a symbolic link to a directory that
% has a symbolic link back to the directory it came from.
%
% Examples:
%
%    bmpfiles = findfiles('bmp')
%    dllfiles = findfiles('dll','C:\WinNT')
%    mfiles = findfiles('m',matlabroot)

% Copyright (C) 2001 Quester Tangent Corporation
% Author: Tony Christney, tchristney@questertangent.com
% $Id: findfiles.m 1.5 2001/05/25 01:54:17 tchristney Exp $

% $Log: findfiles.m $
% Revision 1.5  2001/05/25 01:54:17  tchristney
% Fixed bug where numMatches was not updated after recursive call, causing
% potential overwrites in the fnames cell array.
%
% Revision 1.4  2001/05/24 20:46:09  tchristney
% Recursion on/off support courtesy Brett Shoelson.
% <Brett.Shoelson@joslin.harvard.edu>
%
% Revision 1.2  2001/03/16 21:28:37  tchristney
% added some comments for external release, i.e. examples.
%
% Revision 1.1  2001/03/07 22:38:52  tchristney
% Initial revision
%

if nargin == 1
    directory = cd;
    recurse = (1==1);
elseif nargin == 2
    oldDir = cd;
    cd(directory);
    directory = cd;
    cd(oldDir);
    recurse = (1==1);
elseif nargin >= 3
    oldDir = cd;
    cd(directory);
    directory = cd;
    cd(oldDir);
end

d = dir(directory);

fnames = {};
numMatches = 0;
for i=1:length(d)
    % look for occurences of ['.' extension] in the file name
    extIndices = findstr(['.' extension],d(i).name);

    % if the file is not a directory, and the file has at least one occurence
    if ~d(i).isdir & ~isempty(extIndices)

        % then if the last occurrence is at the end of the file name,
        % add the file name to the list.
        if length(d(i).name) == (extIndices(length(extIndices)) + length(extension))
            numMatches = numMatches + 1;
            fnames{numMatches} = fullfile(directory,d(i).name);
        end
    % otherwise, descend directories appropriately.
    % note that this could result in a recursion limit error if it tries to
    % follow symbolic links that loop back on themselves...
    elseif recurse & d(i).isdir & ~strcmp(d(i).name,'.') & ~strcmp(d(i).name,'..')
        fnames = [fnames findfiles(extension,fullfile(directory,d(i).name),recurse)];
        numMatches = length(fnames);
    end
end


%dump_pdfbimagemodel.m
%written by: Duncan Po
%Date: Sept 27, 2002
%Saves a pdfb model into a file in a readable format
%Usage: dump_pdfbimagemodel(model, filename)
%       model - model of image to be saved
%       filename - name of the file (including full path) to save model in

function dump_pdfbimagemodel(model, filename)

nl = model{1}.nlevels;

for m = 1:nl
    levndir(m) = length(model{1}.stdv{m});
end;

for i = 1:length(model)
    dump_pdfbmodel_to_file(model{i}, filename, levndir, nl);
end;


function varargout=choosenk(varargin)
%
% For calling details please see v_choosenk.m
%
% This dummy routine is included for backward compatibility only
% and will be removed in a future release of voicebox. Please use
% v_choosenk.m in future and/or update with v_voicebox_update.m
%
%      Copyright (C) Mike Brookes 2018
%      Version: $Id: choosenk.m 10863 2018-09-21 15:39:23Z dmb $
%
if nargout
    varargout=cell(1,nargout);
    [varargout{:}]=v_choosenk(varargin{:});
else
    v_choosenk(varargin{:});
end


function makescript(d, filename)

%tstoolbox/@description/makescript
%   Syntax:
%     * makescript (signal, scriptfilename)
%
%   creates a Matlab m-file that contains exactly the the processing steps
%   that have been applied to get the input signal. This gives a kind of
%   macro facility for tstool.
%   Example
%          signal s was calculated through several processing steps from
%          signal s0 (the raw or original signal) Now makescript(s,
%          'foo.m') will create a Matlab m-file named foo.m which, applied
%          to s0, will give s.
%
% Copyright 1997-2001 DPI Goettingen, License http://www.physik3.gwdg.de/tstool/gpl.txt

narginchk(1,2);

[path,name,ext] = fileparts(filename);

n = findstr(name, '.m');
if isempty(n)
	funname = name;
else
	funname = name(1:n-1);
end

if length(d.commandlines)==0
   error('Signal has no commands that can be used to create a script');
end

[fid, message] = fopen(filename, 'wt');	% open as text file

if fid == -1
	error(message)
end

line = ['function s = ' funname '(s)\n'];
fprintf(fid, line);

for i=1:length(d.commandlines)
   line = [get(d.commandlines, i) '\n'];
   fprintf(fid, line);
end

fclose(fid);


function test_bug1527

% MEM 2gb
% WALLTIME 00:10:00
% DEPENDENCY ft_sourceplot

load(dccnpath('/home/common/matlab/fieldtrip/data/test/bug1527.mat'));

% this should be enough to reproduce the error
ft_sourceplot(cfg, source)


function hpaData=parseHPA(fileName, version)
% parseHPA
%   Parses a database dump of the Human Protein Atlas (HPA)
%
%   Input:
%   fileName            comma- or tab-separated database dump of HPA. For details
%                       regarding the format, see
%                       http://www.proteinatlas.org/about/download.
%   version             version of HPA [optional, default=19]
%
%
%   Output:
%   hpaData
%       genes               cell array with the unique gene names. In
%                           version >=18 this is the ensemble name, see
%                           geneNames below for the names in ver >=18
%       geneNames           cell array with the gene names, indexed the
%                           same way as genes.
%       tissues             cell array with the tissue names. The list may not be
%                           unique, as there can be multiple cell types per tissue
%       celltypes           cell array with the cell type names for each tissue
%       levels              cell array with the unique expression levels
%       types               cell array with the unique evidence types
%       reliabilities       cell array with the unique reliability levels
%
%       gene2Level          gene-to-expression level mapping in sparse matrix form.
%                           The value for element i,j is the index in
%                           hpaData.levels of gene i in cell type j
%       gene2Type           gene-to-evidence type mapping in sparse matrix form.
%                           The value for element i,j is the index in
%                           hpaData.types of gene i in cell type j. Doesn't
%                           exist in version >=18.
%       gene2Reliability    gene-to-reliability level mapping in sparse matrix form.
%                           The value for element i,j is the index in
%                           hpaData.reliabilities of gene i in cell type j
%
%   Usage: hpaData=parseHPA(fileName,version)

if nargin<2
    version=19; %Change this and add code for more versions when the current HPA version is increased and the format is changed
end

fileName=char(fileName);
if ~isfile(fileName)
    error('HPA file %s cannot be found',string(fileName));
end

if (version >= 17)
    fid=fopen(fileName,'r');
    hpa=textscan(fid,'%q %q %q %q %q %q','Delimiter','\t');
    fclose(fid);

    %Go through and see if the headers match what was expected
    headers={'Gene' 'Gene name' 'Tissue' 'Cell type' 'Level' 'Reliability'};
    for i=1:numel(headers)
        if ~strcmpi(headers(i),hpa{i}(1))
            EM=['Could not find the header "' headers{i} '". Make sure that the input file matches the format specified at http://www.proteinatlas.org/about/download'];
            dispEM(EM);
        end
        %Remove the header line here
        hpa{i}(1)=[];
    end

    %Get the unique values of each data type
    [hpaData.genes, P, I]=unique(hpa{1});
    hpaData.geneNames=hpa{2}(P); %make this vector use the index as genes
    [~, J, K]=unique(strcat(hpa{3},'€',hpa{4}));
    hpaData.tissues=hpa{3}(J);
    hpaData.celltypes=hpa{4}(J);
    [hpaData.levels, ~, L]=unique(hpa{5});
    [hpaData.reliabilities, ~, N]=unique(hpa{6});

    %Map the data to be sparse matrises instead
    hpaData.gene2Level=sparse(I,K,L,numel(hpaData.genes),numel(hpaData.tissues));
    hpaData.gene2Reliability=sparse(I,K,N,numel(hpaData.genes),numel(hpaData.tissues));
else
    fid=fopen(fileName,'r');
    hpa=textscan(fid,'%q %q %q %q %q %q','Delimiter',',');
    fclose(fid);

    %Go through and see if the headers match what was expected
    headers={'Gene' 'Tissue' 'Cell type' 'Level' 'Expression type' 'Reliability'};
    for i=1:numel(headers)
        if ~strcmpi(headers(i),hpa{i}(1))
            EM=['Could not find the header "' headers{i} '". Make sure that the input file matches the format specified at http://www.proteinatlas.org/about/download'];
            dispEM(EM);
        end
        %Remove the header line here
        hpa{i}(1)=[];
    end

    %Get the unique values of each data type
    [hpaData.genes, ~, I]=unique(hpa{1});
    [~, J, K]=unique(strcat(hpa{2},'€',hpa{3}));
    hpaData.tissues=hpa{2}(J);
    hpaData.celltypes=hpa{3}(J);
    [hpaData.levels, ~, L]=unique(hpa{4});
    [hpaData.types, ~, M]=unique(hpa{5});
    [hpaData.reliabilities, ~, N]=unique(hpa{6});

    %Map the data to be sparse matrises instead
    hpaData.gene2Level=sparse(I,K,L,numel(hpaData.genes),numel(hpaData.tissues));
    hpaData.gene2Type=sparse(I,K,M,numel(hpaData.genes),numel(hpaData.tissues));
    hpaData.gene2Reliability=sparse(I,K,N,numel(hpaData.genes),numel(hpaData.tissues));
end
end


function test_bug3218

% MEM 2gb
% WALLTIME 00:10:00
% DEPENDENCY ft_rejectartifact ft_rejectvisual

load(dccnpath('/home/common/matlab/fieldtrip/data/test/bug3218.mat'), 'data');

% When rejecting artifacts using 'partial', ft_rejectvisual works fine
cfg = [];
cfg.artfctdef.visual.artifact = data.sampleinfo(1, :) + [300 -300];
cfg.artfctdef.reject = 'partial';
dataReject = ft_rejectartifact(cfg, data);

ft_rejectvisual([], dataReject);

% When rejecting artifacts using 'nan', ft_rejectvisual recalculates the
% metric after each trial that is excluded. With this small data set it's
% not really a problem, but it becomes cumbersome with many trials and
% channels.

cfg = [];
cfg.artfctdef.visual.artifact = data.sampleinfo(1, :) + [300 -300];
cfg.artfctdef.reject = 'nan';
dataReject = ft_rejectartifact(cfg, data);

ft_rejectvisual([], dataReject);


%-----------------------------------------------------------------------
% Job saved on 22-Jul-2014 14:45:14 by cfg_util (rev $Rev$)
% spm SPM - SPM12b (5672)
% cfg_basicio BasicIO - Unknown
%-----------------------------------------------------------------------
matlabbatch{1}.spm.spatial.normalise.write.subj.def = {'/Users/kasperla/Documents/code/matlab/fmri_svn/development/analysis/examples/model_based_fmri_3T/zFatTmp/y_raw.nii'};
matlabbatch{1}.spm.spatial.normalise.write.subj.resample = {'/Users/kasperla/Documents/code/matlab/fmri_svn/development/analysis/examples/model_based_fmri_3T/zFatTmp/mraw.nii,1'};
matlabbatch{1}.spm.spatial.normalise.write.woptions.bb = [-78 -112 -70
                                                          78 76 85];
matlabbatch{1}.spm.spatial.normalise.write.woptions.vox = [2 2 2];
matlabbatch{1}.spm.spatial.normalise.write.woptions.interp = 7;


function x = cs_pvec (b,p)                                                  %#ok
%CS_PVEC x=b(p)
%
% Example:
%   x = cs_pvec (b,p)
% See also: cs_demo

%   Copyright 2006-2007, Timothy A. Davis.
%   http://www.cise.ufl.edu/research/sparse

error ('cs_pvec mexFunction not found') ;


% APM Index 2+ DAE Integrator
%
% y = apm_solve(app)
%
% Function apm_solve uploads the model file (apm) and optionally
%   a data file (csv) with the same name to the web-server and performs
%   a forward-time stepping integration of ODE or DAE equations
%   with the following arguments:
%
%  Input:      app = model (apm) and data file (csv) name
%
% Output: y.names  = names of all variables
%         y.values = tables of values corresponding to y.names
%         y.nvar   = number of variables
%         y.x      = combined variables and values but variable
%                      names may be modified to make them valid MATLAB
%                      characters (e.g. replace '[' with '_')
%
function y = apm_solve(app)
    % server and application file names
    server = 'http://xps.apmonitor.com';
    app_model = [app '.apm'];
    app_data = [app '.csv'];

    % clear previous application
    apm(server,app,'clear all');

    % check that model file exists (required)
    if (~exist(app_model,'file')),
        disp(['Error: file ' app_model ' does not exist']);
        y = [];
        return
    else
        % load model file
        apm_load(server,app,app_model);
    end

    % check if data file exists (optional)
    if (exist(app_data,'file')),
        % load data file
        csv_load(server,app,app_data);
    end

    % default options
    % use or don't use web viewer
    web = false;
    if web,
        apm_option(server,app,'nlc.web',2);
    else
        apm_option(server,app,'nlc.web',0);
    end
    % internal nodes in the collocation (between 2 and 6)
    apm_option(server,app,'nlc.nodes',3);
    % sensitivity analysis (default: 0 - off)
    apm_option(server,app,'nlc.sensitivity',0);
    % simulation mode (1=ss,  2=mpu, 3=rto)
    %                 (4=sim, 5=est, 6=nlc, 7=sqs)
    apm_option(server,app,'nlc.imode',7);

    % attempt solution
    solver_output = apm(server,app,'solve');

    % check for successful solution
    status = apm_tag(server,app,'nlc.appstatus');

    if status==1,
        % open web viewer if selected
        if web,
            apm_web(server,app);
        end
        % retrieve solution and solution.csv
        y = apm_sol(server,app);
        return
    else
        apm_web_root(server,app);
        disp(solver_output);
        disp('Error: Did not converge to a solution');
        y = solver_output;
        return
    end


classdef ObjectiveFunctionEnum < matlab.mixin.SetGet
    %ObjectiveFunctionEnum Summary of this class goes here
    %   Detailed explanation goes here
    %%%% See ConstraintEnum!
    enumeration
        NoObjectiveFunction('Satisfy Constraints Only','NoOptimizationObjectiveFcn')
        MinDistToBody('Minimize Distance to Body','MinDistanceToBodyObjectiveFcn')
        MaximizeVehicleMass('Maximize Vehicle Mass','MaximizeLaunchVehicleMassObjectiveFcn')
    end

    properties
        name char = '';
        class char = '';
    end

    methods
        function obj = ObjectiveFunctionEnum(name, class)
            obj.name = name;
            obj.class = class;
        end
    end

    methods(Static)
        function listBoxStr = getListBoxStr()
            m = enumeration('ObjectiveFunctionEnum');
            listBoxStr = {m.name};
        end

        function [ind, enum] = getIndForName(name)
            m = enumeration('ObjectiveFunctionEnum');
            ind = find(ismember({m.name},name),1,'first');
            enum = m(ind);
        end

        function [ind, enum] = getIndForClass(objFcnObject)
            m = enumeration('ObjectiveFunctionEnum');
            ind = find(ismember({m.class},class(objFcnObject)),1,'first');
            enum = m(ind);
        end
    end
end


%This folder contains the so-called ACQUIRE functions for bbci_apply.
%These functions acquire small bolcks of signals (and maybe event markers
%from a specific measurement device, and provide it for online processing.
%If no new data is available, they return an empty structure.
%
%These functions have the following format:
%
% --- --- --- ---
%BBCI_ACQUIRE_XYZ - Online data acquisition from device XYZ
%
%Synopsis:
%  STATE= bbci_acquire_XYZ('init', <PARAM>)
%  [CNTX, MRKTIME, MRKDESC, STATE]= bbci_acquire_XYZ(STATE)
%  bbci_acquire_XYZ('close')
%  bbci_acquire_XYZ('close', STATE)
%
%Arguments:
%  PARAM - Optional arguments, specific to XYZ.
%
%Output:
%  STATE - Structure characterizing the incoming signals; fields:
%     'fs', 'clab', and intern stuff
%  CNTX - 'acquired' signals [Time x Channels]
%  The following variables hold the markers that have been 'acquired' within
%  the current block (if any).
%  MRKTIME - DOUBLE: [1 nMarkers] position [msec] within data block.
%      A marker occurrence within the first sample would give
%      MARTIME= 1/STATE.fs.
%  MRKDESC - CELL {1 nMarkers} descriptors like 'S 52'
% --- --- --- ---
%
%List of ACQUIRE functions (prefix bbci_acquire_ is left out)
% bv:      Acquire data from BV Recorder (option 'Remote Data Access' must
%          be enabled in the BV Recorder settings!)
% nirx:    Acquire data from a NIRx system
% offline: Simulate online acquisition by returning small chunks of signals
%          from an initially given data file.
% randomSignals: Generate random signals
% lsl:     Acquire data from Lab Streaming Layer(LSL). LSL itself can hold
%           data from most common EEG and other recording devices.


function Write_Energy(FileWritingSetup)
% Write_Energy(FileWritingSetup)
%
% FUNCTION:
%
%   This function takes the symbolic expressions for system energy,
%   position, and velocity, and uses them to write a function file.
%
%
% INPUTS: FileWritingSetup.
%
%   States = [2N x 2] cell array where the first column is the name of
%       the states, and the second column is comments about that states.
%       The index of a state in this array will match the index in the
%       dynamics function to be written. This function assumes a second
%       order system that is being written in first order form, so if
%       States{i,1} = z, then States{i+N,1} = dz; Furthermore, the output
%       (dStates) will have the form: dStates(i,:) = dz,
%       and dStates(i+N,:) = ddz.
%
%   Parameters = [K x 2] cell array with all of the input parameters. The
%       first column is for names, the second for comments
%
%   Energy = A struct with fields for the symbolic expressions for
%       position and velocity.
%
%   Directory = the name of the directory to write the files in.
%
%
% OUTPUTS:
%   This function will write the function kinematics()
%
%
% NOTE:
%
%   1)  It is assumed that the symbols in all of the inputs are self
%       consistent; that is - if Contacts{1,1} = H1, then there must be a field
%       in Dyn.(FileNames{i,1}) called H1.
%
%
% Written by Matthew Kelly
% December 6, 2013
% Cornell University
%
% See also DERIVE_EOM

States = FileWritingSetup.States;
Parameters = FileWritingSetup.Parameters;
Directory = FileWritingSetup.Directory;
Energy = FileWritingSetup.Energy;

CurrDir = cd;
if ~exist(Directory,'dir')
    mkdir(Directory);
end
cd(Directory);

fid = fopen('energy.m','w');

%~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~%
%                         Function Header                             %
%~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~%

fprintf(fid,'function Energy = energy(States, Parameters)\n');
fprintf(fid,'%% function Energy = energy(States, Parameters)\n');
fprintf(fid,'%%\n%% Computer Generated File -- DO NOT EDIT \n');
fprintf(fid,['%%\n%% This function was created by the function '...
    'Write_Energy()\n']);
fprintf(fid,['%% ' datestr(now) '\n%%\n']);
fprintf(fid,'%%  RETURNS: \n');
fprintf(fid,'%%   Energy = a struct with fields: \n');
fprintf(fid,'%%       Potential \n');
fprintf(fid,'%%       Kinetic \n');
fprintf(fid,'%%       Total \n');
fprintf(fid,'%% \n');
fprintf(fid,'%%\n');
fprintf(fid,'%% Matthew Kelly \n%% Cornell University \n%% \n\n');
fprintf(fid,'%% \n');
fprintf(fid,'%% See also DERIVE_EOM \n');

%~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~%
%                           Parse Inputs                              %
%~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~%

for idxState=1:size(States,1)
    fprintf(fid,[States{idxState,1} ' = States(:,' num2str(idxState) '); %% ' ...
        States{idxState,2} '\n']);
end %idxState
fprintf(fid,'\n');

for idxParam=1:size(Parameters,1)
    fprintf(fid,[Parameters{idxParam,1} ' = Parameters.' ...
        Parameters{idxParam,1} '; %% ' ...
        Parameters{idxParam,2} '\n']);
end %idxState
fprintf(fid,'\n');

%~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~%
%                          Write Outputs                              %
%~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~%

fprintf(fid,['Energy.Potential.m1 = ' ...
    vectorize(Energy.Potential.m1) ';\n']);
fprintf(fid,['Energy.Potential.m2 = ' ...
    vectorize(    Energy.Potential.m2) ';\n']);
fprintf(fid,['Energy.Potential.M = ' ...
    vectorize(Energy.Potential.M) ';\n']);
fprintf(fid,'Energy.Potential.Total = Energy.Potential.m1 + Energy.Potential.m2 + Energy.Potential.M;\n');
fprintf(fid,'\n');
fprintf(fid,['Energy.Kinetic.m1 = ' ...
    vectorize(Energy.Kinetic.m1) ';\n']);
fprintf(fid,['Energy.Kinetic.m2 = ' ...
    vectorize(Energy.Kinetic.m2) ';\n']);
fprintf(fid,['Energy.Kinetic.M = ' ...
    vectorize(Energy.Kinetic.M) ';\n']);
fprintf(fid,'Energy.Kinetic.Total = Energy.Kinetic.m1 + Energy.Kinetic.m2 + Energy.Kinetic.M;\n');
fprintf(fid,'\n');
fprintf(fid,'Energy.Total = Energy.Kinetic.Total + Energy.Potential.Total;\n');
fprintf(fid,'\n');
fprintf(fid,'end\n');
fclose(fid);

cd(CurrDir);

end

%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%%%%  ~~~~~~~~~~~~~~~~~~~ Sub Functions  ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~%%%%
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%

function characterExpression = vectorize(symbolicExpression)

        characterExpression = char(symbolicExpression);
        characterExpression = strrep(characterExpression,'*','.*');
        characterExpression = strrep(characterExpression,'/','./');
        characterExpression = strrep(characterExpression,'^','.^');
end