0001 function img= inv_solve_core( inv_model, data0, data1);
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
0059
0060
0061
0062
0063
0064
0065
0066
0067
0068
0069
0070
0071
0072
0073
0074
0075
0076
0077
0078
0079
0080
0081
0082
0083
0084
0085
0086
0087
0088
0089
0090
0091
0092
0093
0094
0095
0096
0097
0098
0099
0100
0101
0102
0103
0104
0105
0106
0107
0108
0109
0110
0111
0112
0113
0114
0115
0116
0117
0118
0119
0120
0121
0122
0123
0124
0125
0126
0127
0128
0129
0130
0131
0132
0133
0134
0135
0136
0137
0138
0139
0140
0141
0142
0143
0144
0145
0146
0147
0148
0149
0150
0151
0152
0153
0154
0155
0156
0157
0158
0159
0160
0161
0162
0163
0164
0165
0166
0167
0168
0169
0170
0171
0172
0173
0174
0175
0176
0177
0178
0179
0180
0181
0182
0183
0184
0185
0186
0187
0188
0189
0190
0191
0192
0193
0194
0195
0196
0197
0198
0199
0200
0201
0202
0203
0204
0205
0206
0207
0208
0209
0210
0211
0212
0213
0214
0215
0216
0217
0218
0219
0220
0221
0222
0223
0224
0225
0226
0227
0228
0229
0230
0231
0232
0233
0234
0235
0236
0237
0238
0239
0240
0241
0242
0243
0244 if ischar(inv_model) && strcmp(inv_model,'UNIT_TEST') && (nargin == 1); do_unit_test; return; end
0245 if ischar(inv_model) && strcmp(inv_model,'UNIT_TEST') && (nargin == 2); do_unit_test(data0); return; end
0246
0247
0248 if nargin == 3
0249 n_frames = max(count_data_frames(data0),count_data_frames(data1));
0250 else
0251 n_frames = count_data_frames(data0);
0252 end
0253 opt = parse_options(inv_model, n_frames);
0254
0255
0256
0257
0258
0259
0260 [inv_model, opt] = append_c2f_background(inv_model, opt);
0261
0262
0263
0264
0265
0266 if isfield(inv_model, 'jacobian_bkgnd')
0267 inv_model = rmfield(inv_model,'jacobian_bkgnd');
0268 end
0269 inv_model.jacobian_bkgnd.value = 1;
0270 img = mk_image( inv_model );
0271 img.inv_model = inv_model;
0272 img = data_mapper(img);
0273
0274 img = init_elem_data(img, opt);
0275
0276
0277
0278 img = map_img(img, opt.elem_working);
0279
0280
0281 if nargin == 3
0282 test = strcmp(opt.meas_working{1}, {'apparent_resistivity','log_apparent_resistivity', 'log10_apparent_resitivity'});
0283 errstr= ['meas_working = ''' opt.meas_working{1} ''' not yet supported for difference solutions'];
0284 assert(all(~test), errstr);
0285 for i = 1:length(opt.elem_output)
0286 assert(any(strcmp(opt.elem_output{i}, {'conductivity','resistivity','movement'})), ...
0287 ['elem_output = {' strjoin(opt.elem_output,', ') '} but difference solver log normal outputs are not supported']);
0288 end
0289
0290 nil = struct;
0291 if isstruct(data0)
0292 nil.meas = data0(1).meas(:,1)*0;
0293 else
0294 nil.meas = data0(:,1)*0;
0295 end
0296 nil.type = 'data';
0297 nil.current_params = opt.meas_input;
0298 [dv, opt, err] = update_dv_core(img, nil, 1, opt);
0299
0300
0301 data0 = bsxfun(@plus,calc_difference_data( data0, data1, inv_model.fwd_model ), dv);
0302
0303 assert(strcmp(inv_model.reconst_type, 'difference'), ...
0304 ['expected inv_model.reconst_type = ''difference'' not ' inv_model.reconst_type]);
0305 else
0306 assert(strcmp(inv_model.reconst_type, 'absolute'), ...
0307 ['expected inv_model.reconst_type = ''absolute'' not ' inv_model.reconst_type]);
0308 end
0309
0310
0311 if ~isstruct(data0)
0312 d = data0;
0313 data0 = struct;
0314 data0.meas = d;
0315 data0.type = 'data';
0316 end
0317 data0.current_params = opt.meas_input;
0318
0319
0320 W = init_meas_icov(inv_model, opt);
0321 [N, dN] = init_normalization(inv_model.fwd_model, data0, opt);
0322
0323
0324 img0 = img;
0325 hps2RtR = 0; alpha = 0; k = 0; sx = 0; r = 0; stop = 0;
0326 hpt2LLt = update_hpt2LLt(inv_model, data0, k, opt);
0327 residuals = zeros(opt.max_iterations,3);
0328 dxp = 0;
0329 [dv, opt] = update_dv([], img, data0, N, opt);
0330 de = update_de([], img, img0, opt);
0331 if opt.verbose >= 5
0332 dvall = ones(size(data0.meas,1),opt.max_iterations+1)*NaN;
0333 end
0334 while 1
0335 if opt.verbose >= 1
0336 if k == 0
0337 fprintf(' inv_solve_core: start up\n');
0338 else
0339 fprintf(' inv_solve_core: iteration %d (residual = %g)\n', k, r(k,1));
0340 end
0341 end
0342
0343
0344
0345 [J, opt] = update_jacobian(img, dN, k, opt);
0346
0347
0348 hps2RtR = update_hps2RtR(inv_model, J, k, img, opt);
0349
0350
0351
0352 dx = update_dx(J, W, hps2RtR, hpt2LLt, dv, de, opt);
0353
0354 beta = update_beta(dx, dxp, sx, opt);
0355 beta_all(k+1)=beta;
0356
0357 sx = update_sx(dx, beta, sx, opt);
0358 if k ~= 0
0359 dxp = dx;
0360 end
0361
0362
0363 plot_dx_and_svd_elem(J, W, hps2RtR, k, sx, dx, img, opt);
0364
0365
0366
0367
0368
0369 [alpha, img, dv, opt] = update_alpha(img, sx, data0, img0, N, W, hps2RtR, hpt2LLt, k, dv, opt);
0370 alpha_all(k+1) = alpha;
0371
0372
0373 [img, dv] = update_img_using_limits(img, img0, data0, N, dv, opt);
0374
0375
0376
0377 [dv, opt] = update_dv(dv, img, data0, N, opt);
0378 de = update_de(de, img, img0, opt);
0379 if opt.verbose >= 5
0380 dvall(:,k+1) = dv;
0381 show_meas_err(dvall, data0, k, N, W, opt);
0382 end
0383 show_fem_iter(k, img, inv_model, stop, opt);
0384
0385
0386 [stop, k, r, img] = update_residual(dv, img, de, W, hps2RtR, hpt2LLt, k, r, alpha, sx, opt);
0387 if stop
0388 if stop == -1
0389 alpha_all(k) = 0;
0390 end
0391 break;
0392 end
0393 end
0394 img0 = strip_c2f_background(img0, opt);
0395 [img, opt] = strip_c2f_background(img, opt);
0396
0397 if isfield(inv_model, 'rec_model')
0398 img.fwd_model = inv_model.rec_model;
0399 end
0400 if opt.verbose >= 1
0401 if k==1; itrs=''; else itrs='s'; end
0402 fprintf(' %d fwd_solves required for this solution in %d iteration%s\n', ...
0403 opt.fwd_solutions, k, itrs);
0404 end
0405
0406 img = map_img(img, opt.elem_output);
0407 if strcmp(inv_model.reconst_type, 'difference')
0408 img0 = map_img(img0, opt.elem_output);
0409 img.elem_data = img.elem_data - img0.elem_data;
0410 end
0411 img.meas_err = dv;
0412 if opt.return_working_variables
0413 img.inv_solve_core.J = J;
0414 img.inv_solve_core.dx = dx;
0415 img.inv_solve_core.sx = sx;
0416 img.inv_solve_core.alpha = alpha_all;
0417 img.inv_solve_core.beta = beta_all;
0418 img.inv_solve_core.k = k;
0419 img.inv_solve_core.r = r(1:(k+1),:);
0420 img.inv_solve_core.N = N;
0421 img.inv_solve_core.W = W;
0422 img.inv_solve_core.hps2RtR = hps2RtR;
0423 img.inv_solve_core.dv = dv;
0424 img.inv_solve_core.de = de;
0425 if opt.verbose >= 5
0426 img.inv_solve_core.dvall = dvall;
0427 end
0428 end
0429
0430
0431 function show_meas_err(dvall, data0, k, N, W, opt)
0432 clf;
0433 assert(length(opt.meas_working) == 1,'TODO meas_working len > 1');
0434 subplot(211); bar(dvall(:,k+1)); ylabel(sprintf('dv_k [%s]',opt.meas_working{1})); xlabel('meas #'); title(sprintf('measurement error @ iter=%d',k));
0435 subplot(212); bar(map_meas(dvall(:,k+1),N,opt.meas_working{1}, 'voltage')); ylabel('dv_k [V]'); xlabel('meas #'); title('');
0436 drawnow;
0437 if isfield(opt,'fig_prefix')
0438 print('-dpdf',sprintf('%s-meas_err%d',opt.fig_prefix,k));
0439 print('-dpng',sprintf('%s-meas_err%d',opt.fig_prefix,k));
0440 saveas(gcf,sprintf('%s-meas_err%d.fig',opt.fig_prefix,k));
0441 end
0442 drawnow;
0443
0444
0445 function n_frames = count_data_frames(data1)
0446 if isnumeric(data1)
0447 n_frames = size(data1,2);
0448 else
0449 n_frames = size(horzcat(data1(:).meas),2);
0450 end
0451
0452 function img = init_elem_data(img, opt)
0453 if opt.verbose > 1
0454 fprintf(' setting prior elem_data\n');
0455 end
0456 ne2 = 0;
0457 img.elem_data = zeros(sum([opt.elem_len{:}]),sum([opt.n_frames{:}]));
0458 for i=1:length(opt.elem_prior)
0459 ne1 = ne2+1;
0460 ne2 = ne1+opt.elem_len{i}-1;
0461 if opt.verbose > 1
0462 if length(opt.prior_data{i}) == 1
0463 fprintf(' %d x %s: %0.1f\n',opt.elem_len{i},opt.elem_prior{i}, opt.prior_data{i});
0464 else
0465 fprintf(' %d x %s: ...\n',opt.elem_len{i},opt.elem_prior{i});
0466 if length(opt.prior_data{i}) ~= opt.elem_len{i}
0467 error(sprintf('expected %d elem, got %d elem in elem_prior', ...
0468 opt.elem_len{i}, length(opt.prior_data{i})));
0469 end
0470 end
0471 end
0472 img.params_sel(i) = {ne1:ne2};
0473 img.elem_data(img.params_sel{i},:) = opt.prior_data{i};
0474 end
0475 img.current_params = opt.elem_prior;
0476
0477 function W = init_meas_icov(inv_model, opt)
0478 W = 1;
0479 if opt.calc_meas_icov
0480 if opt.verbose > 1
0481 disp(' calc measurement inverse covariance W');
0482 end
0483 W = calc_meas_icov( inv_model );
0484 end
0485 err_if_inf_or_nan(W, 'init_meas_icov');
0486
0487 function [N, dN] = init_normalization(fmdl, data0, opt)
0488
0489 N = 1;
0490 dN = 1;
0491 vh1.meas = 1;
0492 if ~iscell(opt.meas_input) || ~iscell(opt.meas_working)
0493 error('expected cell array for meas_input and meas_working');
0494 end
0495
0496 assert(length(opt.meas_input) == length(opt.meas_working), 'meas_input and meas_working lengths must match');
0497 assert(length(opt.meas_working) == 1, 'TODO only supports a single type of measurements');
0498 go = any(strcmp({opt.meas_input{1}, opt.meas_working{1}},'apparent_resistivity'));
0499 go = go || any(strcmp({opt.meas_input{1}, opt.meas_working{1}},'log_apparent_resistivity'));
0500 go = go || any(strcmp({opt.meas_input{1}, opt.meas_working{1}},'log10_apparent_resistivity'));
0501 if go
0502 if opt.verbose > 1
0503 disp([' calc measurement normalization matrix N (voltage -> ' opt.meas_working{1} ')']);
0504 end
0505
0506 img1 = mk_image(fmdl,1);
0507 vh1 = fwd_solve(img1);
0508 N = spdiag(1./vh1.meas);
0509 err_if_inf_or_nan(N, 'init_normalization: N');
0510 end
0511 if go && (opt.verbose > 1)
0512 disp([' calc Jacobian normalization matrix dN (voltage -> ' opt.meas_working{1} ')']);
0513 end
0514
0515 assert(length(opt.meas_working)==1, 'only supports single measurement type at a time');
0516 data0 = map_meas_struct(data0, N, 'voltage');
0517 switch opt.meas_working{1}
0518 case 'apparent_resistivity'
0519 dN = da_dv(data0.meas, vh1.meas);
0520 case 'log_apparent_resistivity'
0521 dN = dloga_dv(data0.meas, vh1.meas);
0522 case 'log10_apparent_resistivity'
0523 dN = dlog10a_dv(data0.meas, vh1.meas);
0524 case 'voltage'
0525 dN = dv_dv(data0.meas, vh1.meas);
0526 case 'log_voltage'
0527 dN = dlogv_dv(data0.meas, vh1.meas);
0528 case 'log10_voltage'
0529 dN = dlog10v_dv(data0.meas, vh1.meas);
0530 otherwise
0531 error('hmm');
0532 end
0533 err_if_inf_or_nan(dN, 'init_normalization: dN');
0534
0535
0536
0537 function [stop, k, r, img] = update_residual(dv, img, de, W, hps2RtR, hpt2LLt, k, r, alpha, sx, opt)
0538 stop = 0;
0539
0540
0541 if k == 0
0542 r = ones(opt.max_iterations, 3)*NaN;
0543 r_km1 = inf;
0544 r_1 = inf;
0545 else
0546 r_km1 = r(k, 1);
0547 r_1 = r(1, 1);
0548 end
0549 [r_k m_k e_k] = feval(opt.residual_func, dv, de, W, hps2RtR, hpt2LLt);
0550
0551 r(k+1,1:3) = [r_k m_k e_k];
0552
0553
0554 if opt.verbose > 1
0555 fprintf(' calc residual\n');
0556 if k == 0
0557 fprintf(' stop @ max iter = %d, tol = %0.3g (%0.3g%%), dtol = %0.3g%% (after %d iter)\n', ...
0558 opt.max_iterations, opt.tol, opt.tol/r_k*100, opt.dtol*100, opt.dtol_iter);
0559 fprintf(' r =%0.3g = %0.3g meas + %0.3g elem\n', r_k, m_k, e_k);
0560 else
0561 fprintf(' r =%0.3g (%0.03g%%) = %0.3g meas (%0.03g%%) + %0.3g elem (%0.3g%%)\n', ...
0562 r_k, r_k/r(1,1)*100, m_k, m_k/r(1,2)*100, e_k, e_k/r(1,3)*100);
0563 dr = (r_k - r_km1);
0564 fprintf(' dr=%0.3g (%0.3g%%)\n', dr, dr/r_1*100);
0565 end
0566 end
0567 if opt.plot_residuals
0568
0569 r(k+1,2:3) = [sum(sum(dv.^2,1))/2 sum(sum(de.^2,1))/2];
0570 if k > 0
0571 clf;
0572 x = 1:(k+1);
0573 y = r(x, :);
0574 y = y ./ repmat(max(y,[],1),size(y,1),1) * 100;
0575 plot(x-1, y, 'o-', 'linewidth', 2, 'MarkerSize', 10);
0576 title('residuals');
0577 axis tight;
0578 ylabel('residual (% of max)');
0579 xlabel('iteration');
0580 set(gca, 'xtick', x);
0581 set(gca, 'xlim', [0 max(x)-1]);
0582 legend('residual','meas. misfit','prior misfit');
0583 legend('Location', 'EastOutside');
0584 drawnow;
0585 if isfield(opt,'fig_prefix')
0586 print('-dpdf',sprintf('%s-r',opt.fig_prefix));
0587 print('-dpng',sprintf('%s-r',opt.fig_prefix));
0588 saveas(gcf,sprintf('%s-r.fig',opt.fig_prefix));
0589 end
0590 end
0591 end
0592
0593
0594 if r_k > r_km1
0595 if opt.verbose > 1
0596 fprintf(' terminated at iteration %d (bad step, returning previous iteration''s result)\n',k);
0597 end
0598 img.elem_data = img.elem_data - alpha * sx;
0599 stop = -1;
0600 elseif k >= opt.max_iterations
0601 if opt.verbose > 1
0602 fprintf(' terminated at iteration %d (max iterations)\n',k);
0603 end
0604 stop = 1;
0605 elseif r_k < opt.tol + opt.ntol
0606 if opt.verbose > 1
0607 fprintf(' terminated at iteration %d\n',k);
0608 fprintf(' residual tolerance (%0.3g) achieved\n', opt.tol + opt.ntol);
0609 end
0610 stop = 1;
0611 elseif (k >= opt.dtol_iter) && ((r_k - r_km1)/r_1 > opt.dtol - 2*opt.ntol)
0612 if opt.verbose > 1
0613 fprintf(' terminated at iteration %d (iterations not improving)\n', k);
0614 fprintf(' residual slope tolerance (%0.3g%%) exceeded\n', (opt.dtol - 2*opt.ntol)*100);
0615 end
0616 stop = 1;
0617 end
0618 if ~stop
0619
0620 k = k+1;
0621 end
0622
0623
0624
0625 function beta = update_beta(dx_k, dx_km1, sx_km1, opt);
0626 if isfield(opt, 'beta_func')
0627 if opt.verbose > 1
0628 try beta_str = func2str(opt.beta_func);
0629 catch
0630 try
0631 beta_str = opt.beta_func;
0632 catch
0633 beta_str = 'unknown';
0634 end
0635 end
0636 end
0637 beta= feval(opt.beta_func, dx_k, dx_km1, sx_km1);
0638 else
0639 beta_str = '<none>';
0640 beta = 0;
0641 end
0642 if opt.verbose > 1
0643 str = sprintf(' calc beta (%s)=%0.3f\n', beta_str, beta);
0644 end
0645
0646
0647
0648
0649
0650
0651 function sx = update_sx(dx, beta, sx_km1, opt);
0652 sx = dx + beta * sx_km1;
0653 if(opt.verbose > 1)
0654 nsx = norm(sx);
0655 nsxk = norm(sx_km1);
0656 fprintf( ' update step dx, beta=%0.3g, ||dx||=%0.3g\n', beta, nsx);
0657 if nsxk ~= 0
0658 fprintf( ' acceleration d||dx||=%0.3g\n', nsx-nsxk);
0659
0660 ddx = norm(sx/nsx-sx_km1/nsxk);
0661 fprintf( ' direction change ||ddx||=%0.3g (%0.3g°)\n', ddx, 2*asind(ddx/2));
0662 end
0663 end
0664
0665
0666 function hps2RtR = update_hps2RtR(inv_model, J, k, img, opt)
0667 if k==0
0668 k=1;
0669 end
0670
0671
0672
0673 if ~opt.calc_RtR_prior
0674 error('no RtR calculation mechanism, set imdl.inv_solve_core.RtR_prior or imdl.RtR_prior');
0675 end
0676 if opt.verbose > 1
0677 disp(' calc hp^2 R^t R');
0678 end
0679 hp2 = calc_hyperparameter( inv_model )^2;
0680 net = sum([opt.elem_len{:}]);
0681 RtR = sparse(net,net);
0682 esi = 0; eei = 0;
0683 for i = 1:size(opt.RtR_prior,1)
0684 esi = eei + 1;
0685 eei = eei + opt.elem_len{i};
0686 esj = 0; eej = 0;
0687 for j = 1:size(opt.RtR_prior,2)
0688 esj = eej + 1;
0689 eej = eej + opt.elem_len{j};
0690 if isempty(opt.RtR_prior{i,j})
0691 continue;
0692 end
0693
0694
0695
0696 hp=opt.hyperparameter_spatial{i,j};
0697 if length(hp) > k
0698 hp=hp(k);
0699 else
0700 hp=hp(end);
0701 end
0702
0703 try RtR_str = func2str(opt.RtR_prior{i,j});
0704 catch
0705 try
0706 RtR_str = opt.RtR_prior{i,j};
0707 catch
0708 RtR_str = 'unknown';
0709 end
0710 end
0711 if opt.verbose > 1
0712 fprintf(' {%d,%d} regularization RtR (%s), ne=%dx%d, hp=%0.4g\n', i,j,RtR_str,eei-esi+1,eej-esj+1,hp*sqrt(hp2));
0713 end
0714 imgt = map_img(img, opt.elem_working{i});
0715 inv_modelt = inv_model;
0716 inv_modelt.RtR_prior = opt.RtR_prior{i,j};
0717 if strcmp(RtR_str, 'prior_noser')
0718 if i ~= j
0719 error('noser for off diagonal prior (RtR) is undefined')
0720 end
0721 exponent= 0.5; try exponent = inv_model.prior_noser.exponent; end; try exponent = inv_model.prior_noser.exponent{j}; end
0722 ss = sum(J(:,esj:eej).^2,1)';
0723 Reg = spdiags( ss.^exponent, 0, opt.elem_len{j}, opt.elem_len{j});
0724 RtR(esi:eei, esj:eej) = hp.^2 * Reg;
0725 else
0726 RtR(esi:eei, esj:eej) = hp.^2 * calc_RtR_prior_wrapper(inv_modelt, imgt, opt);
0727 end
0728 end
0729 end
0730 hps2RtR = hp2*RtR;
0731
0732
0733 function hpt2LLt = update_hpt2LLt(inv_model, data0, k, opt)
0734 if k==0
0735 k=1;
0736 end
0737 if ~opt.calc_LLt_prior
0738 error('no LLt calculation mechanism, set imdl.inv_solve_core.LLt_prior or imdl.LLt_prior');
0739 end
0740 if opt.verbose > 1
0741 disp(' calc hp^2 L L^t');
0742 end
0743 hp2 = 1;
0744 nmt = sum([opt.n_frames{:}]);
0745 LLt = sparse(nmt,nmt);
0746 msi = 0; mei = 0;
0747 for i = 1:size(opt.LLt_prior,1)
0748 msi = mei + 1;
0749 mei = mei + opt.n_frames{i};
0750 msj = 0; mej = 0;
0751 for j = 1:size(opt.LLt_prior,2)
0752 msj = mej + 1;
0753 mej = mej + opt.n_frames{j};
0754 if isempty(opt.LLt_prior{i,j})
0755 continue;
0756 end
0757
0758
0759
0760 hp=opt.hyperparameter_temporal{i,j};
0761 if length(hp) > k
0762 hp=hp(k);
0763 else
0764 hp=hp(end);
0765 end
0766
0767 try LLt_str = func2str(opt.LLt_prior{i,j});
0768 catch
0769 try
0770 LLt_str = opt.LLt_prior{i,j};
0771 if isnumeric(LLt_str)
0772 if LLt_str == eye(size(LLt_str))
0773 LLt_str = 'eye';
0774 else
0775 LLt_str = sprintf('array, norm=%0.1g',norm(LLt_str));
0776 end
0777 end
0778 catch
0779 LLt_str = 'unknown';
0780 end
0781 end
0782 if opt.verbose > 1
0783 fprintf(' {%d,%d} regularization LLt (%s), frames=%dx%d, hp=%0.4g\n', i,j,LLt_str,mei-msi+1,mej-msj+1,hp*sqrt(hp2));
0784 end
0785 inv_modelt = inv_model;
0786 inv_modelt.LLt_prior = opt.LLt_prior{i,j};
0787 LLt(msi:mei, msj:mej) = hp.^2 * calc_LLt_prior( data0, inv_modelt );
0788 end
0789 end
0790 hpt2LLt = hp2*LLt;
0791
0792 function plot_dx_and_svd_elem(J, W, hps2RtR, k, sx, dx, img, opt)
0793 if(opt.verbose >= 5)
0794
0795 clf;
0796 imgb=img;
0797 imgb.elem_data = dx;
0798 imgb.current_params = opt.elem_working;
0799 imgb.is_dx_plot = 1;
0800 if isfield(imgb.inv_model,'rec_model')
0801 imgb.fwd_model = imgb.inv_model.rec_model;
0802 end
0803 feval(opt.show_fem,imgb,1);
0804 title(sprintf('dx @ iter=%d',k));
0805 drawnow;
0806 if isfield(opt,'fig_prefix')
0807 print('-dpng',sprintf('%s-dx%d',opt.fig_prefix,k));
0808 print('-dpdf',sprintf('%s-dx%d',opt.fig_prefix,k));
0809 saveas(gcf,sprintf('%s-dx%d.fig',opt.fig_prefix,k));
0810 end
0811 end
0812 if opt.verbose < 8
0813 return;
0814 end
0815
0816 if ~isfield(img, 'params_sel')
0817 img.params_sel = {1:length(img.elem_data)};
0818 end
0819 if ~isfield(img, 'current_params')
0820 img.current_params = 'conductivity';
0821 end
0822 if ~iscell(img.current_params)
0823 img.current_params = {img.current_params};
0824 end
0825
0826 cols=length(opt.elem_working);
0827 if norm(sx - dx) < range(dx)/max(dx)*0.01
0828 rows=2;
0829 else
0830 rows=3;
0831 end
0832 clf;
0833 for i=1:cols
0834 if 1
0835 hp=opt.hyperparameter_spatial{i};
0836 if k ~= 0 && k < length(hp)
0837 hp = hp(k);
0838 else
0839 hp = hp(end);
0840 end
0841 else
0842 hp = [];
0843 end
0844 sel=img.params_sel{i};
0845 str=strrep(img.current_params{i},'_',' ');
0846 plot_svd(J(:,sel), W, hps2RtR(sel,sel), k, hp); xlabel(str);
0847 drawnow;
0848 if isfield(opt,'fig_prefix')
0849 print('-dpdf',sprintf('%s-svd%d-%s',opt.fig_prefix,k,img.current_params{i}));
0850 print('-dpng',sprintf('%s-svd%d-%s',opt.fig_prefix,k,img.current_params{i}));
0851 saveas(gcf,sprintf('%s-svd%d-%s.fig',opt.fig_prefix,k,img.current_params{i}));
0852 end
0853 end
0854 clf;
0855 for i=1:cols
0856 if 1
0857 hp=opt.hyperparameter_spatial{i};
0858 if k ~= 0 && k < length(hp)
0859 hp = hp(k);
0860 else
0861 hp = hp(end);
0862 end
0863 else
0864 hp = [];
0865 end
0866 subplot(rows,cols,i);
0867 sel=img.params_sel{i};
0868 str=strrep(img.current_params{i},'_',' ');
0869 plot_svd(J(:,sel), W, hps2RtR(sel,sel), k, hp); xlabel(str);
0870 subplot(rows,cols,cols+i);
0871 bar(dx(sel)); ylabel(['dx: ' str]);
0872 if rows > 2
0873 subplot(rows,cols,2*cols+i);
0874 bar(sx(sel)); ylabel(['sx: ' str]);
0875 end
0876 end
0877 drawnow;
0878 if isfield(opt,'fig_prefix')
0879 print('-dpdf',sprintf('%s-svd%d',opt.fig_prefix,k));
0880 print('-dpng',sprintf('%s-svd%d',opt.fig_prefix,k));
0881 saveas(gcf,sprintf('%s-svd%d.fig',opt.fig_prefix,k));
0882 end
0883
0884 function plot_svd(J, W, hps2RtR, k, hp)
0885 if nargin < 5
0886 hp = [];
0887 end
0888
0889 [~,s1,~]=svd(J'*W*J); s1=sqrt(diag(s1));
0890 [~,s2,~]=svd(J'*W*J + hps2RtR); s2=sqrt(diag(s2));
0891 h=semilogy(s1,'bx'); axis tight; set(h,'LineWidth',2);
0892 hold on; h=semilogy(s2,'go'); axis tight; set(h,'LineWidth',2); hold off;
0893 xlabel('k'); ylabel('value \sigma');
0894 title(sprintf('singular values of J at iteration %d',k));
0895 legend('J^T J', 'J^T J + \lambda^2 R^T R'); legend location best;
0896
0897
0898
0899
0900
0901
0902
0903 if length(hp)==1
0904 h=line([1 length(s1)],[hp hp]);
0905 ly=10^(log10(hp)-0.05*range(log10([s1;s2])));
0906 text(length(s1)/2,ly,sprintf('\\lambda = %0.4g', hp));
0907
0908 end
0909 set(h,'LineStyle','-.'); set(h,'LineWidth',2);
0910 set(gca,'YMinorTick','on', 'YMinorGrid', 'on', 'YGrid', 'on');
0911
0912
0913
0914 function RtR = calc_RtR_prior_wrapper(inv_model, img, opt)
0915 RtR = calc_RtR_prior( inv_model );
0916 if size(RtR,1) < length(img.elem_data)
0917 ne = length(img.elem_data) - size(RtR,1);
0918
0919 for i=1:ne
0920 RtR(end+1:end+1, end+1:end+1) = RtR(1,1);
0921 end
0922 if opt.verbose > 1
0923 fprintf(' c2f: adjusting RtR by appending %d rows/cols\n', ne);
0924 disp( ' TODO move this fix, or something like it to calc_RtR_prior -- this fix is a quick HACK to get things to run...');
0925 end
0926 end
0927
0928
0929 function [J, opt] = update_jacobian(img, dN, k, opt)
0930 img.elem_data = img.elem_data(:,1);
0931 base_types = map_img_base_types(img);
0932 imgb = map_img(img, base_types);
0933 imgb = feval(opt.update_img_func, imgb, opt);
0934
0935
0936 if any(strcmp(map_img_base_types(img), 'movement')) && any(strcmp(opt.meas_working, 'apparent_resistivity'))
0937 imgh = map_img(imgb, 'conductivity');
0938 imgh.elem_data = imgh.elem_data*0 +1;
0939 vh = fwd_solve(imgh); vh = vh.meas;
0940 dN = da_dv(1,vh);
0941 opt.fwd_solutions = opt.fwd_solutions +1;
0942 end
0943 ee = 0;
0944 pp = fwd_model_parameters(imgb.fwd_model);
0945 J = zeros(pp.n_meas,sum([opt.elem_len{:}]));
0946 for i=1:length(opt.jacobian)
0947 if(opt.verbose > 1)
0948 if isnumeric(opt.jacobian{i})
0949 J_str = '[fixed]';
0950 elseif isa(opt.jacobian{i}, 'function_handle')
0951 J_str = func2str(opt.jacobian{i});
0952 else
0953 J_str = opt.jacobian{i};
0954 end
0955 if i == 1 fprintf(' calc Jacobian J(x) = ');
0956 else fprintf(' + '); end
0957 fprintf('(%s,', J_str);
0958 end
0959
0960 es = ee+1;
0961 ee = es+opt.elem_len{i}-1;
0962
0963 S = feval(opt.calc_jacobian_scaling_func{i}, imgb.elem_data(es:ee));
0964
0965
0966
0967 imgt = imgb;
0968 if strcmp(base_types{i}, 'conductivity')
0969 imgt = map_img(img, 'conductivity');
0970 end
0971 imgt.fwd_model.jacobian = opt.jacobian{i};
0972 Jn = calc_jacobian( imgt );
0973 J(:,es:ee) = dN * Jn * S;
0974 if opt.verbose > 1
0975 tmp = zeros(1,size(J,2));
0976 tmp(es:ee) = 1;
0977 tmp(opt.elem_fixed) = 0;
0978 fprintf(' %d DoF, %d meas, %s)\n', sum(tmp), size(J,1), func2str(opt.calc_jacobian_scaling_func{i}));
0979 end
0980 if opt.verbose >= 5
0981 clf;
0982 t=axes('Position',[0 0 1 1],'Visible','off');
0983 text(0.03,0.1,sprintf('update\\_jacobian (%s), iter=%d', strrep(J_str,'_','\_'), k),'FontSize',20,'Rotation',90);
0984 for y=0:1
0985 if y == 0; D = Jn; else D = J(:,es:ee); end
0986 axes('units', 'normalized', 'position', [ 0.13 0.62-y/2 0.8 0.3 ]);
0987 imagesc(D);
0988 if y == 0; ylabel('meas (1)'); xlabel(['elem (' strrep(base_types{i},'_','\_') ')']);
0989 else ylabel('meas (dN)'); xlabel(['elem (' strrep(opt.elem_working{i},'_','\_') ')']);
0990 end
0991 os = get(gca, 'Position'); c=colorbar('southoutside');
0992 set(gca, 'Position', os);
0993
0994 cP = get(c,'Position'); set(c,'Position', [0.13 0.54-y/2 0.8 0.010]);
0995 axes('units', 'normalized', 'position', [ 0.93 0.62-y/2 0.05 0.3 ]);
0996 barh(sqrt(sum(D.^2,2))); axis tight; axis ij; set(gca, 'ytick', [], 'yticklabel', []);
0997 axes('units', 'normalized', 'position', [ 0.13 0.92-y/2 0.8 0.05 ]);
0998 bar(sqrt(sum(D.^2,1))); axis tight; set(gca, 'xtick', [], 'xticklabel', []);
0999 end
1000 drawnow;
1001 if isfield(opt,'fig_prefix')
1002 print('-dpng',sprintf('%s-J%d-%s',opt.fig_prefix,k,strrep(J_str,'_','')));
1003 print('-dpdf',sprintf('%s-J%d-%s',opt.fig_prefix,k,strrep(J_str,'_','')));
1004 saveas(gcf,sprintf('%s-J%d-%s.fig',opt.fig_prefix,k,strrep(J_str,'_','')));
1005 end
1006 end
1007 end
1008 if opt.verbose >= 4
1009
1010 try
1011 clf;
1012 imgb.elem_data = log(sqrt(sum(J.^2,1)));
1013 for i = 1:length(imgb.current_params)
1014 imgb.current_params{i} = [ 'log_sensitivity_' imgb.current_params{i} ];
1015 end
1016 if isfield(imgb.inv_model,'rec_model')
1017 imgb.fwd_model = imgb.inv_model.rec_model;
1018 end
1019 feval(opt.show_fem,imgb,1);
1020 title(sprintf('sensitivity @ iter=%d',k));
1021 drawnow;
1022 if isfield(opt,'fig_prefix')
1023 print('-dpng',sprintf('%s-Js%d-%s',opt.fig_prefix,k,strrep(J_str,'_','')));
1024 print('-dpdf',sprintf('%s-Js%d-%s',opt.fig_prefix,k,strrep(J_str,'_','')));
1025 saveas(gcf,sprintf('%s-Js%d-%s.fig',opt.fig_prefix,k,strrep(J_str,'_','')));
1026 end
1027 catch
1028 end
1029 end
1030
1031
1032
1033
1034
1035
1036
1037
1038
1039
1040
1041 function S = dx_dlogx(x);
1042 S = spdiag(x);
1043 function S = dx_dlog10x(x);
1044 S = spdiag(x * log(10));
1045
1046
1047
1048
1049 function S = dx_dy(x);
1050 S = spdiag(-(x.^2));
1051
1052 function S = dx_dlogy(x);
1053
1054
1055 S = spdiag(-x);
1056 function S = dx_dlog10y(x);
1057
1058
1059 S = spdiag(-x/log(10));
1060
1061
1062
1063
1064
1065
1066
1067
1068
1069
1070
1071
1072
1073
1074 function dN = da_dv(v,vh)
1075 dN = spdiag(1./vh);
1076 function dN = dloga_dv(v,vh)
1077 dN = spdiag(1./v);
1078 function dN = dlog10a_dv(v,vh)
1079 dN = spdiag( 1./(v * log(10)) );
1080 function dN = dv_dv(v,vh)
1081 dN = 1;
1082 function dN = dlogv_dv(v,vh)
1083 dN = dloga_dv(v,vh);
1084 function dN = dlog10v_dv(v,vh)
1085 dN = dlog10a_dv(v, vh);
1086
1087
1088
1089 function [alpha, img, dv, opt] = update_alpha(img, sx, data0, img0, N, W, hps2RtR, hpt2LLt, k, dv, opt)
1090 if k == 0
1091 alpha = 0;
1092 return;
1093 end
1094
1095 if(opt.verbose > 1)
1096 try
1097 ls_str = func2str(opt.line_search_func);
1098 catch
1099 ls_str = opt.line_search_func;
1100 end
1101 fprintf(' line search, alpha = %s\n', ls_str);
1102 end
1103
1104
1105 err_if_inf_or_nan(sx, 'sx (pre-line search)');
1106 err_if_inf_or_nan(img.elem_data, 'img.elem_data (pre-line search)');
1107
1108 if any(size(img.elem_data) ~= size(sx))
1109 error(sprintf('mismatch on elem_data[%d,%d] vs. sx[%d,%d] vector sizes, check c2f_background_fixed',size(img.elem_data), size(sx)));
1110 end
1111
1112 optt = opt;
1113 if isfield(optt,'fig_prefix')
1114 optt.fig_prefix = [opt.fig_prefix '-k' num2str(k)];
1115 end
1116 [alpha, imgo, dv, opto] = feval(opt.line_search_func, img, sx, data0, img0, N, W, hps2RtR, hpt2LLt, dv, optt);
1117 if isfield(opt,'fig_prefix')
1118 opto.fig_prefix = opt.fig_prefix;
1119 end
1120 if ~isempty(imgo)
1121 img = imgo;
1122 else
1123 img.elem_data = img.elem_data + alpha*sx;
1124 end
1125 if ~isempty(opto)
1126 opt = opto;
1127 end
1128
1129 if(opt.verbose > 1)
1130 fprintf(' selected alpha=%0.3g\n', alpha);
1131 end
1132
1133 if (alpha == 0) && (k == 1)
1134 error('first iteration failed to advance solution');
1135 end
1136
1137 function err_if_inf_or_nan(x, str);
1138 if any(any(isnan(x) | isinf(x)))
1139 error(sprintf('bad %s (%d NaN, %d Inf of %d)', ...
1140 str, ...
1141 length(find(isnan(x))), ...
1142 length(find(isinf(x))), ...
1143 length(x(:))));
1144 end
1145
1146
1147 function [img, dv] = update_img_using_limits(img, img0, data0, N, dv, opt)
1148
1149 if opt.max_value ~= +inf
1150 lih = find(img.elem_data > opt.max_value);
1151 img.elem_data(lih) = opt.max_value;
1152 if opt.verbose > 1
1153 fprintf(' limit max(x)=%g for %d elements\n', opt.max_value, length(lih));
1154 end
1155 dv = [];
1156 end
1157 if opt.min_value ~= -inf
1158 lil = find(img.elem_data < opt.min_value);
1159 img.elem_data(lil) = opt.min_value;
1160 if opt.verbose > 1
1161 fprintf(' limit min(x)=%g for %d elements\n', opt.min_value, length(lil));
1162 end
1163 dv = [];
1164 end
1165
1166 [dv, opt] = update_dv(dv, img, data0, N, opt, '(dv out-of-date)');
1167
1168 function de = update_de(de, img, img0, opt)
1169 img0 = map_img(img0, opt.elem_working);
1170 img = map_img(img, opt.elem_working);
1171 err_if_inf_or_nan(img0.elem_data, 'de img0');
1172 err_if_inf_or_nan(img.elem_data, 'de img');
1173
1174
1175
1176 if isempty(de)
1177
1178 de = zeros(size(img0.elem_data));
1179 else
1180 de = img.elem_data - img0.elem_data;
1181 end
1182 de(opt.elem_fixed) = 0;
1183 err_if_inf_or_nan(de, 'de out');
1184
1185 function [dv, opt] = update_dv(dv, img, data0, N, opt, reason)
1186
1187 if ~isempty(dv)
1188 return;
1189 end
1190 if nargin < 7
1191 reason = '';
1192 end
1193 if opt.verbose > 1
1194 disp([' fwd_solve b=Ax ', reason]);
1195 end
1196 [dv, opt, err] = update_dv_core(img, data0, N, opt);
1197
1198
1199
1200 function data = map_meas_struct(data, N, out)
1201 try
1202 current_meas_params = data.current_params;
1203 catch
1204 current_meas_params = 'voltage';
1205 end
1206 data.meas = map_meas(data.meas, N, current_meas_params, out);
1207 data.current_params = out;
1208 err_if_inf_or_nan(data.meas, 'dv meas');
1209
1210
1211 function [dv, opt, err] = update_dv_core(img, data0, N, opt)
1212 data0 = map_meas_struct(data0, N, 'voltage');
1213 img = map_img(img, map_img_base_types(img));
1214 img = feval(opt.update_img_func, img, opt);
1215 img = map_img(img, 'conductivity');
1216
1217 if any(any(N ~= 1)) && any(strcmp(map_img_base_types(img), 'movement'))
1218
1219 imgh=img; imgh.elem_data = imgh.elem_data(:,1)*0 +1;
1220 vh = fwd_solve(imgh); vh = vh.meas;
1221 N = spdiag(1./vh);
1222 opt.fwd_solutions = opt.fwd_solutions +1;
1223 end
1224 data = fwd_solve(img);
1225 opt.fwd_solutions = opt.fwd_solutions +1;
1226 dv = calc_difference_data(data0, data, img.fwd_model);
1227
1228 if nargout >= 3
1229 err = norm(dv)/norm(data0.meas);
1230 else
1231 err = NaN;
1232 end
1233 dv = map_meas(dv, N, 'voltage', opt.meas_working);
1234 err_if_inf_or_nan(dv, 'dv out');
1235
1236 function show_fem_iter(k, img, inv_model, stop, opt)
1237 if (opt.verbose < 4) || (stop == -1)
1238 return;
1239 end
1240 if opt.verbose > 1
1241 str=opt.show_fem;
1242 if isa(str,'function_handle')
1243 str=func2str(str);
1244 end
1245 disp([' ' str '()']);
1246 end
1247 if isequal(opt.show_fem,@show_fem)
1248 img = map_img(img, 'resistivity');
1249 [img, opt] = strip_c2f_background(img, opt, ' ');
1250
1251 if isfield(inv_model, 'rec_model')
1252 img.fwd_model = inv_model.rec_model;
1253 end
1254
1255
1256
1257 img.calc_colours.cb_shrink_move = [0.3,0.6,0.02];
1258 if size(img.elem_data,1) ~= size(img.fwd_model.elems,1)
1259 warning(sprintf('img.elem_data has %d elements, img.fwd_model.elems has %d elems\n', ...
1260 size(img.elem_data,1), ...
1261 size(img.fwd_model.elems,1)));
1262 end
1263 else
1264 img = map_img(img, opt.elem_output);
1265 [img, opt] = strip_c2f_background(img, opt, ' ');
1266 if isfield(inv_model, 'rec_model')
1267 img.fwd_model = inv_model.rec_model;
1268 end
1269 end
1270 clf; feval(opt.show_fem, img, 1);
1271 title(sprintf('x @ iter=%d',k));
1272 drawnow;
1273 if isfield(opt,'fig_prefix')
1274 print('-dpdf',sprintf('%s-x%d',opt.fig_prefix,k));
1275 print('-dpng',sprintf('%s-x%d',opt.fig_prefix,k));
1276 saveas(gcf,sprintf('%s-x%d.fig',opt.fig_prefix,k));
1277 end
1278
1279 function [ residual meas elem ] = GN_residual(dv, de, W, hps2RtR, hpt2LLt)
1280
1281
1282
1283
1284 Wdv = W*dv;
1285 meas = 0.5 * dv(:)' * Wdv(:);
1286 Rde = hps2RtR * de * hpt2LLt';
1287 elem = 0.5 * de(:)' * Rde(:);
1288 residual = meas + elem;
1289
1290 function residual = meas_residual(dv, de, W, hps2RtR)
1291 residual = norm(dv);
1292
1293
1294
1295
1296
1297
1298
1299
1300
1301
1302
1303
1304
1305
1306
1307
1308
1309
1310
1311
1312
1313
1314
1315
1316
1317
1318
1319
1320
1321
1322
1323
1324
1325
1326
1327
1328
1329
1330
1331
1332
1333
1334
1335
1336
1337
1338
1339
1340
1341
1342
1343
1344
1345
1346
1347
1348
1349
1350
1351
1352
1353
1354
1355
1356
1357
1358
1359
1360
1361 function opt = parse_options(imdl,n_frames)
1362
1363
1364
1365
1366
1367 if isfield(imdl, 'inv_solve_core')
1368 opt = imdl.inv_solve_core;
1369 else
1370 opt = struct;
1371 end
1372
1373
1374
1375
1376
1377 if ~isfield(opt,'verbose')
1378 opt.verbose = 1;
1379 fprintf(' selecting inv_model.inv_solve_core.verbose=1\n');
1380 end
1381 if opt.verbose > 1
1382 fprintf(' verbose = %d\n', opt.verbose);
1383 fprintf(' setting default parameters\n');
1384 end
1385
1386 opt.fwd_solutions = 0;
1387
1388 if ~isfield(opt, 'show_fem')
1389 opt.show_fem = @show_fem;
1390 end
1391
1392 if ~isfield(opt, 'residual_func')
1393 opt.residual_func = @GN_residual;
1394
1395
1396
1397
1398 end
1399
1400
1401 if ~isfield(opt, 'update_func')
1402 opt.update_func = @GN_update;
1403 end
1404 if ~isfield(opt, 'update_method')
1405 opt.update_method = 'cholesky';
1406 end
1407
1408
1409 if ~isfield(opt, 'calc_meas_icov')
1410 opt.calc_meas_icov = 0;
1411 end
1412 if ~isfield(opt, 'calc_RtR_prior')
1413 opt.calc_RtR_prior = 0;
1414 end
1415 if ~isfield(opt, 'calc_LLt_prior')
1416 opt.calc_LLt_prior = 0;
1417 end
1418
1419 if ~isfield(opt, 'calc_hyperparameter')
1420 opt.calc_hyperparameter = 0;
1421 end
1422
1423
1424 if opt.verbose > 1
1425 fprintf(' examining function %s(...) for required arguments\n', func2str(opt.update_func));
1426 end
1427
1428
1429
1430 args = ones(5,1);
1431 if args(2) == 1
1432 opt.calc_meas_icov = 1;
1433 end
1434 if args(3) == 1
1435 opt.calc_hyperparameter = 1;
1436 end
1437 if args(4) == 1
1438 opt.calc_RtR_prior = 1;
1439 end
1440 if args(5) == 1
1441 opt.calc_LLt_prior = 1;
1442 end
1443
1444
1445
1446
1447
1448 if ~isfield(opt, 'max_iterations')
1449 opt.max_iterations = 10;
1450 end
1451 if ~isfield(opt, 'ntol')
1452 opt.ntol = eps;
1453 end
1454 if ~isfield(opt, 'tol')
1455 opt.tol = 0;
1456 end
1457 if ~isfield(opt, 'dtol')
1458
1459
1460
1461 opt.dtol = -1e-4;
1462 end
1463 if opt.dtol > 0
1464 error('dtol must be less than 0 (residual decreases at every iteration)');
1465
1466 end
1467 if ~isfield(opt, 'dtol_iter')
1468
1469 opt.dtol_iter = 0;
1470 end
1471 if ~isfield(opt, 'min_value')
1472 opt.min_value = -inf;
1473 end
1474 if ~isfield(opt, 'max_value')
1475 opt.max_value = +inf;
1476 end
1477
1478 if ~isfield(opt, 'plot_residuals')
1479 if opt.verbose > 2
1480 opt.plot_residuals = 1;
1481 else
1482 opt.plot_residuals = 0;
1483 end
1484 end
1485 if opt.plot_residuals ~= 0
1486 disp(' residual plot (updated per iteration) are enabled, to disable them set');
1487 disp(' inv_model.inv_solve_core.plot_residuals=0');
1488 end
1489
1490
1491 if ~isfield(opt,'line_search_func')
1492
1493 opt.line_search_func = @line_search_onm2;
1494 end
1495 if ~isfield(opt,'line_search_dv_func')
1496 opt.line_search_dv_func = @update_dv_core;
1497
1498 end
1499 if ~isfield(opt,'line_search_de_func')
1500
1501
1502 opt.line_search_de_func = @(img, img0, opt) update_de(1, img, img0, opt);
1503
1504 end
1505
1506
1507 if ~isfield(opt,'line_search_args') || ...
1508 ~isfield(opt.line_search_args, 'perturb')
1509 fmin = 1/4;
1510 opt.line_search_args.perturb = [0 fmin/4 fmin/2 fmin fmin*2 fmin*4];
1511
1512
1513
1514
1515
1516 end
1517
1518 if ~isfield(opt,'line_search_args') || ...
1519 ~isfield(opt.line_search_args, 'plot')
1520 if opt.verbose >= 5
1521 opt.line_search_args.plot = 1;
1522 else
1523 opt.line_search_args.plot = 0;
1524 end
1525 end
1526
1527 if isfield(opt,'fig_prefix') && ...
1528 isfield(opt,'line_search_args') && ...
1529 ~isfield(opt.line_search_args, 'fig_prefix')
1530 opt.line_search_args.fig_prefix = opt.fig_prefix;
1531 end
1532
1533 if opt.line_search_args.plot ~= 0
1534 disp(' line search plots (per iteration) are enabled, to disable them set');
1535 disp(' inv_model.inv_solve_core.line_search_args.plot=0');
1536 end
1537
1538
1539
1540
1541 if ~isfield(opt, 'c2f_background')
1542 if isfield(imdl, 'fwd_model') && isfield(imdl.fwd_model, 'coarse2fine')
1543 opt.c2f_background = -1;
1544 else
1545 opt.c2f_background = 0;
1546 end
1547 end
1548 if ~isfield(opt, 'c2f_background_fixed')
1549 opt.c2f_background_fixed = 1;
1550 end
1551
1552
1553
1554
1555 if ~isfield(opt, 'elem_working')
1556 opt.elem_working = {'conductivity'};
1557 end
1558 if ~isfield(opt, 'elem_prior')
1559 opt.elem_prior = {'conductivity'};
1560 end
1561 if ~isfield(opt, 'elem_output')
1562 opt.elem_output = {'conductivity'};
1563 end
1564 if ~isfield(opt, 'meas_input')
1565 opt.meas_input = 'voltage';
1566 end
1567 if ~isfield(opt, 'meas_working')
1568 opt.meas_working = 'voltage';
1569 end
1570
1571
1572
1573 for i = {'elem_working', 'elem_prior', 'elem_output', 'meas_input', 'meas_working'}
1574
1575
1576 x = opt.(i{1});
1577 if ~iscell(x)
1578 opt.(i{1}) = {x};
1579 end
1580 end
1581 if length(opt.meas_input) > 1
1582 error('imdl.inv_solve_core.meas_input: multiple measurement types not yet supported');
1583 end
1584 if length(opt.meas_working) > 1
1585 error('imdl.inv_solve_core.meas_working: multiple measurement types not yet supported');
1586 end
1587
1588 if ~isfield(opt, 'prior_data')
1589 if isfield(imdl, 'jacobian_bkgnd') && ...
1590 isfield(imdl.jacobian_bkgnd, 'value') && ...
1591 length(opt.elem_prior) == 1
1592 opt.prior_data = {imdl.jacobian_bkgnd.value};
1593 else
1594 error('requires inv_model.inv_solve_core.prior_data');
1595 end
1596 end
1597
1598 if ~isfield(opt, 'elem_len')
1599 if length(opt.elem_working) == 1
1600 if isfield(imdl.fwd_model, 'coarse2fine')
1601 c2f = imdl.fwd_model.coarse2fine;
1602 opt.elem_len = { size(c2f,2) };
1603 else
1604 opt.elem_len = { size(imdl.fwd_model.elems,1) };
1605 end
1606 else
1607 error('requires inv_model.inv_solve_core.elem_len');
1608 end
1609 end
1610
1611 if ~isfield(opt, 'n_frames')
1612 opt.n_frames = {n_frames};
1613 end
1614
1615
1616
1617
1618 if ~isfield(opt, 'elem_fixed')
1619 opt.elem_fixed = [];
1620 elseif iscell(opt.elem_fixed)
1621
1622
1623 offset=0;
1624 ef=[];
1625 for i=1:length(opt.elem_fixed)
1626 ef = [ef, opt.elem_fixed{i} + offset];
1627 offset = offset + opt.elem_len{i};
1628 end
1629 opt.elem_fixed = ef;
1630 end
1631
1632
1633 if ~isfield(opt, 'jacobian')
1634 if ~iscell(imdl.fwd_model.jacobian)
1635 opt.jacobian = {imdl.fwd_model.jacobian};
1636 else
1637 opt.jacobian = imdl.fwd_model.jacobian;
1638 end
1639 elseif isfield(imdl.fwd_model, 'jacobian')
1640 imdl.fwd_model
1641 imdl
1642 error('inv_model.fwd_model.jacobian and inv_model.inv_solve_core.jacobian should not both exist: it''s ambiguous');
1643 end
1644
1645 if isfield(opt, 'hyperparameter')
1646 opt.hyperparameter_spatial = opt.hyperparameter;
1647 opt = rmfield(opt, 'hyperparameter');
1648 end
1649
1650 if ~isfield(opt, 'hyperparameter_spatial')
1651 opt.hyperparameter_spatial = {[]};
1652 for i=1:length(opt.elem_working)
1653 opt.hyperparameter_spatial{i} = 1;
1654 end
1655 end
1656 if ~isfield(opt, 'hyperparameter_temporal')
1657 opt.hyperparameter_temporal = {[]};
1658 for i=1:length(opt.meas_working)
1659 opt.hyperparameter_temporal{i} = 1;
1660 end
1661 end
1662
1663
1664
1665 for i = {'elem_len', 'prior_data', 'jacobian', 'hyperparameter_spatial', 'hyperparameter_temporal'}
1666
1667
1668 x = opt.(i{1});
1669 if ~iscell(x)
1670 opt.(i{1}) = {x};
1671 end
1672 end
1673
1674 if opt.verbose > 1
1675 fprintf(' hyperparameters\n');
1676 try
1677 hp_global = imdl.hyperparameter.value;
1678 hp_global_str = sprintf(' x %0.4g',hp_global);
1679 catch
1680 hp_global = 1;
1681 hp_global_str = '';
1682 end
1683 for i=1:length(opt.elem_working)
1684 if isnumeric(opt.hyperparameter_spatial{i}) && length(opt.hyperparameter_spatial{i}) == 1
1685 fprintf(' %s: %0.4g\n',opt.elem_working{i}, opt.hyperparameter_spatial{i}*hp_global);
1686 elseif isa(opt.hyperparameter_spatial{i}, 'function_handle')
1687 fprintf(' %s: @%s%s\n',opt.elem_working{i}, func2str(opt.hyperparameter_spatial{i}), hp_global_str);
1688 elseif ischar(opt.hyperparameter_spatial{i})
1689 fprintf(' %s: @%s%s\n',opt.elem_working{i}, opt.hyperparameter_spatial{i}, hp_global_str);
1690 else
1691 fprintf(' %s: ...\n',opt.elem_working{i});
1692 end
1693 end
1694 for i=1:length(opt.meas_working)
1695 if isnumeric(opt.hyperparameter_temporal{i}) && length(opt.hyperparameter_temporal{i}) == 1
1696 fprintf(' %s: %0.4g\n',opt.meas_working{i}, opt.hyperparameter_temporal{i}*hp_global);
1697 elseif isa(opt.hyperparameter_temporal{i}, 'function_handle')
1698 fprintf(' %s: @%s%s\n',opt.meas_working{i}, func2str(opt.hyperparameter_temporal{i}), hp_global_str);
1699 elseif ischar(opt.hyperparameter_temporal{i})
1700 fprintf(' %s: @%s%s\n',opt.meas_working{i}, opt.hyperparameter_temporal{i}, hp_global_str);
1701 else
1702 fprintf(' %s: ...\n',opt.meas_working{i});
1703 end
1704 end
1705 end
1706
1707
1708
1709
1710
1711 if ~isfield(opt, 'RtR_prior')
1712 if isfield(imdl, 'RtR_prior')
1713 opt.RtR_prior = {imdl.RtR_prior};
1714 else
1715 opt.RtR_prior = {[]};
1716 warning('missing imdl.inv_solve_core.RtR_prior or imdl.RtR_prior: assuming NO spatial regularization RtR=0');
1717 end
1718 end
1719
1720
1721 if isnumeric(opt.RtR_prior)
1722 if size(opt.RtR_prior, 1) ~= size(opt.RtR_prior, 2)
1723 error('expecting square matrix for imdl.RtR_prior or imdl.inv_solve_core.RtR_prior');
1724 end
1725 if length(opt.RtR_prior) == 1
1726 opt.RtR_prior = {opt.RtR_prior};
1727 else
1728 RtR = opt.RtR_prior;
1729 opt.RtR_prior = {[]};
1730 esi = 0; eei = 0;
1731 for i=1:length(opt.elem_len)
1732 esi = eei +1;
1733 eei = eei +opt.elem_len{i};
1734 esj = 0; eej = 0;
1735 for j=1:length(opt.elem_len)
1736 esj = eej +1;
1737 eej = eej +opt.elem_len{j};
1738 opt.RtR_prior(i,j) = RtR(esi:eei, esj:eej);
1739 end
1740 end
1741 end
1742 elseif ~iscell(opt.RtR_prior)
1743 opt.RtR_prior = {opt.RtR_prior};
1744 end
1745
1746
1747 if any(size(opt.RtR_prior) ~= ([1 1]*length(opt.elem_len)))
1748 if (size(opt.RtR_prior, 1) ~= 1) && ...
1749 (size(opt.RtR_prior, 2) ~= 1)
1750 error('odd imdl.RtR_prior or imdl.inv_solve_core.RtR_prior, cannot figure out how to expand it blockwise');
1751 end
1752 if (size(opt.RtR_prior, 1) ~= length(opt.elem_len)) && ...
1753 (size(opt.RtR_prior, 2) ~= length(opt.elem_len))
1754 error('odd imdl.RtR_prior or imdl.inv_solve_core.RtR_prior, not enough blockwise components vs. elem_working types');
1755 end
1756 RtR_diag = opt.RtR_prior;
1757 opt.RtR_prior = {[]};
1758 for i=1:length(opt.elem_len)
1759 opt.RtR_prior(i,i) = RtR_diag(i);
1760 end
1761 end
1762
1763 hp=opt.hyperparameter_spatial;
1764 if size(hp,1) == 1
1765 hp = hp';
1766 end
1767 if iscell(hp)
1768
1769 if all(size(hp) == size(opt.RtR_prior))
1770 opt.hyperparameter_spatial = hp;
1771
1772 elseif length(hp) == length(opt.RtR_prior)
1773 opt.hyperparameter_spatial = opt.RtR_prior;
1774 [opt.hyperparameter_spatial{:}] = deal(1);
1775 opt.hyperparameter_spatial(logical(eye(size(opt.RtR_prior)))) = hp;
1776 else
1777 error('hmm, don''t understand this opt.hyperparameter_spatial cellarray');
1778 end
1779
1780 elseif isnumeric(hp)
1781 opt.hyperparameter_spatial = opt.RtR_prior;
1782 [opt.hyperparameter_spatial{:}] = deal({hp});
1783 else
1784 error('don''t understand this opt.hyperparameter_spatial');
1785 end
1786
1787
1788
1789
1790
1791 if ~isfield(opt, 'LLt_prior')
1792 if isfield(imdl, 'LLt_prior')
1793 opt.LLt_prior = {imdl.LLt_prior};
1794 else
1795 opt.LLt_prior = {eye(n_frames)};
1796 if n_frames ~= 1
1797 fprintf('warning: missing imdl.inv_solve_core.LLt_prior or imdl.LLt_prior: assuming NO temporal regularization LLt=I\n');
1798 end
1799 end
1800 end
1801
1802
1803 if isnumeric(opt.LLt_prior)
1804 if size(opt.LLt_prior, 1) ~= size(opt.LLt_prior, 2)
1805 error('expecting square matrix for imdl.LLt_prior or imdl.inv_solve_core.LLt_prior');
1806 end
1807 if length(opt.LLt_prior) == 1
1808 opt.LLt_prior = {opt.LLt_prior};
1809 else
1810 LLt = opt.LLt_prior;
1811 opt.LLt_prior = {[]};
1812 msi = 0; mei = 0;
1813 for i=1:length(opt.n_frames)
1814 msi = mei +1;
1815 mei = mei +opt.n_frames{i};
1816 msj = 0; mej = 0;
1817 for j=1:length(opt.n_frames)
1818 msj = mej +1;
1819 mej = mej +opt.n_frames{j};
1820 opt.LLt_prior(i,j) = LLt(msi:mei, msj:mej);
1821 end
1822 end
1823 end
1824 elseif ~iscell(opt.LLt_prior)
1825 opt.LLt_prior = {opt.LLt_prior};
1826 end
1827
1828
1829 if any(size(opt.LLt_prior) ~= ([1 1]*length(opt.n_frames)))
1830 if (size(opt.LLt_prior, 1) ~= 1) && ...
1831 (size(opt.LLt_prior, 2) ~= 1)
1832 error('odd imdl.LLt_prior or imdl.inv_solve_core.LLt_prior, cannot figure out how to expand it blockwise');
1833 end
1834 if (size(opt.LLt_prior, 1) ~= length(opt.n_frames)) && ...
1835 (size(opt.LLt_prior, 2) ~= length(opt.n_frames))
1836 error('odd imdl.LLt_prior or imdl.inv_solve_core.LLt_prior, not enough blockwise components vs. meas_working types');
1837 end
1838 LLt_diag = opt.LLt_prior;
1839 opt.LLt_prior = {[]};
1840 for i=1:length(opt.n_frames)
1841 opt.LLt_prior(i,i) = LLt_diag(i);
1842 end
1843 end
1844
1845 hp=opt.hyperparameter_temporal;
1846 if size(hp,1) == 1
1847 hp = hp';
1848 end
1849 if iscell(hp)
1850
1851 if all(size(hp) == size(opt.LLt_prior))
1852 opt.hyperparameter_temporal = hp;
1853
1854 elseif length(hp) == length(opt.LLt_prior)
1855 opt.hyperparameter_temporal = opt.LLt_prior;
1856 [opt.hyperparameter_temporal{:}] = deal(1);
1857 opt.hyperparameter_temporal(logical(eye(size(opt.LLt_prior)))) = hp;
1858 else
1859 error('hmm, don''t understand this opt.hyperparameter_temporal cellarray');
1860 end
1861
1862 elseif isnumeric(hp)
1863 opt.hyperparameter_temporal = opt.LLt_prior;
1864 [opt.hyperparameter_temporal{:}] = deal({hp});
1865 else
1866 error('don''t understand this opt.hyperparameter_temporal');
1867 end
1868
1869
1870
1871
1872
1873
1874 if ~isfield(opt, 'calc_jacobian_scaling_func')
1875 pinv = strfind(opt.elem_working, 'resistivity');
1876 plog = strfind(opt.elem_working, 'log_');
1877 plog10 = strfind(opt.elem_working, 'log10_');
1878 for i = 1:length(opt.elem_working)
1879 prefix = '';
1880 if plog{i}
1881 prefix = 'log';
1882 elseif plog10{i}
1883 prefix = 'log10';
1884 else
1885 prefix = '';
1886 end
1887 if pinv{i}
1888 prefix = [prefix '_inv'];
1889 end
1890 switch(prefix)
1891 case ''
1892 opt.calc_jacobian_scaling_func{i} = @ret1_func;
1893 case 'log'
1894 opt.calc_jacobian_scaling_func{i} = @dx_dlogx;
1895 case 'log10'
1896 opt.calc_jacobian_scaling_func{i} = @dx_dlog10x;
1897 case '_inv'
1898 opt.calc_jacobian_scaling_func{i} = @dx_dy;
1899 case 'log_inv'
1900 opt.calc_jacobian_scaling_func{i} = @dx_dlogy;
1901 case 'log10_inv'
1902 opt.calc_jacobian_scaling_func{i} = @dx_dlog10y;
1903 otherwise
1904 error('oops');
1905 end
1906 end
1907 end
1908
1909 if ~isfield(opt, 'update_img_func')
1910 opt.update_img_func = @null_func;
1911 end
1912
1913 if ~isfield(opt, 'return_working_variables')
1914 opt.return_working_variables = 0;
1915 end
1916
1917 function check_matrix_sizes(J, W, hps2RtR, hpt2LLt, dv, de, opt)
1918
1919
1920
1921 ne = size(de,1);
1922 nv = size(dv,1);
1923 nf = size(dv,2);
1924 if size(de,2) ~= size(dv,2)
1925 error('de cols (%d) not equal to dv cols (%d)', size(de,2), size(dv,2));
1926 end
1927 if opt.calc_meas_icov && ...
1928 any(size(W) ~= [nv nv])
1929 error('W size (%d rows, %d cols) is incorrect (%d rows, %d cols)', size(W), nv, nv);
1930 end
1931 if any(size(J) ~= [nv ne])
1932 error('J size (%d rows, %d cols) is incorrect (%d rows, %d cols)', size(J), nv, ne);
1933 end
1934 if opt.calc_RtR_prior && ...
1935 any(size(hps2RtR) ~= [ne ne])
1936 error('hps2RtR size (%d rows, %d cols) is incorrect (%d rows, %d cols)', size(hps2RtR), ne, ne);
1937 end
1938 if opt.calc_LLt_prior && ...
1939 any(size(hpt2LLt) ~= [nf nf])
1940 error('hpt2LLt size (%d rows, %d cols) is incorrect (%d rows, %d cols)', size(hpt2LLt), nf, nf);
1941 end
1942
1943 function dx = update_dx(J, W, hps2RtR, hpt2LLt, dv, de, opt)
1944 if(opt.verbose > 1)
1945 fprintf( ' calc step size dx\n');
1946 end
1947
1948 de(opt.elem_fixed) = 0;
1949
1950
1951 check_matrix_sizes(J, W, hps2RtR, hpt2LLt, dv, de, opt)
1952
1953
1954 J(:,opt.elem_fixed) = 0;
1955 de(opt.elem_fixed,:) = 0;
1956 hps2RtR(opt.elem_fixed,:) = 0;
1957 V=opt.elem_fixed;
1958 N=size(hps2RtR,1)+1;
1959 hps2RtR(N*(V-1)+1) = 1;
1960
1961 dx = feval(opt.update_func, J, W, hps2RtR, hpt2LLt, dv, de, opt);
1962
1963
1964 if any(dx(opt.elem_fixed) ~= 0)
1965 error('elem_fixed did''t give dx=0 at update_dx')
1966 end
1967
1968 if(opt.verbose > 1)
1969 fprintf(' ||dx||=%0.3g\n', norm(dx));
1970 es = 0; ee = 0;
1971 for i=1:length(opt.elem_working)
1972 es = ee +1; ee = ee + opt.elem_len{i};
1973 nd = norm(dx(es:ee));
1974 fprintf( ' ||dx_%d||=%0.3g (%s)\n',i, nd, opt.elem_working{i});
1975 end
1976 end
1977
1978 function dx = GN_update(J, W, hps2RtR, hpt2LLt, dv, de, opt)
1979 if ~any(strcmp(opt.update_method, {'cholesky','pcg'}))
1980 error(['unsupported update_method: ',opt.update_method]);
1981 end
1982 if strcmp(opt.update_method, 'cholesky')
1983 try
1984
1985 if any(any(hpt2LLt ~= eye(size(hpt2LLt))))
1986
1987 nf = size(dv,2);
1988 JtWJ = kron(eye(nf),J'*W*J);
1989 RtR = kron(hpt2LLt,hps2RtR);
1990 JtW = kron(eye(nf),J'*W);
1991
1992
1993 dx = -left_divide( (JtWJ + RtR), (JtW*dv(:) + RtR*de(:)) );
1994
1995 dx = reshape(dx,length(dx)/nf,nf);
1996 else
1997
1998 dx = -left_divide( (J'*W*J + hps2RtR), (J'*W*dv + hps2RtR*de) );
1999 end
2000 catch ME
2001 fprintf(' Cholesky failed: ');
2002 disp(ME.message)
2003 fprintf(' try opt.update_method = ''pcg'' on future runs\n');
2004 opt.update_method = 'pcg';
2005 end
2006 end
2007 if strcmp(opt.update_method, 'pcg')
2008 tol = 1e-6;
2009 maxit = [];
2010 M = [];
2011 x0 = [];
2012
2013
2014
2015 nm = size(de,1); nf = size(de,2);
2016 X = @(x) reshape(x,nm,nf);
2017
2018 LHS = @(X) (J'*(W*(J*X)) + hps2RtR*(X*hpt2LLt));
2019 RHS = -(J'*(W*dv) + hps2RtR*(de*hpt2LLt));
2020
2021 LHSv = @(x) reshape(LHS(X(x)),nm*nf,1);
2022 RHSv = reshape(RHS,nm*nf,1);
2023
2024 tol=100*eps*size(J,2)^2;
2025
2026
2027 [dx, flag, relres, iter, resvec] = pcg(LHSv, RHSv, tol, maxit, M', M', x0);
2028 dx = X(dx);
2029
2030 switch flag
2031 case 0
2032 if opt.verbose > 1
2033 fprintf(' PCG: relres=%g < tol=%g @ iter#%d\n',relres,tol,iter);
2034 end
2035 case 1
2036 if opt.verbose > 1
2037 fprintf(' PCG: relres=%g > tol=%g @ iter#%d (max#%d) [max iter]\n',relres,tol,iter,maxit);
2038 end
2039 case 2
2040 error('error: PCG ill-conditioned preconditioner M');
2041 case 3
2042 if opt.verbose > 1
2043 fprintf(' PCG: relres=%g > tol=%g @ iter#%d (max#%d) [stagnated]\n',relres,tol,iter,maxit);
2044 end
2045 case 4
2046 error('error: PCG a scalar quantity became too large or small to continue');
2047 otherwise
2048 error(sprintf('error: PCG unrecognized flag=%d',flag));
2049 end
2050
2051
2052
2053
2054
2055
2056
2057
2058
2059
2060
2061
2062
2063
2064
2065
2066
2067
2068
2069
2070
2071
2072
2073
2074 end
2075
2076
2077
2078 function args = function_depends_upon(func, argn)
2079
2080 str = sprintf('%s(',func2str(func));
2081 args = zeros(argn,1);
2082 for i = 1:argn-1
2083 str = [str sprintf('a(%d),',i)];
2084 end
2085 str = [str sprintf('a(%d))',argn)];
2086
2087 a = ones(argn,1)*2;
2088 x = eval(str);
2089
2090 for i = 1:argn
2091 a = ones(argn,1)*2;
2092 a(i) = 0;
2093 y = eval(str);
2094 if any(x ~= y)
2095 args(i) = 1;
2096 end
2097 end
2098
2099
2100 function out = null_func(in, varargin);
2101 out = in;
2102
2103
2104 function [out, x, y, z] = ret1_func(varargin);
2105 out = 1;
2106 x = [];
2107 y = [];
2108 z = [];
2109
2110
2111
2112 function [inv_model, opt] = append_c2f_background(inv_model, opt)
2113
2114
2115 if opt.c2f_background >= 0
2116 return
2117 end
2118
2119
2120 c2f = inv_model.fwd_model.coarse2fine;
2121 nf = size(inv_model.fwd_model.elems,1);
2122 nc = size(c2f,2);
2123
2124
2125
2126
2127
2128
2129 fel = sum(c2f,2);
2130 n = find(fel < 1 - (1e3+nc)*eps);
2131
2132
2133
2134
2135 if length(n) ~= 0
2136 if(opt.verbose > 1)
2137 fprintf(' c2f: adding background conductivity to %d\n fwd_model elements not covered by rec_model\n', length(n));
2138 end
2139 c2f(n,nc+1) = 1 - fel(n);
2140 inv_model.fwd_model.coarse2fine = c2f;
2141 opt.c2f_background = nc+1;
2142 if opt.c2f_background_fixed
2143
2144 opt.elem_fixed(end+1) = nc+1;
2145 end
2146 end
2147
2148 opt.elem_len(1) = {size(c2f,2)};
2149
2150 function [img, opt] = strip_c2f_background(img, opt, indent)
2151 if nargin < 3
2152 indent = '';
2153 end
2154
2155 if opt.c2f_background <= 0
2156 return;
2157 end
2158
2159
2160
2161
2162 in = img.current_params;
2163 out = opt.elem_output;
2164 if iscell(in)
2165 in = in{1};
2166 end
2167 if iscell(out)
2168 out = out{1};
2169 end
2170
2171
2172 e = opt.c2f_background;
2173
2174
2175 bg = map_data(img.elem_data(e), in, out);
2176 img.elem_data_background = bg;
2177
2178 img.elem_data(e) = [];
2179 img.fwd_model.coarse2fine(:,e) = [];
2180
2181 opt.c2f_background = 0;
2182 ri = find(opt.elem_fixed == e);
2183 opt.elem_fixed(ri) = [];
2184 if isfield(img, 'params_sel')
2185 for i = 1:length(img.params_sel)
2186 t = img.params_sel{i};
2187 ti = find(t == e);
2188 t(ti) = [];
2189 ti = find(t > e);
2190 t(ti) = t(ti)-1;
2191 img.params_sel{i} = t;
2192 end
2193 end
2194
2195
2196 if(opt.verbose > 1)
2197 bg = img.elem_data_background;
2198 bg = map_data(bg, in, 'resistivity');
2199 fprintf('%s background conductivity: %0.1f Ohm.m\n', indent, bg);
2200 end
2201
2202 function b = has_params(s)
2203 b = false;
2204 if isstruct(s)
2205 b = any(ismember(fieldnames(s),supported_params));
2206 end
2207
2208
2209 function out = map_img_base_types(img)
2210 out = to_base_types(img.current_params);
2211
2212
2213
2214
2215 function type = to_base_types(type)
2216 if ~iscell(type)
2217 type = {type};
2218 end
2219 for i = 1:length(type);
2220 type(i) = {strrep(type{i}, 'log_', '')};
2221 type(i) = {strrep(type{i}, 'log10_', '')};
2222 type(i) = {strrep(type{i}, 'resistivity', 'conductivity')};
2223 type(i) = {strrep(type{i}, 'apparent_resistivity', 'voltage')};
2224 end
2225
2226 function img = map_img(img, out);
2227 err_if_inf_or_nan(img.elem_data, 'img-pre');
2228 try
2229 in = img.current_params;
2230 catch
2231 in = {'conductivity'};
2232 end
2233
2234 if ischar(in)
2235 in = {in};
2236 img.current_params = in;
2237 end
2238 if ischar(out)
2239 out = {out};
2240 end
2241
2242
2243 if ~isfield(img, 'params_sel')
2244 if length(in(:)) == 1
2245 img.params_sel = {1:size(img.elem_data,1)};
2246 else
2247 error('found multiple parametrizations (params) but no params_sel cell array in img');
2248 end
2249 end
2250
2251
2252 if length(out(:)) > length(in(:))
2253 error('missing data (more out types than in types)');
2254 elseif length(out(:)) < length(in(:))
2255
2256
2257
2258
2259 if length(out(:)) ~= 1
2260 error('map_img can convert ALL parameters or select a SINGLE output type from multiple input types');
2261 end
2262 inm = to_base_types(in);
2263 outm = to_base_types(out);
2264 del = sort(find(~strcmp(outm(1), inm(:))), 'descend');
2265 if length(del)+1 ~= length(in)
2266 error('Confused about what to remove from the img. You''ll need to sort the parametrizations out yourself when removing data.');
2267 end
2268 for i = del(:)'
2269 ndel = length(img.params_sel{i});
2270 for j = i+1:length(img.params_sel)
2271 img.params_sel{j} = img.params_sel{j} - ndel;
2272 end
2273 img.elem_data(img.params_sel{i}) = [];
2274 img.params_sel(i) = [];
2275 img.current_params(i) = [];
2276 end
2277 in = img.current_params;
2278 end
2279
2280
2281 for i = 1:length(out(:))
2282
2283 x = img.elem_data(img.params_sel{i});
2284 x = map_data(x, in{i}, out{i});
2285 img.elem_data(img.params_sel{i}) = x;
2286 img.current_params{i} = out{i};
2287 end
2288 err_if_inf_or_nan(img.elem_data, 'img-post');
2289
2290
2291 if length(img.current_params(:)) == 1
2292 img.current_params = img.current_params{1};
2293 img = rmfield(img, 'params_sel');
2294 end
2295
2296 function x = map_data(x, in, out)
2297
2298 if ~ischar(in)
2299 if iscell(in) && (length(in(:)) == 1)
2300 in = in{1};
2301 else
2302 error('expecting single string for map_data() "in" type');
2303 end
2304 end
2305 if ~ischar(out)
2306 if iscell(out) && (length(out(:)) == 1)
2307 out = out{1};
2308 else
2309 error('expecting single string for map_data() "out" type');
2310 end
2311 end
2312
2313
2314 if strcmp(in, out)
2315 return;
2316 end
2317
2318
2319
2320
2321 if any(strcmp(in, {'resistivity', 'conductivity'})) && ...
2322 any(strcmp(out, {'resistivity', 'conductivity'}))
2323 x = 1./x;
2324
2325 elseif any(strcmp({in(1:3), out(1:3)}, 'log'))
2326
2327 if strcmp(in(1:6), 'log10_')
2328 if any(x >= log10(realmax)-eps) warning('loss of precision -> inf'); end
2329 x = map_data(10.^x, in(7:end), out);
2330
2331 elseif strcmp(in(1:4), 'log_')
2332 if any(x >= log(realmax)-eps) warning('loss of precision -> inf'); end
2333 x = map_data(exp(x), in(5:end), out);
2334
2335 elseif strcmp(out(1:6), 'log10_')
2336 if any(x <= 0 + eps) warning('loss of precision -> -inf'); end
2337 x = log10(map_data(x, in, out(7:end)));
2338
2339 elseif strcmp(out(1:4), 'log_')
2340 if any(x <= 0 + eps) warning('loss of precision -> -inf'); end
2341 x = log(map_data(x, in, out(5:end)));
2342 else
2343 error(sprintf('unknown conversion (log conversion?) %s - > %s', in, out));
2344 end
2345 else
2346 error('unknown conversion %s -> %s', in, out);
2347 end
2348 x(x == +inf) = +realmax;
2349 x(x == -inf) = -realmax;
2350 err_if_inf_or_nan(x, 'map_data-post');
2351
2352 function b = map_meas(b, N, in, out)
2353 err_if_inf_or_nan(b, 'map_meas-pre');
2354 if strcmp(in, out)
2355 return;
2356 end
2357
2358
2359
2360 if strcmp(in, 'voltage') && strcmp(out, 'apparent_resistivity')
2361 if N == 1
2362 error('missing apparent resistivity conversion factor N');
2363 end
2364 b = N * b;
2365 elseif strcmp(in, 'apparent_resistivity') && strcmp(out, 'voltage')
2366 if N == 1
2367 error('missing apparent resistivity conversion factor N');
2368 end
2369 b = N \ b;
2370
2371 elseif any(strcmp({in(1:3), out(1:3)}, 'log'))
2372
2373 if strcmp(in(1:6), 'log10_')
2374 if any(b > log10(realmax)-eps) warning('loss of precision -> inf'); end
2375 b = map_meas(10.^b, N, in(7:end), out);
2376
2377 elseif strcmp(in(1:4), 'log_')
2378 if any(b > log(realmax)-eps) warning('loss of precision -> inf'); end
2379 b = map_meas(exp(b), N, in(5:end), out);
2380
2381 elseif strcmp(out(1:6), 'log10_')
2382 if any(b <= 0+eps) warning('loss of precision -> -inf'); end
2383 b = log10(map_meas(b, N, in, out(7:end)));
2384
2385 elseif strcmp(out(1:4), 'log_')
2386 if any(b <= 0+eps) warning('loss of precision -> -inf'); end
2387 b = log(map_meas(b, N, in, out(5:end)));
2388 else
2389 error(sprintf('unknown conversion (log conversion?) %s - > %s', in, out));
2390 end
2391 else
2392 error('unknown conversion %s -> %s', in, out);
2393 end
2394 err_if_inf_or_nan(b, 'map_meas-post');
2395
2396 function x=range(y)
2397 x=max(y)-min(y);
2398
2399 function pass=do_unit_test(solver)
2400 if nargin == 0
2401 solver = 'inv_solve_core';
2402 test = 'all'
2403 elseif ((length(solver) < 9) || ~strcmp(solver(1:9),'inv_solve'))
2404 test = solver;
2405 solver = 'inv_solve_core';
2406 else
2407 test = 'all'
2408 end
2409 switch(test)
2410 case 'all'
2411 do_unit_test_sub;
2412 do_unit_test_diff;
2413 do_unit_test_rec1(solver);
2414 do_unit_test_rec2(solver);
2415 do_unit_test_rec_mv(solver);
2416 do_unit_test_img0_bg();
2417 do_unit_test_diffseq(solver);
2418 do_unit_test_absseq(solver);
2419 case 'sub'
2420 do_unit_test_sub;
2421 case 'diff'
2422 do_unit_test_diff;
2423 case 'rec1'
2424 do_unit_test_rec1(solver);
2425 case 'rec2'
2426 do_unit_test_rec2(solver);
2427 case 'rec_mv'
2428 do_unit_test_rec_mv(solver);
2429 case 'diffseq'
2430 do_unit_test_diffseq(solver);
2431 case 'absseq'
2432 do_unit_test_absseq(solver);
2433 otherwise
2434 error(['unrecognized solver or tests: ' test]);
2435 end
2436
2437 function [imdl, vh, imgi, vi] = unit_test_imdl()
2438 imdl = mk_geophysics_model('h22e',32);
2439 imdl.solve = 'inv_solve_core';
2440 imdl.inv_solve_core.max_iterations = 1;
2441 imdl.inv_solve_core.verbose = 0;
2442 imdl.reconst_type = 'difference';
2443 imgh = mk_image(imdl,1);
2444 vh = fwd_solve(imgh);
2445
2446 if nargout > 2
2447 imgi = imgh;
2448 ctrs = interp_mesh(imdl.fwd_model);
2449 x = ctrs(:,1);
2450 y = ctrs(:,2);
2451 r1 = sqrt((x+15).^2 + (y+25).^2);
2452 r2 = sqrt((x-85).^2 + (y+65).^2);
2453 imgi.elem_data(r1<25)= 1/2;
2454 imgi.elem_data(r2<30)= 2;
2455 clf; show_fem(imgi,1);
2456 vi = fwd_solve(imgi);
2457 end
2458
2459 function do_unit_test_diff()
2460 [imdl, vh, imgi, vi] = unit_test_imdl();
2461
2462 imdl.reconst_type = 'absolute';
2463 imdl.inv_solve_core.line_search_func = @ret1_func;
2464 img_abs = inv_solve(imdl,vi);
2465 imdl.reconst_type = 'difference';
2466 img_itr = inv_solve(imdl,vh,vi);
2467 imdl.inv_solve_core.max_iterations = 1;
2468 img_it1 = inv_solve(imdl,vh,vi);
2469 imdl.solve = 'inv_solve_diff_GN_one_step';
2470 img_gn1 = inv_solve(imdl,vh,vi);
2471 clf; subplot(223); show_fem(img_it1,1); title('GN 1-iter');
2472 subplot(224); show_fem(img_gn1,1); title('GN 1-step');
2473 subplot(221); h=show_fem(imgi,1); title('fwd model'); set(h,'EdgeColor','none');
2474 subplot(222); show_fem(img_itr,1); title('GN 10-iter');
2475 subplot(222); show_fem(img_abs,1); title('GN abs 10-iter');
2476 unit_test_cmp('core (1-step) vs. diff_GN_one_step', img_it1.elem_data, img_gn1.elem_data, eps*15);
2477 unit_test_cmp('core (1-step) vs. core (N-step) ', img_it1.elem_data, img_itr.elem_data, eps*2);
2478 unit_test_cmp('core (N-step) vs. abs (N-step) ', img_it1.elem_data, img_abs.elem_data-1, eps);
2479
2480
2481
2482
2483 function do_unit_test_sub
2484 d = 1;
2485 while d ~= 1 & d ~= 0
2486 d = rand(1);
2487 end
2488 disp('TEST: map_data()');
2489 elem_types = {'conductivity', 'log_conductivity', 'log10_conductivity', ...
2490 'resistivity', 'log_resistivity', 'log10_resistivity'};
2491 expected = [d log(d) log10(d) 1./d log(1./d) log10(1./d); ...
2492 exp(d) d log10(exp(d)) 1./exp(d) log(1./exp(d)) log10(1./exp(d)); ...
2493 10.^d log(10.^d ) d 1./10.^d log(1./10.^d ) log10(1./10.^d ); ...
2494 1./d log(1./d ) log10(1./d) d log(d) log10(d); ...
2495 1./exp(d) log(1./exp(d)) log10(1./exp(d)) exp(d) d log10(exp(d)); ...
2496 1./10.^d log(1./10.^d) log10(1./10.^d) 10.^d log(10.^d) d ];
2497 for i = 1:length(elem_types)
2498 for j = 1:length(elem_types)
2499 test_map_data(d, elem_types{i}, elem_types{j}, expected(i,j));
2500 end
2501 end
2502
2503 disp('TEST: map_meas()');
2504 N = 1/15;
2505 Ninv = 1/N;
2506
2507 elem_types = {'voltage', 'log_voltage', 'log10_voltage', ...
2508 'apparent_resistivity', 'log_apparent_resistivity', 'log10_apparent_resistivity'};
2509 expected = [d log(d) log10(d) N*d log(N*d) log10(N*d); ...
2510 exp(d) d log10(exp(d)) N*exp(d) log(N*exp(d)) log10(N*exp(d)); ...
2511 10.^d log(10.^d ) d N*10.^d log(N*10.^d ) log10(N*10.^d ); ...
2512 Ninv*d log(Ninv*d ) log10(Ninv*d) d log(d) log10(d); ...
2513 Ninv*exp(d) log(Ninv*exp(d)) log10(Ninv*exp(d)) exp(d) d log10(exp(d)); ...
2514 Ninv*10.^d log(Ninv*10.^d) log10(Ninv*10.^d) 10.^d log(10.^d) d ];
2515 for i = 1:length(elem_types)
2516 for j = 1:length(elem_types)
2517 test_map_meas(d, N, elem_types{i}, elem_types{j}, expected(i,j));
2518 end
2519 end
2520
2521 disp('TEST: Jacobian scaling');
2522 d = [d d]';
2523 unit_test_cmp( ...
2524 sprintf('Jacobian scaling (%s)', 'conductivity'), ...
2525 ret1_func(d), 1);
2526
2527 unit_test_cmp( ...
2528 sprintf('Jacobian scaling (%s)', 'log_conductivity'), ...
2529 dx_dlogx(d), diag(d));
2530
2531 unit_test_cmp( ...
2532 sprintf('Jacobian scaling (%s)', 'log10_conductivity'), ...
2533 dx_dlog10x(d), diag(d)*log(10));
2534
2535 unit_test_cmp( ...
2536 sprintf('Jacobian scaling (%s)', 'resistivity'), ...
2537 dx_dy(d), diag(-d.^2));
2538
2539 unit_test_cmp( ...
2540 sprintf('Jacobian scaling (%s)', 'log_resistivity'), ...
2541 dx_dlogy(d), diag(-d));
2542
2543 unit_test_cmp( ...
2544 sprintf('Jacobian scaling (%s)', 'log10_resistivity'), ...
2545 dx_dlog10y(d), diag(-d)/log(10));
2546
2547
2548 function test_map_data(data, in, out, expected)
2549
2550 calc_val = map_data(data, in, out);
2551 str = sprintf('map_data(%s -> %s)', in, out);
2552 unit_test_cmp(str, calc_val, expected)
2553
2554 function test_map_meas(data, N, in, out, expected)
2555
2556 calc_val = map_meas(data, N, in, out);
2557 str = sprintf('map_data(%s -> %s)', in, out);
2558 unit_test_cmp(str, calc_val, expected,100*eps)
2559
2560
2561
2562
2563 function do_unit_test_rec1(solver)
2564
2565
2566
2567
2568
2569 [imdl, vh, imgi, vi] = unit_test_imdl();
2570 imdl.solve = solver;
2571 imdl.reconst_type = 'absolute';
2572 imdl.inv_solve_core.prior_data = 1;
2573 imdl.inv_solve_core.elem_prior = 'conductivity';
2574 imdl.inv_solve_core.elem_working = 'log_conductivity';
2575 imdl.inv_solve_core.meas_working = 'apparent_resistivity';
2576 imdl.inv_solve_core.calc_solution_error = 0;
2577 imdl.inv_solve_core.verbose = 0;
2578
2579 imgp = map_img(imgi, 'log10_conductivity');
2580
2581
2582
2583
2584
2585 img1= inv_solve(imdl, vi);
2586
2587 disp('TEST: previous solved at default verbosity');
2588 disp('TEST: now solve same at verbosity=0 --> should be silent');
2589 imdl.inv_solve_core.verbose = 0;
2590
2591 img2= inv_solve(imdl, vi);
2592
2593 imdl.inv_solve_core.elem_output = 'log10_resistivity';
2594 img3= inv_solve(imdl, vi);
2595
2596 disp('TEST: try coarse2fine mapping with background');
2597 ctrs= interp_mesh(imdl.rec_model);
2598 x= ctrs(:,1); y= ctrs(:,2);
2599 r=sqrt((x+5).^2 + (y+5).^2);
2600 imdl.rec_model.elems(x-y > 300, :) = [];
2601 c2f = mk_approx_c2f(imdl.fwd_model,imdl.rec_model);
2602 imdl.fwd_model.coarse2fine = c2f;
2603
2604
2605 imdl.inv_solve_core.elem_output = 'conductivity';
2606 img4= inv_solve(imdl, vi);
2607
2608 clf; subplot(221); h=show_fem(imgp,1); set(h,'EdgeColor','none'); axis tight; title('synthetic data, logC');
2609 subplot(222); show_fem(img1,1); axis tight; title('#1 verbosity=default');
2610 subplot(223); show_fem(img2,1); axis tight; title('#2 verbosity=0');
2611 subplot(223); show_fem(img3,1); axis tight; title('#3 c2f + log10 resistivity out');
2612 subplot(224); show_fem(img4,1); axis tight; title('#4 c2f cut');
2613 drawnow;
2614 d1 = img1.elem_data; d2 = img2.elem_data; d3 = img3.elem_data; d4 = img4.elem_data;
2615 unit_test_cmp('img1 == img2', d1, d2, eps);
2616 unit_test_cmp('img1 == img3', d1, 1./(10.^d3), eps);
2617 unit_test_cmp('img1 == img4', (d1(x-y <=300)-d4)./d4, 0, 0.05);
2618
2619
2620
2621
2622 function do_unit_test_rec_mv(solver)
2623 disp('TEST: conductivity and movement --> baseline conductivity only');
2624
2625
2626
2627
2628
2629 imdl= mk_common_model('c2t4',16);
2630 ne = length(imdl.fwd_model.electrode);
2631 nt = length(imdl.fwd_model.elems);
2632 imdl.solve = solver;
2633 imdl.reconst_type = 'absolute';
2634
2635 imdl.inv_solve_core.meas_input = 'voltage';
2636 imdl.inv_solve_core.meas_working = 'apparent_resistivity';
2637 imdl.inv_solve_core.elem_prior = { 'conductivity' };
2638 imdl.inv_solve_core.prior_data = { 1 };
2639 imdl.inv_solve_core.elem_working = {'log_conductivity'};
2640 imdl.inv_solve_core.elem_output = {'log10_conductivity'};
2641 imdl.inv_solve_core.calc_solution_error = 0;
2642 imdl.inv_solve_core.verbose = 0;
2643 imdl.hyperparameter.value = 0.1;
2644
2645
2646 imgsrc= mk_image( imdl.fwd_model, 1);
2647 vh=fwd_solve(imgsrc);
2648
2649 ctrs= interp_mesh(imdl.fwd_model);
2650 x= ctrs(:,1); y= ctrs(:,2);
2651 r1=sqrt((x+5).^2 + (y+5).^2); r2 = sqrt((x-45).^2 + (y-35).^2);
2652 imgsrc.elem_data(r1<50)= 0.05;
2653 imgsrc.elem_data(r2<30)= 100;
2654
2655
2656 vi=fwd_solve( imgsrc );
2657
2658
2659 noise_level= std(vi.meas - vh.meas)/10^(30/20);
2660 vi.meas = vi.meas + noise_level*randn(size(vi.meas));
2661
2662
2663 hh=clf; subplot(221); imgp = map_img(imgsrc, 'log10_conductivity'); show_fem(imgp,1); axis tight; title('synth baseline, logC');
2664
2665
2666 img0= inv_solve(imdl, vi);
2667 figure(hh); subplot(222);
2668 img0 = map_img(img0, 'log10_conductivity');
2669 show_fem(img0, 1); axis tight;
2670
2671 disp('TEST: conductivity + movement');
2672 imdl.fwd_model = rmfield(imdl.fwd_model, 'jacobian');
2673
2674 imdl.inv_solve_core.elem_prior = { 'conductivity' , 'movement'};
2675 imdl.inv_solve_core.prior_data = { 1 , 0 };
2676 imdl.inv_solve_core.RtR_prior = { @eidors_default, @prior_movement_only};
2677 imdl.inv_solve_core.elem_len = { nt , ne*2 };
2678 imdl.inv_solve_core.elem_working = { 'log_conductivity', 'movement'};
2679 imdl.inv_solve_core.elem_output = {'log10_conductivity', 'movement'};
2680 imdl.inv_solve_core.jacobian = { @jacobian_adjoint , @jacobian_movement_only};
2681 imdl.inv_solve_core.hyperparameter = { [1 1.1 0.9] , sqrt(2e-3) };
2682 imdl.inv_solve_core.verbose = 0;
2683
2684
2685 nn = [imgsrc.fwd_model.electrode(:).nodes];
2686 elec_orig = imgsrc.fwd_model.nodes(nn,:);
2687
2688 nn = imgsrc.fwd_model.nodes;
2689 imgsrc.fwd_model.nodes = nn * [1-0.02 0; 0 1+0.02];
2690
2691 nn = [imgsrc.fwd_model.electrode(:).nodes];
2692 elec_mv = imgsrc.fwd_model.nodes(nn,:);
2693
2694
2695 vi=fwd_solve( imgsrc );
2696
2697
2698 noise_level= std(vi.meas - vh.meas)/10^(30/20);
2699
2700
2701
2702 nn = [imgsrc.fwd_model.electrode(1:4).nodes];
2703 figure(hh); subplot(223); imgp = map_img(imgsrc, 'log10_conductivity'); show_fem_move(imgp,elec_mv-elec_orig,10,1); axis tight; title('synth mvmt, logC');
2704
2705
2706 img1= inv_solve(imdl, vi);
2707 figure(hh); subplot(224);
2708 imgm = map_img(img1, 'movement');
2709 img1 = map_img(img1, 'log10_conductivity');
2710 show_fem_move(img1,reshape(imgm.elem_data,16,2), 10, 1); axis tight;
2711
2712 d0 = img0.elem_data; d1 = img1.elem_data;
2713 unit_test_cmp('img0 == img1 + mvmt', d0-d1, 0, 0.40);
2714
2715
2716 function Jm = jacobian_movement_only (fwd_model, img);
2717 pp = fwd_model_parameters(img.fwd_model);
2718 szJm = pp.n_elec * pp.n_dims;
2719 img = map_img(img, 'conductivity');
2720 Jcm = jacobian_movement(fwd_model, img);
2721 Jm = Jcm(:,(end-szJm+1):end);
2722
2723
2724
2725
2726
2727
2728
2729
2730 function RtR = prior_movement_only(imdl);
2731 imdl.image_prior.parameters(1) = 1;
2732 pp = fwd_model_parameters(imdl.fwd_model);
2733 szPm = pp.n_elec * pp.n_dims;
2734 RtR = prior_movement(imdl);
2735 RtR = RtR((end-szPm+1):end,(end-szPm+1):end);
2736
2737 function do_unit_test_rec2(solver)
2738 disp('TEST: reconstruct a discontinuity');
2739 [imdl, vh] = unit_test_imdl();
2740 imgi = mk_image(imdl, 1);
2741 ctrs = interp_mesh(imdl.fwd_model);
2742 x = ctrs(:,1); y = ctrs(:,2);
2743 imgi.elem_data(x-y>100)= 1/10;
2744 vi = fwd_solve(imgi); vi = vi.meas;
2745 clf; show_fem(imgi,1);
2746
2747 imdl.solve = solver;
2748 imdl.hyperparameter.value = 1e2;
2749
2750 imdl.reconst_type = 'absolute';
2751 imdl.inv_solve_core.elem_working = 'log_conductivity';
2752 imdl.inv_solve_core.elem_output = 'log10_resistivity';
2753 imdl.inv_solve_core.meas_working = 'apparent_resistivity';
2754 imdl.inv_solve_core.dtol_iter = 4;
2755 imdl.inv_solve_core.max_iterations = 20;
2756 imdl.inv_solve_core.calc_solution_error = 0;
2757 imdl.inv_solve_core.verbose = 10;
2758 imgr= inv_solve_core(imdl, vi);
2759
2760 clf; show_fem(imgr,1);
2761 img = mk_image( imdl );
2762 img.elem_data= 1./(10.^imgr.elem_data);
2763
2764
2765
2766
2767
2768
2769
2770
2771
2772
2773
2774 function do_unit_test_img0_bg()
2775 stim = mk_stim_patterns(32,1, ...
2776 [0,5],[0,5],{'meas_current'});
2777 extra = {'ball',['solid ball = ' ...
2778 'sphere(0.4,0,0.4; 0.1);']};
2779 fmdl = ng_mk_cyl_models([1,1,0.1],...
2780 [16,0.3,0.7],0.05,extra);
2781 [~,fmdl] = elec_rearrange([16,2],...
2782 'square',fmdl);
2783 fmdl.stimulation = stim;
2784 img= mk_image(fmdl,1);
2785 vh=fwd_solve(img);
2786 img.elem_data(fmdl.mat_idx{2}) = 2;
2787 vi=fwd_solve(img);
2788 cmdl = ng_mk_cyl_models([1,1,0.2],[],[]);
2789 fmdl.coarse2fine = ...
2790 mk_coarse_fine_mapping(fmdl,cmdl);
2791 imdl1= select_imdl(fmdl,{'Basic GN dif'});
2792 imdl1.rec_model = cmdl;
2793 imdl1.hyperparameter.value = .0001;
2794 imdl1.inv_solve_gn.max_iterations = 1;
2795 imdl1.solve = @inv_solve_gn;
2796
2797 imgr1 = inv_solve(imdl1, vh, vi);
2798
2799
2800
2801
2802
2803
2804
2805
2806 function do_unit_test_diffseq(solver)
2807 lvl = eidors_msg('log_level',1);
2808 imdl = mk_common_model('f2C',16);
2809 imdl.solve = solver;
2810 imdl.hyperparameter.value = 1e-2;
2811
2812 imgh = mk_image(imdl,1);
2813 xyr = [];
2814 for deg = [0:5:360]
2815 R = [sind(deg) cosd(deg); cosd(deg) -sind(deg)];
2816 xyr(:,end+1) = [R*[0.5 0.5]'; 0.2];
2817 end
2818 [vh, vi, ~, imgm] = simulate_movement(imgh, xyr);
2819 disp('*** alert: inverse crime underway ***');
2820 disp(' - no noise has been added to this data');
2821 disp(' - reconstructing to the same FEM discretization as simulated data');
2822 disp('***');
2823 vv.meas = [];
2824 vv.time = nan;
2825 vv.name = 'asfd';
2826 vv.type = 'data';
2827 n_frames = size(vi,2);
2828 for ii = 1:7
2829 switch ii
2830 case 1
2831 fprintf('\n\nvh:numeric, vi:numeric data\n');
2832 vhi = vh;
2833 vii = vi;
2834 case 2
2835 fprintf('\n\nvh:struct, vi:numeric data\n');
2836 vhi = vv; vhi.meas = vh;
2837 vii = vi;
2838 case 3
2839 fprintf('\n\nvh:numeric, vi:struct data\n');
2840 vhi = vh;
2841 clear vii;
2842 for jj=1:n_frames;
2843 vii(jj) = vv; vii(jj).meas = vi(:,jj);
2844 end
2845 case 4
2846 fprintf('\n\nvh:struct, vi:struct data\n');
2847 vhi = vv; vhi.meas = vh;
2848 clear vii;
2849 for jj=1:n_frames;
2850 vii(jj) = vv; vii(jj).meas = vi(:,jj);
2851 end
2852 case 5
2853 fprintf('method = Cholesky\n');
2854 imdl.inv_solve_core.update_method = 'cholesky';
2855 case 6
2856 fprintf('method = PCG\n');
2857 imdl.inv_solve_core.update_method = 'pcg';
2858 otherwise
2859 fprintf('method = default\n');
2860 imdl.inv_solve_core = rmfield(imdl.inv_solve_core,'update_method');
2861 end
2862 img= inv_solve(imdl, vhi, vii);
2863 for i=1:size(imgm,2)
2864 clf;
2865 subplot(211); imgi=imgh; imgi.elem_data = imgm(:,i); show_fem(imgi); title(sprintf('fwd#%d',i));
2866 subplot(212); imgi=imgh; imgi.elem_data = img.elem_data(:,i); show_fem(imgi); title('reconst');
2867 drawnow;
2868 err(i) = norm(imgm(:,i)/max(imgm(:,i)) - img.elem_data(:,i)/max(img.elem_data(:,i)));
2869 fprintf('image#%d: reconstruction error = %g\n',i,err(i));
2870 end
2871 for i=1:size(imgm,2)
2872 unit_test_cmp( sprintf('diff seq image#%d',i), ...
2873 imgm(:,i)/max(imgm(:,i)), ...
2874 img.elem_data(:,i)/max(img.elem_data(:,i)), ...
2875 0.90 );
2876 end
2877 end
2878 eidors_msg('log_level',lvl);
2879
2880
2881 function do_unit_test_absseq(solver)
2882 lvl = eidors_msg('log_level',1);
2883 imdl = mk_common_model('f2C',16);
2884 imdl.reconst_type = 'absolute';
2885 imdl.solve = solver;
2886 imdl.hyperparameter.value = 1e-2;
2887
2888 imgh = mk_image(imdl,1);
2889 xyr = [];
2890 for deg = [0:5:360]
2891 R = [sind(deg) cosd(deg); cosd(deg) -sind(deg)];
2892 xyr(:,end+1) = [R*[0.5 0.5]'; 0.2];
2893 end
2894 [~, vi, ~, imgm] = simulate_movement(imgh, xyr);
2895 imgm = imgm + 1;
2896 disp('*** alert: inverse crime underway ***');
2897 disp(' - no noise has been added to this data');
2898 disp(' - reconstructing to the same FEM discretization as simulated data');
2899 disp('***');
2900 vv.meas = [];
2901 vv.time = nan;
2902 vv.name = 'asfd';
2903 vv.type = 'data';
2904 n_frames = size(vi,2);
2905 for ii = 1:5
2906 switch ii
2907 case 1
2908 fprintf('\n\nvi:numeric data\n');
2909 vii = vi;
2910 case 2
2911 fprintf('\n\nvi:struct data\n');
2912 clear vii;
2913 for jj=1:n_frames;
2914 vii(jj) = vv; vii(jj).meas = vi(:,jj);
2915 end
2916 case 3
2917 fprintf('method = Cholesky\n');
2918 imdl.inv_solve_core.update_method = 'cholesky';
2919 case 4
2920 fprintf('method = PCG\n');
2921 imdl.inv_solve_core.update_method = 'pcg';
2922 otherwise
2923 fprintf('method = default\n');
2924 imdl.inv_solve_core = rmfield(imdl.inv_solve_core,'update_method');
2925 end
2926 img= inv_solve(imdl, vii);
2927 for i=1:size(imgm,2)
2928 clf;
2929 subplot(211); imgi=imgh; imgi.elem_data = imgm(:,i); show_fem(imgi); title(sprintf('fwd#%d',i));
2930 subplot(212); imgi=imgh; imgi.elem_data = img.elem_data(:,i); show_fem(imgi); title('reconst');
2931 drawnow;
2932 err(i) = norm(imgm(:,i)/max(imgm(:,i)) - img.elem_data(:,i)/max(img.elem_data(:,i)));
2933 fprintf('image#%d: reconstruction error = %g\n',i,err(i));
2934 end
2935 for i=1:size(imgm,2)
2936 unit_test_cmp( sprintf('abs seq image#%d',i), ...
2937 imgm(:,i)/max(imgm(:,i)), ...
2938 img.elem_data(:,i)/max(img.elem_data(:,i)), ...
2939 0.46 );
2940 end
2941 end
2942 eidors_msg('log_level',lvl);