0001 function [pass, err_str] = valid_fwd_model(fmdl, type)
0002
0003
0004
0005
0006
0007
0008
0009
0010
0011
0012
0013
0014
0015
0016
0017
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
0030 if ~isstruct(fmdl)
0031 pass = 0;
0032 err_str = [err_str '- not a struct\n'];
0033 end
0034
0035
0036
0037 f = {'name', 'char', ...
0038 'nodes', 'numeric', ...
0039 'elems', 'numeric', ...
0040 'gnd_node', 'numeric', ...
0041 'electrode', 'struct', ...
0042 'stimulation', 'struct', ...
0043 'solve', 'function', ...
0044 'system_mat', 'function_or_numeric', ...
0045 'jacobian', 'function_or_numeric', ...
0046 'normalize_measurements', 'numeric', ...
0047 'type', 'char'};
0048
0049
0050
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
0079 nn = size(fmdl.nodes,1);
0080 for i=1:length(fmdl.electrode)
0081 [pass, err_str] = valid_elec(fmdl.electrode(i), i, nn, pass, err_str);
0082 end
0083
0084 nel = length(fmdl.electrode);
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
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
0096
0097 f = {'boundary', 'numeric', ...
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
0109
0110 f = {'fwd_model', ...
0111 'rec_model', ...
0112 'stim', ...
0113 'elec', ...
0114 'fmdl', ...
0115 'fwd_mdl', ...
0116 'cmdl', ...
0117 'rmdl', ...
0118 'rec_mdl', ...
0119 'electrodes', ...
0120 'stimulations', ...
0121 'node', ...
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
0132 if ~pass
0133 err_str = err_str(1:end-2);
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
0145
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
0160
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
0171 if ~pass_local
0172 pass = 0;
0173 return
0174 end
0175 clear pass_local;
0176
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
0194
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
0209 if ~pass_local
0210 pass = 0;
0211 return
0212 end
0213 clear pass_local;
0214
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