0001 function img= inv_solve_abs_core( inv_model, data0);
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 if isstr(inv_model) && strcmp(inv_model,'UNIT_TEST') && (nargin == 1); do_unit_test; return; end
0232 if isstr(inv_model) && strcmp(inv_model,'UNIT_TEST') && (nargin == 2); do_unit_test(data0); return; end
0233 
0234 
0235 opt = parse_options(inv_model);
0236 if opt.verbose > 1
0237    fprintf('  verbose = %d\n', opt.verbose);
0238 end
0239 
0240 
0241 
0242 
0243 
0244 
0245 [inv_model, opt] = append_c2f_background(inv_model, opt);
0246 
0247 
0248 
0249 
0250 
0251 if isfield(inv_model, 'jacobian_bkgnd')
0252   inv_model = rmfield(inv_model,'jacobian_bkgnd');
0253 end
0254 inv_model.jacobian_bkgnd.value = 1;
0255 img = mk_image( inv_model );
0256 img.inv_model = inv_model; 
0257 img = data_mapper(img); 
0258 
0259 
0260 img = init_elem_data(img, opt);
0261 
0262 
0263 
0264 img = map_img(img, opt.elem_working);
0265 
0266 if ~isstruct(data0)
0267    d = data0;
0268    data0 = struct;
0269    data0.meas = d;
0270    data0.type = 'data';
0271 end
0272 data0.current_params = opt.meas_input;
0273 
0274 
0275 W  = init_meas_icov(inv_model, opt);
0276 [N, dN] = init_normalization(inv_model.fwd_model, data0, opt);
0277 
0278 
0279 img0 = img;
0280 hp2RtR = 0; alpha = 0; k = 0; sx = 0; r = 0; stop = 0; 
0281 residuals = zeros(opt.max_iterations,3); 
0282 dxp = 0; 
0283 [dv, opt] = update_dv([], img, data0, N, opt);
0284 de = update_de([], img, img0, opt);
0285 if opt.verbose >= 5 
0286   dvall = ones(size(data0.meas,1),opt.max_iterations+1)*NaN;
0287 end
0288 while 1
0289   if opt.verbose > 1
0290      if k == 0
0291         fprintf('  iteration start up\n')
0292      else
0293         fprintf('  iteration %d\n', k)
0294      end
0295   end
0296 
0297   
0298   
0299   [J, opt] = update_jacobian(img, dN, k, opt);
0300 
0301   
0302   hp2RtR = update_hp2RtR(inv_model, J, k, img, opt);
0303 
0304   
0305   
0306   dx = update_dx(J, W, hp2RtR, dv, de, opt);
0307   
0308   beta = update_beta(dx, dxp, sx, opt);
0309   
0310   sx = update_sx(dx, beta, sx, opt);
0311   if k ~= 0
0312      dxp = dx; 
0313   end
0314 
0315   
0316   plot_svd_elem(J, W, hp2RtR, k, sx, dx, img, opt);
0317 
0318   
0319   
0320   
0321   
0322   [alpha, img, dv, opt] = update_alpha(img, sx, data0, img0, N, W, hp2RtR, k, dv, opt);
0323   
0324   
0325   [img, dv] = update_img_using_limits(img, img0, data0, N, dv, opt);
0326 
0327   
0328   
0329   [dv, opt] = update_dv(dv, img, data0, N, opt);
0330   de = update_de(de, img, img0, opt);
0331   if opt.verbose >= 5
0332     dvall(:,k+1) = dv;
0333     show_meas_err(dvall, data0, k+1, N, W, opt);
0334   end
0335   show_fem_iter(k, img, inv_model, stop, opt);
0336 
0337   
0338   [stop, k, r, img] = update_residual(dv, img, de, W, hp2RtR, k, r, alpha, sx, opt);
0339   if stop
0340      break;
0341   end
0342 end
0343 [img, opt] = strip_c2f_background(img, opt);
0344 
0345 if isfield(inv_model, 'rec_model')
0346   img.fwd_model = inv_model.rec_model;
0347 end
0348 if opt.verbose > 1
0349    if k==1; itrs=''; else itrs='s'; end
0350    fprintf('  %d fwd_solves required for this solution in %d iteration%s\n', ...
0351            opt.fwd_solutions, k, itrs);
0352 end
0353 
0354 img = map_img(img, opt.elem_output);
0355 img.meas_err = dv;
0356 if opt.return_working_variables
0357   img.inv_solve_abs_core.J = J;
0358   img.inv_solve_abs_core.dx = dx;
0359   img.inv_solve_abs_core.sx = sx;
0360   img.inv_solve_abs_core.alpha = alpha;
0361   img.inv_solve_abs_core.beta = beta;
0362   img.inv_solve_abs_core.k = k;
0363   img.inv_solve_abs_core.r = r;
0364   img.inv_solve_abs_core.N = N;
0365   img.inv_solve_abs_core.W = W;
0366   img.inv_solve_abs_core.hp2RtR = hp2RtR;
0367   img.inv_solve_abs_core.dv = dv;
0368   img.inv_solve_abs_core.de = de;
0369   if opt.verbose >= 5
0370     img.inv_solve_abs_core.dvall = dvall;
0371   end
0372 end
0373 
0374 
0375 function show_meas_err(dvall, data0, k, N, W, opt)
0376    clf;
0377    subplot(211); bar(dvall(:,k)); ylabel(sprintf('dv_k [%s]',opt.meas_working)); xlabel('meas #'); title(sprintf('iter %d',k));
0378    subplot(212); bar(map_meas(dvall(:,k),N,opt.meas_working, 'voltage')); ylabel('dv_k [V]'); xlabel('meas #'); title('');
0379    drawnow;
0380    if isfield(opt,'fig_prefix')
0381       print('-dpdf',sprintf('%s-meas_err%d',opt.fig_prefix,k));
0382       print('-dpng',sprintf('%s-meas_err%d',opt.fig_prefix,k));
0383       saveas(gcf,sprintf('%s-meas_err%d.fig',opt.fig_prefix,k));
0384    end
0385    drawnow;
0386 
0387 function img = init_elem_data(img, opt)
0388   if opt.verbose > 1
0389     fprintf('  setting prior elem_data\n');
0390   end
0391   ne2 = 0; 
0392   img.elem_data = zeros(sum([opt.elem_len{:}]),1); 
0393   for i=1:length(opt.elem_prior)
0394     ne1 = ne2+1; 
0395     ne2 = ne1+opt.elem_len{i}-1; 
0396     if opt.verbose > 1
0397       if length(opt.prior_data{i}) == 1
0398         fprintf('    %d x %s: %0.1f\n',opt.elem_len{i},opt.elem_prior{i}, opt.prior_data{i});
0399       else
0400         fprintf('    %d x %s: ...\n',opt.elem_len{i},opt.elem_prior{i});
0401         if length(opt.prior_data{i}) ~= opt.elem_len{i}
0402            error(sprintf('expected %d elem, got %d elem in elem_prior', ...
0403                          opt.elem_len{i}, length(opt.prior_data{i})));
0404         end
0405       end
0406     end
0407     img.params_sel(i) = {ne1:ne2};
0408     img.elem_data(img.params_sel{i}) = opt.prior_data{i};
0409   end
0410   img.current_params = opt.elem_prior;
0411 
0412 function W = init_meas_icov(inv_model, opt)
0413    W = 1;
0414    if opt.calc_meas_icov
0415       if opt.verbose > 1
0416          disp('  calc measurement inverse covariance W');
0417       end
0418       W   = calc_meas_icov( inv_model );
0419    end
0420    err_if_inf_or_nan(W, 'init_meas_icov');
0421 
0422 function [N, dN] = init_normalization(fmdl, data0, opt)
0423    
0424    N = 1;
0425    dN = 1;
0426    vh1.meas = 1;
0427    if ~ischar(opt.meas_input) || ~ischar(opt.meas_working)
0428       error('expected strings for meas_input and meas_working');
0429    end
0430    go =       any(strcmp({opt.meas_input, opt.meas_working},'apparent_resistivity'));
0431    go = go || any(strcmp({opt.meas_input, opt.meas_working},'log_apparent_resistivity'));
0432    go = go || any(strcmp({opt.meas_input, opt.meas_working},'log10_apparent_resistivity'));
0433    if go
0434       if opt.verbose > 1
0435          disp(['  calc measurement normalization matrix N (voltage -> ' opt.meas_working ')']);
0436       end
0437       
0438       img1 = mk_image(fmdl,1);
0439       vh1  = fwd_solve(img1);
0440       N    = spdiag(1./vh1.meas);
0441       err_if_inf_or_nan(N,  'init_normalization: N');
0442    end
0443    if go && (opt.verbose > 1)
0444       disp(['  calc Jacobian normalization matrix   dN (voltage -> ' opt.meas_working ')']);
0445    end
0446    
0447    data0 = map_meas_struct(data0, N, 'voltage'); 
0448    switch opt.meas_working
0449       case 'apparent_resistivity'
0450          dN = da_dv(data0.meas, vh1.meas);
0451       case 'log_apparent_resistivity'
0452          dN = dloga_dv(data0.meas, vh1.meas);
0453       case 'log10_apparent_resistivity'
0454          dN = dlog10a_dv(data0.meas, vh1.meas);
0455       case 'voltage'
0456          dN = dv_dv(data0.meas, vh1.meas);
0457       case 'log_voltage'
0458          dN = dlogv_dv(data0.meas, vh1.meas);
0459       case 'log10_voltage'
0460          dN = dlog10v_dv(data0.meas, vh1.meas);
0461       otherwise
0462          error('hmm');
0463    end
0464    err_if_inf_or_nan(dN, 'init_normalization: dN');
0465 
0466 
0467 
0468 function [stop, k, r, img] = update_residual(dv, img, de, W, hp2RtR, k, r, alpha, sx, opt)
0469   stop = 0;
0470 
0471   
0472   if k == 0
0473      r = zeros(opt.max_iterations, 3);
0474      r_km1 = inf;
0475   else
0476      r_km1 = r(k, 1);
0477   end
0478   r_k = feval(opt.residual_func, dv, de, W, hp2RtR);
0479   
0480   r(k+1,1) = r_k;
0481 
0482   
0483   if opt.verbose > 1
0484      if k == 0
0485         fprintf('    calc residual, r=%0.3g\n', r_k);
0486      else
0487         fprintf('    calc residual\n');
0488         fprintf('      r =%0.3g\n', r_k);
0489         dr = (r_k - r_km1);
0490         fprintf('      dr=%0.3g (%0.3g%%)\n', dr, dr/r_km1*100);
0491      end
0492   end
0493   if opt.plot_residuals
0494      
0495      r(k+1,2:3) = [(dv'*dv)/2 (de'*de)/2];
0496      if k > 0
0497         clf;
0498         x = 1:(k+1);
0499         y = r(x, :);
0500         y = y ./ repmat(max(y,[],1),size(y,1),1) * 100;
0501         plot(x-1, y, 'o-', 'linewidth', 2, 'MarkerSize', 10);
0502         title('residuals');
0503         axis tight;
0504         ylabel('residual (% of max)');
0505         xlabel('iteration');
0506         set(gca, 'xtick', x);
0507         set(gca, 'xlim', [0 max(x)-1]);
0508         legend('residual','meas. misfit','prior misfit');
0509         legend('Location', 'EastOutside');
0510         drawnow;
0511         if isfield(opt,'fig_prefix')
0512            print('-dpdf',sprintf('%s-r%d',opt.fig_prefix,k));
0513            print('-dpng',sprintf('%s-r%d',opt.fig_prefix,k));
0514            saveas(gcf,sprintf('%s-r%d.fig',opt.fig_prefix,k));
0515         end
0516      end
0517   end
0518 
0519   
0520   
0521   if r_k > r_km1 
0522      if opt.verbose > 1
0523         fprintf('  terminated at iteration %d (bad step, returning previous iteration''s result)\n',k);
0524      end
0525      img.elem_data = img.elem_data - alpha * sx; 
0526      stop = -1;
0527   elseif k >= opt.max_iterations
0528      if opt.verbose > 1
0529         fprintf('  terminated at iteration %d (max iterations)\n',k);
0530      end
0531      stop = 1;
0532   elseif r_k < opt.tol + opt.ntol
0533      if opt.verbose > 1
0534         fprintf('  terminated at iteration %d\n',k);
0535         fprintf('    residual tolerance (%0.3g) achieved\n', opt.tol + opt.ntol);
0536      end
0537      stop = 1;
0538   elseif (k >= opt.dtol_iter) && ((r_k - r_km1)/r_km1 > opt.dtol + 2*opt.ntol)
0539      if opt.verbose > 1
0540         fprintf('  terminated at iteration %d (iterations not improving)\n', k);
0541         fprintf('    residual slope tolerance (%0.3g) exceeded\n', opt.dtol + 2*opt.ntol);
0542      end
0543      stop = 1;
0544   end
0545   if ~stop
0546      
0547      k = k+1;
0548   end
0549 
0550 
0551 
0552 function beta = update_beta(dx_k, dx_km1, sx_km1, opt);
0553    if isfield(opt, 'beta_func')
0554       if opt.verbose > 1
0555          try beta_str = func2str(opt.beta_func);
0556          catch
0557             try beta_str = opt.beta_func;
0558             catch beta_str = 'unknown';
0559             end
0560          end
0561       end
0562       beta= feval(opt.beta_func, dx_k, dx_km1, sx_km1);
0563    else
0564      beta_str = '<none>';
0565      beta = 0;
0566    end
0567    if opt.verbose > 1
0568       str = sprintf('    calc beta (%s)=%0.3f\n', beta_str, beta);
0569    end
0570 
0571 
0572 
0573 
0574 
0575 
0576 function sx = update_sx(dx, beta, sx_km1, opt);
0577    sx = dx + beta * sx_km1;
0578    if(opt.verbose > 1)
0579       nsx = norm(sx);
0580       nsxk = norm(sx_km1);
0581       fprintf( '    update step dx, beta=%0.3g, ||dx||=%0.3g\n', beta, nsx);
0582       if nsxk ~= 0
0583          fprintf( '      acceleration     d||dx||=%0.3g\n', nsx-nsxk);
0584          fprintf( '      direction change ||ddx||=%0.3g\n', norm(sx/nsx-sx_km1/nsxk));
0585       end
0586    end
0587 
0588 
0589 function hp2RtR = update_hp2RtR(inv_model, J, k, img, opt)
0590    if k==0 
0591       k=1;
0592    end
0593    
0594    
0595    
0596    if ~opt.calc_RtR_prior
0597       error('no RtR calculation mechanism, set imdl.inv_solve_abs_core.RtR_prior or imdl.RtR_prior');
0598    end
0599    if opt.verbose > 1
0600       disp('    calc hp^2 R^t R');
0601    end
0602    hp2  = calc_hyperparameter( inv_model ); 
0603    net = sum([opt.elem_len{:}]); 
0604    RtR = zeros(net,net); 
0605    esi = 0; eei = 0; 
0606    for i = 1:size(opt.RtR_prior,1) 
0607       esi = eei + 1;
0608       eei = eei + opt.elem_len{i};
0609       esj = 0; eej = 0; 
0610       for j = 1:size(opt.RtR_prior,2) 
0611          esj = eej + 1;
0612          eej = eej + opt.elem_len{j};
0613          if isempty(opt.RtR_prior{i,j}) 
0614             continue; 
0615          end
0616 
0617          
0618          
0619          hp=opt.hyperparameter{i,j};
0620          if length(hp) > k
0621             hp=hp(k);
0622          else
0623             hp=hp(end);
0624          end
0625 
0626          if opt.verbose > 1
0627             try RtR_str = func2str(opt.RtR_prior{i,j});
0628             catch
0629                try RtR_str = opt.RtR_prior{i,j};
0630                catch RtR_str = 'unknown';
0631                end
0632             end
0633             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));
0634          end
0635          imgt = map_img(img, opt.elem_working{i});
0636          inv_modelt = inv_model;
0637          inv_modelt.RtR_prior = opt.RtR_prior{i,j};
0638          RtR(esi:eei, esj:eej) = hp.^2 * calc_RtR_prior_wrapper(inv_modelt, imgt, opt);
0639       end
0640    end
0641    hp2RtR = hp2*RtR;
0642 
0643 function plot_svd_elem(J, W, hp2RtR, k, sx, dx, img, opt)
0644    if opt.verbose < 1
0645       return; 
0646    end
0647    
0648    if ~isfield(img, 'params_sel')
0649       img.params_sel = {1:length(img.elem_data)};
0650    end
0651    if ~isfield(img, 'current_params')
0652       img.current_params = 'conductivity';
0653    end
0654    if ~iscell(img.current_params)
0655       img.current_params = {img.current_params};
0656    end
0657    
0658    cols=length(opt.elem_working);
0659    if norm(sx - dx) < range(dx)/max(dx)*0.01 
0660       rows=2;
0661    else
0662       rows=3;
0663    end
0664    clf; 
0665    for i=1:cols
0666       if 1 
0667          hp=opt.hyperparameter{i};
0668          if k ~= 0 && k < length(hp)
0669             hp = hp(k);
0670          else
0671             hp = hp(end);
0672          end
0673       else
0674          hp = [];
0675       end
0676       sel=img.params_sel{i};
0677       str=strrep(img.current_params{i},'_',' ');
0678       plot_svd(J(:,sel), W, hp2RtR(sel,sel), k, hp); xlabel(str);
0679       drawnow;
0680       if isfield(opt,'fig_prefix')
0681          print('-dpdf',sprintf('%s-svd%d-%s',opt.fig_prefix,k,img.current_params{i}));
0682          print('-dpng',sprintf('%s-svd%d-%s',opt.fig_prefix,k,img.current_params{i}));
0683          saveas(gcf,sprintf('%s-svd%d-%s.fig',opt.fig_prefix,k,img.current_params{i}));
0684       end
0685    end
0686    clf; 
0687    for i=1:cols
0688       if 1 
0689          hp=opt.hyperparameter{i};
0690          if k ~= 0 && k < length(hp)
0691             hp = hp(k);
0692          else
0693             hp = hp(end);
0694          end
0695       else
0696          hp = [];
0697       end
0698       subplot(rows,cols,i);
0699       sel=img.params_sel{i};
0700       str=strrep(img.current_params{i},'_',' ');
0701       plot_svd(J(:,sel), W, hp2RtR(sel,sel), k, hp); xlabel(str);
0702       subplot(rows,cols,cols+i);
0703       bar(dx(sel)); ylabel(['dx: ' str]);
0704       if rows > 2
0705          subplot(rows,cols,2*cols+i);
0706          bar(sx(sel)); ylabel(['sx: ' str]);
0707       end
0708    end
0709    drawnow;
0710    if isfield(opt,'fig_prefix')
0711       print('-dpdf',sprintf('%s-svd%d',opt.fig_prefix,k));
0712       print('-dpng',sprintf('%s-svd%d',opt.fig_prefix,k));
0713       saveas(gcf,sprintf('%s-svd%d.fig',opt.fig_prefix,k));
0714    end
0715 
0716 function plot_svd(J, W, hp2RtR, k, hp)
0717    if nargin < 5
0718       hp = [];
0719    end
0720    
0721    [~,s1,~]=svd(J'*W*J); s1=sqrt(diag(s1));
0722    [~,s2,~]=svd(J'*W*J + hp2RtR); s2=sqrt(diag(s2));
0723    h=semilogy(s1,'bx'); axis tight; set(h,'LineWidth',2);
0724    hold on; h=semilogy(s2,'go'); axis tight; set(h,'LineWidth',2); hold off;
0725    xlabel('k'); ylabel('value \sigma');
0726    title(sprintf('singular values of J at iteration %d',k));
0727    legend('J^T J', 'J^T J + \lambda^2 R^T R'); legend location best;
0728    
0729 
0730 
0731 
0732 
0733 
0734 
0735    if length(hp)==1
0736         h=line([1 length(s1)],[hp hp]);
0737         ly=10^(log10(hp)-0.05*range(log10([s1;s2])));
0738         text(length(s1)/2,ly,sprintf('\\lambda = %0.4g', hp));
0739 
0740      end
0741      set(h,'LineStyle','-.'); set(h,'LineWidth',2);
0742    set(gca,'YMinorTick','on', 'YMinorGrid', 'on', 'YGrid', 'on');
0743 
0744 
0745 
0746 function RtR = calc_RtR_prior_wrapper(inv_model, img, opt)
0747    RtR = calc_RtR_prior( inv_model );
0748    if size(RtR,1) < length(img.elem_data)
0749      ne = length(img.elem_data) - size(RtR,1);
0750      
0751      for i=1:ne
0752        RtR(end+1:end+1, end+1:end+1) = RtR(1,1);
0753      end
0754      if opt.verbose > 1
0755         fprintf('      c2f: adjusting RtR by appending %d rows/cols\n', ne);
0756         disp(   '      TODO move this fix, or something like it to calc_RtR_prior -- this fix is a quick HACK to get things to run...');
0757      end
0758    end
0759 
0760 
0761 function [J, opt] = update_jacobian(img, dN, k, opt)
0762    k=k+1;
0763    base_types = map_img_base_types(img);
0764    imgb = map_img(img, base_types);
0765    imgb = feval(opt.update_img_func, imgb, opt);
0766    
0767    
0768    if any(strcmp(map_img_base_types(img), 'movement')) && any(strcmp(opt.meas_working, 'apparent_resistivity'))
0769       imgh = map_img(imgb, 'conductivity'); 
0770       imgh.elem_data = imgh.elem_data*0 +1; 
0771       vh = fwd_solve(imgh); vh = vh.meas;
0772       dN = da_dv(1,vh); 
0773       opt.fwd_solutions = opt.fwd_solutions +1;
0774    end
0775    ee = 0; 
0776    pp = fwd_model_parameters(imgb.fwd_model);
0777    J = zeros(pp.n_meas,sum([opt.elem_len{:}]));
0778    for i=1:length(opt.jacobian)
0779      if(opt.verbose > 1)
0780         try J_str = func2str(opt.jacobian{i});
0781         catch J_str = opt.jacobian{i};
0782         end
0783         if i == 1 fprintf('    calc Jacobian J(x) = ');
0784         else      fprintf('                       + '); end
0785         fprintf('(%s,', J_str);
0786      end
0787      
0788      es = ee+1;
0789      ee = es+opt.elem_len{i}-1;
0790      
0791      S = feval(opt.calc_jacobian_scaling_func{i}, imgb.elem_data(es:ee)); 
0792      
0793      
0794      
0795      imgt = imgb;
0796      if  strcmp(base_types{i}, 'conductivity') 
0797         imgt = map_img(img, 'conductivity');
0798      end
0799      imgt.fwd_model.jacobian = opt.jacobian{i};
0800      Jn = calc_jacobian( imgt ); 
0801      J(:,es:ee) = dN * Jn * S; 
0802      if opt.verbose > 1
0803         tmp = zeros(1,size(J,2));
0804         tmp(es:ee) = 1;
0805         tmp(opt.elem_fixed) = 0;
0806         fprintf(' %d DoF, %d meas, %s)\n', sum(tmp), size(J,1), func2str(opt.calc_jacobian_scaling_func{i}));
0807      end
0808      if opt.verbose >= 5
0809         clf;
0810         t=axes('Position',[0 0 1 1],'Visible','off'); 
0811         text(0.03,0.1,sprintf('update\\_jacobian (%s), iter=%d', strrep(J_str,'_','\_'), k),'FontSize',20,'Rotation',90);
0812         for y=0:1
0813            if y == 0; D = Jn; else D = J(:,es:ee); end
0814            axes('units', 'normalized', 'position', [ 0.13 0.62-y/2 0.8 0.3 ]);
0815            imagesc(D);
0816            if y == 0; ylabel('meas (1)'); xlabel(['elem (' strrep(base_types{i},'_','\_') ')']);
0817            else       ylabel('meas (dN)'); xlabel(['elem (' strrep(opt.elem_working{i},'_','\_') ')']);
0818            end
0819            os = get(gca, 'Position'); c=colorbar('southoutside'); 
0820            set(gca, 'Position', os); 
0821            
0822            cP = get(c,'Position'); set(c,'Position', [0.13    0.54-y/2    0.8    0.010]);
0823            axes('units', 'normalized', 'position', [ 0.93 0.62-y/2 0.05 0.3 ]);
0824            barh(sum(D,2)); axis tight; axis ij; set(gca, 'ytick', [], 'yticklabel', []);
0825            axes('units', 'normalized', 'position', [ 0.13 0.92-y/2 0.8 0.05 ]);
0826            bar(sum(D,1)); axis tight; set(gca, 'xtick', [], 'xticklabel', []);
0827         end
0828         drawnow;
0829         if isfield(opt,'fig_prefix')
0830            print('-dpng',sprintf('%s-J%d-%s',opt.fig_prefix,k,strrep(J_str,'_','')));
0831            print('-dpdf',sprintf('%s-J%d-%s',opt.fig_prefix,k,strrep(J_str,'_','')));
0832            saveas(gcf,sprintf('%s-J%d-%s.fig',opt.fig_prefix,k,strrep(J_str,'_','')));
0833         end
0834      end
0835    end
0836 
0837 
0838 
0839 
0840 
0841 
0842 
0843 
0844 
0845 
0846 
0847 function S = dx_dlogx(x);
0848    S = spdiag(x);
0849 function S = dx_dlog10x(x);
0850    S = spdiag(x * log(10));
0851 
0852 
0853 
0854 
0855 function S = dx_dy(x);
0856    S = spdiag(-(x.^2));
0857 
0858 function S = dx_dlogy(x);
0859 
0860 
0861    S = spdiag(-x);
0862 function S = dx_dlog10y(x);
0863 
0864 
0865    S = spdiag(-x/log(10));
0866 
0867 
0868 
0869 
0870 
0871 
0872 
0873 
0874 
0875 
0876 
0877 
0878 
0879 
0880 function dN = da_dv(v,vh)
0881    dN = spdiag(1./vh); 
0882 function dN = dloga_dv(v,vh)
0883    dN = spdiag(1./v);
0884 function dN = dlog10a_dv(v,vh)
0885    dN = spdiag( 1./(v * log(10)) );
0886 function dN = dv_dv(v,vh)
0887    dN = 1;
0888 function dN = dlogv_dv(v,vh) 
0889    dN = dloga_dv(v,vh);
0890 function dN = dlog10v_dv(v,vh) 
0891    dN = dlog10a_dv(v, vh);
0892 
0893 
0894 
0895 function [alpha, img, dv, opt] = update_alpha(img, sx, data0, img0, N, W, hp2RtR, k, dv, opt)
0896   if k == 0 
0897      alpha = 0;
0898      return;
0899   end
0900 
0901   if(opt.verbose > 1)
0902      try ls_str = func2str(opt.line_search_func);
0903      catch ls_str = opt.line_search_func;
0904      end
0905      fprintf('    line search, alpha = %s\n', ls_str);
0906   end
0907 
0908   
0909   err_if_inf_or_nan(sx, 'sx (pre-line search)');
0910   err_if_inf_or_nan(img.elem_data, 'img.elem_data (pre-line search)');
0911 
0912   if any(size(img.elem_data) ~= size(sx))
0913      error(sprintf('mismatch on elem_data[%d,%d] vs. sx[%d,%d] vector sizes, check c2f_background_fixed',size(img.elem_data), size(sx)));
0914   end
0915 
0916   [alpha, imgo, dv, opto] = feval(opt.line_search_func, img, sx, data0, img0, N, W, hp2RtR, dv, opt);
0917   if ~isempty(imgo)
0918      img = imgo;
0919   else
0920      img.elem_data = img.elem_data + alpha*sx;
0921   end
0922   if ~isempty(opto)
0923      opt = opto;
0924   end
0925 
0926   if(opt.verbose > 1)
0927      fprintf('      selected alpha=%0.3g\n', alpha);
0928   end
0929 
0930   if (alpha == 0) && (k == 1)
0931     error('first iteration failed to advance solution');
0932   end
0933 
0934 function err_if_inf_or_nan(x, str);
0935   if any(any(isnan(x) | isinf(x)))
0936       error(sprintf('bad %s (%d NaN, %d Inf of %d)', ...
0937                     str, ...
0938                     length(find(isnan(x))), ...
0939                     length(find(isinf(x))), ...
0940                     length(x(:))));
0941   end
0942 
0943 
0944 function [img, dv] = update_img_using_limits(img, img0, data0, N, dv, opt)
0945   
0946   if opt.max_value ~= +inf
0947      lih = find(img.elem_data > opt.max_value);
0948      img.elem_data(lih) = opt.max_value;
0949      if opt.verbose > 1
0950         fprintf('    limit max(x)=%g for %d elements\n', opt.max_value, length(lih));
0951      end
0952      dv = []; 
0953   end
0954   if opt.min_value ~= -inf
0955      lil = find(img.elem_data < opt.min_value);
0956      img.elem_data(lil) = opt.min_value;
0957      if opt.verbose > 1
0958         fprintf('    limit min(x)=%g for %d elements\n', opt.min_value, length(lil));
0959      end
0960      dv = []; 
0961   end
0962   
0963   [dv, opt] = update_dv(dv, img, data0, N, opt, '(dv out-of-date)');
0964 
0965 function  de = update_de(de, img, img0, opt)
0966    img0 = map_img(img0, opt.elem_working);
0967    img  = map_img(img,  opt.elem_working);
0968    err_if_inf_or_nan(img0.elem_data, 'de img0');
0969    err_if_inf_or_nan(img.elem_data,  'de img');
0970    
0971    
0972    
0973    if isempty(de) 
0974       
0975       de = zeros(size(img0.elem_data));
0976    else
0977       de = img0.elem_data - img.elem_data;
0978    end
0979    de(opt.elem_fixed) = 0; 
0980    err_if_inf_or_nan(de, 'de out');
0981 
0982 function [dv, opt] = update_dv(dv, img, data0, N, opt, reason)
0983    
0984    if ~isempty(dv) 
0985       return;
0986    end
0987    if nargin < 7
0988       reason = '';
0989    end
0990    if opt.verbose > 1
0991       disp(['    fwd_solve b=Ax ', reason]);
0992    end
0993    [dv, opt, err] = update_dv_core(img, data0, N, opt);
0994 
0995 
0996 
0997 function data = map_meas_struct(data, N, out)
0998    try   current_meas_params = data.current_params;
0999    catch current_meas_params = 'voltage';
1000    end
1001    data.meas = map_meas(data.meas, N, current_meas_params, out);
1002    data.current_params = out;
1003    err_if_inf_or_nan(data.meas, 'dv meas');
1004 
1005 
1006 function [dv, opt, err] = update_dv_core(img, data0, N, opt)
1007    data0 = map_meas_struct(data0, N, 'voltage');
1008    img = map_img(img, map_img_base_types(img));
1009    img = feval(opt.update_img_func, img, opt);
1010    img = map_img(img, 'conductivity'); 
1011    
1012    if any(any(N ~= 1)) && any(strcmp(map_img_base_types(img), 'movement'))
1013       
1014       imgh=img; imgh.elem_data = imgh.elem_data*0 +1; 
1015       vh = fwd_solve(imgh); vh = vh.meas;
1016       N = spdiag(1./vh);
1017       opt.fwd_solutions = opt.fwd_solutions +1;
1018    end
1019    data = fwd_solve(img);
1020    opt.fwd_solutions = opt.fwd_solutions +1;
1021    dv = calc_difference_data(data, data0, img.fwd_model);
1022    if nargout >= 3
1023       err = norm(dv)/norm(data0.meas);
1024    else
1025       err = NaN;
1026    end
1027    dv = map_meas(dv, N, 'voltage', opt.meas_working);
1028    err_if_inf_or_nan(dv, 'dv out');
1029 
1030 function show_fem_iter(k, img, inv_model, stop, opt)
1031   if (opt.verbose < 4) || (stop == -1)
1032      return; 
1033   end
1034   if opt.verbose > 1
1035      disp('    show_fem()');
1036   end
1037   img = map_img(img, 'resistivity'); 
1038   [img, opt] = strip_c2f_background(img, opt, '    ');
1039   
1040   if isfield(inv_model, 'rec_model')
1041     img.fwd_model = inv_model.rec_model;
1042   end
1043 
1044 
1045 
1046   img.calc_colours.cb_shrink_move = [0.3,0.6,0.02]; 
1047   if size(img.elem_data,1) ~= size(img.fwd_model.elems,1)
1048      warning(sprintf('img.elem_data has %d elements, img.fwd_model.elems has %d elems\n', ...
1049                      size(img.elem_data,1), ...
1050                      size(img.fwd_model.elems,1)));
1051   end
1052   clf; feval(opt.show_fem, img, 1);
1053   title(sprintf('iter=%d',k));
1054   drawnow;
1055   if isfield(opt,'fig_prefix')
1056      print('-dpdf',sprintf('%s-fem%d',opt.fig_prefix,k));
1057      print('-dpng',sprintf('%s-fem%d',opt.fig_prefix,k));
1058      saveas(gcf,sprintf('%s-fem%d.fig',opt.fig_prefix,k));
1059   end
1060 
1061 
1062 function residual = GN_residual(dv, de, W, hp2RtR)
1063 
1064    
1065    residual = 0.5*( dv'*W*dv + de'*hp2RtR*de);
1066 
1067 function residual = meas_residual(dv, de, W, hp2RtR)
1068    residual = norm(dv);
1069 
1070 
1071 
1072 
1073 
1074 
1075 
1076 
1077 
1078 
1079 
1080 
1081 
1082 
1083 
1084 
1085 
1086 
1087 
1088 
1089 
1090 
1091 
1092 
1093 
1094 
1095 
1096 
1097 
1098 
1099 
1100 
1101 
1102 
1103 
1104 
1105 
1106 
1107 
1108 
1109 
1110 
1111 
1112 
1113 
1114 
1115 
1116 
1117 
1118 
1119 
1120 
1121 
1122 
1123 
1124 
1125 
1126 
1127 
1128 
1129 
1130 
1131 
1132 
1133 
1134 
1135 
1136 
1137 
1138 function imdl = deprecate_imdl_opt(imdl,opt)
1139    if ~isfield(imdl, opt)
1140       return;
1141    end
1142    if ~isstruct(imdl.(opt))
1143       error(['unexpected inv_model.' opt ' where ' opt ' is not a struct... i do not know what to do']);
1144    end
1145 
1146    
1147    Af = fieldnames(imdl.(opt));
1148    if ~strcmp(opt, 'inv_solve') || (length(Af(:)) ~= 1) || ~strcmp(Af(:),'calc_solution_error')
1149       disp(imdl)
1150       disp(imdl.(opt))
1151       warning('EIDORS:deprecatedParameters',['INV_SOLVE inv_model.' opt '.* are deprecated in favor of inv_model.inv_solve_abs_core.* as of 30-Apr-2014.']);
1152    end
1153 
1154    if ~isfield(imdl, 'inv_solve_abs_core')
1155       imdl.inv_solve_abs_core = imdl.(opt);
1156    else 
1157       
1158       
1159       for i = fieldnames(imdl.(opt))'
1160          imdl.inv_solve_abs_core.(i{1})=imdl.(opt).(i{1});
1161       end
1162    end
1163    imdl = rmfield(imdl, opt);
1164 
1165 function opt = parse_options(imdl)
1166    
1167 
1168 
1169 
1170    
1171    if isfield(imdl, 'inv_solve_abs_core')
1172       opt = imdl.inv_solve_abs_core;
1173    else
1174       opt = struct;
1175    end
1176 
1177    
1178    
1179    
1180    
1181    if ~isfield(opt,'verbose')
1182       opt.verbose = 4;
1183       fprintf('  inv_model.inv_solve_abs_core.verbosity not set; defaulting to verbosity=4. See help for details.\n');
1184    end
1185    if opt.verbose > 1
1186       fprintf('  setting default parameters\n');
1187    end
1188    
1189    opt.fwd_solutions = 0;
1190 
1191    if ~isfield(opt, 'show_fem')
1192       opt.show_fem = @show_fem;
1193    end
1194 
1195    if ~isfield(opt, 'residual_func') 
1196       opt.residual_func = @GN_residual; 
1197       
1198       
1199       
1200       
1201    end
1202 
1203    
1204    if ~isfield(opt, 'update_func')
1205       opt.update_func = @GN_update; 
1206    end
1207    
1208    if ~isfield(opt, 'calc_meas_icov') 
1209       opt.calc_meas_icov = 0; 
1210    end
1211    if ~isfield(opt, 'calc_RtR_prior') 
1212       opt.calc_RtR_prior = 0; 
1213    end
1214    if ~isfield(opt, 'calc_hyperparameter')
1215       opt.calc_hyperparameter = 0; 
1216    end
1217 
1218 
1219       if opt.verbose > 1
1220          fprintf('    examining function %s(...) for required arguments\n', func2str(opt.update_func));
1221       end
1222       
1223       
1224 
1225       args = ones(4,1); 
1226       if args(2) == 1
1227          opt.calc_meas_icov = 1;
1228       end
1229       if args(3) == 1
1230          opt.calc_hyperparameter = 1;
1231       end
1232       if args(4) == 1
1233          opt.calc_RtR_prior = 1;
1234       end
1235 
1236 
1237 
1238 
1239    
1240    if ~isfield(opt, 'max_iterations')
1241       opt.max_iterations = 10;
1242    end
1243    if ~isfield(opt, 'ntol')
1244       opt.ntol = eps; 
1245    end
1246    if ~isfield(opt, 'tol')
1247       opt.tol = 0; 
1248    end
1249    if ~isfield(opt, 'dtol')
1250       
1251       
1252       
1253       
1254       opt.dtol = -1e-4; 
1255    end
1256    if ~isfield(opt, 'dtol_iter')
1257       
1258       opt.dtol_iter = 0; 
1259    end
1260    if ~isfield(opt, 'min_value')
1261       opt.min_value = -inf; 
1262    end
1263    if ~isfield(opt, 'max_value')
1264       opt.max_value = +inf; 
1265    end
1266    
1267    if ~isfield(opt, 'plot_residuals')
1268       if opt.verbose > 2
1269          opt.plot_residuals = 1;
1270       else
1271          opt.plot_residuals = 0;
1272       end
1273    end
1274    if opt.plot_residuals ~= 0
1275       disp('  residual plot (updated per iteration) are enabled, to disable them set');
1276       disp('    inv_model.inv_solve_abs_core.plot_residuals=0');
1277    end
1278 
1279    
1280    if ~isfield(opt,'line_search_func')
1281       
1282       opt.line_search_func = @line_search_onm2;
1283    end
1284    if ~isfield(opt,'line_search_dv_func')
1285       opt.line_search_dv_func = @update_dv_core;
1286       
1287    end
1288    if ~isfield(opt,'line_search_de_func')
1289       
1290       
1291       opt.line_search_de_func = @(img, img0, opt) update_de(1, img, img0, opt);
1292       
1293    end
1294    
1295    
1296    if ~isfield(opt,'line_search_args') || ...
1297       ~isfield(opt.line_search_args, 'perturb')
1298       fmin = 1/4; 
1299       opt.line_search_args.perturb = [0 fmin/4 fmin/2 fmin fmin*2 fmin*4];
1300       
1301       
1302       
1303       
1304       
1305    end
1306    
1307    if ~isfield(opt,'line_search_args') || ...
1308       ~isfield(opt.line_search_args, 'plot')
1309       if opt.verbose >= 5
1310          opt.line_search_args.plot = 1;
1311       else
1312          opt.line_search_args.plot = 0;
1313       end
1314    end
1315    
1316    if isfield(opt,'fig_prefix') && ...
1317       isfield(opt,'line_search_args') && ...
1318       ~isfield(opt.line_search_args, 'fig_prefix')
1319       opt.line_search_args.fig_prefix = opt.fig_prefix;
1320    end
1321    
1322    if opt.line_search_args.plot ~= 0
1323       disp('  line search plots (per iteration) are enabled, to disable them set');
1324       disp('    inv_model.inv_solve_abs_core.line_search_args.plot=0');
1325    end
1326 
1327    
1328    
1329    
1330    if ~isfield(opt, 'c2f_background')
1331      if isfield(imdl, 'fwd_model') && isfield(imdl.fwd_model, 'coarse2fine')
1332         opt.c2f_background = -1; 
1333      else
1334         opt.c2f_background = 0;
1335      end
1336    end
1337    if ~isfield(opt, 'c2f_background_fixed')
1338       opt.c2f_background_fixed = 1; 
1339    end
1340 
1341 
1342    
1343    
1344    if ~isfield(opt, 'elem_working')
1345       opt.elem_working = {'conductivity'};
1346    end
1347    if ~isfield(opt, 'elem_prior')
1348       opt.elem_prior = opt.elem_working;
1349    end
1350    if ~isfield(opt, 'elem_output')
1351       opt.elem_output = {'conductivity'};
1352    end
1353    if ~isfield(opt, 'meas_input')
1354       opt.meas_input = 'voltage';
1355    end
1356    if ~isfield(opt, 'meas_working')
1357       opt.meas_working = 'voltage';
1358    end
1359    
1360    
1361    
1362    for i = {'elem_working', 'elem_prior', 'elem_output'}; 
1363      
1364      
1365      x = opt.(i{1});
1366      if ~iscell(x)
1367         opt.(i{1}) = {x};
1368      end
1369    end
1370 
1371    if ~isfield(opt, 'prior_data')
1372       if isfield(imdl, 'jacobian_bkgnd') && ...
1373          isfield(imdl.jacobian_bkgnd, 'value') && ...
1374          length(opt.elem_prior) == 1
1375          opt.prior_data = {imdl.jacobian_bkgnd.value};
1376       else
1377          error('requires inv_model.inv_solve_abs_core.prior_data');
1378       end
1379    end
1380 
1381    if ~isfield(opt, 'elem_len')
1382       if length(opt.elem_working) == 1
1383          if isfield(imdl.fwd_model, 'coarse2fine')
1384             c2f = imdl.fwd_model.coarse2fine; 
1385             opt.elem_len = { size(c2f,2) };
1386          else
1387             opt.elem_len = { size(imdl.fwd_model.elems,1) };
1388          end
1389       else
1390         error('requires inv_model.inv_solve_abs_core.elem_len');
1391       end
1392    end
1393 
1394    
1395    
1396    
1397    if ~isfield(opt, 'elem_fixed') 
1398       opt.elem_fixed = [];
1399    elseif iscell(opt.elem_fixed) 
1400      
1401      
1402       offset=0;
1403       ef=[];
1404       for i=1:length(opt.elem_fixed)
1405          ef = [ef, opt.elem_fixed{i} + offset];
1406          offset = offset + opt.elem_len{i};
1407       end
1408       opt.elem_fixed = ef;
1409    end
1410 
1411    
1412    if ~isfield(opt, 'jacobian')
1413       opt.jacobian = imdl.fwd_model.jacobian;
1414    elseif isfield(imdl.fwd_model, 'jacobian')
1415       imdl.fwd_model
1416       imdl
1417       error('inv_model.fwd_model.jacobian and inv_model.inv_solve_abs_core.jacobian should not both exist: it''s ambiguous');
1418    end
1419    
1420    if ~isfield(opt, 'hyperparameter')
1421       opt.hyperparameter = {[]};
1422       for i=1:length(opt.elem_working)
1423          opt.hyperparameter{i} = 1;
1424       end
1425    end
1426    
1427    
1428    
1429    for i = {'elem_len', 'prior_data', 'jacobian', 'hyperparameter'}
1430      
1431      
1432      x = opt.(i{1});
1433      if ~iscell(x)
1434         opt.(i{1}) = {x};
1435      end
1436    end
1437    
1438    if opt.verbose > 1
1439       fprintf('  hyperparameters\n');
1440       for i=1:length(opt.elem_working)
1441          if isnumeric(opt.hyperparameter{i}) && length(opt.hyperparameter{i}) == 1
1442             fprintf('    %s: %0.4g\n',opt.elem_working{i}, opt.hyperparameter{i});
1443          elseif isa(opt.hyperparameter{i}, 'function_handle')
1444             fprintf('    %s: @%s\n',opt.elem_working{i}, func2str(opt.hyperparameter{i}));
1445          elseif ischar(opt.hyperparameter{i})
1446             fprintf('    %s: @%s\n',opt.elem_working{i}, opt.hyperparameter{i});
1447          else
1448             fprintf('    %s: ...\n',opt.elem_working{i});
1449          end
1450       end
1451    end
1452 
1453    
1454    
1455    
1456    
1457    if ~isfield(opt, 'RtR_prior')
1458       if isfield(imdl, 'RtR_prior')
1459          opt.RtR_prior = {imdl.RtR_prior};
1460       else
1461          opt.RtR_prior = {[]}; 
1462          warning('missing imdl.inv_solve_abs_core.RtR_prior or imdl.RtR_prior: assuming NO regularization RtR=0');
1463       end
1464    end
1465    
1466    
1467    if isnumeric(opt.RtR_prior)
1468       if size(opt.RtR_prior, 1) ~= size(opt.RtR_prior, 2)
1469          error('expecting square matrix for imdl.RtR_prior or imdl.inv_solve_abs_core.RtR_prior');
1470       end
1471       if length(opt.RtR_prior) == 1
1472          opt.RtR_prior = {opt.RtR_prior}; 
1473       else
1474          RtR = opt.RtR_prior;
1475          opt.RtR_prior = {[]};
1476          esi = 0; eei = 0;
1477          for i=1:length(opt.elem_len)
1478             esi = eei +1;
1479             eei = eei +opt.elem_len{i};
1480             esj = 0; eej = 0;
1481             for j=1:length(opt.elem_len)
1482                esj = eej +1;
1483                eej = eej +opt.elem_len{j};
1484                opt.RtR_prior(i,j) = RtR(esi:eei, esj:eej);
1485             end
1486          end
1487       end
1488    elseif ~iscell(opt.RtR_prior) 
1489       opt.RtR_prior = {opt.RtR_prior};
1490    end
1491    
1492    
1493    if any(size(opt.RtR_prior) ~= ([1 1]*length(opt.elem_len)))
1494       if (size(opt.RtR_prior, 1) ~= 1) && ...
1495          (size(opt.RtR_prior, 2) ~= 1)
1496          error('odd imdl.RtR_prior or imdl.inv_solve_abs_core.RtR_prior, cannot figure out how to expand it blockwise');
1497       end
1498       if (size(opt.RtR_prior, 1) ~= length(opt.elem_len)) && ...
1499          (size(opt.RtR_prior, 2) ~= length(opt.elem_len))
1500          error('odd imdl.RtR_prior or imdl.inv_solve_abs_core.RtR_prior, not enough blockwise components vs. elem_working types');
1501       end
1502       RtR_diag = opt.RtR_prior;
1503       opt.RtR_prior = {[]}; 
1504       for i=1:length(opt.elem_len)
1505          opt.RtR_prior(i,i) = RtR_diag(i);
1506       end
1507    end
1508 
1509    
1510    hp=opt.hyperparameter;
1511    if size(hp,2) == 1 
1512       hp = hp'; 
1513    end
1514    if iscell(hp)
1515       
1516       if all(size(hp) == size(opt.RtR_prior))
1517          opt.hyperparameter = hp;
1518       
1519       elseif length(hp) == length(opt.RtR_prior)
1520          opt.hyperparameter = opt.RtR_prior;
1521          [opt.hyperparameter{:}] = deal(1); 
1522          opt.hyperparameter(logical(eye(size(opt.RtR_prior)))) = hp; 
1523       else
1524          error('hmm, don''t understand this opt.hyperparameter cellarray');
1525       end
1526    
1527    elseif isnumeric(hp)
1528       opt.hyperparameter = opt.RtR_prior;
1529       [opt.hyperparameter{:}] = deal({hp});
1530    else
1531       error('don''t understand this opt.hyperparameter');
1532    end
1533 
1534    
1535    
1536    
1537    
1538    
1539    if ~isfield(opt, 'calc_jacobian_scaling_func')
1540       pinv = strfind(opt.elem_working, 'resistivity');
1541       plog = strfind(opt.elem_working, 'log_');
1542       plog10 = strfind(opt.elem_working, 'log10_');
1543       for i = 1:length(opt.elem_working)
1544         prefix = '';
1545         if plog{i}
1546            prefix = 'log';
1547         elseif plog10{i}
1548            prefix = 'log10';
1549         else
1550            prefix = '';
1551         end
1552         if pinv{i}
1553            prefix = [prefix '_inv'];
1554         end
1555         switch(prefix)
1556           case ''
1557              opt.calc_jacobian_scaling_func{i} = @ret1_func;  
1558           case 'log'
1559              opt.calc_jacobian_scaling_func{i} = @dx_dlogx;   
1560           case 'log10'
1561              opt.calc_jacobian_scaling_func{i} = @dx_dlog10x; 
1562           case '_inv'
1563              opt.calc_jacobian_scaling_func{i} = @dx_dy;      
1564           case 'log_inv'
1565              opt.calc_jacobian_scaling_func{i} = @dx_dlogy;   
1566           case 'log10_inv'
1567              opt.calc_jacobian_scaling_func{i} = @dx_dlog10y; 
1568           otherwise
1569              error('oops');
1570        end
1571      end
1572    end
1573 
1574    if ~isfield(opt, 'update_img_func')
1575       opt.update_img_func = @null_func; 
1576    end
1577 
1578    if ~isfield(opt, 'return_working_variables')
1579       opt.return_working_variables = 0;
1580    end
1581 
1582 function check_matrix_sizes(J, W, hp2RtR, dv, de, opt)
1583    
1584    
1585    
1586    ne = size(de,1);
1587    nv = size(dv,1);
1588    if size(de,2) ~= 1
1589       error('de cols (%d) not equal 1', size(de,2));
1590    end
1591    if size(dv,2) ~= 1
1592       error('dv cols (%d) not equal 1', size(dv,2));
1593    end
1594    if opt.calc_meas_icov && ...
1595       any(size(W) ~= [nv nv])
1596       error('W size (%d rows, %d cols) is incorrect (%d rows, %d cols)', size(W), nv, nv);
1597    end
1598    if any(size(J) ~= [nv ne])
1599       error('J size (%d rows, %d cols) is incorrect (%d rows, %d cols)', size(J), nv, ne);
1600    end
1601    if opt.calc_RtR_prior && ...
1602       any(size(hp2RtR) ~= [ne ne])
1603       error('hp2RtR size (%d rows, %d cols) is incorrect (%d rows, %d cols)', size(hp2RtR), ne, ne);
1604    end
1605 
1606 function dx = update_dx(J, W, hp2RtR, dv, de, opt)
1607    if(opt.verbose > 1)
1608       fprintf( '    calc step size dx\n');
1609    end
1610 
1611    
1612    de(opt.elem_fixed) = 0;
1613 
1614    
1615    check_matrix_sizes(J, W, hp2RtR, dv, de, opt)
1616 
1617    
1618    J(:,opt.elem_fixed) = 0;
1619    de(opt.elem_fixed,:) = 0;
1620    hp2RtR(opt.elem_fixed,:) = 0;
1621    V=opt.elem_fixed;
1622    N=size(hp2RtR,1)+1;
1623    hp2RtR(N*(V-1)+1) = 1; 
1624    
1625    dx = feval(opt.update_func, J, W, hp2RtR, dv, de);
1626 
1627    
1628    if any(dx(opt.elem_fixed) ~= 0)
1629       error('elem_fixed did''t give dx=0 at update_dx')
1630    end
1631 
1632    if(opt.verbose > 1)
1633       fprintf('      ||dx||=%0.3g\n', norm(dx));
1634       es = 0; ee = 0;
1635       for i=1:length(opt.elem_working)
1636           es = ee +1; ee = ee + opt.elem_len{i};
1637           nd = norm(dx(es:ee));
1638           fprintf( '      ||dx_%d||=%0.3g (%s)\n',i, nd, opt.elem_working{i});
1639       end
1640    end
1641 
1642 function dx = GN_update(J, W, hp2RtR, dv, de)
1643    
1644    dx = (J'*W*J + hp2RtR)\(J'*dv + hp2RtR*de);
1645 
1646 
1647 
1648 function args = function_depends_upon(func, argn)
1649    
1650    str = sprintf('%s(',func2str(func));
1651    args = zeros(argn,1);
1652    for i = 1:argn-1
1653       str = [str sprintf('a(%d),',i)];
1654    end
1655    str = [str sprintf('a(%d))',argn)];
1656    
1657    a = ones(argn,1)*2;
1658    x = eval(str);
1659    
1660    for i = 1:argn
1661       a = ones(argn,1)*2;
1662       a(i) = 0;
1663       y = eval(str);
1664       if any(x ~= y)
1665          args(i) = 1;
1666       end
1667    end
1668 
1669 
1670 function out = null_func(in, varargin);
1671    out = in;
1672 
1673 
1674 function [out, x, y, z] = ret1_func(varargin);
1675    out = 1;
1676    x = [];
1677    y = [];
1678    z = [];
1679 
1680 
1681 
1682 function [inv_model, opt] = append_c2f_background(inv_model, opt)
1683     
1684     
1685     if opt.c2f_background >= 0
1686       return
1687     end
1688     
1689     
1690     c2f = inv_model.fwd_model.coarse2fine; 
1691     nf = size(inv_model.fwd_model.elems,1); 
1692     nc = size(c2f,2); 
1693     
1694     
1695     
1696     
1697     
1698     
1699     fel = sum(c2f,2); 
1700     n = find(fel < 1 - (1e3+nc)*eps);
1701     
1702     
1703     
1704     
1705     if length(n) ~= 0
1706       if(opt.verbose > 1)
1707         fprintf('  c2f: adding background conductivity to %d\n    fwd_model elements not covered by rec_model\n', length(n));
1708       end
1709       c2f(n,nc+1) = 1 - fel(n);
1710       inv_model.fwd_model.coarse2fine = c2f;
1711       opt.c2f_background = nc+1;
1712       if opt.c2f_background_fixed
1713          
1714          opt.elem_fixed(end+1) = nc+1;
1715       end
1716     end
1717     
1718     opt.elem_len(1) = {size(c2f,2)}; 
1719 
1720 function [img, opt] = strip_c2f_background(img, opt, indent)
1721     if nargin < 3
1722        indent = '';
1723     end
1724     
1725     if opt.c2f_background <= 0
1726       return;
1727     end
1728 
1729     
1730     
1731     
1732     in = img.current_params;
1733     out = opt.elem_output;
1734     if iscell(in)
1735        in = in{1};
1736     end
1737     if iscell(out)
1738        out = out{1};
1739     end
1740 
1741     
1742     e = opt.c2f_background;
1743     
1744     
1745     bg = map_data(img.elem_data(e), in, out);
1746     img.elem_data_background = bg;
1747     
1748     img.elem_data(e) = [];
1749     img.fwd_model.coarse2fine(:,e) = [];
1750     
1751     opt.c2f_background = 0;
1752     ri = find(opt.elem_fixed == e);
1753     opt.elem_fixed(ri) = [];
1754     if isfield(img, 'params_sel')
1755        for i = 1:length(img.params_sel)
1756           t = img.params_sel{i};
1757           ti = find(t == e);
1758           t(ti) = []; 
1759           ti = find(t > e);
1760           t(ti) = t(ti)-1; 
1761           img.params_sel{i} = t;
1762        end
1763     end
1764 
1765     
1766     if(opt.verbose > 1)
1767        bg = img.elem_data_background;
1768        bg = map_data(bg, in, 'resistivity');
1769        fprintf('%s  background conductivity: %0.1f Ohm.m\n', indent, bg);
1770     end
1771 
1772 function b = has_params(s)
1773 b = false;
1774 if isstruct(s)
1775    b = any(ismember(fieldnames(s),supported_params));
1776 end
1777 
1778 
1779 function out = map_img_base_types(img)
1780   out = to_base_types(img.current_params);
1781 
1782 
1783 
1784 
1785 function type = to_base_types(type)
1786   if ~iscell(type)
1787      type = {type};
1788   end
1789   for i = 1:length(type);
1790      type(i) = {strrep(type{i}, 'log_', '')};
1791      type(i) = {strrep(type{i}, 'log10_', '')};
1792      type(i) = {strrep(type{i}, 'resistivity', 'conductivity')};
1793      type(i) = {strrep(type{i}, 'apparent_resistivity', 'voltage')};
1794   end
1795 
1796 function img = map_img(img, out);
1797    err_if_inf_or_nan(img.elem_data, 'img-pre');
1798    try in = img.current_params;
1799    catch in = {'conductivity'};
1800    end
1801    
1802    if isstr(in)
1803       in = {in};
1804       img.current_params = in;
1805    end
1806    if isstr(out)
1807       out = {out};
1808    end
1809 
1810    
1811    if ~isfield(img, 'params_sel')
1812       if length(in(:)) == 1
1813          img.params_sel = {1:size(img.elem_data,1)};
1814       else
1815          error('found multiple parametrizations (params) but no params_sel cell array in img');
1816       end
1817    end
1818 
1819    
1820    if length(out(:)) > length(in(:))
1821       error('missing data (more out types than in types)');
1822    elseif length(out(:)) < length(in(:))
1823       
1824       
1825       
1826       
1827       if length(out(:)) ~= 1
1828          error('map_img can convert ALL parameters or select a SINGLE output type from multiple input types');
1829       end
1830       inm  = to_base_types(in);
1831       outm = to_base_types(out);
1832       del = sort(find(~strcmp(outm(1), inm(:))), 'descend'); 
1833       if length(del)+1 ~= length(in)
1834          error('Confused about what to remove from the img. You''ll need to sort the parametrizations out yourself when removing data.');
1835       end
1836       for i = del(:)' 
1837          ndel = length(img.params_sel{i}); 
1838          for j = i+1:length(img.params_sel)
1839             img.params_sel{j} = img.params_sel{j} - ndel;
1840          end
1841          img.elem_data(img.params_sel{i}) = []; 
1842          img.params_sel(i) = []; 
1843          img.current_params(i) = []; 
1844       end
1845       in = img.current_params;
1846    end
1847 
1848    
1849    for i = 1:length(out(:))
1850       
1851       x = img.elem_data(img.params_sel{i});
1852       x = map_data(x, in{i}, out{i});
1853       img.elem_data(img.params_sel{i}) = x;
1854       img.current_params{i} = out{i};
1855    end
1856    err_if_inf_or_nan(img.elem_data, 'img-post');
1857 
1858    
1859    if length(img.current_params(:)) == 1
1860       img.current_params = img.current_params{1};
1861       img = rmfield(img, 'params_sel'); 
1862    end
1863 
1864 function x = map_data(x, in, out)
1865    
1866    if ~isstr(in)
1867       if iscell(in) && (length(in(:)) == 1)
1868          in = in{1};
1869       else
1870          error('expecting single string for map_data() "in" type');
1871       end
1872    end
1873    if ~isstr(out)
1874       if iscell(out) && (length(out(:)) == 1)
1875          out = out{1};
1876       else
1877          error('expecting single string for map_data() "out" type');
1878       end
1879    end
1880 
1881    
1882    if strcmp(in, out) 
1883       return; 
1884    end
1885 
1886    
1887    
1888    
1889    if any(strcmp(in,  {'resistivity', 'conductivity'})) && ...
1890       any(strcmp(out, {'resistivity', 'conductivity'}))
1891       x = 1./x; 
1892    
1893    elseif any(strcmp({in(1:3), out(1:3)}, 'log'))
1894       
1895       if strcmp(in(1:6), 'log10_')
1896          if any(x >= log10(realmax)-eps) warning('loss of precision -> inf'); end
1897          x = map_data(10.^x, in(7:end), out);
1898       
1899       elseif strcmp(in(1:4), 'log_')
1900          if any(x >= log(realmax)-eps) warning('loss of precision -> inf'); end
1901          x = map_data(exp(x), in(5:end), out);
1902       
1903       elseif strcmp(out(1:6), 'log10_')
1904          if any(x <= 0 + eps) warning('loss of precision -> -inf'); end
1905          x = log10(map_data(x, in, out(7:end)));
1906       
1907       elseif strcmp(out(1:4), 'log_')
1908          if any(x <= 0 + eps) warning('loss of precision -> -inf'); end
1909          x = log(map_data(x, in, out(5:end)));
1910       else
1911          error(sprintf('unknown conversion (log conversion?) %s - > %s', in, out));
1912       end
1913    else
1914       error('unknown conversion %s -> %s', in, out);
1915    end
1916    x(x == +inf) = +realmax;
1917    x(x == -inf) = -realmax;
1918    err_if_inf_or_nan(x, 'map_data-post');
1919 
1920 function b = map_meas(b, N, in, out)
1921    err_if_inf_or_nan(b, 'map_meas-pre');
1922    if strcmp(in, out) 
1923       return; 
1924    end
1925 
1926    
1927    
1928    if     strcmp(in, 'voltage') && strcmp(out, 'apparent_resistivity')
1929       if N == 1
1930          error('missing apparent resistivity conversion factor N');
1931       end
1932       b = N * b; 
1933    elseif strcmp(in, 'apparent_resistivity') && strcmp(out, 'voltage')
1934       if N == 1
1935          error('missing apparent resistivity conversion factor N');
1936       end
1937       b = N \ b; 
1938    
1939    elseif any(strcmp({in(1:3), out(1:3)}, 'log'))
1940       
1941       if strcmp(in(1:6), 'log10_')
1942          if any(b > log10(realmax)-eps) warning('loss of precision -> inf'); end
1943          b = map_meas(10.^b, N, in(7:end), out);
1944       
1945       elseif strcmp(in(1:4), 'log_')
1946          if any(b > log(realmax)-eps) warning('loss of precision -> inf'); end
1947          b = map_meas(exp(b), N, in(5:end), out);
1948       
1949       elseif strcmp(out(1:6), 'log10_')
1950          if any(b <= 0+eps) warning('loss of precision -> -inf'); end
1951          b = log10(map_meas(b, N, in, out(7:end)));
1952       
1953       elseif strcmp(out(1:4), 'log_')
1954          if any(b <= 0+eps) warning('loss of precision -> -inf'); end
1955          b = log(map_meas(b, N, in, out(5:end)));
1956       else
1957          error(sprintf('unknown conversion (log conversion?) %s - > %s', in, out));
1958       end
1959    else
1960       error('unknown conversion %s -> %s', in, out);
1961    end
1962    err_if_inf_or_nan(b, 'map_meas-post');
1963 
1964 function x=range(y)
1965 x=max(y)-min(y);
1966 
1967 function do_unit_test(solver)
1968    if nargin == 0
1969      solver = 'inv_solve_abs_core';
1970    end
1971    do_unit_test_rec_mv(solver);
1972    do_unit_test_sub;
1973    do_unit_test_rec1(solver);
1974 
1975 
1976 
1977 
1978 
1979 
1980 function do_unit_test_sub
1981 d = 1;
1982 while d ~= 1 & d ~= 0
1983   d = rand(1);
1984 end
1985 disp('TEST: map_data()');
1986 elem_types = {'conductivity', 'log_conductivity', 'log10_conductivity', ...
1987               'resistivity',  'log_resistivity',  'log10_resistivity'};
1988 expected = [d         log(d)         log10(d)      1./d      log(1./d)      log10(1./d); ...
1989             exp(d)    d              log10(exp(d)) 1./exp(d) log(1./exp(d)) log10(1./exp(d)); ...
1990             10.^d     log(10.^d )    d             1./10.^d  log(1./10.^d ) log10(1./10.^d ); ...
1991             1./d      log(1./d  )    log10(1./d)   d         log(d)         log10(d); ...
1992             1./exp(d) log(1./exp(d)) log10(1./exp(d)) exp(d) d              log10(exp(d)); ...
1993             1./10.^d  log(1./10.^d)  log10(1./10.^d)  10.^d  log(10.^d)     d ];
1994 for i = 1:length(elem_types)
1995   for j = 1:length(elem_types)
1996     test_map_data(d, elem_types{i}, elem_types{j}, expected(i,j));
1997   end
1998 end
1999 
2000 disp('TEST: map_meas()');
2001 N = 1/15;
2002 Ninv = 1/N;
2003 
2004 elem_types = {'voltage', 'log_voltage', 'log10_voltage', ...
2005               'apparent_resistivity',  'log_apparent_resistivity',  'log10_apparent_resistivity'};
2006 expected = [d         log(d)         log10(d)      N*d      log(N*d)      log10(N*d); ...
2007             exp(d)    d              log10(exp(d)) N*exp(d) log(N*exp(d)) log10(N*exp(d)); ...
2008             10.^d     log(10.^d )    d             N*10.^d  log(N*10.^d ) log10(N*10.^d ); ...
2009             Ninv*d      log(Ninv*d  )    log10(Ninv*d)   d         log(d)         log10(d); ...
2010             Ninv*exp(d) log(Ninv*exp(d)) log10(Ninv*exp(d)) exp(d) d              log10(exp(d)); ...
2011             Ninv*10.^d  log(Ninv*10.^d)  log10(Ninv*10.^d)  10.^d  log(10.^d)     d ];
2012 for i = 1:length(elem_types)
2013   for j = 1:length(elem_types)
2014     test_map_meas(d, N, elem_types{i}, elem_types{j}, expected(i,j));
2015   end
2016 end
2017 
2018 disp('TEST: Jacobian scaling');
2019 d = [d d]';
2020 unit_test_cmp( ...
2021    sprintf('Jacobian scaling (%s)', 'conductivity'), ...
2022    ret1_func(d), 1);
2023 
2024 unit_test_cmp( ...
2025    sprintf('Jacobian scaling (%s)', 'log_conductivity'), ...
2026    dx_dlogx(d), diag(d));
2027 
2028 unit_test_cmp( ...
2029    sprintf('Jacobian scaling (%s)', 'log10_conductivity'), ...
2030    dx_dlog10x(d), diag(d)*log(10));
2031 
2032 unit_test_cmp( ...
2033    sprintf('Jacobian scaling (%s)', 'resistivity'), ...
2034    dx_dy(d), diag(-d.^2));
2035 
2036 unit_test_cmp( ...
2037    sprintf('Jacobian scaling (%s)', 'log_resistivity'), ...
2038    dx_dlogy(d), diag(-d));
2039 
2040 unit_test_cmp( ...
2041    sprintf('Jacobian scaling (%s)', 'log10_resistivity'), ...
2042    dx_dlog10y(d), diag(-d)/log(10));
2043 
2044 
2045 function test_map_data(data, in, out, expected)
2046 
2047    calc_val = map_data(data, in, out);
2048    str = sprintf('map_data(%s -> %s)', in, out);
2049    unit_test_cmp(str, calc_val, expected)
2050 
2051 function test_map_meas(data, N, in, out, expected)
2052 
2053    calc_val = map_meas(data, N, in, out);
2054    str = sprintf('map_data(%s -> %s)', in, out);
2055    unit_test_cmp(str, calc_val, expected)
2056 
2057 
2058 
2059 
2060 function do_unit_test_rec1(solver)
2061 
2062 
2063 
2064 
2065 
2066 imdl= mk_common_model('c2t4',16); 
2067 imdl.solve = solver;
2068 imdl.reconst_type = 'absolute';
2069 imdl.inv_solve_abs_core.prior_data = 1;
2070 imdl.inv_solve_abs_core.elem_prior = 'conductivity';
2071 imdl.inv_solve_abs_core.elem_working = 'log_conductivity';
2072 imdl.inv_solve_abs_core.meas_working = 'apparent_resistivity';
2073 imdl.inv_solve_abs_core.calc_solution_error = 0;
2074 imdl.inv_solve_abs_core.verbose = 0;
2075 
2076 imgsrc= mk_image( imdl.fwd_model, 1);
2077 
2078 vh=fwd_solve(imgsrc);
2079 
2080 ctrs= interp_mesh(imdl.fwd_model);
2081 x= ctrs(:,1); y= ctrs(:,2);
2082 r1=sqrt((x+5).^2 + (y+5).^2); r2 = sqrt((x-85).^2 + (y-65).^2);
2083 imgsrc.elem_data(r1<50)= 0.05;
2084 imgsrc.elem_data(r2<30)= 100;
2085 imgp = map_img(imgsrc, 'log10_conductivity');
2086 hh=clf; subplot(221); show_fem(imgp,1); axis tight; title('synthetic data, logC');
2087 
2088 vi=fwd_solve( imgsrc );
2089 
2090 
2091 noise_level= std(vi.meas - vh.meas)/10^(30/20);
2092 vi.meas = vi.meas + noise_level*randn(size(vi.meas));
2093 
2094 img1= inv_solve(imdl, vi);
2095 figure(hh); subplot(222); show_fem(img1,1); axis tight; title('#1 verbosity=default');
2096 
2097 disp('TEST: previous solved at default verbosity');
2098 disp('TEST: now solve same at verbosity=0 --> should be silent');
2099 imdl.inv_solve_abs_core.verbose = 0;
2100 
2101 img2= inv_solve(imdl, vi);
2102 figure(hh); subplot(223); show_fem(img2,1); axis tight; title('#2 verbosity=0');
2103 max_err = max(abs((img1.elem_data - img2.elem_data)./(img1.elem_data)));
2104 
2105 unit_test_cmp('img1 == img2', max_err >0.15, 0);
2106 if max_err > 0.15
2107   fprintf('TEST:  img1 != img2 --> FAIL %g %%\n', max_err);
2108 end
2109 
2110 disp('TEST: try coarse2fine mapping');
2111 imdl_tmp= mk_common_model('b2t4',16); 
2112 
2113 fmdl = imdl_tmp.fwd_model;
2114 cmdl.type = fmdl.type;
2115 cmdl.name = fmdl.name;
2116 cmdl.nodes = fmdl.nodes;
2117 cmdl.elems = fmdl.elems;
2118 cmdl.gnd_node = 0;
2119 
2120 
2121 
2122 ctrs= interp_mesh(cmdl);
2123 x= ctrs(:,1); y= ctrs(:,2);
2124 r=sqrt((x+5).^2 + (y+5).^2);
2125 cmdl.elems(y-x > 150, :) = [];
2126 
2127 
2128 imdl.rec_model = cmdl;
2129 c2f = mk_coarse_fine_mapping(imdl.fwd_model,cmdl);
2130 imdl.fwd_model.coarse2fine = c2f;
2131 
2132 
2133 img3= inv_solve(imdl, vi);
2134 
2135 figure(hh); subplot(223); show_fem(img3,1); axis tight; title('#3 c2f');
2136 
2137 e1 = c2f \ img1.elem_data; 
2138 e3 = img3.elem_data;
2139 err = abs((e1 - e3) ./ e1);
2140 err(abs(e1) < 20) = 0;
2141 err_thres = 0.55;
2142 
2143 unit_test_cmp('img1 == img3', any(err > err_thres), 0);
2144 if any(err > err_thres) 
2145   ni = find(err > err_thres);
2146   fprintf('TEST:  img1 != img3 --> FAIL max(err) = %0.2e on %d elements (thres=%0.2e)\n', ...
2147           max(err(ni)), length(ni), err_thres);
2148 end
2149 
2150 
2151 imdl.inv_solve_abs_core.elem_output = 'log10_resistivity'; 
2152 img4= inv_solve(imdl, vi);
2153 figure(hh); subplot(224); show_fem(img4,1); axis tight; title('#4 c2f + log10 resistivity out');
2154 
2155 e4 = 1./(10.^img4.elem_data);
2156 err = abs((e1 - e4) ./ e1);
2157 err(abs(e1) < 20) = 0;
2158 err_thres = 0.40;
2159 
2160 unit_test_cmp('img1 == img4', any(err > err_thres), 0);
2161 if any(err > err_thres) 
2162   ni = find(err > err_thres);
2163   fprintf('TEST:  img1 != img4 --> FAIL max(err) = %0.2e on %d elements (thres=%0.2e)\n', ...
2164           max(err(ni)), length(ni), err_thres);
2165 end
2166 
2167 
2168 function do_unit_test_rec_mv(solver)
2169 disp('TEST: conductivity and movement --> baseline conductivity only');
2170 
2171 
2172 
2173 
2174 
2175 imdl= mk_common_model('c2t4',16); 
2176 ne = length(imdl.fwd_model.electrode);
2177 nt = length(imdl.fwd_model.elems);
2178 imdl.solve = solver;
2179 imdl.reconst_type = 'absolute';
2180 
2181 imdl.inv_solve_abs_core.meas_input   = 'voltage';
2182 imdl.inv_solve_abs_core.meas_working = 'apparent_resistivity';
2183 imdl.inv_solve_abs_core.elem_prior   = {   'conductivity'   };
2184 imdl.inv_solve_abs_core.prior_data   = {        1           };
2185 imdl.inv_solve_abs_core.elem_working = {'log_conductivity'};
2186 imdl.inv_solve_abs_core.elem_output  = {'log10_conductivity'};
2187 imdl.inv_solve_abs_core.calc_solution_error = 0;
2188 imdl.inv_solve_abs_core.verbose = 0;
2189 imdl.hyperparameter.value = 0.01;
2190 
2191 
2192 imgsrc= mk_image( imdl.fwd_model, 1);
2193 vh=fwd_solve(imgsrc);
2194 
2195 ctrs= interp_mesh(imdl.fwd_model);
2196 x= ctrs(:,1); y= ctrs(:,2);
2197 r1=sqrt((x+5).^2 + (y+5).^2); r2 = sqrt((x-45).^2 + (y-35).^2);
2198 imgsrc.elem_data(r1<50)= 0.05;
2199 imgsrc.elem_data(r2<30)= 100;
2200 
2201 
2202 vi=fwd_solve( imgsrc );
2203 
2204 
2205 noise_level= std(vi.meas - vh.meas)/10^(30/20);
2206 vi.meas = vi.meas + noise_level*randn(size(vi.meas));
2207 
2208 
2209 hh=clf; subplot(221); imgp = map_img(imgsrc, 'log10_conductivity'); show_fem(imgp,1); axis tight; title('synth baseline, logC');
2210 
2211 
2212 img0= inv_solve(imdl, vi);
2213 figure(hh); subplot(222);
2214  img0 = map_img(img0, 'log10_conductivity');
2215  show_fem(img0, 1); axis tight;
2216 
2217 disp('TEST: conductivity + movement');
2218 imdl.fwd_model = rmfield(imdl.fwd_model, 'jacobian');
2219 
2220 imdl.inv_solve_abs_core.elem_prior   = {   'conductivity'   , 'movement'};
2221 imdl.inv_solve_abs_core.prior_data   = {        1           ,     0     };
2222 imdl.inv_solve_abs_core.RtR_prior    = {     @eidors_default, @prior_movement_only};
2223 imdl.inv_solve_abs_core.elem_len     = {       nt           ,   ne*2    };
2224 imdl.inv_solve_abs_core.elem_working = {  'log_conductivity', 'movement'};
2225 imdl.inv_solve_abs_core.elem_output  = {'log10_conductivity', 'movement'};
2226 imdl.inv_solve_abs_core.jacobian     = { @jacobian_adjoint  , @jacobian_movement_only};
2227 imdl.inv_solve_abs_core.hyperparameter = {   [1 1.1 0.9]    ,  sqrt(2e-3)     }; 
2228 imdl.inv_solve_abs_core.verbose = 2;
2229 
2230 
2231 nn = [imgsrc.fwd_model.electrode(:).nodes];
2232 elec_orig = imgsrc.fwd_model.nodes(nn,:);
2233 
2234 nn = imgsrc.fwd_model.nodes;
2235 imgsrc.fwd_model.nodes = nn * [1-0.02 0; 0 1+0.02]; 
2236 
2237 nn = [imgsrc.fwd_model.electrode(:).nodes];
2238 elec_mv = imgsrc.fwd_model.nodes(nn,:);
2239 
2240 
2241 vi=fwd_solve( imgsrc );
2242 
2243 
2244 noise_level= std(vi.meas - vh.meas)/10^(30/20);
2245 
2246 
2247 
2248 nn = [imgsrc.fwd_model.electrode(1:4).nodes];
2249 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');
2250 
2251 
2252 img1= inv_solve(imdl, vi);
2253 figure(hh); subplot(224);
2254  imgm = map_img(img1, 'movement');
2255  img1 = map_img(img1, 'log10_conductivity');
2256  show_fem_move(img1,reshape(imgm.elem_data,16,2), 10, 1); axis tight;
2257 
2258 
2259 err = abs((img0.elem_data - img1.elem_data) ./ img0.elem_data);
2260 err(abs(img0.elem_data)/max(abs(img0.elem_data)) < 0.50) = 0;
2261 err_thres = 0.40;
2262 
2263 unit_test_cmp('img0 == img1 + mvmt', any(err > err_thres), 0);
2264 
2265 if any(err > err_thres) 
2266   ni = find(err > err_thres);
2267   fprintf('TEST:  img0 != img1 + mvmt --> FAIL max(err) = %0.2e on %d elements (thres=%0.2e)\n', ...
2268           max(err(ni)), length(ni), err_thres);
2269 end
2270 
2271 
2272 function Jm = jacobian_movement_only (fwd_model, img);
2273   pp = fwd_model_parameters(img.fwd_model);
2274   szJm = pp.n_elec * pp.n_dims; 
2275   img = map_img(img, 'conductivity'); 
2276   Jcm = jacobian_movement(fwd_model, img);
2277   Jm = Jcm(:,(end-szJm+1):end);
2278 
2279 
2280 
2281 
2282 
2283 
2284 
2285 
2286 function RtR = prior_movement_only(imdl);
2287   imdl.image_prior.parameters(1) = 1; 
2288   pp = fwd_model_parameters(imdl.fwd_model);
2289   szPm = pp.n_elec * pp.n_dims; 
2290   RtR = prior_movement(imdl);
2291   RtR = RtR((end-szPm+1):end,(end-szPm+1):end);
2292 
2293 function do_unit_test_rec2(solver)
2294 disp('TEST: reconstruct a discontinuity');
2295 shape_str = ['solid top    = plane(0,0,0;0,1,0);\n' ...
2296              'solid mainobj= top and orthobrick(-100,-200,-100;410,10,100) -maxh=20.0;\n'];
2297 e0 = linspace(0,310,64)';
2298 elec_pos = [e0,0*e0,0*e0,1+0*e0,0*e0,0*e0];
2299 elec_shape= [0.1,0.1,1];
2300 elec_obj = 'top';
2301 fmdl = ng_mk_gen_models(shape_str, elec_pos, elec_shape, elec_obj);
2302 
2303 
2304 
2305 
2306 
2307 fmdl.stimulation= stim_pattern_geophys( 64, 'Wenner', {'spacings', 1:32} );
2308 
2309 cmdl= mk_grid_model([], 2.5+[-30,5,20,30:10:290,300,315,340], ...
2310                             -[0:5:10 17 30 50 75 100]);
2311 
2312 cmdl= rmfield(cmdl, 'coarse2fine');
2313 
2314 
2315 [c2f, b_c2f] = mk_coarse_fine_mapping( fmdl, cmdl);
2316 
2317 
2318 
2319 
2320 
2321 
2322 
2323 
2324 
2325 
2326 
2327 
2328 fmdl.coarse2fine= c2f;
2329 
2330 
2331 img = mk_image(fmdl,1);
2332 fm_pts = interp_mesh(fmdl);
2333 x_bary= fm_pts(:,1); z_bary= fm_pts(:,2);
2334 z_params= (min(fmdl.nodes(:,2)):max(fmdl.nodes(:,2)))';
2335 a = 0.36;
2336 b = 130;
2337 x_params= a*z_params+b;
2338 xlim=interp1(z_params,x_params,z_bary);
2339 img.elem_data(x_bary>xlim)= 0.01;
2340 clf; show_fem(img); title('model');
2341 
2342 
2343 
2344 
2345 
2346 
2347 dd  = fwd_solve(img);
2348 
2349 
2350 imdl= eidors_obj('inv_model','test');
2351 imdl.fwd_model= fmdl;
2352 imdl.rec_model= cmdl;
2353 imdl.fwd_model.normalize_measurements = 0;
2354 imdl.rec_model.normalize_measurements = 0;
2355 imdl.RtR_prior = @prior_laplace;
2356 
2357 imdl.solve = solver;
2358 imdl.reconst_type = 'absolute';
2359 imdl.hyperparameter.value = 1e2; 
2360 imdl.jacobian_bkgnd.value = 1;
2361 
2362 imdl.inv_solve_abs_core.elem_working = 'log_conductivity';
2363 imdl.inv_solve_abs_core.meas_working = 'apparent_resistivity';
2364 imdl.inv_solve_abs_core.dtol_iter = 4; 
2365 imdl.inv_solve_abs_core.max_iterations = 20; 
2366 
2367 
2368 
2369 
2370 
2371 
2372 
2373 
2374 imdl.inv_solve_abs_core.calc_solution_error = 0;
2375 
2376 imdl.inv_solve_abs_core.verbose = 10;
2377 
2378 
2379 
2380 imdl.inv_solve_abs_core.line_search_args.perturb= [0 5*logspace(-7,-4,5)];
2381 
2382 
2383 
2384 imdl.inv_solve_abs_core.elem_output = 'log10_resistivity';
2385 imgr= inv_solve_abs_core(imdl, dd);
2386 
2387 
2388 
2389 
2390 imgGNd= imgr;
2391 
2392 
2393 
2394 
2395 
2396 
2397 
2398 elec_posn= zeros(length(fmdl.electrode),3);
2399 for i=1:length(fmdl.electrode)
2400     elec_posn(i,:)= mean(fmdl.nodes(fmdl.electrode(1,i).nodes,:),1);
2401 end
2402 
2403 clf; show_fem(imgGNd,1);
2404 hold on; plot(elec_posn(:,1),elec_posn(:,3),'k*');
2405 axis tight; ylim([-100 0.5])
2406 xlabel('X (m)','fontsize',20,'fontname','Times')
2407 ylabel('Z (m)','fontsize',20,'fontname','Times')
2408 set(gca,'fontsize',20,'fontname','Times');
2409 
2410 img = mk_image( imdl );
2411 img.elem_data= 1./(10.^imgr.elem_data);
2412 vCG= fwd_solve(img); vCG = vCG.meas;
2413 
2414 I = 1; 
2415 
2416 clf; plot(I*(dd.meas-vCG)); title('data misfit');
2417 clf; hist(abs(I*(dd.meas-vCG)),50); title('|data misfit|, histogram'); xlabel('|misfit|'); ylabel('count');
2418 clf; show_pseudosection( fmdl, I*dd.meas); title('measurement data');
2419 clf; show_pseudosection( fmdl, I*vCG); title('reconstruction data');
2420 clf; show_pseudosection( fmdl, (vCG-dd.meas)./dd.meas*100); title('data misfit');