diff m-toolbox/classes/@pest/eval.m @ 0:f0afece42f48

Import.
author Daniele Nicolodi <nicolodi@science.unitn.it>
date Wed, 23 Nov 2011 19:22:13 +0100
parents
children
line wrap: on
line diff
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/m-toolbox/classes/@pest/eval.m	Wed Nov 23 19:22:13 2011 +0100
@@ -0,0 +1,391 @@
+% EVAL evaluate a pest object
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%
+% DESCRIPTION: EVAL evaluate a pest model.
+%
+% CALL:        b = eval(p, pl)
+%              b = eval(p, x, pl)
+%              b = eval(p, x1, ... , xN, pl)
+%              b = eval(p, [x1 ... xN], pl)
+%
+% INPUTS:      p  - input pest(s) containing parameter values.
+%              xi - input ao(s) containing x values (as x or y fields, depending on the 'xfield' parameter)
+%              pl - parameter list (see below)
+%
+% OUTPUTs:     b  - an AO containing the model evaluated at the given X
+%                   values, with the given parameter values.
+%
+% <a href="matlab:utils.helper.displayMethodInfo('pest', 'eval')">Parameters Description</a>
+%
+% VERSION:     $Id: eval.m,v 1.28 2011/05/15 22:47:14 mauro Exp $
+%
+% EXAMPLES:
+%
+% % 1)
+% % Prepare the symbolic model
+% mdl = smodel(plist('expression', 'a1.*x + a2.*x.^2 + a0', 'xvar', 'x', 'yunits', 'V'));
+%
+% % Prepare the pest object
+%
+% p = pest(plist('paramnames', {'a0','a1','a2'}, 'y', [1 2 3], 'models', mdl));
+%
+% % Evaluate the object
+% a1 = eval(p, plist('xdata', ao([1:10])))
+% a2 = eval(p, ao([1:10]))
+%
+% % 2)
+% % Prepare the symbolic model
+% mdl = smodel(plist('expression', 'a1.*x1 + a2.*x2 + a0', 'xvar', {'x1', 'x2'}, 'yunits', 'm', 'xunits', {'T', 'K'}));
+%
+% % Prepare the pest object
+%
+% p = pest(plist('paramnames', {'a0','a1','a2'}, 'y', [1 2 3], 'yunits', {'m', 'T/m', 'K/m'}, 'models', mdl));
+%
+% % Evaluate the object
+% x1 = ao(plist('yvals', [1:10], 'fs', 1, 'yunits', 'T'));
+% x2 = ao(plist('yvals', [1:10], 'fs', 1, 'yunits', 'K'));
+% a1 = eval(p, plist('xdata', [x1 x2]))
+% a2 = eval(p, [x1 x2])
+% a3 = eval(p, x1, x2)
+%
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+function varargout = eval(varargin)
+  
+  % Check if this is a call for parameters
+  if utils.helper.isinfocall(varargin{:})
+    varargout{1} = getInfo(varargin{3});
+    return
+  end
+  
+  import utils.const.*
+  utils.helper.msg(msg.PROC3, 'running %s/%s', mfilename('class'), mfilename);
+  
+  % Collect input variable names
+  in_names = cell(size(varargin));
+  for ii = 1:nargin,in_names{ii} = inputname(ii);end
+  
+  % Collect all AOs and plists
+  [psts, pst_invars, rest] = utils.helper.collect_objects(varargin(:), 'pest', in_names);
+  [pl, pl_invars, rest]   = utils.helper.collect_objects(rest, 'plist', in_names);
+  [as, as_invars, rest]   = utils.helper.collect_objects(rest, 'ao', in_names);
+  [c, c_invars]           = utils.helper.collect_objects(rest, 'cell', in_names);
+  
+  if nargout == 0
+    error('### eval can not be used as a modifier method. Please give at least one output');
+  end
+  
+  % combine plists
+  pl = parse(pl, getDefaultPlist());
+  
+  % Extract necessary parameters
+  index     = find(pl, 'index');
+  x = find(pl, 'Xdata');
+  if ~isempty(as)
+    x = as;
+  end
+  % I don't know how to deal with the history of a cell array of aos
+  if ~isempty(c)
+    error('Please pass the arguments in a vector or a list')
+  end
+  
+  % Extract the information about the x field, if necessary
+  xfield = pl.find('xfield');
+  switch xfield
+    case 'x'
+      op = str2func('x');
+    case 'y'
+      op = str2func('y');
+    otherwise
+      error('oops')
+  end
+  
+  % Extract the xvals for the smodel, and the output x for the ao
+  switch class(x)
+    case 'cell'
+      switch class(x{1})
+        case 'ao'
+          data_type = find(pl, 'type');
+          if isempty(data_type)
+            % Nothing to do, output data type will be inherited from the first AO
+            if ~isa(x{1}.data, 'cdata')
+              out_x      = x{1};
+            else
+              out_x      = [];
+            end
+            out_xunits = '';
+          else
+            % In this case I have to extract the vector with the output x and xunits
+            out_x = feval(op, x{1});
+            out_xunits = feval(str2func([xfield 'units']), x{1});
+          end
+        case 'double'
+          data_type = find(pl, 'type');
+          xvals = x;
+          switch data_type
+            case {'tsdata', 'fsdata', 'xydata'}
+              out_x      = x;
+              out_xunits = find(pl, 'xunits');
+            case {'cdata', ''}
+              out_x      = [];
+              out_xunits = '';
+            otherwise
+              error('LTPDA error')
+          end
+        otherwise
+      end
+    case 'ao'
+      data_type = find(pl, 'type');
+      if isempty(data_type)
+        % Nothing to do, output data type will be inherited from the first AO
+        if ~isa(x(1).data, 'cdata')
+          out_x      = x(1);
+        else
+          out_x      = [];
+        end
+        out_xunits = '';
+      else
+        % In this case I have to extract the vector with the output x and xunits
+        out_x = feval(op, x(1));
+        out_xunits = feval(str2func([xfield 'units']), x(1));
+      end
+    case 'double'
+      data_type = find(pl, 'type');
+      xvals = x;
+      switch data_type
+        case {'tsdata', 'fsdata', 'xydata'}
+          out_x      = x;
+        case {'cdata', ''}
+          out_x      = [];
+        otherwise
+          error('LTPDA error')
+      end
+      out_xunits = find(pl, 'xunits');
+    otherwise
+  end
+  
+  % If the user wants to override the pest/smodel yunits, let's get them
+  % This works only if the user sets them to something not empty
+  yunits = find(pl, 'yunits');
+  
+  % If we have AOs in a cell....
+  if iscell(x) && all(cellfun(@(x)isa(x, 'ao'), x))
+    % if we have multiple x, we need to convert the y values into a cell array
+    xvals = cellfun(op, x, 'UniformOutput', false);
+  elseif isa(x, 'ao')
+    % we put the y values in to a cell array
+    if numel(x) > 1
+      xvals = cellfun(op, num2cell(x), 'UniformOutput', false);
+    else
+      % ... we take the x values, as per the help
+      xvals = feval(op, x);
+    end
+  end
+  
+  % Loop over input objects
+  for jj = 1:numel(psts)
+    
+    pst = psts(jj);
+    % evaluate models
+    m = copy(pst.models, true);
+    switch class(m)
+      case 'smodel'
+        % Make sure the smodel parameters are named the same as the pest
+        m(index).setParams(pst.names, pst.y);
+        % If the user provided the x vector(s), override the smodel x with these
+        if ~isempty(xvals)
+          m(index).setXvals(xvals);
+        end
+        % Go for the model evaluation
+        out(jj) = eval(m(index), plist(...
+          'output type', data_type, 'output x', out_x, 'output xunits', out_xunits));
+
+        % Setting the units of the evaluated model
+        if ~isempty(yunits)
+          out(jj).setYunits(yunits);
+        end
+        
+      case 'ao'
+        % do linear combination: using lincom
+        out(jj) = lincom(m, pst);
+        out(jj).simplifyYunits;
+        
+  
+      case 'matrix'
+        % check objects of the matrix and switch
+        switch class(m(1).objs)
+          case 'smodel'
+            % Make sure the smodel parameters are named the same as the pest
+            for ii = 1:numel(m.objs)
+              m.objs(ii).setParams(pst.names, pst.y);
+            end
+            % If the user provided the x vector(s), override the smodel x with these
+            if ~isempty(x)
+              for ii = 1:numel(m.objs)
+                m.objs(ii).setXvals(x);
+              end
+            end
+            % Go for the model evaluation
+            tout = ao.initObjectWithSize(size(m.objs,1),size(m.objs,2));
+            for ii=1:size(m.objs,1)
+              for kk=1:size(m.objs,2)
+                tout(ii,kk) = eval(m.objs(ii,kk), plist(...
+                  'output type', data_type, 'output x', out_x));
+                % Setting the units of the evaluated model
+                if ~isempty(yunits)
+                  tout(ii,kk).setYunits(yunits);
+                end
+              end
+            end
+            out(jj) = matrix(tout);
+          case 'ao'
+            % get params from the pest object
+            prms = pst.y;
+            % build cdata aos
+            prmsao = ao.initObjectWithSize(numel(prms),1);
+            for ii = 1:numel(prms)
+              prmsao(ii) = ao(cdata(prms(ii)));
+              prmsao(ii).setYunits(pst.yunits(ii));
+            end
+            % build matrix for parameters
+            prm = matrix(prmsao);
+            % build matrix for the model
+            mm = ao.initObjectWithSize(numel(m(1).objs),numel(prms));
+            for ii = 1:numel(m(1).objs)
+              for kk = 1:numel(prms)
+                mm(ii,kk) = m(kk).getObjectAtIndex(ii);
+              end
+            end
+            mmat = matrix(mm);
+            % eval model
+            tout = mmat*prm;
+            out(jj) = tout;
+        end
+      otherwise
+        error('### current version of pest/eval needs the ''models'' field to be a smodel')
+    end
+    
+    
+    
+    % uncertainties for the evaluated model: calculate them from covariance matrix
+    if ~isempty(pst.cov) && utils.prog.yes2true(pl.find('errors'));
+      switch class(m)
+        case 'smodel'
+          C = pst.cov;
+          p = pst.names;
+          % here we need a matrix of "functions" which are the derivatives wrt parameters,
+          % evaluated at each point x:
+
+          F = [];
+          for kk = 1:length(p)
+            md = eval(diff(m(index), plist('var', p{kk})));
+            F = [F md.y];
+          end
+          % The formula is:
+          % D = F * C * F';
+          % and then we need to take
+          % dy = sqrt(diag(D))
+          if size(md.y, 1) > 1
+            % Make sure we work with columns
+            out(jj).setDy(sqrt(sum((F * C)' .* F'))');
+          else
+            out(jj).setDy(sqrt(sum((F' * C)' .* F)));
+          end
+          
+        otherwise
+          warning('Propagation of the errors on the model not yet implemented')
+      end
+    end
+    
+    % Set output AO name
+    name = sprintf('eval(%s,', pst.name);
+    for kk = 2:numel(pst)
+      name = [name pst(kk).name ','];
+    end
+    name = [name(1:end-1) ')'];
+    out(jj).name = name;
+    % Add history
+    if isempty(as)
+      out(jj).addHistory(getInfo('None'), pl, pst_invars, pst(:).hist);
+    else
+      out(jj).addHistory(getInfo('None'), pl, {pst_invars as_invars}, [pst(:).hist as(:).hist]);
+    end
+  end
+  
+  % Set output
+  varargout = utils.helper.setoutputs(nargout, out);
+  
+end
+
+
+%--------------------------------------------------------------------------
+% Get Info Object
+%--------------------------------------------------------------------------
+function ii = getInfo(varargin)
+  if nargin == 1 && strcmpi(varargin{1}, 'None')
+    sets = {};
+    pl   = [];
+  else
+    sets = {'Default'};
+    pl   = getDefaultPlist();
+  end
+  % Build info object
+  ii = minfo(mfilename, 'pest', 'ltpda', utils.const.categories.sigproc, '$Id: eval.m,v 1.28 2011/05/15 22:47:14 mauro Exp $', sets, pl);
+end
+
+%--------------------------------------------------------------------------
+% Get Default Plist
+%--------------------------------------------------------------------------
+function plout = getDefaultPlist()
+  persistent pl;  
+  if ~exist('pl', 'var') || isempty(pl)
+    pl = buildplist();
+  end
+  plout = pl;  
+end
+
+function pl = buildplist()
+  
+  pl = plist();
+  
+  % INDEX
+  p = param({'index', 'Select which model must be evaluated if more than one.'}, paramValue.DOUBLE_VALUE(1));
+  pl.append(p);
+  
+  % XDATA
+  p = param({'Xdata', ['The X values to evaluate the model at. This can be:<ul>'...
+    '<li>a double vector </li>' ...
+    '<li>a cell array of double vectors</li>' ...
+    '<li>a single AO (from which the Y data will be extracted)</li>' ...
+    '<li>a cell array of AOs (from which the Y data will be extracted)</li></ul>' ...
+    ]}, paramValue.EMPTY_DOUBLE);
+  pl.append(p);
+  
+  % XFIELD
+  p = param({'xfield', 'Choose the field to extract the x values from when inputting AOs for parameter ''xdata''.'},  {2, {'x', 'y'}, paramValue.SINGLE});
+  pl.append(p);
+  
+  % TYPE
+  pv = paramValue.DATA_TYPES;
+  % Add an 'empty' on top of the list
+  pv{2} = [{''} pv{2}];
+  p = param({'type', ['Choose the data type for the output ao.<br>'...
+    'If empty, and if the user input AOs as ''XDATA'', the type will be inherited.']},  pv);
+  p.val.setValIndex(1);
+  pl.append(p);
+  
+  % YUNITS
+  p = param({'yunits','Unit on Y axis.'},  paramValue.STRING_VALUE(''));
+  pl.append(p);
+  
+  % XUNITS
+  p = param({'xunits','Unit on X axis.'},  paramValue.STRING_VALUE(''));
+  pl.append(p);
+  
+  % ERRORS
+  p = param({'errors', ['Estimate the uncertainty of the output values based <br>' ...
+    'on the parameters covariance matrix']}, paramValue.TRUE_FALSE);
+  pl.append(p);
+  
+end
+% END