% FROMDATAFILE Construct smodel object from filename AND parameter list%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% FUNCTION: fromDatafile%% DESCRIPTION: Construct smodel object from filename AND parameter list%% CALL: a = fromFilenameAndPlist(a, pli)%% PARAMETER: a: empty ltpda-model-object% pli: plist-object (must contain the filename)%% FORMAT: The text file must have the following format:%% - Blank lines are ignored% - Lines starting with a hash (#) are ignored% (* see description part% - The first continuous comment block will be put into the% description field% - The values for the model are defined with some keywords% - Use only one line for a value% - A colon after a keyword can be optionally inserted% - The following keywords (inside the quotes) are mandatory% and must be at the beginning of a line.% 'expr' - the expression of the model% 'params' - parameters which are used in the model% 'values' - default values for the parameters% 'xvar' - X-variable% - The following keywords are optional% 'xunits' - units of the x-axis% 'yunits' - units of the y-axis% 'xvals' - values for the X-variable% - It is possible to read more than one model from a file.% Use for this the indeces behind the keywords. For example% expr(1,2): ...% expr(3) ...% - It is necessary that each mandatory keyword have an entry% for each index. If a keyword have only one entry then will% be this enty copied to all other models.%% VERSION: $Id: fromDatafile.m,v 1.2 2011/08/15 13:12:17 hewitson Exp $%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%function mdl = fromDatafile(mdlin, pli) utils.helper.msg(utils.const.msg.PROC1, 'constructing from filename and/or plist'); VERSION = '$Id: fromDatafile.m,v 1.2 2011/08/15 13:12:17 hewitson Exp $'; % get ltpda-model info mi = smodel.getInfo('smodel', 'From ASCII File'); % Set the method version string in the minfo object mi.setMversion([VERSION '-->' mi.mversion]); % Get filename file_name = find(pli, 'filename'); [pathstr, f_name, ext] = fileparts(file_name); %%%%%%%%%% Get default parameter list %%%%%%%%%% dpl = smodel.getDefaultPlist('From ASCII File'); pl = applyDefaults(dpl, pli); pl = pset(pl, 'filename', [f_name ext]); pl = pset(pl, 'filepath', pathstr); dxunits = pl.find('xunits'); dyunits = pl.find('yunits'); dxvals = pl.find('xvals'); ddesc = pl.find('description'); %%%%%%%%%% read file %%%%%%%%%% [fid,msg] = fopen (file_name, 'r'); if (fid < 0) error ('### can not open file: %s \n### error msg: %s',file_name, msg); end firstCommentBlock = true; desc = ''; expr = {}; params = {}; xvar = {}; values = {}; xvals = {}; xunits = {}; yunits = {}; while ~feof(fid) fline = fgetl(fid); fline = strtrim(fline); if isempty(fline) firstCommentBlock = isFirstCommentBlock(desc); elseif fline(1) == '#' if firstCommentBlock && ~isempty(strtrim(fline(2:end))) desc = [desc, strtrim(fline(2:end)), '\n']; end elseif strcmpi(fline(1:4), 'expr') firstCommentBlock = isFirstCommentBlock(desc); [i,j,txt] = parseLine(fline, 'expr'); expr{i,j} = txt; elseif strcmpi(fline(1:6), 'params') firstCommentBlock = isFirstCommentBlock(desc); [i,j,txt] = parseLine(fline, 'params'); params{i,j} = txt; elseif strcmpi(fline(1:4), 'xvar') firstCommentBlock = isFirstCommentBlock(desc); [i,j,txt] = parseLine(fline, 'xvar'); xvar{i,j} = txt; elseif strcmpi(fline(1:6), 'values') firstCommentBlock = isFirstCommentBlock(desc); [i,j,txt] = parseLine(fline, 'values'); values{i,j} = txt; elseif strcmpi(fline(1:5), 'xvals') firstCommentBlock = isFirstCommentBlock(desc); [i,j,txt] = parseLine(fline, 'xvals'); xvals{i,j} = txt; elseif strcmpi(fline(1:6), 'xunits') firstCommentBlock = isFirstCommentBlock(desc); [i,j,txt] = parseLine(fline, 'xunits'); xunits{i,j} = txt; elseif strcmpi(fline(1:6), 'yunits') firstCommentBlock = isFirstCommentBlock(desc); [i,j,txt] = parseLine(fline, 'yunits'); yunits{i,j} = txt; end end fclose(fid); % Get maximum size of the smodel matrix maxi = max([size(expr,1), size(params,1), size(xvar,1), size(values,1), size(xvals,1), size(xunits,1), size(yunits,1)]); maxj = max([size(expr,2), size(params,2), size(xvar,2), size(values,2), size(xvals,2), size(xunits,2), size(yunits,2)]); % Make some plausibly checks % 1) Replicate the array to the maximum size of the used indices if the % array have only one input. % 2) The array must have the same size as the used indices. if isempty(xunits) xunits = {dxunits}; end if isempty(yunits) yunits = {dyunits}; end if isempty(xvals) xvals = {dxvals}; end if ~isempty(ddesc) desc = ddesc; end expr = checkArray(expr, maxi, maxj); params = checkArray(params, maxi, maxj); xvar = checkArray(xvar, maxi, maxj); values = checkArray(values, maxi, maxj); xvals = checkArray(xvals, maxi, maxj); xunits = checkArray(xunits, maxi, maxj); yunits = checkArray(yunits, maxi, maxj); mdl = smodel.newarray([maxi, maxj]); % Check mandatory fields if isempty(expr) || isempty(params) || isempty(xvar) || isempty(values) error('### At least one of the mandatory fields (''expr'', ''params'', ''xvar'', ''values'') is empty.'); end % Create Object for ii = 1:numel(mdl) % mandatory fields mdl(ii).expr = expr{ii}; mdl(ii).params = regexp(strtrim(params{ii}), ',', 'split'); mdl(ii).xvar = xvar{ii}; mdl(ii).values = cellfun(@str2num, regexp(strtrim(values{ii}), ',', 'split')); % Optional fields if ~isempty(xvals) if ischar(xvals{ii}) mdl(ii).xvals = eval(xvals{ii}); else mdl(ii).xvals = xvals{ii}; end end if ~isempty(xunits) mdl(ii).xunits = xunits{ii}; end if ~isempty(yunits) mdl(ii).yunits = yunits{ii}; end mdl(ii).description = desc(1:end-2); % remove the last break mdl(ii).addHistory(mi, pl, [], []); endend%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% Local Functions %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% FUNCTION: fromDatafile%% DESCRIPTION:%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%function flag = isFirstCommentBlock(desc) if isempty(desc) flag = true; else flag = false; endend%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% FUNCTION: getIndex%% DESCRIPTION: Returns the index of the input string.% '(3,2)' -> i=3, j=2% '(3)' -> i=3, default: j=1% '()' -> default i=1, default: j=1% '' -> default i=1, default: j=1%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%function [i,j] = getIndex(token) ij = regexp(token, '\d*', 'match'); if numel(ij) == 2 i = eval(ij{1}); j = eval(ij{2}); elseif numel(ij) == 1 i = eval(ij{1}); j = 1; else i = 1; j = 1; endend%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% FUNCTION: parseLine%% DESCRIPTION: Returns the indices i,j and the remaining value for the% given field.%% Example: expr: a+b*t -> i=1, j=1, txt=a+b*t% expr a+b*t -> i=1, j=1, txt=a+b*t% expr(3) a+b*t -> i=3, j=1, txt=a+b*t% expr(3,2): a+b*t -> i=3, j=2, txt=a+b*t%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%function [i,j,txt] = parseLine(lineIn, field) exp = [field '(?<idx>\(\d*(,\d*)?\))?:? *']; idx = regexp(lineIn, exp, 'end'); ij = regexp(lineIn, exp, 'names'); [i,j] = getIndex(ij(1).idx); txt = lineIn(idx+1:end);end%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% FUNCTION: checkArray%% DESCRIPTION: There are the following rules% 1) If the array have only one input then replicate this% input to the maximum size of the used indices.% 2) Throw an error if the inputs are more than one but not so% much as the maximum of the used indices.%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%function array = checkArray(array, maxi, maxj) if numel(array) == 0 % Do nothing elseif numel(array) == 1 array = repmat(array, maxi, maxj); elseif size(array,1) ~= maxi || size(array,2) ~= maxj error('### One model is not well defined. Max (i,j) = (%d,%d) but only used (%d,%d)', maxi, maxj, size(array,1), size(array,2)); endend