valid_fwd_model

PURPOSE ^

[pass, err_str] = valid_fwd_model(fmdl, [type])

SYNOPSIS ^

function [pass, err_str] = valid_fwd_model(fmdl, type)

DESCRIPTION ^

 [pass, err_str] = valid_fwd_model(fmdl, [type])

 Confirms that a valid forward model structure exists or
 explain why a model is not valid.

 The model is assumed to be a fwd_model and all fields are
 checked unless type='rec_model'. A reconstruction model
 (rec_model) is only checked to confirm it has a valid mesh
 associated with it.

 If called without an output argument (nargout=0), will
 error out if invalid. Otherwise the function is silent,
 returning an explaination of failures in err_str.

CROSS-REFERENCE INFORMATION ^

This function calls: This function is called by:

SUBFUNCTIONS ^

SOURCE CODE ^

0001 function [pass, err_str] = valid_fwd_model(fmdl, type)
0002 % [pass, err_str] = valid_fwd_model(fmdl, [type])
0003 %
0004 % Confirms that a valid forward model structure exists or
0005 % explain why a model is not valid.
0006 %
0007 % The model is assumed to be a fwd_model and all fields are
0008 % checked unless type='rec_model'. A reconstruction model
0009 % (rec_model) is only checked to confirm it has a valid mesh
0010 % associated with it.
0011 %
0012 % If called without an output argument (nargout=0), will
0013 % error out if invalid. Otherwise the function is silent,
0014 % returning an explaination of failures in err_str.
0015 
0016 % (C) 2015 Alistair Boyle. License: GPL version 2 or version 3
0017 % $Id: valid_fwd_model.m 5264 2016-09-01 18:09:20Z alistair_boyle $
0018 
0019 pass = 1;
0020 err_str = '';
0021 
0022 if nargin < 2
0023    type = 'fwd_model';
0024 end
0025 if ~any(strcmp(type, {'fwd_model','rec_model'}))
0026    error('unexpected "type"');
0027 end
0028 
0029 % it's a struct with fields
0030 if ~isstruct(fmdl)
0031    pass = 0;
0032    err_str = [err_str '- not a struct\n'];
0033 end
0034 
0035 % required fields
0036 %      field         type
0037 f = {'name',        'char', ...
0038      'nodes',       'numeric', ... % uintX
0039      'elems',       'numeric', ... % uintX
0040      'gnd_node',    'numeric', ... % uintX
0041      'electrode',   'struct', ...
0042      'stimulation', 'struct', ...
0043      'solve',       'function', ...
0044      'system_mat',  'function_or_numeric', ...
0045      'jacobian',    'function_or_numeric', ...
0046      'normalize_measurements', 'numeric', ... % logical
0047      'type',        'char'};
0048 %     'boundary',   'numeric', ... % uintX OPTIONAL
0049 %     'meas_select','numeric', ... % uintX OPTIONAL
0050 % reduced set of requirements for a rec_model
0051 if strcmp(type, 'rec_model')
0052    f = {'name',     'char', ...
0053         'nodes',    'numeric', ...
0054         'elems',    'numeric'};
0055 end
0056 for i=1:length(f)/2
0057    x=2*(i-1)+1;
0058    y=x+1;
0059    if ~isfield(fmdl, f{x})
0060       pass = 0;
0061       err_str = [err_str '- missing required field: "' f{x} '"\n'];
0062    elseif strcmp(f{y},'function')
0063       if ~isfunc(fmdl.(f{x}))
0064          pass = 0;
0065          err_str = [err_str '- expected function (pointer or string): "' f{x} '"\n'];
0066       end
0067    elseif strcmp(f{y},'function_or_numeric')
0068       if ~isfunc(fmdl.(f{x})) && ~isa(fmdl.(f{x}), 'numeric')
0069          pass = 0;
0070          err_str = [err_str '- expected function (pointer or string) or a matrix: "' f{x} '"\n'];
0071       end
0072    elseif ~isa(fmdl.(f{x}), f{y})
0073       pass = 0;
0074       err_str = [err_str '- required field "' f{x} '" is not a ' f{y} '\n'];
0075    end
0076 end
0077 if ~strcmp(type, 'rec_model')
0078    % validate electrode struct
0079    nn = size(fmdl.nodes,1); % number of nodes
0080    for i=1:length(fmdl.electrode)
0081       [pass, err_str] = valid_elec(fmdl.electrode(i), i, nn, pass, err_str);
0082    end
0083    % validate stimulation struct
0084    nel = length(fmdl.electrode); % number of electrodes
0085    for i=1:length(fmdl.stimulation)
0086       [pass, err_str] = valid_stim(fmdl.stimulation(i), i, nel, pass, err_str);
0087    end
0088 end
0089 % check for correct 'type'
0090 if ~any(strcmp(fmdl.type, {'fwd_model', 'rec_model'}))
0091    pass = 0;
0092    err_str = [err_str '- field "type" must be "fwd_model" or "rec_model"\n'];
0093 end
0094 
0095 % optional fields
0096 %      field       type
0097 f = {'boundary',   'numeric', ... % uintX
0098      'meas_select','logical'};
0099 for i=1:length(f)/2
0100    x=2*(i-1)+1;
0101    y=x+1;
0102    if isfield(fmdl, f{x}) && ~isa(fmdl.(f{x}), f{y})
0103       pass = 0;
0104       err_str = [err_str '- optional field "' f{x} '" is not a ' f{y} '\n'];
0105    end
0106 end
0107 
0108 % illegal fields (common typos, etc)
0109 %      field
0110 f = {'fwd_model', ...
0111      'rec_model', ... % no recursion
0112      'stim', ... % not short form
0113      'elec', ...
0114      'fmdl', ...
0115      'fwd_mdl', ...
0116      'cmdl', ...
0117      'rmdl', ...
0118      'rec_mdl', ...
0119      'electrodes', ... % not plural
0120      'stimulations', ...
0121      'node', ... % plural
0122      'elem'};
0123 for i=1:length(f)
0124    x=i;
0125    if isfield(fmdl, f{x})
0126       pass = 0;
0127       err_str = [err_str '- illegal field "' f{x} '" found\n'];
0128    end
0129 end
0130 
0131 % result
0132 if ~pass
0133    err_str = err_str(1:end-2); % drop last \n
0134 end
0135 if ( nargout == 0 ) && ~pass
0136    error(sprintf(['Reasons:\n' err_str]));
0137 end
0138 
0139 function t=isfunc(f)
0140 t=isa(f, 'function_handle') || isa(f, 'char');
0141 
0142 function [pass, err_str] = valid_stim(stim, i, nel, pass, err_str)
0143 pass_local = 1;
0144 % required fields
0145 %      field         type
0146 f = {'stim_pattern', 'numeric', ...
0147      'meas_pattern', 'numeric'};
0148 for i=1:length(f)/2
0149    x=2*(i-1)+1;
0150    y=x+1;
0151    if ~isfield(stim, f{x})
0152       pass_local = 0;
0153       err_str = [err_str '- missing required field: "stimulation(' num2str(i) ').' f{x} '"\n'];
0154    elseif ~isa(stim.(f{x}), f{y})
0155       pass_local = 0;
0156       err_str = [err_str '- required field "stimulation(' num2str(i) ').' f{x} '" is not a ' f{y} '\n'];
0157    end
0158 end
0159 % optional fields
0160 %      field       type
0161 f = {'stimulation',  'char'};
0162 for i=1:length(f)/2
0163    x=2*(i-1)+1;
0164    y=x+1;
0165    if isfield(stim, f{x}) && ~isa(stim.(f{x}), f{y})
0166       pass_local = 0;
0167       err_str = [err_str '- optional field "stimulation(' num2str(i) ').' f{x} '" is not a ' f{y} '\n'];
0168    end
0169 end
0170 % we don't need to check further
0171 if ~pass_local
0172    pass = 0;
0173    return
0174 end
0175 clear pass_local;
0176 % we expect only stimulation, meas/stim_pattern fields
0177 len = length(fieldnames(stim));
0178 if (len > 3) || ((len > 2) && ~any(strcmp(fieldnames(stim),'stimulation')))
0179    pass = 0;
0180    err_str = [err_str '- extraneous fields in "stimulation(' num2str(i) ')\n'];
0181 end
0182 if size(stim.stim_pattern,1) > nel
0183    pass = 0;
0184    err_str = [err_str '- field "stimulation(' num2str(i) ').stim_pattern has more rows than electrodes in the model\n'];
0185 end
0186 if size(stim.meas_pattern,2) > nel
0187    pass = 0;
0188    err_str = [err_str '- field "stimulation(' num2str(i) ').meas_pattern has more columns than electrodes in the model\n'];
0189 end
0190 
0191 function [pass, err_str] = valid_elec(elec, i, nn, pass, err_str);
0192 pass_local = 1;
0193 % required fields
0194 %      field         type
0195 f = {'nodes',     'numeric', ...
0196      'z_contact', 'numeric'};
0197 for i=1:length(f)/2
0198    x=2*(i-1)+1;
0199    y=x+1;
0200    if ~isfield(elec, f{x})
0201       pass_local = 0;
0202       err_str = [err_str '- missing required field: "electrode(' num2str(i) ').' f{x} '"\n'];
0203    elseif ~isa(elec.(f{x}), f{y})
0204       pass_local = 0;
0205       err_str = [err_str '- required field "electrode(' num2str(i) ').' f{x} '" is not a ' f{y} '\n'];
0206    end
0207 end
0208 % we don't need to check further
0209 if ~pass_local
0210    pass = 0;
0211    return
0212 end
0213 clear pass_local;
0214 % check that 'nodes' are valid
0215 if any((elec.nodes > nn) | (elec.nodes < 1))
0216    pass = 0;
0217    err_str = [err_str '- field "electrode(' num2str(i) ').nodes do not exist on the model.nodes\n'];
0218 end

Generated on Fri 30-Dec-2022 19:44:54 by m2html © 2005