remove_unused_nodes

PURPOSE ^

REMOVE_UNUSED_NODES: identify and remove unused nodes in model

SYNOPSIS ^

function fmdl = remove_unused_nodes( fmdl, elec_opt )

DESCRIPTION ^

 REMOVE_UNUSED_NODES: identify and remove unused nodes in model
 Usage: 
 fmdl = REMOVE_UNUSED_NODES( fmdl );
 fmdl = REMOVE_UNUSED_NODES( fmdl, elec_opt) specifies behavior for empty
 electrodes: 
   'warn'      - (default) warns about empty electrodes, but keeps them
   'keep'      - quietly keeps empty electrodes
   'remove'    - quetly removes empty electrodes
   'quiet'     - don't warn about changes to electrodes
 
 See also REMOVE_NODES, REMOVE_ELEMS, CROP_MODEL

CROSS-REFERENCE INFORMATION ^

This function calls: This function is called by:

SUBFUNCTIONS ^

SOURCE CODE ^

0001 function fmdl = remove_unused_nodes( fmdl, elec_opt )
0002 % REMOVE_UNUSED_NODES: identify and remove unused nodes in model
0003 % Usage:
0004 % fmdl = REMOVE_UNUSED_NODES( fmdl );
0005 % fmdl = REMOVE_UNUSED_NODES( fmdl, elec_opt) specifies behavior for empty
0006 % electrodes:
0007 %   'warn'      - (default) warns about empty electrodes, but keeps them
0008 %   'keep'      - quietly keeps empty electrodes
0009 %   'remove'    - quetly removes empty electrodes
0010 %   'quiet'     - don't warn about changes to electrodes
0011 %
0012 % See also REMOVE_NODES, REMOVE_ELEMS, CROP_MODEL
0013 
0014 % (C) 2019 Andy Adler. License: GPL v2 or v3. $Id: remove_unused_nodes.m 7014 2024-11-27 09:07:51Z bgrychtol $
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; % don't operate on pathalogical models
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)]); % all nodes/faces removed
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       % if we had many nodes and less than 3 are left, delete them
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; % don't warn twice
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 %  fmdl.boundary = find_boundary(fmdl);
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 %% New gnd node if missing
0091          fmdl = assign_new_gnd_node( fmdl );
0092       end
0093    end
0094 
0095 %  fmdl.elems = reshape(nidx(fmdl.elems),[],size(fmdl.elems,2));
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,:) = []; % remove all elements using that node
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,:) = []; % remove all elements using that node
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')

Generated on Sun 29-Dec-2024 11:41:59 by m2html © 2005