0001 function img = inv_solve( inv_model, data1, data2)
0002
0003
0004
0005
0006
0007
0008
0009
0010
0011
0012
0013
0014
0015
0016
0017
0018
0019
0020
0021
0022
0023
0024
0025
0026
0027
0028
0029
0030
0031
0032
0033
0034
0035
0036
0037
0038
0039
0040
0041
0042
0043
0044
0045
0046
0047
0048
0049
0050
0051
0052
0053
0054
0055
0056
0057
0058 if ischar(inv_model) && strcmp(inv_model,'UNIT_TEST'); do_unit_test; return; end
0059
0060 inv_model = prepare_model( inv_model );
0061 opts = parse_parameters( inv_model );
0062
0063 print_hello(inv_model.solve);
0064 try inv_model.solve = str2func(inv_model.solve); end
0065
0066 if opts.abs_solve
0067 if nargin~=2;
0068 error('only one data set is allowed for a static reconstruction');
0069 end
0070
0071 fdata = filt_data(inv_model,data1);
0072
0073 imgc= eidors_cache( inv_model.solve, {inv_model, fdata}, 'inv_solve');
0074
0075 else
0076 if nargin~=3;
0077 error('two data sets are required for a difference reconstruction');
0078 end
0079
0080
0081 data_width= max(num_frames(data1), num_frames(data2));
0082
0083 fdata1 = filt_data( inv_model, data1, data_width );
0084 fdata2 = filt_data( inv_model, data2, data_width );
0085
0086 imgc= eidors_cache( inv_model.solve, {inv_model, fdata1, fdata2},'inv_solve');
0087
0088
0089 end
0090
0091 check_parametrization_handling(inv_model,imgc);
0092
0093 img = eidors_obj('image', imgc );
0094
0095 if ~isfield(img,'current_params')
0096
0097 img.current_params = [];
0098 end
0099
0100
0101
0102 if isfield(inv_model,'rec_model')
0103 img.fwd_model= inv_model.rec_model;
0104 end
0105
0106
0107 if opts.select_parameters;
0108 img.elem_data = img.elem_data( opts.select_parameters, :);
0109 end
0110
0111 if isfield(img,'elem_data')
0112 img.time = 1:size(img.elem_data,2);
0113 else
0114 img.time = 1:size(img.node_data,2);
0115 end
0116
0117 if isfield(inv_model.fwd_model,'frame_rate');
0118 img.time = img.time / inv_model.fwd_model.frame_rate;
0119 end
0120
0121 if ~opts.reconst_to_elems
0122 img.node_data= img.elem_data;
0123 img = rmfield(img,'elem_data');
0124 end
0125
0126
0127 try; img.elem_data = opts.offset + opts.scale * img.elem_data; end
0128 try; img.node_data = opts.offset + opts.scale * img.node_data; end
0129
0130
0131
0132
0133
0134 img.info.error = NaN;
0135 img = orderfields(img);
0136
0137
0138 try
0139 do_calc = inv_model.inv_solve.calc_solution_error;
0140 catch
0141 eidors_msg('inv_solve: not calculting solution residual',3);
0142 do_calc = false;
0143 end
0144 if ~do_calc;
0145 return;
0146 end
0147 eidors_msg('inv_solve: Calculating solution residual (inv_model.inv_solve.calc_solution_error = 0 to disable)',2);
0148 try
0149 if opts.abs_solve
0150 img.info.error = calc_solution_error( imgc, inv_model, fdata);
0151 else
0152 img.info.error = calc_solution_error( imgc, inv_model, fdata1, fdata2 );
0153 end
0154 eidors_msg('inv_solve: Solution Error: %f', img.info.error, 2);
0155 catch
0156 eidors_msg('inv_solve: Solution Error calculation failed.',2);
0157 end
0158
0159 function print_hello(solver)
0160 if isa(solver,'function handle')
0161 solver = func2str(solver);
0162 end
0163 if strcmp(solver, 'eidors_default');
0164 solver = eidors_default('get','inv_solve');
0165 end
0166 eidors_msg('inv_solve: %s', solver,3);
0167
0168
0169 function opts = parse_parameters( imdl )
0170 if strcmp(imdl.reconst_type,'static') || ...
0171 strcmp(imdl.reconst_type,'absolute')
0172 opts.abs_solve = 1;
0173 elseif strcmp(imdl.reconst_type,'difference')
0174 opts.abs_solve = 0;
0175 else
0176 error('inv_model.reconst_type (%s) not understood', imdl.reconst_type);
0177 end
0178
0179 opts.select_parameters = [];
0180 try
0181 opts.select_parameters = imdl.inv_solve.select_parameters;
0182 end
0183
0184 opts.reconst_to_elems = 1;
0185 try if strcmp( imdl.reconst_to, 'nodes' )
0186 opts.reconst_to_elems = 0;
0187 end; end
0188
0189 opts.scale = 1;
0190 try opts.scale = imdl.inv_solve.scale_solution.scale; end
0191
0192 opts.offset = 0;
0193 try opts.offset = imdl.inv_solve.scale_solution.offset; end
0194
0195 function imdl = deprecate_imdl_parameters(imdl)
0196 if isfield(imdl, 'parameters')
0197 if isstruct(imdl.parameters)
0198
0199
0200
0201
0202 if ~isfield(imdl, 'inv_solve')
0203 imdl.inv_solve = imdl.parameters;
0204 else
0205
0206
0207 A = imdl.parameters;
0208 B = imdl.inv_solve;
0209 M = [fieldnames(A)' fieldnames(B)'; struct2cell(A)' struct2cell(B)'];
0210 try
0211 imdl.inv_solve=struct(M{:});
0212 catch
0213 [tmp, rows] = unique(M(1,:), 'last');
0214 M=M(:,rows);
0215 imdl.inv_solve=struct(M{:});
0216 end
0217 end
0218 imdl = rmfield(imdl, 'parameters');
0219 imdl.parameters = imdl.inv_solve;
0220 else
0221 error('unexpected inv_model.parameters where parameters is not a struct... i do not know what to do');
0222 end
0223 end
0224
0225 function mdl = prepare_model( mdl )
0226 fmdl = mdl.fwd_model;
0227 fmdl = mdl_normalize(fmdl,mdl_normalize(fmdl));
0228 if ~isfield(fmdl,'elems');
0229 return;
0230 end
0231
0232 fmdl.elems = double(fmdl.elems);
0233 fmdl.n_elem = size(fmdl.elems,1);
0234 fmdl.n_node = size(fmdl.nodes,1);
0235 if isfield(fmdl,'electrode');
0236 fmdl.n_elec = length(fmdl.electrode);
0237 else
0238 fmdl.n_elec = 0;
0239 end
0240
0241 mdl.fwd_model= fmdl;
0242 if ~isfield(mdl,'reconst_type');
0243 mdl.reconst_type= 'difference';
0244 end
0245
0246
0247 mdl = deprecate_imdl_parameters(mdl);
0248
0249 function check_parametrization_handling(inv_model,imgc)
0250 if isfield(inv_model, 'jacobian_bkgnd') && ...
0251 has_params(inv_model.jacobian_bkgnd) && ~has_params(imgc)
0252 if isa(inv_model.solve,'function_handle')
0253 solver = func2str(inv_model.solve);
0254 else
0255 solver = inv_model.solve;
0256 end
0257 if strcmp(solver,'eidors_default');
0258 solver = eidors_default('get','inv_solve');
0259 end
0260 warning('EIDORS:ParamsObliviousSolver',...
0261 ['The solver %s did not handle the parametrization data properly.\n'...
0262 'The results may be incorrect. Please check the code to verify.'], ...
0263 solver);
0264 end
0265
0266
0267 function b = has_params(s)
0268 b = false;
0269 if isstruct(s)
0270 b = any(ismember(fieldnames(s),supported_params));
0271 end
0272
0273
0274
0275 function nf= num_frames(d0)
0276 if isnumeric( d0 )
0277 nf= size(d0,2);
0278 elseif d0(1).type == 'data';
0279 nf= size( horzcat( d0(:).meas ), 2);
0280 else
0281 error('Problem calculating number of frames. Expecting numeric or data object');
0282 end
0283
0284
0285 function d2= filt_data(inv_model, d0, data_width )
0286 if ~isnumeric( d0 )
0287
0288
0289 d1 = [];
0290 for i=1:length(d0)
0291 if strcmp( d0(i).type, 'data' )
0292 d1 = [d1, d0(i).meas];
0293 else
0294 error('expecting an object of type data');
0295 end
0296 end
0297
0298 else
0299
0300 d1 = d0;
0301 end
0302
0303 d1= double(d1);
0304
0305 if isfield(inv_model.fwd_model,'meas_select') && ...
0306 ~isempty(inv_model.fwd_model.meas_select)
0307
0308
0309 meas_select= inv_model.fwd_model.meas_select;
0310 if size(d1,1) == length(meas_select)
0311 d2= d1(meas_select,:);
0312 elseif size(d1,1) == sum(meas_select==1)
0313 d2= d1;
0314 else
0315 error('inconsistent difference data: (%d ~= %d). Maybe check fwd_model.meas_select', ...
0316 size(d1,1), length(meas_select));
0317 end
0318 else
0319 d2= d1;
0320 end
0321
0322 if nargin==3
0323 d2_width= size(d2,2);
0324 if d2_width == data_width
0325
0326 elseif d2_width == 1
0327 d2= d2(:,ones(1,data_width));
0328 else
0329 error('inconsistent difference data: (%d ~= %d)', ...
0330 d2_width, data_width);
0331 end
0332 end
0333
0334
0335 function do_unit_test
0336 k=0; N=5; nd = 5;
0337
0338 imdl = mk_common_model('d2c2',16);
0339 imdl = select_imdl( imdl, {'Choose NF=2.5'});
0340 mvx = linspace(-0.8,0.8,nd);
0341 [vh,vi] = simulate_movement(mk_image(imdl), [mvx;0*mvx;0.05+0*mvx]);
0342
0343 img= inv_solve(imdl,vh,vi); img.show_slices.img_cols = 5;
0344 k=k+1; subplot(N,1,k); show_slices(img);
0345 unit_test_cmp('inv_solve: 1a', mean(img.elem_data), 3e-3, 1e-3);
0346 unit_test_cmp('inv_solve: 1b', std(img.elem_data), 1.5e-2, 1e-2);
0347
0348 vhm= eidors_obj('data','nn','meas',vh);
0349 img= inv_solve(imdl,vhm,vi);
0350 unit_test_cmp('inv_solve: 2a', mean(img.elem_data), 3e-3, 1e-3);
0351 unit_test_cmp('inv_solve: 2b', std(img.elem_data), 1.5e-2, 1e-2);
0352
0353 img= inv_solve(imdl,vh*ones(1,nd),vi);
0354 unit_test_cmp('inv_solve: 3a', mean(img.elem_data), 3e-3, 1e-3);
0355 unit_test_cmp('inv_solve: 3b', std(img.elem_data), 1.5e-2, 1e-2);
0356
0357 vim= eidors_obj('data','nn','meas',vi);
0358 img= inv_solve(imdl,vhm,vim);
0359 unit_test_cmp('inv_solve: 4a', mean(img.elem_data), 3e-3, 1e-3);
0360 unit_test_cmp('inv_solve: 4b', std(img.elem_data), 1.5e-2, 1e-2);
0361
0362 vhm= eidors_obj('data','nn','meas',vh*ones(1,nd));
0363 img= inv_solve(imdl,vhm,vi);
0364 unit_test_cmp('inv_solve: 5a', mean(img.elem_data), 3e-3, 1e-3);
0365 unit_test_cmp('inv_solve: 5b', std(img.elem_data), 1.5e-2, 1e-2);
0366
0367 vhm(1)= eidors_obj('data','nn','meas',vh*ones(1,2));
0368 vhm(2)= eidors_obj('data','nn','meas',vh*ones(1,nd-2));
0369 img= inv_solve(imdl,vhm,vi);
0370 unit_test_cmp('inv_solve: 6a', mean(img.elem_data), 3e-3, 1e-3);
0371 unit_test_cmp('inv_solve: 6b', std(img.elem_data), 1.5e-2, 1e-2);
0372
0373 vim(1)= eidors_obj('data','nn','meas',vi(:,1:3));
0374 vim(2)= eidors_obj('data','nn','meas',vi(:,4:end));
0375 img= inv_solve(imdl,vhm,vim);
0376 unit_test_cmp('inv_solve: 7a', mean(img.elem_data), 3e-3, 1e-3);
0377 unit_test_cmp('inv_solve: 7b', std(img.elem_data), 1.5e-2, 1e-2);
0378
0379 im2 = imdl; im2.inv_solve.select_parameters = 1:5;
0380 img= inv_solve(im2,vh,vi);
0381 unit_test_cmp('inv_solve: 10', size(img.elem_data), [5,nd]);
0382
0383
0384 im2 = imdl;
0385 im2.inv_solve.scale_solution.offset = 1;
0386 im2.inv_solve.scale_solution.scale = 2;
0387 img= inv_solve(im2,vh,vi); img.show_slices.img_cols = 5;
0388 unit_test_cmp('inv_solve: 20a', mean(img.elem_data), 1.006, 2e-3);
0389 unit_test_cmp('inv_solve: 20b', std(img.elem_data), 3e-2, 1e-2);
0390 im2.inv_solve.calc_solution_error = 1;
0391 img= inv_solve(im2,vh,vi);
0392 unit_test_cmp('inv_solve: 20e', mean(img.elem_data), 1.006, 2e-3);
0393
0394 im2.inv_solve.scale_solution.offset = 0;
0395 d = interp_mesh( imdl.fwd_model); d= sqrt(sum(d.^2,2));
0396 im2.inv_solve.scale_solution.scale = spdiags(1-d,0,length(d),length(d));
0397 img= inv_solve(imdl,vh,vi); img.show_slices.img_cols = 5;
0398 k=k+1; subplot(N,1,k); show_slices(img);
0399
0400 im2 = select_imdl(imdl, {'Nodal GN dif'} );
0401 img= inv_solve(im2,vh,vi);
0402 unit_test_cmp('inv_solve: 30a', mean(img.node_data), 3e-3, 1e-3);
0403 unit_test_cmp('inv_solve: 30b', std(img.node_data), 1.5e-2, 1e-2);
0404
0405 im2.inv_solve.scale_solution.offset = 1;
0406 im2.inv_solve.scale_solution.scale = 2;
0407 img= inv_solve(im2,vh,vi); img.show_slices.img_cols = 5;
0408 unit_test_cmp('inv_solve: 31a', mean(img.node_data), 1.006, 2e-3);
0409 unit_test_cmp('inv_solve: 31b', std(img.node_data), 3e-2, 1.5e-2);
0410
0411 im2 = select_imdl(imdl, {'Basic GN abs'} );
0412 im2.inv_solve.calc_solution_error = 0;
0413 img= inv_solve(im2,vi(:,1));
0414 unit_test_cmp('inv_solve: 40a', mean(img.elem_data), 1.004, 1e-3);
0415 unit_test_cmp('inv_solve: 40b', std(img.elem_data), 1.5e-2, 1e-2);
0416 im2.inv_solve.calc_solution_error = 1;
0417 img= inv_solve(im2,vi(:,1));
0418 unit_test_cmp('inv_solve: 40e', mean(img.elem_data), 1.004, 1e-3);
0419
0420