Home > m > gui > gltpda > ltpdasim.m

ltpdasim

PURPOSE ^

This is the automatic function wrapper

SYNOPSIS ^

function ltpdasim(block)

DESCRIPTION ^

             This is the automatic function wrapper
 ========================================================================
 ==================== level-2 M file S-function =========================
 ========================================================================
 This wrapper is the automatic function, called by every function block
 in Simulink, able to execute m-file functions retrieving from Simulink:
 (1) the pointer to the object(s) to be analyzed, coming in as input of 
     the corresponding block (ie, the DATA),
 (2) the name of the function to be applied on those data, from the tag
     of the currently executed block (ie, the true FUNCTION),
 (3) the parameters for that particular block, retrieved from the global
     shared workspace by the handle of the block (ie, the PARAMETERS).

 The output is then generated as:
    OUTPUT = FUNCTION(DATA,PARAMETERS)

 This output in the end is saved into the global array containing all
 the AOs (ie, all the DATA go together with other data): thus this output
 will be freely accessible by all the other functions.

 The only real output to Simulink will be just the ordinal number of the
 so-generated AO into the global array of AOs.

   $Id: ltpdasim.m,v 1.24 2008/08/25 13:20:17 nicola Exp $

CROSS-REFERENCE INFORMATION ^

This function calls: This function is called by:

SUBFUNCTIONS ^

SOURCE CODE ^

0001 function ltpdasim(block)
0002 
0003 %             This is the automatic function wrapper
0004 % ========================================================================
0005 % ==================== level-2 M file S-function =========================
0006 % ========================================================================
0007 % This wrapper is the automatic function, called by every function block
0008 % in Simulink, able to execute m-file functions retrieving from Simulink:
0009 % (1) the pointer to the object(s) to be analyzed, coming in as input of
0010 %     the corresponding block (ie, the DATA),
0011 % (2) the name of the function to be applied on those data, from the tag
0012 %     of the currently executed block (ie, the true FUNCTION),
0013 % (3) the parameters for that particular block, retrieved from the global
0014 %     shared workspace by the handle of the block (ie, the PARAMETERS).
0015 %
0016 % The output is then generated as:
0017 %    OUTPUT = FUNCTION(DATA,PARAMETERS)
0018 %
0019 % This output in the end is saved into the global array containing all
0020 % the AOs (ie, all the DATA go together with other data): thus this output
0021 % will be freely accessible by all the other functions.
0022 %
0023 % The only real output to Simulink will be just the ordinal number of the
0024 % so-generated AO into the global array of AOs.
0025 %
0026 %   $Id: ltpdasim.m,v 1.24 2008/08/25 13:20:17 nicola Exp $
0027 
0028 
0029 setup(block);
0030 
0031 
0032 %% Setup
0033 
0034 function setup(block)
0035 
0036   % Register dialog parameter: none, because they're retrieved directly
0037   % from the memory. This will prevent the user to modify the parameters
0038   % outside the proper parameters panel:
0039   block.NumDialogPrms = 0;
0040 
0041   % Register number of input and output ports
0042   block.NumInputPorts  = 1;
0043   block.NumOutputPorts = 1;
0044 
0045   % Setup functional port properties to dynamically inherited.
0046   block.SetPreCompInpPortInfoToDynamic;
0047 
0048   block.InputPort(1).DirectFeedthrough = true;
0049   block.InputPort(1).DatatypeID = 0;
0050   block.InputPort(1).Complexity = 0;
0051   block.OutputPort(1).DatatypeID = 0;
0052   block.OutputPort(1).Complexity = 0;
0053   block.SampleTimes = [0 0];
0054   block.SetAccelRunOnTLC(false);
0055   
0056   block.OutputPort(1).Dimensions = 1;
0057   
0058   % Register methods
0059   block.RegBlockMethod('SetInputPortSamplingMode',@SetInpPortFrameData);
0060   block.RegBlockMethod('SetInputPortDimensions',  @SetInpPortDims);
0061   block.RegBlockMethod('Outputs',                 @Outputs);
0062   
0063   function SetInpPortFrameData(block, idx, fd) %#ok<INUSL>
0064   block.InputPort(1).SamplingMode = fd;
0065   block.OutputPort(1).SamplingMode  = fd;
0066   
0067   function SetInpPortDims(block, idx, di)
0068   block.InputPort(idx).Dimensions = di;
0069 
0070 
0071 %% Outputs
0072 function Outputs(block)
0073 global LTPDAinvar gl execModels %#ok<NUSED>
0074 
0075 % disp(['The name of the currently executed block is ',get_param(get_param(gcbh,'Parent'),'Name')])
0076 % disp(['The current size of LTPDAinvar is ',num2str(size(LTPDAinvar,1))])
0077 
0078 currparent   = get_param(gcbh,'Parent');
0079 subsyshandle = get_param(currparent, 'handle');
0080 
0081 % Check if it's a partial execution:
0082 if ismember('executionList',evalin('base','who'))
0083    executionList = evalin('base','executionList');
0084    blockIndex = -1;
0085    for i=1:size(executionList,1), if executionList(i)==gcbh, blockIndex = i; break; end; end
0086    if blockIndex == -1 % this block is not included in the list of those to be executed.
0087       disp([' . Partial execution: block ',get_param(subsyshandle,'Name'),' will be skipped.'])
0088       block.OutputPort(1).Data = -1;
0089       return
0090    else
0091     % Check if the block must receive data from Simulink or retrieve them from a previous calculation:
0092       if block.InputPort(1).Data(1)==-1
0093          annotation  = find_system(bdroot,'FindAll','on','Type','Annotation','Tag','ltpda model');
0094          execHistory = get_param(annotation,'UserData');
0095          blockIndex = -1;
0096          for i=1:size(execHistory,1), if execHistory{i,2}==subsyshandle, blockIndex = i; end; end
0097          if blockIndex == -1 % something's wrong: the selected block is not included in the previous execution history
0098             warning(['*** Partial execution: impossible to retrieve inputs. The block ',get_param(subsyshandle,'Name'),' seems to have never been executed.'])
0099             block.OutputPort(1).Data = -1;
0100             return
0101          end
0102          j=3;
0103          while ~isempty(execHistory{blockIndex,j})
0104             block.InputPort(1).Data(j-2) = execHistory{blockIndex,j};
0105             j = j+1;
0106          end
0107          disp([' . Partial execution: block ',get_param(subsyshandle,'Name'),' will now be executed with data retrieved from previous calculation.'])
0108       else
0109          disp([' . Partial execution: block ',get_param(subsyshandle,'Name'),' will now be executed.'])
0110       end
0111    end
0112 end
0113 
0114 % Check if the user wants to stop the execution:
0115 lastChar = get(findobj('Name','LTPDA Progress Bar'),'CurrentCharacter');
0116 if ~isempty(lastChar) && strcmp(lastChar,'x')
0117     set_param(bdroot, 'SimulationCommand', 'stop')
0118     return
0119 end
0120 
0121 % Update the progress bar window:
0122   progressBar  = findobj('Tag','progressaxes');
0123   if ~isempty(progressBar)
0124      blocksTotal = get(findobj('Tag','blockstotal'),'UserData');
0125      blocksDone  = get(findobj('Tag','done'),'UserData');
0126      blocksToGo  = get(findobj('Tag','togo'),'UserData');
0127      set(findobj('Tag','done'),'UserData',blocksDone+1);
0128      set(findobj('Tag','togo'),'UserData',blocksToGo-1);
0129      set(findobj('Tag','done'),'String',['Done: ',num2str(blocksDone+1)]);
0130      set(findobj('Tag','togo'),'String',['To go: ',num2str(blocksToGo-1)]);
0131      set(findobj('Tag','currentexec'),'String',['Currently executed block: ',get_param(get_param(gcbh,'Parent'),'Name')]);
0132      progressSize = get(progressBar,'UserData');
0133      progressPosition    = get(progressBar,'Position');
0134      progressPosition(3) = 1+(progressSize(3)/blocksTotal)*(blocksDone+1);
0135      set(progressBar,'Position',progressPosition)
0136      drawnow
0137   end
0138 
0139 % Retrieve the function name from the block tag:
0140   blocktag = lower(get_param(gcb, 'tag'));
0141   if strcmp(blocktag,'generic')
0142      paramcommand = get_param(get_param(get_param(gcbh,'Parent'), 'handle'),'Description');
0143      eval(paramcommand)
0144      blocktag = functionName;
0145   end
0146   
0147 % ========================================================================
0148 %% For arithmetic blocks
0149 % ========================================================================
0150 
0151   if strcmp(blocktag,'arithmetic')
0152       eq = get_param(currparent,'MaskDescription');
0153       if strcmp(eq,'Arithmetic block: the user can type in the desidered equation.')
0154           disp(sprintf('Error: in the ''%s'' arithmetic block no equation has been typed in.',get_param(currparent,'Name')))
0155           close(findobj('Name','LTPDA Progress Bar'))
0156           error(['Error: in the ',get_param(currparent,'Name'),' arithmetic block no equation has been typed in.'])
0157       end
0158       equation = eq;
0159       equation(strfind(equation,char(10))) = [];
0160       
0161       paramcommand = get_param(subsyshandle,'Description');
0162       if isempty(paramcommand), paramcommand = 'params=plist(''alpha'',''-->'',''beta'',''-->'');'; end
0163       eval(paramcommand)
0164       
0165       for i=1:nparams(params) %#ok<NODEF>
0166           inputBlock = find_system(currparent,'SearchDepth',1,'LookUnderMasks','all','Name',lower(params.params(i).key));
0167            if numel(inputBlock)>1, inputBlock(1)=[]; end % this can happen only when the currparent has the same name: then, ignore the 1st, ie. the currparent itself
0168            inputNumb  = get_param(inputBlock{1},'Tag');
0169            equation = strrep(equation,lower(params.params(i).key),['LTPDAinvar{block.InputPort(1).Data(',inputNumb,'),1}']);
0170       end
0171       
0172    try   
0173       outdata = eval(equation);
0174       
0175     % Setting the output signal name:
0176       ifsetName = get_param(currparent,'UserData');
0177       if ~isempty(ifsetName) && isa(ifsetName,'char')
0178         % ifsetName = ifsetName;
0179       else
0180           ifsetName = get_param(currparent,'Name');
0181       end
0182       if numel(outdata)==1
0183           outdata = setName(outdata,ifsetName);
0184       else
0185           for i=1:size(outdata,1)
0186               for j=1:size(outdata,2)
0187                   outdata(i,j) = setName(outdata(i,j),[ifsetName,'_',num2str(i),'-',num2str(j)]);
0188               end
0189           end
0190       end
0191       
0192       x = size(LTPDAinvar,1);
0193       LTPDAinvar = [LTPDAinvar;{outdata,0}];
0194       block.OutputPort(1).Data = x+1;
0195 
0196       probe = get_param(currparent,'MaskHelp');
0197       if ~isempty(probe) && isa(probe,'char') && strcmp(probe,'probe')
0198           LTPDAinvar{size(LTPDAinvar,1),2} = 2;
0199       end
0200       
0201       return
0202       
0203    catch err
0204        disp(sprintf('Something''s wrong in the calculation of the results of the ''%s'' arithmetic block.',get_param(currparent,'Name')))
0205        disp('The inputs were:')
0206        for i=1:nparams(params)
0207            disp(['Input ',num2str(i),':'])
0208            LTPDAinvar{block.InputPort(1).Data(i),1} %#ok<NOPRT>
0209        end
0210        disp('The equation was:')
0211        disp(eq)
0212        close(findobj('Name','LTPDA Progress Bar'))
0213        
0214        rethrow(err)
0215 
0216    end
0217   end % for the arithmetic block
0218   
0219 % ========================================================================
0220 %% =================== RETRIEVE THE PARAMETERS LIST ======================
0221 % ========================================================================
0222 
0223   % Set this block status to 'executed':
0224     set(subsyshandle,'MaskVariables','1');
0225     set(gcbh,'MaskVariables','1');
0226 
0227   % The command line to produce the proper parameters list for the block
0228   % currently executed is retrieved from the description of this  parent subsystem
0229     paramcommand = get_param(subsyshandle,'Description');
0230 
0231     if ~isempty(paramcommand)
0232         eval(paramcommand);
0233         
0234       % Verify if a global variable name has been used:
0235         for i=1:nparams(params) %#ok<NODEF>
0236             if ischar(params.params(i).val)
0237                 try %#ok<ALIGN>
0238                   % params.params(i).val = evalin('base',params.params(i).val);
0239                     params.params(i).val = eval(params.params(i).val);
0240                 catch end
0241             end
0242         end
0243         
0244         if ~exist('paramEnabled','var'), paramEnabled = ones(1,nparams(params)); end
0245         currparam = plist();
0246         for jj=1:nparams(params)
0247             if paramEnabled(jj)==1
0248                 try %#ok<ALIGN>
0249                 if strcmpi(params.params(jj).key(1:7),'addPar_'), params.params(jj).key(1:7)=[]; end
0250                 catch end
0251 %                 try % for cell array params:
0252 %                     if isa(params.params(jj).val,'char') && strcmp(params.params(jj).val(1),'{'), params.params(jj).val = eval(params.params(jj).val) ; end
0253 %                 catch
0254 %                 end
0255                 currparam = append(currparam,params.params(jj));
0256             end
0257         end
0258     else
0259         currparam = plist();
0260     end
0261 
0262   % Retrieve parameters from Simulink:
0263     paramFromSimulink = 0;
0264     for i=1:nparams(currparam)
0265          paramKey = currparam.params(i).key;
0266          paramVal = currparam.params(i).val;
0267          if (isa(paramVal,'char') && strcmp(paramVal,'-->')) || (isa(paramVal,'cell') && numel(paramVal)==1 && isa(paramVal{1},'char') && strcmp(paramVal{1},'-->'))
0268              paramFromSimulink = paramFromSimulink + 1;
0269              mux = find_system(currparent,'SearchDepth',1,'LookUnderMasks','all','BlockType','Mux');
0270              muxWidths = get_param(mux{1},'CompiledPortWidths');
0271              muxWidths = muxWidths.Inport;
0272              inputBlock = find_system(currparent,'SearchDepth',1,'LookUnderMasks','all','Name',lower(paramKey));
0273              if numel(inputBlock)>1, inputBlock(1)=[]; end % this can happen only when the currparent has the same name: then, ignore the 1st, ie. the currparent itself
0274              inputNumb  = str2double(get_param(inputBlock{1},'Tag'));
0275              x = 0;
0276              for j=1:inputNumb-1
0277                  x=x+muxWidths(j);
0278              end
0279              paramVal = [LTPDAinvar{block.InputPort(1).Data(x+1)}];
0280              if muxWidths(inputNumb)>1
0281                  for j=x+2:x+muxWidths(inputNumb)
0282                      paramVal = [paramVal,LTPDAinvar{block.InputPort(1).Data(j)}];
0283                  end
0284              end
0285              currparam = pset(currparam,paramKey,paramVal);
0286          end
0287     end
0288     
0289 % ========================================================================
0290 %% ======================== CALCULATE THE RESULTS =========================
0291 % ========================================================================
0292 
0293    y = length(block.InputPort(1).Data) - paramFromSimulink;
0294 
0295  % Check to verify the type of function:
0296    specFunc = {'display'};
0297    [meth,classes] = strtok(get(get_param(currparent,'Handle'),'Tag'));
0298    if strcmp(meth,'method')
0299       clas = strtrim(classes);
0300       infoObj = eval([clas,'.getInfo(''',blocktag,''')']);
0301       category = infoObj.mcategory;
0302    end
0303    
0304    if ismember(blocktag,specFunc)
0305      % Input, but no parameters and no output
0306        type = 4;
0307      % ======================================
0308    elseif (exist('category','var') && strcmp(category,'Output'))
0309      % Input and parameters, but no output
0310        type = 3;
0311      % ===================================
0312    elseif ~isempty(utils.prog.find_in_models(currparent,'SearchDepth',1,'LookUnderMasks','all','BlockType','Ground')) || block.InputPort(1).Data(1)==0
0313      % No input, but parameters and output
0314        type = 2;
0315      % ===================================
0316    else
0317      % Input, parameters and output
0318        type = 1;
0319      % ============================
0320    end
0321 
0322 
0323    switch type
0324      % ====================================================================
0325        case 4 % Input, but no parameters and no output
0326             command = 'feval(blocktag,';
0327             for i=1:y
0328                dVal = block.InputPort(1).Data(i);
0329                if dVal>0, command = [command sprintf('LTPDAinvar{%d},', dVal)]; end
0330             end
0331             command = [command(1:end-1) ');'];
0332            try
0333                eval(command)
0334            catch err
0335                disp('4')
0336                disp(sprintf('Something''s wrong in the calculation of the results of the %s function.',blocktag))
0337                disp(sprintf('The name of the currently executed block is %s.',get_param(currparent,'Name')))
0338                disp(sprintf('The (first) input data ordinal number, in the list of objects, was %d.',block.InputPort(1).Data(1)))
0339                close(findobj('Name','LTPDA Progress Bar'))
0340                rethrow(err)
0341            end
0342            block.OutputPort(1).Data = 1; % this will be ignored: no output expected.
0343            return;
0344 
0345      % ====================================================================
0346        case 3 % Input and parameters, but no output
0347            try
0348             command = 'feval(blocktag,';
0349             for i=1:y
0350                dVal = block.InputPort(1).Data(i);
0351                if dVal>0, command = [command sprintf('LTPDAinvar{%d},', dVal)]; end
0352             end
0353             command = [command 'currparam);'];
0354             if strcmpi(blocktag,'plot'), figure; end;
0355             eval(command);
0356            catch err
0357                disp('3')
0358                disp(sprintf('Something''s wrong in the calculation of the results of the %s function.',blocktag))
0359                disp(sprintf('The name of the currently executed block is %s.',get_param(currparent,'Name')))
0360                disp(sprintf('The (first) input data ordinal number, in the list of objects, was %d.',block.InputPort(1).Data(1)))
0361                disp('The plist passed was:')
0362                currparam %#ok<NOPRT>
0363                close(findobj('Name','LTPDA Progress Bar'))
0364                rethrow(err)
0365            end
0366            block.OutputPort(1).Data = 1; % this will be ignored: no output expected.
0367            return;
0368 
0369      % ====================================================================
0370        case 2 % No input, but parameters and output
0371            try
0372                outdata = feval(blocktag,currparam);
0373            catch err
0374                disp('2')
0375                disp(sprintf('Something''s wrong in the calculation of the results of the %s function.',blocktag))
0376                disp(sprintf('The name of the currently executed block is %s.',get_param(currparent,'Name')))
0377                disp('The plist passed was:')
0378                currparam %#ok<NOPRT>
0379                close(findobj('Name','LTPDA Progress Bar'))
0380                rethrow(err)
0381            end
0382 
0383      % ====================================================================
0384        case 1 % Input, parameters and output
0385            try
0386                command = 'outdata = feval(blocktag,';
0387                for i=1:y
0388                   dVal = block.InputPort(1).Data(i);
0389                   if dVal>0, command = [command sprintf('LTPDAinvar{%d},', dVal)]; end
0390                end
0391                command = [command 'currparam);'];
0392                eval(command);
0393            catch err
0394                disp('1')
0395                disp(sprintf('Something''s wrong in the calculation of the results of the %s function.',blocktag))
0396                disp(sprintf('The name of the currently executed block is %s.',get_param(currparent,'Name')))
0397                disp(sprintf('The (first) input data ordinal number, in the list of objects, was %d.',block.InputPort(1).Data(1)))
0398                disp('The plist passed was:')
0399                currparam %#ok<NOPRT>
0400                close(findobj('Name','LTPDA Progress Bar'))
0401                rethrow(err)
0402            end
0403 
0404    end
0405 
0406 % ========================================================================
0407 %% =============================== OUTPUTS ================================
0408 % ========================================================================
0409 
0410 signalName = get_param(currparent,'Name');
0411 ifsetName = get_param(currparent,'UserData');
0412 if ~isempty(ifsetName) && isa(ifsetName,'double') && ifsetName==1
0413     if numel(outdata)==1
0414         outdata = setName(outdata,signalName);
0415     else
0416         for i=1:size(outdata,1)
0417             for j=1:size(outdata,2)
0418                 outdata(i,j) = set(outdata(i,j),'name',[signalName,'_',num2str(i),'-',num2str(j)]);
0419             end
0420         end
0421     end
0422 end
0423 
0424 try
0425   % To prevent the result calculated here from being canceled at the
0426   % end of the calculation:
0427     probe = get_param(currparent,'MaskHelp');
0428     if ~isempty(probe) && isa(probe,'char') && strcmp(probe,'probe'), keepThis = 1;
0429     else keepThis = 0;
0430     end
0431 
0432   % Appending the results:
0433     ltpda_annotation = find_system(bdroot,'FindAll','on','Type','Annotation','Tag','ltpda model');
0434     execHistory = get_param(ltpda_annotation,'UserData');
0435     if ~isempty(execHistory)
0436        member = 0;
0437        for i=1:size(execHistory,1)
0438           if execHistory{i,2}==subsyshandle, member = 1; index = i; break; end
0439        end
0440     end
0441     if ~isempty(execHistory) && member,
0442        x = execHistory{index,1};
0443        if x==-1, x = size(LTPDAinvar,1)+1; end
0444        LTPDAinvar(x,:) = {outdata,keepThis};
0445        block.OutputPort(1).Data = x;
0446        execHistory{index,1}     = x ;
0447        execHistory{index,2}     = subsyshandle ;
0448        for i=1:y , execHistory{index,2+i} = block.InputPort(1).Data(i); end
0449     else
0450        if isempty(execHistory), execHistory = {}; end
0451        x = size(LTPDAinvar,1);
0452        LTPDAinvar = [LTPDAinvar;{outdata,keepThis}];
0453        block.OutputPort(1).Data = x+1;
0454        execHistory{end+1,1}     = x+1 ;
0455        execHistory{end,2}       = subsyshandle ;
0456        for i=1:y , execHistory{end,2+i} = block.InputPort(1).Data(i); end
0457     end
0458 
0459   % Update the execution history:
0460     % Are stored the the output obj pointer, the handle of the current subsytem and the input obj pointers:
0461     set_param(ltpda_annotation,'UserData',execHistory);    
0462     
0463     
0464 catch
0465     disp('------------------============================================------------------')
0466     disp('------------------============================================------------------')
0467     disp('------------------============================================------------------')
0468     disp(sprintf('Something''s wrong in appending to the global variable LTPDAinvar the results of the %s function.',blocktag))
0469     disp(sprintf('The name of the currently executed block is %s.',get_param(currparent,'Name')))
0470     disp('The data to be saved, calculated into this block, are:')
0471     outdata %#ok<NOPRT>
0472     disp('------------------============================================------------------')
0473     disp('------------------============================================------------------')
0474     disp('------------------============================================------------------')
0475 end
0476 
0477 %==========================================================================
0478 %% Cycle to remove objects from memory as soon as they're no longer necessary:
0479 %==========================================================================
0480 
0481 if ~getappdata(0,'maintainresults');
0482    portConnectivity = get(subsyshandle,'PortConnectivity');
0483    for i = 1:numel(portConnectivity)
0484       notUsedAnymore = 1;
0485       if isempty(portConnectivity(i).DstBlock)
0486          parentBlock = portConnectivity(i).SrcBlock;
0487          childrenBlocks = utils.prog.findchildren(parentBlock);
0488          for j = 1:numel(childrenBlocks)
0489             if isempty(get_param(childrenBlocks(j),'MaskVariables')), notUsedAnymore = 0; end
0490          end
0491          if notUsedAnymore && LTPDAinvar{block.InputPort(1).Data(i),2}==0
0492             LTPDAinvar(block.InputPort(1).Data(i),:) = [];
0493             
0494           % Update the execution history:
0495             ltpda_annotation = find_system(bdroot,'FindAll','on','Type','Annotation','Tag','ltpda model');
0496             execHistory = get_param(ltpda_annotation,'UserData');
0497             for xx=1:size(execHistory,1)
0498                for yy=3:size(execHistory,2),
0499                   if execHistory{xx,yy} == block.InputPort(1).Data(i), execHistory{xx,yy} = -1; end
0500                   if execHistory{xx,yy} > block.InputPort(1).Data(i), execHistory{xx,yy} = execHistory{xx,yy}-1; end
0501                end
0502                if execHistory{xx,1} == block.InputPort(1).Data(i), execHistory{xx,1} = -1; end
0503                if execHistory{xx,1} > block.InputPort(1).Data(i), execHistory{xx,1} = execHistory{xx,1}-1; end
0504             end
0505             set_param(ltpda_annotation,'UserData',execHistory);
0506             
0507             disp('*** LTPDA object cleared from memory, being now unused')
0508          end
0509       end
0510    end
0511 end
0512 
0513 %==========================================================================
0514 
0515 
0516     % The output to Simulink is just the ordinal number (ONE AND ONLY ONE
0517     % NUMBER) of the object appended to the global array LTPDAinvar.
0518 
0519 % endfunction

Generated on Mon 08-Sep-2008 13:18:47 by m2html © 2003