Skip to content

Commit

Permalink
implement checks for pspm_tam
Browse files Browse the repository at this point in the history
  • Loading branch information
Dominik Bach committed Jan 6, 2024
1 parent 3c8ce59 commit 627e82d
Show file tree
Hide file tree
Showing 3 changed files with 177 additions and 276 deletions.
158 changes: 129 additions & 29 deletions src/pspm_check_model.m
Original file line number Diff line number Diff line change
Expand Up @@ -193,6 +193,7 @@
% NOTE we need to separate the case of DCM timing being
% . a cell array of cell arrays
% . just a cell array
% see below

%% 3. Fill missing fields common to all models, and accept only allowed values
if ~isfield(model, 'timing')
Expand Down Expand Up @@ -293,32 +294,11 @@
elseif ~ismember(model.modelspec, {settings.glm.modelspec})
warning('ID:invalid_input', 'Unknown model specification %s.', model.modelspec); return;
end

modno = find(strcmpi(model.modelspec, {settings.glm.modelspec}));
model.modality = settings.glm(modno).modality;

if ~isfield(model, 'bf')
model.bf = settings.glm(modno).cbf;
elseif ~isfield(model.bf, 'fhandle')
warning('No basis function given.'); return
elseif ~(ischar(model.bf.fhandle) || isa(model.bf.fhandle, 'function_handle'))
warning('Basis function must be a string or function handle.'); return
elseif ischar(model.bf.fhandle) && ~exist(model.bf.fhandle, 'file')
warning('ID:invalid_fhandle', 'Specified basis function %s doesn''t exist or is faulty', model.bf.fhandle); return;
elseif ~isfield(model.bf, 'args')
model.bf.args = [];
elseif ~isnumeric(model.bf.args)
warning('Basis function arguments must be numeric.'); return
end

if ~isfield(model, 'channel')
if strcmp(model.modality, 'psr')
model.channel = 'pupil';
else
model.channel = model.modality;
end
elseif ~isnumeric(model.channel) && ~ismember(model.channel, {settings.channeltypes.type})
warning('ID:invalid_input', 'Channel number must be numeric or a modality short name.'); return;

if ~isfield(model, 'modality')
model.modality = settings.glm(modno).modality;
end

if ~isfield(model,'centering')
Expand Down Expand Up @@ -413,18 +393,136 @@
warning('ID:invalid_input', 'Window is expected to be a numeric value.'); return;
elseif

if ~isfield(model, 'modelspec')
if ~isfield(model, 'modelspec')
model.modelspec = settings.tam(1).modelspec;
elseif ~ismember(model.modelspec, {settings.tam.modelspec})
warning('ID:invalid_input', 'Unknown model specification %s.', model.modelspec); return;
end

modno = find(strcmpi(model.modelspec, {settings.tam.modelspec}));
model.modality = settings.tam(modno).modality;

if ~isfield(model, 'modality')
model.modality = settings.tam(modno).modality;
end


% Checking the input function
if ~isfield(model, 'if')
model.if = settings.pfm(modno).cif;
else
if ~isfield(model.if, 'fhandle')
warning('No input function given.'); return;
elseif ischar(model.if.fhandle)
[~, basefn,~] = fileparts(model.if.fhandle);
model.if.fhandle = str2func(basefn);
clear basefn
elseif ~isa(model.bf.fhandle, 'function_handle')
warning('Basis function must be a string or function handle.'); return;
end
if ~isfield(model.if,'args') || isempty(model.if.args) || ~isnumeric(model.if.args)
warning('ID:invalid_input',['Arguments for the input',...
' function must be a non-empty numeric array.']); return;
end
if ~isfield(model.if,'lb') || ~isnumeric(model.if.lb) ...
|| any(size(model.if.lb)~=size(model.if.args))
warning('ID:invalid_input',['The lower bounds for the input function',...
' must be a numeric array of the same size than ''model.if.arg''.']); return;
end
if ~isfield(model.if,'ub') || ~isnumeric(model.if.ub) ...
|| any(size(model.if.ub)~=size(model.if.args))
warning('ID:invalid_input',['The upper bounds for the input function',...
' must be a numeric array of the same size than ''model.if.arg''.']); return;
end
if any(model.if.lb > model.if.ub) || any(model.if.lb > model.if.args) ...
|| any(model.if.args > model.if.ub)
warning('ID:invalid_input',['Input function''s parameters are inconsistent.',...
' They must respect: model.if.lb <= model.if.arg <= model.if.ub.']); return;
end
end
model.if.args = model.if.args(:).';
model.if.lb = model.if.lb(:).';
model.if.ub = model.if.ub(:).';

% Checking baseline
if ~isfield(model,'baseline')
model.baseline = 0;
elseif ~isnumeric(model.baseline)
warning('ID:invalid_input','''model.baseline'' has to be a numeric.'); return;
elseif model.baseline > model.window || model.baseline < 0
warning('ID:invalid_input',['''model.baseline'' has to be positive ',...
'and smaller than ''model.window''.']); return;
end

% Checking standard experimental condition
std_cond_war_msg = ['The standard experimental condition must be',...
' either a valid experimental condition or an',...
' index corresponding to it.'];
if ~isfield(model,'std_exp_cond')
model.std_exp_cond = 'none';
elseif ~ischar(model.std_exp_cond) && ~isnumeric(model.std_exp_cond)
warning('ID:invalid_input',std_cond_war_msg); return;
elseif ischar(model.std_exp_cond)
tmp_ind = cellfun(@(x) strcmpi(model.std_exp_cond,x), model.timing{1}.names);
if ~any(tmp_ind)
warning('ID:invalid_input',std_cond_war_msg); return;
end
std_exp_cond.name = model.std_exp_cond;
std_exp_cond.ind = find(tmp_ind);
elseif isnumeric(model.std_exp_cond)
if model.std_exp_cond < 1 || ...
model.std_exp_cond > numel(model.timing{1}.names)
warning('ID:invalid_input',std_cond_war_msg); return;
end
std_exp_cond.name = model.timing{1}.names(model.std_exp_cond);
std_exp_cond.ind = model.std_exp_cond;
end
clear std_cond_war_msg tmp_ind

% Checking norm_max
if ~isfield(model, 'norm_max')
model.norm_max = 0;
elseif ~ismember(model.norm_max, [0, 1])
warning('ID:invalid_input', '''model.norm_max'' has to be 0 or 1.'); return;
end
end

%% 9. GLM- and TAM-specific checks
% -------------------------------------------------------------------------
if strcmpi(modeltype, 'glm') || strcmpi(modeltype, 'tam')
% check the basis function
if ~isfield(model, 'bf')
if strcmpi(modeltype, 'glm')
model.bf = settings.glm(modno).cbf;
elseif strcmpi(modeltype, 'tam')
model.bf = settings.tam(modno).cbf;
end
elseif ~isfield(model.bf, 'fhandle')
warning('No basis function given.'); return
elseif ~(ischar(model.bf.fhandle) || isa(model.bf.fhandle, 'function_handle'))
warning('Basis function must be a string or function handle.'); return
elseif ischar(model.bf.fhandle) && ~exist(model.bf.fhandle, 'file')
warning('ID:invalid_fhandle', 'Specified basis function %s doesn''t exist or is faulty', model.bf.fhandle); return;
elseif ~isfield(model.bf, 'args')
model.bf.args = [];
elseif ~isnumeric(model.bf.args)
warning('Basis function arguments must be numeric.'); return
end

% check the channel definition
if ~isfield(model, 'channel')
if strcmp(model.modality, 'psr')
model.channel = 'pupil';
else
model.channel = model.modality;
end
elseif ~isnumeric(model.channel) && ~ismember(model.channel, {settings.channeltypes.type})
warning('ID:invalid_input', 'Channel number must be numeric or a modality short name.'); return;
end

end

%% 10. General checks that require GLM-specific checks in case of GLM
%% 10. General checks that require preceding GLM/TAM-specific checks in
% case of GLM/TAM
% -------------------------------------------------------------------------
if ~isfield(model, 'filter')
switch modeltype
Expand All @@ -434,6 +532,8 @@
model.filter = settings.dcm{1}.filter;
case 'sf'
model.filter = settings.dcm{2}.filter;
case 'tam'
model.filter = settings.tam(modno).filter;
end
end

Expand Down
5 changes: 3 additions & 2 deletions src/pspm_glm.m
Original file line number Diff line number Diff line change
Expand Up @@ -28,9 +28,10 @@
% ├.modelspec: 'scr' (default); specify the model to be used.
% │ See pspm_init, defaults.glm() which modelspecs are possible
% │ with glm.
% ├─.modality: specify the modality to be processed.
% ├─.modality: specify the data modality to be processed.
% │ When model.modality is set to be sps, the model.channel
% │ should be set among sps_l, sps_r, or defaultly sps.
% │ should be set among sps_l, sps_r, or defaultly sps. By
% │ default, this is determined automatically from "modelspec"
% ├───────.bf: basis function/basis set; modality specific default
% │ with subfields .fhandle (function handle or string) and
% │ .args (arguments, first argument sampling interval will
Expand Down
Loading

0 comments on commit 627e82d

Please sign in to comment.