Unverified Commit 9e882182 authored by jayd1860's avatar jayd1860 Committed by GitHub
Browse files

Create shared code and submodule references to DataTree and Utils (#74)

* -- Move DataTree and some Utils functions to independent submodules used by AtlasViewer and Homer3

* Add config file to DataTree and ability to load mutiple config files to config utility

Add config file to DataTree and ability to load mutiple config files to config utility
parent a58f6121
Loading
Loading
Loading
Loading

.gitmodules

0 → 100644
+8 −0
Original line number Diff line number Diff line
[submodule "Utils/Shared"]
	path = Utils/Shared
	url = https://github.com/jayd1860/Utils
	branch = development
[submodule "DataTree"]
	path = DataTree
	url = https://github.com/jayd1860/DataTree
	branch = development
+0 −31
Original line number Diff line number Diff line

% Processing Stream Config File # 
processOpt_default.cfg

% Regression Test Active # true, false
false

% Include Archived User Functions # Yes, No
No

% Default Processing Stream Style # SNIRF, NIRS
SNIRF

% Logging # On, Off
On

% Check For Updates # on, off
on

% Data Storage Scheme # files, memory
files

% Auto Save Acquisition Files # No, Yes
No

% Group Data Loading Warnings # don't ask again, ask every time
don't ask again

% Stim Edit GUI Save Warnings # don't ask again, ask every time
don't ask again

% Output Folder Name # 
homerOutput

% Output File Name # 
groupResults.mat

% Fix File Name Conflicts # don't ask again, ask every time
ask every time

% END
Original line number Diff line number Diff line
Subproject commit 06abb78afc8905e1862c9913078716048ad1ff38
+0 −255
Original line number Diff line number Diff line
classdef AcqDataClass < matlab.mixin.Copyable
       
    properties (Access = private)
        logger
    end
    properties (Access = protected)
        errmsgs
    end
    
    %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
    % These methods must be implemented in any derived class
    %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
    methods(Abstract)
        
        % ---------------------------------------------------------
        objnew    = GetFormatVersion(obj, options);

        % ---------------------------------------------------------
        val       = GetFormatVersionString(obj);
   
        % ---------------------------------------------------------
        t         = GetTime(obj, iBlk)
       
        % ---------------------------------------------------------
        datamat   = GetDataTimeSeries(obj, options, iBlk)
        
        % ---------------------------------------------------------
        SD        = GetSDG(obj,option)

        % ---------------------------------------------------------
        srcpos    = GetSrcPos(obj,option)

        % ---------------------------------------------------------
        detpos    = GetDetPos(obj,option)
        
        % ---------------------------------------------------------
        ml        = GetMeasList(obj, iBlk)


        % ---------------------------------------------------------
        wls       = GetWls(obj)
        
        % ---------------------------------------------------------
        SetStims_MatInput(obj, s, t, CondNames)
        
        % ---------------------------------------------------------
        s         = GetStims(obj, t)

        % ---------------------------------------------------------
        CondNames = GetConditions(obj)


        % ---------------------------------------------------------
        SetConditions(obj, CondNames)
        
        % ---------------------------------------------------------
        aux       = GetAuxiliary(obj)
        
        % ---------------------------------------------------------
        SetStimDuration(obj, icond, duration);
        
        % ---------------------------------------------------------
        duration = GetStimDuration(obj, icond);
        
        % ---------------------------------------------------------
        n = GetDataBlocksNum(obj);

        % ---------------------------------------------------------
        [iDataBlks, ich] = GetDataBlocksIdxs(obj, ich);
        
        % ---------------------------------------------------------
        objnew = CopyMutable(obj, options);

    end
    
    
    methods
        
        % -------------------------------------------------------
        function Initialize(obj)
            global logger
            obj.logger = InitLogger(logger);
        end
        
        
        % -------------------------------------------------------
        function err = Error(obj)
            err = obj.GetError();
        end
        
        
        % ---------------------------------------------------------
        function msg = GetErrorMsg(obj)
            msg = '';
            if isempty(obj)
                msg = 'AcqDataClass object is empty';
                return;
            end
            if isempty(obj.errmsgs)
                return;
            end
            if ~obj.GetError()
                return;
            end
            msg = obj.errmsgs{abs(obj.GetError())};
        end
        
        
        % -------------------------------------------------------
        function FreeMemory(obj, filename)
            if ~exist('filename','var')
                filename = '';
            end
            if isempty(filename)
                return;
            end            
            obj.Initialize();
        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 varval = GetVar(obj, varname)
            if ismethod(obj,['Get_', varname])
                varval = eval( sprintf('obj.Get_%s()', varname) );
            elseif ismethod(obj,['Get', varname])
                varval = eval( sprintf('obj.Get%s()', varname) );
            elseif isproperty(obj, varname)
                varval = eval( sprintf('obj.%s', varname) );
            else
                varval = [];
            end
            
            % If varval is a class object with an IsEmpty() method and length of varval is one or 
            % less, then use it determine whether it's valid. If not, return empty as if it were 
            % really empty. This is useful when we want to copy only part of an object to save on space. 
            % For instance to reconstruct nirs style 's' variable from a SNIRF stim object we need the t 
            % property from a SNIRF data container, but we only need that one property not the whole thing
            % so we initilize only the t property. We don't want this partially initialized data object 
            % to be found (by GetVar) and used directly in the proc stream processing, we only want to use 
            % indirectly to retrieve s from stim. So we do this check to see if it's valid. It won't be 
            % since it's only partially initialized.
            if isa(varval, 'handle') && ismethod(varval,'IsEmpty')
                if length(varval)==1 && varval(1).IsEmpty()
                    varval = [];
                end
            end
        end
        
        
        % ----------------------------------------------------------------------------------
        function t = GetTimeCombined(obj)
            % Function combines the time vectors for all data blocks into one time vectors. 
            t = obj.GetTime(1);
            tStart = t(1);
            tEnd   = t(end);
            tStep  = mean(diff(t));
            
            nBlks = obj.GetDataBlocksNum();
            for iBlk=2:nBlks
                t = obj.GetTime(iBlk);
                if t(1) < tStart
                    tStart = t(1);
                end
                if t(end) > tEnd
                    tEnd = t(end);
                end
                if mean(diff(t)) < tStep
                    tStep = mean(diff(t));
                end
            end
            t = tStart:tStep:tEnd;            
        end
        
                
        % ----------------------------------------------------------------------------------
        function data = GetStimData(~, ~)
            data = [];
        end
        
        
        % ----------------------------------------------------------------------------------
        function val = GetStimDataLabels(~, ~)
            val = {};
        end
                        
        
        % ----------------------------------------------------------------------------------
        function b = equal(obj, obj2)
            b = true;
            if isempty(obj.GetFilename)
                return;
            end
            if isempty(obj2.GetFilename)
                return;
            end
            [~, fname1, ext1] = fileparts(obj.GetFilename);
            [~, fname2, ext2] = fileparts(obj2.GetFilename);            
            if ~strcmpi([fname1, ext1], [fname2, ext2])
                b = false;
            end
        end
        
        
        % ----------------------------------------------------------------------------------
        function status = Mismatch(obj, obj2)
            status = 0;
            msg = {};
            if ~exist('obj2','var')
                return;
            end
            if ~obj.equal(obj2)
                [~, fname, ext] = fileparts(obj.GetFilename);
                msg{1} = sprintf('WARNING: The acquisition file "%s" does not match the derived data in this group folder. ', [fname, ext]);
                msg{2} = sprintf('Are you sure this acquisition file belongs in this group folder?');
                obj.logger.Write([msg{:}])
            end
        end
        
        
        
    end
    
end
+0 −316
Original line number Diff line number Diff line
classdef DataFilesClass < handle
    
    properties
        files;
        type;
        err;
        errmsg;
        pathnm;
        config;
        nfiles;
    end
    
    methods
        
        % ----------------------------------------------------
        function obj = DataFilesClass(varargin)
            obj.type = '';
            obj.pathnm = pwd;
            obj.nfiles = 0;
            obj.err = -1;
            obj.errmsg = {};
            
            skipconfigfile = false;
            askToFixNameConflicts = [];
            
            if nargin==0
                return
            end            
            if nargin==1
                obj.pathnm = varargin{1};
            end            
            if nargin==2
                obj.pathnm = varargin{1};
                obj.type = varargin{2};
            end            
            if nargin==3
                obj.pathnm = varargin{1};
                obj.type = varargin{2};
                if strcmp(varargin{3}, 'standalone')
                    skipconfigfile = true;
                end
            end            
            if nargin==4
                obj.pathnm = varargin{1};
                obj.type = varargin{2};
                if strcmp(varargin{3}, 'standalone')
                    skipconfigfile = true;
                end
                askToFixNameConflicts = varargin{4};
            end
                        
            if obj.type(1)=='.'
                obj.type(1)='';
            end
            obj.pathnm = filesepStandard(obj.pathnm,'full');
            
            % Configuration parameters
            obj.config = struct('RegressionTestActive','','AskToFixNameConflicts',1);
            cfg = ConfigFileClass();
            if skipconfigfile==false
                str = cfg.GetValue('Regression Test Active');
                if strcmp(str,'true')
                    obj.config.RegressionTestActive=true;
                else
                    obj.config.RegressionTestActive=false;
                end
            else
                obj.config.RegressionTestActive=false;
            end
            if ~isempty(askToFixNameConflicts)
                obj.config.AskToFixNameConflicts = askToFixNameConflicts;
            elseif strcmp(cfg.GetValue('Fix File Name Conflicts'), sprintf('don''t ask again'))
                obj.config.AskToFixNameConflicts = 0;
            end
            
            if nargin==0
                return;
            end
            
            obj.err = 0;
            obj.files = mydir(obj.pathnm);
            GetDataSet(obj);
        end
        
        
        % -----------------------------------------------------------------------------------
        function GetDataSet(obj)
            if exist(obj.pathnm, 'dir')~=7
                error('Invalid subject folder: ''%s''', obj.pathnm);
            end
            obj.findDataSet(obj.type);
            obj.ErrorCheckName();
        end

        
        % ----------------------------------------------------
        function findDataSet(obj, type)
            obj.files = mydir([obj.pathnm, '/*.', type]);
            
            % Remove any files that cannot pass the basic test of loading
            % its data
            obj.ErrorCheck(type);
            
            if isempty( obj.files )                
                % If there are no data files in current dir, don't give up yet - check
                % the subdirs for data files.
                dirs = mydir(obj.pathnm);
                for ii = 1:length(dirs)
                    if dirs(ii).isdir && ...
                            ~strcmp(dirs(ii).name,'.') && ...
                            ~strcmp(dirs(ii).name,'..') && ...
                            ~strcmp(dirs(ii).name,'hide')
                        dirs(ii).idx = length(obj.files)+1;
                        foos = mydir([obj.pathnm, dirs(ii).name, '/*.', type]);
                        nfoos = length(foos);
                        if nfoos>0
                            for jj = 1:nfoos
                                foos(jj).subjdir      = dirs(ii).name;
                                foos(jj).subjdiridx   = dirs(ii).idx;
                                foos(jj).idx          = dirs(ii).idx+jj;
                                foos(jj).filename     = foos(jj).name;
                                foos(jj).name         = [dirs(ii).name, '/', foos(jj).name];
                                foos(jj).map2group    = struct('iGroup',0, 'iSubj',0, 'iRun',0);
                                foos(jj).pathfull     = dirs(ii).pathfull;
                                if ~foos(jj).isdir
                                    obj.nfiles = obj.nfiles+1;
                                end
                            end
                            
                            % Add file from current subdir to files struct
                            if isempty(obj.files)
                                obj.files = dirs(ii);
                            else
                                obj.files(end+1) = dirs(ii);
                            end
                            obj.files(end+1:end+nfoos) = foos;                                                        
                        end
                    end
                end
            else
                for ii = 1:length(obj.files)
                    obj.files(ii).pathfull = obj.pathnm;
                end
                obj.nfiles = obj.nfiles+length(obj.files);
            end
        end
        
        
        
        % ----------------------------------------------------
        function getDataFile(obj, filename)
            obj.files = mydir(filename);
        end
        
        
        
        % ----------------------------------------------------
        function ErrorCheckName(obj)
            for ii = length(obj.files):-1:1
                if obj.files(ii).ErrorCheckName()<0
                    q = obj.AskToFixNameConflicts(ii);                    
                    if q == 1
                        obj.files(ii).FixNameConflict();
                    else
                        obj.files(ii).NameConflictFixed();
                    end
                end
                if obj.files(ii).GetError()<0
                    obj.err = -1;
                end
            end
        end
        
        
        
        % --------------------------------------------------------------------------
        function answer = AskToFixNameConflicts(obj, ii)
            answer = 0;
            if obj.config.AskToFixNameConflicts == 0
                obj.files(ii).NameConflictFixed();
                return
            end
            q = MenuBox(obj.GetErrorMsg(ii), {'YES','NO'},[],[],'askEveryTimeOptions');
            if q(1) == 0
                return;
            end
            if length(q)>1 && q(2) == 1
                cfg = ConfigFileClass();
                cfg.SetValue('Fix File Name Conflicts', sprintf('don''t ask again'));
                cfg.Save()
                obj.config.AskToFixNameConflicts = 0;
            end
            if q(1)==2
                obj.files(ii).NameConflictFixed();
            end
            answer = q(1);
        end
        
        
        
        % -----------------------------------------------------
        function errmsg = GetErrorMsg(obj, ii)
            p1      = fileparts(obj.files(ii).GetName());
            [p2,f2] = fileparts(filesepStandard(obj.files(ii).pathfull,'nameonly:file'));
            [~,f3]  = fileparts(p2);
            if isfile_private(obj.files(ii).GetName())
                filetype = 'file';
            else
                filetype = 'folder';
            end
            containingFolder = '';
            if obj.files(ii).GetError() == -1
                containingFolder = p1;
            end
            if obj.files(ii).GetError() == -2
                containingFolder = f2;
            end
            if obj.files(ii).GetError() == -3
                containingFolder = f3;
            end
            msg{1} = sprintf('WARNING: The current %s (%s) has the same name as the folder (%s) containing it. ', filetype, obj.files(ii).GetName(), containingFolder);
            msg{2} = sprintf('All %ss should have a different name than the folder containing them, otherwise ', ['F',filetype(2:end)]);
            msg{3} = sprintf('it may cause incorrect results in processing. Do you want to rename this %s?', filetype);
            errmsg = [msg{:}];            
        end
        

        
        % -------------------------------------------------------
        function pushbuttonLoadDataset_Callback(~, hObject)
            hp = get(hObject,'parent');
            hc = get(hp,'children');
            for ii=1:length(hc)
                
                if strcmp(get(hc(ii),'tag'),'pushbuttonLoad')
                    hButtnLoad = hc(ii);
                elseif strcmp(get(hc(ii),'tag'),'pushbuttonSelectAnother')
                    hButtnSelectAnother = hc(ii);
                end
                
            end
            
            if hObject==hButtnLoad
                delete(hButtnSelectAnother);
            elseif hObject==hButtnSelectAnother
                delete(hButtnLoad);
            end
            delete(hp);
        end
            
        
        % ----------------------------------------------------------
        function b = isempty(obj)
            if isempty(obj.files)
                b = true;
            else
                b = false;
            end
        end
       
        
                
        % ----------------------------------------------------------
        function found = ConvertedFrom(obj, src)
            found = zeros(length(src.files), 1);
            for ii = 1:length(src.files)
                if src.files(ii).isdir
                    found(ii) = -1;
                    continue;
                end
                [ps, fs] = fileparts(src.files(ii).name);
                for jj = 1:length(obj.files)
                    [pd, fd] = fileparts(obj.files(jj).name);
                    if strcmp(filesepStandard([ps,'/',fs], 'nameonly'), filesepStandard([pd,'/',fd], 'nameonly'))
                        found(ii) = 1;
                        break;
                    else
                        dbgpt = 1;
                    end
                end
            end
        end
        
        
        
        % ----------------------------------------------------------
        function ErrorCheck(obj, type)
            errorIdxs = [];

            % Assume constructor name follows from name of data format type
            constructor = sprintf('%sClass', [upper(type(1)), type(2:end)]);
            
            % Make sure function by that name exists; otherwise no way to
            % use it to check loadability
            if isempty(which(constructor))
                return;
            end
            
            % Try to create object of data type and load data into it
            for ii = 1:length(obj.files)
                eval(sprintf('o = %s(obj.files(ii).name);', constructor));
                if o.GetError()<0
                    errorIdxs = [errorIdxs, ii];
                end
            end
            obj.files(errorIdxs) = [];
        end
        
        
        % ----------------------------------------------------------
        function err = GetError(obj)
            err = obj.err;
        end
        
    end
end
Loading