0001 function FC1 = update_system_mat_fields( fwd_model0, fwd_model1 )
0002
0003
0004
0005
0006
0007
0008
0009
0010
0011
0012 if ischar(fwd_model0) && strcmp(fwd_model0,'UNIT_TEST'); do_unit_test; return; end
0013
0014 copt.cache_obj = mk_cache_obj(fwd_model0);
0015 copt.fstr = 'system_mat_fields';
0016 copt.log_level = 4;
0017 FC0 = eidors_cache(@system_mat_fields,{fwd_model0},copt );
0018
0019 t = tic;
0020 copt.cache_obj = 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 t = toc(t);
0027
0028
0029
0030
0031 fstr = 'system_mat_fields';
0032 cache_obj = mk_cache_obj(fwd_model1);
0033 eidors_obj('set-cache', cache_obj, fstr, {FC1}, t);
0034
0035
0036
0037 function cache_obj = mk_cache_obj(fwd_model)
0038 cache_obj.elems = fwd_model.elems;
0039 cache_obj.nodes = fwd_model.nodes;
0040 try
0041 cache_obj.electrode = fwd_model.electrode;
0042 end
0043 cache_obj.type = 'fwd_model';
0044 cache_obj.name = '';
0045
0046 function dFC= calc_update_system_mat_fields( fwd_model0, fwd_model1 )
0047 p0= fwd_model_parameters( fwd_model0, 'skip_VOLUME' );
0048 p1= fwd_model_parameters( fwd_model1, 'skip_VOLUME' );
0049 d0= p0.n_dims+0;
0050 d1= p0.n_dims+1;
0051 e= p0.n_elem;
0052 n= p0.n_node;
0053
0054
0055 [dn,~] = find(abs(fwd_model0.nodes - fwd_model1.nodes) > eps);
0056 dn = unique(dn);
0057 [de,~] = find(ismember(fwd_model1.elems,dn));
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 FFjidx= floor([0:d0*e-1]'/d0)*d1*ones(1,d1) + ones(d0*e,1)*(1:d1);
0062 FFiidx= [1:d0*e]'*ones(1,d1);
0063 FFdata= zeros(d0*e,d1);
0064 dfact = (d0-1)*d0;
0065 for j=de(:)'
0066 a0= inv([ ones(d1,1), p0.NODE( :, p0.ELEM(:,j) )' ]);
0067 a1= inv([ ones(d1,1), p1.NODE( :, p0.ELEM(:,j) )' ]);
0068 idx= d0*(j-1)+1 : d0*j;
0069 FFdata(idx,1:d1)= a1(2:d1,:)/ sqrt(dfact*abs(det(a1))) - a0(2:d1,:)/ sqrt(dfact*abs(det(a0)));
0070 end
0071
0072 if 0
0073 FF= sparse(FFiidx,FFjidx,FFdata);
0074 CC= sparse((1:d1*e),p0.ELEM(:),ones(d1*e,1), d1*e, n);
0075 else
0076
0077
0078
0079
0080
0081 [F2data0,F2iidx0,F2jidx0, C2data0,C2iidx0,C2jidx0] = compl_elec_mdl(fwd_model0,p0,dn);
0082 [F2data1,F2iidx1,F2jidx1, C2data1,C2iidx1,C2jidx1] = compl_elec_mdl(fwd_model1,p1,dn);
0083
0084 FF= sparse([FFiidx(:); F2iidx0(:); F2iidx1(:)],...
0085 [FFjidx(:); F2jidx0(:); F2jidx1(:)],...
0086 [FFdata(:); -F2data0(:); +F2data1(:)]);
0087
0088 CC= sparse([(1:d1*e)'; C2iidx0(:)], ...
0089 [p0.ELEM(:); C2jidx0(:)], ...
0090 [ones(d1*e,1); C2data0(:)]);
0091 end
0092
0093 dFC= FF*CC;
0094
0095
0096 function [FFdata,FFiidx,FFjidx, CCdata,CCiidx,CCjidx] = ...
0097 compl_elec_mdl(fwd_model,pp,dn)
0098 d0= pp.n_dims;
0099 FFdata= zeros(0,d0);
0100 FFd_block= sqrtm( ( ones(d0) + eye(d0) )/6/(d0-1) );
0101 FFiidx= zeros(0,d0);
0102 FFjidx= zeros(0,d0);
0103 FFi_block= ones(d0,1)*(1:d0);
0104 CCdata= zeros(0,d0);
0105 CCiidx= zeros(0,d0);
0106 CCjidx= zeros(0,d0);
0107
0108 sidx= d0*pp.n_elem;
0109 cidx= (d0+1)*pp.n_elem;
0110 for i= 1:pp.n_elec
0111 eleci = fwd_model.electrode(i);
0112
0113 zc= eleci.z_contact;
0114 if any(find(ismember(eleci.nodes,dn)))
0115 [bdy_idx, bdy_area] = find_electrode_bdy( ...
0116 pp.boundary, fwd_model.nodes, eleci.nodes );
0117
0118
0119 for j= 1:length(bdy_idx);
0120 bdy_nds= pp.boundary(bdy_idx(j),:);
0121
0122
0123
0124 FFdata= [FFdata; FFd_block * sqrt(bdy_area(j)/zc)];
0125 FFiidx= [FFiidx; FFi_block' + sidx];
0126 FFjidx= [FFjidx; FFi_block + cidx];
0127
0128 CCiidx= [CCiidx; FFi_block(1:2,:) + cidx];
0129 CCjidx= [CCjidx; bdy_nds ; (pp.n_node+i)*ones(1,d0)];
0130 CCdata= [CCdata; [1;-1]*ones(1,d0)];
0131 sidx = sidx + d0;
0132 cidx = cidx + d0;
0133 end
0134 else
0135 [bdy_idx] = find_electrode_bdy( ...
0136 pp.boundary, fwd_model.nodes, eleci.nodes );
0137
0138
0139 for j= 1:length(bdy_idx);
0140 bdy_nds= pp.boundary(bdy_idx(j),:);
0141
0142
0143
0144 FFdata= [FFdata; FFd_block * 0];
0145 FFiidx= [FFiidx; FFi_block' + sidx];
0146 FFjidx= [FFjidx; FFi_block + cidx];
0147
0148 CCiidx= [CCiidx; FFi_block(1:2,:) + cidx];
0149 CCjidx= [CCjidx; bdy_nds ; (pp.n_node+i)*ones(1,d0)];
0150 CCdata= [CCdata; [1;-1]*ones(1,d0)];
0151 sidx = sidx + d0;
0152 cidx = cidx + d0;
0153 end
0154 end
0155
0156 end
0157
0158 function do_unit_test
0159 disp('running system_mat_fields UNIT_TEST');
0160 system_mat_fields('UNIT_TEST');
0161
0162 eidors_cache('clear_name', 'system_mat_fields');
0163 eidors_cache('clear_name', 'update_system_mat_fields');
0164 disp('running update_system_mat_fields UNIT_TEST');
0165 imdl= mk_geophysics_model('h2e',32);
0166 ndim = size(imdl.fwd_model.nodes,2);
0167 for i = 1:10
0168 fmdl0 = imdl.fwd_model;
0169 fmdl0.nodes(1,:) = fmdl0.nodes(1,:) + rand(1,ndim)*1e-10;
0170 t=tic; FC0 = system_mat_fields(fmdl0); t0(i)=toc(t);
0171
0172
0173 fmdl1 = fmdl0;
0174 nn = fmdl1.electrode(1).nodes;
0175 nn = [nn(1); nn(end)];
0176 fmdl1.nodes(nn,:) = fmdl1.nodes(nn,:) + 1e-4+rand(2,ndim)*1e-10;
0177 t=tic; FC1a = update_system_mat_fields(fmdl0, fmdl1); t1(i)=toc(t);
0178 t=tic; FC1b = system_mat_fields(fmdl1); t2(i)=toc(t);
0179 eidors_cache('clear_name', 'system_mat_fields');
0180 t=tic; FC1c = system_mat_fields(fmdl1); t3(i)=toc(t);
0181 end
0182 fprintf('system_mat_fields(fmdl0) = %0.2f sec\n',mean(t0));
0183 fprintf('update_system_mat_fields(fmdl0,fmdl1) = %0.3f sec [faster?]\n',mean(t1));
0184 fprintf('system_mat_fields(fmdl1) = %0.3f sec [cache hit?]\n',mean(t2));
0185 fprintf('system_mat_fields(fmdl1+delta) = %0.3f sec [recalculate]\n',mean(t3));
0186 unit_test_cmp('delta FC is fast ',mean(t1) < mean(t0)/2,1);
0187 unit_test_cmp('cache trick is really fast ',mean(t2./t0) < 0.015,1);
0188 unit_test_cmp('cache was cleared before recalc ',mean(t3) > mean(t0)*0.9,1);
0189 unit_test_cmp('cache trick returns correct result',FC1a,FC1b);
0190 unit_test_cmp('delta FC gives same result ',FC1a,FC1c,10*eps);
0191 fprintf('speed-up: %0.2f\n',mean(t0./t1));
0192 if(sum(sum((FC1a - FC1c).^2)) > 0)
0193 err = FC1a - FC1c
0194 end
0195
0196 if 0
0197 disp('---- profiling ----');
0198 fmdl1.nodes(nn,:) = fmdl1.nodes(nn,:) + rand(2,ndim)*1e-3;
0199 t=tic; FC0 = system_mat_fields(fmdl0); t0=toc(t);
0200 profile clear;
0201 profile on;
0202 t = tic; FC1a = update_system_mat_fields(fmdl0, fmdl1); t1=toc(t);
0203 profile off;
0204 profview;
0205 profsave(profile('info'),'profile');
0206 fprintf('update_system_mat_fields(fmdl0,fmdl1) = %0.3f sec [profiled]\n',t1);
0207 end