eidors_obj

PURPOSE ^

EIDORS_OBJ: maintains EIDORS internals

SYNOPSIS ^

function [obj_id, extra_out] = eidors_obj(type,name, varargin )

DESCRIPTION ^

 EIDORS_OBJ: maintains EIDORS internals

 USAGE: to get eidors_version
     version = eidors_obj('eidors_version')

 USAGE: to get interpreter version:
     version = eidors_obj('interpreter_version')

 USAGE: to get path to EIDORS:
     path = eidors_obj('eidors_path');

 USAGE: (for developers) to create a new eidors object:
     obj = eidors_obj('fwd_model','obj name','nodes',N,'elems',E,...)
     obj = eidors_obj('fwd_model',mdl_struct,'name','obj name',..)
     obj = eidors_obj('fwd_model',mdl_struct);
 will return an object of type 'fwd_model' with standardized field order.

 USAGE: (for developers) to set fields on existing objects:
     obj = eidors_obj('set',obj,'name','obj name',...);
     obj = eidors_obj('set',obj);
 will return an object with standardized field order.

 USAGE: to cache values (not recommended)
            obj_id = eidors_obj('set-cache',obj, cachename,value, [time])
     [obj, obj_id] = eidors_obj('get-cache',obj, cachename)

 this will get or set the values of cached properties of the object.

    example: % set jacobian
        obj_id = eidors_obj('set-cache',cache_obj, 'jacobian', J);

    example: % get jacobian or '[]' if not set
        [J, obj_id] = eidors_obj('get-cache',cache_obj, 'jacobian');

 It is recommended to combine in cache_obj the minimum set of variables on
 which the value to be cached depends.
    example: % cache_obj for jacobian
        cache_obj = {img.fwd_model.nodes, img.fwd_model.elems ...
                     img.elem_data, img.fwd_model.jacobian}

 NOTE that rather than directly using eidors_obj to set and get cache, it 
 is recommended to use eidors_cache with a function_handle.

   example:
        J = eidors_cache(@calc_jacobian_adjoint,img,'jacobian');

 See also: EIDORS_CACHE

CROSS-REFERENCE INFORMATION ^

This function calls: This function is called by:

SUBFUNCTIONS ^

SOURCE CODE ^

0001 function [obj_id, extra_out] = eidors_obj(type,name, varargin )
0002 % EIDORS_OBJ: maintains EIDORS internals
0003 %
0004 % USAGE: to get eidors_version
0005 %     version = eidors_obj('eidors_version')
0006 %
0007 % USAGE: to get interpreter version:
0008 %     version = eidors_obj('interpreter_version')
0009 %
0010 % USAGE: to get path to EIDORS:
0011 %     path = eidors_obj('eidors_path');
0012 %
0013 % USAGE: (for developers) to create a new eidors object:
0014 %     obj = eidors_obj('fwd_model','obj name','nodes',N,'elems',E,...)
0015 %     obj = eidors_obj('fwd_model',mdl_struct,'name','obj name',..)
0016 %     obj = eidors_obj('fwd_model',mdl_struct);
0017 % will return an object of type 'fwd_model' with standardized field order.
0018 %
0019 % USAGE: (for developers) to set fields on existing objects:
0020 %     obj = eidors_obj('set',obj,'name','obj name',...);
0021 %     obj = eidors_obj('set',obj);
0022 % will return an object with standardized field order.
0023 %
0024 % USAGE: to cache values (not recommended)
0025 %            obj_id = eidors_obj('set-cache',obj, cachename,value, [time])
0026 %     [obj, obj_id] = eidors_obj('get-cache',obj, cachename)
0027 %
0028 % this will get or set the values of cached properties of the object.
0029 %
0030 %    example: % set jacobian
0031 %        obj_id = eidors_obj('set-cache',cache_obj, 'jacobian', J);
0032 %
0033 %    example: % get jacobian or '[]' if not set
0034 %        [J, obj_id] = eidors_obj('get-cache',cache_obj, 'jacobian');
0035 %
0036 % It is recommended to combine in cache_obj the minimum set of variables on
0037 % which the value to be cached depends.
0038 %    example: % cache_obj for jacobian
0039 %        cache_obj = {img.fwd_model.nodes, img.fwd_model.elems ...
0040 %                     img.elem_data, img.fwd_model.jacobian}
0041 %
0042 % NOTE that rather than directly using eidors_obj to set and get cache, it
0043 % is recommended to use eidors_cache with a function_handle.
0044 %
0045 %   example:
0046 %        J = eidors_cache(@calc_jacobian_adjoint,img,'jacobian');
0047 %
0048 % See also: EIDORS_CACHE
0049 
0050 % (C) 2005-10 Andy Adler. License: GPL version 2 or version 3
0051 % $Id: eidors_obj.m 7121 2024-12-29 14:45:56Z aadler $
0052 
0053 if isstruct(type)
0054    if isfield(type,'type'); 
0055       obj_id = type.type;
0056    else
0057       obj_id = '{non-eidors}';
0058    end
0059    return
0060 end
0061 
0062 if ~ischar(type); % type of a non-eidors char
0063    obj_id = []; %
0064    return
0065 end
0066 
0067 if nargin==0
0068    error('cannot call eidors_obj with no arguments');
0069 end
0070 
0071 
0072 switch type
0073    case 'UNIT_TEST';
0074       do_unit_test; return
0075 % Return the type of an eidors object
0076    case 'set'
0077       obj_id= set_obj( name, varargin{:} );
0078    case 'get-cache'
0079       test_install
0080       obj_id = []; extra_out= [];
0081       if status_check(varargin{1})
0082         [obj_id, extra_out] = get_cache_obj( name, varargin{:} );
0083       end
0084       
0085    case 'set-cache'
0086       test_install
0087       obj_id= [];
0088       if status_check(varargin{1})
0089           obj_id = set_cache_obj( name, varargin{:} );
0090       end
0091 
0092    case 'eidors_version'
0093       obj_id= '3.12';  % Update for New eidors version
0094       
0095    case 'eidors_path'
0096       global eidors_objects
0097       obj_id = eidors_objects.eidors_path;
0098 
0099    case 'interpreter_version'
0100       obj_id= test_versions;
0101 % TODO: Add these functions
0102 %  case 'eidors_path'
0103 %  case 'eidors_dev_path'
0104 %  case 'eidors_cache_path'
0105 
0106    case 'cache_init'
0107       cache_init;
0108       
0109    otherwise
0110       test_install
0111       obj_id= new_obj( type, name, varargin{:} );
0112 end
0113 
0114 function ok = status_check(name)
0115 ok = true;
0116 switch cache_status
0117     case 0
0118         ok = false;
0119     case 0.5
0120         dbs = dbstack;
0121         if cache_status(dbs(3).name) == 0
0122             ok = false;
0123         end
0124         if strcmp(dbs(3).name,'cache_shorthand') && cache_status(dbs(5).name) == 0
0125             ok = false;
0126         end
0127         if cache_status(name) == 0
0128            ok = false;
0129         end
0130 end
0131 
0132 function on = debug_status_check
0133 on = false;
0134 switch debug_status
0135     case 1
0136         on = true;
0137     case 0.5
0138         dbs = dbstack;
0139         if debug_status(dbs(3).name) == 1
0140             on = true;
0141         end
0142 end
0143 
0144 
0145 function out = cache_status(fname)
0146     global eidors_objects;
0147     if nargin == 0
0148         try
0149             out = eidors_objects.cache_enable;
0150         catch
0151             out = 1;
0152         end
0153     else
0154         out = ~any(strcmp(eidors_objects.cache_disabled_on,fname));
0155     end
0156 
0157     
0158 function out = debug_status(fname)   
0159    global eidors_objects;
0160    if nargin == 0
0161       try
0162          out = eidors_objects.debug_enable;
0163       catch
0164          out = 0;
0165       end
0166    else
0167       out = ~any(strcmp(eidors_objects.debug_enabled_on,fname));
0168    end
0169       
0170       
0171 function test_install
0172   global eidors_objects;
0173   if isfield(eidors_objects,'max_cache_size'); return; end % OK
0174   error('EIDORS not correctly started. Did you do ">>run /path/to/eidors/startup"');
0175 
0176 function verstr = test_versions;
0177       ver= version; ver(ver=='.')=' ';
0178       ver = sscanf(ver,'%f'); ver=ver(:);
0179 
0180       % build numbers are too large and interfere
0181       ver(4:end) = [];
0182 
0183       % Convert 7.8.1 to 7.008001
0184       verstr.ver = 1e-3.^(0:length(ver)-1) * ver(:); 
0185 
0186       if exist('OCTAVE_VERSION') == 5
0187          verstr.isoctave = 1;
0188       else
0189          verstr.isoctave = 0;
0190       end
0191 
0192       cptr = computer;
0193       if strcmp(cptr(end+(-1:0)), '64')
0194          verstr.is64bit = 1;
0195       else
0196          verstr.is64bit = 0;
0197       end
0198 
0199 function obj = set_obj( obj, varargin );
0200    for idx= 1:2:nargin-1
0201       obj.( varargin{idx} )= varargin{idx+1};
0202    end
0203    obj = order_fields(obj);
0204 
0205 function obj = order_fields(obj)
0206    if ~isfield(obj, 'type'), return, end
0207    switch obj.type
0208       case 'fwd_model'
0209          field_order = {'type', 'name',...
0210             'nodes', 'elems', 'boundary', ...
0211             'electrode', ...
0212             'stimulation', 'meas_select', ...
0213             'solve', 'jacobian', 'system_mat', ...
0214             'normalize_measurements', 'gnd_node', ... 
0215             'boundary_numbers','mat_idx', 'mat_names'};
0216       case 'inv_model'
0217          field_order = {'type', 'name',...
0218             'fwd_model', 'rec_model','jacobian_bkgnd' ...
0219             'reconst_type','solve', ...
0220             'hyperparameter'};
0221       case 'rec_model'
0222          field_order = {'type', 'name',...
0223             'nodes', 'elems'};
0224       case 'image'
0225          field_order = {'type', 'name', 'fwd_model', ...
0226             'elem_data', 'node_data'};
0227       case 'data'
0228          field_order = {'type', 'name', 'meas'};
0229       otherwise
0230          warning(['Encountered an unexpected object type: ', obj.type,  ...
0231             'Please report on the eidors mailing list if it''s not your typo.'])
0232          return 
0233    end
0234 
0235    fnames = fieldnames(obj);
0236    [~,known_idx] = ismember(fnames,field_order);
0237    field_idx = find(known_idx);
0238    known_order = sortrows([nonzeros(known_idx), field_idx]);
0239 
0240    [~, unknown_order] = sort(fnames(known_idx==0));
0241 
0242    perm = zeros(numel(fnames),1);
0243    perm(1:numel(field_idx)) = known_order(:,2);
0244    perm(numel(field_idx) + unknown_order) = find(known_idx==0);
0245 
0246    obj = orderfields(obj,perm);
0247 
0248    try obj.fwd_model = order_fields(obj.fwd_model); end
0249    try obj.rec_model = order_fields(obj.rec_model); end
0250    
0251 
0252 % val= get_cache_obj( obj, prop, dep_obj1, dep_obj2, ...,  cachename );
0253 function [value, obj_id] = get_cache_obj( obj, prop )
0254    global eidors_objects
0255    DEBUG = eidors_debug('query','eidors_obj');
0256    
0257    value= [];
0258    obj_id = [];
0259    
0260    if DEBUG, str = sprintf('cache request: %s ',prop); end
0261 
0262 % We don't do this since cache directories aren't defined (yet)
0263 %  [objlist, cachename]= proc_obj_list( varargin{:} );
0264    if ~isfield(eidors_objects, 'cache')
0265       cache_init;
0266       if DEBUG, fprintf('%s: NO CACHE FIELD\n',str); end
0267       return
0268    end
0269 
0270    obj_id= calc_obj_id( { obj, prop} );
0271 
0272    if isempty(eidors_objects.cache.meta), 
0273       if DEBUG, fprintf('%s: NO META FIELD\n',str); end
0274       return 
0275    end
0276    c = eidors_objects.cache.cols;
0277 %    match = ismember(prop, eidors_objects.cache.meta(:,c.prop));
0278 %    if any(match)
0279    
0280    if DEBUG, str = [str, obj_id]; end
0281 % if cachename is specified, then cache to that file, rather
0282 %  than to the standard eidors_objects location
0283 % TODO: fixthis - use ( ) for matlab > 6.0
0284 %  if ~isempty( cachename )
0285 %     test_for_cachdir;
0286 %     filename= [ eidors_objects.cachedir, '/' , prop, '_' cachename '.mat' ];
0287 %     if exist( filename, 'file')
0288 %        load(filename); %variable 'value' should be there
0289 %     end
0290 %  else
0291 
0292       if ~isfield( eidors_objects.cache, obj_id);
0293          if DEBUG, fprintf('%s: not found\n',str); end
0294          return
0295       end
0296 
0297       idx = find(strcmp(obj_id, eidors_objects.cache.meta(:,c.obj_id)), 1, 'first');
0298       if DEBUG && isempty(idx), fprintf('%s: EMPTY IDX !!\n',str); end
0299       if ~isempty(idx)
0300          eidors_objects.cache.meta{idx,c.time} = now;
0301          eidors_objects.cache.meta{idx,c.count} = eidors_objects.cache.meta{idx,c.count} + 1;
0302          eidors_objects.cache.meta{idx,c.score_eff} = calc_effort_score(...
0303             eidors_objects.cache.meta{idx,c.effort}, ...
0304             eidors_objects.cache.meta{idx,c.count}, ...
0305             eidors_objects.cache.meta{idx,c.prio});
0306       end
0307       value = eidors_objects.cache.(obj_id);
0308       if DEBUG, fprintf('%s: found\n',str); end
0309 %        value= eval(sprintf('eidors_objects.%s.cache.%s;',obj_id,prop));
0310 %          check_size(obj_id, prop);
0311 %  end
0312 %    end
0313 
0314 function obj_id = set_cache_obj( obj, prop, value, time )
0315    global eidors_objects
0316    obj_id = [];
0317    
0318    if ~cache_this( obj ) ; return ; end
0319 
0320    if nargin  < 4
0321       time = 1; % assume 1 sec
0322    end
0323    
0324    if ~isfield(eidors_objects,'cache');
0325       init_cache;
0326    end
0327 
0328    c = eidors_objects.cache.cols;
0329    
0330 % Cache directories aren't defined, yet
0331 %  [objlist, cachename]= proc_obj_list( varargin{:} );
0332 
0333    obj_id = calc_obj_id( {obj, prop} );
0334    
0335    prio = eidors_objects.cache_priority;
0336 
0337 %  if isempty(cachename)
0338 
0339       ws = whos('value');
0340       row(c.obj_id)   = {obj_id};
0341       row(c.prop)     = {prop};
0342       row(c.size)     = {ws.bytes};
0343       row(c.score_sz) = {calc_size_score(ws.bytes)};
0344       row(c.effort)   = {time};
0345       row(c.prio)     = {prio};
0346       row(c.count)    = {1};
0347       row(c.score_eff)= {calc_effort_score(time, 1, prio)};
0348       row(c.time)     = {now};
0349       
0350       if isfield(eidors_objects.cache, obj_id)
0351          idx = find(strcmp(obj_id, eidors_objects.cache.meta(:,c.obj_id)));
0352          eidors_msg('@@ replaced cache object %s { %s }', obj_id, prop,4);
0353          eidors_objects.cache.size = eidors_objects.cache.size ...
0354                                     - eidors_objects.cache.meta{idx,c.size};
0355                                 
0356       else
0357          idx = size(eidors_objects.cache.meta, 1) + 1;
0358       end
0359       eidors_objects.cache.meta(idx,:) = row;
0360       eidors_objects.cache.( obj_id ) = value;
0361       eidors_objects.cache.size = eidors_objects.cache.size + ws.bytes;
0362       check_size(obj_id, prop);
0363 %  else
0364 %     filename= [ eidors_objects.cachedir, '/' , prop, '_' cachename '.mat' ];
0365 %     save(filename, 'value');
0366 %  end
0367 
0368 function cache_init
0369    global eidors_objects;
0370    
0371    eidors_objects.cache = struct;
0372    eidors_objects.cache.meta = cell(0);
0373    eidors_objects.cache.cols.obj_id    = 1;
0374    eidors_objects.cache.cols.prop      = 2;
0375    eidors_objects.cache.cols.time      = 3;
0376    eidors_objects.cache.cols.size      = 4;
0377    eidors_objects.cache.cols.score_sz  = 5;
0378    eidors_objects.cache.cols.effort    = 6;
0379    eidors_objects.cache.cols.prio      = 7;
0380    eidors_objects.cache.cols.count     = 8;
0381    eidors_objects.cache.cols.score_eff = 9;
0382    eidors_objects.cache.size           = 0;
0383 
0384 function score = calc_size_score(sz)
0385    if iscell(sz)
0386       fn = @(b) round(10*log10(b / 1024));
0387       N = numel(sz);
0388       score = num2cell(cellfun(fn, sz));
0389    else
0390       score = round(10 * log10( sz / 1024));
0391    end
0392    
0393 function score = calc_effort_score( time, counts, prios)
0394    if iscell(time)
0395        score = num2cell( round(10*log10( cell2mat(time) .* cell2mat(counts))) +...
0396                                 cell2mat(prios));
0397    else
0398       score = round(10*log10(time .* counts)) + prios; 
0399    end
0400 
0401 
0402 function obj= new_obj( type, name, varargin );
0403    if isstruct(name)
0404       obj= name;
0405       try
0406          name= obj.name;
0407       catch
0408          name= 'unknown';
0409       end
0410    end
0411 
0412    obj.type = type;
0413    obj.name = name;
0414    obj= set_obj(obj, varargin{:} );
0415 
0416 % This function hashes the value of the variable var
0417 % to create an obj_id. The goal is to allow proper caching
0418 % of calculated matrices, by detecting when a previous
0419 % calculation with same parameters has been made
0420 function obj_id= calc_obj_id( var )
0421    try 
0422       obj_id= eidors_var_id( var );
0423    catch
0424       global eidors_objects;
0425       if ~isfield(eidors_objects,'hash_type')
0426          eidors_objects.hash_type= 1e8+1; 
0427       end
0428 %if hashing code is unavailable, then disable caching function
0429       obj_id= sprintf('id_%031d%08d', 0,eidors_objects.hash_type );
0430       eidors_objects.hash_type= eidors_objects.hash_type + 1;
0431    end
0432 
0433 % Test whether the cachedir field has been set. This is
0434 %  where eidors will store cached calculations. If it has
0435 %  not been set, then create it as 'eidors_cache' in the
0436 %  current directory
0437 %
0438 % NOTE: This code is not (yet) used
0439 function test_for_cachdir
0440    global eidors_objects; 
0441    if ~isfield(eidors_objects, 'cachedir')
0442       cachedir= 'eidors_cache';
0443       eidors_objects.cachedir= [pwd,'/',cachedir];
0444 
0445       if ~exist( eidors_objects.cachedir, 'dir')
0446 % Now we need to ensure that cachedir exists. Because the
0447 % STUPID!!! matlab has a completely useless and nonstandard
0448 % mkdir function, we try this
0449          mkdir(pwd,cachedir); 
0450       end
0451    end
0452 
0453 % Test whether a cachedir function has been provided
0454 % (by testing whether the last entry is a string). If so,
0455 % return it in objlist, otherwise return []
0456 function [objlist, cachedir]= proc_obj_list( varargin );
0457    cachedir= [];
0458    if nargin==0
0459       objlist= {};
0460    elseif ischar(varargin{nargin})
0461       cachedir= varargin{nargin};
0462       objlist = varargin(1:nargin-1);
0463    else
0464       objlist = varargin(:);
0465    end
0466 
0467 function retval= cache_this( obj )
0468 % we choose not to cache data and images because this will
0469 % tend to fill up the workspace.
0470 % TODO: make the DONT_CACHE list use configuable
0471    if ~isstruct( obj); retval=1; return; end
0472    DONT_CACHE= {'data','image'};
0473    if any(strcmp( obj.type, DONT_CACHE));
0474       retval = 0;
0475    else
0476       retval = 1;
0477    end
0478 
0479 function check_size( obj_id , prop )
0480    global eidors_objects;   
0481 %    eidors_objects.( obj_id ).( prop ).last_used = now;
0482 
0483    max_memory= eidors_objects.max_cache_size;
0484 %    ww= whos('eidors_objects');
0485    if eidors_objects.cache.size  > max_memory
0486       eidors_cache('clear_max',floor(max_memory*.75));
0487    end
0488 
0489 % TODO: Lots to write here
0490 function do_unit_test
0491    im = eidors_obj('image','','elem_data',1);
0492    et = eidors_obj(im);
0493    unit_test_cmp('type 0',et,'image');
0494 
0495

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