THE AUDITORY MODELING TOOLBOX

Applies to version: 1.5.0

View the help

Go to function

AMT_CACHE - Caches variables for later or retrieves variables from cache

Program code:

function varargout=amt_cache(cmd,name,varargin)
%AMT_CACHE  Caches variables for later or retrieves variables from cache
%   Usage: var = amt_cache('get', package, flags);
%          amt_cache('set', package, variables);
%   
%   Input parameters:
%
%     get      : gets the content of a package from the cache.
%                variables = AMT_CACHE('get', package) reads a package from the cache
%                and outputs its content in var. package must a be a string
%                identifying the package of variables. If the package contains multiple
%                variables, variables can be a list of variables like 
%                [var1, var2, ... , varN] = .... The order of returned variables is the
%                same as that used for saving in cache.
%                ... = AMT_CACHE('get', package, flags) allows to control the 
%                behaviour of accessing the cache. 
%
%     set      : stores variables as a package in the cache. 
%                AMT_CACHE('set', package, variables) saves variables in the cache using
%                the name package. variables can be a list of variables separated by
%                comma.
%                
%     getURL   : outputs the URL of the cache in the internet. 
%
%     setURL   : sets the URL of the internet cache to a new URL. 
%
%     clearAll : clears the cache directory. An interactive confirmation is required.
%
%
%   AMT_CACHE is a utility function for avoiding long computation times by retrieving
%   pre-calculated intermediate results from the AMT's online repository.
%
%   The following flags can be specified
%
%     'normal'    Use cached package.
%                 If the cached package is locally not available, it will be downloaded from the internet. 
%                 If it is remotely not available, enforce recalculation of the package. 
%                 Note that this method may by-pass the actual processing and thus does not always test the
%                 actual functionality of a model.
%
%     'cached'    Enforce to used cached package.
%                 If the cached package is locally not available, it will be 
%                 downloaded from the internet. 
%                 If it is remotely not available, enforce recalculation of the package. 
%                 Note that this method may by-pass the actual processing and thus 
%                 does not always test the actual functionality of a model. 
%                 It is, however, very convenient for fast access of results 
%                 like plotting figures. On the internet, the cached packages 
%                 are available for the release versions only.
%
%     'redo'    Enforce the recalculation of the package.
%               [..] = AMT_CACHE('get', [..]) outputs empty variables always. 
%
%     'localonly'    Package will be recalculated when locally not available.
%                    Do not connect to the internet.
% 
%
%
%   This is an example of using the cache in a function. 
%   In this example, we store the variables x, y, and z in the package
%   fileABC*:
%
%     definput.import={'amt_cache'}; % setup the usage of cache mode flags
%     [flags,~]  = ltfatarghelper({},definput,varargin); % get default or user-defined cache mode
%     [x,y,z] = amt_cache('get', 'fileABC', flags.cachemode); % get the cached data
%     if isempty(x) % x is empty if cache not available or cache mode set to recalculate
%           % calculate your variables x,y,z here
%         amt_cache('set', 'fileABC', x, y, z); % cache calculated variables in fileABC
%     end
%     %  use your variables x, y, z here
%
%   Note that in this example, the flags indicating the mode of caching are
%   stored in flags.cachemode. These flags can be obtained by:
% 
%     definput.import={'amt_cache'};
%     [flags, ~] = ltfatarghelper({}, definput, varargin); 
%
%   at the begin of your function. This way, the AMT's default cache mode can be 
%   overloaded by the user when calling your function. 
%
%
%   See also: data_ziegelwanger2013 exp_baumgartner2014
%
%   Url: http://amtoolbox.org/amt-1.5.0/doc/core/amt_cache.php


%   #Author: Piotr Majdak (2015): implementation
%   #Author: Clara Hollomey (2021): ???
%   #Author: Piotr Majdak (2023): replaced disp by amt_disp, doc fixes

% This file is licensed unter the GNU General Public License (GPL) either 
% version 3 of the license, or any later version as published by the Free Software 
% Foundation. Details of the GPLv3 can be found in the AMT directory "licences" and 
% at <https://www.gnu.org/licenses/gpl-3.0.html>. 
% You can redistribute this file and/or modify it under the terms of the GPLv3. 
% This file is distributed without any warranty; without even the implied warranty 
% of merchantability or fitness for a particular purpose. 

%%   `amt_cache` supports the following commands:

[~, kv] = amt_configuration;
mlock;
persistent CacheURL CacheMode;
caller = dbstack;
last = 2;

if isempty(CacheURL)
  CacheURL = kv.cacheURL;
  if ( numel(caller)==1 ) || ( numel(caller) > 1 && ~strcmp('amt_configuration', caller(last).name) )
    amt_configuration('cacheURL', CacheURL);
  end  
end

if isempty(CacheMode)
  CacheMode='normal'; 
  if ( numel(caller)==1 ) || ( numel(caller) > 1 && ~strcmp('amt_configuration', caller(last).name) )
    amt_configuration('cachemode', CacheMode);
  end  
end

switch cmd
  case 'set'
    f=dbstack('-completenames');
    fn=f(2).file;
    token=urlencode(strrep(fn(length(amt_basepath)+1:end),'\','/'));
    tokenpath=fullfile(amt_basepath,'cache',token);
    tokenfn=fullfile(tokenpath,[name '.mat']);
    
    if ~exist(tokenpath,'dir'); mkdir(tokenpath); end
    for ii=3:nargin
        cache(ii-2).name=inputname(ii);
        cache(ii-2).value=varargin{ii-2};
    end
    save(tokenfn,'cache','-v6');
    varargout{1}=tokenfn;
    
  case 'get'
    if nargin<3, varargin{1}='global'; end  % if not provided: global
    if strcmp(varargin{1},'global'), varargin{1}=CacheMode; end  % if global: use the stored cache mode
      % now let's parse the cache mode
    switch varargin{1}
      case 'redo' % force recalculations in any case
        for ii=1:nargout, varargout{ii}=[]; end

      case 'cached' % use local cache. If not available download from the internet. If not available throw an error.
        f=dbstack('-completenames');
        fn=f(2).file;
        token=urlencode(strrep(fn(length(amt_basepath)+1:end),'\','/'));
        tokenpath=fullfile(amt_basepath,'cache',token);
        tokenfn=fullfile(tokenpath,[name '.mat']);
        if ~exist(tokenfn,'file')
          webfn=[CacheURL '/' urlencode(token) '/' name '.mat'];
          amt_disp(['Cache: Downloading ' name '.mat for ' token]);
          if ~exist(tokenpath,'dir'); mkdir(tokenpath); end
          if isoctave
            [~, stat]=urlwrite(webfn, tokenfn);
          else
            try
              outfilename = websave(tokenfn,webfn);
              stat = 1;
            catch
              stat = 0;
            end
          end

          if ~stat     
          for ii = 2:numel(kv.version)
            webfn=[kv.downloadURL kv.version{ii} '/cache/' urlencode(token) '/' name '.mat'];
            if isoctave
              [~,stat]=urlwrite(webfn,tokenfn);
            else
              try
                outfilename = websave(tokenfn,webfn);
                stat = 1;
              catch
                stat = 0;
              end
            end  

            if stat
              amt_disp(['Found data in version: ' kv.version{ii}]);
              break;
            end
          
            if ii == numel(kv.version)
              error(['Unable to download file: ' webfn]);
            end
          end
          end      
        end
        load(tokenfn);
        for ii=1:nargout
          varargout{ii}=cache(ii).value;
        end
        
      case 'localonly' % use local cache only. If not available, enforce recalculation
        f=dbstack('-completenames');
        fn=f(2).file;
        token=urlencode(strrep(fn(length(amt_basepath)+1:end),'\','/'));
        tokenpath=fullfile(amt_basepath,'cache',token);
        tokenfn=fullfile(tokenpath,[name '.mat']);
        if ~exist(tokenfn,'file'),
            amt_disp(['Cached data not found: ' tokenfn]);
            amt_disp('Enforce recalculation...');
            for ii=1:nargout, varargout{ii}=[]; end % enforce recalculation
        else
          load(tokenfn);
          for ii=1:nargout
            varargout{ii}=cache(ii).value;
          end
        end

      case 'normal' % use local cache. If not available download from the internet. If not available recalculate.
        f=dbstack('-completenames');
        fn=f(2).file;
        token=urlencode(strrep(fn(length(amt_basepath)+1:end),'\','/'));
        tokenpath=fullfile(amt_basepath,'cache',token);
        tokenfn=fullfile(tokenpath,[name '.mat']);
        if ~exist(tokenfn,'file'),
          webfn=[CacheURL '/' urlencode(token) '/' name '.mat'];
          amt_disp(['Cache: Downloading ' name '.mat for ' token]);
          if ~exist(tokenpath,'dir'); mkdir(tokenpath); end
          if isoctave
            [~, stat]=urlwrite(webfn, tokenfn);
          else
            try
              outfilename = websave(tokenfn,webfn);
              stat = 1;
            catch
              stat = 0;
            end
          end

          if ~stat     
            amt_disp('Data not found. Searching in previous AMT versions...');
          for ii = 2:numel(kv.version)
            webfn=[kv.downloadURL kv.version{ii} '/cache/' urlencode(token) '/' name '.mat'];
            if isoctave
              [~,stat]=urlwrite(webfn,tokenfn);
            else
              try
                outfilename = websave(tokenfn,webfn);
                stat = 1;
              catch
                stat = 0;
              end
            end  

            if stat
              amt_disp(['Found data in version: ' kv.version{ii}]);
              %load(tokenfn);  % downloaded to local cache. Load...
              %for ii=1:nargout
              %varargout{ii}=cache(ii).value;
              %end
              break;
            end
          
            if ii == numel(kv.version)
                amt_disp(['Cached data not found: ' webfn]);
                amt_disp('Enforce recalculation...');
            %else         
            %    load(tokenfn);  % downloaded to local cache. Load...
            %    for ii=1:nargout
            %    varargout{ii}=cache(ii).value;
            %    end
            end 
          end
          end
          %end
          if stat
            load(tokenfn);  % downloaded to local cache. Load...
            for ii=1:nargout
              varargout{ii}=cache(ii).value;
            end
          else
            for ii=1:nargout
              varargout{ii}=[];
            end    
          end
    else
        load(tokenfn);  % Locally available, load...
        for ii=1:nargout
           varargout{ii}=cache(ii).value;
        end
    end    
    end
  case 'setURL'
    CacheURL=name;
    
    if ( numel(caller)==1 ) || ( numel(caller) > 1 && ~strcmp('amt_configuration', caller(last).name) )
      amt_configuration('cacheURL', name);
    end
    
  case 'getURL'
    varargout{1}=CacheURL;
  case 'clearAll'
    cachepath=fullfile(amt_basepath,'cache');
    if strcmp(input(['clearAll clears ' strrep(cachepath,'\','\') '. Type YES for confirmation: '],'s'),'YES'), 
      amt_disp(['Clearing ' cachepath ' ...']);
      rmdir(cachepath, 's');       
    end
  case 'setMode'
    CacheMode = name;
    %if exist(flags.cachemode) && ~strcmp(flags.cachemode, name)
    if ( numel(caller)==1 ) || ( numel(caller) > 1 && ~strcmp('amt_configuration', caller(last).name) )
      amt_configuration('cachemode', name);
    end

  otherwise
    error('Unsupported command');
    end
end