classdef BSMobj.NumSPMs id='BSM:Calc:InvalidIndex'; msg='Invalid Index'; throw(MException(id,msg)); end if numel(SPMidx)>1 obj.SPMIndexList=SPMidx; SPMidx=obj.SPMIndexList(end); try obj.Calc(SPMidx); %handle the single case catch ME %if the identifier matches, just continue with next SPM if ~any(strcmpi(ME.identifier,... {'BSM:CoreCalc:SPMxBFOrder:invalid'... ,'BSM:CoreCalc:SPMSess:invalid'... })) rethrow(ME) else disp(ME.message); end end obj.SPMIndexList=obj.SPMIndexList(1:end-1); if isempty(obj.SPMIndexList) return; else obj.Calc(obj.SPMIndexList);% recursively run the rest of the list end else % deal with single entry obj.CoreCalc(SPMidx) end end end methods %constructor and set/get methods function obj = BSM(varargin) %BSM Construct an instance of this class %option: parse the info of a matlab batch file? see %tbx_cf_bsm? %TODO: % set default values obj.SPMPath=[]; %get the SPM path if nargin>0 [val,TF]=obj.MyGetVal('SPMs',varargin);if TF;obj.SPMs=val;end [val,TF]=obj.MyGetVal('Type',varargin);if TF;obj.Type=val;end [val,TF]=obj.MyGetVal('Acfl',varargin);if TF;obj.Acfl=val;end end % initialize spm job enviourment spm_jobman('initcfg'); end function val=get.NumSPMs(obj) val=numel(obj.SPMs); end function set.Type(obj,val) %check allowed input if ~isnumeric(val)|| any(~ismember(val,1:5)) id='BSM:Type:invalid'; msg='use a value in the range 1..5'; throw(MException(id,msg)); end obj.Type=val; end function set.Acfl(obj,val) %allow clearing if isempty(val) obj.Acfl=[]; end if ~isnumeric(val) || any(val<1) || any(~isfinite(val)) id='BSM:Acfl:invalid'; msg='set an array of positive integer values to the Acfl field'; throw(MException(id,msg)); end obj.Acfl=val; end function set.SPMs(obj,val) %set the SPMs to be analysed %obj.SPMs= %possible values for % {} : clear the SPMs field % {'ui'} : ask user input if ~iscell(val) fprintf('%s\n',... 'Use any of the following options',... 'obj.SPMs={}',... 'obj.SPMs={''ui''}',... 'obj.SPMs={}'); return end if isempty(val) %allow empty input return; end if strcmpi(val{1},'ui') [P,sts]=spm_select([1 Inf],'mat','select the SPM.mat files',obj.SPMs,pwd,'^SPM.mat'); if ~logical(sts);return;end if iscell(P) val=P; else val=cellstr(P); end end % capture file not found somewhat clever TF=cellfun(@exist,val); if any(not(TF)) id='BSM:SetSPMs:FileNotFound'; msg=sprintf('file not found\t%s\n',val{not(TF)}); throw(MException(id,msg)); end obj.SPMs=val; end end methods %private functions function CoreCalc(obj,idx) fprintf('working on :%d: %s\n',idx,obj.SPMs{idx}); % how to store the current status of warning and restore curent WarnStat=warning; warning('OFF', 'MATLAB:MKDIR:DirectoryExists'); %this try catch block will handle any errors that might ocure %warning will not remain off by accident try SpmFile=obj.SPMs{idx}; load(SpmFile); %#ok %% exception block %NB these exception has not been tested properly by the if (SPM.xBF.order ~=1 ) %TestBSMClass program %throw an error. The calling function should properly %handle the error. id='BSM:CoreCalc:SPMxBFOrder:invalid'; msg=sprintf('%s\n','Problem found', ... 'No canonical HRF was used to model the data', ... 'Current file will be skipped'); throw(MException(id,msg)); end if (length(SPM.Sess) > 1 ) id='BSM:CoreCalc:SPMSess:invalid'; msg=sprintf('%s\n',... 'Problem found', ... 'Multiple sessions in one SPM.mat not supported', ... 'Current file will be skipped'); throw(MException(id,msg)); end % end exception block %% set local variables SPMOrig = SPM; UOrig = SPM.Sess(1).U; [ActCol,PasCol,AllCol]=obj.GetColDef(UOrig); LocalTargetFolder = fullfile(fileparts(SpmFile),'BSM');%RR replace BSM by a obj.BSMDir so user can modify this %% create directory mkdir(LocalTargetFolder); % loop over ActCol for c=1:length(ActCol) % get current col, get other col CurCol=ActCol(c); OthCol=setdiff(1:length(ActCol),CurCol); TargetFolderCurCol=fullfile(LocalTargetFolder,sprintf('col_%04d', CurCol)); for e=1:numel(UOrig(CurCol).ons)% loop over events U=obj.GetU(UOrig,e,c)%build U % build SPM % process SPM % Cleanup end% end loop % pack per event result % Cleanup end % end loop act. col % restore warning status warning(WarnStat); catch ME %turn matlab warning back on warning(WarnStat); rethrow(ME); end end function U=GetU(obj,UOrig,Event,Col) U=struct('name',{},'ons', [], 'dur',[], 'P',[], 'dt', [], 'u', [],'pst',[]); idx=1; %split out current event as first condition U(idx).name{1} = sprintf('%s_%d',UOrig(Col).name{1},Event); U(idx).ons = UOrig(Col).ons(Event); U(idx).dur = UOrig(Col).dur(Event); U(idx).P = UOrig(Col).P; U(idx).dt = UOrig(Col).dt; %optional add all other events as the next condition switch obj.Type case {1,2} idx = idx +1; OtherTrials=setdiff(1:numel(UOrig(Col).ons),Event); U(idx).name{1} = sprintf('%s_oe',UOrig(Col).name{1}); U(idx).ons = UOrig(Col).ons(OtherTrials); U(idx).dur = UOrig(Col).dur(OtherTrials); U(idx).P = UOrig(Col).P; U(idx).dt = UOrig(Col).dt; case {3,4} otherwise end % deal with other conditions switch obj.Type case {1,4} %put all other conditions in one column case {2,3} %keep other conditions each in their own column otherwise end end function [ActCol,PasCol,AllCol]=GetColDef(obj,U) AllCol=1:length(U); if ~isempty(obj.Acfl) PasCol = AllCol(obj.Acfl); %cf line 53 in spm_bsm.m else PasCol = []; end ActCol = setdiff(AllCol,PasCol); end function set.SPMPath(obj,~) SPMFound=which('spm'); %check if SPM in searchpath if isempty(SPMFound) %SPM not found error('please add SPM to your path before trying to run BSM'); %to do add a check on spm version end obj.SPMPath=fileparts(SPMFound); end function[val,TF]=MyGetVal(~,selector,List) TF=strcmpi(selector,List); if any(TF) %spmpath is set as option k=find(TF, 1 );%find the first instance if (k+1)>numel(List) id='BSM:getval:ReadBeyondEndInput'; msg=sprintf('use name value pairs\nlast entry is a name'); throw(MException(id,msg)); end val=List{k+1}; TF=true; else val=false; TF=false; end end end end