Home > RAVEN > checkModelStruct.m

checkModelStruct

PURPOSE ^

checkModelStruct

SYNOPSIS ^

function checkModelStruct(model,throwErrors,trimWarnings)

DESCRIPTION ^

 checkModelStruct
   Performs a number of checks to ensure that a model structure is ok

   model           a model structure
   throwErrors     true if the function should throw errors if
                   inconsistencies are found. The alternative is to
                   print warnings for all types of issues (opt, default true)
   trimWarnings    true if only a maximal of 10 items should be displayed in
                   a given error/warning (opt, default true)

   NOTE: This is performed after importing a model from Excel or before
   attempting to export a model to SBML format.

   Usage: checkModelStruct(model,throwErrors,trimWarnings)

   Rasmus Agren, 2013-11-03

CROSS-REFERENCE INFORMATION ^

This function calls: This function is called by:

SUBFUNCTIONS ^

SOURCE CODE ^

0001 function checkModelStruct(model,throwErrors,trimWarnings)
0002 % checkModelStruct
0003 %   Performs a number of checks to ensure that a model structure is ok
0004 %
0005 %   model           a model structure
0006 %   throwErrors     true if the function should throw errors if
0007 %                   inconsistencies are found. The alternative is to
0008 %                   print warnings for all types of issues (opt, default true)
0009 %   trimWarnings    true if only a maximal of 10 items should be displayed in
0010 %                   a given error/warning (opt, default true)
0011 %
0012 %   NOTE: This is performed after importing a model from Excel or before
0013 %   attempting to export a model to SBML format.
0014 %
0015 %   Usage: checkModelStruct(model,throwErrors,trimWarnings)
0016 %
0017 %   Rasmus Agren, 2013-11-03
0018 %
0019 
0020 if nargin<2
0021     throwErrors=true;
0022 end
0023 if nargin<3
0024     trimWarnings=true;
0025 end
0026 
0027 %Missing elements
0028 if ~isfield(model,'id')
0029     dispEM('The model is missing the "id" field',throwErrors);
0030 end
0031 if ~isfield(model,'description')
0032     dispEM('The model is missing the "description" field',throwErrors);
0033 end
0034 if ~isfield(model,'rxns')
0035     dispEM('The model is missing the "rxns" field',throwErrors);
0036 end
0037 if ~isfield(model,'mets')
0038     dispEM('The model is missing the "mets" field',throwErrors);
0039 end
0040 if ~isfield(model,'S')
0041     dispEM('The model is missing the "S" field',throwErrors);
0042 end
0043 if ~isfield(model,'lb')
0044     dispEM('The model is missing the "lb" field',throwErrors);
0045 end
0046 if ~isfield(model,'ub')
0047     dispEM('The model is missing the "ub" field',throwErrors);
0048 end
0049 if ~isfield(model,'rev')
0050     dispEM('The model is missing the "rev" field',throwErrors);
0051 end
0052 if ~isfield(model,'c')
0053     dispEM('The model is missing the "c" field',throwErrors);
0054 end
0055 if ~isfield(model,'b')
0056     dispEM('The model is missing the "b" field',throwErrors);
0057 end
0058 if ~isfield(model,'comps')
0059     dispEM('The model is missing the "comps" field',throwErrors);
0060 end
0061 if ~isfield(model,'metComps')
0062     dispEM('The model is missing the "metComps" field',throwErrors);
0063 end
0064 
0065 %Type check
0066 if ~ischar(model.id)
0067     dispEM('The "id" field must be a string',throwErrors);
0068 end
0069 if ~ischar(model.description)
0070     dispEM('The "description" field must be a string',throwErrors);
0071 end
0072 if ~iscellstr(model.rxns)
0073     dispEM('The "rxns" field must be a cell array of strings',throwErrors);
0074 end
0075 if ~iscellstr(model.mets)
0076     dispEM('The "mets" field must be a cell array of strings',throwErrors);
0077 end
0078 if ~isnumeric(model.S)
0079     dispEM('The "S" field must be of type "double"',throwErrors);
0080 end
0081 if ~isnumeric(model.lb)
0082     dispEM('The "lb" field must be of type "double"',throwErrors);
0083 end
0084 if ~isnumeric(model.ub)
0085     dispEM('The "ub" field must be of type "double"',throwErrors);
0086 end
0087 if ~isnumeric(model.rev)
0088     dispEM('The "rev" field must be of type "double"',throwErrors);
0089 end
0090 if ~isnumeric(model.c)
0091     dispEM('The "c" field must be of type "double"',throwErrors);
0092 end
0093 if ~isnumeric(model.b)
0094     dispEM('The "b" field must be of type "double"',throwErrors);
0095 end
0096 if ~iscellstr(model.comps)
0097     dispEM('The "comps" field must be a cell array of strings',throwErrors);
0098 end
0099 if ~isnumeric(model.metComps)
0100     dispEM('The "metComps" field must be of type "double"',throwErrors);
0101 end
0102 if isfield(model,'compNames')
0103     if ~iscellstr(model.compNames)
0104         dispEM('The "compNames" field must be a cell array of strings',throwErrors);
0105     end
0106 end
0107 if isfield(model,'compOutside')
0108     if ~iscellstr(model.compOutside)
0109         dispEM('The "compOutside" field must be a cell array of strings',throwErrors);
0110     end
0111 end
0112 if isfield(model,'rxnNames')
0113     if ~iscellstr(model.rxnNames)
0114         dispEM('The "rxnNames" field must be a cell array of strings',throwErrors);
0115     end
0116 end
0117 if isfield(model,'metNames')
0118     if ~iscellstr(model.metNames)
0119         dispEM('The "metNames" field must be a cell array of strings',throwErrors);
0120     end
0121 end
0122 if isfield(model,'genes')
0123     if ~iscellstr(model.genes)
0124         dispEM('The "genes" field must be a cell array of strings',throwErrors);
0125     end
0126 end
0127 if isfield(model,'rxnGeneMat')
0128     if ~isnumeric(model.rxnGeneMat)
0129         dispEM('The "rxnGeneMat" field must be of type "double"',throwErrors);
0130     end
0131 end
0132 if isfield(model,'grRules')
0133     if ~iscellstr(model.grRules)
0134         dispEM('The "grRules" field must be a cell array of strings',throwErrors);
0135     end
0136 end
0137 if isfield(model,'rxnComps')
0138     if ~isnumeric(model.rxnComps)
0139         dispEM('The "rxnComps" field must be of type "double"',throwErrors);
0140     end
0141 end
0142 if isfield(model,'inchis')
0143     if ~iscellstr(model.inchis)
0144         dispEM('The "inchis" field must be a cell array of strings',throwErrors);
0145     end
0146 end
0147 if isfield(model,'metFormulas')
0148     if ~iscellstr(model.metFormulas)
0149         dispEM('The "metFormulas" field must be a cell array of strings',throwErrors);
0150     end
0151 end
0152 if isfield(model,'subSystems')
0153     if ~iscellstr(model.subSystems)
0154         dispEM('The "subSystems" field must be a cell array of strings',throwErrors);
0155     end
0156 end
0157 if isfield(model,'eccodes')
0158     if ~iscellstr(model.eccodes)
0159         dispEM('The "eccodes" field must be a cell array of strings',throwErrors);
0160     end
0161 end
0162 if isfield(model,'unconstrained')
0163     if ~isnumeric(model.unconstrained)
0164         dispEM('The "unconstrained" field must be of type "double"',throwErrors);
0165     end
0166 end
0167 
0168 %Empty strings
0169 if isempty(model.id)
0170     dispEM('The "id" field cannot be empty',throwErrors);
0171 end
0172 if any(cellfun(@isempty,model.rxns))
0173     dispEM('The model contains empty reaction IDs',throwErrors);
0174 end
0175 if any(cellfun(@isempty,model.mets))
0176     dispEM('The model contains empty metabolite IDs',throwErrors);
0177 end
0178 if any(cellfun(@isempty,model.comps))
0179     dispEM('The model contains empty compartment IDs',throwErrors);
0180 end
0181 dispEM('The following metabolites have empty names:',throwErrors,model.mets(cellfun(@isempty,model.metNames)),trimWarnings);
0182 
0183 if isfield(model,'genes')
0184     if any(cellfun(@isempty,model.genes))
0185         dispEM('The model contains empty gene IDs',throwErrors);
0186     end
0187 end
0188 
0189 %Illegal characters in IDs
0190 dispEM('Illegal characters in reaction IDs:',throwErrors,model.rxns(illegal(model.rxns,'id')),trimWarnings);
0191 dispEM('Illegal characters in metabolite IDs:',throwErrors,model.mets(illegal(model.mets,'id')),trimWarnings);
0192 dispEM('Illegal characters in compartment IDs:',throwErrors,model.comps(illegal(model.comps,'id')),trimWarnings);
0193 
0194 %Duplicates
0195 dispEM('The following reaction IDs are duplicates:',throwErrors,model.rxns(duplicates(model.rxns)),trimWarnings);
0196 dispEM('The following metabolite IDs are duplicates:',throwErrors,model.mets(duplicates(model.mets)),trimWarnings);
0197 dispEM('The following compartment IDs are duplicates:',throwErrors,model.comps(duplicates(model.comps)),trimWarnings);
0198 if isfield(model,'genes')
0199     dispEM('The following genes are duplicates:',throwErrors,model.genes(duplicates(model.genes)),trimWarnings);
0200 end
0201 metInComp=strcat(model.metNames,'[',model.comps(model.metComps),']');
0202 dispEM('The following metabolites already exist in the same compartment:',throwErrors,metInComp(duplicates(metInComp)),trimWarnings);
0203     
0204 %Elements never used (print only as warnings
0205 dispEM('The following reactions are empty (no involved metabolites):',false,model.rxns(~any(model.S,1)),trimWarnings);
0206 dispEM('The following metabolites are never used in a reaction:',false,model.mets(~any(model.S,2)),trimWarnings);
0207 if isfield(model,'genes')
0208     dispEM('The following genes are not associated to a reaction:',false,model.genes(~any(model.rxnGeneMat,1)),trimWarnings);
0209 end
0210 I=true(numel(model.comps),1);
0211 I(model.metComps)=false;
0212 dispEM('The following compartments contain no metabolites:',false,model.comps(I),trimWarnings);
0213 
0214 %Contradicting bounds
0215 dispEM('The following reactions have contradicting bounds:',throwErrors,model.rxns(model.lb>model.ub),trimWarnings);
0216 dispEM('The following reactions have bounds contradicting their reversibility:',throwErrors,model.rxns(model.lb<0 & model.rev==0),trimWarnings);
0217 
0218 %Mapping of compartments
0219 if isfield(model,'compOutside')
0220     dispEM('The following compartments are in "compOutside" but not in "comps":',throwErrors,setdiff(model.compOutside,[{''};model.comps]),trimWarnings);
0221 end
0222 
0223 %Met names which start with number
0224 I=false(numel(model.metNames),1);
0225 for i=1:numel(model.metNames)
0226    index=strfind(model.metNames{i},' ');
0227    if any(index)
0228        if any(str2double(model.metNames{i}(1:index(1)-1)))
0229            I(i)=true;
0230        end
0231    end
0232 end
0233 dispEM('The following metabolite names begin with a number directly followed by space:',throwErrors,model.mets(I),trimWarnings);
0234 
0235 %Non-parseable composition
0236 if isfield(model,'metFormulas')
0237     [crap, crap, exitFlag]=parseFormulas(model.metFormulas,true,false);
0238      dispEM('The composition for the following metabolites could not be parsed:',false,model.mets(exitFlag==-1),trimWarnings);
0239 end
0240 
0241 %Check if there are metabolites with different names but the same MIRIAM
0242 %codes
0243 if isfield(model,'metMiriams')
0244     miriams=containers.Map();
0245     for i=1:numel(model.mets)
0246        if ~isempty(model.metMiriams{i})
0247           %Loop through and add for each miriam
0248           for j=1:numel(model.metMiriams{i}.name)
0249              %Get existing metabolite indexes
0250              current=strcat(model.metMiriams{i}.name{j},':',model.metMiriams{i}.value{j});
0251              if isKey(miriams,current)
0252                  existing=miriams(current);
0253              else
0254                  existing=[];
0255              end
0256              miriams(current)=[existing;i];
0257           end
0258        end
0259     end
0260     
0261     %Get all keys
0262     allMiriams=keys(miriams);
0263     
0264     hasMultiple=false(numel(allMiriams),1);
0265     for i=1:numel(allMiriams)
0266         if numel(miriams(allMiriams{i}))>1
0267            %Check if they all have the same name
0268            if numel(unique(model.metNames(miriams(allMiriams{i}))))>1
0269                hasMultiple(i)=true;
0270            end
0271         end
0272     end
0273     
0274     %Print output
0275     dispEM('The following MIRIAM strings are associated to more than one unique metabolite name:',false,allMiriams(hasMultiple));
0276 end
0277 
0278 %Check if there are metabolites with different names but the same InChI
0279 %codes
0280 if isfield(model,'inchis')
0281     inchis=containers.Map();
0282     for i=1:numel(model.mets)
0283        if ~isempty(model.inchis{i})
0284          %Get existing metabolite indexes
0285          if isKey(inchis,model.inchis{i})
0286              existing=inchis(model.inchis{i});
0287          else
0288              existing=[];
0289          end
0290          inchis(model.inchis{i})=[existing;i];
0291        end
0292     end
0293     
0294     %Get all keys
0295     allInchis=keys(inchis);
0296     
0297     hasMultiple=false(numel(allInchis),1);
0298     for i=1:numel(allInchis)
0299         if numel(inchis(allInchis{i}))>1
0300            %Check if they all have the same name
0301            if numel(unique(model.metNames(inchis(allInchis{i}))))>1
0302                hasMultiple(i)=true;
0303            end
0304         end
0305     end
0306     
0307     %Print output
0308     dispEM('The following InChI strings are associated to more than one unique metabolite name:',false,allInchis(hasMultiple));
0309 end
0310 end
0311 
0312 function I=duplicates(strings)
0313     I=false(numel(strings),1);
0314     [J K]=unique(strings);
0315     if numel(J)~=numel(strings)
0316         L=1:numel(strings);
0317         L(K)=[];
0318         I(L)=true;
0319     end
0320 end
0321 function I=illegal(strings,type)
0322     %Just to save some space
0323     if strcmpi(type,'id')
0324         %Checks which strings in a cell array contains illegal characters
0325         I=cellfun(@any,regexp(strings,'[^a-z_A-Z0-9-]', 'once'));
0326     else
0327 
0328     end
0329 end

Generated on Mon 06-Jan-2014 14:58:12 by m2html © 2005