From 5dcec1cddddee4757bdb517ec7a811a8f97aa74a Mon Sep 17 00:00:00 2001 From: Eduard Kerkhoven Date: Mon, 14 Oct 2024 17:48:42 +0200 Subject: [PATCH] refactor: identifier prefixes (#566) * refactor: default behaviour add/remove prefixes * fix: filenames * fix: update test result importExport --- core/checkModelStruct.m | 19 +- doc/core/checkModelStruct.html | 399 ++- doc/index.html | 6 +- doc/io/SBMLFromExcel.html | 4 +- doc/io/checkFileExistence.html | 2 +- doc/io/exportForGit.html | 4 +- doc/io/exportModel.html | 1542 ++++++----- doc/io/importModel.html | 2339 ++++++++--------- doc/io/sortIdentifiers.html | 2 +- .../addCOBRAstylePrefixes.html | 125 - .../addIdentifierPrefix.html | 128 + doc/struct_conversion/index.html | 2 +- .../removeCOBRAstylePrefixes.html | 133 - .../removeIdentifierPrefix.html | 143 + io/exportModel.m | 37 +- io/importModel.m | 48 +- struct_conversion/addCOBRAstylePrefixes.m | 58 - struct_conversion/addIdentifierPrefix.m | 60 + ...ylePrefixes.m => removeIdentifierPrefix.m} | 21 +- .../test_data/importExportResults.mat | Bin 1411 -> 1400 bytes 20 files changed, 2522 insertions(+), 2550 deletions(-) delete mode 100644 doc/struct_conversion/addCOBRAstylePrefixes.html create mode 100644 doc/struct_conversion/addIdentifierPrefix.html delete mode 100644 doc/struct_conversion/removeCOBRAstylePrefixes.html create mode 100644 doc/struct_conversion/removeIdentifierPrefix.html delete mode 100644 struct_conversion/addCOBRAstylePrefixes.m create mode 100644 struct_conversion/addIdentifierPrefix.m rename struct_conversion/{removeCOBRAstylePrefixes.m => removeIdentifierPrefix.m} (71%) diff --git a/core/checkModelStruct.m b/core/checkModelStruct.m index 21b1b461..139c43d8 100755 --- a/core/checkModelStruct.m +++ b/core/checkModelStruct.m @@ -250,22 +250,17 @@ function checkModelStruct(model,throwErrors,trimWarnings) fieldPrefix = {'R_';'M_';'C_';'G_'}; for i=1:numel(fields) try - numIDs = startsWith(model.(fields{i}),digitsPattern(1)); + numIDs = ~startsWith(model.(fields{i}),regexpPattern('^[a-zA-Z_]')); catch numIDs = []; end if any(numIDs) - EM = ['The following ' fieldNames{i} ' identifiers start with a ' ... - 'digit, which does not comply with SBML specifications. This ' ... - 'does not impact RAVEN functionality, but before exporting ' ... - 'the model to SBML you should either (a) correct these ' ... - 'identifiers directly; or (b) run "model = addCOBRAstylePrefixes ' ... - '(model,''' fields{i} ''');" to have COBRA style "' fieldPrefix{i} ... - '" prefixes added to all ' fieldNames{i} ' identifiers; or (c) ' ... - 'let exportModel add COBRA style prefixes to all identifiers ' ... - 'in the model by setting COBRAstyle as true. Example: ' ... - '"exportModel(model, ''filename.xml'', true);"']; - dispEM(EM,throwErrors,{model.(fields{i}){numIDs}},trimWarnings); + EM = ['The following ' fieldNames{i} ' identifiers do not start '... + 'with a letter or _ (conflicting with SBML specifications). '... + 'This does not impact RAVEN functionality, but be aware that '... + 'exportModel will automatically add ' fieldPrefix{i} ... + ' prefixes to all ' fieldNames{i} ' identifiers:']; + dispEM(EM,false,{model.(fields{i}){numIDs}},trimWarnings); end end diff --git a/doc/core/checkModelStruct.html b/doc/core/checkModelStruct.html index 2a39d781..288a1ff0 100644 --- a/doc/core/checkModelStruct.html +++ b/doc/core/checkModelStruct.html @@ -309,212 +309,207 @@

SOURCE CODE ^'R_';'M_';'C_';'G_'}; 0251 for i=1:numel(fields) 0252 try -0253 numIDs = startsWith(model.(fields{i}),digitsPattern(1)); +0253 numIDs = ~startsWith(model.(fields{i}),regexpPattern('^[a-zA-Z_]')); 0254 catch 0255 numIDs = []; 0256 end 0257 if any(numIDs) -0258 EM = ['The following ' fieldNames{i} ' identifiers start with a ' ... -0259 'digit, which does not comply with SBML specifications. This ' ... -0260 'does not impact RAVEN functionality, but before exporting ' ... -0261 'the model to SBML you should either (a) correct these ' ... -0262 'identifiers directly; or (b) run "model = addCOBRAstylePrefixes ' ... -0263 '(model,''' fields{i} ''');" to have COBRA style "' fieldPrefix{i} ... -0264 '" prefixes added to all ' fieldNames{i} ' identifiers; or (c) ' ... -0265 'let exportModel add COBRA style prefixes to all identifiers ' ... -0266 'in the model by setting COBRAstyle as true. Example: ' ... -0267 '"exportModel(model, ''filename.xml'', true);"']; -0268 dispEM(EM,throwErrors,{model.(fields{i}){numIDs}},trimWarnings); -0269 end -0270 end -0271 -0272 %Duplicates -0273 EM='The following reaction IDs are duplicates:'; -0274 dispEM(EM,throwErrors,model.rxns(duplicates(model.rxns)),trimWarnings); -0275 EM='The following metabolite IDs are duplicates:'; -0276 dispEM(EM,throwErrors,model.mets(duplicates(model.mets)),trimWarnings); -0277 EM='The following compartment IDs are duplicates:'; -0278 dispEM(EM,throwErrors,model.comps(duplicates(model.comps)),trimWarnings); -0279 if isfield(model,'genes') -0280 EM='The following genes are duplicates:'; -0281 dispEM(EM,throwErrors,model.genes(duplicates(model.genes)),trimWarnings); -0282 end -0283 metInComp=strcat(model.metNames,'[',model.comps(model.metComps),']'); -0284 EM='The following metabolites already exist in the same compartment:'; -0285 dispEM(EM,throwErrors,metInComp(duplicates(metInComp)),trimWarnings); -0286 -0287 %Elements never used (print only as warnings -0288 EM='The following reactions are empty (no involved metabolites):'; -0289 dispEM(EM,false,model.rxns(~any(model.S,1)),trimWarnings); -0290 EM='The following metabolites are never used in a reaction:'; -0291 dispEM(EM,false,model.mets(~any(model.S,2)),trimWarnings); -0292 if isfield(model,'genes') -0293 EM='The following genes are not associated to a reaction:'; -0294 dispEM(EM,false,model.genes(~any(model.rxnGeneMat,1)),trimWarnings); -0295 end -0296 I=true(numel(model.comps),1); -0297 I(model.metComps)=false; -0298 EM='The following compartments contain no metabolites:'; -0299 dispEM(EM,false,model.comps(I),trimWarnings); -0300 -0301 %Contradicting bounds -0302 EM='The following reactions have contradicting bounds (lower bound is higher than upper bound):'; -0303 dispEM(EM,throwErrors,model.rxns(model.lb>model.ub),trimWarnings); -0304 EM='The following reactions have lower and upper bounds that indicate reversibility, but are indicated as irreversible in model.rev:'; -0305 dispEM(EM,false,model.rxns(model.lb < 0 & model.ub > 0 & model.rev==0),trimWarnings); -0306 -0307 %Multiple or no objective functions not allowed in SBML L3V1 FBCv2 -0308 if numel(find(model.c))>1 -0309 EM='Multiple objective functions found. This might be intended, but results in FBCv2 non-compliant SBML file when exported'; -0310 dispEM(EM,false,model.rxns(find(model.c)),trimWarnings); -0311 elseif ~any(model.c) -0312 EM='No objective function found. This might be intended, but results in FBCv2 non-compliant SBML file when exported'; -0313 dispEM(EM,false); -0314 end -0315 -0316 %Mapping of compartments -0317 if isfield(model,'compOutside') -0318 EM='The following compartments are in "compOutside" but not in "comps":'; -0319 dispEM(EM,throwErrors,setdiff(model.compOutside,[{''};model.comps]),trimWarnings); -0320 end -0321 -0322 %Met names which start with number -0323 I=false(numel(model.metNames),1); -0324 for i=1:numel(model.metNames) -0325 index=strfind(model.metNames{i},' '); -0326 if any(index) -0327 if any(str2double(model.metNames{i}(1:index(1)-1))) -0328 I(i)=true; -0329 end -0330 end -0331 end -0332 EM='The following metabolite names begin with a number directly followed by space, which could potentially cause problems:'; -0333 dispEM(EM,false,model.metNames(I),trimWarnings); -0334 -0335 %Non-parseable composition -0336 if isfield(model,'metFormulas') -0337 [~, ~, exitFlag]=parseFormulas(model.metFormulas,true,false); -0338 EM='The composition for the following metabolites could not be parsed:'; -0339 dispEM(EM,false,model.mets(exitFlag==-1),trimWarnings); -0340 end -0341 -0342 %Check if there are metabolites with different names but the same MIRIAM -0343 %codes -0344 if isfield(model,'metMiriams') -0345 miriams=containers.Map(); -0346 for i=1:numel(model.mets) -0347 if ~isempty(model.metMiriams{i}) -0348 %Loop through and add for each miriam -0349 for j=1:numel(model.metMiriams{i}.name) -0350 %Get existing metabolite indexes -0351 current=strcat(model.metMiriams{i}.name{j},'/',model.metMiriams{i}.value{j}); -0352 if isKey(miriams,current) -0353 existing=miriams(current); -0354 else -0355 existing=[]; -0356 end -0357 miriams(current)=[existing;i]; -0358 end -0359 end -0360 end -0361 -0362 %Get all keys -0363 allMiriams=keys(miriams); -0364 -0365 hasMultiple=false(numel(allMiriams),1); -0366 for i=1:numel(allMiriams) -0367 if numel(miriams(allMiriams{i}))>1 -0368 %Check if they all have the same name -0369 if numel(unique(model.metNames(miriams(allMiriams{i}))))>1 -0370 if ~regexp(allMiriams{i},'^sbo\/SBO:') % SBO terms are expected to be multiple -0371 hasMultiple(i)=true; -0372 end -0373 end -0374 end -0375 end -0376 -0377 %Print output -0378 EM='The following MIRIAM strings are associated to more than one unique metabolite name:'; -0379 dispEM(EM,false,allMiriams(hasMultiple),trimWarnings); -0380 end -0381 -0382 %Check if there are metabolites with different names but the same InChI -0383 %codes -0384 if isfield(model,'inchis') -0385 inchis=containers.Map(); -0386 for i=1:numel(model.mets) -0387 if ~isempty(model.inchis{i}) -0388 %Get existing metabolite indexes -0389 if isKey(inchis,model.inchis{i}) -0390 existing=inchis(model.inchis{i}); -0391 else -0392 existing=[]; -0393 end -0394 inchis(model.inchis{i})=[existing;i]; -0395 end -0396 end -0397 -0398 %Get all keys -0399 allInchis=keys(inchis); -0400 -0401 hasMultiple=false(numel(allInchis),1); -0402 for i=1:numel(allInchis) -0403 if numel(inchis(allInchis{i}))>1 -0404 %Check if they all have the same name -0405 if numel(unique(model.metNames(inchis(allInchis{i}))))>1 -0406 hasMultiple(i)=true; -0407 end -0408 end -0409 end -0410 -0411 %Print output -0412 EM='The following InChI strings are associated to more than one unique metabolite name:'; -0413 dispEM(EM,false,allInchis(hasMultiple),trimWarnings); -0414 end -0415 -0416 % %Check if there are metabolites with different names but the same SMILES -0417 % if isfield(model,'metSmiles') -0418 % metSmiles=containers.Map(); -0419 % for i=1:numel(model.mets) -0420 % if ~isempty(model.metSmiles{i}) -0421 % %Get existing metabolite indexes -0422 % if isKey(metSmiles,model.metSmiles{i}) -0423 % existing=metSmiles(model.metSmiles{i}); -0424 % else -0425 % existing=[]; -0426 % end -0427 % metSmiles(model.metSmiles{i})=[existing;i]; -0428 % end -0429 % end -0430 % -0431 % %Get all keys -0432 % allmetSmiles=keys(metSmiles); -0433 % -0434 % hasMultiple=false(numel(metSmiles),1); -0435 % for i=1:numel(metSmiles) -0436 % if numel(metSmiles(metSmiles{i}))>1 -0437 % %Check if they all have the same name -0438 % if numel(unique(model.metNames(metSmiles(allmetSmiles{i}))))>1 -0439 % hasMultiple(i)=true; -0440 % end -0441 % end -0442 % end -0443 % -0444 % %Print output -0445 % EM='The following metSmiles strings are associated to more than one unique metabolite name:'; -0446 % dispEM(EM,false,allmetSmiles(hasMultiple),trimWarnings); -0447 % end -0448 end -0449 -0450 function I=duplicates(strings) -0451 I=false(numel(strings),1); -0452 [J, K]=unique(strings); -0453 if numel(J)~=numel(strings) -0454 L=1:numel(strings); -0455 L(K)=[]; -0456 I(L)=true; -0457 end -0458 end +0258 EM = ['The following ' fieldNames{i} ' identifiers do not start '... +0259 'with a letter or _ (conflicting with SBML specifications). '... +0260 'This does not impact RAVEN functionality, but be aware that '... +0261 'exportModel will automatically add ' fieldPrefix{i} ... +0262 ' prefixes to all ' fieldNames{i} ' identifiers:']; +0263 dispEM(EM,false,{model.(fields{i}){numIDs}},trimWarnings); +0264 end +0265 end +0266 +0267 %Duplicates +0268 EM='The following reaction IDs are duplicates:'; +0269 dispEM(EM,throwErrors,model.rxns(duplicates(model.rxns)),trimWarnings); +0270 EM='The following metabolite IDs are duplicates:'; +0271 dispEM(EM,throwErrors,model.mets(duplicates(model.mets)),trimWarnings); +0272 EM='The following compartment IDs are duplicates:'; +0273 dispEM(EM,throwErrors,model.comps(duplicates(model.comps)),trimWarnings); +0274 if isfield(model,'genes') +0275 EM='The following genes are duplicates:'; +0276 dispEM(EM,throwErrors,model.genes(duplicates(model.genes)),trimWarnings); +0277 end +0278 metInComp=strcat(model.metNames,'[',model.comps(model.metComps),']'); +0279 EM='The following metabolites already exist in the same compartment:'; +0280 dispEM(EM,throwErrors,metInComp(duplicates(metInComp)),trimWarnings); +0281 +0282 %Elements never used (print only as warnings +0283 EM='The following reactions are empty (no involved metabolites):'; +0284 dispEM(EM,false,model.rxns(~any(model.S,1)),trimWarnings); +0285 EM='The following metabolites are never used in a reaction:'; +0286 dispEM(EM,false,model.mets(~any(model.S,2)),trimWarnings); +0287 if isfield(model,'genes') +0288 EM='The following genes are not associated to a reaction:'; +0289 dispEM(EM,false,model.genes(~any(model.rxnGeneMat,1)),trimWarnings); +0290 end +0291 I=true(numel(model.comps),1); +0292 I(model.metComps)=false; +0293 EM='The following compartments contain no metabolites:'; +0294 dispEM(EM,false,model.comps(I),trimWarnings); +0295 +0296 %Contradicting bounds +0297 EM='The following reactions have contradicting bounds (lower bound is higher than upper bound):'; +0298 dispEM(EM,throwErrors,model.rxns(model.lb>model.ub),trimWarnings); +0299 EM='The following reactions have lower and upper bounds that indicate reversibility, but are indicated as irreversible in model.rev:'; +0300 dispEM(EM,false,model.rxns(model.lb < 0 & model.ub > 0 & model.rev==0),trimWarnings); +0301 +0302 %Multiple or no objective functions not allowed in SBML L3V1 FBCv2 +0303 if numel(find(model.c))>1 +0304 EM='Multiple objective functions found. This might be intended, but results in FBCv2 non-compliant SBML file when exported'; +0305 dispEM(EM,false,model.rxns(find(model.c)),trimWarnings); +0306 elseif ~any(model.c) +0307 EM='No objective function found. This might be intended, but results in FBCv2 non-compliant SBML file when exported'; +0308 dispEM(EM,false); +0309 end +0310 +0311 %Mapping of compartments +0312 if isfield(model,'compOutside') +0313 EM='The following compartments are in "compOutside" but not in "comps":'; +0314 dispEM(EM,throwErrors,setdiff(model.compOutside,[{''};model.comps]),trimWarnings); +0315 end +0316 +0317 %Met names which start with number +0318 I=false(numel(model.metNames),1); +0319 for i=1:numel(model.metNames) +0320 index=strfind(model.metNames{i},' '); +0321 if any(index) +0322 if any(str2double(model.metNames{i}(1:index(1)-1))) +0323 I(i)=true; +0324 end +0325 end +0326 end +0327 EM='The following metabolite names begin with a number directly followed by space, which could potentially cause problems:'; +0328 dispEM(EM,false,model.metNames(I),trimWarnings); +0329 +0330 %Non-parseable composition +0331 if isfield(model,'metFormulas') +0332 [~, ~, exitFlag]=parseFormulas(model.metFormulas,true,false); +0333 EM='The composition for the following metabolites could not be parsed:'; +0334 dispEM(EM,false,model.mets(exitFlag==-1),trimWarnings); +0335 end +0336 +0337 %Check if there are metabolites with different names but the same MIRIAM +0338 %codes +0339 if isfield(model,'metMiriams') +0340 miriams=containers.Map(); +0341 for i=1:numel(model.mets) +0342 if ~isempty(model.metMiriams{i}) +0343 %Loop through and add for each miriam +0344 for j=1:numel(model.metMiriams{i}.name) +0345 %Get existing metabolite indexes +0346 current=strcat(model.metMiriams{i}.name{j},'/',model.metMiriams{i}.value{j}); +0347 if isKey(miriams,current) +0348 existing=miriams(current); +0349 else +0350 existing=[]; +0351 end +0352 miriams(current)=[existing;i]; +0353 end +0354 end +0355 end +0356 +0357 %Get all keys +0358 allMiriams=keys(miriams); +0359 +0360 hasMultiple=false(numel(allMiriams),1); +0361 for i=1:numel(allMiriams) +0362 if numel(miriams(allMiriams{i}))>1 +0363 %Check if they all have the same name +0364 if numel(unique(model.metNames(miriams(allMiriams{i}))))>1 +0365 if ~regexp(allMiriams{i},'^sbo\/SBO:') % SBO terms are expected to be multiple +0366 hasMultiple(i)=true; +0367 end +0368 end +0369 end +0370 end +0371 +0372 %Print output +0373 EM='The following MIRIAM strings are associated to more than one unique metabolite name:'; +0374 dispEM(EM,false,allMiriams(hasMultiple),trimWarnings); +0375 end +0376 +0377 %Check if there are metabolites with different names but the same InChI +0378 %codes +0379 if isfield(model,'inchis') +0380 inchis=containers.Map(); +0381 for i=1:numel(model.mets) +0382 if ~isempty(model.inchis{i}) +0383 %Get existing metabolite indexes +0384 if isKey(inchis,model.inchis{i}) +0385 existing=inchis(model.inchis{i}); +0386 else +0387 existing=[]; +0388 end +0389 inchis(model.inchis{i})=[existing;i]; +0390 end +0391 end +0392 +0393 %Get all keys +0394 allInchis=keys(inchis); +0395 +0396 hasMultiple=false(numel(allInchis),1); +0397 for i=1:numel(allInchis) +0398 if numel(inchis(allInchis{i}))>1 +0399 %Check if they all have the same name +0400 if numel(unique(model.metNames(inchis(allInchis{i}))))>1 +0401 hasMultiple(i)=true; +0402 end +0403 end +0404 end +0405 +0406 %Print output +0407 EM='The following InChI strings are associated to more than one unique metabolite name:'; +0408 dispEM(EM,false,allInchis(hasMultiple),trimWarnings); +0409 end +0410 +0411 % %Check if there are metabolites with different names but the same SMILES +0412 % if isfield(model,'metSmiles') +0413 % metSmiles=containers.Map(); +0414 % for i=1:numel(model.mets) +0415 % if ~isempty(model.metSmiles{i}) +0416 % %Get existing metabolite indexes +0417 % if isKey(metSmiles,model.metSmiles{i}) +0418 % existing=metSmiles(model.metSmiles{i}); +0419 % else +0420 % existing=[]; +0421 % end +0422 % metSmiles(model.metSmiles{i})=[existing;i]; +0423 % end +0424 % end +0425 % +0426 % %Get all keys +0427 % allmetSmiles=keys(metSmiles); +0428 % +0429 % hasMultiple=false(numel(metSmiles),1); +0430 % for i=1:numel(metSmiles) +0431 % if numel(metSmiles(metSmiles{i}))>1 +0432 % %Check if they all have the same name +0433 % if numel(unique(model.metNames(metSmiles(allmetSmiles{i}))))>1 +0434 % hasMultiple(i)=true; +0435 % end +0436 % end +0437 % end +0438 % +0439 % %Print output +0440 % EM='The following metSmiles strings are associated to more than one unique metabolite name:'; +0441 % dispEM(EM,false,allmetSmiles(hasMultiple),trimWarnings); +0442 % end +0443 end +0444 +0445 function I=duplicates(strings) +0446 I=false(numel(strings),1); +0447 [J, K]=unique(strings); +0448 if numel(J)~=numel(strings) +0449 L=1:numel(strings); +0450 L(K)=[]; +0451 I(L)=true; +0452 end +0453 end
Generated by m2html © 2005
\ No newline at end of file diff --git a/doc/index.html b/doc/index.html index dc5ea880..25c6ef92 100644 --- a/doc/index.html +++ b/doc/index.html @@ -23,9 +23,9 @@

Matlab Files found in these Directories

INITStepDesc expandModel getObjectiveString randomSampling ManualINITTests exportForGit getPathwayDimensions ravenCobraWrapper SBMLFromExcel exportModel getPhylDist readYAMLmodel - addCOBRAstylePrefixes exportModelToSIF getRxnsFromKEGG removeBadRxns - addExchangeRxns exportToExcelFormat getRxnsFromMetaCyc removeCOBRAstylePrefixes - addGenesRaven exportToTabDelimited getRxnsInComp removeGenes + addExchangeRxns exportModelToSIF getRxnsFromKEGG removeBadRxns + addGenesRaven exportToExcelFormat getRxnsFromMetaCyc removeGenes + addIdentifierPrefix exportToTabDelimited getRxnsInComp removeIdentifierPrefix addJavaPaths extractMiriam getToolboxVersion removeLowScoreGenes addMets fillGaps getTransportRxns removeMets addRavenToUserPath fillGapsLargeTests getWSLpath removeRavenFromPath diff --git a/doc/io/SBMLFromExcel.html b/doc/io/SBMLFromExcel.html index d54c5188..4565e925 100644 --- a/doc/io/SBMLFromExcel.html +++ b/doc/io/SBMLFromExcel.html @@ -49,7 +49,7 @@

DESCRIPTION ^CROSS-REFERENCE INFORMATION ^

This function calls: +
  • exportModel exportModel
  • importExcelModel importExcelModel
  • This function is called by: @@ -87,7 +87,7 @@

    SOURCE CODE ^importExcelModel(fileName,false,printWarnings); 0029 printModelStats(model,printWarnings,false); -0030 exportModel(model,outputFileName,toCOBRA,true); +0030 exportModel(model,outputFileName,toCOBRA,true); 0031 end
    Generated by m2html © 2005
    diff --git a/doc/io/checkFileExistence.html b/doc/io/checkFileExistence.html index bc22e113..d17fbfcd 100644 --- a/doc/io/checkFileExistence.html +++ b/doc/io/checkFileExistence.html @@ -61,7 +61,7 @@

    CROSS-REFERENCE INFORMATION ^
 </ul>
 This function is called by:
 <ul style= -
  • exportModel exportModel
  • getMD5Hash getMD5Hash
  • importModel importModel
  • +
  • exportModel exportModel
  • getMD5Hash getMD5Hash
  • importModel importModel
  • diff --git a/doc/io/exportForGit.html b/doc/io/exportForGit.html index ecb194ad..74a90f62 100644 --- a/doc/io/exportForGit.html +++ b/doc/io/exportForGit.html @@ -69,7 +69,7 @@

    DESCRIPTION ^CROSS-REFERENCE INFORMATION ^

    This function calls: +
  • exportModel exportModel
  • exportToExcelFormat exportToExcelFormat
  • getToolboxVersion getToolboxVersion
  • sortIdentifiers exportModel
  • writeYAMLmodel writeYAMLmodel
  • This function is called by: @@ -222,7 +222,7 @@

    SOURCE CODE ^% Write XML format 0144 if ismember('xml', formats) -0145 exportModel(model,fullfile(filePath{5},strcat(prefix,'.xml')),COBRAstyle); +0145 exportModel(model,fullfile(filePath{5},strcat(prefix,'.xml')),COBRAstyle); 0146 end 0147 0148 %Save file with versions: diff --git a/doc/io/exportModel.html b/doc/io/exportModel.html index ff9eea03..34b6f359 100644 --- a/doc/io/exportModel.html +++ b/doc/io/exportModel.html @@ -24,7 +24,7 @@

    PURPOSE ^exportModel

    SYNOPSIS ^

    -
    function exportModel(model,fileName,COBRAstyle,supressWarnings,sortIds)
    +
    function exportModel(model,fileName,neverPrefix,supressWarnings,sortIds)

    DESCRIPTION ^

     exportModel
    @@ -34,12 +34,9 @@ 

    DESCRIPTION ^DESCRIPTION ^CROSS-REFERENCE INFORMATION ^

    This function calls: +
  • checkFileExistence checkFileExistence
  • exportModel exportModel
  • sortIdentifiers exportModel
  • This function is called by: +
  • SBMLFromExcel SBMLFromExcel
  • exportForGit exportForGit
  • exportModel exportModel
  • SUBFUNCTIONS ^

    @@ -64,7 +61,7 @@

    SUBFUNCTIONS ^function modelSBML=getSBMLStructure(sbmlLevel,sbmlVersion,sbmlPackages,sbmlPackageVersions)
  • function miriamString=getMiriam(miriamStruct)
  • function [tmp_Rxn]=addReactantsProducts(model,sbmlModel,i)
  • function vecT = columnVector(vec)
  • SOURCE CODE ^

    -
    0001 function exportModel(model,fileName,COBRAstyle,supressWarnings,sortIds)
    +
    0001 function exportModel(model,fileName,neverPrefix,supressWarnings,sortIds)
     0002 % exportModel
     0003 %   Exports a constraint-based model to an SBML file (L3V1 FBCv2)
     0004 %
    @@ -72,793 +69,788 @@ 

    SOURCE CODE ^% model a model structure 0007 % fileName filename to export the model to. A dialog window 0008 % will open if no file name is specified. -0009 % COBRAstyle true if COBRA-style prefixes should be added to all -0010 % identifiers: R_ for reactions, M_ for metabolites, -0011 % G_ for genes and C_ for compartments. If all -0012 % identifiers of a particular field already have the -0013 % prefix, then no additional prefixes are added. -0014 % (optional, default false) -0015 % supressWarnings true if warnings should be supressed. This might -0016 % results in invalid SBML files, as no checks are -0017 % performed (optional, default false) -0018 % sortIds logical whether metabolites, reactions and genes -0019 % should be sorted alphabetically by their -0020 % identifiers (optional, default false) -0021 % -0022 % Usage: exportModel(model,fileName,COBRAstyle,supressWarnings,sortIds) -0023 -0024 if nargin<2 || isempty(fileName) -0025 [fileName, pathName] = uiputfile({'*.xml;*.sbml'}, 'Select file for model export',[model.id '.xml']); -0026 if fileName == 0 -0027 error('You should provide a file location') -0028 else -0029 fileName = fullfile(pathName,fileName); -0030 end -0031 end -0032 fileName=char(fileName); -0033 if nargin<3 -0034 COBRAstyle=false; -0035 elseif ~islogical(COBRAstyle) -0036 error("COBRAstyle should be either true or false") -0037 end -0038 if nargin<4 -0039 supressWarnings=false; -0040 end -0041 if nargin<5 -0042 sortIds=false; -0043 end -0044 if sortIds==true -0045 model=sortIdentifiers(model); -0046 end -0047 -0048 if isfield(model,'ec') -0049 warning("exportModel does not store information from the 'model.ec' structure. Use 'writeYAMLmodel(model)' to export all content from a GECKO model.") -0050 end -0051 -0052 %If no subSystems are defined, then no need to use groups package -0053 if isfield(model,'subSystems') -0054 modelHasSubsystems=true; -0055 else -0056 modelHasSubsystems=false; -0057 end -0058 -0059 %The default SBML format settings, which are used as input for appropriate -0060 %libSBML functions to generate the blank SBML model structure before using -0061 %exporting in with OutputSBML to xml file -0062 sbmlLevel=3; -0063 sbmlVersion=1; -0064 sbmlPackages={'fbc'}; -0065 sbmlPackageVersions=2; -0066 if modelHasSubsystems -0067 sbmlPackages={sbmlPackages,'groups'}; -0068 sbmlPackageVersions=[sbmlPackageVersions,1]; -0069 end -0070 -0071 %Check if the "unconstrained" field is still present. This shows if -0072 %exchange metabolites have been removed -0073 if ~isfield(model,'unconstrained') -0074 model.unconstrained=zeros(numel(model.mets),1); -0075 end -0076 -0077 %If model id and name do not exist, make sure that default -0078 %strings are included -0079 if ~isfield(model,'id') -0080 fprintf('WARNING: The model is missing the "id" field. Uses "blankID". \n'); -0081 model.id='blankID'; -0082 end -0083 if ~isfield(model,'name') -0084 fprintf('WARNING: The model is missing the "name" field. Uses "blankName". \n'); -0085 model.name='blankName'; -0086 end -0087 -0088 % Add prefixes if desired -0089 if COBRAstyle -0090 if isfield(model,'ec') -0091 error('ecModels cannot be exported with COBRAstyle flag, manually correct any non-compliant identifiers if needed.') -0092 end -0093 model = addCOBRAstylePrefixes(model,[],false); +0009 % neverPrefix true if prefixes are never added to identifiers, +0010 % even if start with e.g. digits. This might result +0011 % in invalid SBML files (optional, default false) +0012 % supressWarnings true if warnings should be supressed. This might +0013 % results in invalid SBML files, as no checks are +0014 % performed (optional, default false) +0015 % sortIds logical whether metabolites, reactions and genes +0016 % should be sorted alphabetically by their +0017 % identifiers (optional, default false) +0018 % +0019 % Usage: exportModel(model,fileName,neverPrefix,supressWarnings,sortIds) +0020 +0021 if nargin<2 || isempty(fileName) +0022 [fileName, pathName] = uiputfile({'*.xml;*.sbml'}, 'Select file for model export',[model.id '.xml']); +0023 if fileName == 0 +0024 error('You should provide a file location') +0025 else +0026 fileName = fullfile(pathName,fileName); +0027 end +0028 end +0029 fileName=char(fileName); +0030 if nargin<3 || isempty(neverPrefix) +0031 neverPrefix=false; +0032 end +0033 if nargin<4 || isempty(supressWarnings) +0034 supressWarnings=false; +0035 end +0036 if nargin<5 || isempty(sortIds) +0037 sortIds=false; +0038 end +0039 if sortIds==true +0040 model=sortIdentifiers(model); +0041 end +0042 +0043 if isfield(model,'ec') +0044 warning("exportModel does not store information from the 'model.ec' structure. Use 'writeYAMLmodel(model)' to export all content from a GECKO model.") +0045 end +0046 +0047 %If no subSystems are defined, then no need to use groups package +0048 if isfield(model,'subSystems') +0049 modelHasSubsystems=true; +0050 else +0051 modelHasSubsystems=false; +0052 end +0053 +0054 %The default SBML format settings, which are used as input for appropriate +0055 %libSBML functions to generate the blank SBML model structure before using +0056 %exporting in with OutputSBML to xml file +0057 sbmlLevel=3; +0058 sbmlVersion=1; +0059 sbmlPackages={'fbc'}; +0060 sbmlPackageVersions=2; +0061 if modelHasSubsystems +0062 sbmlPackages={sbmlPackages,'groups'}; +0063 sbmlPackageVersions=[sbmlPackageVersions,1]; +0064 end +0065 +0066 %Check if the "unconstrained" field is still present. This shows if +0067 %exchange metabolites have been removed +0068 if ~isfield(model,'unconstrained') +0069 model.unconstrained=zeros(numel(model.mets),1); +0070 end +0071 +0072 %If model id and name do not exist, make sure that default +0073 %strings are included +0074 if ~isfield(model,'id') +0075 fprintf('WARNING: The model is missing the "id" field. Uses "blankID". \n'); +0076 model.id='blankID'; +0077 end +0078 if ~isfield(model,'name') +0079 fprintf('WARNING: The model is missing the "name" field. Uses "blankName". \n'); +0080 model.name='blankName'; +0081 end +0082 +0083 % Add prefixes if required +0084 if ~neverPrefix +0085 [model,hasChanged] = addIdentifierPrefix(model); +0086 dispEM(['The following fields have one or more entries that do not start '... +0087 'with a letter or _ (conflicting with SBML specifications). Prefixes '... +0088 'are added to all entries in those fields:'],false,hasChanged) +0089 end +0090 +0091 %Check the model structure +0092 if supressWarnings==false +0093 checkModelStruct(model); 0094 end 0095 -0096 %Check the model structure -0097 if supressWarnings==false -0098 checkModelStruct(model,false); -0099 end -0100 -0101 %Add several blank fields, if they do not exist already. This is to reduce -0102 %the number of conditions below -0103 if ~isfield(model,'compMiriams') -0104 model.compMiriams=cell(numel(model.comps),1); -0105 end -0106 if ~isfield(model,'inchis') -0107 model.inchis=cell(numel(model.mets),1); -0108 end -0109 if ~isfield(model,'metFormulas') -0110 model.metFormulas=cell(numel(model.mets),1); -0111 end -0112 if ~isfield(model,'metMiriams') -0113 model.metMiriams=cell(numel(model.mets),1); -0114 end -0115 if ~isfield(model,'geneMiriams') && isfield(model,'genes') -0116 model.geneMiriams=cell(numel(model.genes),1); -0117 end -0118 if ~isfield(model,'geneShortNames') && isfield(model,'genes') -0119 model.geneShortNames=cell(numel(model.genes),1); -0120 end -0121 if ~isfield(model,'proteins') && isfield(model,'genes') -0122 model.proteins=cell(numel(model.genes),1); -0123 end -0124 if ~isfield(model,'subSystems') -0125 model.subSystems=cell(numel(model.rxns),1); -0126 end -0127 if ~isfield(model,'eccodes') -0128 model.eccodes=cell(numel(model.rxns),1); -0129 end -0130 if ~isfield(model,'rxnReferences') -0131 model.rxnReferences=cell(numel(model.rxns),1); -0132 end -0133 if ~isfield(model,'rxnConfidenceScores') -0134 model.rxnConfidenceScores=NaN(numel(model.rxns),1); -0135 end -0136 if ~isfield(model,'rxnNotes') -0137 model.rxnNotes=cell(numel(model.rxns),1); -0138 end -0139 if ~isfield(model,'rxnMiriams') -0140 model.rxnMiriams=cell(numel(model.rxns),1); -0141 end -0142 -0143 if sbmlLevel<3 -0144 %Check if genes have associated compartments -0145 if ~isfield(model,'geneComps') && isfield(model,'genes') -0146 if supressWarnings==false -0147 EM='There are no compartments specified for genes. All genes will be assigned to the first compartment. This is because the SBML structure requires all elements to be assigned to a compartment'; -0148 dispEM(EM,false); -0149 end -0150 model.geneComps=ones(numel(model.genes),1); -0151 end -0152 end -0153 -0154 %Convert ids to SBML-convenient format. This is to avoid the data loss when -0155 %unsupported characters are included in ids. Here we are using part from -0156 %convertSBMLID, originating from the COBRA Toolbox -0157 model.rxns=regexprep(model.rxns,'([^0-9_a-zA-Z])','__${num2str($1+0)}__'); -0158 model.mets=regexprep(model.mets,'([^0-9_a-zA-Z])','__${num2str($1+0)}__'); -0159 model.comps=regexprep(model.comps,'([^0-9_a-zA-Z])','__${num2str($1+0)}__'); -0160 if isfield(model,'genes') -0161 problemGenes=find(~cellfun('isempty',regexp(model.genes,'([^0-9_a-zA-Z])'))); -0162 originalGenes=model.genes(problemGenes); -0163 replacedGenes=regexprep(model.genes(problemGenes),'([^0-9_a-zA-Z])','__${num2str($1+0)}__'); -0164 model.genes(problemGenes)=replacedGenes; -0165 for i=1:numel(problemGenes) -0166 model.grRules = regexprep(model.grRules, ['(^|\s|\()' originalGenes{i} '($|\s|\))'], ['$1' replacedGenes{i} '$2']); -0167 end -0168 end -0169 -0170 %Generate an empty SBML structure -0171 modelSBML=getSBMLStructure(sbmlLevel,sbmlVersion,sbmlPackages,sbmlPackageVersions); -0172 modelSBML.metaid=model.id; -0173 modelSBML.id=regexprep(model.id,'([^0-9_a-zA-Z])','__${num2str($1+0)}__'); -0174 modelSBML.name=model.name; -0175 -0176 if isfield(model,'annotation') -0177 if isfield(model.annotation,'note') -0178 modelSBML.notes=['<notes><body xmlns="http://www.w3.org/1999/xhtml"><p>',regexprep(model.annotation.note,'<p>|</p>',''),'</p></body></notes>']; -0179 end -0180 else -0181 modelSBML.notes='<notes><body xmlns="http://www.w3.org/1999/xhtml"><p>This file was generated using the exportModel function in RAVEN Toolbox 2 and OutputSBML in libSBML </p></body></notes>'; -0182 end -0183 -0184 if isfield(model,'annotation') -0185 nameString=''; -0186 if isfield(model.annotation,'familyName') -0187 if ~isempty(model.annotation.familyName) -0188 nameString=['<vCard:Family>' model.annotation.familyName '</vCard:Family>']; +0096 %Add several blank fields, if they do not exist already. This is to reduce +0097 %the number of conditions below +0098 if ~isfield(model,'compMiriams') +0099 model.compMiriams=cell(numel(model.comps),1); +0100 end +0101 if ~isfield(model,'inchis') +0102 model.inchis=cell(numel(model.mets),1); +0103 end +0104 if ~isfield(model,'metFormulas') +0105 model.metFormulas=cell(numel(model.mets),1); +0106 end +0107 if ~isfield(model,'metMiriams') +0108 model.metMiriams=cell(numel(model.mets),1); +0109 end +0110 if ~isfield(model,'geneMiriams') && isfield(model,'genes') +0111 model.geneMiriams=cell(numel(model.genes),1); +0112 end +0113 if ~isfield(model,'geneShortNames') && isfield(model,'genes') +0114 model.geneShortNames=cell(numel(model.genes),1); +0115 end +0116 if ~isfield(model,'proteins') && isfield(model,'genes') +0117 model.proteins=cell(numel(model.genes),1); +0118 end +0119 if ~isfield(model,'subSystems') +0120 model.subSystems=cell(numel(model.rxns),1); +0121 end +0122 if ~isfield(model,'eccodes') +0123 model.eccodes=cell(numel(model.rxns),1); +0124 end +0125 if ~isfield(model,'rxnReferences') +0126 model.rxnReferences=cell(numel(model.rxns),1); +0127 end +0128 if ~isfield(model,'rxnConfidenceScores') +0129 model.rxnConfidenceScores=NaN(numel(model.rxns),1); +0130 end +0131 if ~isfield(model,'rxnNotes') +0132 model.rxnNotes=cell(numel(model.rxns),1); +0133 end +0134 if ~isfield(model,'rxnMiriams') +0135 model.rxnMiriams=cell(numel(model.rxns),1); +0136 end +0137 +0138 if sbmlLevel<3 +0139 %Check if genes have associated compartments +0140 if ~isfield(model,'geneComps') && isfield(model,'genes') +0141 if supressWarnings==false +0142 EM='There are no compartments specified for genes. All genes will be assigned to the first compartment. This is because the SBML structure requires all elements to be assigned to a compartment'; +0143 dispEM(EM,false); +0144 end +0145 model.geneComps=ones(numel(model.genes),1); +0146 end +0147 end +0148 +0149 %Convert ids to SBML-convenient format. This is to avoid the data loss when +0150 %unsupported characters are included in ids. Here we are using part from +0151 %convertSBMLID, originating from the COBRA Toolbox +0152 model.rxns=regexprep(model.rxns,'([^0-9_a-zA-Z])','__${num2str($1+0)}__'); +0153 model.mets=regexprep(model.mets,'([^0-9_a-zA-Z])','__${num2str($1+0)}__'); +0154 model.comps=regexprep(model.comps,'([^0-9_a-zA-Z])','__${num2str($1+0)}__'); +0155 if isfield(model,'genes') +0156 problemGenes=find(~cellfun('isempty',regexp(model.genes,'([^0-9_a-zA-Z])'))); +0157 originalGenes=model.genes(problemGenes); +0158 replacedGenes=regexprep(model.genes(problemGenes),'([^0-9_a-zA-Z])','__${num2str($1+0)}__'); +0159 model.genes(problemGenes)=replacedGenes; +0160 for i=1:numel(problemGenes) +0161 model.grRules = regexprep(model.grRules, ['(^|\s|\()' originalGenes{i} '($|\s|\))'], ['$1' replacedGenes{i} '$2']); +0162 end +0163 end +0164 +0165 %Generate an empty SBML structure +0166 modelSBML=getSBMLStructure(sbmlLevel,sbmlVersion,sbmlPackages,sbmlPackageVersions); +0167 modelSBML.metaid=model.id; +0168 modelSBML.id=regexprep(model.id,'([^0-9_a-zA-Z])','__${num2str($1+0)}__'); +0169 modelSBML.name=model.name; +0170 +0171 if isfield(model,'annotation') +0172 if isfield(model.annotation,'note') +0173 modelSBML.notes=['<notes><body xmlns="http://www.w3.org/1999/xhtml"><p>',regexprep(model.annotation.note,'<p>|</p>',''),'</p></body></notes>']; +0174 end +0175 else +0176 modelSBML.notes='<notes><body xmlns="http://www.w3.org/1999/xhtml"><p>This file was generated using the exportModel function in RAVEN Toolbox 2 and OutputSBML in libSBML </p></body></notes>'; +0177 end +0178 +0179 if isfield(model,'annotation') +0180 nameString=''; +0181 if isfield(model.annotation,'familyName') +0182 if ~isempty(model.annotation.familyName) +0183 nameString=['<vCard:Family>' model.annotation.familyName '</vCard:Family>']; +0184 end +0185 end +0186 if isfield(model.annotation,'givenName') +0187 if ~isempty(model.annotation.givenName) +0188 nameString=[nameString '<vCard:Given>' model.annotation.givenName '</vCard:Given>']; 0189 end 0190 end -0191 if isfield(model.annotation,'givenName') -0192 if ~isempty(model.annotation.givenName) -0193 nameString=[nameString '<vCard:Given>' model.annotation.givenName '</vCard:Given>']; -0194 end -0195 end -0196 email=''; -0197 if isfield(model.annotation,'email') -0198 if ~isempty(model.annotation.email) -0199 email=['<vCard:EMAIL>' model.annotation.email '</vCard:EMAIL>']; -0200 end -0201 end -0202 org=''; -0203 if isfield(model.annotation,'organization') -0204 if ~isempty(model.annotation.organization) -0205 org=['<vCard:ORG rdf:parseType="Resource"><vCard:Orgname>' model.annotation.organization '</vCard:Orgname></vCard:ORG>']; -0206 end -0207 end -0208 if ~isempty(nameString) || ~isempty(email) || ~isempty(org) % Only fill .annotation if ownership data is provided -0209 modelSBML.annotation=['<annotation><rdf:RDF xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#" xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:dcterms="http://purl.org/dc/terms/" xmlns:vCard="http://www.w3.org/2001/vcard-rdf/3.0#" xmlns:bqbiol="http://biomodels.net/biology-qualifiers/" xmlns:bqmodel="http://biomodels.net/model-qualifiers/"><rdf:Description rdf:about="#meta_' model.id '">']; -0210 modelSBML.annotation=[modelSBML.annotation '<dc:creator><rdf:Bag><rdf:li rdf:parseType="Resource">']; -0211 if ~isempty(nameString) -0212 modelSBML.annotation=[modelSBML.annotation '<vCard:N rdf:parseType="Resource">' nameString '</vCard:N>']; -0213 end -0214 modelSBML.annotation=[modelSBML.annotation email org '</rdf:li></rdf:Bag></dc:creator>']; -0215 modelSBML.annotation=[modelSBML.annotation '<dcterms:created rdf:parseType="Resource">'... -0216 '<dcterms:W3CDTF>' datestr(now,'yyyy-mm-ddTHH:MM:SSZ') '</dcterms:W3CDTF></dcterms:created><dcterms:modified rdf:parseType="Resource">'... -0217 '<dcterms:W3CDTF>' datestr(now,'yyyy-mm-ddTHH:MM:SSZ') '</dcterms:W3CDTF></dcterms:modified>']; -0218 if isfield(model.annotation,'taxonomy') -0219 modelSBML.annotation=[modelSBML.annotation '<bqbiol:is><rdf:Bag><rdf:li rdf:resource="https://identifiers.org/taxonomy/' regexprep(model.annotation.taxonomy,'taxonomy/','') '"/></rdf:Bag></bqbiol:is>']; -0220 end -0221 modelSBML.annotation=[modelSBML.annotation '</rdf:Description></rdf:RDF></annotation>']; -0222 end -0223 end -0224 -0225 %Prepare compartments -0226 for i=1:numel(model.comps) -0227 %Add the default values, as these will be the same in all entries -0228 if i==1 -0229 if isfield(modelSBML.compartment, 'sboTerm') -0230 modelSBML.compartment(i).sboTerm=290; -0231 end -0232 if isfield(modelSBML.compartment, 'spatialDimensions') -0233 modelSBML.compartment(i).spatialDimensions=3; -0234 end -0235 if isfield(modelSBML.compartment, 'size') -0236 modelSBML.compartment(i).size=1; -0237 end -0238 if isfield(modelSBML.compartment, 'constant') -0239 modelSBML.compartment(i).constant=1; -0240 end -0241 if isfield(modelSBML.compartment, 'isSetSize') -0242 modelSBML.compartment(i).isSetSize=1; -0243 end -0244 if isfield(modelSBML.compartment, 'isSetSpatialDimensions') -0245 modelSBML.compartment(i).isSetSpatialDimensions=1; -0246 end +0191 email=''; +0192 if isfield(model.annotation,'email') +0193 if ~isempty(model.annotation.email) +0194 email=['<vCard:EMAIL>' model.annotation.email '</vCard:EMAIL>']; +0195 end +0196 end +0197 org=''; +0198 if isfield(model.annotation,'organization') +0199 if ~isempty(model.annotation.organization) +0200 org=['<vCard:ORG rdf:parseType="Resource"><vCard:Orgname>' model.annotation.organization '</vCard:Orgname></vCard:ORG>']; +0201 end +0202 end +0203 if ~isempty(nameString) || ~isempty(email) || ~isempty(org) % Only fill .annotation if ownership data is provided +0204 modelSBML.annotation=['<annotation><rdf:RDF xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#" xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:dcterms="http://purl.org/dc/terms/" xmlns:vCard="http://www.w3.org/2001/vcard-rdf/3.0#" xmlns:bqbiol="http://biomodels.net/biology-qualifiers/" xmlns:bqmodel="http://biomodels.net/model-qualifiers/"><rdf:Description rdf:about="#meta_' model.id '">']; +0205 modelSBML.annotation=[modelSBML.annotation '<dc:creator><rdf:Bag><rdf:li rdf:parseType="Resource">']; +0206 if ~isempty(nameString) +0207 modelSBML.annotation=[modelSBML.annotation '<vCard:N rdf:parseType="Resource">' nameString '</vCard:N>']; +0208 end +0209 modelSBML.annotation=[modelSBML.annotation email org '</rdf:li></rdf:Bag></dc:creator>']; +0210 modelSBML.annotation=[modelSBML.annotation '<dcterms:created rdf:parseType="Resource">'... +0211 '<dcterms:W3CDTF>' datestr(now,'yyyy-mm-ddTHH:MM:SSZ') '</dcterms:W3CDTF></dcterms:created><dcterms:modified rdf:parseType="Resource">'... +0212 '<dcterms:W3CDTF>' datestr(now,'yyyy-mm-ddTHH:MM:SSZ') '</dcterms:W3CDTF></dcterms:modified>']; +0213 if isfield(model.annotation,'taxonomy') +0214 modelSBML.annotation=[modelSBML.annotation '<bqbiol:is><rdf:Bag><rdf:li rdf:resource="https://identifiers.org/taxonomy/' regexprep(model.annotation.taxonomy,'taxonomy/','') '"/></rdf:Bag></bqbiol:is>']; +0215 end +0216 modelSBML.annotation=[modelSBML.annotation '</rdf:Description></rdf:RDF></annotation>']; +0217 end +0218 end +0219 +0220 %Prepare compartments +0221 for i=1:numel(model.comps) +0222 %Add the default values, as these will be the same in all entries +0223 if i==1 +0224 if isfield(modelSBML.compartment, 'sboTerm') +0225 modelSBML.compartment(i).sboTerm=290; +0226 end +0227 if isfield(modelSBML.compartment, 'spatialDimensions') +0228 modelSBML.compartment(i).spatialDimensions=3; +0229 end +0230 if isfield(modelSBML.compartment, 'size') +0231 modelSBML.compartment(i).size=1; +0232 end +0233 if isfield(modelSBML.compartment, 'constant') +0234 modelSBML.compartment(i).constant=1; +0235 end +0236 if isfield(modelSBML.compartment, 'isSetSize') +0237 modelSBML.compartment(i).isSetSize=1; +0238 end +0239 if isfield(modelSBML.compartment, 'isSetSpatialDimensions') +0240 modelSBML.compartment(i).isSetSpatialDimensions=1; +0241 end +0242 end +0243 %Copy the default values to the next entry as long as it is not the +0244 %last one +0245 if i<numel(model.comps) +0246 modelSBML.compartment(i+1)=modelSBML.compartment(i); 0247 end -0248 %Copy the default values to the next entry as long as it is not the -0249 %last one -0250 if i<numel(model.comps) -0251 modelSBML.compartment(i+1)=modelSBML.compartment(i); -0252 end -0253 -0254 if isfield(modelSBML.compartment,'metaid') -0255 modelSBML.compartment(i).metaid=model.comps{i}; -0256 end -0257 %Prepare Miriam strings -0258 if ~isempty(model.compMiriams{i}) -0259 [~,sbo_ind] = ismember('sbo',model.compMiriams{i}.name); -0260 if sbo_ind > 0 -0261 modelSBML.compartment(i).sboTerm=str2double(regexprep(model.compMiriams{i}.value{sbo_ind},'SBO:','','ignorecase')); -0262 % remove the SBO term from compMiriams so the information is -0263 % not duplicated in the "annotation" field later on -0264 model.compMiriams{i}.name(sbo_ind) = []; -0265 model.compMiriams{i}.value(sbo_ind) = []; -0266 end +0248 +0249 if isfield(modelSBML.compartment,'metaid') +0250 modelSBML.compartment(i).metaid=model.comps{i}; +0251 end +0252 %Prepare Miriam strings +0253 if ~isempty(model.compMiriams{i}) +0254 [~,sbo_ind] = ismember('sbo',model.compMiriams{i}.name); +0255 if sbo_ind > 0 +0256 modelSBML.compartment(i).sboTerm=str2double(regexprep(model.compMiriams{i}.value{sbo_ind},'SBO:','','ignorecase')); +0257 % remove the SBO term from compMiriams so the information is +0258 % not duplicated in the "annotation" field later on +0259 model.compMiriams{i}.name(sbo_ind) = []; +0260 model.compMiriams{i}.value(sbo_ind) = []; +0261 end +0262 end +0263 if ~isempty(model.compMiriams{i}) && isfield(modelSBML.compartment(i),'annotation') +0264 modelSBML.compartment(i).annotation=['<annotation><rdf:RDF xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#" xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:dcterms="http://purl.org/dc/terms/" xmlns:vCard="http://www.w3.org/2001/vcard-rdf/3.0#" xmlns:bqbiol="http://biomodels.net/biology-qualifiers/" xmlns:bqmodel="http://biomodels.net/model-qualifiers/"><rdf:Description rdf:about="#meta_' model.comps{i} '">']; +0265 modelSBML.compartment(i).annotation=[modelSBML.compartment(i).annotation '<bqbiol:is><rdf:Bag>']; +0266 modelSBML.compartment(i).annotation=[modelSBML.compartment(i).annotation getMiriam(model.compMiriams{i}) '</rdf:Bag></bqbiol:is></rdf:Description></rdf:RDF></annotation>']; 0267 end -0268 if ~isempty(model.compMiriams{i}) && isfield(modelSBML.compartment(i),'annotation') -0269 modelSBML.compartment(i).annotation=['<annotation><rdf:RDF xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#" xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:dcterms="http://purl.org/dc/terms/" xmlns:vCard="http://www.w3.org/2001/vcard-rdf/3.0#" xmlns:bqbiol="http://biomodels.net/biology-qualifiers/" xmlns:bqmodel="http://biomodels.net/model-qualifiers/"><rdf:Description rdf:about="#meta_' model.comps{i} '">']; -0270 modelSBML.compartment(i).annotation=[modelSBML.compartment(i).annotation '<bqbiol:is><rdf:Bag>']; -0271 modelSBML.compartment(i).annotation=[modelSBML.compartment(i).annotation getMiriam(model.compMiriams{i}) '</rdf:Bag></bqbiol:is></rdf:Description></rdf:RDF></annotation>']; -0272 end -0273 if isfield(modelSBML.compartment, 'name') -0274 modelSBML.compartment(i).name=model.compNames{i}; -0275 end -0276 if isfield(modelSBML.compartment, 'id') -0277 modelSBML.compartment(i).id=model.comps{i}; -0278 end -0279 -0280 end -0281 -0282 %Begin writing species -0283 for i=1:numel(model.mets) -0284 %Add the default values, as these will be the same in all entries -0285 if i==1 -0286 if isfield(modelSBML.species, 'sboTerm') -0287 modelSBML.species(i).sboTerm=247; -0288 end -0289 if isfield(modelSBML.species, 'initialAmount') -0290 modelSBML.species(i).initialAmount=1; -0291 end -0292 if isfield(modelSBML.species, 'initialConcentration') -0293 modelSBML.species(i).initialConcentration=0; -0294 end -0295 if isfield(modelSBML.species, 'isSetInitialAmount') -0296 modelSBML.species(i).isSetInitialAmount=1; -0297 end -0298 if isfield(modelSBML.species, 'isSetInitialConcentration') -0299 modelSBML.species(i).isSetInitialConcentration=1; -0300 end +0268 if isfield(modelSBML.compartment, 'name') +0269 modelSBML.compartment(i).name=model.compNames{i}; +0270 end +0271 if isfield(modelSBML.compartment, 'id') +0272 modelSBML.compartment(i).id=model.comps{i}; +0273 end +0274 +0275 end +0276 +0277 %Begin writing species +0278 for i=1:numel(model.mets) +0279 %Add the default values, as these will be the same in all entries +0280 if i==1 +0281 if isfield(modelSBML.species, 'sboTerm') +0282 modelSBML.species(i).sboTerm=247; +0283 end +0284 if isfield(modelSBML.species, 'initialAmount') +0285 modelSBML.species(i).initialAmount=1; +0286 end +0287 if isfield(modelSBML.species, 'initialConcentration') +0288 modelSBML.species(i).initialConcentration=0; +0289 end +0290 if isfield(modelSBML.species, 'isSetInitialAmount') +0291 modelSBML.species(i).isSetInitialAmount=1; +0292 end +0293 if isfield(modelSBML.species, 'isSetInitialConcentration') +0294 modelSBML.species(i).isSetInitialConcentration=1; +0295 end +0296 end +0297 %Copy the default values to the next entry as long as it is not the +0298 %last one +0299 if i<numel(model.mets) +0300 modelSBML.species(i+1)=modelSBML.species(i); 0301 end -0302 %Copy the default values to the next entry as long as it is not the -0303 %last one -0304 if i<numel(model.mets) -0305 modelSBML.species(i+1)=modelSBML.species(i); -0306 end -0307 -0308 if isfield(modelSBML.species,'metaid') -0309 modelSBML.species(i).metaid=model.mets{i}; -0310 end -0311 if isfield(modelSBML.species, 'name') -0312 modelSBML.species(i).name=model.metNames{i}; -0313 end -0314 if isfield(modelSBML.species, 'id') -0315 modelSBML.species(i).id=model.mets{i}; -0316 end -0317 if isfield(modelSBML.species, 'compartment') -0318 modelSBML.species(i).compartment=model.comps{model.metComps(i)}; +0302 +0303 if isfield(modelSBML.species,'metaid') +0304 modelSBML.species(i).metaid=model.mets{i}; +0305 end +0306 if isfield(modelSBML.species, 'name') +0307 modelSBML.species(i).name=model.metNames{i}; +0308 end +0309 if isfield(modelSBML.species, 'id') +0310 modelSBML.species(i).id=model.mets{i}; +0311 end +0312 if isfield(modelSBML.species, 'compartment') +0313 modelSBML.species(i).compartment=model.comps{model.metComps(i)}; +0314 end +0315 if isfield(model,'unconstrained') +0316 if model.unconstrained(i) +0317 modelSBML.species(i).boundaryCondition=1; +0318 end 0319 end -0320 if isfield(model,'unconstrained') -0321 if model.unconstrained(i) -0322 modelSBML.species(i).boundaryCondition=1; -0323 end -0324 end -0325 if isfield(modelSBML.species, 'fbc_charge') && isfield(model,'metCharges') -0326 if ~isnan(model.metCharges(i)) -0327 modelSBML.species(i).fbc_charge=model.metCharges(i); -0328 modelSBML.species(i).isSetfbc_charge=1; -0329 else -0330 modelSBML.species(i).isSetfbc_charge=0; -0331 end -0332 end -0333 if ~isempty(model.metMiriams{i}) -0334 [~,sbo_ind] = ismember('sbo',model.metMiriams{i}.name); -0335 if sbo_ind > 0 -0336 modelSBML.species(i).sboTerm=str2double(regexprep(model.metMiriams{i}.value{sbo_ind},'SBO:','','ignorecase')); -0337 % remove the SBO term from metMiriams so the information is -0338 % not duplicated in the "annotation" field later on -0339 model.metMiriams{i}.name(sbo_ind) = []; -0340 model.metMiriams{i}.value(sbo_ind) = []; -0341 end -0342 end -0343 if isfield(modelSBML.species,'annotation') -0344 if ~isempty(model.metMiriams{i}) || ~isempty(model.metFormulas{i}) -0345 hasInchi=false; -0346 if ~isempty(model.metFormulas{i}) -0347 %Only export formula if there is no InChI. This is because -0348 %the metFormulas field is populated by InChIs if available -0349 if ~isempty(model.inchis{i}) -0350 hasInchi=true; -0351 end -0352 if hasInchi==false -0353 modelSBML.species(i).fbc_chemicalFormula=model.metFormulas{i}; -0354 end -0355 end -0356 if ~isempty(model.metMiriams{i}) || hasInchi==true -0357 modelSBML.species(i).annotation=['<annotation><rdf:RDF xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#" xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:dcterms="http://purl.org/dc/terms/" xmlns:vCard="http://www.w3.org/2001/vcard-rdf/3.0#" xmlns:bqbiol="http://biomodels.net/biology-qualifiers/" xmlns:bqmodel="http://biomodels.net/model-qualifiers/"><rdf:Description rdf:about="#meta_' model.mets{i} '">']; -0358 modelSBML.species(i).annotation=[modelSBML.species(i).annotation '<bqbiol:is><rdf:Bag>']; -0359 if ~isempty(model.metMiriams{i}) -0360 modelSBML.species(i).annotation=[modelSBML.species(i).annotation getMiriam(model.metMiriams{i})]; -0361 end -0362 if hasInchi==true -0363 modelSBML.species(i).annotation=[modelSBML.species(i).annotation '<rdf:li rdf:resource="https://identifiers.org/inchi/InChI=' regexprep(model.inchis{i},'^InChI=','') '"/>']; -0364 modelSBML.species(i).fbc_chemicalFormula=char(regexp(model.inchis{i}, '/(\w+)/', 'tokens', 'once')); -0365 end -0366 modelSBML.species(i).annotation=[modelSBML.species(i).annotation '</rdf:Bag></bqbiol:is></rdf:Description></rdf:RDF></annotation>']; -0367 end -0368 end -0369 end -0370 end -0371 -0372 if isfield(model,'genes') -0373 for i=1:numel(model.genes) -0374 %Add the default values, as these will be the same in all entries -0375 if i==1 -0376 if isfield(modelSBML.fbc_geneProduct, 'sboTerm') -0377 modelSBML.fbc_geneProduct(i).sboTerm=243; -0378 end +0320 if isfield(modelSBML.species, 'fbc_charge') && isfield(model,'metCharges') +0321 if ~isnan(model.metCharges(i)) +0322 modelSBML.species(i).fbc_charge=model.metCharges(i); +0323 modelSBML.species(i).isSetfbc_charge=1; +0324 else +0325 modelSBML.species(i).isSetfbc_charge=0; +0326 end +0327 end +0328 if ~isempty(model.metMiriams{i}) +0329 [~,sbo_ind] = ismember('sbo',model.metMiriams{i}.name); +0330 if sbo_ind > 0 +0331 modelSBML.species(i).sboTerm=str2double(regexprep(model.metMiriams{i}.value{sbo_ind},'SBO:','','ignorecase')); +0332 % remove the SBO term from metMiriams so the information is +0333 % not duplicated in the "annotation" field later on +0334 model.metMiriams{i}.name(sbo_ind) = []; +0335 model.metMiriams{i}.value(sbo_ind) = []; +0336 end +0337 end +0338 if isfield(modelSBML.species,'annotation') +0339 if ~isempty(model.metMiriams{i}) || ~isempty(model.metFormulas{i}) +0340 hasInchi=false; +0341 if ~isempty(model.metFormulas{i}) +0342 %Only export formula if there is no InChI. This is because +0343 %the metFormulas field is populated by InChIs if available +0344 if ~isempty(model.inchis{i}) +0345 hasInchi=true; +0346 end +0347 if hasInchi==false +0348 modelSBML.species(i).fbc_chemicalFormula=model.metFormulas{i}; +0349 end +0350 end +0351 if ~isempty(model.metMiriams{i}) || hasInchi==true +0352 modelSBML.species(i).annotation=['<annotation><rdf:RDF xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#" xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:dcterms="http://purl.org/dc/terms/" xmlns:vCard="http://www.w3.org/2001/vcard-rdf/3.0#" xmlns:bqbiol="http://biomodels.net/biology-qualifiers/" xmlns:bqmodel="http://biomodels.net/model-qualifiers/"><rdf:Description rdf:about="#meta_' model.mets{i} '">']; +0353 modelSBML.species(i).annotation=[modelSBML.species(i).annotation '<bqbiol:is><rdf:Bag>']; +0354 if ~isempty(model.metMiriams{i}) +0355 modelSBML.species(i).annotation=[modelSBML.species(i).annotation getMiriam(model.metMiriams{i})]; +0356 end +0357 if hasInchi==true +0358 modelSBML.species(i).annotation=[modelSBML.species(i).annotation '<rdf:li rdf:resource="https://identifiers.org/inchi/InChI=' regexprep(model.inchis{i},'^InChI=','') '"/>']; +0359 modelSBML.species(i).fbc_chemicalFormula=char(regexp(model.inchis{i}, '/(\w+)/', 'tokens', 'once')); +0360 end +0361 modelSBML.species(i).annotation=[modelSBML.species(i).annotation '</rdf:Bag></bqbiol:is></rdf:Description></rdf:RDF></annotation>']; +0362 end +0363 end +0364 end +0365 end +0366 +0367 if isfield(model,'genes') +0368 for i=1:numel(model.genes) +0369 %Add the default values, as these will be the same in all entries +0370 if i==1 +0371 if isfield(modelSBML.fbc_geneProduct, 'sboTerm') +0372 modelSBML.fbc_geneProduct(i).sboTerm=243; +0373 end +0374 end +0375 %Copy the default values to the next index as long as it is not the +0376 %last one +0377 if i<numel(model.genes) +0378 modelSBML.fbc_geneProduct(i+1)=modelSBML.fbc_geneProduct(i); 0379 end -0380 %Copy the default values to the next index as long as it is not the -0381 %last one -0382 if i<numel(model.genes) -0383 modelSBML.fbc_geneProduct(i+1)=modelSBML.fbc_geneProduct(i); -0384 end -0385 -0386 if isfield(modelSBML.fbc_geneProduct,'metaid') -0387 modelSBML.fbc_geneProduct(i).metaid=model.genes{i}; -0388 end -0389 if ~isempty(model.geneMiriams{i}) -0390 [~,sbo_ind] = ismember('sbo',model.geneMiriams{i}.name); -0391 if sbo_ind > 0 -0392 modelSBML.fbc_geneProduct(i).sboTerm=str2double(regexprep(model.geneMiriams{i}.value{sbo_ind},'SBO:','','ignorecase')); -0393 % remove the SBO term from compMiriams so the information is -0394 % not duplicated in the "annotation" field later on -0395 model.geneMiriams{i}.name(sbo_ind) = []; -0396 model.geneMiriams{i}.value(sbo_ind) = []; -0397 end +0380 +0381 if isfield(modelSBML.fbc_geneProduct,'metaid') +0382 modelSBML.fbc_geneProduct(i).metaid=model.genes{i}; +0383 end +0384 if ~isempty(model.geneMiriams{i}) +0385 [~,sbo_ind] = ismember('sbo',model.geneMiriams{i}.name); +0386 if sbo_ind > 0 +0387 modelSBML.fbc_geneProduct(i).sboTerm=str2double(regexprep(model.geneMiriams{i}.value{sbo_ind},'SBO:','','ignorecase')); +0388 % remove the SBO term from compMiriams so the information is +0389 % not duplicated in the "annotation" field later on +0390 model.geneMiriams{i}.name(sbo_ind) = []; +0391 model.geneMiriams{i}.value(sbo_ind) = []; +0392 end +0393 end +0394 if ~isempty(model.geneMiriams{i}) && isfield(modelSBML.fbc_geneProduct(i),'annotation') +0395 modelSBML.fbc_geneProduct(i).annotation=['<annotation><rdf:RDF xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#" xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:dcterms="http://purl.org/dc/terms/" xmlns:vCard="http://www.w3.org/2001/vcard-rdf/3.0#" xmlns:bqbiol="http://biomodels.net/biology-qualifiers/" xmlns:bqmodel="http://biomodels.net/model-qualifiers/"><rdf:Description rdf:about="#meta_' model.genes{i} '">']; +0396 modelSBML.fbc_geneProduct(i).annotation=[modelSBML.fbc_geneProduct(i).annotation '<bqbiol:is><rdf:Bag>']; +0397 modelSBML.fbc_geneProduct(i).annotation=[modelSBML.fbc_geneProduct(i).annotation getMiriam(model.geneMiriams{i}) '</rdf:Bag></bqbiol:is></rdf:Description></rdf:RDF></annotation>']; 0398 end -0399 if ~isempty(model.geneMiriams{i}) && isfield(modelSBML.fbc_geneProduct(i),'annotation') -0400 modelSBML.fbc_geneProduct(i).annotation=['<annotation><rdf:RDF xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#" xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:dcterms="http://purl.org/dc/terms/" xmlns:vCard="http://www.w3.org/2001/vcard-rdf/3.0#" xmlns:bqbiol="http://biomodels.net/biology-qualifiers/" xmlns:bqmodel="http://biomodels.net/model-qualifiers/"><rdf:Description rdf:about="#meta_' model.genes{i} '">']; -0401 modelSBML.fbc_geneProduct(i).annotation=[modelSBML.fbc_geneProduct(i).annotation '<bqbiol:is><rdf:Bag>']; -0402 modelSBML.fbc_geneProduct(i).annotation=[modelSBML.fbc_geneProduct(i).annotation getMiriam(model.geneMiriams{i}) '</rdf:Bag></bqbiol:is></rdf:Description></rdf:RDF></annotation>']; -0403 end -0404 if isfield(modelSBML.fbc_geneProduct, 'fbc_id') -0405 modelSBML.fbc_geneProduct(i).fbc_id=model.genes{i}; -0406 end -0407 if isfield(modelSBML.fbc_geneProduct, 'fbc_label') && isfield(model,'geneShortNames') -0408 if isempty(model.geneShortNames{i}) -0409 modelSBML.fbc_geneProduct(i).fbc_label=model.genes{i}; -0410 else -0411 modelSBML.fbc_geneProduct(i).fbc_label=model.geneShortNames{i}; +0399 if isfield(modelSBML.fbc_geneProduct, 'fbc_id') +0400 modelSBML.fbc_geneProduct(i).fbc_id=model.genes{i}; +0401 end +0402 if isfield(modelSBML.fbc_geneProduct, 'fbc_label') && isfield(model,'geneShortNames') +0403 if isempty(model.geneShortNames{i}) +0404 modelSBML.fbc_geneProduct(i).fbc_label=model.genes{i}; +0405 else +0406 modelSBML.fbc_geneProduct(i).fbc_label=model.geneShortNames{i}; +0407 end +0408 end +0409 if isfield(modelSBML.fbc_geneProduct, 'fbc_name') && isfield(model,'proteins') +0410 if ~isempty(model.proteins{i}) +0411 modelSBML.fbc_geneProduct(i).fbc_name=model.proteins{i}; 0412 end 0413 end -0414 if isfield(modelSBML.fbc_geneProduct, 'fbc_name') && isfield(model,'proteins') -0415 if ~isempty(model.proteins{i}) -0416 modelSBML.fbc_geneProduct(i).fbc_name=model.proteins{i}; -0417 end -0418 end -0419 end -0420 end -0421 -0422 %Generate a list of unique fbc_bound names -0423 totalValues=[model.lb; model.ub]; -0424 totalNames=cell(size(totalValues,1),1); -0425 -0426 listUniqueValues=unique(totalValues); -0427 -0428 for i=1:length(listUniqueValues) -0429 listUniqueNames{i,1}=['FB',num2str(i),'N',num2str(abs(round(listUniqueValues(i))))]; % create unique flux bound IDs. -0430 ind=find(ismember(totalValues,listUniqueValues(i))); -0431 totalNames(ind)=listUniqueNames(i,1); -0432 end -0433 -0434 for i=1:length(listUniqueNames) -0435 %Add the default values, as these will be the same in all entries -0436 if i==1 -0437 if isfield(modelSBML.parameter, 'constant') -0438 modelSBML.parameter(i).constant=1; -0439 end -0440 if isfield(modelSBML.parameter, 'isSetValue') -0441 modelSBML.parameter(i).isSetValue=1; -0442 end +0414 end +0415 end +0416 +0417 %Generate a list of unique fbc_bound names +0418 totalValues=[model.lb; model.ub]; +0419 totalNames=cell(size(totalValues,1),1); +0420 +0421 listUniqueValues=unique(totalValues); +0422 +0423 for i=1:length(listUniqueValues) +0424 listUniqueNames{i,1}=['FB',num2str(i),'N',num2str(abs(round(listUniqueValues(i))))]; % create unique flux bound IDs. +0425 ind=find(ismember(totalValues,listUniqueValues(i))); +0426 totalNames(ind)=listUniqueNames(i,1); +0427 end +0428 +0429 for i=1:length(listUniqueNames) +0430 %Add the default values, as these will be the same in all entries +0431 if i==1 +0432 if isfield(modelSBML.parameter, 'constant') +0433 modelSBML.parameter(i).constant=1; +0434 end +0435 if isfield(modelSBML.parameter, 'isSetValue') +0436 modelSBML.parameter(i).isSetValue=1; +0437 end +0438 end +0439 %Copy the default values to the next index as long as it is not the +0440 %last one +0441 if i<numel(listUniqueNames) +0442 modelSBML.parameter(i+1)=modelSBML.parameter(i); 0443 end -0444 %Copy the default values to the next index as long as it is not the -0445 %last one -0446 if i<numel(listUniqueNames) -0447 modelSBML.parameter(i+1)=modelSBML.parameter(i); -0448 end -0449 modelSBML.parameter(i).id=listUniqueNames{i}; -0450 modelSBML.parameter(i).value=listUniqueValues(i); -0451 end -0452 -0453 for i=1:numel(model.rxns) -0454 %Add the default values, as these will be the same in all entries -0455 if i==1 -0456 if isfield(modelSBML.reaction, 'sboTerm') -0457 modelSBML.reaction(i).sboTerm=176; -0458 end -0459 if isfield(modelSBML.reaction, 'isSetFast') -0460 modelSBML.reaction(i).isSetFast=1; -0461 end +0444 modelSBML.parameter(i).id=listUniqueNames{i}; +0445 modelSBML.parameter(i).value=listUniqueValues(i); +0446 end +0447 +0448 for i=1:numel(model.rxns) +0449 %Add the default values, as these will be the same in all entries +0450 if i==1 +0451 if isfield(modelSBML.reaction, 'sboTerm') +0452 modelSBML.reaction(i).sboTerm=176; +0453 end +0454 if isfield(modelSBML.reaction, 'isSetFast') +0455 modelSBML.reaction(i).isSetFast=1; +0456 end +0457 end +0458 %Copy the default values to the next index as long as it is not the +0459 %last one +0460 if i<numel(model.rxns) +0461 modelSBML.reaction(i+1)=modelSBML.reaction(i); 0462 end -0463 %Copy the default values to the next index as long as it is not the -0464 %last one -0465 if i<numel(model.rxns) -0466 modelSBML.reaction(i+1)=modelSBML.reaction(i); -0467 end -0468 -0469 if isfield(modelSBML.reaction,'metaid') -0470 modelSBML.reaction(i).metaid=model.rxns{i}; -0471 end -0472 -0473 %Export notes information -0474 if (~isnan(model.rxnConfidenceScores(i)) || ~isempty(model.rxnReferences{i}) || ~isempty(model.rxnNotes{i})) -0475 modelSBML.reaction(i).notes='<notes><body xmlns="http://www.w3.org/1999/xhtml">'; -0476 if ~isnan(model.rxnConfidenceScores(i)) -0477 modelSBML.reaction(i).notes=[modelSBML.reaction(i).notes '<p>Confidence Level: ' num2str(model.rxnConfidenceScores(i)) '</p>']; -0478 end -0479 if ~isempty(model.rxnReferences{i}) -0480 modelSBML.reaction(i).notes=[modelSBML.reaction(i).notes '<p>AUTHORS: ' model.rxnReferences{i} '</p>']; -0481 end -0482 if ~isempty(model.rxnNotes{i}) -0483 modelSBML.reaction(i).notes=[modelSBML.reaction(i).notes '<p>NOTES: ' model.rxnNotes{i} '</p>']; -0484 end -0485 modelSBML.reaction(i).notes=[modelSBML.reaction(i).notes '</body></notes>']; -0486 end -0487 -0488 % Export SBO terms from rxnMiriams -0489 if ~isempty(model.rxnMiriams{i}) -0490 [~,sbo_ind] = ismember('sbo',model.rxnMiriams{i}.name); -0491 if sbo_ind > 0 -0492 modelSBML.reaction(i).sboTerm=str2double(regexprep(model.rxnMiriams{i}.value{sbo_ind},'SBO:','','ignorecase')); -0493 % remove the SBO term from rxnMiriams so the information is not -0494 % duplicated in the "annotation" field later on -0495 model.rxnMiriams{i}.name(sbo_ind) = []; -0496 model.rxnMiriams{i}.value(sbo_ind) = []; -0497 end -0498 end -0499 -0500 %Export annotation information from rxnMiriams -0501 if (~isempty(model.rxnMiriams{i}) && isfield(modelSBML.reaction(i),'annotation')) || ~isempty(model.eccodes{i}) -0502 modelSBML.reaction(i).annotation=['<annotation><rdf:RDF xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#" xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:dcterms="http://purl.org/dc/terms/" xmlns:vCard="http://www.w3.org/2001/vcard-rdf/3.0#" xmlns:bqbiol="http://biomodels.net/biology-qualifiers/" xmlns:bqmodel="http://biomodels.net/model-qualifiers/"><rdf:Description rdf:about="#meta_' model.rxns{i} '">']; -0503 modelSBML.reaction(i).annotation=[modelSBML.reaction(i).annotation '<bqbiol:is><rdf:Bag>']; -0504 if ~isempty(model.eccodes{i}) -0505 eccodes=regexp(model.eccodes{i},';','split'); -0506 for j=1:numel(eccodes) -0507 modelSBML.reaction(i).annotation=[modelSBML.reaction(i).annotation '<rdf:li rdf:resource="https://identifiers.org/ec-code/' regexprep(eccodes{j},'ec-code/|EC','') '"/>']; -0508 end -0509 end -0510 modelSBML.reaction(i).annotation=[modelSBML.reaction(i).annotation getMiriam(model.rxnMiriams{i}) '</rdf:Bag></bqbiol:is></rdf:Description></rdf:RDF></annotation>']; -0511 end -0512 -0513 if isfield(modelSBML.reaction, 'name') -0514 modelSBML.reaction(i).name=model.rxnNames{i}; -0515 end -0516 if isfield(modelSBML.reaction, 'id') -0517 modelSBML.reaction(i).id=model.rxns{i}; -0518 end -0519 -0520 %Add the information about reactants and products -0521 involvedMets=addReactantsProducts(model,modelSBML,i); -0522 for j=1:numel(involvedMets.reactant) -0523 if j<numel(involvedMets.reactant) -0524 modelSBML.reaction(i).reactant(j+1)=modelSBML.reaction(i).reactant(j); -0525 end -0526 modelSBML.reaction(i).reactant(j).species=involvedMets.reactant(j).species; -0527 modelSBML.reaction(i).reactant(j).stoichiometry=involvedMets.reactant(j).stoichiometry; -0528 modelSBML.reaction(i).reactant(j).isSetStoichiometry=involvedMets.reactant(j).isSetStoichiometry; -0529 modelSBML.reaction(i).reactant(j).constant=involvedMets.reactant(j).constant; -0530 end -0531 if numel(involvedMets.reactant)==0 -0532 modelSBML.reaction(i).reactant=''; -0533 end -0534 for j=1:numel(involvedMets.product) -0535 if j<numel(involvedMets.product) -0536 modelSBML.reaction(i).product(j+1)=modelSBML.reaction(i).product(j); -0537 end -0538 modelSBML.reaction(i).product(j).species=involvedMets.product(j).species; -0539 modelSBML.reaction(i).product(j).stoichiometry=involvedMets.product(j).stoichiometry; -0540 modelSBML.reaction(i).product(j).isSetStoichiometry=involvedMets.product(j).isSetStoichiometry; -0541 modelSBML.reaction(i).product(j).constant=involvedMets.product(j).constant; -0542 end -0543 if numel(involvedMets.product)==0 -0544 modelSBML.reaction(i).product=''; +0463 +0464 if isfield(modelSBML.reaction,'metaid') +0465 modelSBML.reaction(i).metaid=model.rxns{i}; +0466 end +0467 +0468 %Export notes information +0469 if (~isnan(model.rxnConfidenceScores(i)) || ~isempty(model.rxnReferences{i}) || ~isempty(model.rxnNotes{i})) +0470 modelSBML.reaction(i).notes='<notes><body xmlns="http://www.w3.org/1999/xhtml">'; +0471 if ~isnan(model.rxnConfidenceScores(i)) +0472 modelSBML.reaction(i).notes=[modelSBML.reaction(i).notes '<p>Confidence Level: ' num2str(model.rxnConfidenceScores(i)) '</p>']; +0473 end +0474 if ~isempty(model.rxnReferences{i}) +0475 modelSBML.reaction(i).notes=[modelSBML.reaction(i).notes '<p>AUTHORS: ' model.rxnReferences{i} '</p>']; +0476 end +0477 if ~isempty(model.rxnNotes{i}) +0478 modelSBML.reaction(i).notes=[modelSBML.reaction(i).notes '<p>NOTES: ' model.rxnNotes{i} '</p>']; +0479 end +0480 modelSBML.reaction(i).notes=[modelSBML.reaction(i).notes '</body></notes>']; +0481 end +0482 +0483 % Export SBO terms from rxnMiriams +0484 if ~isempty(model.rxnMiriams{i}) +0485 [~,sbo_ind] = ismember('sbo',model.rxnMiriams{i}.name); +0486 if sbo_ind > 0 +0487 modelSBML.reaction(i).sboTerm=str2double(regexprep(model.rxnMiriams{i}.value{sbo_ind},'SBO:','','ignorecase')); +0488 % remove the SBO term from rxnMiriams so the information is not +0489 % duplicated in the "annotation" field later on +0490 model.rxnMiriams{i}.name(sbo_ind) = []; +0491 model.rxnMiriams{i}.value(sbo_ind) = []; +0492 end +0493 end +0494 +0495 %Export annotation information from rxnMiriams +0496 if (~isempty(model.rxnMiriams{i}) && isfield(modelSBML.reaction(i),'annotation')) || ~isempty(model.eccodes{i}) +0497 modelSBML.reaction(i).annotation=['<annotation><rdf:RDF xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#" xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:dcterms="http://purl.org/dc/terms/" xmlns:vCard="http://www.w3.org/2001/vcard-rdf/3.0#" xmlns:bqbiol="http://biomodels.net/biology-qualifiers/" xmlns:bqmodel="http://biomodels.net/model-qualifiers/"><rdf:Description rdf:about="#meta_' model.rxns{i} '">']; +0498 modelSBML.reaction(i).annotation=[modelSBML.reaction(i).annotation '<bqbiol:is><rdf:Bag>']; +0499 if ~isempty(model.eccodes{i}) +0500 eccodes=regexp(model.eccodes{i},';','split'); +0501 for j=1:numel(eccodes) +0502 modelSBML.reaction(i).annotation=[modelSBML.reaction(i).annotation '<rdf:li rdf:resource="https://identifiers.org/ec-code/' regexprep(eccodes{j},'ec-code/|EC','') '"/>']; +0503 end +0504 end +0505 modelSBML.reaction(i).annotation=[modelSBML.reaction(i).annotation getMiriam(model.rxnMiriams{i}) '</rdf:Bag></bqbiol:is></rdf:Description></rdf:RDF></annotation>']; +0506 end +0507 +0508 if isfield(modelSBML.reaction, 'name') +0509 modelSBML.reaction(i).name=model.rxnNames{i}; +0510 end +0511 if isfield(modelSBML.reaction, 'id') +0512 modelSBML.reaction(i).id=model.rxns{i}; +0513 end +0514 +0515 %Add the information about reactants and products +0516 involvedMets=addReactantsProducts(model,modelSBML,i); +0517 for j=1:numel(involvedMets.reactant) +0518 if j<numel(involvedMets.reactant) +0519 modelSBML.reaction(i).reactant(j+1)=modelSBML.reaction(i).reactant(j); +0520 end +0521 modelSBML.reaction(i).reactant(j).species=involvedMets.reactant(j).species; +0522 modelSBML.reaction(i).reactant(j).stoichiometry=involvedMets.reactant(j).stoichiometry; +0523 modelSBML.reaction(i).reactant(j).isSetStoichiometry=involvedMets.reactant(j).isSetStoichiometry; +0524 modelSBML.reaction(i).reactant(j).constant=involvedMets.reactant(j).constant; +0525 end +0526 if numel(involvedMets.reactant)==0 +0527 modelSBML.reaction(i).reactant=''; +0528 end +0529 for j=1:numel(involvedMets.product) +0530 if j<numel(involvedMets.product) +0531 modelSBML.reaction(i).product(j+1)=modelSBML.reaction(i).product(j); +0532 end +0533 modelSBML.reaction(i).product(j).species=involvedMets.product(j).species; +0534 modelSBML.reaction(i).product(j).stoichiometry=involvedMets.product(j).stoichiometry; +0535 modelSBML.reaction(i).product(j).isSetStoichiometry=involvedMets.product(j).isSetStoichiometry; +0536 modelSBML.reaction(i).product(j).constant=involvedMets.product(j).constant; +0537 end +0538 if numel(involvedMets.product)==0 +0539 modelSBML.reaction(i).product=''; +0540 end +0541 %Export reversibility information. Reactions are irreversible by +0542 %default +0543 if model.rev(i)==1 +0544 modelSBML.reaction(i).reversible=1; 0545 end -0546 %Export reversibility information. Reactions are irreversible by -0547 %default -0548 if model.rev(i)==1 -0549 modelSBML.reaction(i).reversible=1; -0550 end -0551 if isfield(model, 'rxnComps') -0552 modelSBML.reaction(i).compartment=model.comps{model.rxnComps(i)}; -0553 end -0554 if isfield(model, 'grRules') -0555 modelSBML.reaction(i).fbc_geneProductAssociation.fbc_association.fbc_association=model.grRules{i}; -0556 end -0557 modelSBML.reaction(i).fbc_lowerFluxBound=totalNames{i}; -0558 modelSBML.reaction(i).fbc_upperFluxBound=totalNames{length(model.lb)+i}; -0559 end -0560 -0561 %Prepare subSystems Code taken from COBRA functions getModelSubSystems, -0562 %writeSBML, findRxnsFromSubSystem under GNU General Public License v3.0, -0563 %license file in readme/GPL.MD. Code modified for RAVEN -0564 if modelHasSubsystems -0565 modelSBML.groups_group.groups_kind = 'partonomy'; -0566 modelSBML.groups_group.sboTerm = 633; -0567 tmpStruct=modelSBML.groups_group; -0568 -0569 rxns=model.rxns; -0570 if ~any(cellfun(@iscell,model.subSystems)) -0571 if ~any(~cellfun(@isempty,model.subSystems)) -0572 subSystems = {}; -0573 else -0574 subSystems = setdiff(model.subSystems,''); -0575 end -0576 else -0577 orderedSubs = cellfun(@(x) columnVector(x),model.subSystems,'UniformOUtput',false); -0578 subSystems = setdiff(vertcat(orderedSubs{:}),''); -0579 end -0580 if isempty(subSystems) -0581 subSystems = {}; -0582 end -0583 if ~isempty(subSystems) -0584 %Build the groups for the group package -0585 groupIDs = strcat('group',cellfun(@num2str, num2cell(1:length(subSystems)),'UniformOutput',false)); -0586 for i = 1:length(subSystems) -0587 cgroup = tmpStruct; -0588 if ~any(cellfun(@iscell,model.subSystems)) -0589 present = ismember(model.subSystems,subSystems{i}); -0590 else -0591 present = cellfun(@(x) any(ismember(x,subSystems{i})),model.subSystems); -0592 end -0593 groupMembers = rxns(present); -0594 for j = 1:numel(groupMembers) -0595 cMember = tmpStruct.groups_member; -0596 cMember.groups_idRef = groupMembers{j}; -0597 if j == 1 -0598 cgroup.groups_member = cMember; -0599 else -0600 cgroup.groups_member(j) = cMember; -0601 end -0602 end -0603 cgroup.groups_id = groupIDs{i}; -0604 cgroup.groups_name = subSystems{i}; -0605 if i == 1 -0606 modelSBML.groups_group = cgroup; -0607 else -0608 modelSBML.groups_group(i) = cgroup; -0609 end -0610 end -0611 end -0612 end +0546 if isfield(model, 'rxnComps') +0547 modelSBML.reaction(i).compartment=model.comps{model.rxnComps(i)}; +0548 end +0549 if isfield(model, 'grRules') +0550 modelSBML.reaction(i).fbc_geneProductAssociation.fbc_association.fbc_association=model.grRules{i}; +0551 end +0552 modelSBML.reaction(i).fbc_lowerFluxBound=totalNames{i}; +0553 modelSBML.reaction(i).fbc_upperFluxBound=totalNames{length(model.lb)+i}; +0554 end +0555 +0556 %Prepare subSystems Code taken from COBRA functions getModelSubSystems, +0557 %writeSBML, findRxnsFromSubSystem under GNU General Public License v3.0, +0558 %license file in readme/GPL.MD. Code modified for RAVEN +0559 if modelHasSubsystems +0560 modelSBML.groups_group.groups_kind = 'partonomy'; +0561 modelSBML.groups_group.sboTerm = 633; +0562 tmpStruct=modelSBML.groups_group; +0563 +0564 rxns=model.rxns; +0565 if ~any(cellfun(@iscell,model.subSystems)) +0566 if ~any(~cellfun(@isempty,model.subSystems)) +0567 subSystems = {}; +0568 else +0569 subSystems = setdiff(model.subSystems,''); +0570 end +0571 else +0572 orderedSubs = cellfun(@(x) columnVector(x),model.subSystems,'UniformOUtput',false); +0573 subSystems = setdiff(vertcat(orderedSubs{:}),''); +0574 end +0575 if isempty(subSystems) +0576 subSystems = {}; +0577 end +0578 if ~isempty(subSystems) +0579 %Build the groups for the group package +0580 groupIDs = strcat('group',cellfun(@num2str, num2cell(1:length(subSystems)),'UniformOutput',false)); +0581 for i = 1:length(subSystems) +0582 cgroup = tmpStruct; +0583 if ~any(cellfun(@iscell,model.subSystems)) +0584 present = ismember(model.subSystems,subSystems{i}); +0585 else +0586 present = cellfun(@(x) any(ismember(x,subSystems{i})),model.subSystems); +0587 end +0588 groupMembers = rxns(present); +0589 for j = 1:numel(groupMembers) +0590 cMember = tmpStruct.groups_member; +0591 cMember.groups_idRef = groupMembers{j}; +0592 if j == 1 +0593 cgroup.groups_member = cMember; +0594 else +0595 cgroup.groups_member(j) = cMember; +0596 end +0597 end +0598 cgroup.groups_id = groupIDs{i}; +0599 cgroup.groups_name = subSystems{i}; +0600 if i == 1 +0601 modelSBML.groups_group = cgroup; +0602 else +0603 modelSBML.groups_group(i) = cgroup; +0604 end +0605 end +0606 end +0607 end +0608 +0609 %Prepare fbc_objective subfield +0610 +0611 modelSBML.fbc_objective.fbc_type='maximize'; +0612 modelSBML.fbc_objective.fbc_id='obj'; 0613 -0614 %Prepare fbc_objective subfield +0614 ind=find(model.c); 0615 -0616 modelSBML.fbc_objective.fbc_type='maximize'; -0617 modelSBML.fbc_objective.fbc_id='obj'; -0618 -0619 ind=find(model.c); -0620 -0621 if isempty(ind) -0622 modelSBML.fbc_objective.fbc_fluxObjective.fbc_coefficient=0; -0623 else -0624 for i=1:length(ind) -0625 %Copy the default values to the next index as long as it is not the -0626 %last one -0627 if i<numel(ind) -0628 modelSBML.reaction(i+1)=modelSBML.reaction(i); -0629 end -0630 values=model.c(model.c~=0); -0631 modelSBML.fbc_objective(i).fbc_fluxObjective.fbc_reaction=modelSBML.reaction(ind(i)).id; -0632 modelSBML.fbc_objective(i).fbc_fluxObjective.fbc_coefficient=values(i); -0633 modelSBML.fbc_objective(i).fbc_fluxObjective.isSetfbc_coefficient=1; -0634 end -0635 end -0636 -0637 modelSBML.fbc_activeObjective=modelSBML.fbc_objective.fbc_id; -0638 -0639 fbcStr=['http://www.sbml.org/sbml/level', num2str(sbmlLevel), '/version', num2str(sbmlVersion), '/fbc/version',num2str(sbmlPackageVersions(1))]; -0640 if modelHasSubsystems -0641 groupStr=['http://www.sbml.org/sbml/level', num2str(sbmlLevel), '/version', num2str(sbmlVersion), '/groups/version',num2str(sbmlPackageVersions(2))]; -0642 modelSBML.namespaces=struct('prefix',{'','fbc','groups'},... -0643 'uri',{['http://www.sbml.org/sbml/level', num2str(sbmlLevel), '/version', num2str(sbmlVersion), '/core'],... -0644 fbcStr,groupStr}); -0645 else -0646 modelSBML.namespaces=struct('prefix',{'','fbc'},... -0647 'uri',{['http://www.sbml.org/sbml/level', num2str(sbmlLevel), '/version', num2str(sbmlVersion), '/core'],... -0648 fbcStr}); +0616 if isempty(ind) +0617 modelSBML.fbc_objective.fbc_fluxObjective.fbc_coefficient=0; +0618 else +0619 for i=1:length(ind) +0620 %Copy the default values to the next index as long as it is not the +0621 %last one +0622 if i<numel(ind) +0623 modelSBML.reaction(i+1)=modelSBML.reaction(i); +0624 end +0625 values=model.c(model.c~=0); +0626 modelSBML.fbc_objective(i).fbc_fluxObjective.fbc_reaction=modelSBML.reaction(ind(i)).id; +0627 modelSBML.fbc_objective(i).fbc_fluxObjective.fbc_coefficient=values(i); +0628 modelSBML.fbc_objective(i).fbc_fluxObjective.isSetfbc_coefficient=1; +0629 end +0630 end +0631 +0632 modelSBML.fbc_activeObjective=modelSBML.fbc_objective.fbc_id; +0633 +0634 fbcStr=['http://www.sbml.org/sbml/level', num2str(sbmlLevel), '/version', num2str(sbmlVersion), '/fbc/version',num2str(sbmlPackageVersions(1))]; +0635 if modelHasSubsystems +0636 groupStr=['http://www.sbml.org/sbml/level', num2str(sbmlLevel), '/version', num2str(sbmlVersion), '/groups/version',num2str(sbmlPackageVersions(2))]; +0637 modelSBML.namespaces=struct('prefix',{'','fbc','groups'},... +0638 'uri',{['http://www.sbml.org/sbml/level', num2str(sbmlLevel), '/version', num2str(sbmlVersion), '/core'],... +0639 fbcStr,groupStr}); +0640 else +0641 modelSBML.namespaces=struct('prefix',{'','fbc'},... +0642 'uri',{['http://www.sbml.org/sbml/level', num2str(sbmlLevel), '/version', num2str(sbmlVersion), '/core'],... +0643 fbcStr}); +0644 end +0645 +0646 if sbmlPackageVersions(1) == 2 +0647 modelSBML.fbc_strict=1; +0648 modelSBML.isSetfbc_strict = 1; 0649 end 0650 -0651 if sbmlPackageVersions(1) == 2 -0652 modelSBML.fbc_strict=1; -0653 modelSBML.isSetfbc_strict = 1; -0654 end -0655 -0656 modelSBML.rule=[]; -0657 modelSBML.constraint=[]; -0658 -0659 [ravenDir,prevDir]=findRAVENroot(); -0660 fileName=checkFileExistence(fileName,1,true,false); -0661 -0662 OutputSBML_RAVEN(modelSBML,fileName,1,0,[1,0]); -0663 end +0651 modelSBML.rule=[]; +0652 modelSBML.constraint=[]; +0653 +0654 [ravenDir,prevDir]=findRAVENroot(); +0655 fileName=checkFileExistence(fileName,1,true,false); +0656 +0657 OutputSBML_RAVEN(modelSBML,fileName,1,0,[1,0]); +0658 end +0659 +0660 +0661 function modelSBML=getSBMLStructure(sbmlLevel,sbmlVersion,sbmlPackages,sbmlPackageVersions) +0662 %Returns the blank SBML model structure by using appropriate libSBML +0663 %functions. This creates structure by considering three levels 0664 -0665 -0666 function modelSBML=getSBMLStructure(sbmlLevel,sbmlVersion,sbmlPackages,sbmlPackageVersions) -0667 %Returns the blank SBML model structure by using appropriate libSBML -0668 %functions. This creates structure by considering three levels -0669 -0670 sbmlFieldNames=getStructureFieldnames('model',sbmlLevel,sbmlVersion,sbmlPackages,sbmlPackageVersions); -0671 sbmlDefaultValues=getDefaultValues('model',sbmlLevel,sbmlVersion,sbmlPackages,sbmlPackageVersions); -0672 -0673 for i=1:numel(sbmlFieldNames) -0674 modelSBML.(sbmlFieldNames{1,i})=sbmlDefaultValues{1,i}; -0675 sbmlSubfieldNames=getStructureFieldnames(sbmlFieldNames{1,i},sbmlLevel,sbmlVersion,sbmlPackages,sbmlPackageVersions); -0676 sbmlSubfieldValues=getDefaultValues(sbmlFieldNames{1,i},sbmlLevel,sbmlVersion,sbmlPackages,sbmlPackageVersions); -0677 if ~strcmp(sbmlFieldNames{1,i},'event') && ~strcmp(sbmlFieldNames{1,i},'functionDefinition') && ~strcmp(sbmlFieldNames{1,i},'initialAssignment') -0678 for j=1:numel(sbmlSubfieldNames) -0679 modelSBML.(sbmlFieldNames{1,i}).(sbmlSubfieldNames{1,j})=sbmlSubfieldValues{1,j}; -0680 sbmlSubsubfieldNames=getStructureFieldnames(sbmlSubfieldNames{1,j},sbmlLevel,sbmlVersion,sbmlPackages,sbmlPackageVersions); -0681 sbmlSubsubfieldValues=getDefaultValues(sbmlSubfieldNames{1,j},sbmlLevel,sbmlVersion,sbmlPackages,sbmlPackageVersions); -0682 if ~strcmp(sbmlSubfieldNames{1,j},'modifier') && ~strcmp(sbmlSubfieldNames{1,j},'kineticLaw') -0683 for k=1:numel(sbmlSubsubfieldNames) -0684 %'compartment' and 'species' fields are not supposed to -0685 %have their standalone structures if they are subfields -0686 %or subsubfields -0687 if ~strcmp(sbmlSubfieldNames{1,j},'compartment') && ~strcmp(sbmlSubfieldNames{1,j},'species') -0688 modelSBML.(sbmlFieldNames{1,i}).(sbmlSubfieldNames{1,j}).(sbmlSubsubfieldNames{1,k})=sbmlSubsubfieldValues{1,k}; -0689 end -0690 %If it is fbc_association in the third level, we need -0691 %to establish the fourth level, since libSBML requires -0692 %it -0693 if strcmp(sbmlSubsubfieldNames{1,k},'fbc_association') -0694 fbc_associationFieldNames=getStructureFieldnames('fbc_association',sbmlLevel,sbmlVersion,sbmlPackages,sbmlPackageVersions); -0695 fbc_associationFieldValues=getDefaultValues('fbc_association',sbmlLevel,sbmlVersion,sbmlPackages,sbmlPackageVersions); -0696 for l=1:numel(fbc_associationFieldNames) -0697 modelSBML.(sbmlFieldNames{1,i}).(sbmlSubfieldNames{1,j}).(sbmlSubsubfieldNames{1,k}).(fbc_associationFieldNames{1,l})=fbc_associationFieldValues{1,l}; -0698 end -0699 end -0700 end -0701 end -0702 end -0703 end -0704 if ~isstruct(modelSBML.(sbmlFieldNames{1,i})) -0705 modelSBML.(sbmlFieldNames{1,i})=sbmlDefaultValues{1,i}; -0706 end -0707 end +0665 sbmlFieldNames=getStructureFieldnames('model',sbmlLevel,sbmlVersion,sbmlPackages,sbmlPackageVersions); +0666 sbmlDefaultValues=getDefaultValues('model',sbmlLevel,sbmlVersion,sbmlPackages,sbmlPackageVersions); +0667 +0668 for i=1:numel(sbmlFieldNames) +0669 modelSBML.(sbmlFieldNames{1,i})=sbmlDefaultValues{1,i}; +0670 sbmlSubfieldNames=getStructureFieldnames(sbmlFieldNames{1,i},sbmlLevel,sbmlVersion,sbmlPackages,sbmlPackageVersions); +0671 sbmlSubfieldValues=getDefaultValues(sbmlFieldNames{1,i},sbmlLevel,sbmlVersion,sbmlPackages,sbmlPackageVersions); +0672 if ~strcmp(sbmlFieldNames{1,i},'event') && ~strcmp(sbmlFieldNames{1,i},'functionDefinition') && ~strcmp(sbmlFieldNames{1,i},'initialAssignment') +0673 for j=1:numel(sbmlSubfieldNames) +0674 modelSBML.(sbmlFieldNames{1,i}).(sbmlSubfieldNames{1,j})=sbmlSubfieldValues{1,j}; +0675 sbmlSubsubfieldNames=getStructureFieldnames(sbmlSubfieldNames{1,j},sbmlLevel,sbmlVersion,sbmlPackages,sbmlPackageVersions); +0676 sbmlSubsubfieldValues=getDefaultValues(sbmlSubfieldNames{1,j},sbmlLevel,sbmlVersion,sbmlPackages,sbmlPackageVersions); +0677 if ~strcmp(sbmlSubfieldNames{1,j},'modifier') && ~strcmp(sbmlSubfieldNames{1,j},'kineticLaw') +0678 for k=1:numel(sbmlSubsubfieldNames) +0679 %'compartment' and 'species' fields are not supposed to +0680 %have their standalone structures if they are subfields +0681 %or subsubfields +0682 if ~strcmp(sbmlSubfieldNames{1,j},'compartment') && ~strcmp(sbmlSubfieldNames{1,j},'species') +0683 modelSBML.(sbmlFieldNames{1,i}).(sbmlSubfieldNames{1,j}).(sbmlSubsubfieldNames{1,k})=sbmlSubsubfieldValues{1,k}; +0684 end +0685 %If it is fbc_association in the third level, we need +0686 %to establish the fourth level, since libSBML requires +0687 %it +0688 if strcmp(sbmlSubsubfieldNames{1,k},'fbc_association') +0689 fbc_associationFieldNames=getStructureFieldnames('fbc_association',sbmlLevel,sbmlVersion,sbmlPackages,sbmlPackageVersions); +0690 fbc_associationFieldValues=getDefaultValues('fbc_association',sbmlLevel,sbmlVersion,sbmlPackages,sbmlPackageVersions); +0691 for l=1:numel(fbc_associationFieldNames) +0692 modelSBML.(sbmlFieldNames{1,i}).(sbmlSubfieldNames{1,j}).(sbmlSubsubfieldNames{1,k}).(fbc_associationFieldNames{1,l})=fbc_associationFieldValues{1,l}; +0693 end +0694 end +0695 end +0696 end +0697 end +0698 end +0699 if ~isstruct(modelSBML.(sbmlFieldNames{1,i})) +0700 modelSBML.(sbmlFieldNames{1,i})=sbmlDefaultValues{1,i}; +0701 end +0702 end +0703 +0704 modelSBML.unitDefinition.id='mmol_per_gDW_per_hr'; +0705 +0706 unitFieldNames=getStructureFieldnames('unit',sbmlLevel,sbmlVersion,sbmlPackages,sbmlPackageVersions); +0707 unitDefaultValues=getDefaultValues('unit',sbmlLevel,sbmlVersion,sbmlPackages,sbmlPackageVersions); 0708 -0709 modelSBML.unitDefinition.id='mmol_per_gDW_per_hr'; -0710 -0711 unitFieldNames=getStructureFieldnames('unit',sbmlLevel,sbmlVersion,sbmlPackages,sbmlPackageVersions); -0712 unitDefaultValues=getDefaultValues('unit',sbmlLevel,sbmlVersion,sbmlPackages,sbmlPackageVersions); +0709 kinds={'mole','gram','second'}; +0710 exponents=[1 -1 -1]; +0711 scales=[-3 0 0]; +0712 multipliers=[1 1 1*60*60]; 0713 -0714 kinds={'mole','gram','second'}; -0715 exponents=[1 -1 -1]; -0716 scales=[-3 0 0]; -0717 multipliers=[1 1 1*60*60]; -0718 -0719 for i=1:numel(unitFieldNames) -0720 modelSBML.unitDefinition.unit(1).(unitFieldNames{1,i})=unitDefaultValues{1,i}; -0721 for j=1:3 -0722 modelSBML.unitDefinition.unit(j).(unitFieldNames{1,i})=unitDefaultValues{1,i}; -0723 if strcmp(unitFieldNames{1,i},'kind') -0724 modelSBML.unitDefinition.unit(j).(unitFieldNames{1,i})=kinds{j}; -0725 elseif strcmp(unitFieldNames{1,i},'exponent') -0726 modelSBML.unitDefinition.unit(j).(unitFieldNames{1,i})=exponents(j); -0727 elseif strcmp(unitFieldNames{1,i},'scale') -0728 modelSBML.unitDefinition.unit(j).(unitFieldNames{1,i})=scales(j); -0729 elseif strcmp(unitFieldNames{1,i},'multiplier') -0730 modelSBML.unitDefinition.unit(j).(unitFieldNames{1,i})=multipliers(j); -0731 end -0732 end -0733 end -0734 end -0735 -0736 function miriamString=getMiriam(miriamStruct) -0737 %Returns a string with list elements for a miriam structure ('<rdf:li -0738 %rdf:resource="https://identifiers.org/go/GO:0005739"/>' for example). This -0739 %is just to speed up things since this is done many times during the -0740 %exporting -0741 -0742 miriamString=''; -0743 if isfield(miriamStruct,'name') -0744 for i=1:numel(miriamStruct.name) -0745 miriamString=[miriamString '<rdf:li rdf:resource="https://identifiers.org/' miriamStruct.name{i} '/' miriamStruct.value{i} '"/>']; -0746 end -0747 end -0748 end -0749 -0750 function [tmp_Rxn]=addReactantsProducts(model,sbmlModel,i) -0751 %This function provides reactants and products for particular reaction. The -0752 %function was 'borrowed' from writeSBML in COBRA toolbox, lines 663-679 -0753 -0754 met_idx = find(model.S(:, i)); -0755 tmp_Rxn.product=[]; -0756 tmp_Rxn.reactant=[]; -0757 for j_met=1:size(met_idx,1) -0758 tmp_idx = met_idx(j_met,1); -0759 sbml_tmp_species_ref.species = sbmlModel.species(tmp_idx).id; -0760 met_stoich = model.S(tmp_idx, i); -0761 sbml_tmp_species_ref.stoichiometry = abs(met_stoich); -0762 sbml_tmp_species_ref.isSetStoichiometry=1; -0763 sbml_tmp_species_ref.constant=1; -0764 if (met_stoich > 0) -0765 tmp_Rxn.product = [ tmp_Rxn.product, sbml_tmp_species_ref ]; -0766 else -0767 tmp_Rxn.reactant = [ tmp_Rxn.reactant, sbml_tmp_species_ref]; -0768 end -0769 end -0770 end -0771 -0772 function vecT = columnVector(vec) -0773 % Code below taken from COBRA Toolbox under GNU General Public License v3.0 -0774 % license file in readme/GPL.MD. -0775 % -0776 % Converts a vector to a column vector -0777 % -0778 % USAGE: +0714 for i=1:numel(unitFieldNames) +0715 modelSBML.unitDefinition.unit(1).(unitFieldNames{1,i})=unitDefaultValues{1,i}; +0716 for j=1:3 +0717 modelSBML.unitDefinition.unit(j).(unitFieldNames{1,i})=unitDefaultValues{1,i}; +0718 if strcmp(unitFieldNames{1,i},'kind') +0719 modelSBML.unitDefinition.unit(j).(unitFieldNames{1,i})=kinds{j}; +0720 elseif strcmp(unitFieldNames{1,i},'exponent') +0721 modelSBML.unitDefinition.unit(j).(unitFieldNames{1,i})=exponents(j); +0722 elseif strcmp(unitFieldNames{1,i},'scale') +0723 modelSBML.unitDefinition.unit(j).(unitFieldNames{1,i})=scales(j); +0724 elseif strcmp(unitFieldNames{1,i},'multiplier') +0725 modelSBML.unitDefinition.unit(j).(unitFieldNames{1,i})=multipliers(j); +0726 end +0727 end +0728 end +0729 end +0730 +0731 function miriamString=getMiriam(miriamStruct) +0732 %Returns a string with list elements for a miriam structure ('<rdf:li +0733 %rdf:resource="https://identifiers.org/go/GO:0005739"/>' for example). This +0734 %is just to speed up things since this is done many times during the +0735 %exporting +0736 +0737 miriamString=''; +0738 if isfield(miriamStruct,'name') +0739 for i=1:numel(miriamStruct.name) +0740 miriamString=[miriamString '<rdf:li rdf:resource="https://identifiers.org/' miriamStruct.name{i} '/' miriamStruct.value{i} '"/>']; +0741 end +0742 end +0743 end +0744 +0745 function [tmp_Rxn]=addReactantsProducts(model,sbmlModel,i) +0746 %This function provides reactants and products for particular reaction. The +0747 %function was 'borrowed' from writeSBML in COBRA toolbox, lines 663-679 +0748 +0749 met_idx = find(model.S(:, i)); +0750 tmp_Rxn.product=[]; +0751 tmp_Rxn.reactant=[]; +0752 for j_met=1:size(met_idx,1) +0753 tmp_idx = met_idx(j_met,1); +0754 sbml_tmp_species_ref.species = sbmlModel.species(tmp_idx).id; +0755 met_stoich = model.S(tmp_idx, i); +0756 sbml_tmp_species_ref.stoichiometry = abs(met_stoich); +0757 sbml_tmp_species_ref.isSetStoichiometry=1; +0758 sbml_tmp_species_ref.constant=1; +0759 if (met_stoich > 0) +0760 tmp_Rxn.product = [ tmp_Rxn.product, sbml_tmp_species_ref ]; +0761 else +0762 tmp_Rxn.reactant = [ tmp_Rxn.reactant, sbml_tmp_species_ref]; +0763 end +0764 end +0765 end +0766 +0767 function vecT = columnVector(vec) +0768 % Code below taken from COBRA Toolbox under GNU General Public License v3.0 +0769 % license file in readme/GPL.MD. +0770 % +0771 % Converts a vector to a column vector +0772 % +0773 % USAGE: +0774 % +0775 % vecT = columnVector(vec) +0776 % +0777 % INPUT: +0778 % vec: a vector 0779 % -0780 % vecT = columnVector(vec) -0781 % -0782 % INPUT: -0783 % vec: a vector -0784 % -0785 % OUTPUT: -0786 % vecT: a column vector -0787 -0788 [n, m] = size(vec); -0789 -0790 if n < m -0791 vecT = vec'; -0792 else -0793 vecT = vec; -0794 end -0795 end

    +0780 % OUTPUT: +0781 % vecT: a column vector +0782 +0783 [n, m] = size(vec); +0784 +0785 if n < m +0786 vecT = vec'; +0787 else +0788 vecT = vec; +0789 end +0790 end

    Generated by m2html © 2005
    \ No newline at end of file diff --git a/doc/io/importModel.html b/doc/io/importModel.html index e54a025a..d0d442fc 100644 --- a/doc/io/importModel.html +++ b/doc/io/importModel.html @@ -24,11 +24,11 @@

    PURPOSE ^importModel

    SYNOPSIS ^

    -
    function model=importModel(fileName,removeExcMets,COBRAstyle,supressWarnings)
    +
    function model=importModel(fileName,removeExcMets,removePrefix,supressWarnings)

    DESCRIPTION ^

     importModel
    -   Import a constraint-based model from a SBML file
    +   Import a constraint-based model from an SBML file.
     
      Input:
        fileName        a SBML file to import. A dialog window will open if
    @@ -37,10 +37,11 @@ 

    DESCRIPTION ^DESCRIPTION ^DESCRIPTION ^CROSS-REFERENCE INFORMATION ^

    @@ -107,9 +108,9 @@

    SUBFUNCTIONS ^function matchGenes=getGeneList(grRules)
  • function fieldContent=parseNote(searchString,fieldName)
  • function fieldContent=parseAnnotation(searchString,startString,midString,fieldName)
  • function miriamStruct=parseMiriam(searchString)
  • function miriam = addSBOtoMiriam(miriam,sboTerm)
  • SOURCE CODE ^

    -
    0001 function model=importModel(fileName,removeExcMets,COBRAstyle,supressWarnings)
    +
    0001 function model=importModel(fileName,removeExcMets,removePrefix,supressWarnings)
     0002 % importModel
    -0003 %   Import a constraint-based model from a SBML file
    +0003 %   Import a constraint-based model from an SBML file.
     0004 %
     0005 % Input:
     0006 %   fileName        a SBML file to import. A dialog window will open if
    @@ -118,1185 +119,1171 @@ 

    SOURCE CODE ^% needed to be able to run simulations, but it could also 0010 % be done using simplifyModel at a later stage (optional, 0011 % default true) -0012 % COBRAstyle true if the model uses COBRA style identifier prefixes -0013 % that should be removed when loading the model: G_ for -0014 % genes, R_ for reactions, M_ for metabolites, and C_ for -0015 % compartments. (optional, default false) -0016 % supressWarnings true if warnings regarding the model structure should -0017 % be supressed (optional, default false) -0018 % -0019 % Output: -0020 % model -0021 % id model ID -0022 % name name of model contents -0023 % annotation additional information about model -0024 % rxns reaction ids -0025 % mets metabolite ids -0026 % S stoichiometric matrix -0027 % lb lower bounds -0028 % ub upper bounds -0029 % rev reversibility vector -0030 % c objective coefficients -0031 % b equality constraints for the metabolite equations -0032 % comps compartment ids -0033 % compNames compartment names -0034 % compOutside the id (as in comps) for the compartment -0035 % surrounding each of the compartments -0036 % compMiriams structure with MIRIAM information about the -0037 % compartments -0038 % rxnNames reaction description -0039 % rxnComps compartments for reactions -0040 % grRules reaction to gene rules in text form -0041 % rxnGeneMat reaction-to-gene mapping in sparse matrix form -0042 % subSystems subsystem name for each reaction -0043 % eccodes EC-codes for the reactions -0044 % rxnMiriams structure with MIRIAM information about the reactions -0045 % rxnNotes reaction notes -0046 % rxnReferences reaction references -0047 % rxnConfidenceScores reaction confidence scores -0048 % genes list of all genes -0049 % geneComps compartments for genes -0050 % geneMiriams structure with MIRIAM information about the genes -0051 % geneShortNames gene alternative names (e.g. ERG10) -0052 % proteins protein associated to each gene -0053 % metNames metabolite description -0054 % metComps compartments for metabolites -0055 % inchis InChI-codes for metabolites -0056 % metFormulas metabolite chemical formula -0057 % metMiriams structure with MIRIAM information about the metabolites -0058 % metCharges metabolite charge -0059 % unconstrained true if the metabolite is an exchange metabolite -0060 % -0061 % A number of consistency checks are performed in order to ensure that the -0062 % model is valid. Take these warnings seriously and modify the model -0063 % structure to solve them. -0064 % -0065 % Usage: model = importModel(fileName, removeExcMets, COBRAstyle, supressWarnings) -0066 -0067 if nargin<1 || isempty(fileName) -0068 [fileName, pathName] = uigetfile({'*.xml;*.sbml'}, 'Please select the model file'); -0069 if fileName == 0 -0070 error('You should select a model file') -0071 else -0072 fileName = fullfile(pathName,fileName); -0073 end -0074 end -0075 fileName=char(fileName); -0076 if nargin<2 || isempty(removeExcMets) -0077 removeExcMets=true; -0078 end -0079 -0080 if nargin<3 || isempty(COBRAstyle) -0081 COBRAstyle=false; -0082 end -0083 -0084 if nargin<4 -0085 supressWarnings=false; -0086 end -0087 -0088 fileName=checkFileExistence(fileName,1); -0089 % If path contains non-ASCII characters, copy file to tempdir first, as -0090 % libSBML is known to have problems with this on Windows: -0091 % https://sbml.org/software/libsbml/libsbml-docs/known-pitfalls/#matlab-on-windows-has-issues-with-unicode-filenames -0092 if ispc && any(double(fileName)>128) -0093 [~,originalFile,ext] = fileparts(fileName); -0094 tempFile = fullfile(tempdir,[originalFile ext]); -0095 copyfile(fileName,tempFile); -0096 fileName = tempFile; -0097 end -0098 -0099 %This is to match the order of the fields to those you get from importing -0100 %from Excel -0101 model=[]; -0102 model.id=[]; -0103 model.name=[]; -0104 model.annotation=[]; -0105 model.rxns={}; -0106 model.mets={}; -0107 model.S=[]; -0108 model.lb=[]; -0109 model.ub=[]; -0110 model.rev=[]; -0111 model.c=[]; -0112 model.b=[]; -0113 model.comps={}; -0114 model.compNames={}; -0115 model.compOutside={}; -0116 model.compMiriams={}; -0117 model.rxnNames={}; -0118 model.rxnComps=[]; -0119 model.grRules={}; -0120 model.rxnGeneMat=[]; -0121 model.subSystems={}; -0122 model.eccodes={}; -0123 model.rxnMiriams={}; -0124 model.rxnNotes={}; -0125 model.rxnReferences={}; -0126 model.rxnConfidenceScores=[]; -0127 model.genes={}; -0128 model.geneComps=[]; -0129 model.geneMiriams={}; -0130 model.geneShortNames={}; -0131 model.proteins={}; -0132 model.metNames={}; -0133 model.metComps=[]; -0134 model.inchis={}; -0135 model.metFormulas={}; -0136 model.metMiriams={}; -0137 model.metCharges=[]; -0138 model.unconstrained=[]; -0139 -0140 %Load the model using libSBML -0141 [modelSBML,errorMsg] = TranslateSBML_RAVEN(fileName,0,0,[1 1]); -0142 if exist('tempFile','var') -0143 delete(tempFile) -0144 end -0145 -0146 if isempty(modelSBML) -0147 EM=['There is a problem with the SBML file. Try using the SBML Validator at http://sbml.org/Facilities/Validator.\nlibSBML reports: ', errorMsg.message]; -0148 dispEM(EM); -0149 end -0150 -0151 %Retrieve compartment names and IDs -0152 compartmentNames=cell(numel(modelSBML.compartment),1); -0153 compartmentIDs=cell(numel(modelSBML.compartment),1); -0154 compartmentOutside=cell(numel(modelSBML.compartment),1); -0155 compartmentMiriams=cell(numel(modelSBML.compartment),1); -0156 -0157 if isfield(modelSBML.compartment,'sboTerm') && numel(unique([modelSBML.compartment.sboTerm])) == 1 -0158 %If all the SBO terms are identical, don't add them to compMiriams -0159 modelSBML.compartment = rmfield(modelSBML.compartment,'sboTerm'); -0160 end -0161 -0162 for i=1:numel(modelSBML.compartment) -0163 compartmentNames{i}=modelSBML.compartment(i).name; -0164 compartmentIDs{i}=modelSBML.compartment(i).id; -0165 if isfield(modelSBML.compartment(i),'outside') -0166 if ~isempty(modelSBML.compartment(i).outside) -0167 compartmentOutside{i}=modelSBML.compartment(i).outside; -0168 else -0169 compartmentOutside{i}=''; -0170 end -0171 else -0172 compartmentOutside{i}=[]; -0173 end -0174 -0175 if isfield(modelSBML.compartment(i),'annotation') -0176 compartmentMiriams{i}=parseMiriam(modelSBML.compartment(i).annotation); -0177 else -0178 compartmentMiriams{i}=[]; -0179 end -0180 -0181 if isfield(modelSBML.compartment(i),'sboTerm') && ~(modelSBML.compartment(i).sboTerm==-1) -0182 compartmentMiriams{i} = addSBOtoMiriam(compartmentMiriams{i},modelSBML.compartment(i).sboTerm); -0183 end -0184 end -0185 -0186 %If there are no compartment names then use compartment id as name -0187 if all(cellfun(@isempty,compartmentNames)) -0188 compartmentNames=compartmentIDs; -0189 end -0190 -0191 %Retrieve info on metabolites, genes, complexes -0192 metaboliteNames={}; -0193 metaboliteIDs={}; -0194 metaboliteCompartments={}; -0195 metaboliteUnconstrained=[]; -0196 metaboliteFormula={}; -0197 metaboliteInChI={}; -0198 metaboliteMiriams={}; -0199 metaboliteCharges=[]; -0200 -0201 geneNames={}; -0202 geneIDs={}; -0203 geneMiriams={}; -0204 geneShortNames={}; -0205 proteins={}; -0206 geneCompartments={}; -0207 complexIDs={}; -0208 complexNames={}; -0209 -0210 %If the file is not a COBRA Toolbox model. According to the format -0211 %specified in the yeast consensus model both metabolites and genes are a -0212 %type of 'species'. The metabolites have names starting with 'M_' and genes -0213 %with 'E_' -0214 geneSBOs = []; -0215 metSBOs = []; -0216 %Regex of compartment names, later to be used to remove from metabolite -0217 %names if present as suffix. -0218 regexCompNames = ['\s?\[((' strjoin({modelSBML.compartment.name},')|(') '))\]$']; -0219 for i=1:numel(modelSBML.species) -0220 if length(modelSBML.species(i).id)>=2 && strcmpi(modelSBML.species(i).id(1:2),'E_') -0221 geneNames{numel(geneNames)+1,1}=modelSBML.species(i).name; -0222 -0223 %The "E_" is included in the ID. This is because it's only used -0224 %internally in this file and it makes the matching a little -0225 %smoother -0226 geneIDs{numel(geneIDs)+1,1}=modelSBML.species(i).id; -0227 geneCompartments{numel(geneCompartments)+1,1}=modelSBML.species(i).compartment; -0228 -0229 %Get Miriam structure -0230 if isfield(modelSBML.species(i),'annotation') -0231 %Get Miriam info -0232 geneMiriam=parseMiriam(modelSBML.species(i).annotation); -0233 geneMiriams{numel(geneMiriams)+1,1}=geneMiriam; -0234 else -0235 geneMiriams{numel(geneMiriams)+1,1}=[]; -0236 end -0237 -0238 %Protein short names (for example ERG10) are saved as SHORT -0239 %NAME: NAME in the notes-section of metabolites for SBML Level -0240 %2 and as PROTEIN_ASSOCIATION for each reaction in SBML Level 2 -0241 %COBRA Toolbox format. For now only the SHORT NAME is loaded -0242 %and no mapping takes place -0243 if isfield(modelSBML.species(i),'notes') -0244 geneShortNames{numel(geneShortNames)+1,1}=parseNote(modelSBML.species(i).notes,'SHORT NAME'); -0245 else -0246 geneShortNames{numel(geneShortNames)+1,1}=''; -0247 end -0248 -0249 %Get SBO term -0250 if isfield(modelSBML.species(i),'sboTerm') && ~(modelSBML.species(i).sboTerm==-1) -0251 geneSBOs(end+1,1) = modelSBML.species(i).sboTerm; -0252 end -0253 elseif length(modelSBML.species(i).id)>=2 && strcmpi(modelSBML.species(i).id(1:3),'Cx_') -0254 %If it's a complex keep the ID and name -0255 complexIDs=[complexIDs;modelSBML.species(i).id]; -0256 complexNames=[complexNames;modelSBML.species(i).name]; -0257 else -0258 %If it is not gene or complex, then it must be a metabolite -0259 metaboliteNames{numel(metaboliteNames)+1,1}=modelSBML.species(i).name; -0260 metaboliteIDs{numel(metaboliteIDs)+1,1}=modelSBML.species(i).id; -0261 metaboliteCompartments{numel(metaboliteCompartments)+1,1}=modelSBML.species(i).compartment; -0262 metaboliteUnconstrained(numel(metaboliteUnconstrained)+1,1)=modelSBML.species(i).boundaryCondition; -0263 -0264 %For each metabolite retrieve the formula and the InChI code if -0265 %available First add the InChI code and the formula from the -0266 %InChI. This allows for overwriting the formula by setting the -0267 %actual formula field -0268 if ~isempty(modelSBML.species(i).annotation) -0269 %Get the formula if available -0270 startString='>InChI='; -0271 endString='</in:inchi>'; -0272 formStart=strfind(modelSBML.species(i).annotation,startString); -0273 if isempty(formStart) -0274 startString='InChI='; -0275 endString='"/>'; -0276 end -0277 formStart=strfind(modelSBML.species(i).annotation,startString); -0278 if ~isempty(formStart) -0279 formEnd=strfind(modelSBML.species(i).annotation,endString); -0280 formEndIndex=find(formEnd>formStart, 1 ); -0281 formula=modelSBML.species(i).annotation(formStart+numel(startString):formEnd(formEndIndex)-1); -0282 metaboliteInChI{numel(metaboliteInChI)+1,1}=formula; -0283 -0284 %The composition is most often present between the -0285 %first and second "/" in the model. In some simple -0286 %molecules, such as salts, there is no second "/". The -0287 %formula is then assumed to be to the end of the string -0288 compositionIndexes=strfind(formula,'/'); -0289 if numel(compositionIndexes)>1 -0290 metaboliteFormula{numel(metaboliteFormula)+1,1}=... -0291 formula(compositionIndexes(1)+1:compositionIndexes(2)-1); -0292 else -0293 if numel(compositionIndexes)==1 -0294 %Probably a simple molecule which can have only -0295 %one conformation -0296 metaboliteFormula{numel(metaboliteFormula)+1,1}=... -0297 formula(compositionIndexes(1)+1:numel(formula)); -0298 else -0299 metaboliteFormula{numel(metaboliteFormula)+1,1}=''; -0300 end -0301 end -0302 elseif isfield(modelSBML.species(i),'fbc_chemicalFormula') -0303 metaboliteInChI{numel(metaboliteInChI)+1,1}=''; -0304 if ~isempty(modelSBML.species(i).fbc_chemicalFormula) -0305 %Cannot extract InChi from formula, so remains -0306 %empty -0307 metaboliteFormula{numel(metaboliteFormula)+1,1}=modelSBML.species(i).fbc_chemicalFormula; -0308 else -0309 metaboliteFormula{numel(metaboliteFormula)+1,1}=''; -0310 end -0311 else -0312 metaboliteInChI{numel(metaboliteInChI)+1,1}=''; -0313 metaboliteFormula{numel(metaboliteFormula)+1,1}=''; -0314 end -0315 -0316 %Get Miriam info -0317 metMiriam=parseMiriam(modelSBML.species(i).annotation); -0318 metaboliteMiriams{numel(metaboliteMiriams)+1,1}=metMiriam; -0319 else -0320 metaboliteInChI{numel(metaboliteInChI)+1,1}=''; -0321 if isfield(modelSBML.species(i),'notes') -0322 metaboliteFormula{numel(metaboliteFormula)+1,1}=parseNote(modelSBML.species(i).notes,'FORMULA'); -0323 else -0324 metaboliteFormula{numel(metaboliteFormula)+1,1}=''; -0325 end -0326 metaboliteMiriams{numel(metaboliteMiriams)+1,1}=[]; -0327 end -0328 if ~isempty(modelSBML.species(i).notes) -0329 if ~isfield(modelSBML.species(i),'annotation') -0330 metaboliteFormula{numel(metaboliteFormula)+1,1}=parseNote(modelSBML.species(i).notes,'FORMULA'); -0331 end -0332 elseif ~isfield(modelSBML.species(i),'annotation') -0333 metaboliteFormula{numel(metaboliteFormula)+1,1}=''; -0334 end -0335 %Get SBO term -0336 if isfield(modelSBML.species(i),'sboTerm') && ~(modelSBML.species(i).sboTerm==-1) -0337 metSBOs(end+1,1) = modelSBML.species(i).sboTerm; -0338 end -0339 end -0340 -0341 %The following lines are executed regardless isSBML2COBRA setting -0342 if isempty(modelSBML.species(i).id) || ~strcmpi(modelSBML.species(i).id(1:2),'E_') -0343 if isempty(modelSBML.species(i).id) || ~strcmpi(modelSBML.species(i).id(1:3),'Cx_') -0344 %Remove trailing [compartment] from metabolite name if present -0345 metaboliteNames{end,1}=regexprep(metaboliteNames{end,1},regexCompNames,''); -0346 metaboliteNames{end,1}=metaboliteNames{end,1}; -0347 if isfield(modelSBML.species(i),'fbc_charge') -0348 if ~isempty(modelSBML.species(i).fbc_charge) && modelSBML.species(i).isSetfbc_charge -0349 metaboliteCharges(numel(metaboliteCharges)+1,1)=double(modelSBML.species(i).fbc_charge); -0350 else -0351 if isfield(modelSBML.species(i),'notes') -0352 if strfind(modelSBML.species(i).notes,'CHARGE') -0353 metaboliteCharges(numel(metaboliteCharges)+1,1)=str2double(parseNote(modelSBML.species(i).notes,'CHARGE')); -0354 else -0355 metaboliteCharges(numel(metaboliteCharges)+1,1)=NaN; -0356 end -0357 else -0358 metaboliteCharges(numel(metaboliteCharges)+1,1)=NaN; -0359 end -0360 end -0361 elseif isfield(modelSBML.species(i),'notes') -0362 if strfind(modelSBML.species(i).notes,'CHARGE') -0363 metaboliteCharges(numel(metaboliteCharges)+1,1)=str2double(parseNote(modelSBML.species(i).notes,'CHARGE')); -0364 else -0365 metaboliteCharges(numel(metaboliteCharges)+1,1)=NaN; -0366 end -0367 else -0368 metaboliteCharges(numel(metaboliteCharges)+1,1)=NaN; -0369 end -0370 %Additional information from FBC format Chemical formula -0371 if isfield(modelSBML.species(i),'fbc_chemicalFormula') -0372 if ~isempty(modelSBML.species(i).fbc_chemicalFormula) -0373 metaboliteFormula{numel(metaboliteFormula),1}=modelSBML.species(i).fbc_chemicalFormula; -0374 end -0375 end -0376 end -0377 end -0378 end -0379 -0380 %Add SBO terms to gene and metabolite miriam fields -0381 if numel(unique(geneSBOs)) > 1 % don't add if they're all identical -0382 for i = 1:numel(geneNames) -0383 geneMiriams{i} = addSBOtoMiriam(geneMiriams{i},geneSBOs(i)); -0384 end -0385 end -0386 if numel(unique(metSBOs)) > 1 -0387 for i = 1:numel(metaboliteNames) -0388 metaboliteMiriams{i} = addSBOtoMiriam(metaboliteMiriams{i},metSBOs(i)); -0389 end -0390 end -0391 -0392 %Retrieve info on reactions -0393 reactionNames=cell(numel(modelSBML.reaction),1); -0394 reactionIDs=cell(numel(modelSBML.reaction),1); -0395 subsystems=cell(numel(modelSBML.reaction),1); -0396 eccodes=cell(numel(modelSBML.reaction),1); -0397 eccodes(:,:)=cellstr(''); -0398 rxnconfidencescores=NaN(numel(modelSBML.reaction),1); -0399 rxnreferences=cell(numel(modelSBML.reaction),1); -0400 rxnreferences(:,:)=cellstr(''); -0401 rxnnotes=cell(numel(modelSBML.reaction),1); -0402 rxnnotes(:,:)=cellstr(''); -0403 grRules=cell(numel(modelSBML.reaction),1); -0404 grRules(:,:)=cellstr(''); -0405 grRulesFromModifier=grRules; -0406 rxnComps=zeros(numel(modelSBML.reaction),1); -0407 rxnMiriams=cell(numel(modelSBML.reaction),1); -0408 reactionReversibility=zeros(numel(modelSBML.reaction),1); -0409 reactionUB=zeros(numel(modelSBML.reaction),1); -0410 reactionLB=zeros(numel(modelSBML.reaction),1); -0411 reactionObjective=zeros(numel(modelSBML.reaction),1); -0412 -0413 %Construct the stoichiometric matrix while the reaction info is read -0414 S=zeros(numel(metaboliteIDs),numel(modelSBML.reaction)); -0415 -0416 counter=0; -0417 %If FBC, then bounds have parameter ids defined for the whole model -0418 if isfield(modelSBML,'parameter') -0419 parameter.name=cell(numel(modelSBML.parameter),1); -0420 parameter.name={modelSBML.parameter(:).id}'; -0421 parameter.value={modelSBML.parameter(:).value}'; -0422 end -0423 -0424 if isfield(modelSBML.reaction,'sboTerm') && numel(unique([modelSBML.reaction.sboTerm])) == 1 -0425 %If all the SBO terms are identical, don't add them to rxnMiriams -0426 modelSBML.reaction = rmfield(modelSBML.reaction,'sboTerm'); -0427 end -0428 -0429 for i=1:numel(modelSBML.reaction) -0430 -0431 %Check that the reaction doesn't produce a complex and nothing else. If -0432 %so, then jump to the next reaction. This is because I get the genes -0433 %for complexes from the names and not from the reactions that create -0434 %them. This only applies to the non-COBRA format -0435 if numel(modelSBML.reaction(i).product)==1 -0436 if length(modelSBML.reaction(i).product(1).species)>=3 -0437 if strcmp(modelSBML.reaction(i).product(1).species(1:3),'Cx_')==true -0438 continue; -0439 end -0440 end -0441 end -0442 -0443 %It didn't look like a gene complex-forming reaction -0444 counter=counter+1; -0445 -0446 reactionNames{counter}=modelSBML.reaction(i).name; -0447 -0448 reactionIDs{counter}=modelSBML.reaction(i).id; -0449 reactionReversibility(counter)=modelSBML.reaction(i).reversible; -0450 -0451 %If model is FBC, first get parameter of bound and then replace it with -0452 %the correct value. Probably faster with replace(), but this was only -0453 %introduced in Matlab R2016b -0454 if isfield(modelSBML.reaction(i),'fbc_lowerFluxBound') -0455 lb=modelSBML.reaction(i).fbc_lowerFluxBound; -0456 ub=modelSBML.reaction(i).fbc_upperFluxBound; -0457 for n=1:numel(parameter.value) -0458 lb=regexprep(lb,parameter.name(n),num2str(parameter.value{n})); -0459 ub=regexprep(ub,parameter.name(n),num2str(parameter.value{n})); -0460 end -0461 if isempty(lb) -0462 lb='-Inf'; -0463 end -0464 if isempty(ub) -0465 ub='Inf'; -0466 end -0467 reactionLB(counter)=str2num(lb); -0468 reactionUB(counter)=str2num(ub); -0469 %The order of these parameters should not be hard coded -0470 elseif isfield(modelSBML.reaction(i).kineticLaw,'parameter') -0471 reactionLB(counter)=modelSBML.reaction(i).kineticLaw.parameter(1).value; -0472 reactionUB(counter)=modelSBML.reaction(i).kineticLaw.parameter(2).value; -0473 reactionObjective(counter)=modelSBML.reaction(i).kineticLaw.parameter(3).value; -0474 else -0475 if reactionReversibility(counter)==true -0476 reactionLB(counter)=-inf; -0477 else -0478 reactionLB(counter)=0; -0479 end -0480 reactionUB(counter)=inf; -0481 reactionObjective(counter)=0; -0482 end -0483 -0484 %Find the associated gene if available -0485 %If FBC, get gene association data from corresponding fields -0486 if isfield(modelSBML.reaction(i),'fbc_geneProductAssociation') -0487 if ~isempty(modelSBML.reaction(i).fbc_geneProductAssociation) && ~isempty(modelSBML.reaction(i).fbc_geneProductAssociation.fbc_association) -0488 grRules{counter}=modelSBML.reaction(i).fbc_geneProductAssociation.fbc_association.fbc_association; -0489 end -0490 elseif isfield(modelSBML.reaction(i),'notes') -0491 %This section was previously executed only if isSBML2COBRA is true. Now -0492 %it will be executed, if 'GENE_ASSOCIATION' is found in -0493 %modelSBML.reaction(i).notes -0494 if strfind(modelSBML.reaction(i).notes,'GENE_ASSOCIATION') -0495 geneAssociation=parseNote(modelSBML.reaction(i).notes,'GENE_ASSOCIATION'); -0496 elseif strfind(modelSBML.reaction(i).notes,'GENE ASSOCIATION') -0497 geneAssociation=parseNote(modelSBML.reaction(i).notes,'GENE ASSOCIATION'); -0498 else -0499 geneAssociation=''; -0500 end -0501 if ~isempty(geneAssociation) -0502 %This adds the grRules. The gene list and rxnGeneMat are created -0503 %later -0504 grRules{counter}=geneAssociation; -0505 end -0506 end -0507 if isempty(grRules{counter}) && ~isempty(modelSBML.reaction(i).modifier) -0508 rules=''; -0509 for j=1:numel(modelSBML.reaction(i).modifier) -0510 modifier=modelSBML.reaction(i).modifier(j).species; -0511 if ~isempty(modifier) -0512 if strcmpi(modifier(1:2),'E_') -0513 index=find(strcmp(modifier,geneIDs)); -0514 %This should be unique and in the geneIDs list, -0515 %otherwise something is wrong -0516 if numel(index)~=1 -0517 EM=['Could not get the gene association data from reaction ' reactionIDs{i}]; -0518 dispEM(EM); -0519 end -0520 if ~isempty(rules) -0521 rules=[rules ' or (' geneNames{index} ')']; -0522 else -0523 rules=['(' geneNames{index} ')']; -0524 end -0525 elseif strcmp(modifier(1:2),'s_') -0526 index=find(strcmp(modifier,metaboliteIDs)); -0527 %This should be unique and in the geneIDs list, -0528 %otherwise something is wrong -0529 if numel(index)~=1 -0530 EM=['Could not get the gene association data from reaction ' reactionIDs{i}]; -0531 dispEM(EM); -0532 end -0533 if ~isempty(rules) -0534 rules=[rules ' or (' metaboliteIDs{index} ')']; -0535 else -0536 rules=['(' metaboliteIDs{index} ')']; -0537 end -0538 else -0539 %It seems to be a complex. Add the corresponding -0540 %genes from the name of the complex (not the -0541 %reaction that creates it) -0542 index=find(strcmp(modifier,complexIDs)); -0543 if numel(index)==1 -0544 if ~isempty(rules) -0545 rules=[rules ' or (' strrep(complexNames{index},':',' and ') ')']; -0546 else -0547 rules=['(' strrep(complexNames{index},':',' and ') ')']; -0548 end -0549 else -0550 %Could not find a complex -0551 EM=['Could not get the gene association data from reaction ' reactionIDs{i}]; -0552 dispEM(EM); -0553 end -0554 end -0555 end -0556 end -0557 grRules{counter}=rules; -0558 grRulesFromModifier{counter}=rules;%Backup copy for grRules, useful to parse Yeast 7.6 -0559 end -0560 -0561 %Add reaction compartment -0562 if isfield(modelSBML.reaction(i),'compartment') -0563 if ~isempty(modelSBML.reaction(i).compartment) -0564 rxnComp=modelSBML.reaction(i).compartment; -0565 else -0566 rxnComp=''; -0567 end -0568 elseif isfield(modelSBML.reaction(i),'notes') -0569 rxnComp=parseNote(modelSBML.reaction(i).notes,'COMPARTMENT'); -0570 end -0571 if ~isempty(rxnComp) -0572 %Find it in the compartment list -0573 [~, J]=ismember(rxnComp,compartmentIDs); -0574 rxnComps(counter)=J; -0575 end -0576 +0012 % removePrefix true if identifier prefixes should be removed when +0013 % loading the model: G_ for genes, R_ for reactions, +0014 % M_ for metabolites, and C_ for compartments. These are +0015 % only removed if all identifiers of a certain type +0016 % contain the prefix. (optional, default true) +0017 % supressWarnings true if warnings regarding the model structure should +0018 % be supressed (optional, default false) +0019 % +0020 % Output: +0021 % model +0022 % id model ID +0023 % name name of model contents +0024 % annotation additional information about model +0025 % rxns reaction ids +0026 % mets metabolite ids +0027 % S stoichiometric matrix +0028 % lb lower bounds +0029 % ub upper bounds +0030 % rev reversibility vector +0031 % c objective coefficients +0032 % b equality constraints for the metabolite equations +0033 % comps compartment ids +0034 % compNames compartment names +0035 % compOutside the id (as in comps) for the compartment +0036 % surrounding each of the compartments +0037 % compMiriams structure with MIRIAM information about the +0038 % compartments +0039 % rxnNames reaction description +0040 % rxnComps compartments for reactions +0041 % grRules reaction to gene rules in text form +0042 % rxnGeneMat reaction-to-gene mapping in sparse matrix form +0043 % subSystems subsystem name for each reaction +0044 % eccodes EC-codes for the reactions +0045 % rxnMiriams structure with MIRIAM information about the reactions +0046 % rxnNotes reaction notes +0047 % rxnReferences reaction references +0048 % rxnConfidenceScores reaction confidence scores +0049 % genes list of all genes +0050 % geneComps compartments for genes +0051 % geneMiriams structure with MIRIAM information about the genes +0052 % geneShortNames gene alternative names (e.g. ERG10) +0053 % proteins protein associated to each gene +0054 % metNames metabolite description +0055 % metComps compartments for metabolites +0056 % inchis InChI-codes for metabolites +0057 % metFormulas metabolite chemical formula +0058 % metMiriams structure with MIRIAM information about the metabolites +0059 % metCharges metabolite charge +0060 % unconstrained true if the metabolite is an exchange metabolite +0061 % +0062 % Note: A number of consistency checks are performed in order to ensure that the +0063 % model is valid. Take these warnings seriously and modify the model +0064 % structure to solve them. +0065 % +0066 % Usage: model = importModel(fileName, removeExcMets, removePrefix, supressWarnings) +0067 +0068 if nargin<1 || isempty(fileName) +0069 [fileName, pathName] = uigetfile({'*.xml;*.sbml'}, 'Please select the model file'); +0070 if fileName == 0 +0071 error('You should select a model file') +0072 else +0073 fileName = fullfile(pathName,fileName); +0074 end +0075 end +0076 fileName=char(fileName); +0077 if nargin<2 || isempty(removeExcMets) +0078 removeExcMets=true; +0079 end +0080 +0081 if nargin<3 || isempty(removePrefix) +0082 removePrefix=true; +0083 end +0084 +0085 if nargin<4 +0086 supressWarnings=false; +0087 end +0088 +0089 fileName=checkFileExistence(fileName,1); +0090 % If path contains non-ASCII characters, copy file to tempdir first, as +0091 % libSBML is known to have problems with this on Windows: +0092 % https://sbml.org/software/libsbml/libsbml-docs/known-pitfalls/#matlab-on-windows-has-issues-with-unicode-filenames +0093 if ispc && any(double(fileName)>128) +0094 [~,originalFile,ext] = fileparts(fileName); +0095 tempFile = fullfile(tempdir,[originalFile ext]); +0096 copyfile(fileName,tempFile); +0097 fileName = tempFile; +0098 end +0099 +0100 %This is to match the order of the fields to those you get from importing +0101 %from Excel +0102 model=[]; +0103 model.id=[]; +0104 model.name=[]; +0105 model.annotation=[]; +0106 model.rxns={}; +0107 model.mets={}; +0108 model.S=[]; +0109 model.lb=[]; +0110 model.ub=[]; +0111 model.rev=[]; +0112 model.c=[]; +0113 model.b=[]; +0114 model.comps={}; +0115 model.compNames={}; +0116 model.compOutside={}; +0117 model.compMiriams={}; +0118 model.rxnNames={}; +0119 model.rxnComps=[]; +0120 model.grRules={}; +0121 model.rxnGeneMat=[]; +0122 model.subSystems={}; +0123 model.eccodes={}; +0124 model.rxnMiriams={}; +0125 model.rxnNotes={}; +0126 model.rxnReferences={}; +0127 model.rxnConfidenceScores=[]; +0128 model.genes={}; +0129 model.geneComps=[]; +0130 model.geneMiriams={}; +0131 model.geneShortNames={}; +0132 model.proteins={}; +0133 model.metNames={}; +0134 model.metComps=[]; +0135 model.inchis={}; +0136 model.metFormulas={}; +0137 model.metMiriams={}; +0138 model.metCharges=[]; +0139 model.unconstrained=[]; +0140 +0141 %Load the model using libSBML +0142 [modelSBML,errorMsg] = TranslateSBML_RAVEN(fileName,0,0,[1 1]); +0143 if exist('tempFile','var') +0144 delete(tempFile) +0145 end +0146 +0147 if isempty(modelSBML) +0148 EM=['There is a problem with the SBML file. Try using the SBML Validator at http://sbml.org/Facilities/Validator.\nlibSBML reports: ', errorMsg.message]; +0149 dispEM(EM); +0150 end +0151 +0152 %Retrieve compartment names and IDs +0153 compartmentNames=cell(numel(modelSBML.compartment),1); +0154 compartmentIDs=cell(numel(modelSBML.compartment),1); +0155 compartmentOutside=cell(numel(modelSBML.compartment),1); +0156 compartmentMiriams=cell(numel(modelSBML.compartment),1); +0157 +0158 if isfield(modelSBML.compartment,'sboTerm') && numel(unique([modelSBML.compartment.sboTerm])) == 1 +0159 %If all the SBO terms are identical, don't add them to compMiriams +0160 modelSBML.compartment = rmfield(modelSBML.compartment,'sboTerm'); +0161 end +0162 +0163 for i=1:numel(modelSBML.compartment) +0164 compartmentNames{i}=modelSBML.compartment(i).name; +0165 compartmentIDs{i}=modelSBML.compartment(i).id; +0166 if isfield(modelSBML.compartment(i),'outside') +0167 if ~isempty(modelSBML.compartment(i).outside) +0168 compartmentOutside{i}=modelSBML.compartment(i).outside; +0169 else +0170 compartmentOutside{i}=''; +0171 end +0172 else +0173 compartmentOutside{i}=[]; +0174 end +0175 +0176 if isfield(modelSBML.compartment(i),'annotation') +0177 compartmentMiriams{i}=parseMiriam(modelSBML.compartment(i).annotation); +0178 else +0179 compartmentMiriams{i}=[]; +0180 end +0181 +0182 if isfield(modelSBML.compartment(i),'sboTerm') && ~(modelSBML.compartment(i).sboTerm==-1) +0183 compartmentMiriams{i} = addSBOtoMiriam(compartmentMiriams{i},modelSBML.compartment(i).sboTerm); +0184 end +0185 end +0186 +0187 %If there are no compartment names then use compartment id as name +0188 if all(cellfun(@isempty,compartmentNames)) +0189 compartmentNames=compartmentIDs; +0190 end +0191 +0192 %Retrieve info on metabolites, genes, complexes +0193 metaboliteNames={}; +0194 metaboliteIDs={}; +0195 metaboliteCompartments={}; +0196 metaboliteUnconstrained=[]; +0197 metaboliteFormula={}; +0198 metaboliteInChI={}; +0199 metaboliteMiriams={}; +0200 metaboliteCharges=[]; +0201 +0202 geneNames={}; +0203 geneIDs={}; +0204 geneMiriams={}; +0205 geneShortNames={}; +0206 proteins={}; +0207 geneCompartments={}; +0208 complexIDs={}; +0209 complexNames={}; +0210 +0211 %If the file is not a COBRA Toolbox model. According to the format +0212 %specified in the yeast consensus model both metabolites and genes are a +0213 %type of 'species'. The metabolites have names starting with 'M_' and genes +0214 %with 'E_' +0215 geneSBOs = []; +0216 metSBOs = []; +0217 %Regex of compartment names, later to be used to remove from metabolite +0218 %names if present as suffix. +0219 regexCompNames = ['\s?\[((' strjoin({modelSBML.compartment.name},')|(') '))\]$']; +0220 for i=1:numel(modelSBML.species) +0221 if length(modelSBML.species(i).id)>=2 && strcmpi(modelSBML.species(i).id(1:2),'E_') +0222 geneNames{numel(geneNames)+1,1}=modelSBML.species(i).name; +0223 +0224 %The "E_" is included in the ID. This is because it's only used +0225 %internally in this file and it makes the matching a little +0226 %smoother +0227 geneIDs{numel(geneIDs)+1,1}=modelSBML.species(i).id; +0228 geneCompartments{numel(geneCompartments)+1,1}=modelSBML.species(i).compartment; +0229 +0230 %Get Miriam structure +0231 if isfield(modelSBML.species(i),'annotation') +0232 %Get Miriam info +0233 geneMiriam=parseMiriam(modelSBML.species(i).annotation); +0234 geneMiriams{numel(geneMiriams)+1,1}=geneMiriam; +0235 else +0236 geneMiriams{numel(geneMiriams)+1,1}=[]; +0237 end +0238 +0239 %Protein short names (for example ERG10) are saved as SHORT +0240 %NAME: NAME in the notes-section of metabolites for SBML Level +0241 %2 and as PROTEIN_ASSOCIATION for each reaction in SBML Level 2 +0242 %COBRA Toolbox format. For now only the SHORT NAME is loaded +0243 %and no mapping takes place +0244 if isfield(modelSBML.species(i),'notes') +0245 geneShortNames{numel(geneShortNames)+1,1}=parseNote(modelSBML.species(i).notes,'SHORT NAME'); +0246 else +0247 geneShortNames{numel(geneShortNames)+1,1}=''; +0248 end +0249 +0250 %Get SBO term +0251 if isfield(modelSBML.species(i),'sboTerm') && ~(modelSBML.species(i).sboTerm==-1) +0252 geneSBOs(end+1,1) = modelSBML.species(i).sboTerm; +0253 end +0254 elseif length(modelSBML.species(i).id)>=2 && strcmpi(modelSBML.species(i).id(1:3),'Cx_') +0255 %If it's a complex keep the ID and name +0256 complexIDs=[complexIDs;modelSBML.species(i).id]; +0257 complexNames=[complexNames;modelSBML.species(i).name]; +0258 else +0259 %If it is not gene or complex, then it must be a metabolite +0260 metaboliteNames{numel(metaboliteNames)+1,1}=modelSBML.species(i).name; +0261 metaboliteIDs{numel(metaboliteIDs)+1,1}=modelSBML.species(i).id; +0262 metaboliteCompartments{numel(metaboliteCompartments)+1,1}=modelSBML.species(i).compartment; +0263 metaboliteUnconstrained(numel(metaboliteUnconstrained)+1,1)=modelSBML.species(i).boundaryCondition; +0264 +0265 %For each metabolite retrieve the formula and the InChI code if +0266 %available First add the InChI code and the formula from the +0267 %InChI. This allows for overwriting the formula by setting the +0268 %actual formula field +0269 if ~isempty(modelSBML.species(i).annotation) +0270 %Get the formula if available +0271 startString='>InChI='; +0272 endString='</in:inchi>'; +0273 formStart=strfind(modelSBML.species(i).annotation,startString); +0274 if isempty(formStart) +0275 startString='InChI='; +0276 endString='"/>'; +0277 end +0278 formStart=strfind(modelSBML.species(i).annotation,startString); +0279 if ~isempty(formStart) +0280 formEnd=strfind(modelSBML.species(i).annotation,endString); +0281 formEndIndex=find(formEnd>formStart, 1 ); +0282 formula=modelSBML.species(i).annotation(formStart+numel(startString):formEnd(formEndIndex)-1); +0283 metaboliteInChI{numel(metaboliteInChI)+1,1}=formula; +0284 +0285 %The composition is most often present between the +0286 %first and second "/" in the model. In some simple +0287 %molecules, such as salts, there is no second "/". The +0288 %formula is then assumed to be to the end of the string +0289 compositionIndexes=strfind(formula,'/'); +0290 if numel(compositionIndexes)>1 +0291 metaboliteFormula{numel(metaboliteFormula)+1,1}=... +0292 formula(compositionIndexes(1)+1:compositionIndexes(2)-1); +0293 else +0294 if numel(compositionIndexes)==1 +0295 %Probably a simple molecule which can have only +0296 %one conformation +0297 metaboliteFormula{numel(metaboliteFormula)+1,1}=... +0298 formula(compositionIndexes(1)+1:numel(formula)); +0299 else +0300 metaboliteFormula{numel(metaboliteFormula)+1,1}=''; +0301 end +0302 end +0303 elseif isfield(modelSBML.species(i),'fbc_chemicalFormula') +0304 metaboliteInChI{numel(metaboliteInChI)+1,1}=''; +0305 if ~isempty(modelSBML.species(i).fbc_chemicalFormula) +0306 %Cannot extract InChi from formula, so remains +0307 %empty +0308 metaboliteFormula{numel(metaboliteFormula)+1,1}=modelSBML.species(i).fbc_chemicalFormula; +0309 else +0310 metaboliteFormula{numel(metaboliteFormula)+1,1}=''; +0311 end +0312 else +0313 metaboliteInChI{numel(metaboliteInChI)+1,1}=''; +0314 metaboliteFormula{numel(metaboliteFormula)+1,1}=''; +0315 end +0316 +0317 %Get Miriam info +0318 metMiriam=parseMiriam(modelSBML.species(i).annotation); +0319 metaboliteMiriams{numel(metaboliteMiriams)+1,1}=metMiriam; +0320 else +0321 metaboliteInChI{numel(metaboliteInChI)+1,1}=''; +0322 if isfield(modelSBML.species(i),'notes') +0323 metaboliteFormula{numel(metaboliteFormula)+1,1}=parseNote(modelSBML.species(i).notes,'FORMULA'); +0324 else +0325 metaboliteFormula{numel(metaboliteFormula)+1,1}=''; +0326 end +0327 metaboliteMiriams{numel(metaboliteMiriams)+1,1}=[]; +0328 end +0329 if ~isempty(modelSBML.species(i).notes) +0330 if ~isfield(modelSBML.species(i),'annotation') +0331 metaboliteFormula{numel(metaboliteFormula)+1,1}=parseNote(modelSBML.species(i).notes,'FORMULA'); +0332 end +0333 elseif ~isfield(modelSBML.species(i),'annotation') +0334 metaboliteFormula{numel(metaboliteFormula)+1,1}=''; +0335 end +0336 %Get SBO term +0337 if isfield(modelSBML.species(i),'sboTerm') && ~(modelSBML.species(i).sboTerm==-1) +0338 metSBOs(end+1,1) = modelSBML.species(i).sboTerm; +0339 end +0340 end +0341 +0342 %The following lines are executed regardless isSBML2COBRA setting +0343 if isempty(modelSBML.species(i).id) || ~strcmpi(modelSBML.species(i).id(1:2),'E_') +0344 if isempty(modelSBML.species(i).id) || ~strcmpi(modelSBML.species(i).id(1:3),'Cx_') +0345 %Remove trailing [compartment] from metabolite name if present +0346 metaboliteNames{end,1}=regexprep(metaboliteNames{end,1},regexCompNames,''); +0347 metaboliteNames{end,1}=metaboliteNames{end,1}; +0348 if isfield(modelSBML.species(i),'fbc_charge') +0349 if ~isempty(modelSBML.species(i).fbc_charge) && modelSBML.species(i).isSetfbc_charge +0350 metaboliteCharges(numel(metaboliteCharges)+1,1)=double(modelSBML.species(i).fbc_charge); +0351 else +0352 if isfield(modelSBML.species(i),'notes') +0353 if strfind(modelSBML.species(i).notes,'CHARGE') +0354 metaboliteCharges(numel(metaboliteCharges)+1,1)=str2double(parseNote(modelSBML.species(i).notes,'CHARGE')); +0355 else +0356 metaboliteCharges(numel(metaboliteCharges)+1,1)=NaN; +0357 end +0358 else +0359 metaboliteCharges(numel(metaboliteCharges)+1,1)=NaN; +0360 end +0361 end +0362 elseif isfield(modelSBML.species(i),'notes') +0363 if strfind(modelSBML.species(i).notes,'CHARGE') +0364 metaboliteCharges(numel(metaboliteCharges)+1,1)=str2double(parseNote(modelSBML.species(i).notes,'CHARGE')); +0365 else +0366 metaboliteCharges(numel(metaboliteCharges)+1,1)=NaN; +0367 end +0368 else +0369 metaboliteCharges(numel(metaboliteCharges)+1,1)=NaN; +0370 end +0371 %Additional information from FBC format Chemical formula +0372 if isfield(modelSBML.species(i),'fbc_chemicalFormula') +0373 if ~isempty(modelSBML.species(i).fbc_chemicalFormula) +0374 metaboliteFormula{numel(metaboliteFormula),1}=modelSBML.species(i).fbc_chemicalFormula; +0375 end +0376 end +0377 end +0378 end +0379 end +0380 +0381 %Add SBO terms to gene and metabolite miriam fields +0382 if numel(unique(geneSBOs)) > 1 % don't add if they're all identical +0383 for i = 1:numel(geneNames) +0384 geneMiriams{i} = addSBOtoMiriam(geneMiriams{i},geneSBOs(i)); +0385 end +0386 end +0387 if numel(unique(metSBOs)) > 1 +0388 for i = 1:numel(metaboliteNames) +0389 metaboliteMiriams{i} = addSBOtoMiriam(metaboliteMiriams{i},metSBOs(i)); +0390 end +0391 end +0392 +0393 %Retrieve info on reactions +0394 reactionNames=cell(numel(modelSBML.reaction),1); +0395 reactionIDs=cell(numel(modelSBML.reaction),1); +0396 subsystems=cell(numel(modelSBML.reaction),1); +0397 eccodes=cell(numel(modelSBML.reaction),1); +0398 eccodes(:,:)=cellstr(''); +0399 rxnconfidencescores=NaN(numel(modelSBML.reaction),1); +0400 rxnreferences=cell(numel(modelSBML.reaction),1); +0401 rxnreferences(:,:)=cellstr(''); +0402 rxnnotes=cell(numel(modelSBML.reaction),1); +0403 rxnnotes(:,:)=cellstr(''); +0404 grRules=cell(numel(modelSBML.reaction),1); +0405 grRules(:,:)=cellstr(''); +0406 grRulesFromModifier=grRules; +0407 rxnComps=zeros(numel(modelSBML.reaction),1); +0408 rxnMiriams=cell(numel(modelSBML.reaction),1); +0409 reactionReversibility=zeros(numel(modelSBML.reaction),1); +0410 reactionUB=zeros(numel(modelSBML.reaction),1); +0411 reactionLB=zeros(numel(modelSBML.reaction),1); +0412 reactionObjective=zeros(numel(modelSBML.reaction),1); +0413 +0414 %Construct the stoichiometric matrix while the reaction info is read +0415 S=zeros(numel(metaboliteIDs),numel(modelSBML.reaction)); +0416 +0417 counter=0; +0418 %If FBC, then bounds have parameter ids defined for the whole model +0419 if isfield(modelSBML,'parameter') +0420 parameter.name=cell(numel(modelSBML.parameter),1); +0421 parameter.name={modelSBML.parameter(:).id}'; +0422 parameter.value={modelSBML.parameter(:).value}'; +0423 end +0424 +0425 if isfield(modelSBML.reaction,'sboTerm') && numel(unique([modelSBML.reaction.sboTerm])) == 1 +0426 %If all the SBO terms are identical, don't add them to rxnMiriams +0427 modelSBML.reaction = rmfield(modelSBML.reaction,'sboTerm'); +0428 end +0429 +0430 for i=1:numel(modelSBML.reaction) +0431 +0432 %Check that the reaction doesn't produce a complex and nothing else. If +0433 %so, then jump to the next reaction. This is because I get the genes +0434 %for complexes from the names and not from the reactions that create +0435 %them. This only applies to the non-COBRA format +0436 if numel(modelSBML.reaction(i).product)==1 +0437 if length(modelSBML.reaction(i).product(1).species)>=3 +0438 if strcmp(modelSBML.reaction(i).product(1).species(1:3),'Cx_')==true +0439 continue; +0440 end +0441 end +0442 end +0443 +0444 %It didn't look like a gene complex-forming reaction +0445 counter=counter+1; +0446 +0447 reactionNames{counter}=modelSBML.reaction(i).name; +0448 +0449 reactionIDs{counter}=modelSBML.reaction(i).id; +0450 reactionReversibility(counter)=modelSBML.reaction(i).reversible; +0451 +0452 %If model is FBC, first get parameter of bound and then replace it with +0453 %the correct value. Probably faster with replace(), but this was only +0454 %introduced in Matlab R2016b +0455 if isfield(modelSBML.reaction(i),'fbc_lowerFluxBound') +0456 lb=modelSBML.reaction(i).fbc_lowerFluxBound; +0457 ub=modelSBML.reaction(i).fbc_upperFluxBound; +0458 for n=1:numel(parameter.value) +0459 lb=regexprep(lb,parameter.name(n),num2str(parameter.value{n})); +0460 ub=regexprep(ub,parameter.name(n),num2str(parameter.value{n})); +0461 end +0462 if isempty(lb) +0463 lb='-Inf'; +0464 end +0465 if isempty(ub) +0466 ub='Inf'; +0467 end +0468 reactionLB(counter)=str2num(lb); +0469 reactionUB(counter)=str2num(ub); +0470 %The order of these parameters should not be hard coded +0471 elseif isfield(modelSBML.reaction(i).kineticLaw,'parameter') +0472 reactionLB(counter)=modelSBML.reaction(i).kineticLaw.parameter(1).value; +0473 reactionUB(counter)=modelSBML.reaction(i).kineticLaw.parameter(2).value; +0474 reactionObjective(counter)=modelSBML.reaction(i).kineticLaw.parameter(3).value; +0475 else +0476 if reactionReversibility(counter)==true +0477 reactionLB(counter)=-inf; +0478 else +0479 reactionLB(counter)=0; +0480 end +0481 reactionUB(counter)=inf; +0482 reactionObjective(counter)=0; +0483 end +0484 +0485 %Find the associated gene if available +0486 %If FBC, get gene association data from corresponding fields +0487 if isfield(modelSBML.reaction(i),'fbc_geneProductAssociation') +0488 if ~isempty(modelSBML.reaction(i).fbc_geneProductAssociation) && ~isempty(modelSBML.reaction(i).fbc_geneProductAssociation.fbc_association) +0489 grRules{counter}=modelSBML.reaction(i).fbc_geneProductAssociation.fbc_association.fbc_association; +0490 end +0491 elseif isfield(modelSBML.reaction(i),'notes') +0492 %This section was previously executed only if isSBML2COBRA is true. Now +0493 %it will be executed, if 'GENE_ASSOCIATION' is found in +0494 %modelSBML.reaction(i).notes +0495 if strfind(modelSBML.reaction(i).notes,'GENE_ASSOCIATION') +0496 geneAssociation=parseNote(modelSBML.reaction(i).notes,'GENE_ASSOCIATION'); +0497 elseif strfind(modelSBML.reaction(i).notes,'GENE ASSOCIATION') +0498 geneAssociation=parseNote(modelSBML.reaction(i).notes,'GENE ASSOCIATION'); +0499 else +0500 geneAssociation=''; +0501 end +0502 if ~isempty(geneAssociation) +0503 %This adds the grRules. The gene list and rxnGeneMat are created +0504 %later +0505 grRules{counter}=geneAssociation; +0506 end +0507 end +0508 if isempty(grRules{counter}) && ~isempty(modelSBML.reaction(i).modifier) +0509 rules=''; +0510 for j=1:numel(modelSBML.reaction(i).modifier) +0511 modifier=modelSBML.reaction(i).modifier(j).species; +0512 if ~isempty(modifier) +0513 if strcmpi(modifier(1:2),'E_') +0514 index=find(strcmp(modifier,geneIDs)); +0515 %This should be unique and in the geneIDs list, +0516 %otherwise something is wrong +0517 if numel(index)~=1 +0518 EM=['Could not get the gene association data from reaction ' reactionIDs{i}]; +0519 dispEM(EM); +0520 end +0521 if ~isempty(rules) +0522 rules=[rules ' or (' geneNames{index} ')']; +0523 else +0524 rules=['(' geneNames{index} ')']; +0525 end +0526 elseif strcmp(modifier(1:2),'s_') +0527 index=find(strcmp(modifier,metaboliteIDs)); +0528 %This should be unique and in the geneIDs list, +0529 %otherwise something is wrong +0530 if numel(index)~=1 +0531 EM=['Could not get the gene association data from reaction ' reactionIDs{i}]; +0532 dispEM(EM); +0533 end +0534 if ~isempty(rules) +0535 rules=[rules ' or (' metaboliteIDs{index} ')']; +0536 else +0537 rules=['(' metaboliteIDs{index} ')']; +0538 end +0539 else +0540 %It seems to be a complex. Add the corresponding +0541 %genes from the name of the complex (not the +0542 %reaction that creates it) +0543 index=find(strcmp(modifier,complexIDs)); +0544 if numel(index)==1 +0545 if ~isempty(rules) +0546 rules=[rules ' or (' strrep(complexNames{index},':',' and ') ')']; +0547 else +0548 rules=['(' strrep(complexNames{index},':',' and ') ')']; +0549 end +0550 else +0551 %Could not find a complex +0552 EM=['Could not get the gene association data from reaction ' reactionIDs{i}]; +0553 dispEM(EM); +0554 end +0555 end +0556 end +0557 end +0558 grRules{counter}=rules; +0559 grRulesFromModifier{counter}=rules;%Backup copy for grRules, useful to parse Yeast 7.6 +0560 end +0561 +0562 %Add reaction compartment +0563 if isfield(modelSBML.reaction(i),'compartment') +0564 if ~isempty(modelSBML.reaction(i).compartment) +0565 rxnComp=modelSBML.reaction(i).compartment; +0566 else +0567 rxnComp=''; +0568 end +0569 elseif isfield(modelSBML.reaction(i),'notes') +0570 rxnComp=parseNote(modelSBML.reaction(i).notes,'COMPARTMENT'); +0571 end +0572 if ~isempty(rxnComp) +0573 %Find it in the compartment list +0574 [~, J]=ismember(rxnComp,compartmentIDs); +0575 rxnComps(counter)=J; +0576 end 0577 -0578 miriamStruct=parseMiriam(modelSBML.reaction(i).annotation); -0579 rxnMiriams{counter}=miriamStruct; -0580 if isfield(modelSBML.reaction(i),'notes') -0581 subsystems{counter,1}=cellstr(parseNote(modelSBML.reaction(i).notes,'SUBSYSTEM')); -0582 subsystems{counter,1}(cellfun('isempty',subsystems{counter,1})) = []; -0583 if strfind(modelSBML.reaction(i).notes,'Confidence Level') -0584 confScore = parseNote(modelSBML.reaction(i).notes,'Confidence Level'); -0585 if isempty(confScore) -0586 confScore = 0; -0587 end -0588 rxnconfidencescores(counter)=str2double(confScore); -0589 end -0590 rxnreferences{counter,1}=parseNote(modelSBML.reaction(i).notes,'AUTHORS'); -0591 rxnnotes{counter,1}=parseNote(modelSBML.reaction(i).notes,'NOTES'); -0592 end -0593 -0594 %Get SBO terms -0595 if isfield(modelSBML.reaction(i),'sboTerm') && ~(modelSBML.reaction(i).sboTerm==-1) -0596 rxnMiriams{counter} = addSBOtoMiriam(rxnMiriams{counter}, modelSBML.reaction(i).sboTerm); -0597 end -0598 -0599 %Get ec-codes -0600 eccode=''; -0601 if ~isempty(modelSBML.reaction(i).annotation) -0602 if strfind(modelSBML.reaction(i).annotation,'urn:miriam:ec-code') -0603 eccode=parseAnnotation(modelSBML.reaction(i).annotation,'urn:miriam:',':','ec-code'); -0604 elseif strfind(modelSBML.reaction(i).annotation,'http://identifiers.org/ec-code') -0605 eccode=parseAnnotation(modelSBML.reaction(i).annotation,'http://identifiers.org/','/','ec-code'); -0606 elseif strfind(modelSBML.reaction(i).annotation,'https://identifiers.org/ec-code') -0607 eccode=parseAnnotation(modelSBML.reaction(i).annotation,'https://identifiers.org/','/','ec-code'); -0608 end -0609 elseif isfield(modelSBML.reaction(i),'notes') -0610 if strfind(modelSBML.reaction(i).notes,'EC Number') -0611 eccode=[eccode parseNote(modelSBML.reaction(i).notes,'EC Number')]; -0612 elseif strfind(modelSBML.reaction(i).notes,'PROTEIN_CLASS') -0613 eccode=[eccode parseNote(modelSBML.reaction(i).notes,'PROTEIN_CLASS')]; -0614 end -0615 end -0616 eccodes{counter}=eccode; -0617 -0618 %Add all reactants -0619 for j=1:numel(modelSBML.reaction(i).reactant) -0620 %Get the index of the metabolite in metaboliteIDs. External -0621 %metabolites will be removed at a later stage -0622 metIndex=find(strcmp(modelSBML.reaction(i).reactant(j).species,metaboliteIDs),1); -0623 if isempty(metIndex) -0624 EM=['Could not find metabolite ' modelSBML.reaction(i).reactant(j).species ' in reaction ' reactionIDs{counter}]; -0625 dispEM(EM); -0626 end -0627 S(metIndex,counter)=S(metIndex,counter)+modelSBML.reaction(i).reactant(j).stoichiometry*-1; -0628 end -0629 -0630 %Add all products -0631 for j=1:numel(modelSBML.reaction(i).product) -0632 %Get the index of the metabolite in metaboliteIDs. -0633 metIndex=find(strcmp(modelSBML.reaction(i).product(j).species,metaboliteIDs),1); -0634 if isempty(metIndex) -0635 EM=['Could not find metabolite ' modelSBML.reaction(i).product(j).species ' in reaction ' reactionIDs{counter}]; -0636 dispEM(EM); -0637 end -0638 S(metIndex,counter)=S(metIndex,counter)+modelSBML.reaction(i).product(j).stoichiometry; -0639 end -0640 end -0641 -0642 %if FBC, objective function is separately defined. Multiple objective -0643 %functions can be defined, one is set as active -0644 if isfield(modelSBML, 'fbc_activeObjective') -0645 obj=modelSBML.fbc_activeObjective; -0646 for i=1:numel(modelSBML.fbc_objective) -0647 if strcmp(obj,modelSBML.fbc_objective(i).fbc_id) -0648 if ~isempty(modelSBML.fbc_objective(i).fbc_fluxObjective) -0649 rxn=modelSBML.fbc_objective(i).fbc_fluxObjective.fbc_reaction; -0650 idx=find(ismember(reactionIDs,rxn)); -0651 reactionObjective(idx)=modelSBML.fbc_objective(i).fbc_fluxObjective.fbc_coefficient; -0652 end -0653 end -0654 end -0655 end -0656 -0657 %subSystems can be stored as groups instead of in annotations -0658 if isfield(modelSBML,'groups_group') -0659 for i=1:numel(modelSBML.groups_group) -0660 groupreactions={modelSBML.groups_group(i).groups_member(:).groups_idRef}; -0661 [~, idx] = ismember(groupreactions, reactionIDs); -0662 if any(idx) -0663 for j=1:numel(idx) -0664 if isempty(subsystems{idx(j)}) % First subsystem -0665 subsystems{idx(j)} = {modelSBML.groups_group(i).groups_name}; -0666 else % Consecutive subsystems: concatenate -0667 subsystems{idx(j)} = horzcat(subsystems{idx(j)}, modelSBML.groups_group(i).groups_name); -0668 end -0669 end -0670 end -0671 end -0672 end -0673 -0674 %Shrink the structures if complex-forming reactions had to be skipped -0675 reactionNames=reactionNames(1:counter); -0676 reactionIDs=reactionIDs(1:counter); -0677 subsystems=subsystems(1:counter); -0678 eccodes=eccodes(1:counter); -0679 rxnconfidencescores=rxnconfidencescores(1:counter); -0680 rxnreferences=rxnreferences(1:counter); -0681 rxnnotes=rxnnotes(1:counter); -0682 grRules=grRules(1:counter); -0683 rxnMiriams=rxnMiriams(1:counter); -0684 reactionReversibility=reactionReversibility(1:counter); -0685 reactionUB=reactionUB(1:counter); -0686 reactionLB=reactionLB(1:counter); -0687 reactionObjective=reactionObjective(1:counter); -0688 S=S(:,1:counter); -0689 -0690 model.name=modelSBML.name; -0691 model.id=modelSBML.id; -0692 model.rxns=reactionIDs; -0693 model.mets=metaboliteIDs; -0694 model.S=sparse(S); -0695 model.lb=reactionLB; -0696 model.ub=reactionUB; -0697 model.rev=reactionReversibility; -0698 model.c=reactionObjective; -0699 model.b=zeros(numel(metaboliteIDs),1); -0700 model.comps=compartmentIDs; -0701 model.compNames=compartmentNames; -0702 model.rxnConfidenceScores=rxnconfidencescores; -0703 model.rxnReferences=rxnreferences; -0704 model.rxnNotes=rxnnotes; -0705 -0706 %Load annotation if available. If there are several authors, only the first -0707 %author credentials are imported -0708 if isfield(modelSBML,'annotation') -0709 endString='</'; -0710 I=strfind(modelSBML.annotation,endString); -0711 J=strfind(modelSBML.annotation,'<vCard:Family>'); -0712 if any(J) -0713 model.annotation.familyName=modelSBML.annotation(J(1)+14:I(find(I>J(1),1))-1); -0714 end -0715 J=strfind(modelSBML.annotation,'<vCard:Given>'); -0716 if any(J) -0717 model.annotation.givenName=modelSBML.annotation(J(1)+13:I(find(I>J(1),1))-1); -0718 end -0719 J=strfind(modelSBML.annotation,'<vCard:EMAIL>'); -0720 if any(J) -0721 model.annotation.email=modelSBML.annotation(J(1)+13:I(find(I>J(1),1))-1); -0722 end -0723 J=strfind(modelSBML.annotation,'<vCard:Orgname>'); -0724 if any(J) -0725 model.annotation.organization=modelSBML.annotation(J(1)+15:I(find(I>J(1),1))-1); -0726 end -0727 endString='"/>'; -0728 I=strfind(modelSBML.annotation,endString); -0729 if strfind(modelSBML.annotation,'"urn:miriam:') -0730 J=strfind(modelSBML.annotation,'"urn:miriam:'); -0731 if any(J) -0732 model.annotation.taxonomy=modelSBML.annotation(J+12:I(find(I>J,1))-1); -0733 end -0734 else -0735 J=strfind(modelSBML.annotation,'"http://identifiers.org/'); -0736 if any(J) -0737 model.annotation.taxonomy=modelSBML.annotation(J+24:I(find(I>J,1))-1); -0738 else -0739 J=strfind(modelSBML.annotation,'"https://identifiers.org/'); -0740 if any(J) -0741 model.annotation.taxonomy=modelSBML.annotation(J+25:I(find(I>J,1))-1); -0742 end -0743 end -0744 end -0745 end -0746 if isfield(modelSBML,'notes') -0747 startString=strfind(modelSBML.notes,'xhtml">'); -0748 endString=strfind(modelSBML.notes,'</body>'); -0749 if any(startString) && any(endString) -0750 model.annotation.note=modelSBML.notes(startString+7:endString-1); -0751 model.annotation.note=regexprep(model.annotation.note,'<p>|</p>',''); -0752 model.annotation.note=strtrim(model.annotation.note); -0753 if regexp(model.annotation.note,'This file was generated using the exportModel function in RAVEN Toolbox \d\.\d and OutputSBML in libSBML') -0754 model.annotation=rmfield(model.annotation,'note'); % Default note added when running exportModel -0755 end -0756 end -0757 end -0758 -0759 if any(~cellfun(@isempty,compartmentOutside)) -0760 model.compOutside=compartmentOutside; -0761 end -0762 -0763 model.rxnNames=reactionNames; -0764 model.metNames=metaboliteNames; -0765 -0766 %Match the compartments for metabolites -0767 [~, J]=ismember(metaboliteCompartments,model.comps); -0768 model.metComps=J; -0769 -0770 %If any genes have been loaded (only for the new format) -0771 if ~isempty(geneNames) -0772 %In some rare cases geneNames may not necessarily be used in grRules. -0773 %That is true for Yeast 7.6. It's therefore important to change gene -0774 %systematic names to geneIDs in sophisticated way. Gene systematic -0775 %names are not unique, since exactly the same name may be in different -0776 %compartments -0777 if all(cellfun(@isempty,strfind(grRules,geneNames{1}))) -0778 geneShortNames=geneNames; -0779 %geneShortNames contain compartments as well, so these are removed -0780 geneShortNames=regexprep(geneShortNames,' \[.+$',''); -0781 %grRules obtained from modifier fields contain geneNames. These are -0782 %changed into geneIDs. grRulesFromModifier is a good way to have -0783 %geneIDs and rxns association when it's important to resolve -0784 %systematic name ambiguities -0785 grRulesFromModifier=regexprep(regexprep(grRulesFromModifier,'\[|\]','_'),regexprep(geneNames,'\[|\]','_'),geneIDs); -0786 grRules=regexprep(regexprep(grRules,'\[|\]','_'),regexprep(geneNames,'\[|\]','_'),geneIDs); -0787 -0788 %Yeast 7.6 contains several metabolites, which were used in gene -0789 %associations. For that reason, the list of species ID is created -0790 %and we then check whether any of them have kegg.genes annotation -0791 %thereby obtaining systematic gene names -0792 geneShortNames=vertcat(geneShortNames,metaboliteNames); -0793 geneIDs=vertcat(geneIDs,metaboliteIDs); -0794 geneSystNames=extractMiriam(vertcat(geneMiriams,metaboliteMiriams),'kegg.genes'); -0795 geneCompartments=vertcat(geneCompartments,metaboliteCompartments); -0796 geneMiriams=vertcat(geneMiriams,metaboliteMiriams); -0797 -0798 %Now we retain information for only these entries, which have -0799 %kegg.genes annotation -0800 geneShortNames=geneShortNames(~cellfun('isempty',geneSystNames)); -0801 geneIDs=geneIDs(~cellfun('isempty',geneSystNames)); -0802 geneSystNames=geneSystNames(~cellfun('isempty',geneSystNames)); -0803 geneCompartments=geneCompartments(~cellfun('isempty',geneSystNames)); -0804 geneMiriams=geneMiriams(~cellfun('isempty',geneSystNames)); -0805 %Now we reorder geneIDs and geneSystNames by geneSystNames string -0806 %length -0807 geneNames=geneIDs;%Backuping geneIDs, since we need unsorted order for later -0808 [~, Indx] = sort(cellfun('size', geneSystNames, 2), 'descend'); -0809 geneIDs = geneIDs(Indx); -0810 geneSystNames = geneSystNames(Indx); -0811 for i=1:numel(geneSystNames) -0812 for j=1:numel(grRules) -0813 if strfind(grRules{j},geneSystNames{i}) -0814 if ~isempty(grRules{j}) -0815 if sum(ismember(geneSystNames,geneSystNames{i}))==1 -0816 grRules{j}=regexprep(grRules{j},geneSystNames{i},geneIDs{i}); -0817 elseif sum(ismember(geneSystNames,geneSystNames{i}))>1 -0818 counter=0; -0819 ovrlpIDs=geneIDs(ismember(geneSystNames,geneSystNames{i})); -0820 for k=1:numel(ovrlpIDs) -0821 if strfind(grRulesFromModifier{j},ovrlpIDs{k}) -0822 counter=counter+1; -0823 grRules{j}=regexprep(grRules{j},geneSystNames{i},ovrlpIDs{k}); -0824 end -0825 if counter>1 -0826 EM=['Gene association is ambiguous for reaction ' modelSBML.reaction(j).id]; -0827 dispEM(EM); -0828 end -0829 end -0830 end -0831 end -0832 end -0833 end -0834 end -0835 end -0836 model.genes=geneNames; -0837 model.grRules=grRules; -0838 [grRules,rxnGeneMat] = standardizeGrRules(model,true); -0839 model.grRules = grRules; -0840 model.rxnGeneMat = rxnGeneMat; -0841 -0842 %Match the compartments for genes -0843 [~, J]=ismember(geneCompartments,model.comps); -0844 model.geneComps=J; -0845 else -0846 if ~all(cellfun(@isempty,grRules)) -0847 %If fbc_geneProduct exists, follow the specified gene order, such -0848 %that matching geneShortNames in function below will work -0849 if isfield(modelSBML,'fbc_geneProduct') -0850 genes={modelSBML.fbc_geneProduct.fbc_id}; -0851 -0852 %Get gene Miriams if they were not retrieved above (this occurs -0853 %when genes are stored as fbc_geneProduct instead of species) -0854 if isempty(geneMiriams) -0855 geneMiriams = cell(numel(genes),1); -0856 if isfield(modelSBML.fbc_geneProduct,'sboTerm') && numel(unique([modelSBML.fbc_geneProduct.sboTerm])) == 1 -0857 %If all the SBO terms are identical, don't add them to geneMiriams -0858 modelSBML.fbc_geneProduct = rmfield(modelSBML.fbc_geneProduct,'sboTerm'); -0859 end -0860 for i = 1:numel(genes) -0861 geneMiriams{i}=parseMiriam(modelSBML.fbc_geneProduct(i).annotation); -0862 if isfield(modelSBML.fbc_geneProduct(i),'sboTerm') && ~(modelSBML.fbc_geneProduct(i).sboTerm==-1) -0863 geneMiriams{i} = addSBOtoMiriam(geneMiriams{i},modelSBML.fbc_geneProduct(i).sboTerm); -0864 end -0865 end -0866 end -0867 proteins={modelSBML.fbc_geneProduct.fbc_name}; -0868 else -0869 genes=getGeneList(grRules); -0870 end -0871 model.genes=genes; -0872 model.grRules=grRules; -0873 [grRules,rxnGeneMat] = standardizeGrRules(model,true); -0874 model.grRules = grRules; -0875 model.rxnGeneMat = rxnGeneMat; -0876 end -0877 end -0878 -0879 if all(cellfun(@isempty,geneShortNames)) -0880 if isfield(modelSBML,'fbc_geneProduct') -0881 for i=1:numel(genes) -0882 if ~isempty(modelSBML.fbc_geneProduct(i).fbc_label) -0883 geneShortNames{i,1}=modelSBML.fbc_geneProduct(i).fbc_label; -0884 elseif ~isempty(modelSBML.fbc_geneProduct(i).fbc_name) -0885 geneShortNames{i,1}=modelSBML.fbc_geneProduct(i).fbc_name; -0886 else -0887 geneShortNames{i,1}=''; -0888 end -0889 end -0890 end -0891 end -0892 -0893 %If any InChIs have been loaded -0894 if any(~cellfun(@isempty,metaboliteInChI)) -0895 model.inchis=metaboliteInChI; -0896 end -0897 -0898 %If any formulas have been loaded -0899 if any(~cellfun(@isempty,metaboliteFormula)) -0900 model.metFormulas=metaboliteFormula; -0901 end -0902 -0903 %If any charges have been loaded -0904 if ~isempty(metaboliteCharges) -0905 model.metCharges=metaboliteCharges; -0906 end -0907 -0908 %If any gene short names have been loaded -0909 if any(~cellfun(@isempty,geneShortNames)) -0910 model.geneShortNames=geneShortNames; -0911 end -0912 -0913 %If any Miriam strings for compartments have been loaded -0914 if any(~cellfun(@isempty,compartmentMiriams)) -0915 model.compMiriams=compartmentMiriams; -0916 end -0917 -0918 %If any Miriam strings for metabolites have been loaded -0919 if any(~cellfun(@isempty,metaboliteMiriams)) -0920 model.metMiriams=metaboliteMiriams; -0921 end -0922 -0923 %If any subsystems have been loaded -0924 if any(~cellfun(@isempty,subsystems)) -0925 model.subSystems=subsystems; -0926 end -0927 if any(rxnComps) -0928 if all(rxnComps) -0929 model.rxnComps=rxnComps; -0930 else -0931 if supressWarnings==false -0932 EM='The compartments for the following reactions could not be matched. Ignoring reaction compartment information'; -0933 dispEM(EM,false,model.rxns(rxnComps==0)); -0934 end -0935 end -0936 end -0937 -0938 %If any ec-codes have been loaded -0939 if any(~cellfun(@isempty,eccodes)) -0940 model.eccodes=eccodes; -0941 end -0942 -0943 %If any Miriam strings for reactions have been loaded -0944 if any(~cellfun(@isempty,rxnMiriams)) -0945 model.rxnMiriams=rxnMiriams; -0946 end -0947 -0948 %If any Miriam strings for genes have been loaded -0949 if any(~cellfun(@isempty,geneMiriams)) -0950 model.geneMiriams=geneMiriams; -0951 end -0952 -0953 %If any protein strings have been loaded -0954 if any(~cellfun(@isempty,proteins)) -0955 proteins = reshape(proteins,[],1); -0956 model.proteins=proteins; -0957 end -0958 -0959 model.unconstrained=metaboliteUnconstrained; -0960 -0961 %Convert SBML IDs back into their original strings. Here we are using part -0962 %from convertSBMLID, originating from the COBRA Toolbox -0963 model.rxns=regexprep(model.rxns,'__([0-9]+)__','${char(str2num($1))}'); -0964 model.mets=regexprep(model.mets,'__([0-9]+)__','${char(str2num($1))}'); -0965 model.comps=regexprep(model.comps,'__([0-9]+)__','${char(str2num($1))}'); -0966 model.grRules=regexprep(model.grRules,'__([0-9]+)__','${char(str2num($1))}'); -0967 model.genes=regexprep(model.genes,'__([0-9]+)__','${char(str2num($1))}'); -0968 model.id=regexprep(model.id,'__([0-9]+)__','${char(str2num($1))}'); -0969 -0970 if COBRAstyle -0971 model=removeCOBRAstylePrefixes(model); -0972 else -0973 hasCOBRAids(1) = all(startsWith(model.rxns,'R_')); -0974 hasCOBRAids(2) = all(startsWith(model.mets,'M_')); -0975 hasCOBRAids(3) = all(startsWith(model.comps,'C_')); -0976 hasCOBRAids(4) = all(startsWith(model.genes,'G_')); -0977 if any(hasCOBRAids) -0978 hasCOBRAidsMsg = {'model.rxns (R_ prefix)',... -0979 'model.mets (M_ prefix)',... -0980 'model.comps (C_ prefix)',... -0981 'model.genes (G_ prefix)'}; -0982 hasCOBRAidsMsg(~hasCOBRAids) = []; -0983 printOrange(['COBRA style identifier prefixes are found in: "' ... -0984 strjoin(hasCOBRAidsMsg,'"; "') '". Since RAVEN 2.10.0, identifiers ' ... -0985 'are by default imported "as-is". If you do prefer to remove these ' ... -0986 'identifier prefixes, run "removeCOBRAstylePrefixes" on the ' ... -0987 'imported model, or directly run importModel with COBRAstyle as true ' ... -0988 'Example: importModel(''filename.xml'', [], true);\n']); -0989 end +0578 +0579 miriamStruct=parseMiriam(modelSBML.reaction(i).annotation); +0580 rxnMiriams{counter}=miriamStruct; +0581 if isfield(modelSBML.reaction(i),'notes') +0582 subsystems{counter,1}=cellstr(parseNote(modelSBML.reaction(i).notes,'SUBSYSTEM')); +0583 subsystems{counter,1}(cellfun('isempty',subsystems{counter,1})) = []; +0584 if strfind(modelSBML.reaction(i).notes,'Confidence Level') +0585 confScore = parseNote(modelSBML.reaction(i).notes,'Confidence Level'); +0586 if isempty(confScore) +0587 confScore = 0; +0588 end +0589 rxnconfidencescores(counter)=str2double(confScore); +0590 end +0591 rxnreferences{counter,1}=parseNote(modelSBML.reaction(i).notes,'AUTHORS'); +0592 rxnnotes{counter,1}=parseNote(modelSBML.reaction(i).notes,'NOTES'); +0593 end +0594 +0595 %Get SBO terms +0596 if isfield(modelSBML.reaction(i),'sboTerm') && ~(modelSBML.reaction(i).sboTerm==-1) +0597 rxnMiriams{counter} = addSBOtoMiriam(rxnMiriams{counter}, modelSBML.reaction(i).sboTerm); +0598 end +0599 +0600 %Get ec-codes +0601 eccode=''; +0602 if ~isempty(modelSBML.reaction(i).annotation) +0603 if strfind(modelSBML.reaction(i).annotation,'urn:miriam:ec-code') +0604 eccode=parseAnnotation(modelSBML.reaction(i).annotation,'urn:miriam:',':','ec-code'); +0605 elseif strfind(modelSBML.reaction(i).annotation,'http://identifiers.org/ec-code') +0606 eccode=parseAnnotation(modelSBML.reaction(i).annotation,'http://identifiers.org/','/','ec-code'); +0607 elseif strfind(modelSBML.reaction(i).annotation,'https://identifiers.org/ec-code') +0608 eccode=parseAnnotation(modelSBML.reaction(i).annotation,'https://identifiers.org/','/','ec-code'); +0609 end +0610 elseif isfield(modelSBML.reaction(i),'notes') +0611 if strfind(modelSBML.reaction(i).notes,'EC Number') +0612 eccode=[eccode parseNote(modelSBML.reaction(i).notes,'EC Number')]; +0613 elseif strfind(modelSBML.reaction(i).notes,'PROTEIN_CLASS') +0614 eccode=[eccode parseNote(modelSBML.reaction(i).notes,'PROTEIN_CLASS')]; +0615 end +0616 end +0617 eccodes{counter}=eccode; +0618 +0619 %Add all reactants +0620 for j=1:numel(modelSBML.reaction(i).reactant) +0621 %Get the index of the metabolite in metaboliteIDs. External +0622 %metabolites will be removed at a later stage +0623 metIndex=find(strcmp(modelSBML.reaction(i).reactant(j).species,metaboliteIDs),1); +0624 if isempty(metIndex) +0625 EM=['Could not find metabolite ' modelSBML.reaction(i).reactant(j).species ' in reaction ' reactionIDs{counter}]; +0626 dispEM(EM); +0627 end +0628 S(metIndex,counter)=S(metIndex,counter)+modelSBML.reaction(i).reactant(j).stoichiometry*-1; +0629 end +0630 +0631 %Add all products +0632 for j=1:numel(modelSBML.reaction(i).product) +0633 %Get the index of the metabolite in metaboliteIDs. +0634 metIndex=find(strcmp(modelSBML.reaction(i).product(j).species,metaboliteIDs),1); +0635 if isempty(metIndex) +0636 EM=['Could not find metabolite ' modelSBML.reaction(i).product(j).species ' in reaction ' reactionIDs{counter}]; +0637 dispEM(EM); +0638 end +0639 S(metIndex,counter)=S(metIndex,counter)+modelSBML.reaction(i).product(j).stoichiometry; +0640 end +0641 end +0642 +0643 %if FBC, objective function is separately defined. Multiple objective +0644 %functions can be defined, one is set as active +0645 if isfield(modelSBML, 'fbc_activeObjective') +0646 obj=modelSBML.fbc_activeObjective; +0647 for i=1:numel(modelSBML.fbc_objective) +0648 if strcmp(obj,modelSBML.fbc_objective(i).fbc_id) +0649 if ~isempty(modelSBML.fbc_objective(i).fbc_fluxObjective) +0650 rxn=modelSBML.fbc_objective(i).fbc_fluxObjective.fbc_reaction; +0651 idx=find(ismember(reactionIDs,rxn)); +0652 reactionObjective(idx)=modelSBML.fbc_objective(i).fbc_fluxObjective.fbc_coefficient; +0653 end +0654 end +0655 end +0656 end +0657 +0658 %subSystems can be stored as groups instead of in annotations +0659 if isfield(modelSBML,'groups_group') +0660 for i=1:numel(modelSBML.groups_group) +0661 groupreactions={modelSBML.groups_group(i).groups_member(:).groups_idRef}; +0662 [~, idx] = ismember(groupreactions, reactionIDs); +0663 if any(idx) +0664 for j=1:numel(idx) +0665 if isempty(subsystems{idx(j)}) % First subsystem +0666 subsystems{idx(j)} = {modelSBML.groups_group(i).groups_name}; +0667 else % Consecutive subsystems: concatenate +0668 subsystems{idx(j)} = horzcat(subsystems{idx(j)}, modelSBML.groups_group(i).groups_name); +0669 end +0670 end +0671 end +0672 end +0673 end +0674 +0675 %Shrink the structures if complex-forming reactions had to be skipped +0676 reactionNames=reactionNames(1:counter); +0677 reactionIDs=reactionIDs(1:counter); +0678 subsystems=subsystems(1:counter); +0679 eccodes=eccodes(1:counter); +0680 rxnconfidencescores=rxnconfidencescores(1:counter); +0681 rxnreferences=rxnreferences(1:counter); +0682 rxnnotes=rxnnotes(1:counter); +0683 grRules=grRules(1:counter); +0684 rxnMiriams=rxnMiriams(1:counter); +0685 reactionReversibility=reactionReversibility(1:counter); +0686 reactionUB=reactionUB(1:counter); +0687 reactionLB=reactionLB(1:counter); +0688 reactionObjective=reactionObjective(1:counter); +0689 S=S(:,1:counter); +0690 +0691 model.name=modelSBML.name; +0692 model.id=modelSBML.id; +0693 model.rxns=reactionIDs; +0694 model.mets=metaboliteIDs; +0695 model.S=sparse(S); +0696 model.lb=reactionLB; +0697 model.ub=reactionUB; +0698 model.rev=reactionReversibility; +0699 model.c=reactionObjective; +0700 model.b=zeros(numel(metaboliteIDs),1); +0701 model.comps=compartmentIDs; +0702 model.compNames=compartmentNames; +0703 model.rxnConfidenceScores=rxnconfidencescores; +0704 model.rxnReferences=rxnreferences; +0705 model.rxnNotes=rxnnotes; +0706 +0707 %Load annotation if available. If there are several authors, only the first +0708 %author credentials are imported +0709 if isfield(modelSBML,'annotation') +0710 endString='</'; +0711 I=strfind(modelSBML.annotation,endString); +0712 J=strfind(modelSBML.annotation,'<vCard:Family>'); +0713 if any(J) +0714 model.annotation.familyName=modelSBML.annotation(J(1)+14:I(find(I>J(1),1))-1); +0715 end +0716 J=strfind(modelSBML.annotation,'<vCard:Given>'); +0717 if any(J) +0718 model.annotation.givenName=modelSBML.annotation(J(1)+13:I(find(I>J(1),1))-1); +0719 end +0720 J=strfind(modelSBML.annotation,'<vCard:EMAIL>'); +0721 if any(J) +0722 model.annotation.email=modelSBML.annotation(J(1)+13:I(find(I>J(1),1))-1); +0723 end +0724 J=strfind(modelSBML.annotation,'<vCard:Orgname>'); +0725 if any(J) +0726 model.annotation.organization=modelSBML.annotation(J(1)+15:I(find(I>J(1),1))-1); +0727 end +0728 endString='"/>'; +0729 I=strfind(modelSBML.annotation,endString); +0730 if strfind(modelSBML.annotation,'"urn:miriam:') +0731 J=strfind(modelSBML.annotation,'"urn:miriam:'); +0732 if any(J) +0733 model.annotation.taxonomy=modelSBML.annotation(J+12:I(find(I>J,1))-1); +0734 end +0735 else +0736 J=strfind(modelSBML.annotation,'"http://identifiers.org/'); +0737 if any(J) +0738 model.annotation.taxonomy=modelSBML.annotation(J+24:I(find(I>J,1))-1); +0739 else +0740 J=strfind(modelSBML.annotation,'"https://identifiers.org/'); +0741 if any(J) +0742 model.annotation.taxonomy=modelSBML.annotation(J+25:I(find(I>J,1))-1); +0743 end +0744 end +0745 end +0746 end +0747 if isfield(modelSBML,'notes') +0748 startString=strfind(modelSBML.notes,'xhtml">'); +0749 endString=strfind(modelSBML.notes,'</body>'); +0750 if any(startString) && any(endString) +0751 model.annotation.note=modelSBML.notes(startString+7:endString-1); +0752 model.annotation.note=regexprep(model.annotation.note,'<p>|</p>',''); +0753 model.annotation.note=strtrim(model.annotation.note); +0754 if regexp(model.annotation.note,'This file was generated using the exportModel function in RAVEN Toolbox \d\.\d and OutputSBML in libSBML') +0755 model.annotation=rmfield(model.annotation,'note'); % Default note added when running exportModel +0756 end +0757 end +0758 end +0759 +0760 if any(~cellfun(@isempty,compartmentOutside)) +0761 model.compOutside=compartmentOutside; +0762 end +0763 +0764 model.rxnNames=reactionNames; +0765 model.metNames=metaboliteNames; +0766 +0767 %Match the compartments for metabolites +0768 [~, J]=ismember(metaboliteCompartments,model.comps); +0769 model.metComps=J; +0770 +0771 %If any genes have been loaded (only for the new format) +0772 if ~isempty(geneNames) +0773 %In some rare cases geneNames may not necessarily be used in grRules. +0774 %That is true for Yeast 7.6. It's therefore important to change gene +0775 %systematic names to geneIDs in sophisticated way. Gene systematic +0776 %names are not unique, since exactly the same name may be in different +0777 %compartments +0778 if all(cellfun(@isempty,strfind(grRules,geneNames{1}))) +0779 geneShortNames=geneNames; +0780 %geneShortNames contain compartments as well, so these are removed +0781 geneShortNames=regexprep(geneShortNames,' \[.+$',''); +0782 %grRules obtained from modifier fields contain geneNames. These are +0783 %changed into geneIDs. grRulesFromModifier is a good way to have +0784 %geneIDs and rxns association when it's important to resolve +0785 %systematic name ambiguities +0786 grRulesFromModifier=regexprep(regexprep(grRulesFromModifier,'\[|\]','_'),regexprep(geneNames,'\[|\]','_'),geneIDs); +0787 grRules=regexprep(regexprep(grRules,'\[|\]','_'),regexprep(geneNames,'\[|\]','_'),geneIDs); +0788 +0789 %Yeast 7.6 contains several metabolites, which were used in gene +0790 %associations. For that reason, the list of species ID is created +0791 %and we then check whether any of them have kegg.genes annotation +0792 %thereby obtaining systematic gene names +0793 geneShortNames=vertcat(geneShortNames,metaboliteNames); +0794 geneIDs=vertcat(geneIDs,metaboliteIDs); +0795 geneSystNames=extractMiriam(vertcat(geneMiriams,metaboliteMiriams),'kegg.genes'); +0796 geneCompartments=vertcat(geneCompartments,metaboliteCompartments); +0797 geneMiriams=vertcat(geneMiriams,metaboliteMiriams); +0798 +0799 %Now we retain information for only these entries, which have +0800 %kegg.genes annotation +0801 geneShortNames=geneShortNames(~cellfun('isempty',geneSystNames)); +0802 geneIDs=geneIDs(~cellfun('isempty',geneSystNames)); +0803 geneSystNames=geneSystNames(~cellfun('isempty',geneSystNames)); +0804 geneCompartments=geneCompartments(~cellfun('isempty',geneSystNames)); +0805 geneMiriams=geneMiriams(~cellfun('isempty',geneSystNames)); +0806 %Now we reorder geneIDs and geneSystNames by geneSystNames string +0807 %length +0808 geneNames=geneIDs;%Backuping geneIDs, since we need unsorted order for later +0809 [~, Indx] = sort(cellfun('size', geneSystNames, 2), 'descend'); +0810 geneIDs = geneIDs(Indx); +0811 geneSystNames = geneSystNames(Indx); +0812 for i=1:numel(geneSystNames) +0813 for j=1:numel(grRules) +0814 if strfind(grRules{j},geneSystNames{i}) +0815 if ~isempty(grRules{j}) +0816 if sum(ismember(geneSystNames,geneSystNames{i}))==1 +0817 grRules{j}=regexprep(grRules{j},geneSystNames{i},geneIDs{i}); +0818 elseif sum(ismember(geneSystNames,geneSystNames{i}))>1 +0819 counter=0; +0820 ovrlpIDs=geneIDs(ismember(geneSystNames,geneSystNames{i})); +0821 for k=1:numel(ovrlpIDs) +0822 if strfind(grRulesFromModifier{j},ovrlpIDs{k}) +0823 counter=counter+1; +0824 grRules{j}=regexprep(grRules{j},geneSystNames{i},ovrlpIDs{k}); +0825 end +0826 if counter>1 +0827 EM=['Gene association is ambiguous for reaction ' modelSBML.reaction(j).id]; +0828 dispEM(EM); +0829 end +0830 end +0831 end +0832 end +0833 end +0834 end +0835 end +0836 end +0837 model.genes=geneNames; +0838 model.grRules=grRules; +0839 [grRules,rxnGeneMat] = standardizeGrRules(model,true); +0840 model.grRules = grRules; +0841 model.rxnGeneMat = rxnGeneMat; +0842 +0843 %Match the compartments for genes +0844 [~, J]=ismember(geneCompartments,model.comps); +0845 model.geneComps=J; +0846 else +0847 if ~all(cellfun(@isempty,grRules)) +0848 %If fbc_geneProduct exists, follow the specified gene order, such +0849 %that matching geneShortNames in function below will work +0850 if isfield(modelSBML,'fbc_geneProduct') +0851 genes={modelSBML.fbc_geneProduct.fbc_id}; +0852 +0853 %Get gene Miriams if they were not retrieved above (this occurs +0854 %when genes are stored as fbc_geneProduct instead of species) +0855 if isempty(geneMiriams) +0856 geneMiriams = cell(numel(genes),1); +0857 if isfield(modelSBML.fbc_geneProduct,'sboTerm') && numel(unique([modelSBML.fbc_geneProduct.sboTerm])) == 1 +0858 %If all the SBO terms are identical, don't add them to geneMiriams +0859 modelSBML.fbc_geneProduct = rmfield(modelSBML.fbc_geneProduct,'sboTerm'); +0860 end +0861 for i = 1:numel(genes) +0862 geneMiriams{i}=parseMiriam(modelSBML.fbc_geneProduct(i).annotation); +0863 if isfield(modelSBML.fbc_geneProduct(i),'sboTerm') && ~(modelSBML.fbc_geneProduct(i).sboTerm==-1) +0864 geneMiriams{i} = addSBOtoMiriam(geneMiriams{i},modelSBML.fbc_geneProduct(i).sboTerm); +0865 end +0866 end +0867 end +0868 proteins={modelSBML.fbc_geneProduct.fbc_name}; +0869 else +0870 genes=getGeneList(grRules); +0871 end +0872 model.genes=genes; +0873 model.grRules=grRules; +0874 [grRules,rxnGeneMat] = standardizeGrRules(model,true); +0875 model.grRules = grRules; +0876 model.rxnGeneMat = rxnGeneMat; +0877 end +0878 end +0879 +0880 if all(cellfun(@isempty,geneShortNames)) +0881 if isfield(modelSBML,'fbc_geneProduct') +0882 for i=1:numel(genes) +0883 if ~isempty(modelSBML.fbc_geneProduct(i).fbc_label) +0884 geneShortNames{i,1}=modelSBML.fbc_geneProduct(i).fbc_label; +0885 elseif ~isempty(modelSBML.fbc_geneProduct(i).fbc_name) +0886 geneShortNames{i,1}=modelSBML.fbc_geneProduct(i).fbc_name; +0887 else +0888 geneShortNames{i,1}=''; +0889 end +0890 end +0891 end +0892 end +0893 +0894 %If any InChIs have been loaded +0895 if any(~cellfun(@isempty,metaboliteInChI)) +0896 model.inchis=metaboliteInChI; +0897 end +0898 +0899 %If any formulas have been loaded +0900 if any(~cellfun(@isempty,metaboliteFormula)) +0901 model.metFormulas=metaboliteFormula; +0902 end +0903 +0904 %If any charges have been loaded +0905 if ~isempty(metaboliteCharges) +0906 model.metCharges=metaboliteCharges; +0907 end +0908 +0909 %If any gene short names have been loaded +0910 if any(~cellfun(@isempty,geneShortNames)) +0911 model.geneShortNames=geneShortNames; +0912 end +0913 +0914 %If any Miriam strings for compartments have been loaded +0915 if any(~cellfun(@isempty,compartmentMiriams)) +0916 model.compMiriams=compartmentMiriams; +0917 end +0918 +0919 %If any Miriam strings for metabolites have been loaded +0920 if any(~cellfun(@isempty,metaboliteMiriams)) +0921 model.metMiriams=metaboliteMiriams; +0922 end +0923 +0924 %If any subsystems have been loaded +0925 if any(~cellfun(@isempty,subsystems)) +0926 model.subSystems=subsystems; +0927 end +0928 if any(rxnComps) +0929 if all(rxnComps) +0930 model.rxnComps=rxnComps; +0931 else +0932 if supressWarnings==false +0933 EM='The compartments for the following reactions could not be matched. Ignoring reaction compartment information'; +0934 dispEM(EM,false,model.rxns(rxnComps==0)); +0935 end +0936 end +0937 end +0938 +0939 %If any ec-codes have been loaded +0940 if any(~cellfun(@isempty,eccodes)) +0941 model.eccodes=eccodes; +0942 end +0943 +0944 %If any Miriam strings for reactions have been loaded +0945 if any(~cellfun(@isempty,rxnMiriams)) +0946 model.rxnMiriams=rxnMiriams; +0947 end +0948 +0949 %If any Miriam strings for genes have been loaded +0950 if any(~cellfun(@isempty,geneMiriams)) +0951 model.geneMiriams=geneMiriams; +0952 end +0953 +0954 %If any protein strings have been loaded +0955 if any(~cellfun(@isempty,proteins)) +0956 proteins = reshape(proteins,[],1); +0957 model.proteins=proteins; +0958 end +0959 +0960 model.unconstrained=metaboliteUnconstrained; +0961 +0962 %Convert SBML IDs back into their original strings. Here we are using part +0963 %from convertSBMLID, originating from the COBRA Toolbox +0964 model.rxns=regexprep(model.rxns,'__([0-9]+)__','${char(str2num($1))}'); +0965 model.mets=regexprep(model.mets,'__([0-9]+)__','${char(str2num($1))}'); +0966 model.comps=regexprep(model.comps,'__([0-9]+)__','${char(str2num($1))}'); +0967 model.grRules=regexprep(model.grRules,'__([0-9]+)__','${char(str2num($1))}'); +0968 model.genes=regexprep(model.genes,'__([0-9]+)__','${char(str2num($1))}'); +0969 model.id=regexprep(model.id,'__([0-9]+)__','${char(str2num($1))}'); +0970 +0971 if removePrefix +0972 [model, hasChanged]=removeIdentifierPrefix(model); +0973 dispEM(['The following fields have prefixes removed from all entries. '... +0974 'If this is undesired, run importModel with removePrefix as false. Example: '... +0975 'importModel(''filename.xml'',[],false);'],false,hasChanged) +0976 end +0977 +0978 %Remove unused fields +0979 if isempty(model.annotation) +0980 model=rmfield(model,'annotation'); +0981 end +0982 if isempty(model.compOutside) +0983 model=rmfield(model,'compOutside'); +0984 end +0985 if isempty(model.compMiriams) +0986 model=rmfield(model,'compMiriams'); +0987 end +0988 if isempty(model.rxnComps) +0989 model=rmfield(model,'rxnComps'); 0990 end -0991 -0992 %Remove unused fields -0993 if isempty(model.annotation) -0994 model=rmfield(model,'annotation'); -0995 end -0996 if isempty(model.compOutside) -0997 model=rmfield(model,'compOutside'); -0998 end -0999 if isempty(model.compMiriams) -1000 model=rmfield(model,'compMiriams'); +0991 if isempty(model.grRules) +0992 model=rmfield(model,'grRules'); +0993 end +0994 if isempty(model.rxnGeneMat) +0995 model=rmfield(model,'rxnGeneMat'); +0996 end +0997 if isempty(model.subSystems) +0998 model=rmfield(model,'subSystems'); +0999 else +1000 model.subSystems(cellfun(@isempty,subsystems))={{''}}; 1001 end -1002 if isempty(model.rxnComps) -1003 model=rmfield(model,'rxnComps'); +1002 if isempty(model.eccodes) +1003 model=rmfield(model,'eccodes'); 1004 end -1005 if isempty(model.grRules) -1006 model=rmfield(model,'grRules'); +1005 if isempty(model.rxnMiriams) +1006 model=rmfield(model,'rxnMiriams'); 1007 end -1008 if isempty(model.rxnGeneMat) -1009 model=rmfield(model,'rxnGeneMat'); +1008 if cellfun(@isempty,model.rxnNotes) +1009 model=rmfield(model,'rxnNotes'); 1010 end -1011 if isempty(model.subSystems) -1012 model=rmfield(model,'subSystems'); -1013 else -1014 model.subSystems(cellfun(@isempty,subsystems))={{''}}; -1015 end -1016 if isempty(model.eccodes) -1017 model=rmfield(model,'eccodes'); -1018 end -1019 if isempty(model.rxnMiriams) -1020 model=rmfield(model,'rxnMiriams'); +1011 if cellfun(@isempty,model.rxnReferences) +1012 model=rmfield(model,'rxnReferences'); +1013 end +1014 if isempty(model.rxnConfidenceScores) || all(isnan(model.rxnConfidenceScores)) +1015 model=rmfield(model,'rxnConfidenceScores'); +1016 end +1017 if isempty(model.genes) +1018 model=rmfield(model,'genes'); +1019 elseif isrow(model.genes) +1020 model.genes=transpose(model.genes); 1021 end -1022 if cellfun(@isempty,model.rxnNotes) -1023 model=rmfield(model,'rxnNotes'); +1022 if isempty(model.geneComps) +1023 model=rmfield(model,'geneComps'); 1024 end -1025 if cellfun(@isempty,model.rxnReferences) -1026 model=rmfield(model,'rxnReferences'); +1025 if isempty(model.geneMiriams) +1026 model=rmfield(model,'geneMiriams'); 1027 end -1028 if isempty(model.rxnConfidenceScores) || all(isnan(model.rxnConfidenceScores)) -1029 model=rmfield(model,'rxnConfidenceScores'); +1028 if isempty(model.geneShortNames) +1029 model=rmfield(model,'geneShortNames'); 1030 end -1031 if isempty(model.genes) -1032 model=rmfield(model,'genes'); -1033 elseif isrow(model.genes) -1034 model.genes=transpose(model.genes); -1035 end -1036 if isempty(model.geneComps) -1037 model=rmfield(model,'geneComps'); -1038 end -1039 if isempty(model.geneMiriams) -1040 model=rmfield(model,'geneMiriams'); -1041 end -1042 if isempty(model.geneShortNames) -1043 model=rmfield(model,'geneShortNames'); -1044 end -1045 if isempty(model.proteins) -1046 model=rmfield(model,'proteins'); -1047 end -1048 if isempty(model.inchis) -1049 model=rmfield(model,'inchis'); +1031 if isempty(model.proteins) +1032 model=rmfield(model,'proteins'); +1033 end +1034 if isempty(model.inchis) +1035 model=rmfield(model,'inchis'); +1036 end +1037 if isempty(model.metFormulas) +1038 model=rmfield(model,'metFormulas'); +1039 end +1040 if isempty(model.metMiriams) +1041 model=rmfield(model,'metMiriams'); +1042 end +1043 if ~any(model.metCharges) +1044 model=rmfield(model,'metCharges'); +1045 end +1046 +1047 %This just removes the grRules if no genes have been loaded +1048 if ~isfield(model,'genes') && isfield(model,'grRules') +1049 model=rmfield(model,'grRules'); 1050 end -1051 if isempty(model.metFormulas) -1052 model=rmfield(model,'metFormulas'); -1053 end -1054 if isempty(model.metMiriams) -1055 model=rmfield(model,'metMiriams'); -1056 end -1057 if ~any(model.metCharges) -1058 model=rmfield(model,'metCharges'); +1051 +1052 %Print warnings about bad structure +1053 if supressWarnings==false +1054 checkModelStruct(model,false); +1055 end +1056 +1057 if removeExcMets==true +1058 model=simplifyModel(model); 1059 end -1060 -1061 %This just removes the grRules if no genes have been loaded -1062 if ~isfield(model,'genes') && isfield(model,'grRules') -1063 model=rmfield(model,'grRules'); -1064 end -1065 -1066 %Print warnings about bad structure -1067 if supressWarnings==false -1068 checkModelStruct(model,false); -1069 end -1070 -1071 if removeExcMets==true -1072 model=simplifyModel(model); -1073 end -1074 end -1075 -1076 function matchGenes=getGeneList(grRules) -1077 %Constructs the list of unique genes from grRules -1078 -1079 %Assumes that everything that isn't a paranthesis, " AND " or " or " is a -1080 %gene name -1081 genes=strrep(grRules,'(',''); -1082 genes=strrep(genes,')',''); -1083 genes=strrep(genes,' or ',' '); -1084 genes=strrep(genes,' and ',' '); -1085 genes=strrep(genes,' OR ',' '); -1086 genes=strrep(genes,' AND ',' '); -1087 genes=regexp(genes,' ','split'); -1088 -1089 allNames={}; -1090 for i=1:numel(genes) -1091 allNames=[allNames genes{i}]; -1092 end -1093 matchGenes=unique(allNames)'; -1094 -1095 %Remove the empty element if present -1096 if isempty(matchGenes{1}) -1097 matchGenes(1)=[]; -1098 end -1099 end -1100 -1101 function fieldContent=parseNote(searchString,fieldName) -1102 %The function obtains the particular information from 'notes' field, using -1103 %fieldName as the dummy string -1104 -1105 fieldContent=''; -1106 -1107 if strfind(searchString,fieldName) -1108 [~,targetString] = regexp(searchString,['<p>' fieldName '.*?</p>'],'tokens','match'); -1109 targetString=regexprep(targetString,'<p>|</p>',''); -1110 targetString=regexprep(targetString,[fieldName, ':'],''); -1111 for i=1:numel(targetString) -1112 fieldContent=[fieldContent ';' strtrim(targetString{1,i})]; -1113 end -1114 fieldContent=regexprep(fieldContent,'^;|;$',''); -1115 else -1116 fieldContent=''; -1117 end -1118 end -1119 -1120 function fieldContent=parseAnnotation(searchString,startString,midString,fieldName) +1060 end +1061 +1062 function matchGenes=getGeneList(grRules) +1063 %Constructs the list of unique genes from grRules +1064 +1065 %Assumes that everything that isn't a paranthesis, " AND " or " or " is a +1066 %gene name +1067 genes=strrep(grRules,'(',''); +1068 genes=strrep(genes,')',''); +1069 genes=strrep(genes,' or ',' '); +1070 genes=strrep(genes,' and ',' '); +1071 genes=strrep(genes,' OR ',' '); +1072 genes=strrep(genes,' AND ',' '); +1073 genes=regexp(genes,' ','split'); +1074 +1075 allNames={}; +1076 for i=1:numel(genes) +1077 allNames=[allNames genes{i}]; +1078 end +1079 matchGenes=unique(allNames)'; +1080 +1081 %Remove the empty element if present +1082 if isempty(matchGenes{1}) +1083 matchGenes(1)=[]; +1084 end +1085 end +1086 +1087 function fieldContent=parseNote(searchString,fieldName) +1088 %The function obtains the particular information from 'notes' field, using +1089 %fieldName as the dummy string +1090 +1091 fieldContent=''; +1092 +1093 if strfind(searchString,fieldName) +1094 [~,targetString] = regexp(searchString,['<p>' fieldName '.*?</p>'],'tokens','match'); +1095 targetString=regexprep(targetString,'<p>|</p>',''); +1096 targetString=regexprep(targetString,[fieldName, ':'],''); +1097 for i=1:numel(targetString) +1098 fieldContent=[fieldContent ';' strtrim(targetString{1,i})]; +1099 end +1100 fieldContent=regexprep(fieldContent,'^;|;$',''); +1101 else +1102 fieldContent=''; +1103 end +1104 end +1105 +1106 function fieldContent=parseAnnotation(searchString,startString,midString,fieldName) +1107 +1108 fieldContent=''; +1109 +1110 %Removing whitespace characters from the ending strings, which may occur in +1111 %several cases +1112 searchString=regexprep(searchString,'" />','"/>'); +1113 [~,targetString] = regexp(searchString,['<rdf:li rdf:resource="' startString fieldName midString '.*?"/>'],'tokens','match'); +1114 targetString=regexprep(targetString,'<rdf:li rdf:resource="|"/>',''); +1115 targetString=regexprep(targetString,startString,''); +1116 targetString=regexprep(targetString,[fieldName midString],''); +1117 +1118 for i=1:numel(targetString) +1119 fieldContent=[fieldContent ';' strtrim(targetString{1,i})]; +1120 end 1121 -1122 fieldContent=''; -1123 -1124 %Removing whitespace characters from the ending strings, which may occur in -1125 %several cases -1126 searchString=regexprep(searchString,'" />','"/>'); -1127 [~,targetString] = regexp(searchString,['<rdf:li rdf:resource="' startString fieldName midString '.*?"/>'],'tokens','match'); -1128 targetString=regexprep(targetString,'<rdf:li rdf:resource="|"/>',''); -1129 targetString=regexprep(targetString,startString,''); -1130 targetString=regexprep(targetString,[fieldName midString],''); -1131 -1132 for i=1:numel(targetString) -1133 fieldContent=[fieldContent ';' strtrim(targetString{1,i})]; -1134 end -1135 -1136 fieldContent=regexprep(fieldContent,'^;|;$',''); -1137 end -1138 -1139 function miriamStruct=parseMiriam(searchString) -1140 %Generates miriam structure from annotation field -1141 -1142 %Finding whether miriams are written in the old or the new way -1143 if strfind(searchString,'urn:miriam:') -1144 startString='urn:miriam:'; -1145 midString=':'; -1146 elseif strfind(searchString,'http://identifiers.org/') -1147 startString='http://identifiers.org/'; -1148 midString='/'; -1149 elseif strfind(searchString,'https://identifiers.org/') -1150 startString='https://identifiers.org/'; -1151 midString='/'; -1152 else -1153 miriamStruct=[]; -1154 return; -1155 end -1156 -1157 miriamStruct=[]; -1158 -1159 searchString=regexprep(searchString,'" />','"/>'); -1160 [~,targetString] = regexp(searchString,'<rdf:li rdf:resource=".*?"/>','tokens','match'); -1161 targetString=regexprep(targetString,'<rdf:li rdf:resource="|"/>',''); -1162 targetString=regexprep(targetString,startString,''); -1163 targetString=regexprep(targetString,midString,'/','once'); +1122 fieldContent=regexprep(fieldContent,'^;|;$',''); +1123 end +1124 +1125 function miriamStruct=parseMiriam(searchString) +1126 %Generates miriam structure from annotation field +1127 +1128 %Finding whether miriams are written in the old or the new way +1129 if strfind(searchString,'urn:miriam:') +1130 startString='urn:miriam:'; +1131 midString=':'; +1132 elseif strfind(searchString,'http://identifiers.org/') +1133 startString='http://identifiers.org/'; +1134 midString='/'; +1135 elseif strfind(searchString,'https://identifiers.org/') +1136 startString='https://identifiers.org/'; +1137 midString='/'; +1138 else +1139 miriamStruct=[]; +1140 return; +1141 end +1142 +1143 miriamStruct=[]; +1144 +1145 searchString=regexprep(searchString,'" />','"/>'); +1146 [~,targetString] = regexp(searchString,'<rdf:li rdf:resource=".*?"/>','tokens','match'); +1147 targetString=regexprep(targetString,'<rdf:li rdf:resource="|"/>',''); +1148 targetString=regexprep(targetString,startString,''); +1149 targetString=regexprep(targetString,midString,'/','once'); +1150 +1151 counter=0; +1152 for i=1:numel(targetString) +1153 if isempty(regexp(targetString{1,i},'inchi|ec-code', 'once')) +1154 counter=counter+1; +1155 miriamStruct.name{counter,1} = regexprep(targetString{1,i},'/.+','','once'); +1156 miriamStruct.value{counter,1} = regexprep(targetString{1,i},[miriamStruct.name{counter,1} '/'],'','once'); +1157 miriamStruct.name{counter,1} = regexprep(miriamStruct.name{counter,1},'^obo\.',''); +1158 end +1159 end +1160 end +1161 +1162 function miriam = addSBOtoMiriam(miriam,sboTerm) +1163 %Appends SBO term to miriam structure 1164 -1165 counter=0; -1166 for i=1:numel(targetString) -1167 if isempty(regexp(targetString{1,i},'inchi|ec-code', 'once')) -1168 counter=counter+1; -1169 miriamStruct.name{counter,1} = regexprep(targetString{1,i},'/.+','','once'); -1170 miriamStruct.value{counter,1} = regexprep(targetString{1,i},[miriamStruct.name{counter,1} '/'],'','once'); -1171 miriamStruct.name{counter,1} = regexprep(miriamStruct.name{counter,1},'^obo\.',''); -1172 end -1173 end -1174 end -1175 -1176 function miriam = addSBOtoMiriam(miriam,sboTerm) -1177 %Appends SBO term to miriam structure -1178 -1179 sboTerm = {['SBO:' sprintf('%07u',sboTerm)]}; % convert to proper format -1180 if isempty(miriam) -1181 miriam.name = {'sbo'}; -1182 miriam.value = sboTerm; -1183 elseif any(strcmp('sbo',miriam.name)) -1184 currSbo = strcmp('sbo',miriam.name); -1185 miriam.value(currSbo) = sboTerm; -1186 else -1187 miriam.name(end+1) = {'sbo'}; -1188 miriam.value(end+1) = sboTerm; -1189 end -1190 end

    +1165 sboTerm = {['SBO:' sprintf('%07u',sboTerm)]}; % convert to proper format +1166 if isempty(miriam) +1167 miriam.name = {'sbo'}; +1168 miriam.value = sboTerm; +1169 elseif any(strcmp('sbo',miriam.name)) +1170 currSbo = strcmp('sbo',miriam.name); +1171 miriam.value(currSbo) = sboTerm; +1172 else +1173 miriam.name(end+1) = {'sbo'}; +1174 miriam.value(end+1) = sboTerm; +1175 end +1176 end

    Generated by m2html © 2005
    \ No newline at end of file diff --git a/doc/io/sortIdentifiers.html b/doc/io/sortIdentifiers.html index ee3d8aaa..71563563 100644 --- a/doc/io/sortIdentifiers.html +++ b/doc/io/sortIdentifiers.html @@ -47,7 +47,7 @@

    CROSS-REFERENCE INFORMATION ^
 </ul>
 This function is called by:
 <ul style= -
  • exportForGit exportForGit
  • exportModel exportModel
  • exportToExcelFormat exportToExcelFormat
  • exportToTabDelimited exportToTabDelimited
  • writeYAMLmodel writeYAMLmodel
  • +
  • exportForGit exportForGit
  • exportModel exportModel
  • exportToExcelFormat exportToExcelFormat
  • exportToTabDelimited exportToTabDelimited
  • writeYAMLmodel writeYAMLmodel
  • diff --git a/doc/struct_conversion/addCOBRAstylePrefixes.html b/doc/struct_conversion/addCOBRAstylePrefixes.html deleted file mode 100644 index a5b0b928..00000000 --- a/doc/struct_conversion/addCOBRAstylePrefixes.html +++ /dev/null @@ -1,125 +0,0 @@ - - - - Description of addCOBRAstylePrefixes - - - - - - - - - -
    Home > struct_conversion > addCOBRAstylePrefixes.m
    - - - -

    addCOBRAstylePrefixes -

    - -

    PURPOSE ^

    -
    addCOBRAstylePrefixes
    - -

    SYNOPSIS ^

    -
    function model=addCOBRAstylePrefixes(model,fields,printWarnings)
    - -

    DESCRIPTION ^

    -
     addCOBRAstylePrefixes
    -   This function adds COBRA style identifier prefixes, which are:
    -       "R_" for model.rxns,
    -       "M_" for model.mets,
    -       "C_" for model.comps;
    -       "G_" for model.genes (and also represented in model.grRules).
    -   If all entries in a field already have the prefix, then no additional
    -   prefix will be added.
    -
    - Input:
    -   model           model whose identifiers should be modified
    -   fields          cell array with model field names to which the prefix
    -                   should be added, possible values: {'rxns', 'mets', 
    -                   'comps', 'genes'} (optional, by default prefixes are
    -                   added to all listed model fields will be checked).
    -   printWarnings   if warnings should be shown (optional, default true).
    -
    - Output:
    -   model           modified model
    -
    - Usage: model=addCOBRAstylePrefixes(model,fields,printWarnings)
    - - -

    CROSS-REFERENCE INFORMATION ^

    -This function calls: -
      -
    -This function is called by: -
      -
    - - - - -

    SOURCE CODE ^

    -
    0001 function model=addCOBRAstylePrefixes(model,fields,printWarnings)
    -0002 % addCOBRAstylePrefixes
    -0003 %   This function adds COBRA style identifier prefixes, which are:
    -0004 %       "R_" for model.rxns,
    -0005 %       "M_" for model.mets,
    -0006 %       "C_" for model.comps;
    -0007 %       "G_" for model.genes (and also represented in model.grRules).
    -0008 %   If all entries in a field already have the prefix, then no additional
    -0009 %   prefix will be added.
    -0010 %
    -0011 % Input:
    -0012 %   model           model whose identifiers should be modified
    -0013 %   fields          cell array with model field names to which the prefix
    -0014 %                   should be added, possible values: {'rxns', 'mets',
    -0015 %                   'comps', 'genes'} (optional, by default prefixes are
    -0016 %                   added to all listed model fields will be checked).
    -0017 %   printWarnings   if warnings should be shown (optional, default true).
    -0018 %
    -0019 % Output:
    -0020 %   model           modified model
    -0021 %
    -0022 % Usage: model=addCOBRAstylePrefixes(model,fields,printWarnings)
    -0023 
    -0024 if nargin<2 || isempty(fields)
    -0025     fields = {'rxns','mets','comps','genes'};
    -0026 end
    -0027 if nargin<3 || isempty(printWarnings)
    -0028     printWarnings = true;
    -0029 end
    -0030 
    -0031 modelFields = {'rxns','R_';
    -0032                'mets','M_';
    -0033                'comps','C_';
    -0034                'genes','G_'};
    -0035 
    -0036 toChangeIdx = find(ismember(modelFields(:,1),fields));
    -0037 for i=1:numel(toChangeIdx)
    -0038     currName    = modelFields{toChangeIdx(i),1};
    -0039     currPrefix  = modelFields{toChangeIdx(i),2};
    -0040     if isfield(model,currName)
    -0041         currField   = model.(currName);
    -0042     else
    -0043         continue;
    -0044     end
    -0045     if ~all(startsWith(currField,currPrefix))
    -0046         currField = strcat(currPrefix, currField);
    -0047         if strcmp(currName,'genes')
    -0048                 model.grRules = regexprep(model.grRules, '(\<[0-9_a-zA-Z])', 'G_$1');
    -0049                 model.grRules = regexprep(model.grRules, ' G_or ', ' or ');
    -0050                 model.grRules = regexprep(model.grRules, ' G_and ', ' and ');
    -0051         end
    -0052         model.(currName) = currField;
    -0053     elseif printWarnings
    -0054         warning(['All identifiers in "model.' currName '" already start ' ...
    -0055             'with "' currPrefix '", no additional prefix added.'])
    -0056     end
    -0057 end
    -0058 end
    -
    Generated by m2html © 2005
    - - \ No newline at end of file diff --git a/doc/struct_conversion/addIdentifierPrefix.html b/doc/struct_conversion/addIdentifierPrefix.html new file mode 100644 index 00000000..de10d34d --- /dev/null +++ b/doc/struct_conversion/addIdentifierPrefix.html @@ -0,0 +1,128 @@ + + + + Description of addIdentifierPrefix + + + + + + + + + +
    Home > struct_conversion > addIdentifierPrefix.m
    + + + +

    addIdentifierPrefix +

    + +

    PURPOSE ^

    +
    addIdentifierPrefix
    + +

    SYNOPSIS ^

    +
    function [model, hasChanged]=addIdentifierPrefix(model,fields)
    + +

    DESCRIPTION ^

    +
     addIdentifierPrefix
    +   If reaction, metabolite, compartment, gene or model identifiers do not
    +   start with a letter or _, which conflicts with SBML specifications,
    +   prefixes are added for all identifiers in the respective model field.
    +   The prefixes are:
    +       "R_" for model.rxns,
    +       "M_" for model.mets,
    +       "C_" for model.comps;
    +       "G_" for model.genes (and also represented in model.grRules)
    +
    + Input:
    +   model           model whose identifiers should be modified
    +   fields          cell array with model field names that should be
    +                   checked if prefixes should be added, possible values: 
    +                   'rxns', 'mets', 'comps', 'genes', 'id'. (optional, by
    +                   default all listed model fields will be checked).
    +
    + Output:
    +   model           modified model
    +   hasChanged      cell array with fields and prefixes that are added
    +
    + Usage: [model, hasChanged]=addIdentifierPrefix(model,fields)
    + + +

    CROSS-REFERENCE INFORMATION ^

    +This function calls: +
      +
    +This function is called by: +
      +
    + + + + +

    SOURCE CODE ^

    +
    0001 function [model, hasChanged]=addIdentifierPrefix(model,fields)
    +0002 % addIdentifierPrefix
    +0003 %   If reaction, metabolite, compartment, gene or model identifiers do not
    +0004 %   start with a letter or _, which conflicts with SBML specifications,
    +0005 %   prefixes are added for all identifiers in the respective model field.
    +0006 %   The prefixes are:
    +0007 %       "R_" for model.rxns,
    +0008 %       "M_" for model.mets,
    +0009 %       "C_" for model.comps;
    +0010 %       "G_" for model.genes (and also represented in model.grRules)
    +0011 %
    +0012 % Input:
    +0013 %   model           model whose identifiers should be modified
    +0014 %   fields          cell array with model field names that should be
    +0015 %                   checked if prefixes should be added, possible values:
    +0016 %                   'rxns', 'mets', 'comps', 'genes', 'id'. (optional, by
    +0017 %                   default all listed model fields will be checked).
    +0018 %
    +0019 % Output:
    +0020 %   model           modified model
    +0021 %   hasChanged      cell array with fields and prefixes that are added
    +0022 %
    +0023 % Usage: [model, hasChanged]=addIdentifierPrefix(model,fields)
    +0024 
    +0025 if nargin<2 || isempty(fields)
    +0026     fields = {'rxns','mets','comps','genes','id'};
    +0027 end
    +0028 
    +0029 modelFields = {'rxns','R_';
    +0030                'mets','M_';
    +0031                'comps','C_';
    +0032                'genes','G_';
    +0033                'id','M_'};
    +0034 
    +0035 toChangeIdx = find(ismember(modelFields(:,1),fields));
    +0036 hasChanged  = false(numel(modelFields(:,1)),1);
    +0037 for i=1:numel(toChangeIdx)
    +0038     currName    = modelFields{toChangeIdx(i),1};
    +0039     currPrefix  = modelFields{toChangeIdx(i),2};
    +0040     if isfield(model,currName)
    +0041         currField   = model.(currName);
    +0042     else
    +0043         continue;
    +0044     end
    +0045     if ~all(startsWith(currField,regexpPattern('^[a-zA-Z_]')))
    +0046         currField = strcat(currPrefix, currField);
    +0047         hasChanged(toChangeIdx(i)) = true;
    +0048 
    +0049         if strcmp(currName,'genes')
    +0050                 model.grRules = regexprep(model.grRules, '(\<[0-9_a-zA-Z])', 'G_$1');
    +0051                 model.grRules = regexprep(model.grRules, ' G_or ', ' or ');
    +0052                 model.grRules = regexprep(model.grRules, ' G_and ', ' and ');
    +0053         end
    +0054         model.(currName) = currField;
    +0055     end
    +0056 end
    +0057 
    +0058 hasChanged = modelFields(hasChanged,:);
    +0059 hasChanged = append('model.', hasChanged(:,1), ' (', hasChanged(:,2), ' prefix)');
    +0060 end
    +
    Generated by m2html © 2005
    + + \ No newline at end of file diff --git a/doc/struct_conversion/index.html b/doc/struct_conversion/index.html index 879c8df1..aa35ccd6 100644 --- a/doc/struct_conversion/index.html +++ b/doc/struct_conversion/index.html @@ -19,7 +19,7 @@

    Index for struct_conversion

    Matlab files in this directory:

    -
     addCOBRAstylePrefixesaddCOBRAstylePrefixes
     editMiriameditMiriam
     extractMiriamextractMiriam
     ravenCobraWrapperravenCobraWrapper
     removeCOBRAstylePrefixesremoveCOBRAstylePrefixes
     standardizeModelFieldOrderstandardizeModelFieldOrder
    + addIdentifierPrefixaddIdentifierPrefix  editMiriameditMiriam  extractMiriamextractMiriam  ravenCobraWrapperravenCobraWrapper  removeIdentifierPrefixremoveIdentifierPrefix  standardizeModelFieldOrderstandardizeModelFieldOrder diff --git a/doc/struct_conversion/removeCOBRAstylePrefixes.html b/doc/struct_conversion/removeCOBRAstylePrefixes.html deleted file mode 100644 index 6bf13d2a..00000000 --- a/doc/struct_conversion/removeCOBRAstylePrefixes.html +++ /dev/null @@ -1,133 +0,0 @@ - - - - Description of removeCOBRAstylePrefixes - - - - - - - - - -
    Home > struct_conversion > removeCOBRAstylePrefixes.m
    - - - -

    removeCOBRAstylePrefixes -

    - -

    PURPOSE ^

    -
    removeCOBRAstylePrefixes
    - -

    SYNOPSIS ^

    -
    function model=removeCOBRAstylePrefixes(model,fields,forceRemove)
    - -

    DESCRIPTION ^

    -
     removeCOBRAstylePrefixes
    -   This function removes COBRA style identifier prefixes, which are:
    -       "R_" for model.rxns, model.rxnNames and model.id,
    -       "M_" for model.mets and model.metNames,
    -       "C_" for model.comps;
    -       "G_" for model.genes (and also represented in model.grRules).
    -   By default, the prefixes are only removed if all entries in a
    -   particular field has the prefix.
    -
    - Input:
    -   model           model whose identifiers should be modified
    -   fields          cell array with model field names from which the
    -                   identifiers should be removed, possible values: 
    -                   'rxns', 'mets', 'comps', 'genes', 'metNames', 
    -                   'rxnNames', 'id'. (optional, by default all listed
    -                   model fields will be checked).
    -   forceRemove     if prefixes should be removed even if not all entries
    -                   in a model field have the prefix (optional, default
    -                   false)
    -
    - Output:
    -   model           modified model
    -
    - Usage: model=removeCOBRAstylePrefixes(model,fields,forceRemove)
    - - -

    CROSS-REFERENCE INFORMATION ^

    -This function calls: -
      -
    -This function is called by: -
      -
    - - - - -

    SOURCE CODE ^

    -
    0001 function model=removeCOBRAstylePrefixes(model,fields,forceRemove)
    -0002 % removeCOBRAstylePrefixes
    -0003 %   This function removes COBRA style identifier prefixes, which are:
    -0004 %       "R_" for model.rxns, model.rxnNames and model.id,
    -0005 %       "M_" for model.mets and model.metNames,
    -0006 %       "C_" for model.comps;
    -0007 %       "G_" for model.genes (and also represented in model.grRules).
    -0008 %   By default, the prefixes are only removed if all entries in a
    -0009 %   particular field has the prefix.
    -0010 %
    -0011 % Input:
    -0012 %   model           model whose identifiers should be modified
    -0013 %   fields          cell array with model field names from which the
    -0014 %                   identifiers should be removed, possible values:
    -0015 %                   'rxns', 'mets', 'comps', 'genes', 'metNames',
    -0016 %                   'rxnNames', 'id'. (optional, by default all listed
    -0017 %                   model fields will be checked).
    -0018 %   forceRemove     if prefixes should be removed even if not all entries
    -0019 %                   in a model field have the prefix (optional, default
    -0020 %                   false)
    -0021 %
    -0022 % Output:
    -0023 %   model           modified model
    -0024 %
    -0025 % Usage: model=removeCOBRAstylePrefixes(model,fields,forceRemove)
    -0026 
    -0027 if nargin<2 || isempty(fields)
    -0028     fields = {'rxns','mets','comps','genes','metNames','rxnNames','id'};
    -0029 end
    -0030 if nargin<3 || isempty(forceRemove)
    -0031     forceRemove = true;
    -0032 end
    -0033 
    -0034 modelFields = {'rxns',      'R_';
    -0035     'mets',      'M_';
    -0036     'comps',     'C_';
    -0037     'genes',     'G_';
    -0038     'metNames',  'M_';
    -0039     'rxnNames',  'R_';
    -0040     'id',        'M_'};
    -0041 
    -0042 toChangeIdx = find(ismember(modelFields(:,1),fields));
    -0043 for i=1:numel(toChangeIdx)
    -0044     currName    = modelFields{toChangeIdx(i),1};
    -0045     currPrefix  = modelFields{toChangeIdx(i),2};
    -0046     currField   = model.(currName);
    -0047 
    -0048     if forceRemove
    -0049         hasPrefix = true;
    -0050     else
    -0051         hasPrefix = all(startsWith(currField,currPrefix));
    -0052     end
    -0053     if hasPrefix
    -0054         currField = regexprep(currField,['^' currPrefix],'');
    -0055         if strcmp(currName,'genes')
    -0056             model.grRules=regexprep(model.grRules,'^G_','');
    -0057             model.grRules=regexprep(model.grRules,'\(G_','(');
    -0058             model.grRules=regexprep(model.grRules,' G_',' ');
    -0059         end
    -0060     end
    -0061     model.(currName) = currField;
    -0062 end
    -0063 end
    -
    Generated by m2html © 2005
    - - \ No newline at end of file diff --git a/doc/struct_conversion/removeIdentifierPrefix.html b/doc/struct_conversion/removeIdentifierPrefix.html new file mode 100644 index 00000000..3fae6a6c --- /dev/null +++ b/doc/struct_conversion/removeIdentifierPrefix.html @@ -0,0 +1,143 @@ + + + + Description of removeIdentifierPrefix + + + + + + + + + +
    Home > struct_conversion > removeIdentifierPrefix.m
    + + + +

    removeIdentifierPrefix +

    + +

    PURPOSE ^

    +
    removeIdentifierPrefix
    + +

    SYNOPSIS ^

    +
    function [model, hasChanged]=removeIdentifierPrefix(model,fields,forceRemove)
    + +

    DESCRIPTION ^

    +
     removeIdentifierPrefix
    +   This function removes identifier prefixes:
    +       "R_" for model.rxns, model.rxnNames and model.id,
    +       "M_" for model.mets and model.metNames,
    +       "C_" for model.comps;
    +       "G_" for model.genes (and also represented in model.grRules).
    +   By default, the prefixes are only removed if all entries in a
    +   particular field has the prefix. The prefixes might have been present
    +   because one or more identifiers do not start with a letter or _, which
    +   conflicts with SBML specifications.
    +
    + Input:
    +   model           model whose identifiers should be modified
    +   fields          cell array with model field names from which the
    +                   identifiers should be removed, possible values: 
    +                   'rxns', 'mets', 'comps', 'genes', 'metNames', 
    +                   'rxnNames', 'id'. (optional, by default all listed
    +                   model fields will be checked).
    +   forceRemove     if prefixes should be removed even if not all entries
    +                   in a model field have the prefix (optional, default
    +                   false)
    +
    + Output:
    +   model           modified model
    +   hasChanged      cell array with fields and prefixes that are removed
    +
    + Usage: model=removeIdentifierPrefix(model,fields,forceRemove)
    + + +

    CROSS-REFERENCE INFORMATION ^

    +This function calls: +
      +
    +This function is called by: +
      +
    + + + + +

    SOURCE CODE ^

    +
    0001 function [model, hasChanged]=removeIdentifierPrefix(model,fields,forceRemove)
    +0002 % removeIdentifierPrefix
    +0003 %   This function removes identifier prefixes:
    +0004 %       "R_" for model.rxns, model.rxnNames and model.id,
    +0005 %       "M_" for model.mets and model.metNames,
    +0006 %       "C_" for model.comps;
    +0007 %       "G_" for model.genes (and also represented in model.grRules).
    +0008 %   By default, the prefixes are only removed if all entries in a
    +0009 %   particular field has the prefix. The prefixes might have been present
    +0010 %   because one or more identifiers do not start with a letter or _, which
    +0011 %   conflicts with SBML specifications.
    +0012 %
    +0013 % Input:
    +0014 %   model           model whose identifiers should be modified
    +0015 %   fields          cell array with model field names from which the
    +0016 %                   identifiers should be removed, possible values:
    +0017 %                   'rxns', 'mets', 'comps', 'genes', 'metNames',
    +0018 %                   'rxnNames', 'id'. (optional, by default all listed
    +0019 %                   model fields will be checked).
    +0020 %   forceRemove     if prefixes should be removed even if not all entries
    +0021 %                   in a model field have the prefix (optional, default
    +0022 %                   false)
    +0023 %
    +0024 % Output:
    +0025 %   model           modified model
    +0026 %   hasChanged      cell array with fields and prefixes that are removed
    +0027 %
    +0028 % Usage: model=removeIdentifierPrefix(model,fields,forceRemove)
    +0029 
    +0030 if nargin<2 || isempty(fields)
    +0031     fields = {'rxns','mets','comps','genes','metNames','rxnNames','id'};
    +0032 end
    +0033 if nargin<3 || isempty(forceRemove)
    +0034     forceRemove = false;
    +0035 end
    +0036 
    +0037 modelFields = {'rxns',      'R_';
    +0038     'mets',      'M_';
    +0039     'comps',     'C_';
    +0040     'genes',     'G_';
    +0041     'metNames',  'M_';
    +0042     'rxnNames',  'R_';
    +0043     'id',        'M_'};
    +0044 
    +0045 toChangeIdx = find(ismember(modelFields(:,1),fields));
    +0046 hasChanged  = false(numel(modelFields(:,1)),1);
    +0047 for i=1:numel(toChangeIdx)
    +0048     currName    = modelFields{toChangeIdx(i),1};
    +0049     currPrefix  = modelFields{toChangeIdx(i),2};
    +0050     currField   = model.(currName);
    +0051 
    +0052     if forceRemove && any(startsWith(currField,currPrefix))
    +0053         hasPrefix = true;
    +0054     else
    +0055         hasPrefix = all(startsWith(currField,currPrefix));
    +0056     end
    +0057     if hasPrefix
    +0058         currField = regexprep(currField,['^' currPrefix],'');
    +0059         hasChanged(toChangeIdx(i)) = true;
    +0060         if strcmp(currName,'genes')
    +0061             model.grRules=regexprep(model.grRules,'^G_','');
    +0062             model.grRules=regexprep(model.grRules,'\(G_','(');
    +0063             model.grRules=regexprep(model.grRules,' G_',' ');
    +0064         end
    +0065     end
    +0066     model.(currName) = currField;
    +0067 end
    +0068 hasChanged = modelFields(hasChanged,:);
    +0069 hasChanged = append('model.', hasChanged(:,1), ' (', hasChanged(:,2), ' prefix)');
    +0070 end
    +
    Generated by m2html © 2005
    + + \ No newline at end of file diff --git a/io/exportModel.m b/io/exportModel.m index 1d60eef1..8beef3b2 100755 --- a/io/exportModel.m +++ b/io/exportModel.m @@ -1,4 +1,4 @@ -function exportModel(model,fileName,COBRAstyle,supressWarnings,sortIds) +function exportModel(model,fileName,neverPrefix,supressWarnings,sortIds) % exportModel % Exports a constraint-based model to an SBML file (L3V1 FBCv2) % @@ -6,12 +6,9 @@ function exportModel(model,fileName,COBRAstyle,supressWarnings,sortIds) % model a model structure % fileName filename to export the model to. A dialog window % will open if no file name is specified. -% COBRAstyle true if COBRA-style prefixes should be added to all -% identifiers: R_ for reactions, M_ for metabolites, -% G_ for genes and C_ for compartments. If all -% identifiers of a particular field already have the -% prefix, then no additional prefixes are added. -% (optional, default false) +% neverPrefix true if prefixes are never added to identifiers, +% even if start with e.g. digits. This might result +% in invalid SBML files (optional, default false) % supressWarnings true if warnings should be supressed. This might % results in invalid SBML files, as no checks are % performed (optional, default false) @@ -19,7 +16,7 @@ function exportModel(model,fileName,COBRAstyle,supressWarnings,sortIds) % should be sorted alphabetically by their % identifiers (optional, default false) % -% Usage: exportModel(model,fileName,COBRAstyle,supressWarnings,sortIds) +% Usage: exportModel(model,fileName,neverPrefix,supressWarnings,sortIds) if nargin<2 || isempty(fileName) [fileName, pathName] = uiputfile({'*.xml;*.sbml'}, 'Select file for model export',[model.id '.xml']); @@ -30,15 +27,13 @@ function exportModel(model,fileName,COBRAstyle,supressWarnings,sortIds) end end fileName=char(fileName); -if nargin<3 - COBRAstyle=false; -elseif ~islogical(COBRAstyle) - error("COBRAstyle should be either true or false") +if nargin<3 || isempty(neverPrefix) + neverPrefix=false; end -if nargin<4 +if nargin<4 || isempty(supressWarnings) supressWarnings=false; end -if nargin<5 +if nargin<5 || isempty(sortIds) sortIds=false; end if sortIds==true @@ -85,17 +80,17 @@ function exportModel(model,fileName,COBRAstyle,supressWarnings,sortIds) model.name='blankName'; end -% Add prefixes if desired -if COBRAstyle - if isfield(model,'ec') - error('ecModels cannot be exported with COBRAstyle flag, manually correct any non-compliant identifiers if needed.') - end - model = addCOBRAstylePrefixes(model,[],false); +% Add prefixes if required +if ~neverPrefix + [model,hasChanged] = addIdentifierPrefix(model); + dispEM(['The following fields have one or more entries that do not start '... + 'with a letter or _ (conflicting with SBML specifications). Prefixes '... + 'are added to all entries in those fields:'],false,hasChanged) end %Check the model structure if supressWarnings==false - checkModelStruct(model,false); + checkModelStruct(model); end %Add several blank fields, if they do not exist already. This is to reduce diff --git a/io/importModel.m b/io/importModel.m index 56bd19dd..b36a4ad9 100755 --- a/io/importModel.m +++ b/io/importModel.m @@ -1,6 +1,6 @@ -function model=importModel(fileName,removeExcMets,COBRAstyle,supressWarnings) +function model=importModel(fileName,removeExcMets,removePrefix,supressWarnings) % importModel -% Import a constraint-based model from a SBML file +% Import a constraint-based model from an SBML file. % % Input: % fileName a SBML file to import. A dialog window will open if @@ -9,10 +9,11 @@ % needed to be able to run simulations, but it could also % be done using simplifyModel at a later stage (optional, % default true) -% COBRAstyle true if the model uses COBRA style identifier prefixes -% that should be removed when loading the model: G_ for -% genes, R_ for reactions, M_ for metabolites, and C_ for -% compartments. (optional, default false) +% removePrefix true if identifier prefixes should be removed when +% loading the model: G_ for genes, R_ for reactions, +% M_ for metabolites, and C_ for compartments. These are +% only removed if all identifiers of a certain type +% contain the prefix. (optional, default true) % supressWarnings true if warnings regarding the model structure should % be supressed (optional, default false) % @@ -49,7 +50,7 @@ % geneComps compartments for genes % geneMiriams structure with MIRIAM information about the genes % geneShortNames gene alternative names (e.g. ERG10) -% proteins protein associated to each gene +% proteins protein associated to each gene % metNames metabolite description % metComps compartments for metabolites % inchis InChI-codes for metabolites @@ -58,11 +59,11 @@ % metCharges metabolite charge % unconstrained true if the metabolite is an exchange metabolite % -% A number of consistency checks are performed in order to ensure that the +% Note: A number of consistency checks are performed in order to ensure that the % model is valid. Take these warnings seriously and modify the model % structure to solve them. % -% Usage: model = importModel(fileName, removeExcMets, COBRAstyle, supressWarnings) +% Usage: model = importModel(fileName, removeExcMets, removePrefix, supressWarnings) if nargin<1 || isempty(fileName) [fileName, pathName] = uigetfile({'*.xml;*.sbml'}, 'Please select the model file'); @@ -77,8 +78,8 @@ removeExcMets=true; end -if nargin<3 || isempty(COBRAstyle) - COBRAstyle=false; +if nargin<3 || isempty(removePrefix) + removePrefix=true; end if nargin<4 @@ -967,26 +968,11 @@ model.genes=regexprep(model.genes,'__([0-9]+)__','${char(str2num($1))}'); model.id=regexprep(model.id,'__([0-9]+)__','${char(str2num($1))}'); -if COBRAstyle - model=removeCOBRAstylePrefixes(model); -else - hasCOBRAids(1) = all(startsWith(model.rxns,'R_')); - hasCOBRAids(2) = all(startsWith(model.mets,'M_')); - hasCOBRAids(3) = all(startsWith(model.comps,'C_')); - hasCOBRAids(4) = all(startsWith(model.genes,'G_')); - if any(hasCOBRAids) - hasCOBRAidsMsg = {'model.rxns (R_ prefix)',... - 'model.mets (M_ prefix)',... - 'model.comps (C_ prefix)',... - 'model.genes (G_ prefix)'}; - hasCOBRAidsMsg(~hasCOBRAids) = []; - printOrange(['COBRA style identifier prefixes are found in: "' ... - strjoin(hasCOBRAidsMsg,'"; "') '". Since RAVEN 2.10.0, identifiers ' ... - 'are by default imported "as-is". If you do prefer to remove these ' ... - 'identifier prefixes, run "removeCOBRAstylePrefixes" on the ' ... - 'imported model, or directly run importModel with COBRAstyle as true ' ... - 'Example: importModel(''filename.xml'', [], true);\n']); - end +if removePrefix + [model, hasChanged]=removeIdentifierPrefix(model); + dispEM(['The following fields have prefixes removed from all entries. '... + 'If this is undesired, run importModel with removePrefix as false. Example: '... + 'importModel(''filename.xml'',[],false);'],false,hasChanged) end %Remove unused fields diff --git a/struct_conversion/addCOBRAstylePrefixes.m b/struct_conversion/addCOBRAstylePrefixes.m deleted file mode 100644 index a84a6954..00000000 --- a/struct_conversion/addCOBRAstylePrefixes.m +++ /dev/null @@ -1,58 +0,0 @@ -function model=addCOBRAstylePrefixes(model,fields,printWarnings) -% addCOBRAstylePrefixes -% This function adds COBRA style identifier prefixes, which are: -% "R_" for model.rxns, -% "M_" for model.mets, -% "C_" for model.comps; -% "G_" for model.genes (and also represented in model.grRules). -% If all entries in a field already have the prefix, then no additional -% prefix will be added. -% -% Input: -% model model whose identifiers should be modified -% fields cell array with model field names to which the prefix -% should be added, possible values: {'rxns', 'mets', -% 'comps', 'genes'} (optional, by default prefixes are -% added to all listed model fields will be checked). -% printWarnings if warnings should be shown (optional, default true). -% -% Output: -% model modified model -% -% Usage: model=addCOBRAstylePrefixes(model,fields,printWarnings) - -if nargin<2 || isempty(fields) - fields = {'rxns','mets','comps','genes'}; -end -if nargin<3 || isempty(printWarnings) - printWarnings = true; -end - -modelFields = {'rxns','R_'; - 'mets','M_'; - 'comps','C_'; - 'genes','G_'}; - -toChangeIdx = find(ismember(modelFields(:,1),fields)); -for i=1:numel(toChangeIdx) - currName = modelFields{toChangeIdx(i),1}; - currPrefix = modelFields{toChangeIdx(i),2}; - if isfield(model,currName) - currField = model.(currName); - else - continue; - end - if ~all(startsWith(currField,currPrefix)) - currField = strcat(currPrefix, currField); - if strcmp(currName,'genes') - model.grRules = regexprep(model.grRules, '(\<[0-9_a-zA-Z])', 'G_$1'); - model.grRules = regexprep(model.grRules, ' G_or ', ' or '); - model.grRules = regexprep(model.grRules, ' G_and ', ' and '); - end - model.(currName) = currField; - elseif printWarnings - warning(['All identifiers in "model.' currName '" already start ' ... - 'with "' currPrefix '", no additional prefix added.']) - end -end -end diff --git a/struct_conversion/addIdentifierPrefix.m b/struct_conversion/addIdentifierPrefix.m new file mode 100644 index 00000000..74672ff6 --- /dev/null +++ b/struct_conversion/addIdentifierPrefix.m @@ -0,0 +1,60 @@ +function [model, hasChanged]=addIdentifierPrefix(model,fields) +% addIdentifierPrefix +% If reaction, metabolite, compartment, gene or model identifiers do not +% start with a letter or _, which conflicts with SBML specifications, +% prefixes are added for all identifiers in the respective model field. +% The prefixes are: +% "R_" for model.rxns, +% "M_" for model.mets, +% "C_" for model.comps; +% "G_" for model.genes (and also represented in model.grRules) +% +% Input: +% model model whose identifiers should be modified +% fields cell array with model field names that should be +% checked if prefixes should be added, possible values: +% 'rxns', 'mets', 'comps', 'genes', 'id'. (optional, by +% default all listed model fields will be checked). +% +% Output: +% model modified model +% hasChanged cell array with fields and prefixes that are added +% +% Usage: [model, hasChanged]=addIdentifierPrefix(model,fields) + +if nargin<2 || isempty(fields) + fields = {'rxns','mets','comps','genes','id'}; +end + +modelFields = {'rxns','R_'; + 'mets','M_'; + 'comps','C_'; + 'genes','G_'; + 'id','M_'}; + +toChangeIdx = find(ismember(modelFields(:,1),fields)); +hasChanged = false(numel(modelFields(:,1)),1); +for i=1:numel(toChangeIdx) + currName = modelFields{toChangeIdx(i),1}; + currPrefix = modelFields{toChangeIdx(i),2}; + if isfield(model,currName) + currField = model.(currName); + else + continue; + end + if ~all(startsWith(currField,regexpPattern('^[a-zA-Z_]'))) + currField = strcat(currPrefix, currField); + hasChanged(toChangeIdx(i)) = true; + + if strcmp(currName,'genes') + model.grRules = regexprep(model.grRules, '(\<[0-9_a-zA-Z])', 'G_$1'); + model.grRules = regexprep(model.grRules, ' G_or ', ' or '); + model.grRules = regexprep(model.grRules, ' G_and ', ' and '); + end + model.(currName) = currField; + end +end + +hasChanged = modelFields(hasChanged,:); +hasChanged = append('model.', hasChanged(:,1), ' (', hasChanged(:,2), ' prefix)'); +end diff --git a/struct_conversion/removeCOBRAstylePrefixes.m b/struct_conversion/removeIdentifierPrefix.m similarity index 71% rename from struct_conversion/removeCOBRAstylePrefixes.m rename to struct_conversion/removeIdentifierPrefix.m index 9f0dfbf4..0a960108 100644 --- a/struct_conversion/removeCOBRAstylePrefixes.m +++ b/struct_conversion/removeIdentifierPrefix.m @@ -1,12 +1,14 @@ -function model=removeCOBRAstylePrefixes(model,fields,forceRemove) -% removeCOBRAstylePrefixes -% This function removes COBRA style identifier prefixes, which are: +function [model, hasChanged]=removeIdentifierPrefix(model,fields,forceRemove) +% removeIdentifierPrefix +% This function removes identifier prefixes: % "R_" for model.rxns, model.rxnNames and model.id, % "M_" for model.mets and model.metNames, % "C_" for model.comps; % "G_" for model.genes (and also represented in model.grRules). % By default, the prefixes are only removed if all entries in a -% particular field has the prefix. +% particular field has the prefix. The prefixes might have been present +% because one or more identifiers do not start with a letter or _, which +% conflicts with SBML specifications. % % Input: % model model whose identifiers should be modified @@ -21,14 +23,15 @@ % % Output: % model modified model +% hasChanged cell array with fields and prefixes that are removed % -% Usage: model=removeCOBRAstylePrefixes(model,fields,forceRemove) +% Usage: model=removeIdentifierPrefix(model,fields,forceRemove) if nargin<2 || isempty(fields) fields = {'rxns','mets','comps','genes','metNames','rxnNames','id'}; end if nargin<3 || isempty(forceRemove) - forceRemove = true; + forceRemove = false; end modelFields = {'rxns', 'R_'; @@ -40,18 +43,20 @@ 'id', 'M_'}; toChangeIdx = find(ismember(modelFields(:,1),fields)); +hasChanged = false(numel(modelFields(:,1)),1); for i=1:numel(toChangeIdx) currName = modelFields{toChangeIdx(i),1}; currPrefix = modelFields{toChangeIdx(i),2}; currField = model.(currName); - if forceRemove + if forceRemove && any(startsWith(currField,currPrefix)) hasPrefix = true; else hasPrefix = all(startsWith(currField,currPrefix)); end if hasPrefix currField = regexprep(currField,['^' currPrefix],''); + hasChanged(toChangeIdx(i)) = true; if strcmp(currName,'genes') model.grRules=regexprep(model.grRules,'^G_',''); model.grRules=regexprep(model.grRules,'\(G_','('); @@ -60,4 +65,6 @@ end model.(currName) = currField; end +hasChanged = modelFields(hasChanged,:); +hasChanged = append('model.', hasChanged(:,1), ' (', hasChanged(:,2), ' prefix)'); end diff --git a/testing/unit_tests/test_data/importExportResults.mat b/testing/unit_tests/test_data/importExportResults.mat index bc7210f5ec123bb24c2c891d038597b768a6310c..0a5df5ef1977e6c2d780509b52c8d408c8d71bf9 100644 GIT binary patch delta 624 zcmV-$0+0QJ3-}6YIBvYgDOTv0f&lpy(P!NP`;Ur-p^Tzf6VB3J3t54XLt*?}bc@Bq9nsy1#+n z`SHwqnjhbc*aimkbg8}>{-}Zftj0%thhX0==KjZhpz8^!mTl$fuS zjAEW7x=c!=^S!0rrn%K3|b$?IuL|J&Zr zS@7q+@qRjgvEv(MdLOI*02Rjj_mKWSlpWTxt~Y(3AAx0)+ke3WE!fI22Q5a3C@=ATTgGF*iCeH6SuDGBlAF9(Qec^GEAIBRBXyT2rYOF$ZMXki^7E-URmc*6gY~_ugv469_!y`Wd z-{O>W*hrJXEV=e)-*rLD}<_RALD&N&}q8Z_2E~Ls8>H|{E8dA*~eh@OwqJU`F(fuv_ z&W~%>X?{9p#MU#I$4m9i@COzA7bQO8BjmH&Y_n9!EL54~M&C7Te|BH;b$9I_jynIm zIM?S2zjjN0A=VLMS<2ZWVQS9V`2Clo6Lux!MLHKtqxX#Hb?(qh{X_Xz6@IvuA1;hf zrH8z(bHAN}^AJ13)7Wds^BeMBH{`uR-iq)#y7e}2o%>hfI8{L!w@YibX9&IY`4d|M`S|KmMS`JSE?bzxc4&OwEp zXO^8D^Ocf8$fHP?Non+auW7fc?y!s8<9Ct%+v#O4Y$ z=Fg%m+?3xf@e!ZnCtWMpBu;IM--dxdYE+LL-H^9eGrk8E{%x1ehq&+g1K%Hc9?{bz V&i(y?=a2UP3BO64e*xB{mtb?fLCgRE