0001 function[data] = fwd_solve_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 if ischar(fwd_model) && strcmp(fwd_model,'UNIT_TEST'); do_unit_test; return; end
0033
0034 if nargin == 1
0035 img= fwd_model;
0036 elseif strcmp(getfield(warning('query','EIDORS:DeprecatedInterface'),'state'),'on')
0037 warning('EIDORS:DeprecatedInterface', ...
0038 ['Calling FWD_SOLVE_HIGHER_ORDER with two arguments is deprecated and will cause' ...
0039 ' an error in a future version. First argument ignored.']);
0040 end
0041
0042 fwd_model= img.fwd_model;
0043
0044
0045 if ~isfield(fwd_model,'approx_type') || ...
0046 strcmp(fwd_model.approx_type,'tri3') || ...
0047 strcmp(fwd_model.approx_type,'tet4')
0048
0049 else
0050 [bound,elem,nodes] = fem_1st_to_higher_order(fwd_model);
0051 fwd_model.boundary=bound; fwd_model.elems=elem; fwd_model.nodes=nodes;
0052
0053 img.fwd_model=fwd_model;
0054 end
0055
0056
0057 s_mat = calc_system_mat(img); At=s_mat.E;
0058
0059
0060
0061
0062 elecstruc=fwd_model.electrode; nelecs=size(elecstruc,2);
0063 stimstruc=fwd_model.stimulation; nstims=size(stimstruc,2);
0064 nodestruc=fwd_model.nodes; nnodes=size(nodestruc,1);
0065
0066
0067 nmeass=0;
0068 for k=1:nstims
0069 stimkmeasmatrix = stimstruc(k).meas_pattern;
0070 nmeass=nmeass+size(stimkmeasmatrix,1);
0071 end
0072
0073
0074
0075 elecnode=zeros(1,nelecs);
0076 if(size(elecstruc(1).nodes,2)==1 && size(elecstruc(1).nodes,1)==1)
0077 for i=1:nelecs
0078
0079 elecnode(i)=elecstruc(i).nodes;
0080 end
0081
0082 rhsdata=zeros(nnodes,nstims);
0083 nodeunknowns=zeros(nnodes,nstims);
0084 else
0085 for i=1:nelecs
0086
0087 elecnode(i)=nnodes+i;
0088 end
0089
0090 rhsdata=zeros(nnodes+nelecs,nstims);
0091 nodeunknowns=zeros(nnodes+nelecs,nstims);
0092 end
0093
0094
0095 for ii=1:nstims
0096
0097 curnode=stimstruc(ii).stim_pattern;
0098 for i=1:nelecs
0099 rhsdata(elecnode(i),ii)=curnode(i);
0100 end
0101 end
0102
0103
0104 groundnode=fwd_model.gnd_node; idx=1:size(At,1); idx(groundnode)=[];
0105
0106
0107 nodeunknowns(idx,:)=left_divide(At(idx,idx),rhsdata(idx,:));
0108
0109
0110
0111
0112 velec=zeros(nelecs,nstims);
0113 for i=1:nelecs
0114
0115 velec(i,:)=nodeunknowns(elecnode(i),:);
0116 end
0117
0118
0119 vmeaselec=zeros(nmeass,1); idx=0;
0120 for ii=1:nstims
0121 meas_pat=stimstruc(ii).meas_pattern;
0122 n_meas=size(meas_pat,1);
0123 vmeaselec(idx + (1:n_meas) ) = meas_pat*velec(:,ii);
0124 idx=idx+n_meas;
0125 end
0126
0127
0128 data.meas= vmeaselec;
0129 data.time= NaN;
0130 data.name= 'solved by fwd_solve_higher_order';
0131 data.quantity = 'voltage';
0132 try; if img.fwd_solve.get_all_meas == 1
0133 data.volt = nodeunknowns(1:nnodes,:);
0134 end; end
0135 try; if img.fwd_solve.get_all_nodes== 1
0136 data.volt = nodeunknowns;
0137 end; end
0138
0139
0140 end
0141
0142 function do_unit_test
0143 tol = 1e-13;
0144 vve = do_unit_test_2D;
0145 vve_ref = [
0146 0.898225115241117 0.921510761628436 0.928516596253320
0147 0.406398239528486 0.412406966923347 0.413938179536629
0148 0.248067950415984 0.250212111398160 0.250609888163540
0149 0.179592593985273 0.179643951982781 0.179734695991927];
0150
0151 unit_test_cmp('2D: 1st order',vve(1:4,1),vve_ref(1:4,1),tol);
0152 unit_test_cmp('2D: 2nd order',vve(1:4,2),vve_ref(1:4,2),tol);
0153 unit_test_cmp('2D: 3rd order',vve(1:4,3),vve_ref(1:4,3),tol);
0154 vve = do_unit_test_3D;
0155 vve_ref = [
0156 1.404189968566952 1.410900674463290
0157 0.403207625837809 0.402992578774667
0158 0.198517193844915 0.201211971071238
0159 0.133852904079284 0.133841105904217];
0160 unit_test_cmp('3D: 1st order',vve(1:4,1),vve_ref(1:4,1),tol);
0161 unit_test_cmp('3D: 2nd order',vve(1:4,2),vve_ref(1:4,2),tol);
0162
0163 end
0164 function [vve] = do_unit_test_2D
0165 imdl = mk_common_model('c2C',16); img = mk_image(imdl.fwd_model,1);
0166 vv=fwd_solve(img); v0e=vv.meas;
0167
0168
0169 img.fwd_model.solve = @fwd_solve_higher_order;
0170 img.fwd_model.system_mat = @system_mat_higher_order;
0171
0172 vve=[]; JJ4=[];
0173 for i= 1:3; switch i;
0174 case 1; img.fwd_model.approx_type = 'tri3';
0175 case 2; img.fwd_model.approx_type = 'tri6';
0176 case 3; img.fwd_model.approx_type = 'tri10';
0177 end
0178 vv=fwd_solve(img); vve(:,i)=vv.meas;
0179 end
0180
0181 subplot(321);
0182 plot([v0e,vve,(v0e*[1,1,1]-vve)*10]);
0183 legend('Default','linear','quadratic','cubic','(1-0)x10','(2-0)x10','(3-0)x10');
0184 xlim([1,100]);
0185 end
0186 function vve=do_unit_test_3D;
0187 imdl = mk_common_model('b3cr',16); img = mk_image(imdl.fwd_model,1);
0188 vv=fwd_solve(img); v0e=vv.meas;
0189
0190
0191 img.fwd_model.solve = @fwd_solve_higher_order;
0192 img.fwd_model.system_mat = @system_mat_higher_order;
0193
0194 vve=[]; JJ4=[];
0195 for i= 1:2; switch i;
0196 case 1; img.fwd_model.approx_type = 'tet4';
0197 case 2; img.fwd_model.approx_type = 'tet10';
0198 end
0199 vv=fwd_solve(img); vve(:,i)=vv.meas;
0200 end
0201
0202 subplot(322);
0203 plot([v0e,vve,(v0e*[1,1]-vve)*10]);
0204 legend('Default','linear','quadratic','(1-0)x10','(2-0)x10');
0205 xlim([1,100]);
0206
0207 end