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