0001 function J = jacobian_adjoint_higher_order(fwd_model,img)
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 if ischar(fwd_model) && strcmp(fwd_model,'UNIT_TEST'); do_unit_test; return; end
0037
0038 if nargin == 1
0039 img= fwd_model;
0040 elseif strcmp(getfield(warning('query','EIDORS:DeprecatedInterface'),'state'),'on')
0041 warning('EIDORS:DeprecatedInterface', ...
0042 ['Calling JACOBIAN_ADJOINT_HIGHER_ORDER with two arguments is deprecated and will cause' ...
0043 ' an error in a future version. First argument ignored.']);
0044 end
0045 fwd_model= img.fwd_model;
0046
0047 if mdl_normalize(fwd_model)
0048 fwd_solve_data= fwd_solve( img );
0049 end
0050
0051
0052 if ~isfield(fwd_model,'approx_type') || ...
0053 strcmp(fwd_model.approx_type,'tri3') || ...
0054 strcmp(fwd_model.approx_type,'tet4')
0055
0056 else
0057 [bound,elem,nodes] = fem_1st_to_higher_order(fwd_model);
0058 fwd_model.boundary=bound; fwd_model.elems=elem; fwd_model.nodes=nodes;
0059 img.fwd_model=fwd_model;
0060 end
0061
0062
0063 s_mat = calc_system_mat(img); At=s_mat.E; elemstiff=s_mat.elemstiff;
0064
0065
0066
0067
0068
0069 elecstruc=fwd_model.electrode; nelecs=size(elecstruc,2);
0070 stimstruc=fwd_model.stimulation; nstims=size(stimstruc,2);
0071 nodestruc=fwd_model.nodes; nnodes=size(nodestruc,1);
0072 elemstruc=fwd_model.elems; nelems=size(elemstruc,1);
0073
0074
0075 nmeass=0;
0076 for k=1:nstims
0077 stimkmeasmatrix = stimstruc(k).meas_pattern;
0078 nmeass=nmeass+size(stimkmeasmatrix,1);
0079 end
0080
0081
0082
0083 elecnode=zeros(1,nelecs);
0084 if(size(elecstruc(1).nodes,2)==1 && size(elecstruc(1).nodes,1)==1)
0085
0086 Node2Elec=sparse(nelecs,nnodes);
0087 for i=1:nelecs
0088
0089 elecnode(i)=elecstruc(i).nodes;
0090 Node2Elec(i,elecnode(i))=1;
0091 end
0092
0093 dA_zero=sparse(nnodes,nnodes);
0094
0095
0096 datafwd=zeros(nnodes,nstims);
0097 nodeunknownsfwd=zeros(nnodes,nstims);
0098 else
0099
0100 Node2Elec=sparse(nelecs,nnodes+nelecs);
0101 for i=1:nelecs
0102
0103 elecnode(i)=nnodes+i;
0104 Node2Elec(i,elecnode(i))=1;
0105 end
0106
0107
0108 dA_zero=sparse(nnodes+nelecs,nnodes+nelecs);
0109
0110
0111 datafwd=zeros(nnodes+nelecs,nstims);
0112 nodeunknownsfwd=zeros(nnodes+nelecs,nstims);
0113 end
0114
0115
0116
0117 for ii=1:nstims
0118
0119 curnode=stimstruc(ii).stim_pattern;
0120 for i=1:nelecs
0121 datafwd(elecnode(i),ii)=curnode(i);
0122 end
0123 end
0124
0125
0126 groundnode=fwd_model.gnd_node; idx=1:size(At,1); idx(groundnode)=[];
0127
0128
0129 nodeunknownsfwd(idx,:)=left_divide(At(idx,idx),datafwd(idx,:));
0130
0131
0132
0133
0134 DE= zeros(nelecs,nstims,nelems);
0135
0136
0137 zi2E(:,idx) = Node2Elec(:,idx)/At(idx,idx);
0138
0139
0140
0141
0142
0143
0144
0145
0146
0147
0148
0149 for k=1:nelems
0150
0151 stiffk=elemstiff(k).elemstiff; nodesk=elemstruc(k,:); idx2=1:size(nodesk,2);
0152
0153
0154 dA_dSk=dA_zero; dA_dSk(nodesk(idx2),nodesk(idx2))=stiffk(idx2,idx2);
0155
0156
0157 DE(:,:,k) = zi2E(:,idx)*dA_dSk(idx,idx)*nodeunknownsfwd(idx,:);
0158 end
0159
0160
0161 cntjac=0; J=zeros(nmeass,nelems);
0162 for j=1:nstims
0163 meas_pat= fwd_model.stimulation(j).meas_pattern;
0164 n_meas = size(meas_pat,1);
0165 DEj = reshape( DE(:,j,:), nelecs, nelems);
0166 J( cntjac+(1:n_meas),: ) = meas_pat*DEj;
0167 cntjac = cntjac + n_meas;
0168 end;
0169
0170
0171 if mdl_normalize(fwd_model)
0172 data= fwd_solve_data;
0173 J= J ./ (data.meas(:)*ones(1,nelems));
0174 end
0175
0176
0177 J= -J;
0178 end
0179
0180 function do_unit_test
0181 tol = 1e-14;
0182 JJ = do_unit_test_2D(0);
0183 JJ_ref = -1e-4*[
0184 2.440415272063380 2.705754096983918 2.721135010947898
0185 2.578623854199123 2.327923064064513 2.342086727271722
0186 1.438743206711758 1.333580385504260 1.337599904647092
0187 1.300534624576032 1.650702059478922 1.659896278693538];
0188
0189 unit_test_cmp('2D: 1st order',JJ(1:4,1),JJ_ref(1:4,1),tol);
0190 unit_test_cmp('2D: 2nd order',JJ(1:4,2),JJ_ref(1:4,2),tol);
0191 unit_test_cmp('2D: 3rd order',JJ(1:4,3),JJ_ref(1:4,3),tol);
0192
0193 [JJ1,vve]= do_unit_test_2D(1); for i=1:3
0194 unit_test_cmp('2D: (normalize)',JJ1(:,i),JJ(:,i)/vve(4,i),tol);
0195 end
0196
0197 JJ = do_unit_test_3D(0);
0198 JJ_ref = -1e-5*[
0199 1.246064580179371 1.585061706092707
0200 1.332632578853691 1.354929239220232
0201 0.712061825721561 0.443297935900921
0202 0.625493827047241 0.604174950085724];
0203 [JJ1,vve]= do_unit_test_3D(1); for i=1:2
0204 unit_test_cmp('3D: (normalize)',JJ1(:,i),JJ(:,i)/vve(4,i),tol);
0205 end
0206
0207 unit_test_cmp('3D: 1st order',JJ(1:4,1),JJ_ref(1:4,1),tol);
0208 unit_test_cmp('3D: 2nd order',JJ(1:4,2),JJ_ref(1:4,2),tol);
0209
0210 end
0211 function [JJ4,vve]=do_unit_test_2D(normalize_flag)
0212 imdl = mk_common_model('c2C',16); img = mk_image(imdl.fwd_model,1);
0213 img.fwd_model.normalize_measurements = normalize_flag;
0214 vv=fwd_solve(img); v0e=vv.meas;
0215 JJ=calc_jacobian(img); J04=JJ(4,:)';
0216
0217
0218 img.fwd_model.solve = @fwd_solve_higher_order;
0219 img.fwd_model.system_mat = @system_mat_higher_order;
0220 img.fwd_model.jacobian = @jacobian_adjoint_higher_order;
0221
0222 vve=[]; JJ4=[];
0223 for i= 1:3; switch i;
0224 case 1; img.fwd_model.approx_type = 'tri3';
0225 case 2; img.fwd_model.approx_type = 'tri6';
0226 case 3; img.fwd_model.approx_type = 'tri10';
0227 end
0228 vv=fwd_solve(img); vve(:,i)=vv.meas;
0229 JJ=calc_jacobian(img); JJ4(:,i)=JJ(4,:)';
0230 end
0231
0232 subplot(321);
0233 plot([v0e,vve,(v0e*[1,1,1]-vve)*10]);
0234 legend('Default','linear','quadratic','cubic','(1-0)x10','(2-0)x10','(3-0)x10');
0235 xlim([1,100]);
0236
0237 imgJJ=img; imgJJ.elem_data = JJ4;
0238 imgJJ.show_slices.img_cols = 3;
0239
0240 subplot(323); show_slices(imgJJ); eidors_colourbar(imgJJ);
0241
0242 imgJJ.elem_data = JJ4 - J04*[1,1,1];
0243 subplot(325); show_slices(imgJJ); eidors_colourbar(imgJJ);
0244 end
0245 function [JJ4,vve]=do_unit_test_3D(normalize_flag)
0246 imdl = mk_common_model('b3cr',16); img = mk_image(imdl.fwd_model,1);
0247 img.fwd_model.normalize_measurements = normalize_flag;
0248 vv=fwd_solve(img); v0e=vv.meas;
0249 JJ=calc_jacobian(img); J04=JJ(4,:)';
0250
0251
0252 img.fwd_model.solve = @fwd_solve_higher_order;
0253 img.fwd_model.system_mat = @system_mat_higher_order;
0254 img.fwd_model.jacobian = @jacobian_adjoint_higher_order;
0255
0256 vve=[]; JJ4=[];
0257 for i= 1:2; switch i;
0258 case 1; img.fwd_model.approx_type = 'tet4';
0259 case 2; img.fwd_model.approx_type = 'tet10';
0260 end
0261 vv=fwd_solve(img); vve(:,i)=vv.meas;
0262 JJ=calc_jacobian(img); JJ4(:,i)=JJ(4,:)';
0263 end
0264
0265 subplot(322);
0266 plot([v0e,vve,(v0e*[1,1]-vve)*10]);
0267 legend('Default','linear','quadratic','(1-0)x10','(2-0)x10');
0268 xlim([1,100]);
0269
0270 imgJJ=img; imgJJ.elem_data = JJ4;
0271 imgJJ.show_slices.img_cols = 2;
0272
0273 level = [inf,inf,0.3];
0274 subplot(324); show_slices(imgJJ,level); eidors_colourbar(imgJJ);
0275
0276 imgJJ.elem_data = JJ4 - J04*[1,1];
0277 subplot(326); show_slices(imgJJ,level); eidors_colourbar(imgJJ);
0278 end