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 if ischar(fmdl) && strcmp(fmdl,'UNIT_TEST'); do_unit_test; return; end
0020
0021 pass = 1;
0022 err_str = '';
0023
0024 if nargin < 2
0025 type = 'fwd_model';
0026 end
0027 if ~any(strcmp(type, {'fwd_model','rec_model'}))
0028 error('unexpected "type"');
0029 end
0030
0031
0032 if ~isstruct(fmdl)
0033 pass = 0;
0034 err_str = [err_str '- not a struct\n'];
0035 end
0036
0037
0038
0039 f = {'name', 'char', ...
0040 'nodes', 'numeric', ...
0041 'elems', 'numeric', ...
0042 'gnd_node', 'numeric', ...
0043 'electrode', 'none_or_struct', ...
0044 'stimulation', 'none_or_struct', ...
0045 'solve', 'function', ...
0046 'system_mat', 'function_or_numeric', ...
0047 'jacobian', 'function_or_numeric', ...
0048 'normalize_measurements', 'numeric_or_logical', ...
0049 'type', 'char'};
0050
0051
0052
0053 if strcmp(type, 'rec_model')
0054 f = {'name', 'char', ...
0055 'nodes', 'numeric', ...
0056 'elems', 'numeric'};
0057 end
0058 for i=1:length(f)/2
0059 x=2*(i-1)+1;
0060 y=x+1;
0061
0062 [pass,err_str]= validate_fmdl(fmdl,f{x},f{y},pass,err_str);
0063 end
0064 if ~strcmp(type, 'rec_model')
0065
0066 nn = size(fmdl.nodes,1);
0067 if isfield(fmdl,'electrode');
0068 for i=1:length(fmdl.electrode)
0069 [pass, err_str] = valid_elec(fmdl.electrode(i), i, nn, pass, err_str);
0070 end
0071 nel = length(fmdl.electrode);
0072 end
0073
0074 if isfield(fmdl,'stimulation');
0075 for i=1:length(fmdl.stimulation)
0076 [pass, err_str] = valid_stim(fmdl.stimulation(i), i, nel, pass, err_str);
0077 end
0078 end
0079 end
0080
0081 if ~any(strcmp(fmdl.type, {'fwd_model', 'rec_model'}))
0082 pass = 0;
0083 err_str = [err_str '- field "type" must be "fwd_model" or "rec_model"\n'];
0084 end
0085
0086
0087
0088 f = {'boundary', 'numeric', ...
0089 'meas_select','logical'};
0090 for i=1:length(f)/2
0091 x=2*(i-1)+1;
0092 y=x+1;
0093 if isfield(fmdl, f{x}) && ~isa(fmdl.(f{x}), f{y})
0094 pass = 0;
0095 err_str = [err_str '- optional field "' f{x} '" is not a ' f{y} '\n'];
0096 end
0097 end
0098
0099
0100
0101 f = {'fwd_model', ...
0102 'rec_model', ...
0103 'stim', ...
0104 'elec', ...
0105 'fmdl', ...
0106 'fwd_mdl', ...
0107 'cmdl', ...
0108 'rmdl', ...
0109 'rec_mdl', ...
0110 'electrodes', ...
0111 'stimulations', ...
0112 'node', ...
0113 'elem'};
0114 for i=1:length(f)
0115 x=i;
0116 if isfield(fmdl, f{x})
0117 pass = 0;
0118 err_str = [err_str '- illegal field "' f{x} '" found\n'];
0119 end
0120 end
0121
0122
0123 if ~pass
0124 err_str = err_str(1:end-2);
0125 end
0126 if ( nargout == 0 ) && ~pass
0127 error(sprintf(['Reasons:\n' err_str]));
0128 end
0129
0130 function [pass,err_str]= validate_fmdl(fmdl,f_x,f_y,pass,err_str);
0131 hasfield= isfield(fmdl, f_x);
0132 if strcmp(f_y(1:4),'none')
0133 if ~hasfield
0134 return
0135 else
0136 f_y(1:8) = '';
0137 end
0138 end
0139
0140 if ~hasfield
0141 pass = 0;
0142 err_str = [err_str '- missing required field: "' f_x '"\n'];
0143 elseif strcmp(f_y,'function')
0144 if ~isfunc(fmdl.(f_x))
0145 pass = 0;
0146 err_str = [err_str '- expected function (pointer or string): "' f_x '"\n'];
0147 end
0148 elseif strcmp(f_y,'function_or_numeric')
0149 if ~isfunc(fmdl.(f_x)) && ~isa(fmdl.(f_x), 'numeric')
0150 pass = 0;
0151 err_str = [err_str '- expected function (pointer or string) or a matrix: "' f_x '"\n'];
0152 end
0153 elseif strcmp(f_y,'numeric_or_logical')
0154 if ~isa(fmdl.(f_x), 'numeric') && ~isa(fmdl.(f_x),'logical')
0155 pass = 0;
0156 err_str = [err_str '- expected numerical or logical value: "' f_x '"\n'];
0157 end
0158 elseif ~isa(fmdl.(f_x), f_y)
0159 pass = 0;
0160 err_str = [err_str '- required field "' f_x '" is not a ' f_y '\n'];
0161 end
0162
0163 function t=isfunc(f)
0164 t=isa(f, 'function_handle') || isa(f, 'char');
0165
0166 function [pass, err_str] = valid_stim(stim, i, nel, pass, err_str)
0167 pass_local = 1;
0168
0169
0170 f = {'stim_pattern', 'numeric', ...
0171 'meas_pattern', 'numeric'};
0172 for i=1:length(f)/2
0173 x=2*(i-1)+1;
0174 y=x+1;
0175 if ~isfield(stim, f{x})
0176 pass_local = 0;
0177 err_str = [err_str '- missing required field: "stimulation(' num2str(i) ').' f{x} '"\n'];
0178 elseif ~isa(stim.(f{x}), f{y})
0179 pass_local = 0;
0180 err_str = [err_str '- required field "stimulation(' num2str(i) ').' f{x} '" is not a ' f{y} '\n'];
0181 end
0182 end
0183
0184
0185 f = {'stimulation', 'char'};
0186 for i=1:length(f)/2
0187 x=2*(i-1)+1;
0188 y=x+1;
0189 if isfield(stim, f{x}) && ~isa(stim.(f{x}), f{y})
0190 pass_local = 0;
0191 err_str = [err_str '- optional field "stimulation(' num2str(i) ').' f{x} '" is not a ' f{y} '\n'];
0192 end
0193 end
0194
0195 if ~pass_local
0196 pass = 0;
0197 return
0198 end
0199 clear pass_local;
0200
0201 len = length(fieldnames(stim));
0202 if (len > 3) || ((len > 2) && ~any(strcmp(fieldnames(stim),'stimulation')))
0203 pass = 0;
0204 err_str = [err_str '- extraneous fields in "stimulation(' num2str(i) ')\n'];
0205 end
0206 if size(stim.stim_pattern,1) > nel
0207 pass = 0;
0208 err_str = [err_str '- field "stimulation(' num2str(i) ').stim_pattern has more rows than electrodes in the model\n'];
0209 end
0210 if size(stim.meas_pattern,2) > nel
0211 pass = 0;
0212 err_str = [err_str '- field "stimulation(' num2str(i) ').meas_pattern has more columns than electrodes in the model\n'];
0213 end
0214
0215 function [pass, err_str] = valid_elec(elec, i, nn, pass, err_str);
0216 pass_local = 1;
0217
0218
0219 f = {'nodes', 'numeric', ...
0220 'z_contact', 'numeric'};
0221 for i=1:length(f)/2
0222 x=2*(i-1)+1;
0223 y=x+1;
0224 if ~isfield(elec, f{x})
0225 pass_local = 0;
0226 err_str = [err_str '- missing required field: "electrode(' num2str(i) ').' f{x} '"\n'];
0227 elseif ~isa(elec.(f{x}), f{y})
0228 pass_local = 0;
0229 err_str = [err_str '- required field "electrode(' num2str(i) ').' f{x} '" is not a ' f{y} '\n'];
0230 end
0231 end
0232
0233 if ~pass_local
0234 pass = 0;
0235 return
0236 end
0237 clear pass_local;
0238
0239 if any((elec.nodes > nn) | (elec.nodes < 1))
0240 pass = 0;
0241 err_str = [err_str '- field "electrode(' num2str(i) ').nodes do not exist on the model.nodes\n'];
0242 end
0243
0244 function do_unit_test
0245 fmdl = mk_circ_tank(2,[],0);
0246 pass=1;
0247 try [pass, err_str] = valid_fwd_model(fmdl);
0248 catch pass=0;
0249 end
0250 unit_test_cmp('valid_fwd_model 1',pass,1);
0251
0252 fmdl= rmfield(fmdl,'nodes');
0253 try [pass, err_str] = valid_fwd_model(fmdl);
0254 catch pass=0;
0255 end
0256 unit_test_cmp('valid_fwd_model 2',pass,0);