0001 function fmdl = remove_unused_nodes( fmdl, elec_opt )
0002
0003
0004
0005
0006
0007
0008
0009
0010
0011
0012
0013
0014
0015
0016 if ischar(fmdl) && strcmp(fmdl,'UNIT_TEST'); do_unit_test; return; end
0017
0018 if nargin < 2 || isempty(elec_opt), elec_opt = 'warn'; end
0019 quiet = strcmp(elec_opt, 'quiet');
0020 rm_elec = strcmp(elec_opt, 'remove');
0021 keep = strcmp(elec_opt, 'keep');
0022
0023 if num_elems(fmdl)==0; return; end;
0024
0025 usednodes = unique(fmdl.elems(:));
0026 if max(usednodes) > num_nodes(fmdl)
0027 error('remove_unused_nodes: more nodes are used than exist');
0028 end
0029 fmdl0 = fmdl;
0030 nidx = zeros(num_nodes(fmdl),1);
0031 nidx(usednodes) = 1:length(usednodes);
0032 fmdl.nodes(nidx==0,:) = [];
0033 fmdl.elems = remap(nidx, fmdl.elems);
0034
0035 elecs_changed = false([1 num_elecs(fmdl)]);
0036 elecs_removed = false([1 num_elecs(fmdl)]);
0037 for i=1:num_elecs(fmdl)
0038 fmdl.electrode(i).nodes = remap(nidx, fmdl.electrode(i).nodes);
0039 removed = fmdl.electrode(i).nodes == 0;
0040 elecs_changed(i) = any(removed);
0041 fmdl.electrode(i).nodes( removed ) = [];
0042
0043 if numel(fmdl.electrode(i).nodes) < 3 && any(removed)
0044 fmdl.electrode(i).nodes = [];
0045 end
0046 elec_empty = isempty(fmdl.electrode(i).nodes);
0047 if isfield(fmdl.electrode(i),'faces')
0048 fmdl.electrode(i).faces = remap(nidx, fmdl.electrode(i).faces);
0049 removed = any(fmdl.electrode(i).faces== 0,2);
0050 fmdl.electrode(i).faces(removed,:) = [];
0051 elec_empty= elec_empty && isempty(fmdl.electrode(i).faces);
0052 end
0053 if elec_empty
0054 elecs_removed(i) = true;
0055 if eidors_debug('query', 'remove_unused_nodes')
0056 eidors_msg('Zeros in electrode #%d nodes and faces. Often this means parts of the model are disconnected.',i,1);
0057 keyboard
0058 end
0059 end
0060
0061 end
0062 if any(elecs_removed)
0063 if rm_elec
0064 fmdl.electrode(elecs_removed) = [];
0065 eidors_msg('@@ removed electrode(s) # %s', num2str(find(elecs_removed)),1);
0066 else
0067 if ~keep && ~quiet
0068 warning('EIDORS:ElecEmpty', ['Empty electrodes(s) # %s.\n' ...
0069 'Set eidors_debug(''on'', ''remove_unused_electrodes'') to debug or\n' ...
0070 'set elec_opt to ''keep'' or ''quiet'' to suppress.'], ...
0071 num2str(find(elecs_removed)))
0072 end
0073 if keep
0074 eidors_msg('@@ created empty electrode(s) # %s', num2str(find(elecs_removed)),1);
0075 end
0076 end
0077 elecs_changed(elecs_removed) = false;
0078 end
0079 if ~quiet && ~keep && any(elecs_changed)
0080 warning('EIDORS:ElecChange', ...
0081 'Removed parts of electrode(s) # %s.', num2str(find(elecs_changed)));
0082 end
0083
0084 if isfield(fmdl, 'boundary')
0085 fmdl.boundary = remap(nidx, fmdl.boundary);
0086 fmdl.boundary(any(fmdl.boundary==0,2),:) = [];
0087 end
0088 if isfield(fmdl, 'gnd_node')
0089 fmdl.gnd_node = nidx(fmdl.gnd_node);
0090 if fmdl.gnd_node == 0
0091 fmdl = assign_new_gnd_node( fmdl );
0092 end
0093 end
0094
0095
0096 function mat = remap(nidx,mat)
0097 mat = reshape(nidx(mat),size(mat));
0098
0099 function fmdl = assign_new_gnd_node( fmdl );
0100 eidors_msg('FEM_ELECTRODE: Lost ground node => replacing',1);
0101 d2 = sum((fmdl.nodes - repmat(mean(fmdl.nodes, 1), size(fmdl.nodes, 1), 1)).^2,2);
0102 [~,fmdl.gnd_node] = min(d2);
0103
0104 function do_unit_test
0105 fmdl = getfield(mk_common_model('a2c2',4),'fwd_model');
0106 fmdl.elems(1:4,:) = [];
0107 fmdl = remove_unused_nodes(fmdl);
0108
0109 unit_test_cmp('nodes',size(fmdl.nodes),[40,2]);
0110 unit_test_cmp('elems',size(fmdl.elems),[60,3]);
0111 unit_test_cmp('ground',fmdl.gnd_node,3);
0112
0113 idx = any(fmdl.elems == fmdl.electrode(1).nodes,2);
0114 fmdl.elems(idx,:) = [];
0115 warning('off','EIDORS:ElecEmpty')
0116 fmdl = remove_unused_nodes(fmdl);
0117 [~, id] = lastwarn;
0118 unit_test_cmp('empty warn', id, 'EIDORS:ElecEmpty')
0119 warning('on', 'EIDORS:ElecEmpty')
0120
0121 fmdl = getfield(mk_common_model('n3r2',[16,2]), 'fwd_model');
0122 idx = any(fmdl.elems == fmdl.electrode(1).nodes(1),2);
0123 fmdl.elems(idx,:) = [];
0124 warning('off','EIDORS:ElecChange')
0125 fmdl = remove_unused_nodes(fmdl);
0126 [~, id] = lastwarn;
0127 unit_test_cmp('change warn', id, 'EIDORS:ElecChange')
0128 warning('on', 'EIDORS:ElecChange')