0001 function FC1 = update_system_mat_fields( fwd_model0, fwd_model1 )
0002
0003
0004
0005
0006
0007
0008
0009
0010
0011
0012
0013
0014
0015 if ischar(fwd_model0) && strcmp(fwd_model0,'UNIT_TEST'); do_unit_test; return; end
0016
0017 FC0 = system_mat_fields(fwd_model0);
0018
0019 copt.cache_obj= {mk_cache_obj(fwd_model0), ...
0020 mk_cache_obj(fwd_model1)};
0021 copt.fstr = 'update_system_mat_fields';
0022 dFC = eidors_cache(@calc_update_system_mat_fields,{fwd_model0, fwd_model1},copt );
0023
0024
0025 FC1 = FC0 + dFC;
0026
0027
0028
0029
0030 fstr = 'system_mat_fields';
0031 cache_obj = mk_cache_obj(fwd_model1);
0032 eidors_obj('set-cache', cache_obj, fstr, {FC1});
0033
0034
0035
0036 function cache_obj = mk_cache_obj(fwd_model)
0037 cache_obj.elems = fwd_model.elems;
0038 cache_obj.nodes = fwd_model.nodes;
0039 try
0040 cache_obj.electrode = fwd_model.electrode;
0041 end
0042 cache_obj.type = 'fwd_model';
0043 cache_obj.name = '';
0044
0045 function dFC= calc_update_system_mat_fields( fwd_model0, fwd_model1 )
0046 p0= fwd_model_parameters( fwd_model0, 'skip_VOLUME' );
0047 p1= fwd_model_parameters( fwd_model1, 'skip_VOLUME' );
0048 d0= p0.n_dims+0;
0049 d1= p0.n_dims+1;
0050 e= p0.n_elem;
0051 n= p0.n_node;
0052
0053
0054 [dn,~] = find(abs(fwd_model0.nodes - fwd_model1.nodes) > eps);
0055 dn = unique(dn);
0056 [de,~] = find(ismember(fwd_model1.elems,dn));
0057 de = unique(de);
0058 assert(all(all(fwd_model0.elems == fwd_model1.elems)), 'expected fmdl0 and fmdl1 to have the same element structure');
0059 assert(all(de <= e), 'invalid elem# found for delta nodes');
0060
0061
0062
0063 if 1
0064 FFjidx= floor([0:d0*e-1]'/d0)*d1*ones(1,d1) + ones(d0*e,1)*(1:d1);
0065 FFiidx= [1:d0*e]'*ones(1,d1);
0066 FFdata= zeros(d0*e,d1);
0067 dfact = (d0-1)*d0;
0068 for j=de(:)'
0069 a0= inv([ ones(d1,1), p0.NODE( :, p0.ELEM(:,j) )' ]);
0070 a1= inv([ ones(d1,1), p1.NODE( :, p0.ELEM(:,j) )' ]);
0071 idx= d0*(j-1)+1 : d0*j;
0072 FFdata(idx,1:d1)= a1(2:d1,:)/ sqrt(dfact*abs(det(a1))) - a0(2:d1,:)/ sqrt(dfact*abs(det(a0)));
0073 end
0074
0075 idx = all(FFdata==0,2);
0076 FFdata(idx,:) = [];
0077 FFiidx(idx,:) = [];
0078 FFjidx(idx,:) = [];
0079
0080 else
0081 ded0 = bsxfun(@plus,[de(:)-1]*d0,1:d0)';
0082 ded0 = ded0(:); lded0= length(ded0);
0083 FFjidx= floor([ded0-1]/d0)*d1*ones(1,d1) + ...
0084 ones(lded0,1)*(1:d1);
0085 FFiidx= ded0*ones(1,d1);
0086 FFdata= zeros(lded0,d1);
0087 dfact = (d0-1)*d0;
0088 for i=1:length(de); j=de(i);
0089 a0= inv([ ones(d1,1), p0.NODE( :, p0.ELEM(:,j) )' ]);
0090 a1= inv([ ones(d1,1), p1.NODE( :, p0.ELEM(:,j) )' ]);
0091 idx= d0*(i-1)+1 : d0*i;
0092 FFdata(idx,1:d1)= a1(2:d1,:)/ sqrt(dfact*abs(det(a1))) - a0(2:d1,:)/ sqrt(dfact*abs(det(a0)));
0093 end
0094 end
0095
0096
0097
0098
0099
0100
0101 [F2data0,F2iidx0,F2jidx0, C2data0,C2iidx0,C2jidx0] = compl_elec_mdl(fwd_model0,p0,dn);
0102 [F2data1,F2iidx1,F2jidx1, C2data1,C2iidx1,C2jidx1] = compl_elec_mdl(fwd_model1,p1,dn);
0103
0104 if 1
0105 FF= sparse([FFiidx(:); F2iidx0(:); F2iidx1(:)],...
0106 [FFjidx(:); F2jidx0(:); F2jidx1(:)],...
0107 [FFdata(:); -F2data0(:); +F2data1(:)]);
0108 else
0109
0110 F1=sparse(FFiidx, FFjidx, ...
0111 FFdata, d0*e, d1*e);
0112 F2=sparse(F2iidx0,F2jidx0, ...
0113 -F2data0, d0*e, d1*e);
0114 F3= sparse(F2iidx1,F2jidx1, ...
0115 F2data1,d0*e, d1*e);
0116 FF = F1 + F2 + F3;
0117 end
0118
0119 CC= sparse([(1:d1*e)'; C2iidx0(:)], ...
0120 [p0.ELEM(:); C2jidx0(:)], ...
0121 [ones(d1*e,1); C2data0(:)]);
0122
0123 dFC= FF*CC;
0124
0125
0126
0127 function [FFdata,FFiidx,FFjidx, CCdata,CCiidx,CCjidx] = ...
0128 compl_elec_mdl(fwd_model,pp,dn)
0129 d0= pp.n_dims;
0130 FFdata= zeros(0,d0);
0131 FFd_block= sqrtm( ( ones(d0) + eye(d0) )/6/(d0-1) );
0132 FFiidx= zeros(0,d0);
0133 FFjidx= zeros(0,d0);
0134 FFi_block= ones(d0,1)*(1:d0);
0135 CCdata= zeros(0,d0);
0136 CCiidx= zeros(0,d0);
0137 CCjidx= zeros(0,d0);
0138
0139 sidx= d0*pp.n_elem;
0140 cidx= (d0+1)*pp.n_elem;
0141 for i= 1:pp.n_elec
0142 eleci = fwd_model.electrode(i);
0143
0144 zc= eleci.z_contact;
0145 if any(find(ismember(eleci.nodes,dn)))
0146 [bdy_idx, bdy_area] = find_electrode_bdy( ...
0147 pp.boundary, fwd_model.nodes, eleci.nodes );
0148
0149
0150 for j= 1:length(bdy_idx);
0151 bdy_nds= pp.boundary(bdy_idx(j),:);
0152
0153
0154
0155 FFdata= [FFdata; FFd_block * sqrt(bdy_area(j)/zc)];
0156 FFiidx= [FFiidx; FFi_block' + sidx];
0157 FFjidx= [FFjidx; FFi_block + cidx];
0158
0159 CCiidx= [CCiidx; FFi_block(1:2,:) + cidx];
0160 CCjidx= [CCjidx; bdy_nds ; (pp.n_node+i)*ones(1,d0)];
0161 CCdata= [CCdata; [1;-1]*ones(1,d0)];
0162 sidx = sidx + d0;
0163 cidx = cidx + d0;
0164 end
0165 else
0166 [bdy_idx] = find_electrode_bdy( ...
0167 pp.boundary, fwd_model.nodes, eleci.nodes );
0168
0169
0170 for j= 1:length(bdy_idx);
0171 bdy_nds= pp.boundary(bdy_idx(j),:);
0172
0173
0174
0175 FFdata= [FFdata; FFd_block * 0];
0176 FFiidx= [FFiidx; FFi_block' + sidx];
0177 FFjidx= [FFjidx; FFi_block + cidx];
0178
0179 CCiidx= [CCiidx; FFi_block(1:2,:) + cidx];
0180 CCjidx= [CCjidx; bdy_nds ; (pp.n_node+i)*ones(1,d0)];
0181 CCdata= [CCdata; [1;-1]*ones(1,d0)];
0182 sidx = sidx + d0;
0183 cidx = cidx + d0;
0184 end
0185 end
0186
0187 end
0188
0189 function do_unit_test
0190 disp('running system_mat_fields UNIT_TEST');
0191 system_mat_fields('UNIT_TEST');
0192
0193 eidors_cache('clear_name', 'system_mat_fields');
0194 eidors_cache('clear_name', 'update_system_mat_fields');
0195 disp('running update_system_mat_fields UNIT_TEST');
0196 imdl= mk_geophysics_model('h2e',32);
0197 ndim = size(imdl.fwd_model.nodes,2);
0198 for i = 1:10
0199 fmdl0 = imdl.fwd_model;
0200 fmdl0.nodes(1,:) = fmdl0.nodes(1,:) + rand(1,ndim)*1e-10;
0201 t=tic; FC0 = system_mat_fields(fmdl0); t0(i)=toc(t);
0202
0203
0204 fmdl1 = fmdl0;
0205 nn = fmdl1.electrode(1).nodes;
0206 nn = [nn(1); nn(end)];
0207 fmdl1.nodes(nn,:) = fmdl1.nodes(nn,:) + 1e-4+rand(2,ndim)*1e-10;
0208 FC0 = system_mat_fields(fmdl0);
0209 fwd_model_parameters(fmdl1,'skip_VOLUME');
0210 t=tic; FC1a = update_system_mat_fields(fmdl0, fmdl1); t1(i)=toc(t);
0211 t=tic; FC1b = system_mat_fields(fmdl1); t2(i)=toc(t);
0212 eidors_cache('clear_name', 'system_mat_fields');
0213 t=tic; FC1c = system_mat_fields(fmdl1); t3(i)=toc(t);
0214 end
0215 fprintf('system_mat_fields(fmdl0) = %0.2f sec\n',mean(t0));
0216 fprintf('update_system_mat_fields(fmdl0,fmdl1) = %0.3f sec [faster?]\n',mean(t1));
0217 fprintf('system_mat_fields(fmdl1) = %0.3f sec [cache hit?]\n',mean(t2));
0218 fprintf('system_mat_fields(fmdl1+delta) = %0.3f sec [recalculate]\n',mean(t3));
0219
0220 unit_test_cmp('delta FC is fast ',mean(t1) < mean(t0)/2,1);
0221 unit_test_cmp('cache trick is really fast ',mean(t2./t0) < 0.030,1);
0222 unit_test_cmp('cache was cleared before recalc ',mean(t3) > mean(t2)*5,1);
0223 unit_test_cmp('cache trick returns correct result',FC1a,FC1b);
0224 unit_test_cmp('delta FC gives same result ',FC1a,FC1c,3e2*eps);
0225 fprintf('speed-up: %0.2f\n',mean(t0./t1));
0226 if(sum(sum((FC1a - FC1c).^2)) > 100*eps)
0227 err = FC1a - FC1c
0228 end
0229
0230 if 0
0231 disp('---- profiling ----');
0232 fmdl1.nodes(nn,:) = fmdl1.nodes(nn,:) + rand(2,ndim)*1e-3;
0233 t=tic; FC0 = system_mat_fields(fmdl0); t0=toc(t);
0234 profile clear;
0235 profile on;
0236 t = tic; FC1a = update_system_mat_fields(fmdl0, fmdl1); t1=toc(t);
0237 profile off;
0238 profview;
0239 profsave(profile('info'),'profile');
0240 fprintf('update_system_mat_fields(fmdl0,fmdl1) = %0.3f sec [profiled]\n',t1);
0241 end
0242
0243 function time_test_code
0244 f0= mk_common_model('e3cr',4);
0245 f0 = f0.fwd_model; f1=f0;
0246 f1.nodes(1,:)= f1.nodes(1,:) + 1e-6*[1,1,1];
0247 Fa= system_mat_fields(f1);
0248 for sp=1:10;eidors_cache clear;switch sp;
0249 case 1;
0250 tic; F1= update_system_mat_fields(f0,f1); toc
0251 case 2;
0252 tic; F0= system_mat_fields(f0); toc
0253 tic; F1= update_system_mat_fields(f0,f1); toc
0254 case 3;
0255 sv = 'skip_VOLUME';
0256 tic; fwd_model_parameters(f0,sv); toc
0257 tic; fwd_model_parameters(f0,sv); toc
0258 tic; fwd_model_parameters(f1,sv); toc
0259 tic; fwd_model_parameters(f1,sv); toc
0260 disp ----
0261 tic; F0= system_mat_fields(f0); toc
0262 tic; F0= system_mat_fields(f0); toc
0263 disp ----
0264 tic; F1= update_system_mat_fields(f0,f1); toc
0265 tic; F1= update_system_mat_fields(f0,f1); toc
0266 tic; Fb= system_mat_fields(f1); toc
0267 unit_test_cmp('',Fa,F1,1e-10);
0268 otherwise; break;
0269 end; end
0270