From acd91f1eb128abb8e3f57c62afe77fcd2b4fdb64 Mon Sep 17 00:00:00 2001 From: Eduard Kerkhoven Date: Mon, 26 Feb 2024 16:45:57 +0100 Subject: [PATCH 01/23] fix: simplifyModel w/ backwards-only irrev rxns --- core/simplifyModel.m | 2 +- doc/core/simplifyModel.html | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/core/simplifyModel.m b/core/simplifyModel.m index bf970416..86ccffe4 100755 --- a/core/simplifyModel.m +++ b/core/simplifyModel.m @@ -126,7 +126,7 @@ in=any(reducedModel.b<0,2); out=any(reducedModel.b>0,2); I=speye(numel(reducedModel.mets)); - revS=[reducedModel.S,reducedModel.S(:,reducedModel.rev~=0)*-1 I(:,in) I(:,out)*-1]; + revS=[reducedModel.S,reducedModel.S(:,reducedModel.lb<0)*-1 I(:,in) I(:,out)*-1]; metUsage=sum(abs(revS')>0); onlyProducts=sum(revS'>0) == metUsage; diff --git a/doc/core/simplifyModel.html b/doc/core/simplifyModel.html index 4a1082f2..0f19608c 100644 --- a/doc/core/simplifyModel.html +++ b/doc/core/simplifyModel.html @@ -204,7 +204,7 @@

SOURCE CODE ^ Date: Sat, 9 Mar 2024 00:36:19 +0100 Subject: [PATCH 02/23] fix: writeYAMLmodel do not write empty lines --- io/writeYAMLmodel.m | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/io/writeYAMLmodel.m b/io/writeYAMLmodel.m index a83b0090..fb3e3276 100644 --- a/io/writeYAMLmodel.m +++ b/io/writeYAMLmodel.m @@ -241,6 +241,9 @@ function writeField(model,fid,fieldName,type,pos,name,preserveQuotes) %eccodes/rxnNotes: if 1 write in 1 line, if more create header and list if strcmp(fieldName,'subSystems') list = field{pos}; %subSystems already comes in a cell array + if isempty(list) + return + end elseif strcmp(fieldName,'newMetMiriams') index = str2double(regexprep(name,'^.+_','')); name = regexprep(name,'_\d+$',''); @@ -261,7 +264,7 @@ function writeField(model,fid,fieldName,type,pos,name,preserveQuotes) list = strrep(field{pos},' ',''); list = strsplit(list,';'); else - list = ''; + return % empty, needs no line in file end list=strip(list); From acd3cd01ae4f71db49a3d74f2940cd67fdeccddb Mon Sep 17 00:00:00 2001 From: Eduard Kerkhoven Date: Sat, 9 Mar 2024 00:36:44 +0100 Subject: [PATCH 03/23] fix: getModelFromKEGG essential fields --- external/kegg/getModelFromKEGG.m | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/external/kegg/getModelFromKEGG.m b/external/kegg/getModelFromKEGG.m index 9233e259..c27fbe13 100755 --- a/external/kegg/getModelFromKEGG.m +++ b/external/kegg/getModelFromKEGG.m @@ -235,6 +235,10 @@ %reason. In that case, use the ID instead I=cellfun(@isempty,model.metNames); model.metNames(I)=model.mets(I); + + %Deafult LB and UB + model.annotation.defaultLB = -1000; + model.annotation.defaultUB = 1000; %Save the model structure save(modelFile,'model','KOModel','isGeneral','isIncomplete','isUndefinedStoich','isSpontaneous'); From 42c809d33e5c3e4b462bea94dd02161e48e531cb Mon Sep 17 00:00:00 2001 From: Eduard Kerkhoven Date: Sat, 9 Mar 2024 00:37:16 +0100 Subject: [PATCH 04/23] feat: printFluxes better error with empty fluxes --- core/printFluxes.m | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/core/printFluxes.m b/core/printFluxes.m index 8b484aa0..5fc6d9d4 100755 --- a/core/printFluxes.m +++ b/core/printFluxes.m @@ -63,7 +63,10 @@ function printFluxes(model, fluxes, onlyExchange, cutOffFlux, outputFile,outputS else metaboliteList=convertCharArray(metaboliteList); end -if size(fluxes,1)~=numel(model.rxns) +if isempty(fluxes) + EM='Empty vector of fluxes, solveLP possibly returned infeasible'; + dispEM(EM); +elseif size(fluxes,1)~=numel(model.rxns) EM='The number of fluxes and the number of reactions must be the same'; dispEM(EM); end From 3c078ab7b3309b7fc670e7292b53b5ab76739810 Mon Sep 17 00:00:00 2001 From: Eduard Kerkhoven Date: Sat, 9 Mar 2024 00:37:38 +0100 Subject: [PATCH 05/23] fix: getGenesFromGrRules if '|' in gene --- core/getGenesFromGrRules.m | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/core/getGenesFromGrRules.m b/core/getGenesFromGrRules.m index 7f84fa5f..857d7169 100644 --- a/core/getGenesFromGrRules.m +++ b/core/getGenesFromGrRules.m @@ -31,7 +31,7 @@ end % check if the grRules use written or symbolic boolean operators -if any(contains(grRules,{'&','|'})) +if any(contains(grRules,{' & ',' | '})) % fix some potential missing spaces between parentheses and &/| grRules = regexprep(grRules,'\)&',') &'); % ")&" -> ") &" grRules = regexprep(grRules,'&\(','& ('); % "&(" -> "& (" @@ -50,11 +50,12 @@ end % extract list of genes from each reaction -rxnGenes = cellfun(@(r) unique(regexp(r,'[^&|\(\) ]+','match')),grRules,'UniformOutput',false); +rxnGenes = cellfun(@(r) unique(strsplit(r,{' | ',' & '})),grRules,'UniformOutput',false); % construct new gene list nonEmpty = ~cellfun(@isempty,rxnGenes); genes = unique([rxnGenes{nonEmpty}]'); +genes(cellfun(@isempty,genes)) = []; if ~isempty(originalGenes) if ~isequal(sort(originalGenes), sort(genes)) From 4d7853dd362b464bfde1832ce45f98cc9259747e Mon Sep 17 00:00:00 2001 From: Eduard Kerkhoven Date: Tue, 12 Mar 2024 00:05:51 +0100 Subject: [PATCH 06/23] fix: getGenesFromGrRules correct earlier fix --- core/getGenesFromGrRules.m | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/core/getGenesFromGrRules.m b/core/getGenesFromGrRules.m index 857d7169..ac97c771 100644 --- a/core/getGenesFromGrRules.m +++ b/core/getGenesFromGrRules.m @@ -50,7 +50,7 @@ end % extract list of genes from each reaction -rxnGenes = cellfun(@(r) unique(strsplit(r,{' | ',' & '})),grRules,'UniformOutput',false); +rxnGenes = cellfun(@(r) regexprep(unique(strsplit(r,{' | ',' & '})),'[\(\) ]+',''),grRules,'UniformOutput',false); % construct new gene list nonEmpty = ~cellfun(@isempty,rxnGenes); From 48ff147b5a24e9c25c87a4f83309884df1f054fb Mon Sep 17 00:00:00 2001 From: Eduard Kerkhoven Date: Thu, 14 Mar 2024 09:05:36 +0100 Subject: [PATCH 07/23] fix: getModelFromHomology remove geneFrom field --- core/getModelFromHomology.m | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/core/getModelFromHomology.m b/core/getModelFromHomology.m index 6f4adeb0..30aca2ac 100755 --- a/core/getModelFromHomology.m +++ b/core/getModelFromHomology.m @@ -115,6 +115,11 @@ if isfield(models{i},'geneMiriams') models{i}=rmfield(models{i},'geneMiriams'); end + %The geneFrom field also loses meaning if the genes are replaced by + %orthologs + if isfield(models{i},'geneFrom') + models{i}=rmfield(models{i},'geneFrom'); + end end %Check that genes do not begin with ( or end with ), as this makes problematic grRules From ff086b46f929d9146ac3cbe34ada96ce1dc4cd8c Mon Sep 17 00:00:00 2001 From: Eduard Kerkhoven Date: Thu, 14 Mar 2024 09:22:24 +0100 Subject: [PATCH 08/23] refactor: reduce default verbosity --- core/getMinNrFluxes.m | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/core/getMinNrFluxes.m b/core/getMinNrFluxes.m index 25deba8c..5b24530f 100755 --- a/core/getMinNrFluxes.m +++ b/core/getMinNrFluxes.m @@ -135,7 +135,7 @@ prob=rmfield(prob,{'blx','bux','blc','buc'}); % Optimize the problem -res = optimizeProb(prob,params); +res = optimizeProb(prob,params,false); isFeasible=checkSolution(res); if ~isFeasible From 4f4354ae1743e886ac3354caf915aee515cca564 Mon Sep 17 00:00:00 2001 From: Eduard Kerkhoven Date: Thu, 14 Mar 2024 09:22:44 +0100 Subject: [PATCH 09/23] fix: writeYAMLmodel allow empty id and name fields --- io/writeYAMLmodel.m | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-) diff --git a/io/writeYAMLmodel.m b/io/writeYAMLmodel.m index fb3e3276..63e0455e 100644 --- a/io/writeYAMLmodel.m +++ b/io/writeYAMLmodel.m @@ -317,8 +317,16 @@ function writeMetadata(model,fid) % are hard-coded defaults for HumanGEM. fprintf(fid, '- metaData:\n'); -fprintf(fid, ' id: "%s"\n', model.id); -fprintf(fid, ' name: "%s"\n',model.name); +if isfield(model,'id') + fprintf(fid, ' id: "%s"\n', model.id); +else + fprintf(fid, ' id: "blankID"\n'); +end +if isfield(model,'name') + fprintf(fid, ' name: "%s"\n',model.name); +else + fprintf(fid, ' name: "blankName"\n'); +end if isfield(model,'version') fprintf(fid, ' version: "%s"\n',model.version); end From 29667255802073d84efc000540504416ecd418cc Mon Sep 17 00:00:00 2001 From: Eduard Kerkhoven Date: Thu, 14 Mar 2024 09:23:20 +0100 Subject: [PATCH 10/23] doc: updateDocumentation --- doc/core/getGenesFromGrRules.html | 33 +- doc/core/getMinNrFluxes.html | 2 +- doc/core/getModelFromHomology.html | 851 ++++++++++++------------ doc/core/printFluxes.html | 241 +++---- doc/external/kegg/getModelFromKEGG.html | 100 +-- doc/io/writeYAMLmodel.html | 249 +++---- 6 files changed, 750 insertions(+), 726 deletions(-) diff --git a/doc/core/getGenesFromGrRules.html b/doc/core/getGenesFromGrRules.html index 12835184..19302a47 100644 --- a/doc/core/getGenesFromGrRules.html +++ b/doc/core/getGenesFromGrRules.html @@ -97,7 +97,7 @@

SOURCE CODE ^end 0032 0033 % check if the grRules use written or symbolic boolean operators -0034 if any(contains(grRules,{'&','|'})) +0034 if any(contains(grRules,{' & ',' | '})) 0035 % fix some potential missing spaces between parentheses and &/| 0036 grRules = regexprep(grRules,'\)&',') &'); % ")&" -> ") &" 0037 grRules = regexprep(grRules,'&\(','& ('); % "&(" -> "& (" @@ -116,25 +116,26 @@

SOURCE CODE ^end 0051 0052 % extract list of genes from each reaction -0053 rxnGenes = cellfun(@(r) unique(regexp(r,'[^&|\(\) ]+','match')),grRules,'UniformOutput',false); +0053 rxnGenes = cellfun(@(r) regexprep(unique(strsplit(r,{' | ',' & '})),'[\(\) ]+',''),grRules,'UniformOutput',false); 0054 0055 % construct new gene list 0056 nonEmpty = ~cellfun(@isempty,rxnGenes); 0057 genes = unique([rxnGenes{nonEmpty}]'); -0058 -0059 if ~isempty(originalGenes) -0060 if ~isequal(sort(originalGenes), sort(genes)) -0061 error('The grRules and original gene list are inconsistent!'); -0062 else -0063 genes = originalGenes; -0064 end -0065 end -0066 -0067 % construct new rxnGeneMat (if requested) -0068 if nargout > 1 -0069 rxnGeneCell = cellfun(@(rg) ismember(genes,rg),rxnGenes,'UniformOutput',false); -0070 rxnGeneMat = sparse(double(horzcat(rxnGeneCell{:})')); -0071 end +0058 genes(cellfun(@isempty,genes)) = []; +0059 +0060 if ~isempty(originalGenes) +0061 if ~isequal(sort(originalGenes), sort(genes)) +0062 error('The grRules and original gene list are inconsistent!'); +0063 else +0064 genes = originalGenes; +0065 end +0066 end +0067 +0068 % construct new rxnGeneMat (if requested) +0069 if nargout > 1 +0070 rxnGeneCell = cellfun(@(rg) ismember(genes,rg),rxnGenes,'UniformOutput',false); +0071 rxnGeneMat = sparse(double(horzcat(rxnGeneCell{:})')); +0072 end
Generated by m2html © 2005
\ No newline at end of file diff --git a/doc/core/getMinNrFluxes.html b/doc/core/getMinNrFluxes.html index a6595cb4..625f9f6b 100644 --- a/doc/core/getMinNrFluxes.html +++ b/doc/core/getMinNrFluxes.html @@ -205,7 +205,7 @@

SOURCE CODE ^'blx','bux','blc','buc'}); 0136 0137 % Optimize the problem -0138 res = optimizeProb(prob,params); +0138 res = optimizeProb(prob,params,false); 0139 isFeasible=checkSolution(res); 0140 0141 if ~isFeasible diff --git a/doc/core/getModelFromHomology.html b/doc/core/getModelFromHomology.html index f1be6abf..464b2bfb 100644 --- a/doc/core/getModelFromHomology.html +++ b/doc/core/getModelFromHomology.html @@ -222,434 +222,439 @@

SOURCE CODE ^if isfield(models{i},'geneMiriams') 0116 models{i}=rmfield(models{i},'geneMiriams'); 0117 end -0118 end -0119 -0120 %Check that genes do not begin with ( or end with ), as this makes problematic grRules -0121 for i=1:numel(blastStructure) -0122 problemGenes = startsWith(blastStructure(i).fromGenes,'(') | endsWith(blastStructure(i).fromGenes,')'); -0123 if any(problemGenes) -0124 error(['One or multiple gene identifiers from ' blastStructure(i).fromId ... -0125 ' starts with ''('' and/or ends with '')'', which is not allowed']) -0126 end -0127 end -0128 -0129 %Assume for now that all information is there and that it's correct. This -0130 %is important to fix since no further checks are being made! -0131 -0132 %Check whether provided fasta files use the same gene identifiers as -0133 %provided template models -0134 for i=1:numel(blastStructure) -0135 if ~strcmp(blastStructure(i).fromId,getModelFor) -0136 j=strcmpi(blastStructure(i).fromId,modelNames); -0137 if j==0 -0138 error(['While the blastStructure contains sequences from '... -0139 'organismID "%s" (as\nprovided in getBlast), none of '... -0140 'template models have this id (as model.id)'],... -0141 string(blastStructure(i).fromId)); -0142 end -0143 k=sum(ismember(blastStructure(i).fromGenes,models{j}.genes)); -0144 if k<(numel(models{j}.genes)*0.05) -0145 error(['Less than 5%% of the genes in the template model '... -0146 'with model.id "%s"\ncan be found in the blastStructure. '... -0147 'Ensure that the protein FASTA\nused in getBlast and '... -0148 'the template model used in getModelFromHomology\nuse '... -0149 'the same style of gene identifiers'],models{j}.id) -0150 end -0151 end -0152 end -0153 -0154 %Standardize grRules of template models -0155 for i=1:length(models) -0156 fprintf('\nStandardizing grRules of template model with ID "%s" ...',models{i}.id); -0157 [models{i}.grRules,models{i}.rxnGeneMat]=standardizeGrRules(models{i},false); -0158 end -0159 fprintf(' done\n'); -0160 -0161 %Remove all gene matches that are below the cutoffs -0162 for i=1:numel(blastStructure) -0163 indexes=blastStructure(i).evalue<maxE & blastStructure(i).aligLen>=minLen & blastStructure(i).identity>=minIde; %Do it in this direction to lose NaNs -0164 blastStructure(i).fromGenes(~indexes)=[]; -0165 blastStructure(i).toGenes(~indexes)=[]; -0166 blastStructure(i).evalue(~indexes)=[]; -0167 blastStructure(i).identity(~indexes)=[]; -0168 blastStructure(i).aligLen(~indexes)=[]; -0169 blastStructure(i).bitscore(~indexes)=[]; -0170 blastStructure(i).ppos(~indexes)=[]; -0171 end -0172 -0173 %Remove all reactions from the models that have no genes encoding for them. -0174 %Also remove all genes that encode for no reactions. There shouldn't be any -0175 %but there might be mistakes -0176 for i=1:numel(models) -0177 [hasGenes, ~]=find(models{i}.rxnGeneMat); -0178 hasNoGenes=1:numel(models{i}.rxns); -0179 hasNoGenes(hasGenes)=[]; -0180 models{i}=removeReactions(models{i},hasNoGenes,true,true); -0181 end -0182 -0183 %Create a structure that contains all genes used in the blasts in any -0184 %direction for each of the models in 'models' and for the new organism. The -0185 %first cell is for the new organism and then according to the preferred -0186 %order. If no such order is supplied, then according to the order in -0187 %'models' -0188 allGenes=cell(numel(models)+1,1); -0189 if isempty(preferredOrder) -0190 useOrder=modelNames; -0191 else -0192 useOrder=preferredOrder; -0193 end -0194 -0195 %Get the corresponding indexes for those models in the 'models' structure -0196 useOrderIndexes=zeros(numel(models),1); -0197 for i=1:numel(models) -0198 [~, index]=ismember(models{i}.id,useOrder); -0199 useOrderIndexes(index)=i; -0200 end -0201 -0202 %Remove all genes from the blast structure that have no genes in the models -0203 if onlyGenesInModels==true -0204 modelGenes={}; -0205 for i=1:numel(models) -0206 modelGenes=[modelGenes;models{i}.genes]; -0207 end -0208 for i=1:numel(blastStructure) -0209 %Check to see if it should match the toId or fromId -0210 if strcmpi(blastStructure(i).fromId,getModelFor) -0211 I=ismember(blastStructure(i).toGenes,modelGenes); -0212 else -0213 I=ismember(blastStructure(i).fromGenes,modelGenes); -0214 end -0215 blastStructure(i).fromGenes(~I)=[]; -0216 blastStructure(i).toGenes(~I)=[]; -0217 blastStructure(i).evalue(~I)=[]; -0218 blastStructure(i).identity(~I)=[]; -0219 blastStructure(i).aligLen(~I)=[]; -0220 blastStructure(i).bitscore(~I)=[]; -0221 blastStructure(i).ppos(~I)=[]; -0222 -0223 %Check that no matching in blastStructure is empty. This happens if -0224 %no genes in the models are present in the corresponding sheet -0225 if isempty(blastStructure(i).fromGenes) -0226 EM=['No genes in matching from ' blastStructure(i).fromId ' to ' blastStructure(i).toId ' are present in the corresponding model']; -0227 dispEM(EM); -0228 end -0229 end -0230 end -0231 -0232 %If only best orthologs are to be used then all other measurements are -0233 %deleted from the blastStructure. All code after this stays the same. This -0234 %means that preferred order can still matter. The best ortholog scoring is -0235 %based only on the E-value -0236 if strictness==3 -0237 for i=1:numel(blastStructure) -0238 keep=false(numel(blastStructure(i).toGenes),1); -0239 [allFromGenes, ~, I]=unique(blastStructure(i).fromGenes); -0240 -0241 %It would be nice to get rid of this loop -0242 for j=1:numel(allFromGenes) -0243 allMatches=find(I==j); -0244 bestMatches=allMatches(blastStructure(i).evalue(allMatches)==min(blastStructure(i).evalue(allMatches))); -0245 -0246 %Keep the best matches -0247 keep(bestMatches)=true; -0248 end -0249 -0250 %Delete all matches that were not best matches -0251 blastStructure(i).fromGenes(~keep)=[]; -0252 blastStructure(i).toGenes(~keep)=[]; -0253 blastStructure(i).evalue(~keep)=[]; -0254 blastStructure(i).identity(~keep)=[]; -0255 blastStructure(i).aligLen(~keep)=[]; -0256 blastStructure(i).bitscore(~keep)=[]; -0257 blastStructure(i).ppos(~keep)=[]; -0258 end -0259 end -0260 -0261 useOrder=[{getModelFor};useOrder]; -0262 -0263 for i=1:numel(blastStructure) -0264 [~, toIndex]=ismember(blastStructure(i).toId,useOrder); -0265 [~, fromIndex]=ismember(blastStructure(i).fromId,useOrder); -0266 -0267 %Add all genes to the corresponding list in allGenes -0268 allGenes{toIndex}=[allGenes{toIndex};blastStructure(i).toGenes]; -0269 allGenes{fromIndex}=[allGenes{fromIndex};blastStructure(i).fromGenes]; -0270 end -0271 -0272 %Keep only the unique gene names -0273 maxOtherGeneNr=0; %Determines the dimension of the connectivity matrixes -0274 for i=1:numel(allGenes) -0275 allGenes{i}=unique(allGenes{i}); -0276 if i>1 -0277 if numel(allGenes{i})>maxOtherGeneNr -0278 maxOtherGeneNr=numel(allGenes{i}); -0279 end -0280 end -0281 end -0282 -0283 %Generate a cell array of matrixes that describes how the genes in the new -0284 %organism map to the models. Each cell matches to the corresponding model -0285 %in useOrder (starting at 2 of course). First dimension is gene in new -0286 %organism, second which gene it is in the other organism. The second matrix -0287 %describes how they map back. -0288 -0289 %As it is now, a significant match is indicated by a 1. This could be -0290 %expanded to contain some kind of significance level. The first dimension -0291 %is still the genes in the new model. -0292 -0293 allTo=cell(numel(useOrder)-1,1); -0294 allFrom=cell(numel(useOrder)-1,1); -0295 -0296 for i=1:numel(useOrder)-1 -0297 allTo{i}=sparse(numel(allGenes{1}),numel(allGenes{i+1})); -0298 allFrom{i}=sparse(numel(allGenes{1}),numel(allGenes{i+1})); -0299 end +0118 %The geneFrom field also loses meaning if the genes are replaced by +0119 %orthologs +0120 if isfield(models{i},'geneFrom') +0121 models{i}=rmfield(models{i},'geneFrom'); +0122 end +0123 end +0124 +0125 %Check that genes do not begin with ( or end with ), as this makes problematic grRules +0126 for i=1:numel(blastStructure) +0127 problemGenes = startsWith(blastStructure(i).fromGenes,'(') | endsWith(blastStructure(i).fromGenes,')'); +0128 if any(problemGenes) +0129 error(['One or multiple gene identifiers from ' blastStructure(i).fromId ... +0130 ' starts with ''('' and/or ends with '')'', which is not allowed']) +0131 end +0132 end +0133 +0134 %Assume for now that all information is there and that it's correct. This +0135 %is important to fix since no further checks are being made! +0136 +0137 %Check whether provided fasta files use the same gene identifiers as +0138 %provided template models +0139 for i=1:numel(blastStructure) +0140 if ~strcmp(blastStructure(i).fromId,getModelFor) +0141 j=strcmpi(blastStructure(i).fromId,modelNames); +0142 if j==0 +0143 error(['While the blastStructure contains sequences from '... +0144 'organismID "%s" (as\nprovided in getBlast), none of '... +0145 'template models have this id (as model.id)'],... +0146 string(blastStructure(i).fromId)); +0147 end +0148 k=sum(ismember(blastStructure(i).fromGenes,models{j}.genes)); +0149 if k<(numel(models{j}.genes)*0.05) +0150 error(['Less than 5%% of the genes in the template model '... +0151 'with model.id "%s"\ncan be found in the blastStructure. '... +0152 'Ensure that the protein FASTA\nused in getBlast and '... +0153 'the template model used in getModelFromHomology\nuse '... +0154 'the same style of gene identifiers'],models{j}.id) +0155 end +0156 end +0157 end +0158 +0159 %Standardize grRules of template models +0160 for i=1:length(models) +0161 fprintf('\nStandardizing grRules of template model with ID "%s" ...',models{i}.id); +0162 [models{i}.grRules,models{i}.rxnGeneMat]=standardizeGrRules(models{i},false); +0163 end +0164 fprintf(' done\n'); +0165 +0166 %Remove all gene matches that are below the cutoffs +0167 for i=1:numel(blastStructure) +0168 indexes=blastStructure(i).evalue<maxE & blastStructure(i).aligLen>=minLen & blastStructure(i).identity>=minIde; %Do it in this direction to lose NaNs +0169 blastStructure(i).fromGenes(~indexes)=[]; +0170 blastStructure(i).toGenes(~indexes)=[]; +0171 blastStructure(i).evalue(~indexes)=[]; +0172 blastStructure(i).identity(~indexes)=[]; +0173 blastStructure(i).aligLen(~indexes)=[]; +0174 blastStructure(i).bitscore(~indexes)=[]; +0175 blastStructure(i).ppos(~indexes)=[]; +0176 end +0177 +0178 %Remove all reactions from the models that have no genes encoding for them. +0179 %Also remove all genes that encode for no reactions. There shouldn't be any +0180 %but there might be mistakes +0181 for i=1:numel(models) +0182 [hasGenes, ~]=find(models{i}.rxnGeneMat); +0183 hasNoGenes=1:numel(models{i}.rxns); +0184 hasNoGenes(hasGenes)=[]; +0185 models{i}=removeReactions(models{i},hasNoGenes,true,true); +0186 end +0187 +0188 %Create a structure that contains all genes used in the blasts in any +0189 %direction for each of the models in 'models' and for the new organism. The +0190 %first cell is for the new organism and then according to the preferred +0191 %order. If no such order is supplied, then according to the order in +0192 %'models' +0193 allGenes=cell(numel(models)+1,1); +0194 if isempty(preferredOrder) +0195 useOrder=modelNames; +0196 else +0197 useOrder=preferredOrder; +0198 end +0199 +0200 %Get the corresponding indexes for those models in the 'models' structure +0201 useOrderIndexes=zeros(numel(models),1); +0202 for i=1:numel(models) +0203 [~, index]=ismember(models{i}.id,useOrder); +0204 useOrderIndexes(index)=i; +0205 end +0206 +0207 %Remove all genes from the blast structure that have no genes in the models +0208 if onlyGenesInModels==true +0209 modelGenes={}; +0210 for i=1:numel(models) +0211 modelGenes=[modelGenes;models{i}.genes]; +0212 end +0213 for i=1:numel(blastStructure) +0214 %Check to see if it should match the toId or fromId +0215 if strcmpi(blastStructure(i).fromId,getModelFor) +0216 I=ismember(blastStructure(i).toGenes,modelGenes); +0217 else +0218 I=ismember(blastStructure(i).fromGenes,modelGenes); +0219 end +0220 blastStructure(i).fromGenes(~I)=[]; +0221 blastStructure(i).toGenes(~I)=[]; +0222 blastStructure(i).evalue(~I)=[]; +0223 blastStructure(i).identity(~I)=[]; +0224 blastStructure(i).aligLen(~I)=[]; +0225 blastStructure(i).bitscore(~I)=[]; +0226 blastStructure(i).ppos(~I)=[]; +0227 +0228 %Check that no matching in blastStructure is empty. This happens if +0229 %no genes in the models are present in the corresponding sheet +0230 if isempty(blastStructure(i).fromGenes) +0231 EM=['No genes in matching from ' blastStructure(i).fromId ' to ' blastStructure(i).toId ' are present in the corresponding model']; +0232 dispEM(EM); +0233 end +0234 end +0235 end +0236 +0237 %If only best orthologs are to be used then all other measurements are +0238 %deleted from the blastStructure. All code after this stays the same. This +0239 %means that preferred order can still matter. The best ortholog scoring is +0240 %based only on the E-value +0241 if strictness==3 +0242 for i=1:numel(blastStructure) +0243 keep=false(numel(blastStructure(i).toGenes),1); +0244 [allFromGenes, ~, I]=unique(blastStructure(i).fromGenes); +0245 +0246 %It would be nice to get rid of this loop +0247 for j=1:numel(allFromGenes) +0248 allMatches=find(I==j); +0249 bestMatches=allMatches(blastStructure(i).evalue(allMatches)==min(blastStructure(i).evalue(allMatches))); +0250 +0251 %Keep the best matches +0252 keep(bestMatches)=true; +0253 end +0254 +0255 %Delete all matches that were not best matches +0256 blastStructure(i).fromGenes(~keep)=[]; +0257 blastStructure(i).toGenes(~keep)=[]; +0258 blastStructure(i).evalue(~keep)=[]; +0259 blastStructure(i).identity(~keep)=[]; +0260 blastStructure(i).aligLen(~keep)=[]; +0261 blastStructure(i).bitscore(~keep)=[]; +0262 blastStructure(i).ppos(~keep)=[]; +0263 end +0264 end +0265 +0266 useOrder=[{getModelFor};useOrder]; +0267 +0268 for i=1:numel(blastStructure) +0269 [~, toIndex]=ismember(blastStructure(i).toId,useOrder); +0270 [~, fromIndex]=ismember(blastStructure(i).fromId,useOrder); +0271 +0272 %Add all genes to the corresponding list in allGenes +0273 allGenes{toIndex}=[allGenes{toIndex};blastStructure(i).toGenes]; +0274 allGenes{fromIndex}=[allGenes{fromIndex};blastStructure(i).fromGenes]; +0275 end +0276 +0277 %Keep only the unique gene names +0278 maxOtherGeneNr=0; %Determines the dimension of the connectivity matrixes +0279 for i=1:numel(allGenes) +0280 allGenes{i}=unique(allGenes{i}); +0281 if i>1 +0282 if numel(allGenes{i})>maxOtherGeneNr +0283 maxOtherGeneNr=numel(allGenes{i}); +0284 end +0285 end +0286 end +0287 +0288 %Generate a cell array of matrixes that describes how the genes in the new +0289 %organism map to the models. Each cell matches to the corresponding model +0290 %in useOrder (starting at 2 of course). First dimension is gene in new +0291 %organism, second which gene it is in the other organism. The second matrix +0292 %describes how they map back. +0293 +0294 %As it is now, a significant match is indicated by a 1. This could be +0295 %expanded to contain some kind of significance level. The first dimension +0296 %is still the genes in the new model. +0297 +0298 allTo=cell(numel(useOrder)-1,1); +0299 allFrom=cell(numel(useOrder)-1,1); 0300 -0301 %Fill the matches to other species -0302 for i=1:numel(blastStructure) -0303 if strcmp(blastStructure(i).toId,getModelFor) -0304 %This was 'to' the new organism. They should all match so no checks -0305 %are being made -0306 [~, a]=ismember(blastStructure(i).toGenes,allGenes{1}); -0307 [~, fromModel]=ismember(blastStructure(i).fromId,useOrder); -0308 [~, b]=ismember(blastStructure(i).fromGenes,allGenes{fromModel}); -0309 idx = sub2ind(size(allTo{fromModel-1}), a, b); -0310 allTo{fromModel-1}(idx)=1; -0311 else -0312 %This was 'from' the new organism -0313 [~, a]=ismember(blastStructure(i).fromGenes,allGenes{1}); -0314 [~, toModel]=ismember(blastStructure(i).toId,useOrder); -0315 [~, b]=ismember(blastStructure(i).toGenes,allGenes{toModel}); -0316 idx = sub2ind(size(allFrom{toModel-1}), a, b); -0317 allFrom{toModel-1}(idx)=1; -0318 end -0319 end -0320 -0321 %Now we have all the gene matches in a convenient way. For all the genes in -0322 %the new organism get the genes that should be included from other -0323 %organisms. If all genes should be included this simply means keep the -0324 %allFrom matrix as it is. If only orthologs which could be mapped in both -0325 %BLAST directions are to be included then only those elements are kept. -0326 -0327 finalMappings=cell(numel(useOrder)-1,1); -0328 if strictness==1 || strictness==3 -0329 for j=1:numel(allFrom) -0330 finalMappings{j}=allTo{j}~=0 & allFrom{j}~=0; -0331 end -0332 else -0333 if mapNewGenesToOld==true -0334 finalMappings=allFrom; -0335 else -0336 finalMappings=allTo; -0337 end -0338 end -0339 -0340 %Remove all genes from the mapping that are not in the models. This doesn't -0341 %do much if only genes in the models were used for the original mapping. -0342 %Also simplify the finalMapping and allGenes structures so that they only -0343 %contain mappings that exist -0344 usedNewGenes=false(numel(allGenes{1}),1); -0345 -0346 for i=1:numel(allGenes)-1 -0347 %First remove mappings for those genes that are not in the model -0348 if onlyGenesInModels==false -0349 a=ismember(allGenes{i+1},models{useOrderIndexes(i)}.genes); -0350 finalMappings{i}(:,~a)=false; -0351 end -0352 -0353 %Then remove unused ones and simplify -0354 [a, b]=find(finalMappings{i}); -0355 usedGenes=false(numel(allGenes{i+1}),1); -0356 usedNewGenes(a)=true; -0357 usedGenes(b)=true; -0358 finalMappings{i}=finalMappings{i}(:,usedGenes); -0359 allGenes{i+1}=allGenes{i+1}(usedGenes); -0360 end -0361 -0362 %Remove all new genes that have not been mapped to anything -0363 allGenes{1}=allGenes{1}(usedNewGenes); -0364 for i=1:numel(finalMappings) -0365 finalMappings{i}=finalMappings{i}(usedNewGenes,:); -0366 end -0367 -0368 %Now is it time to choose which reactions should be included from which -0369 %models. If there is a preferred order specified then each gene can only -0370 %result in reactions from one model, otherwise they should all be included -0371 -0372 %Start by simplifying the models by removing genes/reactions that are not -0373 %used. This is where it gets weird with complexes, especially "or" -0374 %complexes. In this step only reactions which are encoded by one single -0375 %gene, or where all genes should be deleted, are deleted. The info on the -0376 %full complex is still present in the grRules -0377 -0378 for i=1:numel(models) -0379 a=ismember(models{useOrderIndexes(i)}.genes,allGenes{i+1}); -0380 -0381 %Remove reactions that are not associated to any of the genes in -0382 %allGenes, thereby also keeping complexes where only for one of the -0383 %genes was matched -0384 [rxnsToKeep,~] = find(models{useOrderIndexes(i)}.rxnGeneMat(:,a)); -0385 rxnsToRemove = repmat(1,numel(models{useOrderIndexes(i)}.rxns),1); -0386 rxnsToRemove(rxnsToKeep) = 0; -0387 rxnsToRemove = find(rxnsToRemove); -0388 models{useOrderIndexes(i)}=removeReactions(models{useOrderIndexes(i)},rxnsToRemove,true,true,true); -0389 end -0390 -0391 %Since mergeModels function will be used in the end, the models are -0392 %simplified further by deleting genes/reactions in the order specified by -0393 %preferredOrder. This means that the last model will only contain reactions -0394 %for genes that mapped only to that model +0301 for i=1:numel(useOrder)-1 +0302 allTo{i}=sparse(numel(allGenes{1}),numel(allGenes{i+1})); +0303 allFrom{i}=sparse(numel(allGenes{1}),numel(allGenes{i+1})); +0304 end +0305 +0306 %Fill the matches to other species +0307 for i=1:numel(blastStructure) +0308 if strcmp(blastStructure(i).toId,getModelFor) +0309 %This was 'to' the new organism. They should all match so no checks +0310 %are being made +0311 [~, a]=ismember(blastStructure(i).toGenes,allGenes{1}); +0312 [~, fromModel]=ismember(blastStructure(i).fromId,useOrder); +0313 [~, b]=ismember(blastStructure(i).fromGenes,allGenes{fromModel}); +0314 idx = sub2ind(size(allTo{fromModel-1}), a, b); +0315 allTo{fromModel-1}(idx)=1; +0316 else +0317 %This was 'from' the new organism +0318 [~, a]=ismember(blastStructure(i).fromGenes,allGenes{1}); +0319 [~, toModel]=ismember(blastStructure(i).toId,useOrder); +0320 [~, b]=ismember(blastStructure(i).toGenes,allGenes{toModel}); +0321 idx = sub2ind(size(allFrom{toModel-1}), a, b); +0322 allFrom{toModel-1}(idx)=1; +0323 end +0324 end +0325 +0326 %Now we have all the gene matches in a convenient way. For all the genes in +0327 %the new organism get the genes that should be included from other +0328 %organisms. If all genes should be included this simply means keep the +0329 %allFrom matrix as it is. If only orthologs which could be mapped in both +0330 %BLAST directions are to be included then only those elements are kept. +0331 +0332 finalMappings=cell(numel(useOrder)-1,1); +0333 if strictness==1 || strictness==3 +0334 for j=1:numel(allFrom) +0335 finalMappings{j}=allTo{j}~=0 & allFrom{j}~=0; +0336 end +0337 else +0338 if mapNewGenesToOld==true +0339 finalMappings=allFrom; +0340 else +0341 finalMappings=allTo; +0342 end +0343 end +0344 +0345 %Remove all genes from the mapping that are not in the models. This doesn't +0346 %do much if only genes in the models were used for the original mapping. +0347 %Also simplify the finalMapping and allGenes structures so that they only +0348 %contain mappings that exist +0349 usedNewGenes=false(numel(allGenes{1}),1); +0350 +0351 for i=1:numel(allGenes)-1 +0352 %First remove mappings for those genes that are not in the model +0353 if onlyGenesInModels==false +0354 a=ismember(allGenes{i+1},models{useOrderIndexes(i)}.genes); +0355 finalMappings{i}(:,~a)=false; +0356 end +0357 +0358 %Then remove unused ones and simplify +0359 [a, b]=find(finalMappings{i}); +0360 usedGenes=false(numel(allGenes{i+1}),1); +0361 usedNewGenes(a)=true; +0362 usedGenes(b)=true; +0363 finalMappings{i}=finalMappings{i}(:,usedGenes); +0364 allGenes{i+1}=allGenes{i+1}(usedGenes); +0365 end +0366 +0367 %Remove all new genes that have not been mapped to anything +0368 allGenes{1}=allGenes{1}(usedNewGenes); +0369 for i=1:numel(finalMappings) +0370 finalMappings{i}=finalMappings{i}(usedNewGenes,:); +0371 end +0372 +0373 %Now is it time to choose which reactions should be included from which +0374 %models. If there is a preferred order specified then each gene can only +0375 %result in reactions from one model, otherwise they should all be included +0376 +0377 %Start by simplifying the models by removing genes/reactions that are not +0378 %used. This is where it gets weird with complexes, especially "or" +0379 %complexes. In this step only reactions which are encoded by one single +0380 %gene, or where all genes should be deleted, are deleted. The info on the +0381 %full complex is still present in the grRules +0382 +0383 for i=1:numel(models) +0384 a=ismember(models{useOrderIndexes(i)}.genes,allGenes{i+1}); +0385 +0386 %Remove reactions that are not associated to any of the genes in +0387 %allGenes, thereby also keeping complexes where only for one of the +0388 %genes was matched +0389 [rxnsToKeep,~] = find(models{useOrderIndexes(i)}.rxnGeneMat(:,a)); +0390 rxnsToRemove = repmat(1,numel(models{useOrderIndexes(i)}.rxns),1); +0391 rxnsToRemove(rxnsToKeep) = 0; +0392 rxnsToRemove = find(rxnsToRemove); +0393 models{useOrderIndexes(i)}=removeReactions(models{useOrderIndexes(i)},rxnsToRemove,true,true,true); +0394 end 0395 -0396 allUsedGenes=false(numel(allGenes{1}),1); -0397 -0398 if ~isempty(preferredOrder) && numel(models)>1 -0399 [usedGenes, ~]=find(finalMappings{1}); %All that are used in the first model in preferredOrder -0400 allUsedGenes(usedGenes)=true; -0401 for i=2:numel(finalMappings) -0402 [usedGenes, ~]=find(finalMappings{i}); -0403 usedGenes=unique(usedGenes); -0404 a=ismember(usedGenes,find(allUsedGenes)); -0405 -0406 [~, genesToDelete]=find(finalMappings{i}(usedGenes(a),:)); %IMPORTANT! IS it really correct to remove all genes that map? -0407 genesToDelete=unique(genesToDelete); %Maybe not needed, but for clarity if nothing else -0408 -0409 %Remove all the genes that were already found and add the other -0410 %ones to allUsedGenes -0411 models{useOrderIndexes(i)}=removeGenes(models{useOrderIndexes(i)},allGenes{i+1}(genesToDelete),true,true,false); -0412 allUsedGenes(usedGenes)=true; +0396 %Since mergeModels function will be used in the end, the models are +0397 %simplified further by deleting genes/reactions in the order specified by +0398 %preferredOrder. This means that the last model will only contain reactions +0399 %for genes that mapped only to that model +0400 +0401 allUsedGenes=false(numel(allGenes{1}),1); +0402 +0403 if ~isempty(preferredOrder) && numel(models)>1 +0404 [usedGenes, ~]=find(finalMappings{1}); %All that are used in the first model in preferredOrder +0405 allUsedGenes(usedGenes)=true; +0406 for i=2:numel(finalMappings) +0407 [usedGenes, ~]=find(finalMappings{i}); +0408 usedGenes=unique(usedGenes); +0409 a=ismember(usedGenes,find(allUsedGenes)); +0410 +0411 [~, genesToDelete]=find(finalMappings{i}(usedGenes(a),:)); %IMPORTANT! IS it really correct to remove all genes that map? +0412 genesToDelete=unique(genesToDelete); %Maybe not needed, but for clarity if nothing else 0413 -0414 %Remove the deleted genes from finalMappings and allGenes. -0415 finalMappings{i}(:,genesToDelete)=[]; -0416 allGenes{i+1}(genesToDelete)=[]; -0417 end -0418 end -0419 -0420 %Now loop through the models and update the gene associations. Genes not -0421 %belonging to the new organism will be renamed as 'OLD_MODELID_gene' -0422 for i=1:numel(models) -0423 %Find all the new genes that should be used for this model -0424 [newGenes, oldGenes]=find(finalMappings{i}); -0425 -0426 %Create a new gene list with the genes from the new organism and those -0427 %genes that could not be removed -0428 replaceableGenes=allGenes{i+1}(unique(oldGenes)); -0429 nonReplaceableGenes=setdiff(models{useOrderIndexes(i)}.genes,replaceableGenes); -0430 fullGeneList=[allGenes{1}(unique(newGenes));nonReplaceableGenes]; -0431 -0432 %Just to save some indexing later. This is the LAST index of -0433 %replaceable ones -0434 nonRepStartIndex=numel(unique(newGenes)); -0435 -0436 %Construct a new rxnGeneMat -0437 newRxnGeneMat=sparse(numel(models{useOrderIndexes(i)}.rxns),numel(fullGeneList)); -0438 -0439 %Now update the rxnGeneMat. This is a little tricky and could -0440 %probably be done in a more efficient way, but I just loop through the -0441 %reactions and add them one by one -0442 for j=1:numel(models{useOrderIndexes(i)}.rxns) -0443 %Get the old genes encoding for this reaction -0444 [~, oldGeneIds]=find(models{useOrderIndexes(i)}.rxnGeneMat(j,:)); -0445 -0446 %Update the matrix for each gene. This includes replacing one gene -0447 %with several new ones if there were several matches -0448 for k=1:numel(oldGeneIds) -0449 %Match the gene to one in the gene list. This is done as a text -0450 %match. Could probably be done better, but I'm a little lost in -0451 %the indexing -0452 -0453 geneName=models{useOrderIndexes(i)}.genes(oldGeneIds(k)); -0454 -0455 %First search in the mappable genes -0456 mapIndex=find(ismember(allGenes{i+1},geneName)); +0414 %Remove all the genes that were already found and add the other +0415 %ones to allUsedGenes +0416 models{useOrderIndexes(i)}=removeGenes(models{useOrderIndexes(i)},allGenes{i+1}(genesToDelete),true,true,false); +0417 allUsedGenes(usedGenes)=true; +0418 +0419 %Remove the deleted genes from finalMappings and allGenes. +0420 finalMappings{i}(:,genesToDelete)=[]; +0421 allGenes{i+1}(genesToDelete)=[]; +0422 end +0423 end +0424 +0425 %Now loop through the models and update the gene associations. Genes not +0426 %belonging to the new organism will be renamed as 'OLD_MODELID_gene' +0427 for i=1:numel(models) +0428 %Find all the new genes that should be used for this model +0429 [newGenes, oldGenes]=find(finalMappings{i}); +0430 +0431 %Create a new gene list with the genes from the new organism and those +0432 %genes that could not be removed +0433 replaceableGenes=allGenes{i+1}(unique(oldGenes)); +0434 nonReplaceableGenes=setdiff(models{useOrderIndexes(i)}.genes,replaceableGenes); +0435 fullGeneList=[allGenes{1}(unique(newGenes));nonReplaceableGenes]; +0436 +0437 %Just to save some indexing later. This is the LAST index of +0438 %replaceable ones +0439 nonRepStartIndex=numel(unique(newGenes)); +0440 +0441 %Construct a new rxnGeneMat +0442 newRxnGeneMat=sparse(numel(models{useOrderIndexes(i)}.rxns),numel(fullGeneList)); +0443 +0444 %Now update the rxnGeneMat. This is a little tricky and could +0445 %probably be done in a more efficient way, but I just loop through the +0446 %reactions and add them one by one +0447 for j=1:numel(models{useOrderIndexes(i)}.rxns) +0448 %Get the old genes encoding for this reaction +0449 [~, oldGeneIds]=find(models{useOrderIndexes(i)}.rxnGeneMat(j,:)); +0450 +0451 %Update the matrix for each gene. This includes replacing one gene +0452 %with several new ones if there were several matches +0453 for k=1:numel(oldGeneIds) +0454 %Match the gene to one in the gene list. This is done as a text +0455 %match. Could probably be done better, but I'm a little lost in +0456 %the indexing 0457 -0458 if ~isempty(mapIndex) -0459 % add the old genes -0460 hitGenes.oldGenes = [hitGenes.oldGenes, {geneName}]; -0461 -0462 %Get the new genes for that gene -0463 a=find(finalMappings{i}(:,mapIndex)); -0464 -0465 %Find the positions of these genes in the final gene list -0466 [~, b]=ismember(allGenes{1}(a),fullGeneList); -0467 -0468 %Update the matrix -0469 newRxnGeneMat(j,b)=1; -0470 -0471 %Update the grRules string. This is tricky, but I hope that -0472 %it's ok to replace the old gene name with the new one and -0473 %add ') or (' if there were several matches. Be sure of -0474 %this! -0475 repString=fullGeneList{b(1)}; -0476 if numel(b)>1 -0477 for l=2:numel(b) -0478 repString=[repString ' or ' fullGeneList{b(l)}]; -0479 end -0480 repString=['(' repString ')']; -0481 end -0482 -0483 % add the new matched genes -0484 hitGenes.newGenes = [hitGenes.newGenes, {repString}]; -0485 -0486 %Use regexprep instead of strrep to prevent partial matches -0487 models{useOrderIndexes(i)}.grRules{j}=regexprep(models{useOrderIndexes(i)}.grRules{j},['(^|\s|\()' geneName{1} '($|\s|\))'],['$1' repString '$2']); -0488 else -0489 %Then search in the non-replaceable genes. There could only -0490 %be one match here -0491 index=find(ismember(nonReplaceableGenes,geneName)); -0492 -0493 %Update the matrix -0494 newRxnGeneMat(j,nonRepStartIndex+index)=1; -0495 -0496 models{useOrderIndexes(i)}.grRules{j}=strrep(models{useOrderIndexes(i)}.grRules{j},geneName{1},strcat('OLD_',models{useOrderIndexes(i)}.id,'_',geneName{1})); -0497 end -0498 end -0499 end -0500 -0501 %Add the new list of genes -0502 models{useOrderIndexes(i)}.rxnGeneMat=newRxnGeneMat; -0503 if ~isempty(nonReplaceableGenes) -0504 models{useOrderIndexes(i)}.genes=[allGenes{1}(unique(newGenes));strcat('OLD_',models{useOrderIndexes(i)}.id,'_',nonReplaceableGenes)]; -0505 else -0506 models{useOrderIndexes(i)}.genes=allGenes{1}(unique(newGenes)); -0507 end -0508 if isfield(models{useOrderIndexes(i)},'geneComps') -0509 geneComps=models{useOrderIndexes(i)}.geneComps(1); -0510 models{useOrderIndexes(i)}.geneComps=zeros(numel(models{useOrderIndexes(i)}.genes),1); -0511 %Assume that all genes are in the same compartment, and this -0512 %compartment is specified for the first gene -0513 models{useOrderIndexes(i)}.geneComps(:)=geneComps; -0514 end -0515 end -0516 -0517 %Now merge the models. All information should be correct except for 'or' -0518 %complexes -0519 draftModel=mergeModels(models,'metNames'); -0520 -0521 %Remove unnecessary OLD_ genes, that were added with OR relationships -0522 regexStr=['OLD_(', strjoin(modelNames(:),'|'),')_(\S^\))+']; -0523 draftModel.grRules=regexprep(draftModel.grRules,[' or ' regexStr],''); -0524 draftModel.grRules=regexprep(draftModel.grRules,[regexStr ' or '],''); +0458 geneName=models{useOrderIndexes(i)}.genes(oldGeneIds(k)); +0459 +0460 %First search in the mappable genes +0461 mapIndex=find(ismember(allGenes{i+1},geneName)); +0462 +0463 if ~isempty(mapIndex) +0464 % add the old genes +0465 hitGenes.oldGenes = [hitGenes.oldGenes, {geneName}]; +0466 +0467 %Get the new genes for that gene +0468 a=find(finalMappings{i}(:,mapIndex)); +0469 +0470 %Find the positions of these genes in the final gene list +0471 [~, b]=ismember(allGenes{1}(a),fullGeneList); +0472 +0473 %Update the matrix +0474 newRxnGeneMat(j,b)=1; +0475 +0476 %Update the grRules string. This is tricky, but I hope that +0477 %it's ok to replace the old gene name with the new one and +0478 %add ') or (' if there were several matches. Be sure of +0479 %this! +0480 repString=fullGeneList{b(1)}; +0481 if numel(b)>1 +0482 for l=2:numel(b) +0483 repString=[repString ' or ' fullGeneList{b(l)}]; +0484 end +0485 repString=['(' repString ')']; +0486 end +0487 +0488 % add the new matched genes +0489 hitGenes.newGenes = [hitGenes.newGenes, {repString}]; +0490 +0491 %Use regexprep instead of strrep to prevent partial matches +0492 models{useOrderIndexes(i)}.grRules{j}=regexprep(models{useOrderIndexes(i)}.grRules{j},['(^|\s|\()' geneName{1} '($|\s|\))'],['$1' repString '$2']); +0493 else +0494 %Then search in the non-replaceable genes. There could only +0495 %be one match here +0496 index=find(ismember(nonReplaceableGenes,geneName)); +0497 +0498 %Update the matrix +0499 newRxnGeneMat(j,nonRepStartIndex+index)=1; +0500 +0501 models{useOrderIndexes(i)}.grRules{j}=strrep(models{useOrderIndexes(i)}.grRules{j},geneName{1},strcat('OLD_',models{useOrderIndexes(i)}.id,'_',geneName{1})); +0502 end +0503 end +0504 end +0505 +0506 %Add the new list of genes +0507 models{useOrderIndexes(i)}.rxnGeneMat=newRxnGeneMat; +0508 if ~isempty(nonReplaceableGenes) +0509 models{useOrderIndexes(i)}.genes=[allGenes{1}(unique(newGenes));strcat('OLD_',models{useOrderIndexes(i)}.id,'_',nonReplaceableGenes)]; +0510 else +0511 models{useOrderIndexes(i)}.genes=allGenes{1}(unique(newGenes)); +0512 end +0513 if isfield(models{useOrderIndexes(i)},'geneComps') +0514 geneComps=models{useOrderIndexes(i)}.geneComps(1); +0515 models{useOrderIndexes(i)}.geneComps=zeros(numel(models{useOrderIndexes(i)}.genes),1); +0516 %Assume that all genes are in the same compartment, and this +0517 %compartment is specified for the first gene +0518 models{useOrderIndexes(i)}.geneComps(:)=geneComps; +0519 end +0520 end +0521 +0522 %Now merge the models. All information should be correct except for 'or' +0523 %complexes +0524 draftModel=mergeModels(models,'metNames'); 0525 -0526 %Change name of the resulting model -0527 draftModel.id=getModelFor; -0528 name='Generated by getModelFromHomology using '; -0529 for i=1:numel(models) -0530 if i<numel(models) -0531 name=[name models{i}.id ', ']; -0532 else -0533 name=[name models{i}.id]; -0534 end -0535 end -0536 draftModel.name=name; -0537 draftModel.rxnNotes=cell(length(draftModel.rxns),1); -0538 draftModel.rxnNotes(:)={'Included by getModelFromHomology'}; -0539 draftModel.rxnConfidenceScores=NaN(length(draftModel.rxns),1); -0540 draftModel.rxnConfidenceScores(:)=2; -0541 draftModel=deleteUnusedGenes(draftModel,0); -0542 %Standardize grRules and notify if problematic grRules are found -0543 [draftModel.grRules,draftModel.rxnGeneMat]=standardizeGrRules(draftModel,false); -0544 draftModel=deleteUnusedGenes(draftModel,false); -0545 end +0526 %Remove unnecessary OLD_ genes, that were added with OR relationships +0527 regexStr=['OLD_(', strjoin(modelNames(:),'|'),')_(\S^\))+']; +0528 draftModel.grRules=regexprep(draftModel.grRules,[' or ' regexStr],''); +0529 draftModel.grRules=regexprep(draftModel.grRules,[regexStr ' or '],''); +0530 +0531 %Change name of the resulting model +0532 draftModel.id=getModelFor; +0533 name='Generated by getModelFromHomology using '; +0534 for i=1:numel(models) +0535 if i<numel(models) +0536 name=[name models{i}.id ', ']; +0537 else +0538 name=[name models{i}.id]; +0539 end +0540 end +0541 draftModel.name=name; +0542 draftModel.rxnNotes=cell(length(draftModel.rxns),1); +0543 draftModel.rxnNotes(:)={'Included by getModelFromHomology'}; +0544 draftModel.rxnConfidenceScores=NaN(length(draftModel.rxns),1); +0545 draftModel.rxnConfidenceScores(:)=2; +0546 draftModel=deleteUnusedGenes(draftModel,0); +0547 %Standardize grRules and notify if problematic grRules are found +0548 [draftModel.grRules,draftModel.rxnGeneMat]=standardizeGrRules(draftModel,false); +0549 draftModel=deleteUnusedGenes(draftModel,false); +0550 end
Generated by m2html © 2005
\ No newline at end of file diff --git a/doc/core/printFluxes.html b/doc/core/printFluxes.html index 451ad827..1aef30c5 100644 --- a/doc/core/printFluxes.html +++ b/doc/core/printFluxes.html @@ -140,126 +140,129 @@

SOURCE CODE ^else 0064 metaboliteList=convertCharArray(metaboliteList); 0065 end -0066 if size(fluxes,1)~=numel(model.rxns) -0067 EM='The number of fluxes and the number of reactions must be the same'; +0066 if isempty(fluxes) +0067 EM='Empty vector of fluxes, solveLP possibly returned infeasible'; 0068 dispEM(EM); -0069 end -0070 -0071 %Only keep reactions involving the defined metabolites -0072 if ~isempty(metaboliteList) -0073 I=ismember(upper(model.metNames),upper(metaboliteList)); -0074 [~, K]=find(model.S(I,:)); -0075 -0076 %Delete all other reactions -0077 toDelete=true(numel(model.rxns),1); -0078 toDelete(K)=false; -0079 model=removeReactions(model,toDelete); -0080 fluxes(toDelete,:)=[]; -0081 end -0082 -0083 if onlyExchange==true -0084 fprintf(fid,'EXCHANGE FLUXES:\n'); -0085 else -0086 fprintf(fid,'FLUXES:\n'); -0087 end -0088 -0089 %Remove reactions which are below the cut off -0090 toDelete=abs(fluxes)<cutOffFlux; -0091 toDelete=all(toDelete,2); -0092 model=removeReactions(model,toDelete,true,true); -0093 fluxes(toDelete,:)=[]; -0094 -0095 if any(strfind(outputString,'%eqn')) -0096 %Construct the equations -0097 eqn=constructEquations(model); -0098 else -0099 eqn=cell(numel(model.rxns),1); -0100 eqn(:)={''}; -0101 end -0102 if any(strfind(outputString,'%element')) -0103 %For printing equations using the composition -0104 cModel=model; -0105 cModel.metNames=cModel.metFormulas; -0106 cModel.metNames(cellfun(@isempty,cModel.metNames))={'?'}; -0107 element=constructEquations(cModel); -0108 else -0109 element=cell(numel(model.rxns),1); -0110 element(:)={''}; -0111 end -0112 -0113 if any(strfind(outputString,'%unbalanced')) || any(strfind(outputString,'%lumped')) -0114 balanceStructure=getElementalBalance(model); -0115 end -0116 -0117 unbalanced=cell(numel(model.rxns),1); -0118 unbalanced(:)={''}; -0119 if any(strfind(outputString,'%unbalanced')) -0120 unbalanced(balanceStructure.balanceStatus==0)={'(*)'}; -0121 unbalanced(balanceStructure.balanceStatus<0)={'(-)'}; -0122 end -0123 -0124 lumped=cell(numel(model.rxns),1); -0125 lumped(:)={''}; -0126 if any(strfind(outputString,'%lumped')) -0127 for i=1:numel(model.rxns) -0128 leftGroup=''; -0129 rightGroup=''; -0130 for j=1:numel(balanceStructure.elements.names) -0131 I=balanceStructure.leftComp(i,j); -0132 if I~=0 -0133 if I==1 -0134 leftGroup=[leftGroup balanceStructure.elements.abbrevs{j}]; -0135 else -0136 leftGroup=[leftGroup balanceStructure.elements.abbrevs{j} num2str(I)]; -0137 end -0138 end -0139 I=balanceStructure.rightComp(i,j); -0140 if I~=0 -0141 if I==1 -0142 rightGroup=[rightGroup balanceStructure.elements.abbrevs{j}]; -0143 else -0144 rightGroup=[rightGroup balanceStructure.elements.abbrevs{j} num2str(I)]; -0145 end -0146 end -0147 end -0148 if model.rev(i) -0149 lumped{i}=[leftGroup ' <=> ' rightGroup]; -0150 else -0151 lumped{i}=[leftGroup ' => ' rightGroup]; -0152 end -0153 end -0154 end -0155 -0156 for i=1:numel(model.rxns) -0157 %Only print if it's an exchange reaction or if all reactions should be -0158 %printed. Exchange reactions only have reactants or only products. -0159 reactants=model.S(:,i)<0; -0160 products=model.S(:,i)>0; -0161 -0162 %Only print if the absolute value is >= cutOffFlux -0163 if (onlyExchange==false || (~any(reactants) || ~any(products))) -0164 printString=outputString; -0165 -0166 %Produce the final string -0167 printString=strrep(printString,'%rxnID',model.rxns{i}); -0168 printString=strrep(printString,'%eqn',eqn{i}); -0169 printString=strrep(printString,'%rxnName',model.rxnNames{i}); -0170 printString=strrep(printString,'%lower',num2str(model.lb(i))); -0171 printString=strrep(printString,'%upper',num2str(model.ub(i))); -0172 printString=strrep(printString,'%obj',num2str(model.c(i))); -0173 printString=strrep(printString,'%flux',num2str(fluxes(i,:))); -0174 printString=strrep(printString,'%element',element{i}); -0175 printString=strrep(printString,'%unbalanced',unbalanced{i}); -0176 printString=strrep(printString,'%lumped',lumped{i}); -0177 fprintf(fid,printString); -0178 end -0179 end -0180 -0181 if fid~=1 -0182 fprintf('File successfully saved.\n'); -0183 fclose(fid); -0184 end -0185 end +0069 elseif size(fluxes,1)~=numel(model.rxns) +0070 EM='The number of fluxes and the number of reactions must be the same'; +0071 dispEM(EM); +0072 end +0073 +0074 %Only keep reactions involving the defined metabolites +0075 if ~isempty(metaboliteList) +0076 I=ismember(upper(model.metNames),upper(metaboliteList)); +0077 [~, K]=find(model.S(I,:)); +0078 +0079 %Delete all other reactions +0080 toDelete=true(numel(model.rxns),1); +0081 toDelete(K)=false; +0082 model=removeReactions(model,toDelete); +0083 fluxes(toDelete,:)=[]; +0084 end +0085 +0086 if onlyExchange==true +0087 fprintf(fid,'EXCHANGE FLUXES:\n'); +0088 else +0089 fprintf(fid,'FLUXES:\n'); +0090 end +0091 +0092 %Remove reactions which are below the cut off +0093 toDelete=abs(fluxes)<cutOffFlux; +0094 toDelete=all(toDelete,2); +0095 model=removeReactions(model,toDelete,true,true); +0096 fluxes(toDelete,:)=[]; +0097 +0098 if any(strfind(outputString,'%eqn')) +0099 %Construct the equations +0100 eqn=constructEquations(model); +0101 else +0102 eqn=cell(numel(model.rxns),1); +0103 eqn(:)={''}; +0104 end +0105 if any(strfind(outputString,'%element')) +0106 %For printing equations using the composition +0107 cModel=model; +0108 cModel.metNames=cModel.metFormulas; +0109 cModel.metNames(cellfun(@isempty,cModel.metNames))={'?'}; +0110 element=constructEquations(cModel); +0111 else +0112 element=cell(numel(model.rxns),1); +0113 element(:)={''}; +0114 end +0115 +0116 if any(strfind(outputString,'%unbalanced')) || any(strfind(outputString,'%lumped')) +0117 balanceStructure=getElementalBalance(model); +0118 end +0119 +0120 unbalanced=cell(numel(model.rxns),1); +0121 unbalanced(:)={''}; +0122 if any(strfind(outputString,'%unbalanced')) +0123 unbalanced(balanceStructure.balanceStatus==0)={'(*)'}; +0124 unbalanced(balanceStructure.balanceStatus<0)={'(-)'}; +0125 end +0126 +0127 lumped=cell(numel(model.rxns),1); +0128 lumped(:)={''}; +0129 if any(strfind(outputString,'%lumped')) +0130 for i=1:numel(model.rxns) +0131 leftGroup=''; +0132 rightGroup=''; +0133 for j=1:numel(balanceStructure.elements.names) +0134 I=balanceStructure.leftComp(i,j); +0135 if I~=0 +0136 if I==1 +0137 leftGroup=[leftGroup balanceStructure.elements.abbrevs{j}]; +0138 else +0139 leftGroup=[leftGroup balanceStructure.elements.abbrevs{j} num2str(I)]; +0140 end +0141 end +0142 I=balanceStructure.rightComp(i,j); +0143 if I~=0 +0144 if I==1 +0145 rightGroup=[rightGroup balanceStructure.elements.abbrevs{j}]; +0146 else +0147 rightGroup=[rightGroup balanceStructure.elements.abbrevs{j} num2str(I)]; +0148 end +0149 end +0150 end +0151 if model.rev(i) +0152 lumped{i}=[leftGroup ' <=> ' rightGroup]; +0153 else +0154 lumped{i}=[leftGroup ' => ' rightGroup]; +0155 end +0156 end +0157 end +0158 +0159 for i=1:numel(model.rxns) +0160 %Only print if it's an exchange reaction or if all reactions should be +0161 %printed. Exchange reactions only have reactants or only products. +0162 reactants=model.S(:,i)<0; +0163 products=model.S(:,i)>0; +0164 +0165 %Only print if the absolute value is >= cutOffFlux +0166 if (onlyExchange==false || (~any(reactants) || ~any(products))) +0167 printString=outputString; +0168 +0169 %Produce the final string +0170 printString=strrep(printString,'%rxnID',model.rxns{i}); +0171 printString=strrep(printString,'%eqn',eqn{i}); +0172 printString=strrep(printString,'%rxnName',model.rxnNames{i}); +0173 printString=strrep(printString,'%lower',num2str(model.lb(i))); +0174 printString=strrep(printString,'%upper',num2str(model.ub(i))); +0175 printString=strrep(printString,'%obj',num2str(model.c(i))); +0176 printString=strrep(printString,'%flux',num2str(fluxes(i,:))); +0177 printString=strrep(printString,'%element',element{i}); +0178 printString=strrep(printString,'%unbalanced',unbalanced{i}); +0179 printString=strrep(printString,'%lumped',lumped{i}); +0180 fprintf(fid,printString); +0181 end +0182 end +0183 +0184 if fid~=1 +0185 fprintf('File successfully saved.\n'); +0186 fclose(fid); +0187 end +0188 end
Generated by m2html © 2005
\ No newline at end of file diff --git a/doc/external/kegg/getModelFromKEGG.html b/doc/external/kegg/getModelFromKEGG.html index 90800f00..ea8c105e 100644 --- a/doc/external/kegg/getModelFromKEGG.html +++ b/doc/external/kegg/getModelFromKEGG.html @@ -323,54 +323,58 @@

SOURCE CODE ^%reason. In that case, use the ID instead 0236 I=cellfun(@isempty,model.metNames); 0237 model.metNames(I)=model.mets(I); -0238 -0239 %Save the model structure -0240 save(modelFile,'model','KOModel','isGeneral','isIncomplete','isUndefinedStoich','isSpontaneous'); -0241 fprintf('COMPLETE\n'); -0242 end -0243 -0244 %Delete reactions which are labeled as "incomplete", "erroneous", -0245 %"unclear", "general reaction" or having undefined stoichiometry (depending -0246 %on settings) -0247 if keepSpontaneous==false -0248 model=removeReactions(model,intersect(isSpontaneous,model.rxns),true,true); -0249 end -0250 if keepUndefinedStoich==false -0251 model=removeReactions(model,intersect(isUndefinedStoich,model.rxns),true,true); -0252 end -0253 if keepIncomplete==false -0254 model=removeReactions(model,intersect(isIncomplete,model.rxns),true,true); -0255 end -0256 if keepGeneral==false -0257 model=removeReactions(model,intersect(isGeneral,model.rxns),true,true); -0258 end -0259 -0260 end -0261 -0262 function output = isNewestFile(ravenPath) -0263 %The ad hoc function, which checks whether keggModel.mat is the more -0264 %recently modified than keggRxns.mat, keggGenes.mat and keggRxns.mat -0265 modelFile=fullfile(ravenPath,'external','kegg','keggModel.mat'); -0266 rxnsFile=fullfile(ravenPath,'external','kegg','keggRxns.mat'); -0267 genesFile=fullfile(ravenPath,'external','kegg','keggGenes.mat'); -0268 metsFile=fullfile(ravenPath,'external','kegg','keggMets.mat'); -0269 if (getFileTime(modelFile)>getFileTime(rxnsFile))&&... -0270 (getFileTime(modelFile)>getFileTime(genesFile))&&... -0271 (getFileTime(modelFile)>getFileTime(metsFile)) -0272 output=1; -0273 else -0274 output=0; -0275 end -0276 end -0277 -0278 function modTime = getFileTime(fileName) -0279 %Gets a last modification time for a particular file in datenum format that -0280 %the numbers could be easily compared for different files -0281 listing = dir(fileName); -0282 assert(numel(listing) == 1, 'No such file: %s', fileName); -0283 modTime = listing.datenum; -0284 format long; -0285 end +0238 +0239 %Deafult LB and UB +0240 model.annotation.defaultLB = -1000; +0241 model.annotation.defaultUB = 1000; +0242 +0243 %Save the model structure +0244 save(modelFile,'model','KOModel','isGeneral','isIncomplete','isUndefinedStoich','isSpontaneous'); +0245 fprintf('COMPLETE\n'); +0246 end +0247 +0248 %Delete reactions which are labeled as "incomplete", "erroneous", +0249 %"unclear", "general reaction" or having undefined stoichiometry (depending +0250 %on settings) +0251 if keepSpontaneous==false +0252 model=removeReactions(model,intersect(isSpontaneous,model.rxns),true,true); +0253 end +0254 if keepUndefinedStoich==false +0255 model=removeReactions(model,intersect(isUndefinedStoich,model.rxns),true,true); +0256 end +0257 if keepIncomplete==false +0258 model=removeReactions(model,intersect(isIncomplete,model.rxns),true,true); +0259 end +0260 if keepGeneral==false +0261 model=removeReactions(model,intersect(isGeneral,model.rxns),true,true); +0262 end +0263 +0264 end +0265 +0266 function output = isNewestFile(ravenPath) +0267 %The ad hoc function, which checks whether keggModel.mat is the more +0268 %recently modified than keggRxns.mat, keggGenes.mat and keggRxns.mat +0269 modelFile=fullfile(ravenPath,'external','kegg','keggModel.mat'); +0270 rxnsFile=fullfile(ravenPath,'external','kegg','keggRxns.mat'); +0271 genesFile=fullfile(ravenPath,'external','kegg','keggGenes.mat'); +0272 metsFile=fullfile(ravenPath,'external','kegg','keggMets.mat'); +0273 if (getFileTime(modelFile)>getFileTime(rxnsFile))&&... +0274 (getFileTime(modelFile)>getFileTime(genesFile))&&... +0275 (getFileTime(modelFile)>getFileTime(metsFile)) +0276 output=1; +0277 else +0278 output=0; +0279 end +0280 end +0281 +0282 function modTime = getFileTime(fileName) +0283 %Gets a last modification time for a particular file in datenum format that +0284 %the numbers could be easily compared for different files +0285 listing = dir(fileName); +0286 assert(numel(listing) == 1, 'No such file: %s', fileName); +0287 modTime = listing.datenum; +0288 format long; +0289 end
Generated by m2html © 2005
\ No newline at end of file diff --git a/doc/io/writeYAMLmodel.html b/doc/io/writeYAMLmodel.html index 2618fbeb..636fa540 100644 --- a/doc/io/writeYAMLmodel.html +++ b/doc/io/writeYAMLmodel.html @@ -300,126 +300,137 @@

SOURCE CODE ^%eccodes/rxnNotes: if 1 write in 1 line, if more create header and list 0242 if strcmp(fieldName,'subSystems') 0243 list = field{pos}; %subSystems already comes in a cell array -0244 elseif strcmp(fieldName,'newMetMiriams') -0245 index = str2double(regexprep(name,'^.+_','')); -0246 name = regexprep(name,'_\d+$',''); -0247 list = strsplit(model.newMetMiriams{pos,index},'; '); -0248 elseif strcmp(fieldName,'newRxnMiriams') -0249 index = str2double(regexprep(name,'^.+_','')); -0250 name = regexprep(name,'_\d+$',''); -0251 list = strsplit(model.newRxnMiriams{pos,index},'; '); -0252 elseif strcmp(fieldName,'newGeneMiriams') -0253 index = str2double(regexprep(name,'^.+_','')); -0254 name = regexprep(name,'_\d+$',''); -0255 list = strsplit(model.newGeneMiriams{pos,index},'; '); -0256 elseif strcmp(fieldName,'newCompMiriams') -0257 index = str2double(regexprep(name,'^.+_','')); -0258 name = regexprep(name,'_\d+$',''); -0259 list = strsplit(model.newCompMiriams{pos,index},'; '); -0260 elseif ~isempty(field{pos}) -0261 list = strrep(field{pos},' ',''); -0262 list = strsplit(list,';'); -0263 else -0264 list = ''; -0265 end -0266 list=strip(list); -0267 -0268 if length(list) == 1 && ~strcmp(list{1},'') && ~strcmp(fieldName,'subSystems') -0269 if preserveQuotes -0270 list = ['"' list{1} '"']; -0271 end -0272 fprintf(fid,' %s: %s\n',name,list); -0273 elseif ischar(list) && strcmp(fieldName,'subSystems') -0274 if preserveQuotes -0275 list = ['"' list '"']; -0276 end -0277 fprintf(fid,' %s: %s\n',name,list); -0278 elseif length(list) > 1 || strcmp(fieldName,'subSystems') -0279 if preserveQuotes -0280 for j=1:numel(list) -0281 list{j} = ['"' list{j} '"']; -0282 end -0283 end -0284 fprintf(fid,' %s:\n',name); -0285 for i = 1:length(list) -0286 fprintf(fid,'%s - %s\n',regexprep(name,'(^\s*).*','$1'),list{i}); -0287 end -0288 end -0289 -0290 elseif sum(pos) > 0 -0291 %All other fields: -0292 if strcmp(type,'txt') -0293 value = field{pos}; -0294 if preserveQuotes && ~isempty(value) -0295 value = ['"',value,'"']; -0296 end -0297 elseif strcmp(type,'num') -0298 if isnan(field(pos)) -0299 value = []; -0300 else -0301 value = sprintf('%.15g',full(field(pos))); -0302 end -0303 end -0304 if ~isempty(value) -0305 fprintf(fid,' %s: %s\n',name,value); +0244 if isempty(list) +0245 return +0246 end +0247 elseif strcmp(fieldName,'newMetMiriams') +0248 index = str2double(regexprep(name,'^.+_','')); +0249 name = regexprep(name,'_\d+$',''); +0250 list = strsplit(model.newMetMiriams{pos,index},'; '); +0251 elseif strcmp(fieldName,'newRxnMiriams') +0252 index = str2double(regexprep(name,'^.+_','')); +0253 name = regexprep(name,'_\d+$',''); +0254 list = strsplit(model.newRxnMiriams{pos,index},'; '); +0255 elseif strcmp(fieldName,'newGeneMiriams') +0256 index = str2double(regexprep(name,'^.+_','')); +0257 name = regexprep(name,'_\d+$',''); +0258 list = strsplit(model.newGeneMiriams{pos,index},'; '); +0259 elseif strcmp(fieldName,'newCompMiriams') +0260 index = str2double(regexprep(name,'^.+_','')); +0261 name = regexprep(name,'_\d+$',''); +0262 list = strsplit(model.newCompMiriams{pos,index},'; '); +0263 elseif ~isempty(field{pos}) +0264 list = strrep(field{pos},' ',''); +0265 list = strsplit(list,';'); +0266 else +0267 return % empty, needs no line in file +0268 end +0269 list=strip(list); +0270 +0271 if length(list) == 1 && ~strcmp(list{1},'') && ~strcmp(fieldName,'subSystems') +0272 if preserveQuotes +0273 list = ['"' list{1} '"']; +0274 end +0275 fprintf(fid,' %s: %s\n',name,list); +0276 elseif ischar(list) && strcmp(fieldName,'subSystems') +0277 if preserveQuotes +0278 list = ['"' list '"']; +0279 end +0280 fprintf(fid,' %s: %s\n',name,list); +0281 elseif length(list) > 1 || strcmp(fieldName,'subSystems') +0282 if preserveQuotes +0283 for j=1:numel(list) +0284 list{j} = ['"' list{j} '"']; +0285 end +0286 end +0287 fprintf(fid,' %s:\n',name); +0288 for i = 1:length(list) +0289 fprintf(fid,'%s - %s\n',regexprep(name,'(^\s*).*','$1'),list{i}); +0290 end +0291 end +0292 +0293 elseif sum(pos) > 0 +0294 %All other fields: +0295 if strcmp(type,'txt') +0296 value = field{pos}; +0297 if preserveQuotes && ~isempty(value) +0298 value = ['"',value,'"']; +0299 end +0300 elseif strcmp(type,'num') +0301 if isnan(field(pos)) +0302 value = []; +0303 else +0304 value = sprintf('%.15g',full(field(pos))); +0305 end 0306 end -0307 end -0308 end -0309 end -0310 -0311 function writeMetadata(model,fid) -0312 % Writes model metadata to the yaml file. This information will eventually -0313 % be extracted entirely from the model, but for now, many of the entries -0314 % are hard-coded defaults for HumanGEM. -0315 -0316 fprintf(fid, '- metaData:\n'); -0317 fprintf(fid, ' id: "%s"\n', model.id); -0318 fprintf(fid, ' name: "%s"\n',model.name); -0319 if isfield(model,'version') -0320 fprintf(fid, ' version: "%s"\n',model.version); -0321 end -0322 fprintf(fid, ' date: "%s"\n',datestr(now,29)); % 29=YYYY-MM-DD -0323 if isfield(model,'annotation') -0324 if isfield(model.annotation,'defaultLB') -0325 fprintf(fid, ' defaultLB: "%g"\n', model.annotation.defaultLB); -0326 end -0327 if isfield(model.annotation,'defaultUB') -0328 fprintf(fid, ' defaultUB: "%g"\n', model.annotation.defaultUB); -0329 end -0330 if isfield(model.annotation,'givenName') -0331 fprintf(fid, ' givenName: "%s"\n', model.annotation.givenName); -0332 end -0333 if isfield(model.annotation,'familyName') -0334 fprintf(fid, ' familyName: "%s"\n', model.annotation.familyName); -0335 end -0336 if isfield(model.annotation,'authors') -0337 fprintf(fid, ' authors: "%s"\n', model.annotation.authors); -0338 end -0339 if isfield(model.annotation,'email') -0340 fprintf(fid, ' email: "%s"\n', model.annotation.email); -0341 end -0342 if isfield(model.annotation,'organization') -0343 fprintf(fid, ' organization: "%s"\n',model.annotation.organization); -0344 end -0345 if isfield(model.annotation,'taxonomy') -0346 fprintf(fid, ' taxonomy: "%s"\n', model.annotation.taxonomy); -0347 end -0348 if isfield(model.annotation,'note') -0349 fprintf(fid, ' note: "%s"\n', model.annotation.note); -0350 end -0351 if isfield(model.annotation,'sourceUrl') -0352 fprintf(fid, ' sourceUrl: "%s"\n', model.annotation.sourceUrl); -0353 end -0354 end -0355 if isfield(model,'ec') -0356 if model.ec.geckoLight -0357 geckoLight = 'true'; -0358 else -0359 geckoLight = 'false'; -0360 end -0361 fprintf(fid,' geckoLight: "%s"\n',geckoLight); -0362 end -0363 end +0307 if ~isempty(value) +0308 fprintf(fid,' %s: %s\n',name,value); +0309 end +0310 end +0311 end +0312 end +0313 +0314 function writeMetadata(model,fid) +0315 % Writes model metadata to the yaml file. This information will eventually +0316 % be extracted entirely from the model, but for now, many of the entries +0317 % are hard-coded defaults for HumanGEM. +0318 +0319 fprintf(fid, '- metaData:\n'); +0320 if isfield(model,'id') +0321 fprintf(fid, ' id: "%s"\n', model.id); +0322 else +0323 fprintf(fid, ' id: "blankID"\n'); +0324 end +0325 if isfield(model,'name') +0326 fprintf(fid, ' name: "%s"\n',model.name); +0327 else +0328 fprintf(fid, ' name: "blankName"\n'); +0329 end +0330 if isfield(model,'version') +0331 fprintf(fid, ' version: "%s"\n',model.version); +0332 end +0333 fprintf(fid, ' date: "%s"\n',datestr(now,29)); % 29=YYYY-MM-DD +0334 if isfield(model,'annotation') +0335 if isfield(model.annotation,'defaultLB') +0336 fprintf(fid, ' defaultLB: "%g"\n', model.annotation.defaultLB); +0337 end +0338 if isfield(model.annotation,'defaultUB') +0339 fprintf(fid, ' defaultUB: "%g"\n', model.annotation.defaultUB); +0340 end +0341 if isfield(model.annotation,'givenName') +0342 fprintf(fid, ' givenName: "%s"\n', model.annotation.givenName); +0343 end +0344 if isfield(model.annotation,'familyName') +0345 fprintf(fid, ' familyName: "%s"\n', model.annotation.familyName); +0346 end +0347 if isfield(model.annotation,'authors') +0348 fprintf(fid, ' authors: "%s"\n', model.annotation.authors); +0349 end +0350 if isfield(model.annotation,'email') +0351 fprintf(fid, ' email: "%s"\n', model.annotation.email); +0352 end +0353 if isfield(model.annotation,'organization') +0354 fprintf(fid, ' organization: "%s"\n',model.annotation.organization); +0355 end +0356 if isfield(model.annotation,'taxonomy') +0357 fprintf(fid, ' taxonomy: "%s"\n', model.annotation.taxonomy); +0358 end +0359 if isfield(model.annotation,'note') +0360 fprintf(fid, ' note: "%s"\n', model.annotation.note); +0361 end +0362 if isfield(model.annotation,'sourceUrl') +0363 fprintf(fid, ' sourceUrl: "%s"\n', model.annotation.sourceUrl); +0364 end +0365 end +0366 if isfield(model,'ec') +0367 if model.ec.geckoLight +0368 geckoLight = 'true'; +0369 else +0370 geckoLight = 'false'; +0371 end +0372 fprintf(fid,' geckoLight: "%s"\n',geckoLight); +0373 end +0374 end
Generated by m2html © 2005
\ No newline at end of file From f8b0c44ff7b6822fe144a4f8b95af5fdc105b745 Mon Sep 17 00:00:00 2001 From: Eduard Kerkhoven Date: Thu, 14 Mar 2024 21:15:56 +0100 Subject: [PATCH 11/23] fix: ravenCobraWrapper prefers to use grRules --- doc/struct_conversion/ravenCobraWrapper.html | 832 ++++++++++--------- struct_conversion/ravenCobraWrapper.m | 10 +- 2 files changed, 426 insertions(+), 416 deletions(-) diff --git a/doc/struct_conversion/ravenCobraWrapper.html b/doc/struct_conversion/ravenCobraWrapper.html index 556cdc4a..7f06866e 100644 --- a/doc/struct_conversion/ravenCobraWrapper.html +++ b/doc/struct_conversion/ravenCobraWrapper.html @@ -36,7 +36,9 @@

DESCRIPTION ^SOURCE CODE ^% 0009 % This function is a bidirectional tool to convert between RAVEN and 0010 % COBRA structures. It recognises COBRA structure by checking field -0011 % 'rules' existense, which is only found in COBRA Toolbox structure. -0012 % -0013 % NOTE: During RAVEN -> COBRA -> RAVEN conversion cycle the following -0014 % fields are lost: annotation, compOutside, compMiriams, rxnComps, -0015 % geneComps, unconstrained. Boundary metabolites are lost, because COBRA -0016 % structure does not involve boundary metabolites, so they are removed -0017 % using simplifyModel before RAVEN -> COBRA conversion. The field 'rev' -0018 % is also partially lost, but during COBRA -> RAVEN conversion it's -0019 % reconstructed based on lower bound reaction values -0020 % -0021 % NOTE: During COBRA -> RAVEN -> COBRA conversion cycle the following -0022 % fields are lost: geneEntrezID, metSmiles, modelVersion, -0023 % proteinNames, proteins -0024 % -0025 % NOTE: The information about mandatory RAVEN fields was taken from -0026 % checkModelStruct function, whereas the corresponding information about -0027 % COBRA fields was fetched from verifyModel function -0028 % -0029 % Usage: newModel=ravenCobraWrapper(model) -0030 -0031 if isfield(model,'rules') -0032 isRaven=false; -0033 else -0034 isRaven=true; -0035 end -0036 -0037 ravenPath=findRAVENroot(); +0011 % 'rules' existense, which is only found in COBRA Toolbox structure. If +0012 % the COBRA model also has a grRules field, then this will be used +0013 % instead of parsing the rules field. +0014 % +0015 % NOTE: During RAVEN -> COBRA -> RAVEN conversion cycle the following +0016 % fields are lost: annotation, compOutside, compMiriams, rxnComps, +0017 % geneComps, unconstrained. Boundary metabolites are lost, because COBRA +0018 % structure does not involve boundary metabolites, so they are removed +0019 % using simplifyModel before RAVEN -> COBRA conversion. The field 'rev' +0020 % is also partially lost, but during COBRA -> RAVEN conversion it's +0021 % reconstructed based on lower bound reaction values +0022 % +0023 % NOTE: During COBRA -> RAVEN -> COBRA conversion cycle the following +0024 % fields are lost: geneEntrezID, metSmiles, modelVersion, +0025 % proteinNames, proteins +0026 % +0027 % NOTE: The information about mandatory RAVEN fields was taken from +0028 % checkModelStruct function, whereas the corresponding information about +0029 % COBRA fields was fetched from verifyModel function +0030 % +0031 % Usage: newModel=ravenCobraWrapper(model) +0032 +0033 if isfield(model,'rules') +0034 isRaven=false; +0035 else +0036 isRaven=true; +0037 end 0038 -0039 % Load COBRA field information -0040 fid = fopen(fullfile(ravenPath,'struct_conversion','COBRA_structure_fields.csv')); % Taken from https://github.com/opencobra/cobratoolbox/blob/develop/src/base/io/definitions/COBRA_structure_fields.csv -0041 fieldFile = textscan(fid,repmat('%s',1,15),'Delimiter','\t','HeaderLines',1); -0042 dbFields = ~cellfun(@isempty,fieldFile{5}); % Only keep fields with database annotations that should be translated to xxxMiriams -0043 dbFields = dbFields & ~contains(fieldFile{1},{'metInChIString','metKEGGID','metPubChemID','rxnECNumbers'}); -0044 COBRAnamespace = fieldFile{5}(dbFields); -0045 COBRAnamespace = regexprep(COBRAnamespace,';.*',''); % Only keep first suggested namespace -0046 COBRAfields = fieldFile{1}(dbFields); -0047 fclose(fid); -0048 -0049 % Load conversion between additional COBRA fields and namespaces: -0050 fid = fopen(fullfile(ravenPath,'struct_conversion','cobraNamespaces.csv')); -0051 fieldFile = textscan(fid,'%s %s','Delimiter',',','HeaderLines',0); -0052 COBRAfields = [COBRAfields; fieldFile{1}]; -0053 COBRAnamespace = [COBRAnamespace; fieldFile{2}]; -0054 rxnCOBRAfields = COBRAfields(startsWith(COBRAfields,'rxn')); -0055 rxnNamespaces = COBRAnamespace(startsWith(COBRAfields,'rxn')); -0056 metCOBRAfields = COBRAfields(startsWith(COBRAfields,'met')); -0057 metNamespaces = COBRAnamespace(startsWith(COBRAfields,'met')); -0058 geneCOBRAfields = COBRAfields(startsWith(COBRAfields,'gene')); -0059 geneNamespaces = COBRAnamespace(startsWith(COBRAfields,'gene')); -0060 fclose(fid); -0061 -0062 if isRaven -0063 %Firstly remove boundary metabolites -0064 model=simplifyModel(model); -0065 end -0066 -0067 % Keep fields that have identical names and content -0068 newModel.S=model.S; -0069 newModel.lb=model.lb; -0070 newModel.ub=model.ub; -0071 if isfield(model,'c') -0072 newModel.c=model.c; -0073 else -0074 newModel.c=zeros(numel(model.rxns),1); -0075 end -0076 newModel.rxns=model.rxns; -0077 optFields = {'rxnNames','subSystems','rxnNotes','metDeltaG','rxnDeltaG',... -0078 'metFormulas','comps','compNames','metCharges','genes',... -0079 'rxnConfidenceScores','rxnGeneMat','metNotes','rev'}; -0080 for i=1:length(optFields) -0081 if isfield(model,optFields{i}) -0082 newModel.(optFields{i})=model.(optFields{i}); -0083 end -0084 end -0085 -0086 % Convert unique fields -0087 if isRaven -0088 fprintf('Converting RAVEN structure to COBRA..\n'); -0089 %Convert from RAVEN to COBRA structure -0090 -0091 %Mandatory COBRA fields -0092 newModel.rxns=model.rxns; -0093 if all(~cellfun(@isempty,regexp(model.mets,'\[[^\]]+\]$'))) -0094 newModel.mets=model.mets; -0095 else -0096 %Check if model has compartment info as "met_c" suffix in all metabolites: -0097 BiGGformat = false(size(model.mets)); -0098 for i=1:numel(model.comps) -0099 compPos=model.metComps==i; -0100 BiGGformat(compPos)=~cellfun(@isempty,regexp(model.mets(compPos),['_' model.comps{i} '$'])); -0101 end -0102 if all(BiGGformat) -0103 newModel.mets=model.mets; -0104 for i=1:numel(model.comps) -0105 newModel.mets=regexprep(newModel.mets,['_' model.comps{i} '$'],['[' model.comps{i} ']']); -0106 end -0107 else -0108 newModel.mets=strcat(model.mets,'[',model.comps(model.metComps),']'); -0109 end -0110 end -0111 -0112 %b, csense, osenseStr, genes, rules are also mandatory, but defined -0113 %later to match the order of fields -0114 -0115 %Optional COBRA fields -0116 if isfield(model,'id') -0117 newModel.modelID=model.id; -0118 end -0119 if isfield(model,'name') -0120 newModel.modelName=model.name; -0121 end -0122 if isfield(model,'eccodes') -0123 newModel.rxnECNumbers=model.eccodes; -0124 end -0125 if isfield(model,'rxnMiriams') -0126 [miriams,extractedMiriamNames]=extractMiriam(model.rxnMiriams); -0127 for i = 1:length(rxnCOBRAfields) -0128 j=ismember(extractedMiriamNames,rxnNamespaces{i}); -0129 if any(j) -0130 eval(['newModel.' rxnCOBRAfields{i} ' = miriams(:,j);']) -0131 end -0132 end -0133 end -0134 if isfield(model,'rxnReferences') % Concatenate model.rxnReferences to those extracted from model.rxnMiriams -0135 if isfield(newModel,'rxnReferences') -0136 newModel.rxnReferences = strcat(newModel.rxnReferences,{'; '},model.rxnReferences); -0137 newModel.rxnReferences = regexprep(newModel.rxnReferences,'^; $',''); -0138 else -0139 newModel.rxnReferences = model.rxnReferences; -0140 end -0141 end -0142 if isfield(model,'metNames') -0143 newModel.metNames=strcat(model.metNames,' [',model.compNames(model.metComps),']'); -0144 end -0145 if isfield(model,'metMiriams') -0146 [miriams,extractedMiriamNames]=extractMiriam(model.metMiriams); -0147 %Shorten miriam names for KEGG and PubChem. These shorter names -0148 %will be used later to concatenate KEGG COMPOUND/GLYCAN and PubChem -0149 %Compound/Substance, into corresponding COBRA model fields -0150 extractedMiriamNames=regexprep(extractedMiriamNames,'^kegg\..+','kegg'); -0151 extractedMiriamNames=regexprep(extractedMiriamNames,'^pubchem\..+','pubchem'); -0152 i=ismember(extractedMiriamNames,'kegg'); -0153 if any(i) % Combine KEGG compounds and glycans -0154 for j=1:length(i) -0155 if i(j) && isfield(newModel,'metKEGGID')~=1 -0156 newModel.metKEGGID=miriams(:,j); -0157 elseif i(j) -0158 newModel.metKEGGID=strcat(newModel.metKEGGID,';',miriams(:,j)); -0159 end -0160 end -0161 newModel.metKEGGID=regexprep(newModel.metKEGGID,'^;|;$',''); -0162 end -0163 i=ismember(extractedMiriamNames,'pubchem'); -0164 if any(i) % Combine Pubchem compounds and substances -0165 for j=1:length(i) -0166 if i(j) && isfield(newModel,'metPubChemID')~=1 -0167 newModel.metPubChemID=miriams(:,j); -0168 elseif i(j) -0169 newModel.metPubChemID=strcat(newModel.metPubChemID,';',miriams(:,j)); -0170 end -0171 end -0172 newModel.metPubChemID=regexprep(newModel.metPubChemID,'^;|;$',''); -0173 end -0174 %All other Miriams can be directly parsed with no modifications: -0175 for i = 1:length(metCOBRAfields) -0176 j=ismember(extractedMiriamNames,metNamespaces{i}); -0177 if any(j) -0178 eval(['newModel.' metCOBRAfields{i} ' = miriams(:,j);']) -0179 end -0180 end -0181 end -0182 if isfield(model,'inchis') -0183 newModel.metInChIString=regexprep(strcat('InChI=', model.inchis),'^InChI=$',''); -0184 end -0185 newModel.b=zeros(numel(model.mets),1); -0186 newModel.csense=repmat('E',size(model.mets)); -0187 if isfield(model,'geneMiriams') -0188 [miriams,extractedMiriamNames]=extractMiriam(model.geneMiriams); -0189 for i = 1:length(geneCOBRAfields) -0190 j=ismember(extractedMiriamNames,geneNamespaces{i}); -0191 if any(j) -0192 eval(['newModel.' geneCOBRAfields{i} ' = miriams(:,j);']) -0193 end -0194 end -0195 end -0196 if isfield(model,'geneShortNames') -0197 newModel.geneNames=model.geneShortNames; -0198 end -0199 if isfield(model,'genes') -0200 newModel.rules=grrulesToRules(model); -0201 else -0202 fprintf('WARNING: no genes detected. The model therefore may not be exportable to SBML file with writeCbModel\n'); -0203 end -0204 newModel.osenseStr='max'; -0205 else -0206 fprintf('Converting COBRA structure to RAVEN..\n'); -0207 %Convert from COBRA to RAVEN structure -0208 -0209 %Mandatory RAVEN fields -0210 newModel.mets=model.mets; -0211 if ~isfield(model,'comps') -0212 %Since 'comps' field is not mandatory in COBRA, it may be required -0213 %to obtain the non-redundant list of comps from metabolite ids, if -0214 %'comps' field is not available -0215 newModel.comps = unique(regexprep(model.mets,'.*\[([^\]]+)\]$','$1')); -0216 newModel.compNames = newModel.comps; -0217 end -0218 for i=1:numel(newModel.comps) -0219 newModel.mets=regexprep(newModel.mets,['\[', newModel.comps{i}, '\]$'],''); -0220 newModel.mets=regexprep(newModel.mets,['\[', newModel.compNames{i}, '\]$'],''); -0221 end -0222 -0223 %In some cases (e.g. any model that uses BiGG ids as main ids), there -0224 %may be overlapping mets due to removal of compartment info. To avoid -0225 %this, we change compartments from e.g. [c] into _c -0226 if numel(unique(newModel.mets))~=numel(model.mets) -0227 newModel.mets=model.mets; -0228 for i=1:numel(newModel.comps) -0229 newModel.mets=regexprep(newModel.mets,['\[' newModel.comps{i} '\]$'],['_' newModel.comps{i}]); -0230 end -0231 end -0232 %Since COBRA no longer contains rev field it is assumed that rxn is -0233 %reversible if its lower bound is set below zero -0234 if ~isfield(model,'rev') -0235 for i=1:numel(model.rxns) -0236 if model.lb(i)<0 -0237 newModel.rev(i,1)=1; -0238 else -0239 newModel.rev(i,1)=0; -0240 end -0241 end -0242 end -0243 newModel.b=zeros(numel(model.mets),1); -0244 -0245 %metComps is also mandatory, but defined later to match the order of -0246 %fields -0247 -0248 %Fields 'name' and 'id' are also considered as mandatory, but -0249 %these are added to the model during exportModel/exportToExcelFormat -0250 %anyway, so there is no point to add this information here -0251 -0252 %Optional RAVEN fields -0253 if isfield(model,'modelID') -0254 newModel.id=model.modelID; -0255 end -0256 if isfield(model,'modelName') -0257 newModel.name=model.modelName; -0258 end -0259 if isfield(model,'rules') -0260 model.grRules = rulesTogrrules(model); -0261 [grRules,rxnGeneMat] = standardizeGrRules(model,true); -0262 newModel.grRules = grRules; -0263 newModel.rxnGeneMat = rxnGeneMat; -0264 end -0265 if isfield(model,'rxnECNumbers') -0266 newModel.eccodes=regexprep(model.rxnECNumbers,'EC|EC:',''); -0267 end -0268 if any(isfield(model,rxnCOBRAfields)) -0269 for i=1:numel(model.rxns) -0270 counter=1; -0271 newModel.rxnMiriams{i,1}=[]; -0272 if isfield(model,'rxnReferences') -0273 if ~isempty(model.rxnReferences{i}) -0274 pmids = model.rxnReferences{i}; -0275 pmids = strsplit(pmids,'; '); -0276 nonPmids = cellfun(@isempty,regexp(pmids,'^\d+$','match','once')); -0277 if any(nonPmids) %Not a pubmed id, keep in rxnReferences instead -0278 newModel.rxnReferences{i,1} = strjoin(pmids(nonPmids),', '); -0279 pmids(nonPmids)=[]; -0280 end -0281 for j = 1:length(pmids) -0282 newModel.rxnMiriams{i,1}.name{counter,1} = 'pubmed'; -0283 newModel.rxnMiriams{i,1}.value{counter,1} = pmids{j}; -0284 counter=counter+1; -0285 end -0286 end -0287 end -0288 for j = 2:length(rxnCOBRAfields) %Start from 2, as 1 is rxnReferences -0289 if isfield(model,rxnCOBRAfields{j}) -0290 rxnAnnotation = eval(['model.' rxnCOBRAfields{j} '{i}']); -0291 if ~isempty(rxnAnnotation) -0292 rxnAnnotation = strtrim(strsplit(rxnAnnotation,';')); -0293 for a=1:length(rxnAnnotation) -0294 newModel.rxnMiriams{i,1}.name{counter,1} = rxnNamespaces{j}; -0295 newModel.rxnMiriams{i,1}.value{counter,1} = rxnAnnotation{a}; -0296 counter=counter+1; -0297 end -0298 end -0299 end -0300 end -0301 end -0302 end -0303 if isfield(newModel,'rxnReferences') -0304 emptyEntry = cellfun(@isempty,newModel.rxnReferences); -0305 newModel.rxnReferences(emptyEntry)={''}; +0039 ravenPath=findRAVENroot(); +0040 +0041 % Load COBRA field information +0042 fid = fopen(fullfile(ravenPath,'struct_conversion','COBRA_structure_fields.csv')); % Taken from https://github.com/opencobra/cobratoolbox/blob/develop/src/base/io/definitions/COBRA_structure_fields.csv +0043 fieldFile = textscan(fid,repmat('%s',1,15),'Delimiter','\t','HeaderLines',1); +0044 dbFields = ~cellfun(@isempty,fieldFile{5}); % Only keep fields with database annotations that should be translated to xxxMiriams +0045 dbFields = dbFields & ~contains(fieldFile{1},{'metInChIString','metKEGGID','metPubChemID','rxnECNumbers'}); +0046 COBRAnamespace = fieldFile{5}(dbFields); +0047 COBRAnamespace = regexprep(COBRAnamespace,';.*',''); % Only keep first suggested namespace +0048 COBRAfields = fieldFile{1}(dbFields); +0049 fclose(fid); +0050 +0051 % Load conversion between additional COBRA fields and namespaces: +0052 fid = fopen(fullfile(ravenPath,'struct_conversion','cobraNamespaces.csv')); +0053 fieldFile = textscan(fid,'%s %s','Delimiter',',','HeaderLines',0); +0054 COBRAfields = [COBRAfields; fieldFile{1}]; +0055 COBRAnamespace = [COBRAnamespace; fieldFile{2}]; +0056 rxnCOBRAfields = COBRAfields(startsWith(COBRAfields,'rxn')); +0057 rxnNamespaces = COBRAnamespace(startsWith(COBRAfields,'rxn')); +0058 metCOBRAfields = COBRAfields(startsWith(COBRAfields,'met')); +0059 metNamespaces = COBRAnamespace(startsWith(COBRAfields,'met')); +0060 geneCOBRAfields = COBRAfields(startsWith(COBRAfields,'gene')); +0061 geneNamespaces = COBRAnamespace(startsWith(COBRAfields,'gene')); +0062 fclose(fid); +0063 +0064 if isRaven +0065 %Firstly remove boundary metabolites +0066 model=simplifyModel(model); +0067 end +0068 +0069 % Keep fields that have identical names and content +0070 newModel.S=model.S; +0071 newModel.lb=model.lb; +0072 newModel.ub=model.ub; +0073 if isfield(model,'c') +0074 newModel.c=model.c; +0075 else +0076 newModel.c=zeros(numel(model.rxns),1); +0077 end +0078 newModel.rxns=model.rxns; +0079 optFields = {'rxnNames','subSystems','rxnNotes','metDeltaG','rxnDeltaG',... +0080 'metFormulas','comps','compNames','metCharges','genes',... +0081 'rxnConfidenceScores','rxnGeneMat','metNotes','rev'}; +0082 for i=1:length(optFields) +0083 if isfield(model,optFields{i}) +0084 newModel.(optFields{i})=model.(optFields{i}); +0085 end +0086 end +0087 +0088 % Convert unique fields +0089 if isRaven +0090 fprintf('Converting RAVEN structure to COBRA..\n'); +0091 %Convert from RAVEN to COBRA structure +0092 +0093 %Mandatory COBRA fields +0094 newModel.rxns=model.rxns; +0095 if all(~cellfun(@isempty,regexp(model.mets,'\[[^\]]+\]$'))) +0096 newModel.mets=model.mets; +0097 else +0098 %Check if model has compartment info as "met_c" suffix in all metabolites: +0099 BiGGformat = false(size(model.mets)); +0100 for i=1:numel(model.comps) +0101 compPos=model.metComps==i; +0102 BiGGformat(compPos)=~cellfun(@isempty,regexp(model.mets(compPos),['_' model.comps{i} '$'])); +0103 end +0104 if all(BiGGformat) +0105 newModel.mets=model.mets; +0106 for i=1:numel(model.comps) +0107 newModel.mets=regexprep(newModel.mets,['_' model.comps{i} '$'],['[' model.comps{i} ']']); +0108 end +0109 else +0110 newModel.mets=strcat(model.mets,'[',model.comps(model.metComps),']'); +0111 end +0112 end +0113 +0114 %b, csense, osenseStr, genes, rules are also mandatory, but defined +0115 %later to match the order of fields +0116 +0117 %Optional COBRA fields +0118 if isfield(model,'id') +0119 newModel.modelID=model.id; +0120 end +0121 if isfield(model,'name') +0122 newModel.modelName=model.name; +0123 end +0124 if isfield(model,'eccodes') +0125 newModel.rxnECNumbers=model.eccodes; +0126 end +0127 if isfield(model,'rxnMiriams') +0128 [miriams,extractedMiriamNames]=extractMiriam(model.rxnMiriams); +0129 for i = 1:length(rxnCOBRAfields) +0130 j=ismember(extractedMiriamNames,rxnNamespaces{i}); +0131 if any(j) +0132 eval(['newModel.' rxnCOBRAfields{i} ' = miriams(:,j);']) +0133 end +0134 end +0135 end +0136 if isfield(model,'rxnReferences') % Concatenate model.rxnReferences to those extracted from model.rxnMiriams +0137 if isfield(newModel,'rxnReferences') +0138 newModel.rxnReferences = strcat(newModel.rxnReferences,{'; '},model.rxnReferences); +0139 newModel.rxnReferences = regexprep(newModel.rxnReferences,'^; $',''); +0140 else +0141 newModel.rxnReferences = model.rxnReferences; +0142 end +0143 end +0144 if isfield(model,'metNames') +0145 newModel.metNames=strcat(model.metNames,' [',model.compNames(model.metComps),']'); +0146 end +0147 if isfield(model,'metMiriams') +0148 [miriams,extractedMiriamNames]=extractMiriam(model.metMiriams); +0149 %Shorten miriam names for KEGG and PubChem. These shorter names +0150 %will be used later to concatenate KEGG COMPOUND/GLYCAN and PubChem +0151 %Compound/Substance, into corresponding COBRA model fields +0152 extractedMiriamNames=regexprep(extractedMiriamNames,'^kegg\..+','kegg'); +0153 extractedMiriamNames=regexprep(extractedMiriamNames,'^pubchem\..+','pubchem'); +0154 i=ismember(extractedMiriamNames,'kegg'); +0155 if any(i) % Combine KEGG compounds and glycans +0156 for j=1:length(i) +0157 if i(j) && isfield(newModel,'metKEGGID')~=1 +0158 newModel.metKEGGID=miriams(:,j); +0159 elseif i(j) +0160 newModel.metKEGGID=strcat(newModel.metKEGGID,';',miriams(:,j)); +0161 end +0162 end +0163 newModel.metKEGGID=regexprep(newModel.metKEGGID,'^;|;$',''); +0164 end +0165 i=ismember(extractedMiriamNames,'pubchem'); +0166 if any(i) % Combine Pubchem compounds and substances +0167 for j=1:length(i) +0168 if i(j) && isfield(newModel,'metPubChemID')~=1 +0169 newModel.metPubChemID=miriams(:,j); +0170 elseif i(j) +0171 newModel.metPubChemID=strcat(newModel.metPubChemID,';',miriams(:,j)); +0172 end +0173 end +0174 newModel.metPubChemID=regexprep(newModel.metPubChemID,'^;|;$',''); +0175 end +0176 %All other Miriams can be directly parsed with no modifications: +0177 for i = 1:length(metCOBRAfields) +0178 j=ismember(extractedMiriamNames,metNamespaces{i}); +0179 if any(j) +0180 eval(['newModel.' metCOBRAfields{i} ' = miriams(:,j);']) +0181 end +0182 end +0183 end +0184 if isfield(model,'inchis') +0185 newModel.metInChIString=regexprep(strcat('InChI=', model.inchis),'^InChI=$',''); +0186 end +0187 newModel.b=zeros(numel(model.mets),1); +0188 newModel.csense=repmat('E',size(model.mets)); +0189 if isfield(model,'geneMiriams') +0190 [miriams,extractedMiriamNames]=extractMiriam(model.geneMiriams); +0191 for i = 1:length(geneCOBRAfields) +0192 j=ismember(extractedMiriamNames,geneNamespaces{i}); +0193 if any(j) +0194 eval(['newModel.' geneCOBRAfields{i} ' = miriams(:,j);']) +0195 end +0196 end +0197 end +0198 if isfield(model,'geneShortNames') +0199 newModel.geneNames=model.geneShortNames; +0200 end +0201 if isfield(model,'genes') +0202 newModel.rules=grrulesToRules(model); +0203 else +0204 fprintf('WARNING: no genes detected. The model therefore may not be exportable to SBML file with writeCbModel\n'); +0205 end +0206 newModel.osenseStr='max'; +0207 else +0208 fprintf('Converting COBRA structure to RAVEN..\n'); +0209 %Convert from COBRA to RAVEN structure +0210 +0211 %Mandatory RAVEN fields +0212 newModel.mets=model.mets; +0213 if ~isfield(model,'comps') +0214 %Since 'comps' field is not mandatory in COBRA, it may be required +0215 %to obtain the non-redundant list of comps from metabolite ids, if +0216 %'comps' field is not available +0217 newModel.comps = unique(regexprep(model.mets,'.*\[([^\]]+)\]$','$1')); +0218 newModel.compNames = newModel.comps; +0219 end +0220 for i=1:numel(newModel.comps) +0221 newModel.mets=regexprep(newModel.mets,['\[', newModel.comps{i}, '\]$'],''); +0222 newModel.mets=regexprep(newModel.mets,['\[', newModel.compNames{i}, '\]$'],''); +0223 end +0224 +0225 %In some cases (e.g. any model that uses BiGG ids as main ids), there +0226 %may be overlapping mets due to removal of compartment info. To avoid +0227 %this, we change compartments from e.g. [c] into _c +0228 if numel(unique(newModel.mets))~=numel(model.mets) +0229 newModel.mets=model.mets; +0230 for i=1:numel(newModel.comps) +0231 newModel.mets=regexprep(newModel.mets,['\[' newModel.comps{i} '\]$'],['_' newModel.comps{i}]); +0232 end +0233 end +0234 %Since COBRA no longer contains rev field it is assumed that rxn is +0235 %reversible if its lower bound is set below zero +0236 if ~isfield(model,'rev') +0237 for i=1:numel(model.rxns) +0238 if model.lb(i)<0 +0239 newModel.rev(i,1)=1; +0240 else +0241 newModel.rev(i,1)=0; +0242 end +0243 end +0244 end +0245 newModel.b=zeros(numel(model.mets),1); +0246 +0247 %metComps is also mandatory, but defined later to match the order of +0248 %fields +0249 +0250 %Fields 'name' and 'id' are also considered as mandatory, but +0251 %these are added to the model during exportModel/exportToExcelFormat +0252 %anyway, so there is no point to add this information here +0253 +0254 %Optional RAVEN fields +0255 if isfield(model,'modelID') +0256 newModel.id=model.modelID; +0257 end +0258 if isfield(model,'modelName') +0259 newModel.name=model.modelName; +0260 end +0261 if isfield(model,'rules') && ~isfield(model,'grRules') +0262 model.grRules = rulesTogrrules(model); +0263 end +0264 if isfield(model,'grRules') +0265 [grRules,rxnGeneMat] = standardizeGrRules(model,true); +0266 newModel.grRules = grRules; +0267 newModel.rxnGeneMat = rxnGeneMat; +0268 end +0269 if isfield(model,'rxnECNumbers') +0270 newModel.eccodes=regexprep(model.rxnECNumbers,'EC|EC:',''); +0271 end +0272 if any(isfield(model,rxnCOBRAfields)) +0273 for i=1:numel(model.rxns) +0274 counter=1; +0275 newModel.rxnMiriams{i,1}=[]; +0276 if isfield(model,'rxnReferences') +0277 if ~isempty(model.rxnReferences{i}) +0278 pmids = model.rxnReferences{i}; +0279 pmids = strsplit(pmids,'; '); +0280 nonPmids = cellfun(@isempty,regexp(pmids,'^\d+$','match','once')); +0281 if any(nonPmids) %Not a pubmed id, keep in rxnReferences instead +0282 newModel.rxnReferences{i,1} = strjoin(pmids(nonPmids),', '); +0283 pmids(nonPmids)=[]; +0284 end +0285 for j = 1:length(pmids) +0286 newModel.rxnMiriams{i,1}.name{counter,1} = 'pubmed'; +0287 newModel.rxnMiriams{i,1}.value{counter,1} = pmids{j}; +0288 counter=counter+1; +0289 end +0290 end +0291 end +0292 for j = 2:length(rxnCOBRAfields) %Start from 2, as 1 is rxnReferences +0293 if isfield(model,rxnCOBRAfields{j}) +0294 rxnAnnotation = eval(['model.' rxnCOBRAfields{j} '{i}']); +0295 if ~isempty(rxnAnnotation) +0296 rxnAnnotation = strtrim(strsplit(rxnAnnotation,';')); +0297 for a=1:length(rxnAnnotation) +0298 newModel.rxnMiriams{i,1}.name{counter,1} = rxnNamespaces{j}; +0299 newModel.rxnMiriams{i,1}.value{counter,1} = rxnAnnotation{a}; +0300 counter=counter+1; +0301 end +0302 end +0303 end +0304 end +0305 end 0306 end -0307 if any(isfield(model,geneCOBRAfields)) -0308 for i=1:numel(model.genes) -0309 counter=1; -0310 newModel.geneMiriams{i,1}=[]; -0311 for j = 1:length(geneCOBRAfields) -0312 if isfield(model,geneCOBRAfields{j}) -0313 geneAnnotation = eval(['model.' geneCOBRAfields{j} '{i}']); -0314 if ~isempty(geneAnnotation) -0315 geneAnnotation = strtrim(strsplit(geneAnnotation,';')); -0316 for a=1:length(geneAnnotation) -0317 newModel.geneMiriams{i,1}.name{counter,1} = geneNamespaces{j}; -0318 newModel.geneMiriams{i,1}.value{counter,1} = geneAnnotation{a}; -0319 counter=counter+1; -0320 end -0321 end -0322 end -0323 end -0324 end -0325 end -0326 if isfield(model,'geneNames') -0327 newModel.geneShortNames=model.geneNames; -0328 end -0329 newModel.metNames=model.metNames; -0330 for i=1:numel(newModel.comps) -0331 newModel.metNames=regexprep(newModel.metNames,['\[', newModel.comps{i}, '\]$'],''); -0332 newModel.metNames=regexprep(newModel.metNames,['\[', newModel.compNames{i}, '\]$'],''); -0333 end -0334 newModel.metNames=deblank(newModel.metNames); -0335 newModel.metComps=regexprep(model.mets,'^.+\[',''); -0336 newModel.metComps=regexprep(newModel.metComps,'\]$',''); -0337 [~, newModel.metComps]=ismember(newModel.metComps,newModel.comps); -0338 if isfield(model,'metInChIString') -0339 newModel.inchis=regexprep(model.metInChIString,'^InChI=',''); -0340 end -0341 printWarning=false; -0342 if any(isfield(model,[metCOBRAfields;'metKEGGID';'metPubChemID'])) -0343 for i=1:numel(model.mets) -0344 counter=1; -0345 newModel.metMiriams{i,1}=[]; -0346 if isfield(model,'metKEGGID') -0347 if ~isempty(model.metKEGGID{i}) -0348 if strcmp(model.metKEGGID{i}(1),'C') -0349 newModel.metMiriams{i,1}.name{counter,1} = 'kegg.compound'; -0350 newModel.metMiriams{i,1}.value{counter,1} = model.metKEGGID{i}; -0351 counter=counter+1; -0352 elseif strcmp(model.metKEGGID{i}(1),'G') -0353 newModel.metMiriams{i,1}.name{counter,1} = 'kegg.glycan'; +0307 if isfield(newModel,'rxnReferences') +0308 emptyEntry = cellfun(@isempty,newModel.rxnReferences); +0309 newModel.rxnReferences(emptyEntry)={''}; +0310 end +0311 if any(isfield(model,geneCOBRAfields)) +0312 for i=1:numel(model.genes) +0313 counter=1; +0314 newModel.geneMiriams{i,1}=[]; +0315 for j = 1:length(geneCOBRAfields) +0316 if isfield(model,geneCOBRAfields{j}) +0317 geneAnnotation = eval(['model.' geneCOBRAfields{j} '{i}']); +0318 if ~isempty(geneAnnotation) +0319 geneAnnotation = strtrim(strsplit(geneAnnotation,';')); +0320 for a=1:length(geneAnnotation) +0321 newModel.geneMiriams{i,1}.name{counter,1} = geneNamespaces{j}; +0322 newModel.geneMiriams{i,1}.value{counter,1} = geneAnnotation{a}; +0323 counter=counter+1; +0324 end +0325 end +0326 end +0327 end +0328 end +0329 end +0330 if isfield(model,'geneNames') +0331 newModel.geneShortNames=model.geneNames; +0332 end +0333 newModel.metNames=model.metNames; +0334 for i=1:numel(newModel.comps) +0335 newModel.metNames=regexprep(newModel.metNames,['\[', newModel.comps{i}, '\]$'],''); +0336 newModel.metNames=regexprep(newModel.metNames,['\[', newModel.compNames{i}, '\]$'],''); +0337 end +0338 newModel.metNames=deblank(newModel.metNames); +0339 newModel.metComps=regexprep(model.mets,'^.+\[',''); +0340 newModel.metComps=regexprep(newModel.metComps,'\]$',''); +0341 [~, newModel.metComps]=ismember(newModel.metComps,newModel.comps); +0342 if isfield(model,'metInChIString') +0343 newModel.inchis=regexprep(model.metInChIString,'^InChI=',''); +0344 end +0345 printWarning=false; +0346 if any(isfield(model,[metCOBRAfields;'metKEGGID';'metPubChemID'])) +0347 for i=1:numel(model.mets) +0348 counter=1; +0349 newModel.metMiriams{i,1}=[]; +0350 if isfield(model,'metKEGGID') +0351 if ~isempty(model.metKEGGID{i}) +0352 if strcmp(model.metKEGGID{i}(1),'C') +0353 newModel.metMiriams{i,1}.name{counter,1} = 'kegg.compound'; 0354 newModel.metMiriams{i,1}.value{counter,1} = model.metKEGGID{i}; 0355 counter=counter+1; -0356 end -0357 end -0358 end -0359 if isfield(model,'metPubChemID') -0360 if ~isempty(model.metPubChemID{i}) -0361 if length(model.metPubChemID{i})>3 && strcmp(model.metPubChemID{i}(1:4),'CID:') -0362 newModel.metMiriams{i,1}.name{counter,1} = 'pubchem.compound'; -0363 newModel.metMiriams{i,1}.value{counter,1} = model.metPubChemID{i}; -0364 counter=counter+1; -0365 elseif length(model.metPubChemID{i})>3 && strcmp(model.metPubChemID{i}(1:4),'SID:') -0366 newModel.metMiriams{i,1}.name{counter,1} = 'pubchem.substance'; +0356 elseif strcmp(model.metKEGGID{i}(1),'G') +0357 newModel.metMiriams{i,1}.name{counter,1} = 'kegg.glycan'; +0358 newModel.metMiriams{i,1}.value{counter,1} = model.metKEGGID{i}; +0359 counter=counter+1; +0360 end +0361 end +0362 end +0363 if isfield(model,'metPubChemID') +0364 if ~isempty(model.metPubChemID{i}) +0365 if length(model.metPubChemID{i})>3 && strcmp(model.metPubChemID{i}(1:4),'CID:') +0366 newModel.metMiriams{i,1}.name{counter,1} = 'pubchem.compound'; 0367 newModel.metMiriams{i,1}.value{counter,1} = model.metPubChemID{i}; 0368 counter=counter+1; -0369 else -0370 newModel.metMiriams{i,1}.name{counter,1} = 'pubchem.compound'; +0369 elseif length(model.metPubChemID{i})>3 && strcmp(model.metPubChemID{i}(1:4),'SID:') +0370 newModel.metMiriams{i,1}.name{counter,1} = 'pubchem.substance'; 0371 newModel.metMiriams{i,1}.value{counter,1} = model.metPubChemID{i}; 0372 counter=counter+1; -0373 printWarning=true; -0374 end -0375 end -0376 end -0377 for j = 1:length(metCOBRAfields) -0378 if isfield(model,metCOBRAfields{j}) -0379 metAnnotation = eval(['model.' metCOBRAfields{j} '{i}']); -0380 if ~isempty(metAnnotation) -0381 metAnnotation = strtrim(strsplit(metAnnotation,';')); -0382 for a=1:length(metAnnotation) -0383 newModel.metMiriams{i,1}.name{counter,1} = metNamespaces{j}; -0384 newModel.metMiriams{i,1}.value{counter,1} = metAnnotation{a}; -0385 counter=counter+1; -0386 end -0387 end -0388 end -0389 end -0390 end -0391 end -0392 if printWarning -0393 fprintf('Could not determine whether PubChemIDs are compounds (CID)\n or substances (SID). All annotated PubChemIDs will therefore \n be assigned as compounds (CID).\n'); -0394 end -0395 end -0396 -0397 % Order fields -0398 modelNew=standardizeModelFieldOrder(newModel); % Corrects for both RAVEN and COBRA models +0373 else +0374 newModel.metMiriams{i,1}.name{counter,1} = 'pubchem.compound'; +0375 newModel.metMiriams{i,1}.value{counter,1} = model.metPubChemID{i}; +0376 counter=counter+1; +0377 printWarning=true; +0378 end +0379 end +0380 end +0381 for j = 1:length(metCOBRAfields) +0382 if isfield(model,metCOBRAfields{j}) +0383 metAnnotation = eval(['model.' metCOBRAfields{j} '{i}']); +0384 if ~isempty(metAnnotation) +0385 metAnnotation = strtrim(strsplit(metAnnotation,';')); +0386 for a=1:length(metAnnotation) +0387 newModel.metMiriams{i,1}.name{counter,1} = metNamespaces{j}; +0388 newModel.metMiriams{i,1}.value{counter,1} = metAnnotation{a}; +0389 counter=counter+1; +0390 end +0391 end +0392 end +0393 end +0394 end +0395 end +0396 if printWarning +0397 fprintf('Could not determine whether PubChemIDs are compounds (CID)\n or substances (SID). All annotated PubChemIDs will therefore \n be assigned as compounds (CID).\n'); +0398 end 0399 end 0400 -0401 function rules=grrulesToRules(model) -0402 %This function just takes grRules, changes all gene names to -0403 %'x(geneNumber)' and also changes 'or' and 'and' relations to corresponding -0404 %symbols -0405 replacingGenes=cell([size(model.genes,1) 1]); -0406 for i=1:numel(replacingGenes) -0407 replacingGenes{i}=strcat('x(',num2str(i),')'); -0408 end -0409 rules = strcat({' '},model.grRules,{' '}); -0410 for i=1:length(model.genes) -0411 rules=regexprep(rules,[' ' model.genes{i} ' '],[' ' replacingGenes{i} ' ']); -0412 rules=regexprep(rules,['(' model.genes{i} ' '],['(' replacingGenes{i} ' ']); -0413 rules=regexprep(rules,[' ' model.genes{i} ')'],[' ' replacingGenes{i} ')']); -0414 end -0415 rules=regexprep(rules,' and ',' & '); -0416 rules=regexprep(rules,' or ',' | '); -0417 rules=strtrim(rules); +0401 % Order fields +0402 newModel=standardizeModelFieldOrder(newModel); % Corrects for both RAVEN and COBRA models +0403 end +0404 +0405 function rules=grrulesToRules(model) +0406 %This function just takes grRules, changes all gene names to +0407 %'x(geneNumber)' and also changes 'or' and 'and' relations to corresponding +0408 %symbols +0409 replacingGenes=cell([size(model.genes,1) 1]); +0410 for i=1:numel(replacingGenes) +0411 replacingGenes{i}=strcat('x(',num2str(i),')'); +0412 end +0413 rules = strcat({' '},model.grRules,{' '}); +0414 for i=1:length(model.genes) +0415 rules=regexprep(rules,[' ' model.genes{i} ' '],[' ' replacingGenes{i} ' ']); +0416 rules=regexprep(rules,['(' model.genes{i} ' '],['(' replacingGenes{i} ' ']); +0417 rules=regexprep(rules,[' ' model.genes{i} ')'],[' ' replacingGenes{i} ')']); 0418 end -0419 -0420 function grRules=rulesTogrrules(model) -0421 %This function takes rules, replaces &/| for and/or, replaces the x(i) -0422 %format with the actual gene ID, and takes out extra whitespace and -0423 %redundant parenthesis introduced by COBRA, to create grRules. -0424 grRules = strrep(model.rules,'&','and'); -0425 grRules = strrep(grRules,'|','or'); -0426 for i = 1:length(model.genes) -0427 grRules = strrep(grRules,['x(' num2str(i) ')'],model.genes{i}); -0428 end -0429 grRules = strrep(grRules,'( ','('); -0430 grRules = strrep(grRules,' )',')'); -0431 grRules = regexprep(grRules,'^(',''); %rules that start with a "(" -0432 grRules = regexprep(grRules,')$',''); %rules that end with a ")" -0433 end +0419 rules=regexprep(rules,' and ',' & '); +0420 rules=regexprep(rules,' or ',' | '); +0421 rules=strtrim(rules); +0422 end +0423 +0424 function grRules=rulesTogrrules(model) +0425 %This function takes rules, replaces &/| for and/or, replaces the x(i) +0426 %format with the actual gene ID, and takes out extra whitespace and +0427 %redundant parenthesis introduced by COBRA, to create grRules. +0428 grRules = strrep(model.rules,'&','and'); +0429 grRules = strrep(grRules,'|','or'); +0430 for i = 1:length(model.genes) +0431 grRules = strrep(grRules,['x(' num2str(i) ')'],model.genes{i}); +0432 end +0433 grRules = strrep(grRules,'( ','('); +0434 grRules = strrep(grRules,' )',')'); +0435 grRules = regexprep(grRules,'^(',''); %rules that start with a "(" +0436 grRules = regexprep(grRules,')$',''); %rules that end with a ")" +0437 end
Generated by m2html © 2005
\ No newline at end of file diff --git a/struct_conversion/ravenCobraWrapper.m b/struct_conversion/ravenCobraWrapper.m index 0e391969..b1b37e77 100755 --- a/struct_conversion/ravenCobraWrapper.m +++ b/struct_conversion/ravenCobraWrapper.m @@ -8,7 +8,9 @@ % % This function is a bidirectional tool to convert between RAVEN and % COBRA structures. It recognises COBRA structure by checking field -% 'rules' existense, which is only found in COBRA Toolbox structure. +% 'rules' existense, which is only found in COBRA Toolbox structure. If +% the COBRA model also has a grRules field, then this will be used +% instead of parsing the rules field. % % NOTE: During RAVEN -> COBRA -> RAVEN conversion cycle the following % fields are lost: annotation, compOutside, compMiriams, rxnComps, @@ -256,8 +258,10 @@ if isfield(model,'modelName') newModel.name=model.modelName; end - if isfield(model,'rules') + if isfield(model,'rules') && ~isfield(model,'grRules') model.grRules = rulesTogrrules(model); + end + if isfield(model,'grRules') [grRules,rxnGeneMat] = standardizeGrRules(model,true); newModel.grRules = grRules; newModel.rxnGeneMat = rxnGeneMat; @@ -395,7 +399,7 @@ end % Order fields -modelNew=standardizeModelFieldOrder(newModel); % Corrects for both RAVEN and COBRA models +newModel=standardizeModelFieldOrder(newModel); % Corrects for both RAVEN and COBRA models end function rules=grrulesToRules(model) From 10d0055da1625631a779cf9af4db39bfa7edabc1 Mon Sep 17 00:00:00 2001 From: Eduard Kerkhoven Date: Wed, 27 Mar 2024 15:00:32 +0100 Subject: [PATCH 12/23] feat: optimizeProb error solving milp with glpk --- doc/solver/optimizeProb.html | 484 ++++++++++++++++++----------------- solver/optimizeProb.m | 10 +- 2 files changed, 255 insertions(+), 239 deletions(-) diff --git a/doc/solver/optimizeProb.html b/doc/solver/optimizeProb.html index ed433a36..50d2fd04 100644 --- a/doc/solver/optimizeProb.html +++ b/doc/solver/optimizeProb.html @@ -80,247 +80,255 @@

SOURCE CODE ^end 0027 end 0028 solver=RAVENSOLVER; -0029 -0030 if ~all(lower(prob.vartype) == 'c') -0031 milp=true; -0032 else -0033 milp=false; -0034 end -0035 -0036 %% Define default parameters, which will then be used to make solver- -0037 % specific solverparams structures -0038 defaultparams.feasTol = 1e-9; -0039 defaultparams.optTol = 1e-9; -0040 defaultparams.objTol = 1e-6; -0041 defaultparams.timeLimit = 1000; -0042 %defaultparams.iterationLimit = 1000; -0043 defaultparams.intTol = 1e-12; -0044 defaultparams.relMipGapTol = 1e-12; -0045 defaultparams.absMipGapTol = 1e-12; -0046 if milp -0047 defaultparams.MIPGap = 1e-12; -0048 defaultparams.Seed = 1; -0049 end -0050 -0051 switch solver -0052 %% Use whatever solver is set by COBRA Toolbox changeCobraSolver -0053 case 'cobra' -0054 if milp -0055 cparams=struct('timeLimit',1e9,'printLevel',0,'intTol',1e-6,'relMipGapTol',1e-9); -0056 cparams=structUpdate(cparams,params); -0057 res=solveCobraMILP(prob,cparams); -0058 else -0059 res=solveCobraLP(prob); -0060 end -0061 if isfield(res,{'dual','rcost'}) -0062 res.dual=res.dual; -0063 res.rcost=res.rcost; -0064 end -0065 -0066 %% Use Gurobi in a MATLAB environment -0067 case 'gurobi' -0068 if milp -0069 if verbose -0070 solverparams.OutputFlag = 1; -0071 else -0072 solverparams.OutputFlag = 0; -0073 end -0074 solverparams.IntFeasTol = 10^-9; %min val for gurobi -0075 solverparams.MIPGap = defaultparams.MIPGap; -0076 solverparams.Seed = defaultparams.Seed; -0077 else -0078 solverparams.OutputFlag = 0; -0079 end -0080 solverparams.DisplayInterval= 1; % Level of verbosity -0081 solverparams.TimeLimit = defaultparams.timeLimit; -0082 solverparams.FeasibilityTol = defaultparams.feasTol; -0083 solverparams.OptimalityTol = defaultparams.optTol; -0084 solverparams.Presolve = 2; -0085 solverparams = structUpdate(solverparams,params); -0086 -0087 % Restructering problem according to gurobi format -0088 if isfield(prob, 'csense') -0089 prob.sense = renameparams(prob.csense, {'L','G','E'}, {'<','>','='}); -0090 prob = rmfield(prob, {'csense'}); -0091 end -0092 if isfield(prob, 'osense') -0093 osense = prob.osense; -0094 prob.modelsense = renameparams(num2str(prob.osense), {'1','-1'}, {'min','max'}); -0095 prob = rmfield(prob, {'osense'}); -0096 end -0097 [prob.obj, prob.rhs, prob.vtype] = deal(prob.c, prob.b, prob.vartype); -0098 prob = rmfield(prob, {'c','b','vartype'}); -0099 -0100 resG = gurobi(prob,solverparams); -0101 -0102 try -0103 % Name output fields the same as COBRA does -0104 res.full = resG.x; -0105 res.obj = resG.objval; -0106 res.origStat = resG.status; -0107 if isfield(resG,{'pi','rc'}) -0108 res.dual = -resG.pi*osense; -0109 res.rcost = -resG.rc*osense; -0110 end -0111 if milp && strcmp(resG.status, 'TIME_LIMIT') -0112 % If res has the objval field, it succeeded, regardless of -0113 % time_limit status -0114 resG.status = 'OPTIMAL'; -0115 end -0116 switch resG.status -0117 case 'OPTIMAL' -0118 res.stat = 1; -0119 case 'UNBOUNDED' -0120 res.stat = 2; -0121 otherwise -0122 res.stat = 0; +0029 if ~all(lower(prob.vartype) == 'c') +0030 milp=true; +0031 errorText = 'glpk is not suitable for solving MILPs, '; +0032 switch solver +0033 case 'glpk' +0034 error([errorText 'select a different solver with setRavenSolver().']) +0035 case 'cobra' +0036 if strcmp(CBT_MILP_SOLVER,'glpk') +0037 error([errorText 'select a different solver with changeCobraSolver() or setRavenSolver().']) +0038 end +0039 end +0040 else +0041 milp=false; +0042 end +0043 +0044 %% Define default parameters, which will then be used to make solver- +0045 % specific solverparams structures +0046 defaultparams.feasTol = 1e-9; +0047 defaultparams.optTol = 1e-9; +0048 defaultparams.objTol = 1e-6; +0049 defaultparams.timeLimit = 1000; +0050 %defaultparams.iterationLimit = 1000; +0051 defaultparams.intTol = 1e-12; +0052 defaultparams.relMipGapTol = 1e-12; +0053 defaultparams.absMipGapTol = 1e-12; +0054 if milp +0055 defaultparams.MIPGap = 1e-12; +0056 defaultparams.Seed = 1; +0057 end +0058 +0059 switch solver +0060 %% Use whatever solver is set by COBRA Toolbox changeCobraSolver +0061 case 'cobra' +0062 if milp +0063 cparams=struct('timeLimit',1e9,'printLevel',0,'intTol',1e-6,'relMipGapTol',1e-9); +0064 cparams=structUpdate(cparams,params); +0065 res=solveCobraMILP(prob,cparams); +0066 else +0067 res=solveCobraLP(prob); +0068 end +0069 if isfield(res,{'dual','rcost'}) +0070 res.dual=res.dual; +0071 res.rcost=res.rcost; +0072 end +0073 +0074 %% Use Gurobi in a MATLAB environment +0075 case 'gurobi' +0076 if milp +0077 if verbose +0078 solverparams.OutputFlag = 1; +0079 else +0080 solverparams.OutputFlag = 0; +0081 end +0082 solverparams.IntFeasTol = 10^-9; %min val for gurobi +0083 solverparams.MIPGap = defaultparams.MIPGap; +0084 solverparams.Seed = defaultparams.Seed; +0085 else +0086 solverparams.OutputFlag = 0; +0087 end +0088 solverparams.DisplayInterval= 1; % Level of verbosity +0089 solverparams.TimeLimit = defaultparams.timeLimit; +0090 solverparams.FeasibilityTol = defaultparams.feasTol; +0091 solverparams.OptimalityTol = defaultparams.optTol; +0092 solverparams.Presolve = 2; +0093 solverparams = structUpdate(solverparams,params); +0094 +0095 % Restructering problem according to gurobi format +0096 if isfield(prob, 'csense') +0097 prob.sense = renameparams(prob.csense, {'L','G','E'}, {'<','>','='}); +0098 prob = rmfield(prob, {'csense'}); +0099 end +0100 if isfield(prob, 'osense') +0101 osense = prob.osense; +0102 prob.modelsense = renameparams(num2str(prob.osense), {'1','-1'}, {'min','max'}); +0103 prob = rmfield(prob, {'osense'}); +0104 end +0105 [prob.obj, prob.rhs, prob.vtype] = deal(prob.c, prob.b, prob.vartype); +0106 prob = rmfield(prob, {'c','b','vartype'}); +0107 +0108 resG = gurobi(prob,solverparams); +0109 +0110 try +0111 % Name output fields the same as COBRA does +0112 res.full = resG.x; +0113 res.obj = resG.objval; +0114 res.origStat = resG.status; +0115 if isfield(resG,{'pi','rc'}) +0116 res.dual = -resG.pi*osense; +0117 res.rcost = -resG.rc*osense; +0118 end +0119 if milp && strcmp(resG.status, 'TIME_LIMIT') +0120 % If res has the objval field, it succeeded, regardless of +0121 % time_limit status +0122 resG.status = 'OPTIMAL'; 0123 end -0124 if ~milp -0125 res.vbasis = resG.vbasis; -0126 res.cbasis = resG.cbasis; -0127 else -0128 res.mipgap = resG.mipgap; -0129 end -0130 catch -0131 res.stat = 0; -0132 res.origStat = resG.status; % useful information to have -0133 end -0134 %% Use GLPK using RAVEN-provided binary -0135 case 'glpk' -0136 solverparams.scale = 1; % Auto scaling -0137 solverparams.tmlim = defaultparams.timeLimit; -0138 solverparams.tolbnd = defaultparams.feasTol; -0139 solverparams.toldj = defaultparams.optTol; -0140 solverparams.tolint = defaultparams.intTol; -0141 solverparams.tolobj = defaultparams.objTol; -0142 solverparams.msglev = 0; % Level of verbosity -0143 solverparams = structUpdate(solverparams,params); -0144 -0145 prob.csense = renameparams(prob.csense, {'L','G','E'}, {'U','L','S'}); -0146 -0147 if milp -0148 solverparams.tmlim = solverparams.tmlim*10; -0149 solverparams.msglev = 1; % Level of verbosity -0150 disp('Issues have been observed when using GLPK for MILP solving. Be advised to carefully observe the results, or us another solver.') -0151 end +0124 switch resG.status +0125 case 'OPTIMAL' +0126 res.stat = 1; +0127 case 'UNBOUNDED' +0128 res.stat = 2; +0129 otherwise +0130 res.stat = 0; +0131 end +0132 if ~milp +0133 res.vbasis = resG.vbasis; +0134 res.cbasis = resG.cbasis; +0135 else +0136 res.mipgap = resG.mipgap; +0137 end +0138 catch +0139 res.stat = 0; +0140 res.origStat = resG.status; % useful information to have +0141 end +0142 %% Use GLPK using RAVEN-provided binary +0143 case 'glpk' +0144 solverparams.scale = 1; % Auto scaling +0145 solverparams.tmlim = defaultparams.timeLimit; +0146 solverparams.tolbnd = defaultparams.feasTol; +0147 solverparams.toldj = defaultparams.optTol; +0148 solverparams.tolint = defaultparams.intTol; +0149 solverparams.tolobj = defaultparams.objTol; +0150 solverparams.msglev = 0; % Level of verbosity +0151 solverparams = structUpdate(solverparams,params); 0152 -0153 % Ensure that RAVEN glpk binary is used, return to original -0154 % directory afterwards -0155 [ravenDir,currDir]=findRAVENroot(); -0156 cd(fullfile(ravenDir,'software','GLPKmex')) -0157 [xopt, fmin, errnum, extra] = glpk(prob.c, prob.A, prob.b, prob.lb, prob.ub, prob.csense, prob.vartype, prob.osense, solverparams); -0158 cd(currDir) -0159 -0160 switch errnum % 1 = undefined; 2 = feasible; 3 = infeasible; 4 = no feasible solution; 5 = optimal; 6 = no unbounded solution -0161 case 5 -0162 res.stat = 1; % Optimal -0163 case 2 -0164 res.stat = 2; % Feasible, but not optimal -0165 otherwise -0166 res.stat = 0; -0167 end -0168 res.origStat = errnum; -0169 res.full = xopt; -0170 res.obj = fmin; -0171 res.dual = -extra.lambda*prob.osense; -0172 res.rcost = -extra.redcosts*prob.osense; -0173 %% Use SoPlex -0174 case {'soplex','scip'} % Old 'soplex' option also allowed -0175 [xopt,fval,exitflag] = scip([], prob.c, prob.A,-prob.b, prob.b, prob.lb, prob.ub, prob.vartype); -0176 -0177 % [x,fval,exitflag,stats] = scip(H, f, A, rl, ru, lb, ub, xtype, sos, qc, nl, x0, opts) -0178 % -0179 % Input arguments*: -0180 % H - quadratic objective matrix (sparse, optional [NOT TRIL / TRIU]) -0181 % f - linear objective vector -0182 % A - linear constraint matrix (sparse) -0183 % rl - linear constraint lhs -0184 % ru - linear constraint rhs -0185 % lb - decision variable lower bounds -0186 % ub - decision variable upper bounds -0187 % xtype - string of variable integrality ('c' continuous, 'i' integer, 'b' binary) -0188 % sos - SOS structure with fields type, index and weight (see below) -0189 % qc - Quadratic Constraints structure with fields Q, l, qrl and qru (see below) -0190 % nl - Nonlinear Objective and Constraints structure (see below) -0191 % x0 - primal solution -0192 % opts - solver options (see below) -0193 % -0194 % Return arguments: -0195 % x - solution vector -0196 % fval - objective value at the solution -0197 % exitflag - exit status (see below) -0198 % stats - statistics structure -0199 % -0200 % Option Fields (all optional, see also optiset for a list): -0201 % solverOpts - specific SCIP options (list of pairs of parameter names and values) -0202 % maxiter - maximum LP solver iterations -0203 % maxnodes - maximum nodes to explore -0204 % maxtime - maximum execution time [s] -0205 % tolrfun - primal feasibility tolerance -0206 % display - solver display level [0-5] -0207 % probfile - write problem to given file -0208 % presolvedfile - write presolved problem to file -0209 % -0210 % Return Status: -0211 % 0 - Unknown -0212 % 1 - User Interrupted -0213 % 2 - Node Limit Reached -0214 % 3 - Total Node Limit Reached -0215 % 4 - Stall Node Limit Reached -0216 % 5 - Time Limit Reached -0217 % 6 - Memory Limit Reached -0218 % 7 - Gap Limit Reached -0219 % 8 - Solution Limit Reached -0220 % 9 - Solution Improvement Limit Reached -0221 % 10 - Restart Limit Reached -0222 % 11 - Problem Solved to Optimality -0223 % 12 - Problem is Infeasible -0224 % 13 - Problem is Unbounded -0225 % 14 - Problem is Either Infeasible or Unbounded -0226 -0227 res.origStat = exitflag; -0228 res.full = xopt; -0229 res.obj = fval; -0230 -0231 switch exitflag -0232 case 11 -0233 res.stat = 1; -0234 case [5, 6, 7, 8, 9, 10, 13] -0235 res.stat = 2; -0236 otherwise -0237 res.stat = 0; -0238 end -0239 otherwise -0240 error('RAVEN solver not defined or unknown. Try using setRavenSolver(''solver'').'); -0241 end -0242 if res.stat>0 -0243 res.full=res.full(1:size(prob.a,2)); -0244 end -0245 end -0246 -0247 function s_merged=structUpdate(s_old,s_new) -0248 %Remove overlapping fields from first struct; -0249 %Obtain all unique names of remaining fields; -0250 %Merge both structs -0251 s_merged = rmfield(s_old, intersect(fieldnames(s_old), fieldnames(s_new))); -0252 names = [fieldnames(s_merged); fieldnames(s_new)]; -0253 s_merged = cell2struct([struct2cell(s_merged); struct2cell(s_new)], names, 1); -0254 end -0255 -0256 function paramlist = renameparams(paramlist,old,new) -0257 if ~iscell(paramlist) -0258 wasNoCell = true; -0259 paramlist={paramlist}; -0260 else -0261 wasNoCell = false; +0153 prob.csense = renameparams(prob.csense, {'L','G','E'}, {'U','L','S'}); +0154 +0155 if milp +0156 solverparams.tmlim = solverparams.tmlim*10; +0157 solverparams.msglev = 1; % Level of verbosity +0158 disp('Issues have been observed when using GLPK for MILP solving. Be advised to carefully observe the results, or us another solver.') +0159 end +0160 +0161 % Ensure that RAVEN glpk binary is used, return to original +0162 % directory afterwards +0163 [ravenDir,currDir]=findRAVENroot(); +0164 cd(fullfile(ravenDir,'software','GLPKmex')) +0165 [xopt, fmin, errnum, extra] = glpk(prob.c, prob.A, prob.b, prob.lb, prob.ub, prob.csense, prob.vartype, prob.osense, solverparams); +0166 cd(currDir) +0167 +0168 switch errnum % 1 = undefined; 2 = feasible; 3 = infeasible; 4 = no feasible solution; 5 = optimal; 6 = no unbounded solution +0169 case 5 +0170 res.stat = 1; % Optimal +0171 case 2 +0172 res.stat = 2; % Feasible, but not optimal +0173 otherwise +0174 res.stat = 0; +0175 end +0176 res.origStat = errnum; +0177 res.full = xopt; +0178 res.obj = fmin; +0179 res.dual = -extra.lambda*prob.osense; +0180 res.rcost = -extra.redcosts*prob.osense; +0181 %% Use SoPlex +0182 case {'soplex','scip'} % Old 'soplex' option also allowed +0183 [xopt,fval,exitflag] = scip([], prob.c, prob.A,-prob.b, prob.b, prob.lb, prob.ub, prob.vartype); +0184 +0185 % [x,fval,exitflag,stats] = scip(H, f, A, rl, ru, lb, ub, xtype, sos, qc, nl, x0, opts) +0186 % +0187 % Input arguments*: +0188 % H - quadratic objective matrix (sparse, optional [NOT TRIL / TRIU]) +0189 % f - linear objective vector +0190 % A - linear constraint matrix (sparse) +0191 % rl - linear constraint lhs +0192 % ru - linear constraint rhs +0193 % lb - decision variable lower bounds +0194 % ub - decision variable upper bounds +0195 % xtype - string of variable integrality ('c' continuous, 'i' integer, 'b' binary) +0196 % sos - SOS structure with fields type, index and weight (see below) +0197 % qc - Quadratic Constraints structure with fields Q, l, qrl and qru (see below) +0198 % nl - Nonlinear Objective and Constraints structure (see below) +0199 % x0 - primal solution +0200 % opts - solver options (see below) +0201 % +0202 % Return arguments: +0203 % x - solution vector +0204 % fval - objective value at the solution +0205 % exitflag - exit status (see below) +0206 % stats - statistics structure +0207 % +0208 % Option Fields (all optional, see also optiset for a list): +0209 % solverOpts - specific SCIP options (list of pairs of parameter names and values) +0210 % maxiter - maximum LP solver iterations +0211 % maxnodes - maximum nodes to explore +0212 % maxtime - maximum execution time [s] +0213 % tolrfun - primal feasibility tolerance +0214 % display - solver display level [0-5] +0215 % probfile - write problem to given file +0216 % presolvedfile - write presolved problem to file +0217 % +0218 % Return Status: +0219 % 0 - Unknown +0220 % 1 - User Interrupted +0221 % 2 - Node Limit Reached +0222 % 3 - Total Node Limit Reached +0223 % 4 - Stall Node Limit Reached +0224 % 5 - Time Limit Reached +0225 % 6 - Memory Limit Reached +0226 % 7 - Gap Limit Reached +0227 % 8 - Solution Limit Reached +0228 % 9 - Solution Improvement Limit Reached +0229 % 10 - Restart Limit Reached +0230 % 11 - Problem Solved to Optimality +0231 % 12 - Problem is Infeasible +0232 % 13 - Problem is Unbounded +0233 % 14 - Problem is Either Infeasible or Unbounded +0234 +0235 res.origStat = exitflag; +0236 res.full = xopt; +0237 res.obj = fval; +0238 +0239 switch exitflag +0240 case 11 +0241 res.stat = 1; +0242 case [5, 6, 7, 8, 9, 10, 13] +0243 res.stat = 2; +0244 otherwise +0245 res.stat = 0; +0246 end +0247 otherwise +0248 error('RAVEN solver not defined or unknown. Try using setRavenSolver(''solver'').'); +0249 end +0250 if res.stat>0 +0251 res.full=res.full(1:size(prob.a,2)); +0252 end +0253 end +0254 +0255 function s_merged=structUpdate(s_old,s_new) +0256 %Remove overlapping fields from first struct; +0257 %Obtain all unique names of remaining fields; +0258 %Merge both structs +0259 s_merged = rmfield(s_old, intersect(fieldnames(s_old), fieldnames(s_new))); +0260 names = [fieldnames(s_merged); fieldnames(s_new)]; +0261 s_merged = cell2struct([struct2cell(s_merged); struct2cell(s_new)], names, 1); 0262 end -0263 for i=1:numel(old) -0264 paramlist = regexprep(paramlist,old{i},new{i}); -0265 end -0266 if wasNoCell -0267 paramlist=paramlist{1}; -0268 end -0269 end +0263 +0264 function paramlist = renameparams(paramlist,old,new) +0265 if ~iscell(paramlist) +0266 wasNoCell = true; +0267 paramlist={paramlist}; +0268 else +0269 wasNoCell = false; +0270 end +0271 for i=1:numel(old) +0272 paramlist = regexprep(paramlist,old{i},new{i}); +0273 end +0274 if wasNoCell +0275 paramlist=paramlist{1}; +0276 end +0277 end
Generated by m2html © 2005
\ No newline at end of file diff --git a/solver/optimizeProb.m b/solver/optimizeProb.m index 833a3932..86749410 100755 --- a/solver/optimizeProb.m +++ b/solver/optimizeProb.m @@ -26,9 +26,17 @@ end end solver=RAVENSOLVER; - if ~all(lower(prob.vartype) == 'c') milp=true; + errorText = 'glpk is not suitable for solving MILPs, '; + switch solver + case 'glpk' + error([errorText 'select a different solver with setRavenSolver().']) + case 'cobra' + if strcmp(CBT_MILP_SOLVER,'glpk') + error([errorText 'select a different solver with changeCobraSolver() or setRavenSolver().']) + end + end else milp=false; end From 9421480c44e18895ac76f379a58e08c3794f1181 Mon Sep 17 00:00:00 2001 From: Eduard Kerkhoven Date: Wed, 27 Mar 2024 18:29:06 +0100 Subject: [PATCH 13/23] fix: adjust tests to separate solvers --- .../unit_tests/fillGapsLargeTests.html | 184 +++++-------- .../unit_tests/fillGapsSmallTests.html | 45 +-- doc/testing/unit_tests/solverTests.html | 259 +++++++++--------- testing/unit_tests/fillGapsLargeTests.m | 54 +--- testing/unit_tests/fillGapsSmallTests.m | 41 +-- testing/unit_tests/solverTests.m | 9 - 6 files changed, 214 insertions(+), 378 deletions(-) diff --git a/doc/testing/unit_tests/fillGapsLargeTests.html b/doc/testing/unit_tests/fillGapsLargeTests.html index ab7c3e0a..fd60f30e 100644 --- a/doc/testing/unit_tests/fillGapsLargeTests.html +++ b/doc/testing/unit_tests/fillGapsLargeTests.html @@ -42,7 +42,7 @@

CROSS-REFERENCE INFORMATION ^
 
 <h2><a name=SUBFUNCTIONS ^

+
  • function testLargeGurobi(testCase)
  • function testLargeSCIP(testCase)
  • SOURCE CODE ^

    0001 %run this test case with the command
    @@ -51,115 +51,79 @@ 

    SOURCE CODE ^end 0006 -0007 %% Skip testLargeGlpk, fails with larger models, known issue with glpk -0008 % function testLargeGurobi(testCase) -0009 % sourceDir = fileparts(fileparts(fileparts(which(mfilename)))); -0010 % evalc('model=importModel(fullfile(sourceDir,''tutorial'',''iAL1006 v1.00.xml''))'); -0011 % model.c(1484)=1; -0012 % modelDB=model; % Keep as database with reactions -0013 % try -0014 % oldSolver=getpref('RAVEN','solver'); -0015 % catch -0016 % end -0017 % setRavenSolver('glpk'); -0018 % -0019 % %Remove first 10 reactions -0020 % model=removeReactions(modelDB,(1:10)); -0021 % modelDB.id='DB'; -0022 % try -0023 % evalc('[newConnected,cannotConnect,addedRxns,model,exitFlag]=fillGaps(model,modelDB)'); -0024 % catch -0025 % try -0026 % setRavenSolver(oldSolver); -0027 % catch -0028 % rmpref('RAVEN','solver'); -0029 % end -0030 % error('Solver not working') -0031 % end -0032 % sol=solveLP(model); -0033 % try -0034 % setRavenSolver(oldSolver); -0035 % catch -0036 % rmpref('RAVEN','solver'); -0037 % end -0038 % %Expect at least 5% of the original growth -0039 % verifyTrue(testCase,-sol.f>0); -0040 % end -0041 %% -0042 function testLargeGurobi(testCase) -0043 if exist('gurobi','file')~=3 -0044 error('Gurobi not installed or cannot be found in MATLAB path, test skipped') -0045 end -0046 sourceDir = fileparts(fileparts(fileparts(which(mfilename)))); -0047 evalc('model=importModel(fullfile(sourceDir,''tutorial'',''iAL1006 v1.00.xml''))'); -0048 model.c(1484)=1; -0049 modelDB=model; % Keep as database with reactions -0050 try -0051 oldSolver=getpref('RAVEN','solver'); -0052 catch -0053 end -0054 setRavenSolver('gurobi'); -0055 -0056 %Remove first 10 reactions -0057 model=removeReactions(modelDB,(1:10)); -0058 modelDB.id='DB'; -0059 try -0060 evalc('[newConnected,cannotConnect,addedRxns,model,exitFlag]=fillGaps(model,modelDB)'); -0061 catch -0062 try -0063 setRavenSolver(oldSolver); -0064 catch -0065 rmpref('RAVEN','solver'); -0066 end -0067 error('Solver not working') -0068 end -0069 sol=solveLP(model); -0070 try -0071 setRavenSolver(oldSolver); -0072 catch -0073 rmpref('RAVEN','solver'); -0074 end -0075 %Expect at least 5% of the original growth -0076 verifyTrue(testCase,-sol.f>0); -0077 end -0078 -0079 function testLargeCobra(testCase) -0080 if exist('initCobraToolbox.m','file')~=2 -0081 error('COBRA Toolbox not installed or cannot be found in MATLAB path, test skipped') -0082 end -0083 sourceDir = fileparts(fileparts(fileparts(which(mfilename)))); -0084 evalc('model=importModel(fullfile(sourceDir,''tutorial'',''iAL1006 v1.00.xml''))'); -0085 model.c(1484)=1; -0086 modelDB=model; % Keep as database with reactions -0087 try -0088 oldSolver=getpref('RAVEN','solver'); -0089 catch -0090 end -0091 setRavenSolver('cobra'); -0092 -0093 %Remove first 10 reactions -0094 model=removeReactions(modelDB,(1:10)); -0095 modelDB.id='DB'; -0096 try -0097 evalc('[newConnected,cannotConnect,addedRxns,model,exitFlag]=fillGaps(model,modelDB)'); -0098 catch -0099 try -0100 setRavenSolver(oldSolver); -0101 catch -0102 rmpref('RAVEN','solver'); -0103 end -0104 error('Solver not working') -0105 end -0106 sol=solveLP(model); -0107 try -0108 setRavenSolver(oldSolver); -0109 catch -0110 rmpref('RAVEN','solver'); -0111 end -0112 -0113 %Expect at least 5% of the original growth -0114 verifyTrue(testCase,-sol.f>0); -0115 end

    +0007 function testLargeGurobi(testCase) +0008 if exist('gurobi','file')~=3 +0009 error('Gurobi not installed or cannot be found in MATLAB path, test skipped') +0010 end +0011 sourceDir = fileparts(fileparts(fileparts(which(mfilename)))); +0012 evalc('model=importModel(fullfile(sourceDir,''tutorial'',''iAL1006 v1.00.xml''))'); +0013 model.c(1484)=1; +0014 modelDB=model; % Keep as database with reactions +0015 try +0016 oldSolver=getpref('RAVEN','solver'); +0017 catch +0018 end +0019 setRavenSolver('gurobi'); +0020 +0021 %Remove first 10 reactions +0022 model=removeReactions(modelDB,(1:10)); +0023 modelDB.id='DB'; +0024 try +0025 evalc('[newConnected,cannotConnect,addedRxns,model,exitFlag]=fillGaps(model,modelDB,false,false)'); +0026 catch +0027 try +0028 setRavenSolver(oldSolver); +0029 catch +0030 rmpref('RAVEN','solver'); +0031 end +0032 error('Solver not working') +0033 end +0034 sol=solveLP(model); +0035 try +0036 setRavenSolver(oldSolver); +0037 catch +0038 rmpref('RAVEN','solver'); +0039 end +0040 %Expect at least 5% of the original growth +0041 verifyTrue(testCase,-sol.f>0); +0042 end +0043 +0044 function testLargeSCIP(testCase) +0045 sourceDir = fileparts(fileparts(fileparts(which(mfilename)))); +0046 evalc('model=importModel(fullfile(sourceDir,''tutorial'',''iAL1006 v1.00.xml''))'); +0047 model.c(1484)=1; +0048 modelDB=model; % Keep as database with reactions +0049 % Force growth in gapped model +0050 sol=solveLP(model); +0051 model.lb(1484)=abs(sol.f*0.1); +0052 try +0053 oldSolver=getpref('RAVEN','solver'); +0054 catch +0055 end +0056 setRavenSolver('scip'); +0057 +0058 %Remove first 10 reactions +0059 model=removeReactions(model,(1:10)); +0060 modelDB.id='DB'; +0061 try +0062 evalc('[newConnected,cannotConnect,addedRxns,model,exitFlag]=fillGaps(model,modelDB,false,true)'); +0063 catch +0064 try +0065 setRavenSolver(oldSolver); +0066 catch +0067 rmpref('RAVEN','solver'); +0068 end +0069 error('Solver not working') +0070 end +0071 sol=solveLP(model); +0072 try +0073 setRavenSolver(oldSolver); +0074 catch +0075 rmpref('RAVEN','solver'); +0076 end +0077 %Expect at least 5% of the original growth +0078 verifyTrue(testCase,-sol.f>0); +0079 end
    Generated by m2html © 2005
    \ No newline at end of file diff --git a/doc/testing/unit_tests/fillGapsSmallTests.html b/doc/testing/unit_tests/fillGapsSmallTests.html index 5d76c5e0..fc65eed0 100644 --- a/doc/testing/unit_tests/fillGapsSmallTests.html +++ b/doc/testing/unit_tests/fillGapsSmallTests.html @@ -42,7 +42,7 @@

    CROSS-REFERENCE INFORMATION ^
 
 <h2><a name=SUBFUNCTIONS ^

    +
  • function testSmallSCIP(testCase)
  • function testSmallGurobi(testCase)
  • SOURCE CODE ^

    0001 %run this test case with the command
    @@ -51,7 +51,7 @@ 

    SOURCE CODE ^end 0006 -0007 function testSmallGlpk(testCase) +0007 function testSmallSCIP(testCase) 0008 %Test using small model 0009 sourceDir = fileparts(which(mfilename)); 0010 load([sourceDir,'/test_data/ecoli_textbook.mat'], 'model'); @@ -60,7 +60,7 @@

    SOURCE CODE ^'RAVEN','solver'); 0014 catch 0015 end -0016 setRavenSolver('glpk'); +0016 setRavenSolver('scip'); 0017 0018 %Remove first 10 reactions 0019 model=removeReactions(modelDB,(1:10)); @@ -121,44 +121,7 @@

    SOURCE CODE ^end 0075 %Expect at least 5% of the original growth 0076 verifyTrue(testCase,-sol.f>0); -0077 end -0078 -0079 function testSmallCobra(testCase) -0080 if exist('initCobraToolbox.m','file')~=2 -0081 error('COBRA Toolbox not installed or cannot be found in MATLAB path, test skipped') -0082 end -0083 %Test using small model -0084 sourceDir = fileparts(which(mfilename)); -0085 load([sourceDir,'/test_data/ecoli_textbook.mat'], 'model'); -0086 modelDB=model; % Keep as database with reactions -0087 try -0088 oldSolver=getpref('RAVEN','solver'); -0089 catch -0090 end -0091 setRavenSolver('cobra'); -0092 -0093 %Remove first 10 reactions -0094 model=removeReactions(modelDB,(1:10)); -0095 modelDB.id='DB'; -0096 try -0097 evalc('[newConnected,cannotConnect,addedRxns,model,exitFlag]=fillGaps(model,modelDB)'); -0098 catch -0099 try -0100 setRavenSolver(oldSolver); -0101 catch -0102 rmpref('RAVEN','solver'); -0103 end -0104 error('Solver not working') -0105 end -0106 sol=solveLP(model); -0107 try -0108 setRavenSolver(oldSolver); -0109 catch -0110 rmpref('RAVEN','solver'); -0111 end -0112 %Expect at least 5% of the original growth -0113 verifyTrue(testCase,-sol.f>0); -0114 end

    +0077 end
    Generated by m2html © 2005
    \ No newline at end of file diff --git a/doc/testing/unit_tests/solverTests.html b/doc/testing/unit_tests/solverTests.html index 968a8300..67486487 100644 --- a/doc/testing/unit_tests/solverTests.html +++ b/doc/testing/unit_tests/solverTests.html @@ -61,141 +61,132 @@

    SOURCE CODE ^'glpk'); 0015 0016 try -0017 % Try all three types of flux minimization -0018 evalc('sol=solveLP(model,3);'); -0019 evalc('sol=solveLP(model,1);'); -0020 evalc('sol=solveLP(model,0);'); -0021 catch -0022 try -0023 setRavenSolver(oldSolver); -0024 catch -0025 rmpref('RAVEN','solver'); -0026 end -0027 error('Solver not working') -0028 end -0029 try -0030 setRavenSolver(oldSolver); -0031 catch -0032 rmpref('RAVEN','solver'); -0033 end -0034 -0035 load([sourceDir,'/test_data/solverTestOutput.mat'], 'solOut'); -0036 %Check that the actual model is the same as the expected model -0037 verifyEqual(testCase,sol,solOut,'AbsTol',0.1) %Quite generous tolerance, as shadow price calculations fluctuate quite a bit between solvers -0038 end -0039 -0040 function testGurobi(testCase) -0041 if exist('gurobi','file')~=3 -0042 error('Gurobi not installed or cannot be found in MATLAB path, test skipped') -0043 end -0044 sourceDir = fileparts(which(mfilename)); -0045 load([sourceDir,'/test_data/ecoli_textbook.mat'], 'model'); -0046 try -0047 oldSolver=getpref('RAVEN','solver'); -0048 catch -0049 end -0050 setRavenSolver('gurobi'); -0051 -0052 try -0053 % Try all three types of flux minimization -0054 evalc('sol=solveLP(model,3);'); -0055 evalc('sol=solveLP(model,1);'); -0056 evalc('sol=solveLP(model,0);'); -0057 catch -0058 try -0059 setRavenSolver(oldSolver); -0060 catch -0061 rmpref('RAVEN','solver'); -0062 end -0063 error('Solver not working') -0064 end -0065 try -0066 setRavenSolver(oldSolver); -0067 catch -0068 rmpref('RAVEN','solver'); -0069 end -0070 -0071 load([sourceDir,'/test_data/solverTestOutput.mat'], 'solOut'); -0072 %Check that the actual model is the same as the expected model -0073 verifyEqual(testCase,sol,solOut,'AbsTol',0.1) -0074 end -0075 -0076 function testSCIP(testCase) -0077 try -0078 scip; -0079 catch -0080 error('SCIP MEX binary not installed or not functional, test skipped') -0081 end -0082 sourceDir = fileparts(which(mfilename)); -0083 load([sourceDir,'/test_data/ecoli_textbook.mat'], 'model'); -0084 try -0085 oldSolver=getpref('RAVEN','solver'); -0086 catch -0087 end -0088 setRavenSolver('scip'); -0089 try -0090 % Try all three types of flux minimization -0091 evalc('sol=solveLP(model,3);'); -0092 evalc('sol=solveLP(model,1);'); -0093 evalc('sol=solveLP(model,0);'); -0094 catch -0095 try -0096 setRavenSolver(oldSolver); -0097 catch -0098 rmpref('RAVEN','solver'); -0099 end -0100 error('Solver not working') -0101 end -0102 try -0103 setRavenSolver(oldSolver); -0104 catch -0105 rmpref('RAVEN','solver'); -0106 end -0107 -0108 load([sourceDir,'/test_data/solverTestOutput.mat'], 'solOutSCIP'); -0109 %Check that the actual model is the same as the expected model -0110 verifyEqual(testCase,sol,solOutSCIP,'AbsTol',0.1) -0111 end -0112 -0113 function testCobra(testCase) -0114 if exist('initCobraToolbox.m','file')~=2 -0115 error('COBRA Toolbox not installed or cannot be found in MATLAB path, test skipped') +0017 evalc('sol=solveLP(model,0);'); +0018 catch +0019 try +0020 setRavenSolver(oldSolver); +0021 catch +0022 rmpref('RAVEN','solver'); +0023 end +0024 error('Solver not working') +0025 end +0026 try +0027 setRavenSolver(oldSolver); +0028 catch +0029 rmpref('RAVEN','solver'); +0030 end +0031 +0032 load([sourceDir,'/test_data/solverTestOutput.mat'], 'solOut'); +0033 %Check that the actual model is the same as the expected model +0034 verifyEqual(testCase,sol,solOut,'AbsTol',0.1) %Quite generous tolerance, as shadow price calculations fluctuate quite a bit between solvers +0035 end +0036 +0037 function testGurobi(testCase) +0038 if exist('gurobi','file')~=3 +0039 error('Gurobi not installed or cannot be found in MATLAB path, test skipped') +0040 end +0041 sourceDir = fileparts(which(mfilename)); +0042 load([sourceDir,'/test_data/ecoli_textbook.mat'], 'model'); +0043 try +0044 oldSolver=getpref('RAVEN','solver'); +0045 catch +0046 end +0047 setRavenSolver('gurobi'); +0048 +0049 try +0050 % Try all three types of flux minimization +0051 evalc('sol=solveLP(model,3);'); +0052 evalc('sol=solveLP(model,1);'); +0053 evalc('sol=solveLP(model,0);'); +0054 catch +0055 try +0056 setRavenSolver(oldSolver); +0057 catch +0058 rmpref('RAVEN','solver'); +0059 end +0060 error('Solver not working') +0061 end +0062 try +0063 setRavenSolver(oldSolver); +0064 catch +0065 rmpref('RAVEN','solver'); +0066 end +0067 +0068 load([sourceDir,'/test_data/solverTestOutput.mat'], 'solOut'); +0069 %Check that the actual model is the same as the expected model +0070 verifyEqual(testCase,sol,solOut,'AbsTol',0.1) +0071 end +0072 +0073 function testSCIP(testCase) +0074 try +0075 scip; +0076 catch +0077 error('SCIP MEX binary not installed or not functional, test skipped') +0078 end +0079 sourceDir = fileparts(which(mfilename)); +0080 load([sourceDir,'/test_data/ecoli_textbook.mat'], 'model'); +0081 try +0082 oldSolver=getpref('RAVEN','solver'); +0083 catch +0084 end +0085 setRavenSolver('scip'); +0086 try +0087 evalc('sol=solveLP(model,0);'); +0088 catch +0089 try +0090 setRavenSolver(oldSolver); +0091 catch +0092 rmpref('RAVEN','solver'); +0093 end +0094 error('Solver not working') +0095 end +0096 try +0097 setRavenSolver(oldSolver); +0098 catch +0099 rmpref('RAVEN','solver'); +0100 end +0101 +0102 load([sourceDir,'/test_data/solverTestOutput.mat'], 'solOutSCIP'); +0103 %Check that the actual model is the same as the expected model +0104 verifyEqual(testCase,sol,solOutSCIP,'AbsTol',0.1) +0105 end +0106 +0107 function testCobra(testCase) +0108 if exist('initCobraToolbox.m','file')~=2 +0109 error('COBRA Toolbox not installed or cannot be found in MATLAB path, test skipped') +0110 end +0111 sourceDir = fileparts(which(mfilename)); +0112 load([sourceDir,'/test_data/ecoli_textbook.mat'], 'model'); +0113 try +0114 oldSolver=getpref('RAVEN','solver'); +0115 catch 0116 end -0117 sourceDir = fileparts(which(mfilename)); -0118 load([sourceDir,'/test_data/ecoli_textbook.mat'], 'model'); -0119 try -0120 oldSolver=getpref('RAVEN','solver'); -0121 catch -0122 end -0123 global CBT_LP_SOLVER -0124 global CBT_MILP_SOLVER -0125 CBT_LP_SOLVER = 'glpk'; -0126 CBT_MILP_SOLVER = 'glpk'; -0127 setRavenSolver('cobra'); -0128 -0129 try -0130 % Try all three types of flux minimization -0131 evalc('sol=solveLP(model,3);'); -0132 evalc('sol=solveLP(model,1);'); -0133 evalc('sol=solveLP(model,0);'); -0134 catch -0135 try -0136 setRavenSolver(oldSolver); -0137 catch -0138 rmpref('RAVEN','solver'); -0139 end -0140 error('Solver not working') -0141 end -0142 try -0143 setRavenSolver(oldSolver); -0144 catch -0145 rmpref('RAVEN','solver'); -0146 end -0147 -0148 load([sourceDir,'/test_data/solverTestOutput.mat'], 'solOut'); -0149 %Check that the actual model is the same as the expected model -0150 verifyEqual(testCase,sol,solOut,'AbsTol',0.1) -0151 end +0117 global CBT_LP_SOLVER +0118 global CBT_MILP_SOLVER +0119 CBT_LP_SOLVER = 'glpk'; +0120 CBT_MILP_SOLVER = 'glpk'; +0121 setRavenSolver('cobra'); +0122 +0123 try +0124 evalc('sol=solveLP(model,0);'); +0125 catch +0126 try +0127 setRavenSolver(oldSolver); +0128 catch +0129 rmpref('RAVEN','solver'); +0130 end +0131 error('Solver not working') +0132 end +0133 try +0134 setRavenSolver(oldSolver); +0135 catch +0136 rmpref('RAVEN','solver'); +0137 end +0138 +0139 load([sourceDir,'/test_data/solverTestOutput.mat'], 'solOut'); +0140 %Check that the actual model is the same as the expected model +0141 verifyEqual(testCase,sol,solOut,'AbsTol',0.1) +0142 end
    Generated by m2html © 2005
    \ No newline at end of file diff --git a/testing/unit_tests/fillGapsLargeTests.m b/testing/unit_tests/fillGapsLargeTests.m index 5df25eab..9f3bb59b 100644 --- a/testing/unit_tests/fillGapsLargeTests.m +++ b/testing/unit_tests/fillGapsLargeTests.m @@ -4,41 +4,6 @@ tests = functiontests(localfunctions); end -%% Skip testLargeGlpk, fails with larger models, known issue with glpk -% function testLargeGurobi(testCase) -% sourceDir = fileparts(fileparts(fileparts(which(mfilename)))); -% evalc('model=importModel(fullfile(sourceDir,''tutorial'',''iAL1006 v1.00.xml''))'); -% model.c(1484)=1; -% modelDB=model; % Keep as database with reactions -% try -% oldSolver=getpref('RAVEN','solver'); -% catch -% end -% setRavenSolver('glpk'); -% -% %Remove first 10 reactions -% model=removeReactions(modelDB,(1:10)); -% modelDB.id='DB'; -% try -% evalc('[newConnected,cannotConnect,addedRxns,model,exitFlag]=fillGaps(model,modelDB)'); -% catch -% try -% setRavenSolver(oldSolver); -% catch -% rmpref('RAVEN','solver'); -% end -% error('Solver not working') -% end -% sol=solveLP(model); -% try -% setRavenSolver(oldSolver); -% catch -% rmpref('RAVEN','solver'); -% end -% %Expect at least 5% of the original growth -% verifyTrue(testCase,-sol.f>0); -% end -%% function testLargeGurobi(testCase) if exist('gurobi','file')~=3 error('Gurobi not installed or cannot be found in MATLAB path, test skipped') @@ -57,7 +22,7 @@ function testLargeGurobi(testCase) model=removeReactions(modelDB,(1:10)); modelDB.id='DB'; try - evalc('[newConnected,cannotConnect,addedRxns,model,exitFlag]=fillGaps(model,modelDB)'); + evalc('[newConnected,cannotConnect,addedRxns,model,exitFlag]=fillGaps(model,modelDB,false,false)'); catch try setRavenSolver(oldSolver); @@ -76,25 +41,25 @@ function testLargeGurobi(testCase) verifyTrue(testCase,-sol.f>0); end -function testLargeCobra(testCase) -if exist('initCobraToolbox.m','file')~=2 - error('COBRA Toolbox not installed or cannot be found in MATLAB path, test skipped') -end +function testLargeSCIP(testCase) sourceDir = fileparts(fileparts(fileparts(which(mfilename)))); evalc('model=importModel(fullfile(sourceDir,''tutorial'',''iAL1006 v1.00.xml''))'); model.c(1484)=1; modelDB=model; % Keep as database with reactions +% Force growth in gapped model +sol=solveLP(model); +model.lb(1484)=abs(sol.f*0.1); try oldSolver=getpref('RAVEN','solver'); catch end -setRavenSolver('cobra'); +setRavenSolver('scip'); %Remove first 10 reactions -model=removeReactions(modelDB,(1:10)); +model=removeReactions(model,(1:10)); modelDB.id='DB'; try - evalc('[newConnected,cannotConnect,addedRxns,model,exitFlag]=fillGaps(model,modelDB)'); + evalc('[newConnected,cannotConnect,addedRxns,model,exitFlag]=fillGaps(model,modelDB,false,true)'); catch try setRavenSolver(oldSolver); @@ -109,7 +74,6 @@ function testLargeCobra(testCase) catch rmpref('RAVEN','solver'); end - %Expect at least 5% of the original growth verifyTrue(testCase,-sol.f>0); -end \ No newline at end of file +end diff --git a/testing/unit_tests/fillGapsSmallTests.m b/testing/unit_tests/fillGapsSmallTests.m index 83487714..7d29ac49 100644 --- a/testing/unit_tests/fillGapsSmallTests.m +++ b/testing/unit_tests/fillGapsSmallTests.m @@ -4,7 +4,7 @@ tests = functiontests(localfunctions); end -function testSmallGlpk(testCase) +function testSmallSCIP(testCase) %Test using small model sourceDir = fileparts(which(mfilename)); load([sourceDir,'/test_data/ecoli_textbook.mat'], 'model'); @@ -13,7 +13,7 @@ function testSmallGlpk(testCase) oldSolver=getpref('RAVEN','solver'); catch end -setRavenSolver('glpk'); +setRavenSolver('scip'); %Remove first 10 reactions model=removeReactions(modelDB,(1:10)); @@ -55,43 +55,6 @@ function testSmallGurobi(testCase) %Remove first 10 reactions model=removeReactions(modelDB,(1:10)); -modelDB.id='DB'; -try - evalc('[newConnected,cannotConnect,addedRxns,model,exitFlag]=fillGaps(model,modelDB)'); -catch - try - setRavenSolver(oldSolver); - catch - rmpref('RAVEN','solver'); - end - error('Solver not working') -end -sol=solveLP(model); -try - setRavenSolver(oldSolver); -catch - rmpref('RAVEN','solver'); -end -%Expect at least 5% of the original growth -verifyTrue(testCase,-sol.f>0); -end - -function testSmallCobra(testCase) -if exist('initCobraToolbox.m','file')~=2 - error('COBRA Toolbox not installed or cannot be found in MATLAB path, test skipped') -end -%Test using small model -sourceDir = fileparts(which(mfilename)); -load([sourceDir,'/test_data/ecoli_textbook.mat'], 'model'); -modelDB=model; % Keep as database with reactions -try - oldSolver=getpref('RAVEN','solver'); -catch -end -setRavenSolver('cobra'); - -%Remove first 10 reactions -model=removeReactions(modelDB,(1:10)); modelDB.id='DB'; try evalc('[newConnected,cannotConnect,addedRxns,model,exitFlag]=fillGaps(model,modelDB)'); diff --git a/testing/unit_tests/solverTests.m b/testing/unit_tests/solverTests.m index d42a0e4b..9694de41 100644 --- a/testing/unit_tests/solverTests.m +++ b/testing/unit_tests/solverTests.m @@ -14,9 +14,6 @@ function testGlpk(testCase) setRavenSolver('glpk'); try - % Try all three types of flux minimization - evalc('sol=solveLP(model,3);'); - evalc('sol=solveLP(model,1);'); evalc('sol=solveLP(model,0);'); catch try @@ -87,9 +84,6 @@ function testSCIP(testCase) end setRavenSolver('scip'); try - % Try all three types of flux minimization - evalc('sol=solveLP(model,3);'); - evalc('sol=solveLP(model,1);'); evalc('sol=solveLP(model,0);'); catch try @@ -127,9 +121,6 @@ function testCobra(testCase) setRavenSolver('cobra'); try - % Try all three types of flux minimization - evalc('sol=solveLP(model,3);'); - evalc('sol=solveLP(model,1);'); evalc('sol=solveLP(model,0);'); catch try From 3ce4fd8502d3749c76c396c047bd5d6178d8a772 Mon Sep 17 00:00:00 2001 From: Eduard Kerkhoven Date: Thu, 28 Mar 2024 09:53:11 +0100 Subject: [PATCH 14/23] fix: writeYAMLmodel error if dir does not exist --- doc/io/writeYAMLmodel.html | 603 +++++++++++++++++++------------------ io/writeYAMLmodel.m | 3 + 2 files changed, 306 insertions(+), 300 deletions(-) diff --git a/doc/io/writeYAMLmodel.html b/doc/io/writeYAMLmodel.html index 636fa540..11fbc084 100644 --- a/doc/io/writeYAMLmodel.html +++ b/doc/io/writeYAMLmodel.html @@ -118,319 +118,322 @@

    SOURCE CODE ^%Open file: 0061 fid = fopen(fileName,'wt'); -0062 fprintf(fid,'---\n!!omap\n'); -0063 -0064 %Insert file header (metadata) -0065 writeMetadata(model,fid); +0062 if fid == -1 +0063 error(['Cannot write to ' fileName ', does the directory exist?']) +0064 end +0065 fprintf(fid,'---\n!!omap\n'); 0066 -0067 %Metabolites: -0068 fprintf(fid,'- metabolites:\n'); -0069 for i = 1:length(model.mets) -0070 fprintf(fid,' - !!omap\n'); -0071 writeField(model, fid, 'mets', 'txt', i, ' - id', preserveQuotes) -0072 writeField(model, fid, 'metNames', 'txt', i, ' - name', preserveQuotes) -0073 writeField(model, fid, 'metComps', 'txt', i, ' - compartment', preserveQuotes) -0074 writeField(model, fid, 'metFormulas', 'txt', i, ' - formula', preserveQuotes) -0075 writeField(model, fid, 'metCharges', 'num', i, ' - charge', preserveQuotes) -0076 writeField(model, fid, 'inchis', 'txt', i, ' - inchis', preserveQuotes) -0077 writeField(model, fid, 'metSmiles', 'txt', i, ' - smiles', preserveQuotes) -0078 writeField(model, fid, 'metMiriams', 'txt', i, ' - annotation', preserveQuotes) -0079 writeField(model, fid, 'metDeltaG', 'num', i, ' - deltaG', preserveQuotes) -0080 writeField(model, fid, 'metNotes', 'txt', i, ' - notes', preserveQuotes) -0081 writeField(model, fid, 'metFrom', 'txt', i, ' - metFrom', preserveQuotes) -0082 end -0083 -0084 %Reactions: -0085 fprintf(fid,'- reactions:\n'); -0086 for i = 1:length(model.rxns) -0087 fprintf(fid,' - !!omap\n'); -0088 writeField(model, fid, 'rxns', 'txt', i, ' - id', preserveQuotes) -0089 writeField(model, fid, 'rxnNames', 'txt', i, ' - name', preserveQuotes) -0090 writeField(model, fid, 'S', 'txt', i, ' - metabolites', preserveQuotes) -0091 writeField(model, fid, 'lb', 'num', i, ' - lower_bound', preserveQuotes) -0092 writeField(model, fid, 'ub', 'num', i, ' - upper_bound', preserveQuotes) -0093 writeField(model, fid, 'grRules', 'txt', i, ' - gene_reaction_rule', preserveQuotes) -0094 writeField(model, fid, 'rxnFrom', 'txt', i, ' - rxnFrom', preserveQuotes) -0095 if model.c(i)~=0 -0096 writeField(model, fid, 'c', 'num', i, ' - objective_coefficient', preserveQuotes) -0097 end -0098 writeField(model, fid, 'eccodes', 'txt', i, ' - eccodes', preserveQuotes) -0099 writeField(model, fid, 'rxnReferences', 'txt', i, ' - references', preserveQuotes) -0100 writeField(model, fid, 'subSystems', 'txt', i, ' - subsystem', preserveQuotes) -0101 writeField(model, fid, 'rxnMiriams', 'txt', i, ' - annotation', preserveQuotes) -0102 writeField(model, fid, 'rxnDeltaG', 'num', i, ' - deltaG', preserveQuotes) -0103 writeField(model, fid, 'rxnConfidenceScores', 'num', i, ' - confidence_score', preserveQuotes) -0104 writeField(model, fid, 'rxnNotes', 'txt', i, ' - rxnNotes', preserveQuotes) -0105 end -0106 -0107 %Genes: -0108 fprintf(fid,'- genes:\n'); -0109 for i = 1:length(model.genes) -0110 fprintf(fid,' - !!omap\n'); -0111 writeField(model, fid, 'genes', 'txt', i, ' - id', preserveQuotes) -0112 writeField(model, fid, 'geneShortNames', 'txt', i, ' - name', preserveQuotes) -0113 writeField(model, fid, 'geneMiriams', 'txt', i, ' - annotation', preserveQuotes) -0114 end -0115 -0116 %Compartments: -0117 fprintf(fid,'- compartments: !!omap\n'); -0118 for i = 1:length(model.comps) -0119 writeField(model, fid, 'compNames', 'txt', i, ['- ' model.comps{i}], preserveQuotes) -0120 writeField(model, fid, 'compMiriams', 'txt', i, '- annotation', preserveQuotes) -0121 end -0122 -0123 -0124 %EC-model: -0125 if isfield(model,'ec') -0126 fprintf(fid,'- ec-rxns:\n'); -0127 for i = 1:length(model.ec.rxns) -0128 fprintf(fid,' - !!omap\n'); -0129 writeField(model.ec, fid, 'rxns', 'txt', i, '- id', preserveQuotes) -0130 writeField(model.ec, fid, 'kcat', 'num', i, '- kcat', preserveQuotes) -0131 writeField(model.ec, fid, 'source', 'txt', i, '- source', preserveQuotes) -0132 writeField(model.ec, fid, 'notes', 'txt', i, '- notes', preserveQuotes) -0133 writeField(model.ec, fid, 'eccodes', 'txt', i, '- eccodes', preserveQuotes) -0134 writeField(model.ec, fid, 'rxnEnzMat', 'txt', i, '- enzymes', preserveQuotes) -0135 end -0136 -0137 fprintf(fid,'- ec-enzymes:\n'); -0138 for i = 1:length(model.ec.genes) -0139 fprintf(fid,' - !!omap\n'); -0140 writeField(model.ec, fid, 'genes', 'txt', i, '- genes', preserveQuotes) -0141 writeField(model.ec, fid, 'enzymes', 'txt', i, '- enzymes', preserveQuotes) -0142 writeField(model.ec, fid, 'mw', 'num', i, '- mw', preserveQuotes) -0143 writeField(model.ec, fid, 'sequence', 'txt', i, '- sequence', preserveQuotes) -0144 writeField(model.ec, fid, 'concs', 'num', i, '- concs', preserveQuotes) -0145 end -0146 end -0147 -0148 %Close file: -0149 fclose(fid); +0067 %Insert file header (metadata) +0068 writeMetadata(model,fid); +0069 +0070 %Metabolites: +0071 fprintf(fid,'- metabolites:\n'); +0072 for i = 1:length(model.mets) +0073 fprintf(fid,' - !!omap\n'); +0074 writeField(model, fid, 'mets', 'txt', i, ' - id', preserveQuotes) +0075 writeField(model, fid, 'metNames', 'txt', i, ' - name', preserveQuotes) +0076 writeField(model, fid, 'metComps', 'txt', i, ' - compartment', preserveQuotes) +0077 writeField(model, fid, 'metFormulas', 'txt', i, ' - formula', preserveQuotes) +0078 writeField(model, fid, 'metCharges', 'num', i, ' - charge', preserveQuotes) +0079 writeField(model, fid, 'inchis', 'txt', i, ' - inchis', preserveQuotes) +0080 writeField(model, fid, 'metSmiles', 'txt', i, ' - smiles', preserveQuotes) +0081 writeField(model, fid, 'metMiriams', 'txt', i, ' - annotation', preserveQuotes) +0082 writeField(model, fid, 'metDeltaG', 'num', i, ' - deltaG', preserveQuotes) +0083 writeField(model, fid, 'metNotes', 'txt', i, ' - notes', preserveQuotes) +0084 writeField(model, fid, 'metFrom', 'txt', i, ' - metFrom', preserveQuotes) +0085 end +0086 +0087 %Reactions: +0088 fprintf(fid,'- reactions:\n'); +0089 for i = 1:length(model.rxns) +0090 fprintf(fid,' - !!omap\n'); +0091 writeField(model, fid, 'rxns', 'txt', i, ' - id', preserveQuotes) +0092 writeField(model, fid, 'rxnNames', 'txt', i, ' - name', preserveQuotes) +0093 writeField(model, fid, 'S', 'txt', i, ' - metabolites', preserveQuotes) +0094 writeField(model, fid, 'lb', 'num', i, ' - lower_bound', preserveQuotes) +0095 writeField(model, fid, 'ub', 'num', i, ' - upper_bound', preserveQuotes) +0096 writeField(model, fid, 'grRules', 'txt', i, ' - gene_reaction_rule', preserveQuotes) +0097 writeField(model, fid, 'rxnFrom', 'txt', i, ' - rxnFrom', preserveQuotes) +0098 if model.c(i)~=0 +0099 writeField(model, fid, 'c', 'num', i, ' - objective_coefficient', preserveQuotes) +0100 end +0101 writeField(model, fid, 'eccodes', 'txt', i, ' - eccodes', preserveQuotes) +0102 writeField(model, fid, 'rxnReferences', 'txt', i, ' - references', preserveQuotes) +0103 writeField(model, fid, 'subSystems', 'txt', i, ' - subsystem', preserveQuotes) +0104 writeField(model, fid, 'rxnMiriams', 'txt', i, ' - annotation', preserveQuotes) +0105 writeField(model, fid, 'rxnDeltaG', 'num', i, ' - deltaG', preserveQuotes) +0106 writeField(model, fid, 'rxnConfidenceScores', 'num', i, ' - confidence_score', preserveQuotes) +0107 writeField(model, fid, 'rxnNotes', 'txt', i, ' - rxnNotes', preserveQuotes) +0108 end +0109 +0110 %Genes: +0111 fprintf(fid,'- genes:\n'); +0112 for i = 1:length(model.genes) +0113 fprintf(fid,' - !!omap\n'); +0114 writeField(model, fid, 'genes', 'txt', i, ' - id', preserveQuotes) +0115 writeField(model, fid, 'geneShortNames', 'txt', i, ' - name', preserveQuotes) +0116 writeField(model, fid, 'geneMiriams', 'txt', i, ' - annotation', preserveQuotes) +0117 end +0118 +0119 %Compartments: +0120 fprintf(fid,'- compartments: !!omap\n'); +0121 for i = 1:length(model.comps) +0122 writeField(model, fid, 'compNames', 'txt', i, ['- ' model.comps{i}], preserveQuotes) +0123 writeField(model, fid, 'compMiriams', 'txt', i, '- annotation', preserveQuotes) +0124 end +0125 +0126 +0127 %EC-model: +0128 if isfield(model,'ec') +0129 fprintf(fid,'- ec-rxns:\n'); +0130 for i = 1:length(model.ec.rxns) +0131 fprintf(fid,' - !!omap\n'); +0132 writeField(model.ec, fid, 'rxns', 'txt', i, '- id', preserveQuotes) +0133 writeField(model.ec, fid, 'kcat', 'num', i, '- kcat', preserveQuotes) +0134 writeField(model.ec, fid, 'source', 'txt', i, '- source', preserveQuotes) +0135 writeField(model.ec, fid, 'notes', 'txt', i, '- notes', preserveQuotes) +0136 writeField(model.ec, fid, 'eccodes', 'txt', i, '- eccodes', preserveQuotes) +0137 writeField(model.ec, fid, 'rxnEnzMat', 'txt', i, '- enzymes', preserveQuotes) +0138 end +0139 +0140 fprintf(fid,'- ec-enzymes:\n'); +0141 for i = 1:length(model.ec.genes) +0142 fprintf(fid,' - !!omap\n'); +0143 writeField(model.ec, fid, 'genes', 'txt', i, '- genes', preserveQuotes) +0144 writeField(model.ec, fid, 'enzymes', 'txt', i, '- enzymes', preserveQuotes) +0145 writeField(model.ec, fid, 'mw', 'num', i, '- mw', preserveQuotes) +0146 writeField(model.ec, fid, 'sequence', 'txt', i, '- sequence', preserveQuotes) +0147 writeField(model.ec, fid, 'concs', 'num', i, '- concs', preserveQuotes) +0148 end +0149 end 0150 -0151 end -0152 -0153 function writeField(model,fid,fieldName,type,pos,name,preserveQuotes) -0154 %Writes a new line in the yaml file if the field exists and the field is -0155 %not empty at the correspoinding position. It's recursive for some fields -0156 %(metMiriams, rxnMiriams, and S) -0157 -0158 if isfield(model,fieldName) -0159 if strcmp(fieldName,'metComps') -0160 %metComps: write full name -0161 fieldName = 'comps'; -0162 pos = model.metComps(pos); -0163 end -0164 -0165 field = model.(fieldName); -0166 -0167 if strcmp(fieldName,'metMiriams') -0168 if ~isempty(model.metMiriams{pos}) -0169 fprintf(fid,' %s: !!omap\n',name); -0170 for i=1:size(model.newMetMiriams,2) -0171 %'i' represents the different miriam names, e.g. -0172 %kegg.compound or chebi -0173 if ~isempty(model.newMetMiriams{pos,i}) -0174 %As during the following writeField call the value of -0175 %'i' would be lost, it is temporarily concatenated to -0176 %'name' parameter, which will be edited later -0177 writeField(model, fid, 'newMetMiriams', 'txt', pos, [' - ' model.newMetMiriamNames{i} '_' sprintf('%d',i)], preserveQuotes) -0178 end -0179 end -0180 end -0181 -0182 elseif strcmp(fieldName,'rxnMiriams') -0183 if ~isempty(model.rxnMiriams{pos}) -0184 fprintf(fid,' %s: !!omap\n',name); -0185 for i=1:size(model.newRxnMiriams,2) -0186 if ~isempty(model.newRxnMiriams{pos,i}) -0187 writeField(model, fid, 'newRxnMiriams', 'txt', pos, [' - ' model.newRxnMiriamNames{i} '_' sprintf('%d',i)], preserveQuotes) -0188 end -0189 end -0190 end -0191 -0192 elseif strcmp(fieldName,'geneMiriams') -0193 if ~isempty(model.geneMiriams{pos}) -0194 fprintf(fid,' %s: !!omap\n',name); -0195 for i=1:size(model.newGeneMiriams,2) -0196 if ~isempty(model.newGeneMiriams{pos,i}) -0197 writeField(model, fid, 'newGeneMiriams', 'txt', pos, [' - ' model.newGeneMiriamNames{i} '_' sprintf('%d',i)], preserveQuotes) -0198 end -0199 end -0200 end -0201 -0202 elseif strcmp(fieldName,'compMiriams') -0203 if ~isempty(model.compMiriams{pos}) -0204 fprintf(fid,' %s: !!omap\n',name); -0205 for i=1:size(model.newCompMiriams,2) -0206 if ~isempty(model.newCompMiriams{pos,i}) -0207 writeField(model, fid, 'newCompMiriams', 'txt', pos, [' - ' model.newCompMiriamNames{i} '_' sprintf('%d',i)], preserveQuotes) -0208 end -0209 end -0210 end -0211 -0212 elseif strcmp(fieldName,'S') -0213 %S: create header & write each metabolite in a new line -0214 fprintf(fid,' %s: !!omap\n',name); -0215 if sum(field(:,pos) ~= 0) > 0 -0216 model.mets = model.mets(field(:,pos) ~= 0); -0217 model.coeffs = field(field(:,pos) ~= 0,pos); -0218 %Sort metabolites: -0219 [model.mets,order] = sort(model.mets); -0220 model.coeffs = model.coeffs(order); -0221 for i = 1:length(model.mets) -0222 writeField(model, fid, 'coeffs', 'num', i, [' - ' model.mets{i}], preserveQuotes) -0223 end -0224 end -0225 -0226 elseif strcmp(fieldName,'rxnEnzMat') -0227 %S: create header & write each enzyme in a new line -0228 fprintf(fid,' %s: !!omap\n',name); -0229 if sum(field(pos,:) ~= 0) > 0 -0230 model.enzymes = model.enzymes(field(pos,:) ~= 0); -0231 model.coeffs = field(pos,field(pos,:) ~= 0); -0232 %Sort metabolites: -0233 [model.enzymes,order] = sort(model.enzymes); -0234 model.coeffs = model.coeffs(order); -0235 for i = 1:length(model.enzymes) -0236 writeField(model, fid, 'coeffs', 'num', i, [' - ' model.enzymes{i}], preserveQuotes) -0237 end -0238 end -0239 -0240 elseif sum(strcmp({'subSystems','newMetMiriams','newRxnMiriams','newGeneMiriams','newCompMiriams','eccodes'},fieldName)) > 0 -0241 %eccodes/rxnNotes: if 1 write in 1 line, if more create header and list -0242 if strcmp(fieldName,'subSystems') -0243 list = field{pos}; %subSystems already comes in a cell array -0244 if isempty(list) -0245 return -0246 end -0247 elseif strcmp(fieldName,'newMetMiriams') -0248 index = str2double(regexprep(name,'^.+_','')); -0249 name = regexprep(name,'_\d+$',''); -0250 list = strsplit(model.newMetMiriams{pos,index},'; '); -0251 elseif strcmp(fieldName,'newRxnMiriams') -0252 index = str2double(regexprep(name,'^.+_','')); -0253 name = regexprep(name,'_\d+$',''); -0254 list = strsplit(model.newRxnMiriams{pos,index},'; '); -0255 elseif strcmp(fieldName,'newGeneMiriams') -0256 index = str2double(regexprep(name,'^.+_','')); -0257 name = regexprep(name,'_\d+$',''); -0258 list = strsplit(model.newGeneMiriams{pos,index},'; '); -0259 elseif strcmp(fieldName,'newCompMiriams') -0260 index = str2double(regexprep(name,'^.+_','')); -0261 name = regexprep(name,'_\d+$',''); -0262 list = strsplit(model.newCompMiriams{pos,index},'; '); -0263 elseif ~isempty(field{pos}) -0264 list = strrep(field{pos},' ',''); -0265 list = strsplit(list,';'); -0266 else -0267 return % empty, needs no line in file -0268 end -0269 list=strip(list); -0270 -0271 if length(list) == 1 && ~strcmp(list{1},'') && ~strcmp(fieldName,'subSystems') -0272 if preserveQuotes -0273 list = ['"' list{1} '"']; -0274 end -0275 fprintf(fid,' %s: %s\n',name,list); -0276 elseif ischar(list) && strcmp(fieldName,'subSystems') -0277 if preserveQuotes -0278 list = ['"' list '"']; -0279 end -0280 fprintf(fid,' %s: %s\n',name,list); -0281 elseif length(list) > 1 || strcmp(fieldName,'subSystems') -0282 if preserveQuotes -0283 for j=1:numel(list) -0284 list{j} = ['"' list{j} '"']; -0285 end -0286 end -0287 fprintf(fid,' %s:\n',name); -0288 for i = 1:length(list) -0289 fprintf(fid,'%s - %s\n',regexprep(name,'(^\s*).*','$1'),list{i}); -0290 end -0291 end -0292 -0293 elseif sum(pos) > 0 -0294 %All other fields: -0295 if strcmp(type,'txt') -0296 value = field{pos}; -0297 if preserveQuotes && ~isempty(value) -0298 value = ['"',value,'"']; -0299 end -0300 elseif strcmp(type,'num') -0301 if isnan(field(pos)) -0302 value = []; -0303 else -0304 value = sprintf('%.15g',full(field(pos))); -0305 end -0306 end -0307 if ~isempty(value) -0308 fprintf(fid,' %s: %s\n',name,value); +0151 %Close file: +0152 fclose(fid); +0153 +0154 end +0155 +0156 function writeField(model,fid,fieldName,type,pos,name,preserveQuotes) +0157 %Writes a new line in the yaml file if the field exists and the field is +0158 %not empty at the correspoinding position. It's recursive for some fields +0159 %(metMiriams, rxnMiriams, and S) +0160 +0161 if isfield(model,fieldName) +0162 if strcmp(fieldName,'metComps') +0163 %metComps: write full name +0164 fieldName = 'comps'; +0165 pos = model.metComps(pos); +0166 end +0167 +0168 field = model.(fieldName); +0169 +0170 if strcmp(fieldName,'metMiriams') +0171 if ~isempty(model.metMiriams{pos}) +0172 fprintf(fid,' %s: !!omap\n',name); +0173 for i=1:size(model.newMetMiriams,2) +0174 %'i' represents the different miriam names, e.g. +0175 %kegg.compound or chebi +0176 if ~isempty(model.newMetMiriams{pos,i}) +0177 %As during the following writeField call the value of +0178 %'i' would be lost, it is temporarily concatenated to +0179 %'name' parameter, which will be edited later +0180 writeField(model, fid, 'newMetMiriams', 'txt', pos, [' - ' model.newMetMiriamNames{i} '_' sprintf('%d',i)], preserveQuotes) +0181 end +0182 end +0183 end +0184 +0185 elseif strcmp(fieldName,'rxnMiriams') +0186 if ~isempty(model.rxnMiriams{pos}) +0187 fprintf(fid,' %s: !!omap\n',name); +0188 for i=1:size(model.newRxnMiriams,2) +0189 if ~isempty(model.newRxnMiriams{pos,i}) +0190 writeField(model, fid, 'newRxnMiriams', 'txt', pos, [' - ' model.newRxnMiriamNames{i} '_' sprintf('%d',i)], preserveQuotes) +0191 end +0192 end +0193 end +0194 +0195 elseif strcmp(fieldName,'geneMiriams') +0196 if ~isempty(model.geneMiriams{pos}) +0197 fprintf(fid,' %s: !!omap\n',name); +0198 for i=1:size(model.newGeneMiriams,2) +0199 if ~isempty(model.newGeneMiriams{pos,i}) +0200 writeField(model, fid, 'newGeneMiriams', 'txt', pos, [' - ' model.newGeneMiriamNames{i} '_' sprintf('%d',i)], preserveQuotes) +0201 end +0202 end +0203 end +0204 +0205 elseif strcmp(fieldName,'compMiriams') +0206 if ~isempty(model.compMiriams{pos}) +0207 fprintf(fid,' %s: !!omap\n',name); +0208 for i=1:size(model.newCompMiriams,2) +0209 if ~isempty(model.newCompMiriams{pos,i}) +0210 writeField(model, fid, 'newCompMiriams', 'txt', pos, [' - ' model.newCompMiriamNames{i} '_' sprintf('%d',i)], preserveQuotes) +0211 end +0212 end +0213 end +0214 +0215 elseif strcmp(fieldName,'S') +0216 %S: create header & write each metabolite in a new line +0217 fprintf(fid,' %s: !!omap\n',name); +0218 if sum(field(:,pos) ~= 0) > 0 +0219 model.mets = model.mets(field(:,pos) ~= 0); +0220 model.coeffs = field(field(:,pos) ~= 0,pos); +0221 %Sort metabolites: +0222 [model.mets,order] = sort(model.mets); +0223 model.coeffs = model.coeffs(order); +0224 for i = 1:length(model.mets) +0225 writeField(model, fid, 'coeffs', 'num', i, [' - ' model.mets{i}], preserveQuotes) +0226 end +0227 end +0228 +0229 elseif strcmp(fieldName,'rxnEnzMat') +0230 %S: create header & write each enzyme in a new line +0231 fprintf(fid,' %s: !!omap\n',name); +0232 if sum(field(pos,:) ~= 0) > 0 +0233 model.enzymes = model.enzymes(field(pos,:) ~= 0); +0234 model.coeffs = field(pos,field(pos,:) ~= 0); +0235 %Sort metabolites: +0236 [model.enzymes,order] = sort(model.enzymes); +0237 model.coeffs = model.coeffs(order); +0238 for i = 1:length(model.enzymes) +0239 writeField(model, fid, 'coeffs', 'num', i, [' - ' model.enzymes{i}], preserveQuotes) +0240 end +0241 end +0242 +0243 elseif sum(strcmp({'subSystems','newMetMiriams','newRxnMiriams','newGeneMiriams','newCompMiriams','eccodes'},fieldName)) > 0 +0244 %eccodes/rxnNotes: if 1 write in 1 line, if more create header and list +0245 if strcmp(fieldName,'subSystems') +0246 list = field{pos}; %subSystems already comes in a cell array +0247 if isempty(list) +0248 return +0249 end +0250 elseif strcmp(fieldName,'newMetMiriams') +0251 index = str2double(regexprep(name,'^.+_','')); +0252 name = regexprep(name,'_\d+$',''); +0253 list = strsplit(model.newMetMiriams{pos,index},'; '); +0254 elseif strcmp(fieldName,'newRxnMiriams') +0255 index = str2double(regexprep(name,'^.+_','')); +0256 name = regexprep(name,'_\d+$',''); +0257 list = strsplit(model.newRxnMiriams{pos,index},'; '); +0258 elseif strcmp(fieldName,'newGeneMiriams') +0259 index = str2double(regexprep(name,'^.+_','')); +0260 name = regexprep(name,'_\d+$',''); +0261 list = strsplit(model.newGeneMiriams{pos,index},'; '); +0262 elseif strcmp(fieldName,'newCompMiriams') +0263 index = str2double(regexprep(name,'^.+_','')); +0264 name = regexprep(name,'_\d+$',''); +0265 list = strsplit(model.newCompMiriams{pos,index},'; '); +0266 elseif ~isempty(field{pos}) +0267 list = strrep(field{pos},' ',''); +0268 list = strsplit(list,';'); +0269 else +0270 return % empty, needs no line in file +0271 end +0272 list=strip(list); +0273 +0274 if length(list) == 1 && ~strcmp(list{1},'') && ~strcmp(fieldName,'subSystems') +0275 if preserveQuotes +0276 list = ['"' list{1} '"']; +0277 end +0278 fprintf(fid,' %s: %s\n',name,list); +0279 elseif ischar(list) && strcmp(fieldName,'subSystems') +0280 if preserveQuotes +0281 list = ['"' list '"']; +0282 end +0283 fprintf(fid,' %s: %s\n',name,list); +0284 elseif length(list) > 1 || strcmp(fieldName,'subSystems') +0285 if preserveQuotes +0286 for j=1:numel(list) +0287 list{j} = ['"' list{j} '"']; +0288 end +0289 end +0290 fprintf(fid,' %s:\n',name); +0291 for i = 1:length(list) +0292 fprintf(fid,'%s - %s\n',regexprep(name,'(^\s*).*','$1'),list{i}); +0293 end +0294 end +0295 +0296 elseif sum(pos) > 0 +0297 %All other fields: +0298 if strcmp(type,'txt') +0299 value = field{pos}; +0300 if preserveQuotes && ~isempty(value) +0301 value = ['"',value,'"']; +0302 end +0303 elseif strcmp(type,'num') +0304 if isnan(field(pos)) +0305 value = []; +0306 else +0307 value = sprintf('%.15g',full(field(pos))); +0308 end 0309 end -0310 end -0311 end -0312 end -0313 -0314 function writeMetadata(model,fid) -0315 % Writes model metadata to the yaml file. This information will eventually -0316 % be extracted entirely from the model, but for now, many of the entries -0317 % are hard-coded defaults for HumanGEM. -0318 -0319 fprintf(fid, '- metaData:\n'); -0320 if isfield(model,'id') -0321 fprintf(fid, ' id: "%s"\n', model.id); -0322 else -0323 fprintf(fid, ' id: "blankID"\n'); -0324 end -0325 if isfield(model,'name') -0326 fprintf(fid, ' name: "%s"\n',model.name); -0327 else -0328 fprintf(fid, ' name: "blankName"\n'); -0329 end -0330 if isfield(model,'version') -0331 fprintf(fid, ' version: "%s"\n',model.version); +0310 if ~isempty(value) +0311 fprintf(fid,' %s: %s\n',name,value); +0312 end +0313 end +0314 end +0315 end +0316 +0317 function writeMetadata(model,fid) +0318 % Writes model metadata to the yaml file. This information will eventually +0319 % be extracted entirely from the model, but for now, many of the entries +0320 % are hard-coded defaults for HumanGEM. +0321 +0322 fprintf(fid, '- metaData:\n'); +0323 if isfield(model,'id') +0324 fprintf(fid, ' id: "%s"\n', model.id); +0325 else +0326 fprintf(fid, ' id: "blankID"\n'); +0327 end +0328 if isfield(model,'name') +0329 fprintf(fid, ' name: "%s"\n',model.name); +0330 else +0331 fprintf(fid, ' name: "blankName"\n'); 0332 end -0333 fprintf(fid, ' date: "%s"\n',datestr(now,29)); % 29=YYYY-MM-DD -0334 if isfield(model,'annotation') -0335 if isfield(model.annotation,'defaultLB') -0336 fprintf(fid, ' defaultLB: "%g"\n', model.annotation.defaultLB); -0337 end -0338 if isfield(model.annotation,'defaultUB') -0339 fprintf(fid, ' defaultUB: "%g"\n', model.annotation.defaultUB); +0333 if isfield(model,'version') +0334 fprintf(fid, ' version: "%s"\n',model.version); +0335 end +0336 fprintf(fid, ' date: "%s"\n',datestr(now,29)); % 29=YYYY-MM-DD +0337 if isfield(model,'annotation') +0338 if isfield(model.annotation,'defaultLB') +0339 fprintf(fid, ' defaultLB: "%g"\n', model.annotation.defaultLB); 0340 end -0341 if isfield(model.annotation,'givenName') -0342 fprintf(fid, ' givenName: "%s"\n', model.annotation.givenName); +0341 if isfield(model.annotation,'defaultUB') +0342 fprintf(fid, ' defaultUB: "%g"\n', model.annotation.defaultUB); 0343 end -0344 if isfield(model.annotation,'familyName') -0345 fprintf(fid, ' familyName: "%s"\n', model.annotation.familyName); +0344 if isfield(model.annotation,'givenName') +0345 fprintf(fid, ' givenName: "%s"\n', model.annotation.givenName); 0346 end -0347 if isfield(model.annotation,'authors') -0348 fprintf(fid, ' authors: "%s"\n', model.annotation.authors); +0347 if isfield(model.annotation,'familyName') +0348 fprintf(fid, ' familyName: "%s"\n', model.annotation.familyName); 0349 end -0350 if isfield(model.annotation,'email') -0351 fprintf(fid, ' email: "%s"\n', model.annotation.email); +0350 if isfield(model.annotation,'authors') +0351 fprintf(fid, ' authors: "%s"\n', model.annotation.authors); 0352 end -0353 if isfield(model.annotation,'organization') -0354 fprintf(fid, ' organization: "%s"\n',model.annotation.organization); +0353 if isfield(model.annotation,'email') +0354 fprintf(fid, ' email: "%s"\n', model.annotation.email); 0355 end -0356 if isfield(model.annotation,'taxonomy') -0357 fprintf(fid, ' taxonomy: "%s"\n', model.annotation.taxonomy); +0356 if isfield(model.annotation,'organization') +0357 fprintf(fid, ' organization: "%s"\n',model.annotation.organization); 0358 end -0359 if isfield(model.annotation,'note') -0360 fprintf(fid, ' note: "%s"\n', model.annotation.note); +0359 if isfield(model.annotation,'taxonomy') +0360 fprintf(fid, ' taxonomy: "%s"\n', model.annotation.taxonomy); 0361 end -0362 if isfield(model.annotation,'sourceUrl') -0363 fprintf(fid, ' sourceUrl: "%s"\n', model.annotation.sourceUrl); +0362 if isfield(model.annotation,'note') +0363 fprintf(fid, ' note: "%s"\n', model.annotation.note); 0364 end -0365 end -0366 if isfield(model,'ec') -0367 if model.ec.geckoLight -0368 geckoLight = 'true'; -0369 else -0370 geckoLight = 'false'; -0371 end -0372 fprintf(fid,' geckoLight: "%s"\n',geckoLight); -0373 end -0374 end +0365 if isfield(model.annotation,'sourceUrl') +0366 fprintf(fid, ' sourceUrl: "%s"\n', model.annotation.sourceUrl); +0367 end +0368 end +0369 if isfield(model,'ec') +0370 if model.ec.geckoLight +0371 geckoLight = 'true'; +0372 else +0373 geckoLight = 'false'; +0374 end +0375 fprintf(fid,' geckoLight: "%s"\n',geckoLight); +0376 end +0377 end
    Generated by m2html © 2005
    \ No newline at end of file diff --git a/io/writeYAMLmodel.m b/io/writeYAMLmodel.m index 63e0455e..c2305df1 100644 --- a/io/writeYAMLmodel.m +++ b/io/writeYAMLmodel.m @@ -59,6 +59,9 @@ function writeYAMLmodel(model,fileName,preserveQuotes,sortIds) %Open file: fid = fopen(fileName,'wt'); +if fid == -1 + error(['Cannot write to ' fileName ', does the directory exist?']) +end fprintf(fid,'---\n!!omap\n'); %Insert file header (metadata) From 027b4338d9cb1f9f8add2a41ca05167aefbe7ec6 Mon Sep 17 00:00:00 2001 From: Eduard Kerkhoven Date: Thu, 11 Apr 2024 19:31:26 +0200 Subject: [PATCH 15/23] feat: parallel randomSampling and new progressbar2 --- core/getAllowedBounds.m | 116 +++----- core/handleParallelRAVEN.m | 49 ++++ core/randomSampling.m | 145 +++++----- doc/core/getAllowedBounds.html | 189 ++++++------- doc/core/handleParallelRAVEN.html | 121 +++++++++ doc/core/randomSampling.html | 397 ++++++++++++++-------------- doc/core/simplifyModel.html | 2 +- software/progressbar/ProgressBar2.m | 389 +++++++++++++++++++++++++++ 8 files changed, 953 insertions(+), 455 deletions(-) create mode 100644 core/handleParallelRAVEN.m create mode 100644 doc/core/handleParallelRAVEN.html create mode 100644 software/progressbar/ProgressBar2.m diff --git a/core/getAllowedBounds.m b/core/getAllowedBounds.m index 6510f3f6..13900a63 100755 --- a/core/getAllowedBounds.m +++ b/core/getAllowedBounds.m @@ -3,25 +3,30 @@ % Returns the minimal and maximal fluxes through each reaction. % % Input: -% model a model structure -% rxns either a cell array of reaction IDs, a logical vector with the -% same number of elements as reactions in the model, or a vector -% of reaction indexes (opt, default model.rxns) -% runParallel make use of MATLAB parallel pool to speed up calculations. Not -% beneficial if only a limited number of reactions are simulated. -% (opt, default true) +% model a model structure +% rxns either a cell array of reaction IDs, a logical vector +% with the same number of elements as reactions in the +% model, or a vector of reaction indexes (opt, default +% model.rxns) +% runParallel speed up calculations by parallel processing. This is +% not beneficial if allowed bounds are calculated for +% only a few reactions, as the overhead of parallel +% processing will take longer. It requires MATLAB +% Parallel Computing Toolbox. If this is not installed, +% the calculations will not be parallelized, regardless +% what is indicated as runParallel. (opt, default true) % % Output: -% minFluxes minimal allowed fluxes -% maxFluxes maximal allowed fluxes -% exitFlags exit flags for min/max for each of the reactions. True if it was -% possible to calculate a flux +% minFluxes minimal allowed fluxes +% maxFluxes maximal allowed fluxes +% exitFlags exit flags for min/max for each of the reactions. True +% if it was possible to calculate a flux % % NOTE: In cases where no solution can be calculated, NaN is returned. % % Usage: [minFluxes, maxFluxes, exitFlags] = getAllowedBounds(model, rxns, runParallel) -if nargin<2 +if nargin<2 || isempty(rxns) rxns = 1:numel(model.rxns); elseif ~islogical(rxns) && ~isnumeric(rxns) rxns = convertCharArray(rxns); @@ -30,78 +35,39 @@ if nargin<3 runParallel = true; end -if runParallel - addonList = matlab.addons.installedAddons; - if ~any(strcmpi(addonList.Name,'Parallel Computing Toolbox')) - disp('Cannot find MATLAB Parallel Computing Toolbox, process is not parallelized.') - runParallel = false; - end -end + +[ps, oldPoolAutoCreateSetting] = parallelPoolRAVEN(runParallel); minFluxes = zeros(numel(rxns),1); maxFluxes = zeros(numel(rxns),1); exitFlags = zeros(numel(rxns),2); c = zeros(numel(model.rxns),1); -p = 1; -progressbar('Calculating the minimal and maximal fluxes') -if runParallel - D = parallel.pool.DataQueue; - afterEach(D, @updateProgressParallel); - parfor i = 1:numel(rxns) - tmpModel = model; - tmpModel.c = c; - - % Get minimal flux - tmpModel.c(rxns(i)) = -1; - solMin = solveLP(tmpModel); - if ~isempty(solMin.f) - minFluxes(i) = solMin.x(rxns(i)); - else - minFluxes(i) = NaN; - end +PB = ProgressBar(numel(rxns),'Running getAllowedBounds','cli'); +parfor i = 1:numel(rxns) + count(PB) + tmpModel = model; + tmpModel.c = c; - % Get maximal flux - tmpModel.c(rxns(i)) = 1; - solMax=solveLP(tmpModel); - exitFlags(i,:) = [solMin.stat solMax.stat]; - if ~isempty(solMax.f) - maxFluxes(i) = solMax.x(rxns(i)); - else - maxFluxes(i) = NaN; - end - send(D, i); + % Get minimal flux + tmpModel.c(rxns(i)) = -1; + solMin = solveLP(tmpModel); + if ~isempty(solMin.f) + minFluxes(i) = solMin.x(rxns(i)); + else + minFluxes(i) = NaN; end -else - for i = 1:numel(rxns) - tmpModel = model; - tmpModel.c = c; - % Get minimal flux - tmpModel.c(rxns(i)) = -1; - solMin=solveLP(tmpModel); - if ~isempty(solMin.f) - minFluxes(i) = solMin.x(rxns(i)); - else - minFluxes(i) = NaN; - end - - % Get maximal flux - tmpModel.c(rxns(i)) = 1; - solMax = solveLP(tmpModel); - exitFlags(i,:) = [solMin.stat solMax.stat]; - if ~isempty(solMax.f) - maxFluxes(i) = solMax.x(rxns(i)); - else - maxFluxes(i) = NaN; - end - progressbar(i/numel(rxns)) + % Get maximal flux + tmpModel.c(rxns(i)) = 1; + solMax=solveLP(tmpModel); + exitFlags(i,:) = [solMin.stat solMax.stat]; + if ~isempty(solMax.f) + maxFluxes(i) = solMax.x(rxns(i)); + else + maxFluxes(i) = NaN; end end -progressbar(1) % Make sure it closes - - function updateProgressParallel(~) - progressbar(p/numel(rxns)) - p = p + 1; - end +% Reset original Parallel setting +ps.Pool.AutoCreate = oldPoolAutoCreateSetting; end diff --git a/core/handleParallelRAVEN.m b/core/handleParallelRAVEN.m new file mode 100644 index 00000000..b39680a0 --- /dev/null +++ b/core/handleParallelRAVEN.m @@ -0,0 +1,49 @@ +function [ps, oldPoolAutoCreate] = parallelPoolRAVEN(runParallel) +% handleParallelRAVEN +% Called by RAVEN functions that support parallel processing, to confirm +% whether the MATLAB Parallel Computing Toolbox is installed. +% - The toolbox is installed, and runParallel == true, ==> a parallel +% pool is started. +% - The toolbox is installed, but runParallel == false, ==> the auto- +% creation of a parallel pool is disabled, to prevent "parfor" in +% the target function to start a pool anyway. +% - The toolbox is not installed, and runParallel == true, ==> a warning +% is displayed that parallel computer is not possible. +% - The toolbox is not installed, and runParallel == false, ==> the +% target runs as intended, as "parfor" will automatically run in serial +% mode instead. +% +% Input: +% runParallel logical, whether the target function (which calls +% parallelPoolRAVEN) should be run in parallel (opt, +% default true) +% +% Output: +% ps parallel settings structure that will be used by +% the target function +% oldPoolAutoCreate logical, to reset the original ps.Pool.AutoCreate +% setting once the target function has finished +% +% Use: [ps, oldPoolAutoCreate] = parallelPoolRAVEN(runParallel) + +addonList = matlab.addons.installedAddons; +ps = []; oldPoolAutoCreate = []; +if ~any(strcmpi(addonList.Name,'Parallel Computing Toolbox')) + if runParallel % User wants parallel, but will not be possible + disp('Cannot find MATLAB Parallel Computing Toolbox, process is not parallelized.') + end +else + if ~runParallel % User has Parallel toolbox, but does not want pool to start. + % If pool is already running, then it will use the max workers + % anyway, but this is probably okay. + ps = parallel.Settings; + oldPoolAutoCreate = ps.Pool.AutoCreate; + ps.Pool.AutoCreate = false; + else + pool = gcp('nocreate'); + if isempty(pool) + parpool; + end + end +end +end \ No newline at end of file diff --git a/core/randomSampling.m b/core/randomSampling.m index ec6b5410..1edb9714 100755 --- a/core/randomSampling.m +++ b/core/randomSampling.m @@ -1,7 +1,9 @@ -function [solutions, goodRxns]=randomSampling(model,nSamples,replaceBoundsWithInf,supressErrors,showProgress,goodRxns,minFlux) +function [solutions, goodRxns]=randomSampling(model,nSamples,replaceBoundsWithInf,supressErrors,runParallel,goodRxns,minFlux) % randomSampling -% Returns a number of random solutions +% Performs random sampling of the solution space, as described in Bordel +% et al. (2010) PLOS Compt Biol (doi:10.1371/journal.pcbi.1000859). % +% Input: % model a model structure % nSamples the number of solutions to return % (opt, default 1000) @@ -19,9 +21,11 @@ % as unlimited glucose uptake) or too strict % (such as too many and too narrow constraints) % (opt, default false) -% showProgress if true, it will display in the command window -% how many iterations have been done (opt, default -% false) +% runParallel speed up calculations by parallel processing. +% Requires MATLAB Parallel Computing Toolbox. If +% this is not installed, the calculations will +% not be parallelized, regardless what is +% indicated as runParallel. (opt, default true) % goodRxns double vector of indexes of those reactions % that are not involved in loops and can be used % as random objective functions, as generated by @@ -34,6 +38,8 @@ % large number of samples are taken, but this is % not always the case (opt, default false) % +% +% Output: % solutions matrix with the solutions % goodRxns double vector of indexes of those reactions % that are not involved in loops and can be used @@ -43,25 +49,27 @@ % random set of three reactions. For reversible reactions it randomly % chooses between maximizing and minimizing. % -% Usage: solutions=randomSampling(model,nSamples,replaceBoundsWithInf,supressErrors,showProgress,goodRxns,minFlux) +% Usage: solutions=randomSampling(model,nSamples,replaceBoundsWithInf,supressErrors,runParallel,goodRxns,minFlux) -if nargin<2 +if nargin<2 | isempty(nSamples) nSamples=1000; end -if nargin<3 +if nargin<3 | isempty(replaceBoundsWithInf) replaceBoundsWithInf=true; end -if nargin<4 +if nargin<4 | isempty(supressErrors) supressErrors=false; end -if nargin<5 - showProgress=false; +if nargin<5 | isempty(runParallel) + runParallel=true; end -if nargin<7 +if nargin<7 | isempty(minFlux) minFlux=false; end -nRxns=2; %Number of reactions in the objective function in each iteration +[ps, oldPoolAutoCreateSetting] = parallelPoolRAVEN(runParallel); + +nObjRxns=2; %Number of reactions in the objective function in each iteration %Simplify the model to speed stuff up a little. Keep original mapping originalRxns=model.rxns; @@ -86,87 +94,78 @@ end [~,hsSol]=solveLP(model); +nRxns = numel(model.rxns); %Reactions which can be involved in loops should not be optimized for. %Check which reactions reach an arbitary high upper bound if nargin<6 || isempty(goodRxns) - goodRxns=true(numel(model.rxns),1); - if showProgress - fprintf('Prepare goodRxns list of reactions not involved in loops... 0%% complete'); - end - for i=1:numel(model.rxns) - if showProgress && rem(i,100) == 0 - progress=num2str(floor(100*i/numel(model.rxns))); - progress=pad(progress,3,'left'); - fprintf('\b\b\b\b\b\b\b\b\b\b\b\b\b%s%% complete',progress); - end - if goodRxns(i)==true - testModel=setParam(model,'eq',model.rxns(i),1000); - sol=solveLP(testModel,0,[],hsSol); - if ~isempty(sol.f) - goodRxns(abs(sol.x)>999)=false; - else - %If the reaction is reversible, also check in that direction - if model.rev(i) - testModel=setParam(model,'eq',model.rxns(i),-1000); - sol=solveLP(testModel,0,[],hsSol); - if ~isempty(sol.f) - goodRxns(abs(sol.x)>999)=false; - end + goodRxns = true(numel(model.rxns),numel(model.rxns)); + goodRxns = num2cell(goodRxns,1); + PB = ProgressBar2(nRxns,'Prepare goodRxns not involved in loops','cli'); + parfor (i=1:nRxns) + testModel=setParam(model,'eq',model.rxns(i),1000); + sol=solveLP(testModel,0,[],hsSol); + if ~isempty(sol.f) + notGood = abs(sol.x)>999; + goodRxns{i}(notGood)=false; + else + %If the reaction is reversible, also check in that direction + if model.rev(i) + testModel=setParam(model,'eq',model.rxns(i),-1000); + sol=solveLP(testModel,0,[],hsSol); + if ~isempty(sol.f) + notGood = abs(sol.x)>999; + goodRxns{i}(notGood)=false; end end end + count(PB); end - if showProgress - fprintf('\b\b\b\b\b\b\b\b\b\b\b\b\b100%% complete\n'); - end - goodRxns=find(goodRxns); + goodRxns = cell2mat(goodRxns); + goodRxns = find(prod(goodRxns,2)); end %Reserve space for a solution matrix -sols=zeros(numel(model.rxns),nSamples); +sols = zeros(numel(model.rxns),nSamples); +sols = num2cell(sols,1); %Main loop -counter=1; -badSolutions=0; -if showProgress - itrStr=num2str(nSamples); - fprintf('Performing random sampling: ready with%s0/%s iterations',repmat(' ',1,length(itrStr)),itrStr); -end -while counter<=nSamples - if showProgress && rem(counter,100) == 0 - fprintf([repmat('\b',1,length(itrStr)*2) '\b\b\b\b\b\b\b\b\b\b\b\b%s/%s iterations'],pad(num2str(counter),length(itrStr),'left'),itrStr); - end - rxns=randsample(numel(goodRxns),nRxns); - model.c=zeros(numel(model.rxns),1); - multipliers=randsample([-1 1],nRxns,true); - multipliers(model.rev(goodRxns(rxns))==0)=1; - model.c(goodRxns(rxns))=rand(nRxns,1).*multipliers; - if true(minFlux) - sol=solveLP(model,1,[],hsSol); - else - sol=solveLP(model,0,[],hsSol); - end - if any(sol.x) && abs(sol.f)>10^-8 - sols(:,counter)=sol.x; - counter=counter+1; - badSolutions=0; - else - badSolutions=badSolutions+1; - %If it only finds bad solutions then throw an error. - if badSolutions==100 && supressErrors==false - error('The program is having problems finding non-zero solutions (ignoring reactions that might be involved in loops). Review the constraints on your model. Set supressErrors to true to ignore this error'); +PB = ProgressBar2(nSamples,'Performing random sampling','cli'); +parfor i=1:nSamples + badSolutions = 1; + tmpModel = model; + while lt(0,badSolutions) + rxns = randsample(numel(goodRxns),nObjRxns); + tmpModel.c = zeros(numel(tmpModel.rxns),1); + multipliers = randsample([-1 1],nObjRxns,true); + multipliers(tmpModel.rev(goodRxns(rxns))==0) = 1; + tmpModel.c(goodRxns(rxns)) = rand(nObjRxns,1).*multipliers; + if true(minFlux) + sol=solveLP(tmpModel,1,[],hsSol); + else + sol=solveLP(tmpModel,0,[],hsSol); + end + if any(sol.x) && abs(sol.f)>10^-8 + sols{i} = sol.x; + badSolutions = 0; + else + badSolutions = badSolutions+1; + %If it only finds bad solutions then throw an error. + if badSolutions == 100 && supressErrors==false + error('The program is having problems finding non-zero solutions (ignoring reactions that might be involved in loops). Review the constraints on your model. Set supressErrors to true to ignore this error'); + end end end -end -if showProgress - fprintf('\n') + count(PB); end %Map to original model +sols = cell2mat(sols); [~, I]=ismember(model.rxns,originalRxns); solutions=zeros(numel(originalRxns),nSamples); solutions(I,:)=sols; solutions=sparse(solutions); +% Reset original Parallel setting +ps.Pool.AutoCreate = oldPoolAutoCreateSetting; end %To use instead of the normal Matlab randsample function. This is in order diff --git a/doc/core/getAllowedBounds.html b/doc/core/getAllowedBounds.html index 351227f4..953ddfff 100644 --- a/doc/core/getAllowedBounds.html +++ b/doc/core/getAllowedBounds.html @@ -31,19 +31,24 @@

    DESCRIPTION ^CROSS-REFERENCE INFORMATION ^
 <li><a href=simplifyModel simplifyModel -

    SUBFUNCTIONS ^

    - +

    SOURCE CODE ^

    0001 function [minFluxes, maxFluxes, exitFlags]=getAllowedBounds(model,rxns,runParallel)
    @@ -69,108 +72,74 @@ 

    SOURCE CODE ^% Returns the minimal and maximal fluxes through each reaction. 0004 % 0005 % Input: -0006 % model a model structure -0007 % rxns either a cell array of reaction IDs, a logical vector with the -0008 % same number of elements as reactions in the model, or a vector -0009 % of reaction indexes (opt, default model.rxns) -0010 % runParallel make use of MATLAB parallel pool to speed up calculations. Not -0011 % beneficial if only a limited number of reactions are simulated. -0012 % (opt, default true) -0013 % -0014 % Output: -0015 % minFluxes minimal allowed fluxes -0016 % maxFluxes maximal allowed fluxes -0017 % exitFlags exit flags for min/max for each of the reactions. True if it was -0018 % possible to calculate a flux -0019 % -0020 % NOTE: In cases where no solution can be calculated, NaN is returned. -0021 % -0022 % Usage: [minFluxes, maxFluxes, exitFlags] = getAllowedBounds(model, rxns, runParallel) -0023 -0024 if nargin<2 -0025 rxns = 1:numel(model.rxns); -0026 elseif ~islogical(rxns) && ~isnumeric(rxns) -0027 rxns = convertCharArray(rxns); -0028 rxns = getIndexes(model,rxns, 'rxns'); -0029 end -0030 if nargin<3 -0031 runParallel = true; -0032 end -0033 if runParallel -0034 addonList = matlab.addons.installedAddons; -0035 if ~any(strcmpi(addonList.Name,'Parallel Computing Toolbox')) -0036 disp('Cannot find MATLAB Parallel Computing Toolbox, process is not parallelized.') -0037 runParallel = false; -0038 end -0039 end +0006 % model a model structure +0007 % rxns either a cell array of reaction IDs, a logical vector +0008 % with the same number of elements as reactions in the +0009 % model, or a vector of reaction indexes (opt, default +0010 % model.rxns) +0011 % runParallel speed up calculations by parallel processing. This is +0012 % not beneficial if allowed bounds are calculated for +0013 % only a few reactions, as the overhead of parallel +0014 % processing will take longer. It requires MATLAB +0015 % Parallel Computing Toolbox. If this is not installed, +0016 % the calculations will not be parallelized, regardless +0017 % what is indicated as runParallel. (opt, default true) +0018 % +0019 % Output: +0020 % minFluxes minimal allowed fluxes +0021 % maxFluxes maximal allowed fluxes +0022 % exitFlags exit flags for min/max for each of the reactions. True +0023 % if it was possible to calculate a flux +0024 % +0025 % NOTE: In cases where no solution can be calculated, NaN is returned. +0026 % +0027 % Usage: [minFluxes, maxFluxes, exitFlags] = getAllowedBounds(model, rxns, runParallel) +0028 +0029 if nargin<2 || isempty(rxns) +0030 rxns = 1:numel(model.rxns); +0031 elseif ~islogical(rxns) && ~isnumeric(rxns) +0032 rxns = convertCharArray(rxns); +0033 rxns = getIndexes(model,rxns, 'rxns'); +0034 end +0035 if nargin<3 +0036 runParallel = true; +0037 end +0038 +0039 [ps, oldPoolAutoCreateSetting] = parallelPoolRAVEN(runParallel); 0040 0041 minFluxes = zeros(numel(rxns),1); 0042 maxFluxes = zeros(numel(rxns),1); 0043 exitFlags = zeros(numel(rxns),2); 0044 c = zeros(numel(model.rxns),1); 0045 -0046 p = 1; -0047 progressbar('Calculating the minimal and maximal fluxes') -0048 if runParallel -0049 D = parallel.pool.DataQueue; -0050 afterEach(D, @updateProgressParallel); -0051 parfor i = 1:numel(rxns) -0052 tmpModel = model; -0053 tmpModel.c = c; -0054 -0055 % Get minimal flux -0056 tmpModel.c(rxns(i)) = -1; -0057 solMin = solveLP(tmpModel); -0058 if ~isempty(solMin.f) -0059 minFluxes(i) = solMin.x(rxns(i)); -0060 else -0061 minFluxes(i) = NaN; -0062 end -0063 -0064 % Get maximal flux -0065 tmpModel.c(rxns(i)) = 1; -0066 solMax=solveLP(tmpModel); -0067 exitFlags(i,:) = [solMin.stat solMax.stat]; -0068 if ~isempty(solMax.f) -0069 maxFluxes(i) = solMax.x(rxns(i)); -0070 else -0071 maxFluxes(i) = NaN; -0072 end -0073 send(D, i); -0074 end -0075 else -0076 for i = 1:numel(rxns) -0077 tmpModel = model; -0078 tmpModel.c = c; -0079 -0080 % Get minimal flux -0081 tmpModel.c(rxns(i)) = -1; -0082 solMin=solveLP(tmpModel); -0083 if ~isempty(solMin.f) -0084 minFluxes(i) = solMin.x(rxns(i)); -0085 else -0086 minFluxes(i) = NaN; -0087 end -0088 -0089 % Get maximal flux -0090 tmpModel.c(rxns(i)) = 1; -0091 solMax = solveLP(tmpModel); -0092 exitFlags(i,:) = [solMin.stat solMax.stat]; -0093 if ~isempty(solMax.f) -0094 maxFluxes(i) = solMax.x(rxns(i)); -0095 else -0096 maxFluxes(i) = NaN; -0097 end -0098 progressbar(i/numel(rxns)) -0099 end -0100 end -0101 progressbar(1) % Make sure it closes -0102 -0103 function updateProgressParallel(~) -0104 progressbar(p/numel(rxns)) -0105 p = p + 1; -0106 end -0107 end

    +0046 PB = ProgressBar(numel(rxns),'Running getAllowedBounds','cli'); +0047 parfor i = 1:numel(rxns) +0048 count(PB) +0049 tmpModel = model; +0050 tmpModel.c = c; +0051 +0052 % Get minimal flux +0053 tmpModel.c(rxns(i)) = -1; +0054 solMin = solveLP(tmpModel); +0055 if ~isempty(solMin.f) +0056 minFluxes(i) = solMin.x(rxns(i)); +0057 else +0058 minFluxes(i) = NaN; +0059 end +0060 +0061 % Get maximal flux +0062 tmpModel.c(rxns(i)) = 1; +0063 solMax=solveLP(tmpModel); +0064 exitFlags(i,:) = [solMin.stat solMax.stat]; +0065 if ~isempty(solMax.f) +0066 maxFluxes(i) = solMax.x(rxns(i)); +0067 else +0068 maxFluxes(i) = NaN; +0069 end +0070 end +0071 % Reset original Parallel setting +0072 ps.Pool.AutoCreate = oldPoolAutoCreateSetting; +0073 end
    Generated by m2html © 2005
    \ No newline at end of file diff --git a/doc/core/handleParallelRAVEN.html b/doc/core/handleParallelRAVEN.html new file mode 100644 index 00000000..4c0128a1 --- /dev/null +++ b/doc/core/handleParallelRAVEN.html @@ -0,0 +1,121 @@ + + + + Description of handleParallelRAVEN + + + + + + + + + +
    Home > core > handleParallelRAVEN.m
    + + + +

    handleParallelRAVEN +

    + +

    PURPOSE ^

    +
    handleParallelRAVEN
    + +

    SYNOPSIS ^

    +
    function [ps, oldPoolAutoCreate] = parallelPoolRAVEN(runParallel)
    + +

    DESCRIPTION ^

    +
     handleParallelRAVEN
    +   Called by RAVEN functions that support parallel processing, to confirm
    +   whether the MATLAB Parallel Computing Toolbox is installed.
    +   - The toolbox is installed, and runParallel == true, ==> a parallel
    +     pool is started.
    +   - The toolbox is installed, but runParallel == false, ==> the auto-
    +     creation of a parallel pool is disabled, to prevent "parfor" in
    +     the target function to start a pool anyway.
    +   - The toolbox is not installed, and runParallel == true, ==> a warning
    +     is displayed that parallel computer is not possible.
    +   - The toolbox is not installed, and runParallel == false, ==> the
    +     target runs as intended, as "parfor" will automatically run in serial
    +     mode instead.
    +
    + Input:
    +   runParallel         logical, whether the target function (which calls
    +                       parallelPoolRAVEN) should be run in parallel (opt,
    +                       default true)
    +
    + Output:
    +   ps                  parallel settings structure that will be used by
    +                       the target function    
    +   oldPoolAutoCreate   logical, to reset the original ps.Pool.AutoCreate
    +                       setting once the target function has finished
    +
    + Use: [ps, oldPoolAutoCreate] = parallelPoolRAVEN(runParallel)
    + + +

    CROSS-REFERENCE INFORMATION ^

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

    SOURCE CODE ^

    +
    0001 function [ps, oldPoolAutoCreate] = parallelPoolRAVEN(runParallel)
    +0002 % handleParallelRAVEN
    +0003 %   Called by RAVEN functions that support parallel processing, to confirm
    +0004 %   whether the MATLAB Parallel Computing Toolbox is installed.
    +0005 %   - The toolbox is installed, and runParallel == true, ==> a parallel
    +0006 %     pool is started.
    +0007 %   - The toolbox is installed, but runParallel == false, ==> the auto-
    +0008 %     creation of a parallel pool is disabled, to prevent "parfor" in
    +0009 %     the target function to start a pool anyway.
    +0010 %   - The toolbox is not installed, and runParallel == true, ==> a warning
    +0011 %     is displayed that parallel computer is not possible.
    +0012 %   - The toolbox is not installed, and runParallel == false, ==> the
    +0013 %     target runs as intended, as "parfor" will automatically run in serial
    +0014 %     mode instead.
    +0015 %
    +0016 % Input:
    +0017 %   runParallel         logical, whether the target function (which calls
    +0018 %                       parallelPoolRAVEN) should be run in parallel (opt,
    +0019 %                       default true)
    +0020 %
    +0021 % Output:
    +0022 %   ps                  parallel settings structure that will be used by
    +0023 %                       the target function
    +0024 %   oldPoolAutoCreate   logical, to reset the original ps.Pool.AutoCreate
    +0025 %                       setting once the target function has finished
    +0026 %
    +0027 % Use: [ps, oldPoolAutoCreate] = parallelPoolRAVEN(runParallel)
    +0028 
    +0029 addonList = matlab.addons.installedAddons;
    +0030 ps = []; oldPoolAutoCreate = [];
    +0031 if ~any(strcmpi(addonList.Name,'Parallel Computing Toolbox'))
    +0032     if runParallel % User wants parallel, but will not be possible
    +0033         disp('Cannot find MATLAB Parallel Computing Toolbox, process is not parallelized.')
    +0034     end
    +0035 else
    +0036     if ~runParallel % User has Parallel toolbox, but does not want pool to start.
    +0037         % If pool is already running, then it will use the max workers
    +0038         % anyway, but this is probably okay.
    +0039         ps = parallel.Settings;
    +0040         oldPoolAutoCreate = ps.Pool.AutoCreate;
    +0041         ps.Pool.AutoCreate = false;
    +0042     else
    +0043         pool = gcp('nocreate');
    +0044         if isempty(pool)
    +0045             parpool;
    +0046         end
    +0047     end
    +0048 end
    +0049 end
    +
    Generated by m2html © 2005
    + + \ No newline at end of file diff --git a/doc/core/randomSampling.html b/doc/core/randomSampling.html index 0d4bb78d..be0fa5ff 100644 --- a/doc/core/randomSampling.html +++ b/doc/core/randomSampling.html @@ -24,12 +24,14 @@

    PURPOSE ^randomSampling

    SYNOPSIS ^

    -
    function [solutions, goodRxns]=randomSampling(model,nSamples,replaceBoundsWithInf,supressErrors,showProgress,goodRxns,minFlux)
    +
    function [solutions, goodRxns]=randomSampling(model,nSamples,replaceBoundsWithInf,supressErrors,runParallel,goodRxns,minFlux)

    DESCRIPTION ^

     randomSampling
    -   Returns a number of random solutions
    +   Performs random sampling of the solution space, as described in Bordel
    +   et al. (2010) PLOS Compt Biol (doi:10.1371/journal.pcbi.1000859).
     
    + Input:
        model                   a model structure
        nSamples                the number of solutions to return
                                (opt, default 1000)
    @@ -47,9 +49,11 @@ 

    DESCRIPTION ^DESCRIPTION ^DESCRIPTION ^CROSS-REFERENCE INFORMATION ^

    @@ -88,202 +94,201 @@

    SUBFUNCTIONS ^function I=randsample(n,k,replacement)

    SOURCE CODE ^

    -
    0001 function [solutions, goodRxns]=randomSampling(model,nSamples,replaceBoundsWithInf,supressErrors,showProgress,goodRxns,minFlux)
    +
    0001 function [solutions, goodRxns]=randomSampling(model,nSamples,replaceBoundsWithInf,supressErrors,runParallel,goodRxns,minFlux)
     0002 % randomSampling
    -0003 %   Returns a number of random solutions
    -0004 %
    -0005 %   model                   a model structure
    -0006 %   nSamples                the number of solutions to return
    -0007 %                           (opt, default 1000)
    -0008 %   replaceBoundsWithInf    replace the largest upper bounds with Inf and
    -0009 %                           the smallest lower bounds with -Inf. This is
    -0010 %                           needed in order to get solutions without loops
    -0011 %                           if your model has for example 1000/-1000 as
    -0012 %                           arbitary large bounds. If your model only has
    -0013 %                           "biologically relevant" bounds, then set this
    -0014 %                           to false (opt, default true)
    -0015 %   supressErrors           the program will halt if it has problems
    -0016 %                           finding non-zero solutions which are not
    -0017 %                           involved in loops. This could be because the
    -0018 %                           constraints on the model are too relaxed (such
    -0019 %                           as unlimited glucose uptake) or too strict
    -0020 %                           (such as too many and too narrow constraints)
    -0021 %                           (opt, default false)
    -0022 %   showProgress            if true, it will display in the command window
    -0023 %                           how many iterations have been done (opt, default
    -0024 %                           false)
    -0025 %   goodRxns                double vector of indexes of those reactions
    -0026 %                           that are not involved in loops and can be used
    -0027 %                           as random objective functions, as generated by
    -0028 %                           a previous run of randomSampling on the same
    -0029 %                           model (opt, default empty)
    -0030 %   minFlux                 determines if a second optimization should be
    -0031 %                           performed for each random sample, to minimize
    -0032 %                           the number of fluxes and thereby preventing
    -0033 %                           loops. Typically, loops are averaged out when a
    -0034 %                           large number of samples are taken, but this is
    -0035 %                           not always the case (opt, default false)
    -0036 %
    -0037 %   solutions               matrix with the solutions
    -0038 %   goodRxns                double vector of indexes of those reactions
    -0039 %                           that are not involved in loops and can be used
    -0040 %                           as random objective functions
    +0003 %   Performs random sampling of the solution space, as described in Bordel
    +0004 %   et al. (2010) PLOS Compt Biol (doi:10.1371/journal.pcbi.1000859).
    +0005 %
    +0006 % Input:
    +0007 %   model                   a model structure
    +0008 %   nSamples                the number of solutions to return
    +0009 %                           (opt, default 1000)
    +0010 %   replaceBoundsWithInf    replace the largest upper bounds with Inf and
    +0011 %                           the smallest lower bounds with -Inf. This is
    +0012 %                           needed in order to get solutions without loops
    +0013 %                           if your model has for example 1000/-1000 as
    +0014 %                           arbitary large bounds. If your model only has
    +0015 %                           "biologically relevant" bounds, then set this
    +0016 %                           to false (opt, default true)
    +0017 %   supressErrors           the program will halt if it has problems
    +0018 %                           finding non-zero solutions which are not
    +0019 %                           involved in loops. This could be because the
    +0020 %                           constraints on the model are too relaxed (such
    +0021 %                           as unlimited glucose uptake) or too strict
    +0022 %                           (such as too many and too narrow constraints)
    +0023 %                           (opt, default false)
    +0024 %   runParallel             speed up calculations by parallel processing.
    +0025 %                           Requires MATLAB Parallel Computing Toolbox. If
    +0026 %                           this is not installed, the calculations will
    +0027 %                           not be parallelized, regardless what is
    +0028 %                           indicated as runParallel. (opt, default true)
    +0029 %   goodRxns                double vector of indexes of those reactions
    +0030 %                           that are not involved in loops and can be used
    +0031 %                           as random objective functions, as generated by
    +0032 %                           a previous run of randomSampling on the same
    +0033 %                           model (opt, default empty)
    +0034 %   minFlux                 determines if a second optimization should be
    +0035 %                           performed for each random sample, to minimize
    +0036 %                           the number of fluxes and thereby preventing
    +0037 %                           loops. Typically, loops are averaged out when a
    +0038 %                           large number of samples are taken, but this is
    +0039 %                           not always the case (opt, default false)
    +0040 %
     0041 %
    -0042 %   The solutions are generated by maximizing (with random weights) for a
    -0043 %   random set of three reactions. For reversible reactions it randomly
    -0044 %   chooses between maximizing and minimizing.
    -0045 %
    -0046 %   Usage: solutions=randomSampling(model,nSamples,replaceBoundsWithInf,supressErrors,showProgress,goodRxns,minFlux)
    -0047 
    -0048 if nargin<2
    -0049     nSamples=1000;
    -0050 end
    -0051 if nargin<3
    -0052     replaceBoundsWithInf=true;
    -0053 end
    -0054 if nargin<4
    -0055     supressErrors=false;
    +0042 % Output:
    +0043 %   solutions               matrix with the solutions
    +0044 %   goodRxns                double vector of indexes of those reactions
    +0045 %                           that are not involved in loops and can be used
    +0046 %                           as random objective functions
    +0047 %
    +0048 %   The solutions are generated by maximizing (with random weights) for a
    +0049 %   random set of three reactions. For reversible reactions it randomly
    +0050 %   chooses between maximizing and minimizing.
    +0051 %
    +0052 %   Usage: solutions=randomSampling(model,nSamples,replaceBoundsWithInf,supressErrors,runParallel,goodRxns,minFlux)
    +0053 
    +0054 if nargin<2 | isempty(nSamples)
    +0055     nSamples=1000;
     0056 end
    -0057 if nargin<5
    -0058     showProgress=false;
    +0057 if nargin<3 | isempty(replaceBoundsWithInf)
    +0058     replaceBoundsWithInf=true;
     0059 end
    -0060 if nargin<7
    -0061     minFlux=false;
    +0060 if nargin<4 | isempty(supressErrors)
    +0061     supressErrors=false;
     0062 end
    -0063 
    -0064 nRxns=2; %Number of reactions in the objective function in each iteration
    -0065 
    -0066 %Simplify the model to speed stuff up a little. Keep original mapping
    -0067 originalRxns=model.rxns;
    -0068 model=simplifyModel(model,false,false,true,true);
    +0063 if nargin<5 | isempty(runParallel)
    +0064     runParallel=true;
    +0065 end
    +0066 if nargin<7 | isempty(minFlux)
    +0067     minFlux=false;
    +0068 end
     0069 
    -0070 %Then change the bounds to +/- Inf. This is needed in order to not have
    -0071 %loops in the solutions
    -0072 if replaceBoundsWithInf==true
    -0073     model.ub(model.ub==max(model.ub))=Inf;
    -0074     if min(model.lb)<0 % Only negative lower bounds should be set to -Inf
    -0075         model.lb(model.lb==min(model.lb))=-Inf;
    -0076     end
    -0077 end
    -0078 
    -0079 %Check that the model is feasible given the constraints
    -0080 [sol,~]=solveLP(model);
    -0081 if isempty(sol.x)
    -0082     EM='The model has no feasible solution, likely due to incompatible constraints';
    -0083     dispEM(EM);
    -0084 elseif sol.f==0 && showProgress
    -0085     warning('The model objective function cannot reach a non-zero value. This might be intended, so randomSampling will continue, but this could indicate problems with your model')
    -0086 end
    -0087 
    -0088 [~,hsSol]=solveLP(model);
    -0089 %Reactions which can be involved in loops should not be optimized for.
    -0090 %Check which reactions reach an arbitary high upper bound
    -0091 if nargin<6 || isempty(goodRxns)
    -0092     goodRxns=true(numel(model.rxns),1);
    -0093     if showProgress
    -0094         fprintf('Prepare goodRxns list of reactions not involved in loops...   0%% complete');
    -0095     end
    -0096     for i=1:numel(model.rxns)
    -0097         if showProgress && rem(i,100) == 0
    -0098             progress=num2str(floor(100*i/numel(model.rxns)));
    -0099             progress=pad(progress,3,'left');
    -0100             fprintf('\b\b\b\b\b\b\b\b\b\b\b\b\b%s%% complete',progress);
    -0101         end
    -0102         if goodRxns(i)==true
    -0103             testModel=setParam(model,'eq',model.rxns(i),1000);
    -0104             sol=solveLP(testModel,0,[],hsSol);
    -0105             if ~isempty(sol.f)
    -0106                 goodRxns(abs(sol.x)>999)=false;
    -0107             else
    -0108                 %If the reaction is reversible, also check in that direction
    -0109                 if model.rev(i)
    -0110                     testModel=setParam(model,'eq',model.rxns(i),-1000);
    -0111                     sol=solveLP(testModel,0,[],hsSol);
    -0112                     if ~isempty(sol.f)
    -0113                         goodRxns(abs(sol.x)>999)=false;
    -0114                     end
    -0115                 end
    -0116             end
    -0117         end
    -0118     end
    -0119     if showProgress
    -0120         fprintf('\b\b\b\b\b\b\b\b\b\b\b\b\b100%% complete\n');
    -0121     end
    -0122     goodRxns=find(goodRxns);
    -0123 end
    -0124 
    -0125 %Reserve space for a solution matrix
    -0126 sols=zeros(numel(model.rxns),nSamples);
    -0127 
    -0128 %Main loop
    -0129 counter=1;
    -0130 badSolutions=0;
    -0131 if showProgress
    -0132     itrStr=num2str(nSamples);
    -0133     fprintf('Performing random sampling: ready with%s0/%s iterations',repmat(' ',1,length(itrStr)),itrStr);
    -0134 end
    -0135 while counter<=nSamples
    -0136     if showProgress && rem(counter,100) == 0
    -0137         fprintf([repmat('\b',1,length(itrStr)*2) '\b\b\b\b\b\b\b\b\b\b\b\b%s/%s iterations'],pad(num2str(counter),length(itrStr),'left'),itrStr);
    -0138     end
    -0139     rxns=randsample(numel(goodRxns),nRxns);
    -0140     model.c=zeros(numel(model.rxns),1);
    -0141     multipliers=randsample([-1 1],nRxns,true);
    -0142     multipliers(model.rev(goodRxns(rxns))==0)=1;
    -0143     model.c(goodRxns(rxns))=rand(nRxns,1).*multipliers;
    -0144     if true(minFlux)
    -0145         sol=solveLP(model,1,[],hsSol);
    -0146     else
    -0147         sol=solveLP(model,0,[],hsSol);
    -0148     end
    -0149     if any(sol.x) && abs(sol.f)>10^-8
    -0150         sols(:,counter)=sol.x;
    -0151         counter=counter+1;
    -0152         badSolutions=0;
    -0153     else
    -0154         badSolutions=badSolutions+1;
    -0155         %If it only finds bad solutions then throw an error.
    -0156         if badSolutions==100 && supressErrors==false
    -0157             error('The program is having problems finding non-zero solutions (ignoring reactions that might be involved in loops). Review the constraints on your model. Set supressErrors to true to ignore this error');
    -0158         end
    -0159     end
    -0160 end
    -0161 if showProgress
    -0162     fprintf('\n')
    -0163 end
    -0164 
    -0165 %Map to original model
    -0166 [~, I]=ismember(model.rxns,originalRxns);
    -0167 solutions=zeros(numel(originalRxns),nSamples);
    -0168 solutions(I,:)=sols;
    -0169 solutions=sparse(solutions);
    -0170 end
    -0171 
    -0172 %To use instead of the normal Matlab randsample function. This is in order
    -0173 %to not depend on the Matlab statistical toolbox.
    -0174 function I=randsample(n,k,replacement)
    -0175 if nargin<3
    -0176     replacement=false;
    -0177 end
    -0178 %n can be a integer, which leads to I being sampled from 1:n, or it can be
    -0179 %a population to sample from.
    -0180 if numel(n)==1 && isnumeric(n)
    -0181     n=1:n;
    -0182 end
    -0183 %Loop and get random numbers until the list is unique. This is only a good
    -0184 %option is the number of samples is small compared to the population. There
    -0185 %are several checks that should be made here, for example regarding size
    -0186 %and that the number of samples is <=population size if replacement==false.
    -0187 %This is not the case in randomSampling, so such checks are ignored
    -0188 while true
    -0189     J=randi(numel(n),[k,1]);
    -0190     if replacement==true || numel(J)==numel(unique(J))
    -0191         I=n(J);
    -0192         break;
    -0193     end
    -0194 end
    -0195 I=I(:);
    -0196 end
    +0070 [ps, oldPoolAutoCreateSetting] = parallelPoolRAVEN(runParallel); +0071 +0072 nObjRxns=2; %Number of reactions in the objective function in each iteration +0073 +0074 %Simplify the model to speed stuff up a little. Keep original mapping +0075 originalRxns=model.rxns; +0076 model=simplifyModel(model,false,false,true,true); +0077 +0078 %Then change the bounds to +/- Inf. This is needed in order to not have +0079 %loops in the solutions +0080 if replaceBoundsWithInf==true +0081 model.ub(model.ub==max(model.ub))=Inf; +0082 if min(model.lb)<0 % Only negative lower bounds should be set to -Inf +0083 model.lb(model.lb==min(model.lb))=-Inf; +0084 end +0085 end +0086 +0087 %Check that the model is feasible given the constraints +0088 [sol,~]=solveLP(model); +0089 if isempty(sol.x) +0090 EM='The model has no feasible solution, likely due to incompatible constraints'; +0091 dispEM(EM); +0092 elseif sol.f==0 && showProgress +0093 warning('The model objective function cannot reach a non-zero value. This might be intended, so randomSampling will continue, but this could indicate problems with your model') +0094 end +0095 +0096 [~,hsSol]=solveLP(model); +0097 nRxns = numel(model.rxns); +0098 %Reactions which can be involved in loops should not be optimized for. +0099 %Check which reactions reach an arbitary high upper bound +0100 if nargin<6 || isempty(goodRxns) +0101 goodRxns = true(numel(model.rxns),numel(model.rxns)); +0102 goodRxns = num2cell(goodRxns,1); +0103 PB = ProgressBar2(nRxns,'Prepare goodRxns not involved in loops','cli'); +0104 parfor (i=1:nRxns) +0105 testModel=setParam(model,'eq',model.rxns(i),1000); +0106 sol=solveLP(testModel,0,[],hsSol); +0107 if ~isempty(sol.f) +0108 notGood = abs(sol.x)>999; +0109 goodRxns{i}(notGood)=false; +0110 else +0111 %If the reaction is reversible, also check in that direction +0112 if model.rev(i) +0113 testModel=setParam(model,'eq',model.rxns(i),-1000); +0114 sol=solveLP(testModel,0,[],hsSol); +0115 if ~isempty(sol.f) +0116 notGood = abs(sol.x)>999; +0117 goodRxns{i}(notGood)=false; +0118 end +0119 end +0120 end +0121 count(PB); +0122 end +0123 goodRxns = cell2mat(goodRxns); +0124 goodRxns = find(prod(goodRxns,2)); +0125 end +0126 +0127 %Reserve space for a solution matrix +0128 sols = zeros(numel(model.rxns),nSamples); +0129 sols = num2cell(sols,1); +0130 +0131 %Main loop +0132 PB = ProgressBar2(nSamples,'Performing random sampling','cli'); +0133 parfor i=1:nSamples +0134 badSolutions = 1; +0135 tmpModel = model; +0136 while lt(0,badSolutions) +0137 rxns = randsample(numel(goodRxns),nObjRxns); +0138 tmpModel.c = zeros(numel(tmpModel.rxns),1); +0139 multipliers = randsample([-1 1],nObjRxns,true); +0140 multipliers(tmpModel.rev(goodRxns(rxns))==0) = 1; +0141 tmpModel.c(goodRxns(rxns)) = rand(nObjRxns,1).*multipliers; +0142 if true(minFlux) +0143 sol=solveLP(tmpModel,1,[],hsSol); +0144 else +0145 sol=solveLP(tmpModel,0,[],hsSol); +0146 end +0147 if any(sol.x) && abs(sol.f)>10^-8 +0148 sols{i} = sol.x; +0149 badSolutions = 0; +0150 else +0151 badSolutions = badSolutions+1; +0152 %If it only finds bad solutions then throw an error. +0153 if badSolutions == 100 && supressErrors==false +0154 error('The program is having problems finding non-zero solutions (ignoring reactions that might be involved in loops). Review the constraints on your model. Set supressErrors to true to ignore this error'); +0155 end +0156 end +0157 end +0158 count(PB); +0159 end +0160 +0161 %Map to original model +0162 sols = cell2mat(sols); +0163 [~, I]=ismember(model.rxns,originalRxns); +0164 solutions=zeros(numel(originalRxns),nSamples); +0165 solutions(I,:)=sols; +0166 solutions=sparse(solutions); +0167 % Reset original Parallel setting +0168 ps.Pool.AutoCreate = oldPoolAutoCreateSetting; +0169 end +0170 +0171 %To use instead of the normal Matlab randsample function. This is in order +0172 %to not depend on the Matlab statistical toolbox. +0173 function I=randsample(n,k,replacement) +0174 if nargin<3 +0175 replacement=false; +0176 end +0177 %n can be a integer, which leads to I being sampled from 1:n, or it can be +0178 %a population to sample from. +0179 if numel(n)==1 && isnumeric(n) +0180 n=1:n; +0181 end +0182 %Loop and get random numbers until the list is unique. This is only a good +0183 %option is the number of samples is small compared to the population. There +0184 %are several checks that should be made here, for example regarding size +0185 %and that the number of samples is <=population size if replacement==false. +0186 %This is not the case in randomSampling, so such checks are ignored +0187 while true +0188 J=randi(numel(n),[k,1]); +0189 if replacement==true || numel(J)==numel(unique(J)) +0190 I=n(J); +0191 break; +0192 end +0193 end +0194 I=I(:); +0195 end

    Generated by m2html © 2005
    \ No newline at end of file diff --git a/doc/core/simplifyModel.html b/doc/core/simplifyModel.html index 0f19608c..10889c26 100644 --- a/doc/core/simplifyModel.html +++ b/doc/core/simplifyModel.html @@ -70,7 +70,7 @@

    CROSS-REFERENCE INFORMATION ^
 <li><a href=contractModel contractModel
  • convertCharArray convertCharArray
  • convertToIrrev convertToIrrev
  • dispEM dispEM
  • getAllowedBounds getAllowedBounds
  • getIndexes getIndexes
  • haveFlux haveFlux
  • removeMets removeMets
  • removeReactions removeReactions
  • This function is called by: +
  • fillGaps fillGaps
  • findGeneDeletions findGeneDeletions
  • gapReport gapReport
  • haveFlux haveFlux
  • printModelStats printModelStats
  • randomSampling randomSampling
  • diff --git a/software/progressbar/ProgressBar2.m b/software/progressbar/ProgressBar2.m new file mode 100644 index 00000000..ef70e24d --- /dev/null +++ b/software/progressbar/ProgressBar2.m @@ -0,0 +1,389 @@ +% Function renamed to ProgressBar2 to avoid conflict with earlier +% progressbar.m. +% ProgressBar +% +% Handy progress bar that can be used in GUI or text interface. +% - Faster than waitbar (MATLAB builtin) +% - GUI interface +% - CLI interface +% - Parfor compatibility +% +% -=#( Monospaced fonts are recommended for the CLI interface )#=- +% +% GUI progress bar +% | N = 100; +% | task_name = 'Task name'; +% | +% | PB = ProgressBar(N, task_name); % or ProgressBar(N); +% | for n = 1:N +% | pause(0.5) % Loop body +% | PB.count % or count(PB) +% | end +% +% GUI progress bar (parfor loop) +% | N = 500; +% | task_name = 'Task name'; +% | +% | PB = ProgressBar(N, task_name); % or ProgressBar(N); +% | parfor n = 1:N +% | pause(0.5*rand) % Loop body +% | count(PB) % It is recommended to use count(PB) +% | % instead of PB.count in parfor loop. +% | end +% +% CLI progress bar +% | N = 100; +% | task_name = 'Task name'; +% | +% | PB = ProgressBar(N, task_name, 'cli'); +% | % or ProgressBar(N, [], 'cli'); +% | for n = 1:N +% | pause(0.5) % Loop body +% | PB.count % or count(PB) +% | end +% +% CLI progress bar (parfor loop) +% | N = 500; +% | task_name = 'Task name'; +% | +% | PB = ProgressBar(N, task_name, 'cli'); +% | % or ProgressBar(N, [], 'cli'); +% | parfor n = 1:N +% | pause(0.5*rand) % Loop body +% | count(PB) % It is recommended to use count(PB) +% | % instead of PB.count in parfor loop. +% | end +% +% CLI progress bar +% |███████████████████████████ 1 min, 18 sec ███████████████████████████|100% +% Task name |██████████████████████████ 8 sec ██████████████████████████|100% +% Task name |███████████████████████████████████████████████ | 80% +% Elapsed: 2 hour, 1 min, Remaining: 30 min +% +% +% compatibility: MATLAB 2020b ~ latest +% +% created 2023. 07. 14. +% edited 2023. 09. 28. +% author Cho HyunGwang +% +% https://github.com/elgar328/matlab-code-examples/tree/main/tools/ProgressBar + +% Note for character set +% char_set{1}↓↓char_set{4} ↓char_set{2} ↓char_set{3} ↓char_set{4} +% downloading.. |██████████████████████████████ | 80% +% downloading.. |██████████████████████████████---------------| 80% +% downloading.. |██████████████████████████████•••••••••••••••| 80% +% downloading.. |==============================•••••••••••••••| 80% +% downloading.. |============================== | 80% +% downloading.. |****************************** | 80% +% downloading.. |##############################...............| 80% +% 0 1 2 3 4 5 6 7 +% 123456789012345678901234567890123456789012345678901234567890123456789012345 + +classdef ProgressBar2 < handle + % -------------------- Properties for asynchronous -------------------- + properties (SetAccess = immutable, GetAccess = private) + Queue = [] + end + properties (SetAccess = immutable, GetAccess = private, Transient) + Listener = [] + no_parallel_toolbox + end + % ---------------------------- Properties ----------------------------- + properties (SetAccess = private, Transient) + task_name + counter = 0 + start_time = [] + end_time + end + properties (SetAccess = immutable, GetAccess = private, Transient) + N % final integer + ui_type % 'gui' or 'cli' + frame_interval_limit = 0.1 % sec + end + properties (Access = private, Transient) + time_info = ""; + ratio = 0; + int_percent = 0; + end + % ------------------------ Properties for GUI ------------------------- + properties (Access = private, Transient) + bar_ratio = 0; + prev_count_time + end + properties (SetAccess = immutable, Hidden = true, Transient) + fig_handle + ratio_resol = 0.01; + end + % ------------------------ Properties for CLI ------------------------- + properties (Access = private, Transient) + bar_n = 0; + end + properties (SetAccess = immutable, GetAccess = private, Transient) + bar_N + terminal_width = 40 + minimal_terminal_width = 20; + char_set = {' ','â–ˆ',' ','|'}; % <----- Character set + end + + methods + % -------------------------- Constructor -------------------------- + function obj = ProgressBar2(N, task_name, ui) + arguments + N (1,1) double {mustBePositive,mustBeFinite, ... + mustBeReal,mustBeInteger} + task_name (1,:) char {mustBeText} = '' + ui (1,3) char {mustBeMember(ui,{'gui','cli'})} = 'gui' + end + + obj.N = N; + obj.no_parallel_toolbox = ~contains([ver().Name], ... + 'parallel computing toolbox','IgnoreCase',true); + if ~obj.no_parallel_toolbox + obj.Queue = parallel.pool.DataQueue; + obj.Listener = afterEach(obj.Queue, @(~) localIncrement(obj)); + end + obj.ui_type = ui; + obj.start_time = datetime(); + obj.prev_count_time = datetime(); + + switch obj.ui_type + case 'cli' + obj.task_name = check_task_name_cli(obj, task_name); + bar_N = obj.terminal_width -4 -2*length(obj.char_set{4}); + if ~isempty(obj.task_name) + bar_N = bar_N -length(obj.char_set{1}) ... + -length(obj.task_name); + end + obj.bar_N = bar_N; + update_cli("", true, true); + case 'gui' + obj.task_name = task_name; + obj.fig_handle = waitbar(0, '', 'Name', ... + sprintf('%d%% %s',obj.int_percent, obj.task_name)); + obj.bar_N = 0; + end + end + % ---------------------------- Counter ---------------------------- + function count(obj) + % The || operator was not used intentionally. + % Short circuit does not work normally under certain conditions. + if obj.no_parallel_toolbox + obj.localIncrement(); % Serial processing + elseif isempty(getCurrentJob) + obj.localIncrement(); % Serial processing + else + send(obj.Queue, true); % Parallel processing + end + end + end + + methods (Hidden = true) + % -------------------------- Destructor --------------------------- + function delete(obj) + delete(obj.Queue); + if strcmp(obj.ui_type,'gui') + delete(obj.fig_handle); + end + end + end + + methods (Access = private) + % ------------------------- localIncrement ------------------------ + function localIncrement(obj) + obj.counter = 1 + obj.counter; + obj.ratio = obj.counter/obj.N; + + if (seconds(datetime()-obj.prev_count_time) < obj.frame_interval_limit) ... + && (obj.counter ~= obj.N) + return + end + obj.prev_count_time = datetime(); + + switch obj.ui_type + case 'cli' + % ------------------------ CLI ------------------------ + outdated = false; + if obj.int_percent ~= floor(obj.ratio*100) + obj.int_percent = floor(obj.ratio*100); + outdated = true; + if obj.int_percent == 100 + obj.end_time = datetime(); + end + end + new_time_info = get_time_info_string(obj); + if ~strcmp(obj.time_info, new_time_info) + obj.time_info = new_time_info; + outdated = true; + end + if obj.bar_n ~= floor(obj.bar_N*obj.ratio) + obj.bar_n = floor(obj.bar_N*obj.ratio); + outdated = true; + end + if outdated + print_progressbar_cli(obj); + end + case 'gui' + % ------------------------ GUI ------------------------ + if obj.int_percent ~= floor(obj.ratio*100) + obj.int_percent = floor(obj.ratio*100); + obj.fig_handle.Name = ... + sprintf('%d%% %s',obj.int_percent, obj.task_name); + end + if obj.bar_ratio + obj.ratio_resol <= obj.ratio + obj.bar_ratio = obj.ratio; + waitbar(obj.bar_ratio, obj.fig_handle) + end + new_time_info = get_time_info_string(obj); + if ~strcmp(obj.time_info, new_time_info) + obj.time_info = new_time_info; + waitbar(obj.ratio, obj.fig_handle, obj.time_info) + end + if obj.counter == obj.N + obj.end_time = datetime(); + % if ~isempty(obj.task_name) + % fprintf('%s\n', obj.task_name) + % end + % fprintf('%s\n', obj.time_info) + obj.delete + end + end + end + end +end + +% ---------------------------- Local functions ---------------------------- +function string_out = duration2string(dur) +if isinf(dur) + string_out = "Inf"; + return +end +if dur >= days(1) + string_out = sprintf('%d day, %d hour', ... + floor(dur/days(1)), floor(hours(mod(dur,days(1))))); +elseif dur >= hours(1) + string_out = sprintf('%d hour, %d min', ... + floor(dur/hours(1)), floor(minutes(mod(dur,hours(1))))); +elseif dur >= minutes(1) + string_out = sprintf('%d min, %d sec', ... + floor(dur/minutes(1)), floor(seconds(mod(dur,minutes(1))))); +else + string_out = sprintf('%d sec', floor(dur/seconds(1))); +end +string_out = string(string_out); +end + +function time_info = get_time_info_string(obj) +if obj.int_percent == 100 + time_info = "Elapsed: " ... + + duration2string(datetime() - obj.start_time); +else + elapsed = datetime() - obj.start_time; + remain = elapsed/obj.ratio - elapsed; + time_info = "Elapsed: " + duration2string(elapsed) ... + + ", Remaining: " + duration2string(remain); +end +end + +function print_progressbar_cli(obj) + +if isempty(obj.task_name) + name_string = ""; +else + name_string = string([obj.task_name, obj.char_set{1}]); +end +bar_bound_string = string(obj.char_set{4}); +percent_string = string(sprintf('%3d%%', obj.int_percent)); +% Bar text +bar_string = [repmat(obj.char_set{2},[1,obj.bar_n]), ... + repmat(obj.char_set{3},[1,obj.bar_N-obj.bar_n])]; +if obj.int_percent == 100 + % finished + end_flag = true; + time_info_char = [' ', ... + convertStringsToChars(... + extractAfter(obj.time_info,"Elapsed: ")), ' ']; + time_info_len = length(time_info_char); + if time_info_len + 2 <= length(bar_string) + head_ind = floor((length(bar_string)-time_info_len)/2)+1; + tail_ind = head_ind + time_info_len -1; + bar_string(head_ind:tail_ind) = time_info_char; + second_line = ""; + else + second_line = obj.time_info + newline; + end +else + % on progress + end_flag = false; + second_line = obj.time_info + newline; +end +bar_string = string(bar_string); + +first_line = ... + name_string ... + + bar_bound_string ... + + bar_string ... + + bar_bound_string ... + + percent_string ... + + newline; + +formatted_string = first_line + second_line; + +% print out +update_cli(formatted_string, end_flag); +end + +function update_cli(string_vec, lock_this_msg, lock_prev_msg) +% string_vec(1) -> std out (black) +% string_vec(2) -> std error (red) +% string_vec(3) -> std out (black) +% string_vec(4) -> std error (red) +% ... +% Not escaping at \, ', % + +arguments + string_vec (1,:) string + lock_this_msg (1,1) logical = false + lock_prev_msg (1,1) logical = false +end + +persistent previous_msg_length +if isempty(previous_msg_length) + previous_msg_length = 0; +end +if lock_prev_msg + previous_msg_length = 0; +end + +backspace_chain = string(repmat(sprintf('\b'),[1,previous_msg_length])); +previous_msg_length = sum(strlength(string_vec)); + +string_vec(1) = backspace_chain + string_vec(1); + +fileid = 1; +for n=1:length(string_vec) + msg = string_vec(n); + msg = strrep(msg, '%', '%%'); + msg = strrep(msg, '\', '\\'); + msg = strrep(msg, "'", "''"); + fprintf(fileid, msg); + switch fileid + case 1 + fileid = 2; + case 2 + fileid = 1; + end +end + +if lock_this_msg + previous_msg_length = 0; +end +end + +function task_name = check_task_name_cli(obj, task_name) +if length(task_name) >= (obj.terminal_width - obj.minimal_terminal_width) + task_name = task_name(1:obj.terminal_width-obj.minimal_terminal_width-1); + warning('The task name has been truncated due to its length!') +end +end \ No newline at end of file From 70fe6d6bff8225e34154d83e7a2afd1f89bb38b3 Mon Sep 17 00:00:00 2001 From: Eduard Kerkhoven Date: Thu, 11 Apr 2024 19:33:46 +0200 Subject: [PATCH 16/23] feat: setParam has 'unc' as option for unconstrained reactions --- core/setParam.m | 28 +++++- doc/core/dispEM.html | 2 +- doc/core/index.html | 2 +- doc/core/setParam.html | 218 +++++++++++++++++++++++------------------ doc/index.html | 106 ++++++++++---------- 5 files changed, 198 insertions(+), 158 deletions(-) diff --git a/core/setParam.m b/core/setParam.m index b5f00c67..c1ae9c79 100755 --- a/core/setParam.m +++ b/core/setParam.m @@ -6,11 +6,15 @@ % paramType the type of parameter to set: % 'lb' Lower bound % 'ub' Upper bound -% 'eq' Both upper and lower bound (equality -% constraint) +% 'eq' Both upper and lower bound (equality constraint) % 'obj' Objective coefficient -% 'rev' Reversibility +% 'rev' Reversibility (only changes the model.rev fields, +% does not affect model.lb and model.ub) % 'var' Variance around measured bound +% 'unc' Unconstrained, set lower and upper bound to the +% default values (-1000 and 1000, or any other values +% that are defined in model.annotation.defaultLB and +% .defaultUB) % rxnList a cell array of reaction IDs or a vector with their % corresponding indexes % params a vector of the corresponding values @@ -24,7 +28,7 @@ % Usage: model=setParam(model, paramType, rxnList, params) paramType=convertCharArray(paramType); -if ~any(strcmpi(paramType,{'lb','ub','eq','obj','rev','var'})) +if ~any(strcmpi(paramType,{'lb','ub','eq','obj','rev','var','unc'})) EM=['Incorrect parameter type: "' paramType '"']; dispEM(EM); end @@ -73,7 +77,7 @@ if ~isempty(indexes) if contains(paramType,'obj') model.c=zeros(numel(model.c),1); % parameter is changed, not added - end + end for j=1:length(paramType) if strcmpi(paramType{j},'eq') model.lb(indexes(j))=params(j); @@ -101,6 +105,20 @@ model.ub(indexes(j)) = params(j) * (1+var/200); end end + if strcmpi(paramType{j},'unc') + if isfield(model.annotation,'defaultLB') + lb = model.annotation.defaultLB; + else + lb = -1000; + end + if isfield(model.annotation,'defaultUB') + ub = model.annotation.defaultUB; + else + ub = 1000; + end + model.lb(indexes(j)) = lb; + model.ub(indexes(j)) = ub; + end end end end \ No newline at end of file diff --git a/doc/core/dispEM.html b/doc/core/dispEM.html index 9553e946..fc08cb9a 100644 --- a/doc/core/dispEM.html +++ b/doc/core/dispEM.html @@ -49,7 +49,7 @@

    CROSS-REFERENCE INFORMATION ^
 <li><a href=convertCharArray convertCharArray This function is called by: +
  • addGenesRaven addGenesRaven
  • addMets addMets
  • addRxns addRxns
  • addRxnsGenesMets addRxnsGenesMets
  • addTransport addTransport
  • analyzeSampling analyzeSampling
  • buildEquation buildEquation
  • changeRxns changeRxns
  • checkModelStruct checkModelStruct
  • checkRxn checkRxn
  • checkTasks checkTasks
  • compareMultipleModels compareMultipleModels
  • compareRxnsGenesMetsComps compareRxnsGenesMetsComps
  • constructS constructS
  • consumeSomething consumeSomething
  • contractModel contractModel
  • fillGaps fillGaps
  • findGeneDeletions findGeneDeletions
  • fitParameters fitParameters
  • fitTasks fitTasks
  • getElementalBalance getElementalBalance
  • getEssentialRxns getEssentialRxns
  • getExpressionStructure getExpressionStructure
  • getFluxZ getFluxZ
  • getMetsInComp getMetsInComp
  • getMinNrFluxes getMinNrFluxes
  • getModelFromHomology getModelFromHomology
  • getRxnsInComp getRxnsInComp
  • guessComposition guessComposition
  • makeSomething makeSomething
  • mapCompartments mapCompartments
  • mergeCompartments mergeCompartments
  • mergeModels mergeModels
  • parseTaskList parseTaskList
  • predictLocalization predictLocalization
  • printFluxes printFluxes
  • randomSampling randomSampling
  • removeBadRxns removeBadRxns
  • reporterMetabolites reporterMetabolites
  • setParam setParam
  • simplifyModel simplifyModel
  • sortModel sortModel
  • diff --git a/doc/core/index.html b/doc/core/index.html index d941a816..b09c29e5 100644 --- a/doc/core/index.html +++ b/doc/core/index.html @@ -19,7 +19,7 @@

    Index for core

    Matlab files in this directory:

    -
     FSEOFFSEOF: implements the algorithm of Flux Scanning based on Enforced Objective Flux.
     addExchangeRxnsaddExchangeRxns
     addGenesRavenaddGenesRaven
     addMetsaddMets
     addRxnsaddRxns
     addRxnsGenesMetsaddRxnsGenesMets
     addTransportaddTransport
     analyzeSamplinganalyzeSampling
     buildEquationbuildEquation
     canConsumecanConsume
     canProducecanProduce
     changeGrRuleschangeGrRules
     changeRxnschangeRxns
     checkModelStructcheckModelStruct
     checkProductioncheckProduction
     checkRxncheckRxn
     checkTaskscheckTasks
     compareMultipleModelscompareMultipleModels
     compareRxnsGenesMetsCompscompareRxnsGenesMetsComps
     constructEquationsconstructEquations
     constructSconstructS
     consumeSomethingconsumeSomething
     contractModelcontractModel
     convertCharArrayconvertCharArray
     convertToIrrevconvertToIrrev
     copyToCompscopyToComps
     deleteUnusedGenesdeleteUnusedGenes
     dispEMdispEM
     expandModelexpandModel
     fillGapsfillGaps
     findGeneDeletionsfindGeneDeletions
     findRAVENrootfindRAVENroot
     fitParametersfitParameters
     fitTasksfitTasks
     followChangedfollowChanged
     followFluxesfollowFluxes
     gapReportgapReport
     generateNewIdsgenerateNewIds
     getAllRxnsFromGenesgetAllRxnsFromGenes
     getAllSubGraphsgetAllSubGraphs
     getAllowedBoundsgetAllowedBounds
     getElementalBalancegetElementalBalance
     getEssentialRxnsgetEssentialRxns
     getExchangeRxnsgetExchangeRxns
     getExpressionStructuregetExpressionStructure
     getFluxZgetFluxZ
     getGenesFromGrRulesgetGenesFromGrRules Extract gene list and rxnGeneMat from grRules array.
     getIndexesgetIndexes
     getMetsInCompgetMetsInComp
     getMinNrFluxesgetMinNrFluxes
     getModelFromHomologygetModelFromHomology
     getRxnsInCompgetRxnsInComp
     getTransportRxnsgetTransportRxns
     guessCompositionguessComposition
     haveFluxhaveFlux
     makeSomethingmakeSomething
     mapCompartmentsmapCompartments
     mergeCompartmentsmergeCompartments
     mergeModelsmergeModels
     parseFormulasparseFormulas
     parseRxnEquparseRxnEqu
     parseTaskListparseTaskList
     permuteModelpermuteModel
     predictLocalizationpredictLocalization
     printFluxesprintFluxes
     printModelprintModel
     printModelStatsprintModelStats
     printOrangeprintOrange
     randomSamplingrandomSampling
     removeBadRxnsremoveBadRxns
     removeGenesremoveGenes
     removeMetsremoveMets
     removeReactionsremoveReactions
     replaceMetsreplaceMets
     reporterMetabolitesreporterMetabolites
     runDynamicFBArunDynamicFBA
     runPhenotypePhasePlanerunPhenotypePhasePlane
     runProductionEnveloperunProductionEnvelope
     runRobustnessAnalysisrunRobustnessAnalysis
     runSimpleOptKnockrunSimpleOptKnock
     setExchangeBoundssetExchangeBounds
     setParamsetParam
     simplifyModelsimplifyModel
     sortModelsortModel
     standardizeGrRulesstandardizeGrRules
    + FSEOFFSEOF: implements the algorithm of Flux Scanning based on Enforced Objective Flux.  addExchangeRxnsaddExchangeRxns  addGenesRavenaddGenesRaven  addMetsaddMets  addRxnsaddRxns  addRxnsGenesMetsaddRxnsGenesMets  addTransportaddTransport  analyzeSamplinganalyzeSampling  buildEquationbuildEquation  canConsumecanConsume  canProducecanProduce  changeGrRuleschangeGrRules  changeRxnschangeRxns  checkModelStructcheckModelStruct  checkProductioncheckProduction  checkRxncheckRxn  checkTaskscheckTasks  compareMultipleModelscompareMultipleModels  compareRxnsGenesMetsCompscompareRxnsGenesMetsComps  constructEquationsconstructEquations  constructSconstructS  consumeSomethingconsumeSomething  contractModelcontractModel  convertCharArrayconvertCharArray  convertToIrrevconvertToIrrev  copyToCompscopyToComps  deleteUnusedGenesdeleteUnusedGenes  dispEMdispEM  expandModelexpandModel  fillGapsfillGaps  findGeneDeletionsfindGeneDeletions  findRAVENrootfindRAVENroot  fitParametersfitParameters  fitTasksfitTasks  followChangedfollowChanged  followFluxesfollowFluxes  gapReportgapReport  generateNewIdsgenerateNewIds  getAllRxnsFromGenesgetAllRxnsFromGenes  getAllSubGraphsgetAllSubGraphs  getAllowedBoundsgetAllowedBounds  getElementalBalancegetElementalBalance  getEssentialRxnsgetEssentialRxns  getExchangeRxnsgetExchangeRxns  getExpressionStructuregetExpressionStructure  getFluxZgetFluxZ  getGenesFromGrRulesgetGenesFromGrRules Extract gene list and rxnGeneMat from grRules array.  getIndexesgetIndexes  getMetsInCompgetMetsInComp  getMinNrFluxesgetMinNrFluxes  getModelFromHomologygetModelFromHomology  getRxnsInCompgetRxnsInComp  getTransportRxnsgetTransportRxns  guessCompositionguessComposition  handleParallelRAVENhandleParallelRAVEN  haveFluxhaveFlux  makeSomethingmakeSomething  mapCompartmentsmapCompartments  mergeCompartmentsmergeCompartments  mergeModelsmergeModels  parseFormulasparseFormulas  parseRxnEquparseRxnEqu  parseTaskListparseTaskList  permuteModelpermuteModel  predictLocalizationpredictLocalization  printFluxesprintFluxes  printModelprintModel  printModelStatsprintModelStats  printOrangeprintOrange  randomSamplingrandomSampling  removeBadRxnsremoveBadRxns  removeGenesremoveGenes  removeMetsremoveMets  removeReactionsremoveReactions  replaceMetsreplaceMets  reporterMetabolitesreporterMetabolites  runDynamicFBArunDynamicFBA  runPhenotypePhasePlanerunPhenotypePhasePlane  runProductionEnveloperunProductionEnvelope  runRobustnessAnalysisrunRobustnessAnalysis  runSimpleOptKnockrunSimpleOptKnock  setExchangeBoundssetExchangeBounds  setParamsetParam  simplifyModelsimplifyModel  sortModelsortModel  standardizeGrRulesstandardizeGrRules diff --git a/doc/core/setParam.html b/doc/core/setParam.html index d1af3f3a..a0fdf22a 100644 --- a/doc/core/setParam.html +++ b/doc/core/setParam.html @@ -34,11 +34,15 @@

    DESCRIPTION ^CROSS-REFERENCE INFORMATION ^
 <li><a href=convertCharArray convertCharArray
  • dispEM dispEM
  • This function is called by: +
  • FSEOF FSEOF: implements the algorithm of Flux Scanning based on Enforced Objective Flux.
  • checkRxn checkRxn
  • checkTasks checkTasks
  • consumeSomething consumeSomething
  • fitTasks fitTasks
  • getEssentialRxns getEssentialRxns
  • makeSomething makeSomething
  • randomSampling randomSampling
  • runPhenotypePhasePlane runPhenotypePhasePlane
  • runProductionEnvelope runProductionEnvelope
  • runRobustnessAnalysis runRobustnessAnalysis
  • runSimpleOptKnock runSimpleOptKnock
  • setExchangeBounds setExchangeBounds
  • @@ -72,104 +76,122 @@

    SOURCE CODE ^% paramType the type of parameter to set: 0007 % 'lb' Lower bound 0008 % 'ub' Upper bound -0009 % 'eq' Both upper and lower bound (equality -0010 % constraint) -0011 % 'obj' Objective coefficient -0012 % 'rev' Reversibility +0009 % 'eq' Both upper and lower bound (equality constraint) +0010 % 'obj' Objective coefficient +0011 % 'rev' Reversibility (only changes the model.rev fields, +0012 % does not affect model.lb and model.ub) 0013 % 'var' Variance around measured bound -0014 % rxnList a cell array of reaction IDs or a vector with their -0015 % corresponding indexes -0016 % params a vector of the corresponding values -0017 % var percentage of variance around measured value, if 'var' is -0018 % set as paramType. Defining 'var' as 5 results in lb and ub -0019 % at 97.5% and 102.5% of the provide params value (if params -0020 % value is negative, then lb and ub are 102.5% and 97.5%). -0021 % -0022 % model an updated model structure -0023 % -0024 % Usage: model=setParam(model, paramType, rxnList, params) -0025 -0026 paramType=convertCharArray(paramType); -0027 if ~any(strcmpi(paramType,{'lb','ub','eq','obj','rev','var'})) -0028 EM=['Incorrect parameter type: "' paramType '"']; -0029 dispEM(EM); -0030 end -0031 if isnumeric(rxnList) || islogical(rxnList) -0032 rxnList=model.rxns(rxnList); -0033 else -0034 rxnList=convertCharArray(rxnList); -0035 end -0036 -0037 %Allow to set several parameters to the same value -0038 if numel(rxnList)~=numel(params) && numel(params)~=1 -0039 EM='The number of parameter values and the number of reactions must be the same'; -0040 dispEM(EM); -0041 end -0042 -0043 if length(rxnList)>1 -0044 if length(paramType)==1 -0045 paramType(1:length(rxnList))=paramType; -0046 end -0047 if length(params)==1 -0048 params(1:length(rxnList))=params; -0049 end -0050 end -0051 -0052 %Find the indexes for the reactions in rxnList. Do not use getIndexes -0053 %as we do not want to throw errors if matches fail -0054 indexes=zeros(numel(rxnList),1); +0014 % 'unc' Unconstrained, set lower and upper bound to the +0015 % default values (-1000 and 1000, or any other values +0016 % that are defined in model.annotation.defaultLB and +0017 % .defaultUB) +0018 % rxnList a cell array of reaction IDs or a vector with their +0019 % corresponding indexes +0020 % params a vector of the corresponding values +0021 % var percentage of variance around measured value, if 'var' is +0022 % set as paramType. Defining 'var' as 5 results in lb and ub +0023 % at 97.5% and 102.5% of the provide params value (if params +0024 % value is negative, then lb and ub are 102.5% and 97.5%). +0025 % +0026 % model an updated model structure +0027 % +0028 % Usage: model=setParam(model, paramType, rxnList, params) +0029 +0030 paramType=convertCharArray(paramType); +0031 if ~any(strcmpi(paramType,{'lb','ub','eq','obj','rev','var','unc'})) +0032 EM=['Incorrect parameter type: "' paramType '"']; +0033 dispEM(EM); +0034 end +0035 if isnumeric(rxnList) || islogical(rxnList) +0036 rxnList=model.rxns(rxnList); +0037 else +0038 rxnList=convertCharArray(rxnList); +0039 end +0040 +0041 %Allow to set several parameters to the same value +0042 if numel(rxnList)~=numel(params) && numel(params)~=1 +0043 EM='The number of parameter values and the number of reactions must be the same'; +0044 dispEM(EM); +0045 end +0046 +0047 if length(rxnList)>1 +0048 if length(paramType)==1 +0049 paramType(1:length(rxnList))=paramType; +0050 end +0051 if length(params)==1 +0052 params(1:length(rxnList))=params; +0053 end +0054 end 0055 -0056 for i=1:numel(rxnList) -0057 index=find(strcmp(rxnList{i},model.rxns),1); -0058 if ~isempty(index) -0059 indexes(i)=index; -0060 else -0061 indexes(i)=-1; -0062 EM=['Reaction ' rxnList{i} ' is not present in the reaction list']; -0063 dispEM(EM,false); -0064 end -0065 end -0066 -0067 %Remove the reactions that were not found -0068 params(indexes==-1)=[]; -0069 indexes(indexes==-1)=[]; -0070 paramType(indexes==-1)=[]; -0071 %Change the parameters -0072 -0073 if ~isempty(indexes) -0074 if contains(paramType,'obj') -0075 model.c=zeros(numel(model.c),1); % parameter is changed, not added -0076 end -0077 for j=1:length(paramType) -0078 if strcmpi(paramType{j},'eq') -0079 model.lb(indexes(j))=params(j); -0080 model.ub(indexes(j))=params(j); -0081 end -0082 if strcmpi(paramType{j},'lb') +0056 %Find the indexes for the reactions in rxnList. Do not use getIndexes +0057 %as we do not want to throw errors if matches fail +0058 indexes=zeros(numel(rxnList),1); +0059 +0060 for i=1:numel(rxnList) +0061 index=find(strcmp(rxnList{i},model.rxns),1); +0062 if ~isempty(index) +0063 indexes(i)=index; +0064 else +0065 indexes(i)=-1; +0066 EM=['Reaction ' rxnList{i} ' is not present in the reaction list']; +0067 dispEM(EM,false); +0068 end +0069 end +0070 +0071 %Remove the reactions that were not found +0072 params(indexes==-1)=[]; +0073 indexes(indexes==-1)=[]; +0074 paramType(indexes==-1)=[]; +0075 %Change the parameters +0076 +0077 if ~isempty(indexes) +0078 if contains(paramType,'obj') +0079 model.c=zeros(numel(model.c),1); % parameter is changed, not added +0080 end +0081 for j=1:length(paramType) +0082 if strcmpi(paramType{j},'eq') 0083 model.lb(indexes(j))=params(j); -0084 end -0085 if strcmpi(paramType{j},'ub') -0086 model.ub(indexes(j))=params(j); -0087 end -0088 if strcmpi(paramType{j},'obj') -0089 model.c(indexes(j))=params(j); -0090 end -0091 if strcmpi(paramType{j},'rev') -0092 %Non-zero values are interpreted as reversible -0093 model.rev(indexes(j))=params(j)~=0; +0084 model.ub(indexes(j))=params(j); +0085 end +0086 if strcmpi(paramType{j},'lb') +0087 model.lb(indexes(j))=params(j); +0088 end +0089 if strcmpi(paramType{j},'ub') +0090 model.ub(indexes(j))=params(j); +0091 end +0092 if strcmpi(paramType{j},'obj') +0093 model.c(indexes(j))=params(j); 0094 end -0095 if strcmpi(paramType{j},'var') -0096 if params(j) < 0 -0097 model.lb(indexes(j)) = params(j) * (1+var/200); -0098 model.ub(indexes(j)) = params(j) * (1-var/200); -0099 else -0100 model.lb(indexes(j)) = params(j) * (1-var/200); -0101 model.ub(indexes(j)) = params(j) * (1+var/200); -0102 end -0103 end -0104 end -0105 end -0106 end

    +0095 if strcmpi(paramType{j},'rev') +0096 %Non-zero values are interpreted as reversible +0097 model.rev(indexes(j))=params(j)~=0; +0098 end +0099 if strcmpi(paramType{j},'var') +0100 if params(j) < 0 +0101 model.lb(indexes(j)) = params(j) * (1+var/200); +0102 model.ub(indexes(j)) = params(j) * (1-var/200); +0103 else +0104 model.lb(indexes(j)) = params(j) * (1-var/200); +0105 model.ub(indexes(j)) = params(j) * (1+var/200); +0106 end +0107 end +0108 if strcmpi(paramType{j},'unc') +0109 if isfield(model.annotation,'defaultLB') +0110 lb = model.annotation.defaultLB; +0111 else +0112 lb = -1000; +0113 end +0114 if isfield(model.annotation,'defaultUB') +0115 ub = model.annotation.defaultUB; +0116 else +0117 ub = 1000; +0118 end +0119 model.lb(indexes(j)) = lb; +0120 model.ub(indexes(j)) = ub; +0121 end +0122 end +0123 end +0124 end
    Generated by m2html © 2005
    \ No newline at end of file diff --git a/doc/index.html b/doc/index.html index d3bcf010..5e31fc2a 100644 --- a/doc/index.html +++ b/doc/index.html @@ -19,59 +19,59 @@

    Matlab Directories

    Matlab Files found in these Directories

    - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
    FSEOF expandModel getObjectiveString ravenCobraWrapper
    INITStepDesc exportForGit getPathwayDimensions readYAMLmodel
    ManualINITTests exportModel getPhylDist removeBadRxns
    SBMLFromExcel exportModelToSIF getRxnsFromKEGG removeGenes
    addExchangeRxns exportToExcelFormat getRxnsFromMetaCyc removeLowScoreGenes
    addGenesRaven exportToTabDelimited getRxnsInComp removeMets
    addJavaPaths extractMiriam getToolboxVersion removeRavenFromPath
    addMets fillGaps getTransportRxns removeReactions
    addRavenToUserPath fillGapsLargeTests getWSLpath replaceMets
    addRxns fillGapsSmallTests getWoLFScores reporterMetabolites
    addRxnsGenesMets findGeneDeletions groupRxnScores rescaleModelForINIT
    addSpontaneousRxns findRAVENroot guessComposition reverseRxns
    addTransport fitParameters haveFlux runDynamicFBA
    analyzeSampling fitTasks hmmerTests runINIT
    blastPlusTests followChanged importExcelModel runPhenotypePhasePlane
    buildEquation followFluxes importExportTests runProductionEnvelope
    canConsume ftINIT importModel runRobustnessAnalysis
    canProduce ftINITFillGaps linkMetaCycKEGGRxns runSimpleOptKnock
    cdhitTests ftINITFillGapsForAllTasks loadSheet scoreComplexModel
    changeGeneAssoc ftINITFillGapsMILP loadWorkbook scoreModel
    changeGrRules ftINITInternalAlg mafftTests setColorToMapRxns
    changeRxns gapReport makeFakeBlastStructure setExchangeBounds
    checkFileExistence generateNewIds makeSomething setOmicDataToRxns
    checkFunctionUniqueness getAllRxnsFromGenes mapCompartments setParam
    checkInstallation getAllSubGraphs mapPathwayRxnNames setRavenSolver
    checkModelStruct getAllowedBounds markPathwayWithExpression setTitle
    checkProduction getBlast markPathwayWithFluxes simplifyModel
    checkRxn getBlastFromExcel mergeCompartments solveLP
    checkSolution getColorCodes mergeLinear solveQP
    checkTasks getDiamond mergeModels solverTests
    checkTasksTests getElementalBalance miriamTests sortIdentifiers
    cleanSheet getEnzymesFromMetaCyc modelAbilitiesTests sortModel
    closeModel getEssentialRxns modelConversionTests standardizeGrRules
    colorPathway getExchangeRxns modelCurationTests standardizeModelFieldOrder
    colorSubsystem getExprForRxnScore modelSortingTests startup
    combineMetaCycKEGGModels getExpressionStructure optimizeProb tinitTests
    compareMultipleModels getFluxZ parseFormulas trimPathway
    compareRxnsGenesMetsComps getFullPath parseHPA tutorial1
    constructEquations getGenesFromGrRules parseHPArna tutorial2
    constructMultiFasta getGenesFromKEGG parseRxnEqu tutorial2_solutions
    constructPathwayFromCelldesigner getINITModel parseScores tutorial3
    constructS getINITSteps parseTaskList tutorial3_solutions
    consumeSomething getIndexes permuteModel tutorial4
    contractModel getKEGGModelForOrganism plotAdditionalInfo tutorial4_solutions
    convertCharArray getMD5Hash plotLabels tutorial5
    convertToIrrev getMetaCycModelForOrganism predictLocalization tutorial6
    copyToComps getMetsFromKEGG prepINITModel updateDocumentation
    deleteUnusedGenes getMetsFromMetaCyc printFluxes writeSheet
    diamondTests getMetsInComp printModel writeYAMLmodel
    dispEM getMinNrFluxes printModelStats
    drawMap getModelFromHomology printOrange
    drawPathway getModelFromKEGG qMOMA
    editMiriam getModelFromMetaCyc randomSampling
    + FSEOF expandModel getObjectiveString randomSampling + INITStepDesc exportForGit getPathwayDimensions ravenCobraWrapper + ManualINITTests exportModel getPhylDist readYAMLmodel + SBMLFromExcel exportModelToSIF getRxnsFromKEGG removeBadRxns + addExchangeRxns exportToExcelFormat getRxnsFromMetaCyc removeGenes + addGenesRaven exportToTabDelimited getRxnsInComp removeLowScoreGenes + addJavaPaths extractMiriam getToolboxVersion removeMets + addMets fillGaps getTransportRxns removeRavenFromPath + addRavenToUserPath fillGapsLargeTests getWSLpath removeReactions + addRxns fillGapsSmallTests getWoLFScores replaceMets + addRxnsGenesMets findGeneDeletions groupRxnScores reporterMetabolites + addSpontaneousRxns findRAVENroot guessComposition rescaleModelForINIT + addTransport fitParameters handleParallelRAVEN reverseRxns + analyzeSampling fitTasks haveFlux runDynamicFBA + blastPlusTests followChanged hmmerTests runINIT + buildEquation followFluxes importExcelModel runPhenotypePhasePlane + canConsume ftINIT importExportTests runProductionEnvelope + canProduce ftINITFillGaps importModel runRobustnessAnalysis + cdhitTests ftINITFillGapsForAllTasks linkMetaCycKEGGRxns runSimpleOptKnock + changeGeneAssoc ftINITFillGapsMILP loadSheet scoreComplexModel + changeGrRules ftINITInternalAlg loadWorkbook scoreModel + changeRxns gapReport mafftTests setColorToMapRxns + checkFileExistence generateNewIds makeFakeBlastStructure setExchangeBounds + checkFunctionUniqueness getAllRxnsFromGenes makeSomething setOmicDataToRxns + checkInstallation getAllSubGraphs mapCompartments setParam + checkModelStruct getAllowedBounds mapPathwayRxnNames setRavenSolver + checkProduction getBlast markPathwayWithExpression setTitle + checkRxn getBlastFromExcel markPathwayWithFluxes simplifyModel + checkSolution getColorCodes mergeCompartments solveLP + checkTasks getDiamond mergeLinear solveQP + checkTasksTests getElementalBalance mergeModels solverTests + cleanSheet getEnzymesFromMetaCyc miriamTests sortIdentifiers + closeModel getEssentialRxns modelAbilitiesTests sortModel + colorPathway getExchangeRxns modelConversionTests standardizeGrRules + colorSubsystem getExprForRxnScore modelCurationTests standardizeModelFieldOrder + combineMetaCycKEGGModels getExpressionStructure modelSortingTests startup + compareMultipleModels getFluxZ optimizeProb tinitTests + compareRxnsGenesMetsComps getFullPath parseFormulas trimPathway + constructEquations getGenesFromGrRules parseHPA tutorial1 + constructMultiFasta getGenesFromKEGG parseHPArna tutorial2 + constructPathwayFromCelldesigner getINITModel parseRxnEqu tutorial2_solutions + constructS getINITSteps parseScores tutorial3 + consumeSomething getIndexes parseTaskList tutorial3_solutions + contractModel getKEGGModelForOrganism permuteModel tutorial4 + convertCharArray getMD5Hash plotAdditionalInfo tutorial4_solutions + convertToIrrev getMetaCycModelForOrganism plotLabels tutorial5 + copyToComps getMetsFromKEGG predictLocalization tutorial6 + deleteUnusedGenes getMetsFromMetaCyc prepINITModel updateDocumentation + diamondTests getMetsInComp printFluxes writeSheet + dispEM getMinNrFluxes printModel writeYAMLmodel + drawMap getModelFromHomology printModelStats + drawPathway getModelFromKEGG printOrange + editMiriam getModelFromMetaCyc qMOMA
    Generated by m2html © 2005
    From f2b4a2355a84a4ff7b7673bd75b6125940068479 Mon Sep 17 00:00:00 2001 From: Eduard Kerkhoven Date: Thu, 11 Apr 2024 19:45:53 +0200 Subject: [PATCH 17/23] feat: parallelPoolRAVEN handles parallelization --- core/getAllowedBounds.m | 2 +- ...dleParallelRAVEN.m => parallelPoolRAVEN.m} | 6 +- doc/core/getAllowedBounds.html | 6 +- doc/core/index.html | 2 +- ...allelRAVEN.html => parallelPoolRAVEN.html} | 56 ++++++++++--------- doc/core/randomSampling.html | 4 +- doc/index.html | 50 ++++++++--------- .../unit_tests/modelAbilitiesTests.html | 2 +- software/progressbar/ProgressBar2.m | 1 - testing/unit_tests/modelAbilitiesTests.m | 2 +- 10 files changed, 69 insertions(+), 62 deletions(-) rename core/{handleParallelRAVEN.m => parallelPoolRAVEN.m} (95%) rename doc/core/{handleParallelRAVEN.html => parallelPoolRAVEN.html} (74%) diff --git a/core/getAllowedBounds.m b/core/getAllowedBounds.m index 13900a63..fc915f4a 100755 --- a/core/getAllowedBounds.m +++ b/core/getAllowedBounds.m @@ -43,7 +43,7 @@ exitFlags = zeros(numel(rxns),2); c = zeros(numel(model.rxns),1); -PB = ProgressBar(numel(rxns),'Running getAllowedBounds','cli'); +PB = ProgressBar2(numel(rxns),'Running getAllowedBounds','cli'); parfor i = 1:numel(rxns) count(PB) tmpModel = model; diff --git a/core/handleParallelRAVEN.m b/core/parallelPoolRAVEN.m similarity index 95% rename from core/handleParallelRAVEN.m rename to core/parallelPoolRAVEN.m index b39680a0..f01d7884 100644 --- a/core/handleParallelRAVEN.m +++ b/core/parallelPoolRAVEN.m @@ -26,6 +26,10 @@ % % Use: [ps, oldPoolAutoCreate] = parallelPoolRAVEN(runParallel) +if nargin<1 || isempty(runParallel) + runParallel = true; +end + addonList = matlab.addons.installedAddons; ps = []; oldPoolAutoCreate = []; if ~any(strcmpi(addonList.Name,'Parallel Computing Toolbox')) @@ -42,7 +46,7 @@ else pool = gcp('nocreate'); if isempty(pool) - parpool; + parpool(IdleTimeout=120); end end end diff --git a/doc/core/getAllowedBounds.html b/doc/core/getAllowedBounds.html index 953ddfff..8f583cdd 100644 --- a/doc/core/getAllowedBounds.html +++ b/doc/core/getAllowedBounds.html @@ -58,7 +58,7 @@

    DESCRIPTION ^CROSS-REFERENCE INFORMATION ^

    This function calls: +
  • convertCharArray convertCharArray
  • getIndexes getIndexes
  • parallelPoolRAVEN handleParallelRAVEN
  • This function is called by: @@ -105,14 +105,14 @@

    SOURCE CODE ^end 0038 -0039 [ps, oldPoolAutoCreateSetting] = parallelPoolRAVEN(runParallel); +0039 [ps, oldPoolAutoCreateSetting] = parallelPoolRAVEN(runParallel); 0040 0041 minFluxes = zeros(numel(rxns),1); 0042 maxFluxes = zeros(numel(rxns),1); 0043 exitFlags = zeros(numel(rxns),2); 0044 c = zeros(numel(model.rxns),1); 0045 -0046 PB = ProgressBar(numel(rxns),'Running getAllowedBounds','cli'); +0046 PB = ProgressBar2(numel(rxns),'Running getAllowedBounds','cli'); 0047 parfor i = 1:numel(rxns) 0048 count(PB) 0049 tmpModel = model; diff --git a/doc/core/index.html b/doc/core/index.html index b09c29e5..bc4e4382 100644 --- a/doc/core/index.html +++ b/doc/core/index.html @@ -19,7 +19,7 @@

    Index for core

    Matlab files in this directory:

    -
     FSEOFFSEOF: implements the algorithm of Flux Scanning based on Enforced Objective Flux.
     addExchangeRxnsaddExchangeRxns
     addGenesRavenaddGenesRaven
     addMetsaddMets
     addRxnsaddRxns
     addRxnsGenesMetsaddRxnsGenesMets
     addTransportaddTransport
     analyzeSamplinganalyzeSampling
     buildEquationbuildEquation
     canConsumecanConsume
     canProducecanProduce
     changeGrRuleschangeGrRules
     changeRxnschangeRxns
     checkModelStructcheckModelStruct
     checkProductioncheckProduction
     checkRxncheckRxn
     checkTaskscheckTasks
     compareMultipleModelscompareMultipleModels
     compareRxnsGenesMetsCompscompareRxnsGenesMetsComps
     constructEquationsconstructEquations
     constructSconstructS
     consumeSomethingconsumeSomething
     contractModelcontractModel
     convertCharArrayconvertCharArray
     convertToIrrevconvertToIrrev
     copyToCompscopyToComps
     deleteUnusedGenesdeleteUnusedGenes
     dispEMdispEM
     expandModelexpandModel
     fillGapsfillGaps
     findGeneDeletionsfindGeneDeletions
     findRAVENrootfindRAVENroot
     fitParametersfitParameters
     fitTasksfitTasks
     followChangedfollowChanged
     followFluxesfollowFluxes
     gapReportgapReport
     generateNewIdsgenerateNewIds
     getAllRxnsFromGenesgetAllRxnsFromGenes
     getAllSubGraphsgetAllSubGraphs
     getAllowedBoundsgetAllowedBounds
     getElementalBalancegetElementalBalance
     getEssentialRxnsgetEssentialRxns
     getExchangeRxnsgetExchangeRxns
     getExpressionStructuregetExpressionStructure
     getFluxZgetFluxZ
     getGenesFromGrRulesgetGenesFromGrRules Extract gene list and rxnGeneMat from grRules array.
     getIndexesgetIndexes
     getMetsInCompgetMetsInComp
     getMinNrFluxesgetMinNrFluxes
     getModelFromHomologygetModelFromHomology
     getRxnsInCompgetRxnsInComp
     getTransportRxnsgetTransportRxns
     guessCompositionguessComposition
     handleParallelRAVENhandleParallelRAVEN
     haveFluxhaveFlux
     makeSomethingmakeSomething
     mapCompartmentsmapCompartments
     mergeCompartmentsmergeCompartments
     mergeModelsmergeModels
     parseFormulasparseFormulas
     parseRxnEquparseRxnEqu
     parseTaskListparseTaskList
     permuteModelpermuteModel
     predictLocalizationpredictLocalization
     printFluxesprintFluxes
     printModelprintModel
     printModelStatsprintModelStats
     printOrangeprintOrange
     randomSamplingrandomSampling
     removeBadRxnsremoveBadRxns
     removeGenesremoveGenes
     removeMetsremoveMets
     removeReactionsremoveReactions
     replaceMetsreplaceMets
     reporterMetabolitesreporterMetabolites
     runDynamicFBArunDynamicFBA
     runPhenotypePhasePlanerunPhenotypePhasePlane
     runProductionEnveloperunProductionEnvelope
     runRobustnessAnalysisrunRobustnessAnalysis
     runSimpleOptKnockrunSimpleOptKnock
     setExchangeBoundssetExchangeBounds
     setParamsetParam
     simplifyModelsimplifyModel
     sortModelsortModel
     standardizeGrRulesstandardizeGrRules
    + FSEOFFSEOF: implements the algorithm of Flux Scanning based on Enforced Objective Flux.  addExchangeRxnsaddExchangeRxns  addGenesRavenaddGenesRaven  addMetsaddMets  addRxnsaddRxns  addRxnsGenesMetsaddRxnsGenesMets  addTransportaddTransport  analyzeSamplinganalyzeSampling  buildEquationbuildEquation  canConsumecanConsume  canProducecanProduce  changeGrRuleschangeGrRules  changeRxnschangeRxns  checkModelStructcheckModelStruct  checkProductioncheckProduction  checkRxncheckRxn  checkTaskscheckTasks  compareMultipleModelscompareMultipleModels  compareRxnsGenesMetsCompscompareRxnsGenesMetsComps  constructEquationsconstructEquations  constructSconstructS  consumeSomethingconsumeSomething  contractModelcontractModel  convertCharArrayconvertCharArray  convertToIrrevconvertToIrrev  copyToCompscopyToComps  deleteUnusedGenesdeleteUnusedGenes  dispEMdispEM  expandModelexpandModel  fillGapsfillGaps  findGeneDeletionsfindGeneDeletions  findRAVENrootfindRAVENroot  fitParametersfitParameters  fitTasksfitTasks  followChangedfollowChanged  followFluxesfollowFluxes  gapReportgapReport  generateNewIdsgenerateNewIds  getAllRxnsFromGenesgetAllRxnsFromGenes  getAllSubGraphsgetAllSubGraphs  getAllowedBoundsgetAllowedBounds  getElementalBalancegetElementalBalance  getEssentialRxnsgetEssentialRxns  getExchangeRxnsgetExchangeRxns  getExpressionStructuregetExpressionStructure  getFluxZgetFluxZ  getGenesFromGrRulesgetGenesFromGrRules Extract gene list and rxnGeneMat from grRules array.  getIndexesgetIndexes  getMetsInCompgetMetsInComp  getMinNrFluxesgetMinNrFluxes  getModelFromHomologygetModelFromHomology  getRxnsInCompgetRxnsInComp  getTransportRxnsgetTransportRxns  guessCompositionguessComposition  haveFluxhaveFlux  makeSomethingmakeSomething  mapCompartmentsmapCompartments  mergeCompartmentsmergeCompartments  mergeModelsmergeModels  parallelPoolRAVENhandleParallelRAVEN  parseFormulasparseFormulas  parseRxnEquparseRxnEqu  parseTaskListparseTaskList  permuteModelpermuteModel  predictLocalizationpredictLocalization  printFluxesprintFluxes  printModelprintModel  printModelStatsprintModelStats  printOrangeprintOrange  randomSamplingrandomSampling  removeBadRxnsremoveBadRxns  removeGenesremoveGenes  removeMetsremoveMets  removeReactionsremoveReactions  replaceMetsreplaceMets  reporterMetabolitesreporterMetabolites  runDynamicFBArunDynamicFBA  runPhenotypePhasePlanerunPhenotypePhasePlane  runProductionEnveloperunProductionEnvelope  runRobustnessAnalysisrunRobustnessAnalysis  runSimpleOptKnockrunSimpleOptKnock  setExchangeBoundssetExchangeBounds  setParamsetParam  simplifyModelsimplifyModel  sortModelsortModel  standardizeGrRulesstandardizeGrRules diff --git a/doc/core/handleParallelRAVEN.html b/doc/core/parallelPoolRAVEN.html similarity index 74% rename from doc/core/handleParallelRAVEN.html rename to doc/core/parallelPoolRAVEN.html index 4c0128a1..999782cb 100644 --- a/doc/core/handleParallelRAVEN.html +++ b/doc/core/parallelPoolRAVEN.html @@ -2,8 +2,8 @@ "http://www.w3.org/TR/REC-html40/loose.dtd"> - Description of handleParallelRAVEN - + Description of parallelPoolRAVEN + @@ -12,12 +12,12 @@ -
    Home > core > handleParallelRAVEN.m
    +
    Home > core > parallelPoolRAVEN.m
    -

    handleParallelRAVEN +

    parallelPoolRAVEN

    PURPOSE ^

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

    CROSS-REFERENCE INFORMATION ^
 </ul>
 This function is called by:
 <ul style= - +
  • findGeneDeletions findGeneDeletions
  • getAllowedBounds getAllowedBounds
  • randomSampling randomSampling
  • @@ -95,27 +95,31 @@

    SOURCE CODE ^% 0027 % Use: [ps, oldPoolAutoCreate] = parallelPoolRAVEN(runParallel) 0028 -0029 addonList = matlab.addons.installedAddons; -0030 ps = []; oldPoolAutoCreate = []; -0031 if ~any(strcmpi(addonList.Name,'Parallel Computing Toolbox')) -0032 if runParallel % User wants parallel, but will not be possible -0033 disp('Cannot find MATLAB Parallel Computing Toolbox, process is not parallelized.') -0034 end -0035 else -0036 if ~runParallel % User has Parallel toolbox, but does not want pool to start. -0037 % If pool is already running, then it will use the max workers -0038 % anyway, but this is probably okay. -0039 ps = parallel.Settings; -0040 oldPoolAutoCreate = ps.Pool.AutoCreate; -0041 ps.Pool.AutoCreate = false; -0042 else -0043 pool = gcp('nocreate'); -0044 if isempty(pool) -0045 parpool; -0046 end -0047 end -0048 end -0049 end +0029 if nargin<1 || isempty(runParallel) +0030 runParallel = true; +0031 end +0032 +0033 addonList = matlab.addons.installedAddons; +0034 ps = []; oldPoolAutoCreate = []; +0035 if ~any(strcmpi(addonList.Name,'Parallel Computing Toolbox')) +0036 if runParallel % User wants parallel, but will not be possible +0037 disp('Cannot find MATLAB Parallel Computing Toolbox, process is not parallelized.') +0038 end +0039 else +0040 if ~runParallel % User has Parallel toolbox, but does not want pool to start. +0041 % If pool is already running, then it will use the max workers +0042 % anyway, but this is probably okay. +0043 ps = parallel.Settings; +0044 oldPoolAutoCreate = ps.Pool.AutoCreate; +0045 ps.Pool.AutoCreate = false; +0046 else +0047 pool = gcp('nocreate'); +0048 if isempty(pool) +0049 parpool(IdleTimeout=120); +0050 end +0051 end +0052 end +0053 end
    Generated by m2html © 2005
    \ No newline at end of file diff --git a/doc/core/randomSampling.html b/doc/core/randomSampling.html index be0fa5ff..3b18a512 100644 --- a/doc/core/randomSampling.html +++ b/doc/core/randomSampling.html @@ -83,7 +83,7 @@

    DESCRIPTION ^CROSS-REFERENCE INFORMATION ^

    This function calls: +
  • dispEM dispEM
  • parallelPoolRAVEN handleParallelRAVEN
  • setParam setParam
  • simplifyModel simplifyModel
  • This function is called by:
    @@ -163,7 +163,7 @@

    SOURCE CODE ^end 0069 -0070 [ps, oldPoolAutoCreateSetting] = parallelPoolRAVEN(runParallel); +0070 [ps, oldPoolAutoCreateSetting] = parallelPoolRAVEN(runParallel); 0071 0072 nObjRxns=2; %Number of reactions in the objective function in each iteration 0073 diff --git a/doc/index.html b/doc/index.html index 5e31fc2a..c87f7edd 100644 --- a/doc/index.html +++ b/doc/index.html @@ -31,31 +31,31 @@

    Matlab Files found in these Directories

    addRxns fillGapsSmallTests getWoLFScores replaceMets addRxnsGenesMets findGeneDeletions groupRxnScores reporterMetabolites addSpontaneousRxns findRAVENroot guessComposition rescaleModelForINIT - addTransport fitParameters handleParallelRAVEN reverseRxns - analyzeSampling fitTasks haveFlux runDynamicFBA - blastPlusTests followChanged hmmerTests runINIT - buildEquation followFluxes importExcelModel runPhenotypePhasePlane - canConsume ftINIT importExportTests runProductionEnvelope - canProduce ftINITFillGaps importModel runRobustnessAnalysis - cdhitTests ftINITFillGapsForAllTasks linkMetaCycKEGGRxns runSimpleOptKnock - changeGeneAssoc ftINITFillGapsMILP loadSheet scoreComplexModel - changeGrRules ftINITInternalAlg loadWorkbook scoreModel - changeRxns gapReport mafftTests setColorToMapRxns - checkFileExistence generateNewIds makeFakeBlastStructure setExchangeBounds - checkFunctionUniqueness getAllRxnsFromGenes makeSomething setOmicDataToRxns - checkInstallation getAllSubGraphs mapCompartments setParam - checkModelStruct getAllowedBounds mapPathwayRxnNames setRavenSolver - checkProduction getBlast markPathwayWithExpression setTitle - checkRxn getBlastFromExcel markPathwayWithFluxes simplifyModel - checkSolution getColorCodes mergeCompartments solveLP - checkTasks getDiamond mergeLinear solveQP - checkTasksTests getElementalBalance mergeModels solverTests - cleanSheet getEnzymesFromMetaCyc miriamTests sortIdentifiers - closeModel getEssentialRxns modelAbilitiesTests sortModel - colorPathway getExchangeRxns modelConversionTests standardizeGrRules - colorSubsystem getExprForRxnScore modelCurationTests standardizeModelFieldOrder - combineMetaCycKEGGModels getExpressionStructure modelSortingTests startup - compareMultipleModels getFluxZ optimizeProb tinitTests + addTransport fitParameters haveFlux reverseRxns + analyzeSampling fitTasks hmmerTests runDynamicFBA + blastPlusTests followChanged importExcelModel runINIT + buildEquation followFluxes importExportTests runPhenotypePhasePlane + canConsume ftINIT importModel runProductionEnvelope + canProduce ftINITFillGaps linkMetaCycKEGGRxns runRobustnessAnalysis + cdhitTests ftINITFillGapsForAllTasks loadSheet runSimpleOptKnock + changeGeneAssoc ftINITFillGapsMILP loadWorkbook scoreComplexModel + changeGrRules ftINITInternalAlg mafftTests scoreModel + changeRxns gapReport makeFakeBlastStructure setColorToMapRxns + checkFileExistence generateNewIds makeSomething setExchangeBounds + checkFunctionUniqueness getAllRxnsFromGenes mapCompartments setOmicDataToRxns + checkInstallation getAllSubGraphs mapPathwayRxnNames setParam + checkModelStruct getAllowedBounds markPathwayWithExpression setRavenSolver + checkProduction getBlast markPathwayWithFluxes setTitle + checkRxn getBlastFromExcel mergeCompartments simplifyModel + checkSolution getColorCodes mergeLinear solveLP + checkTasks getDiamond mergeModels solveQP + checkTasksTests getElementalBalance miriamTests solverTests + cleanSheet getEnzymesFromMetaCyc modelAbilitiesTests sortIdentifiers + closeModel getEssentialRxns modelConversionTests sortModel + colorPathway getExchangeRxns modelCurationTests standardizeGrRules + colorSubsystem getExprForRxnScore modelSortingTests standardizeModelFieldOrder + combineMetaCycKEGGModels getExpressionStructure optimizeProb startup + compareMultipleModels getFluxZ parallelPoolRAVEN tinitTests compareRxnsGenesMetsComps getFullPath parseFormulas trimPathway constructEquations getGenesFromGrRules parseHPA tutorial1 constructMultiFasta getGenesFromKEGG parseHPArna tutorial2 diff --git a/doc/testing/unit_tests/modelAbilitiesTests.html b/doc/testing/unit_tests/modelAbilitiesTests.html index 7092baf7..6841b69a 100644 --- a/doc/testing/unit_tests/modelAbilitiesTests.html +++ b/doc/testing/unit_tests/modelAbilitiesTests.html @@ -143,7 +143,7 @@

    SOURCE CODE ^'testing','unit_tests','test_data','ecoli_textbook.mat'), 'model'); 0097 0098 -0099 [testOut.min, testOut.max, testOut.flag]=getAllowedBounds(model,[1:10],false); +0099 evalc("[testOut.min, testOut.max, testOut.flag]=getAllowedBounds(model,[1:10],false);"); 0100 % Simplify output for later check, no need for high precision 0101 % testOut.min(abs(testOut.min)<1e-10)=0; 0102 % testOut.min=single(testOut.min); diff --git a/software/progressbar/ProgressBar2.m b/software/progressbar/ProgressBar2.m index ef70e24d..89bd4cb0 100644 --- a/software/progressbar/ProgressBar2.m +++ b/software/progressbar/ProgressBar2.m @@ -384,6 +384,5 @@ function update_cli(string_vec, lock_this_msg, lock_prev_msg) function task_name = check_task_name_cli(obj, task_name) if length(task_name) >= (obj.terminal_width - obj.minimal_terminal_width) task_name = task_name(1:obj.terminal_width-obj.minimal_terminal_width-1); - warning('The task name has been truncated due to its length!') end end \ No newline at end of file diff --git a/testing/unit_tests/modelAbilitiesTests.m b/testing/unit_tests/modelAbilitiesTests.m index b72cff76..b29f2d91 100644 --- a/testing/unit_tests/modelAbilitiesTests.m +++ b/testing/unit_tests/modelAbilitiesTests.m @@ -96,7 +96,7 @@ function getAllowedBoundsTest(testCase) load(fullfile(sourceDir,'testing','unit_tests','test_data','ecoli_textbook.mat'), 'model'); -[testOut.min, testOut.max, testOut.flag]=getAllowedBounds(model,[1:10],false); +evalc("[testOut.min, testOut.max, testOut.flag]=getAllowedBounds(model,[1:10],false);"); % Simplify output for later check, no need for high precision % testOut.min(abs(testOut.min)<1e-10)=0; % testOut.min=single(testOut.min); From 8918962be824ecbd8738530c40a3e3e04f95ba38 Mon Sep 17 00:00:00 2001 From: Eduard Kerkhoven Date: Thu, 11 Apr 2024 22:01:32 +0200 Subject: [PATCH 18/23] feat: use alternative ProgressBar function works both when parfor is run in parallel or in serial, without any further changes to the code --- core/parallelPoolRAVEN.m | 2 +- core/runDynamicFBA.m | 6 +-- core/runPhenotypePhasePlane.m | 5 +- core/runProductionEnvelope.m | 6 +-- core/runRobustnessAnalysis.m | 7 ++- doc/core/parallelPoolRAVEN.html | 4 +- doc/core/runDynamicFBA.html | 52 ++++++++++--------- doc/core/runPhenotypePhasePlane.html | 75 ++++++++++++++-------------- doc/core/runProductionEnvelope.html | 52 ++++++++++--------- doc/core/runRobustnessAnalysis.html | 39 +++++++-------- 10 files changed, 118 insertions(+), 130 deletions(-) diff --git a/core/parallelPoolRAVEN.m b/core/parallelPoolRAVEN.m index f01d7884..36018ce2 100644 --- a/core/parallelPoolRAVEN.m +++ b/core/parallelPoolRAVEN.m @@ -46,7 +46,7 @@ else pool = gcp('nocreate'); if isempty(pool) - parpool(IdleTimeout=120); + parpool('IdleTimeout',120) end end end diff --git a/core/runDynamicFBA.m b/core/runDynamicFBA.m index 64a15616..cb776d3d 100644 --- a/core/runDynamicFBA.m +++ b/core/runDynamicFBA.m @@ -76,7 +76,7 @@ biomassVec = biomass; timeVec(1) = 0; [~,hsSol]=solveLP(model,1); -fprintf('Running dynamic FBA analysis... 0%% complete'); +PB = ProgressBar2(nSteps,'Running dynamic FBA analysis','cli'); for stepNo = 1:nSteps % Run FBA [sol,hsSol] = solveLP(model,1,[],hsSol); @@ -107,10 +107,8 @@ model.lb(excInd) = -uptakeBound; timeVec(stepNo+1) = stepNo*timeStep; - progress=pad(num2str(floor(stepNo/nSteps*100)),3,'left'); - fprintf('\b\b\b\b\b\b\b\b\b\b\b\b\b%s%% complete',progress); + count(PB); end -fprintf('\b\b\b\b\b\b\b\b\b\b\b\b\bCOMPLETE\n'); selNonZero = any(concentrationMatrix>0,2); concentrationMatrix = concentrationMatrix(selNonZero,:); diff --git a/core/runPhenotypePhasePlane.m b/core/runPhenotypePhasePlane.m index 9b4a17ea..2b1d9f73 100644 --- a/core/runPhenotypePhasePlane.m +++ b/core/runPhenotypePhasePlane.m @@ -49,10 +49,8 @@ shadowPrices2 = zeros(nPts); [~,hsSol] = solveLP(model); % Calulate points -fprintf('Running PhPP analysis... 0%% complete'); +PB = ProgressBar2(nPts,'Running PhPP analysis','cli'); for i = 1:nPts %ind1 - progress=pad(num2str(floor(i/nPts*100)),3,'left'); - fprintf('\b\b\b\b\b\b\b\b\b\b\b\b\b%s%% complete',progress); for j = 1:nPts %ind2 model1 = setParam(model,'eq',controlRxn1,-1*ind1(i)); model1 = setParam(model1,'eq',controlRxn2,-1*ind2(j)); @@ -63,6 +61,7 @@ shadowPrices2(j,i) = fbasol.sPrice(metID2); end end + count(PB); end fprintf('\b\b\b\b\b\b\b\b\b\b\b\b\bCOMPLETE\n'); diff --git a/core/runProductionEnvelope.m b/core/runProductionEnvelope.m index 163da119..46eea9d6 100644 --- a/core/runProductionEnvelope.m +++ b/core/runProductionEnvelope.m @@ -33,12 +33,10 @@ targetUpperBound = nan(1,numel(biomassValues)); targetLowerBound = nan(1,numel(biomassValues)); -fprintf('Creating production envelope... 0%% complete'); +PB = ProgressBar2(length(biomassValues),'Creating production envelope','cli'); % Max/min for target production model = setParam(model,'obj',targetRxn,1); for i = 1:length(biomassValues) - progress=pad(num2str(floor(i/numel(biomassValues)*100)),3,'left'); - fprintf('\b\b\b\b\b\b\b\b\b\b\b\b\b%s%% complete',progress); model1 = setParam(model,'eq',biomassRxn,biomassValues(i)); sol = solveLP(model1,0,[],hsSol); if (sol.stat > 0) @@ -53,8 +51,8 @@ else targetLowerBound(i) = NaN; end + count(PB); end -fprintf('\b\b\b\b\b\b\b\b\b\b\b\b\bCOMPLETE\n'); % Plot results plot([biomassValues fliplr(biomassValues)],[targetUpperBound fliplr(targetLowerBound)],'blue','LineWidth',2); diff --git a/core/runRobustnessAnalysis.m b/core/runRobustnessAnalysis.m index c494f9aa..7504f3a7 100644 --- a/core/runRobustnessAnalysis.m +++ b/core/runRobustnessAnalysis.m @@ -50,16 +50,15 @@ redCost = zeros(nPoints,1); controlFlux = linspace(solMin,solMax,nPoints)'; -fprintf('Running robustness analysis... 0%% complete'); + +PB = ProgressBar2(length(controlFlux),'Running robustness analysis','cli'); for i=1:length(controlFlux) - progress=pad(num2str(floor(i/numel(controlFlux)*100)),3,'left'); - fprintf('\b\b\b\b\b\b\b\b\b\b\b\b\b%s%% complete',progress); modelControlled = setParam(baseModel,'eq',controlRxnIdx,controlFlux(i)); solControlled = solveLP(modelControlled); objFlux(i) = solControlled.x(logical(modelControlled.c)); redCost(i) = solControlled.rCost(controlRxnIdx); + count(PB); end -fprintf('\b\b\b\b\b\b\b\b\b\b\b\b\bCOMPLETE\n'); if plotRedCost yyaxis right diff --git a/doc/core/parallelPoolRAVEN.html b/doc/core/parallelPoolRAVEN.html index 999782cb..1fbf2f46 100644 --- a/doc/core/parallelPoolRAVEN.html +++ b/doc/core/parallelPoolRAVEN.html @@ -61,7 +61,7 @@

    CROSS-REFERENCE INFORMATION ^
 </ul>
 This function is called by:
 <ul style= -
  • findGeneDeletions findGeneDeletions
  • getAllowedBounds getAllowedBounds
  • randomSampling randomSampling
  • +
  • getAllowedBounds getAllowedBounds
  • randomSampling randomSampling
  • @@ -115,7 +115,7 @@

    SOURCE CODE ^else 0047 pool = gcp('nocreate'); 0048 if isempty(pool) -0049 parpool(IdleTimeout=120); +0049 parpool('IdleTimeout',120) 0050 end 0051 end 0052 end diff --git a/doc/core/runDynamicFBA.html b/doc/core/runDynamicFBA.html index a234780a..7a6bcf30 100644 --- a/doc/core/runDynamicFBA.html +++ b/doc/core/runDynamicFBA.html @@ -158,7 +158,7 @@

    SOURCE CODE ^'Running dynamic FBA analysis... 0%% complete'); +0079 PB = ProgressBar2(nSteps,'Running dynamic FBA analysis','cli'); 0080 for stepNo = 1:nSteps 0081 % Run FBA 0082 [sol,hsSol] = solveLP(model,1,[],hsSol); @@ -189,32 +189,30 @@

    SOURCE CODE ^'left'); -0111 fprintf('\b\b\b\b\b\b\b\b\b\b\b\b\b%s%% complete',progress); -0112 end -0113 fprintf('\b\b\b\b\b\b\b\b\b\b\b\b\bCOMPLETE\n'); -0114 -0115 selNonZero = any(concentrationMatrix>0,2); -0116 concentrationMatrix = concentrationMatrix(selNonZero,:); -0117 excRxnNames = excRxnNames(selNonZero); -0118 selPlot = ismember(excRxnNames,plotRxns); -0119 -0120 % Plot concentrations as a function of time -0121 clf -0122 subplot(1,2,1); -0123 plot(timeVec,biomassVec); -0124 axis tight -0125 title('Biomass'); -0126 xlabel('Time (h)'); -0127 ylabel('Concentration (g/L)'); -0128 subplot(1,2,2); -0129 plot(timeVec,concentrationMatrix(selPlot,:)); -0130 axis tight -0131 title('Substrates and/or products'); -0132 xlabel('Time (h)'); -0133 ylabel('Concentration (mmol/L)'); -0134 legend(strrep(excRxnNames(selPlot),'EX_','')); -0135 end +0110 count(PB); +0111 end +0112 +0113 selNonZero = any(concentrationMatrix>0,2); +0114 concentrationMatrix = concentrationMatrix(selNonZero,:); +0115 excRxnNames = excRxnNames(selNonZero); +0116 selPlot = ismember(excRxnNames,plotRxns); +0117 +0118 % Plot concentrations as a function of time +0119 clf +0120 subplot(1,2,1); +0121 plot(timeVec,biomassVec); +0122 axis tight +0123 title('Biomass'); +0124 xlabel('Time (h)'); +0125 ylabel('Concentration (g/L)'); +0126 subplot(1,2,2); +0127 plot(timeVec,concentrationMatrix(selPlot,:)); +0128 axis tight +0129 title('Substrates and/or products'); +0130 xlabel('Time (h)'); +0131 ylabel('Concentration (mmol/L)'); +0132 legend(strrep(excRxnNames(selPlot),'EX_','')); +0133 end
    Generated by m2html © 2005
    \ No newline at end of file diff --git a/doc/core/runPhenotypePhasePlane.html b/doc/core/runPhenotypePhasePlane.html index 1edab1e7..3efcf052 100644 --- a/doc/core/runPhenotypePhasePlane.html +++ b/doc/core/runPhenotypePhasePlane.html @@ -118,45 +118,44 @@

    SOURCE CODE ^% Calulate points -0052 fprintf('Running PhPP analysis... 0%% complete'); +0052 PB = ProgressBar2(nPts,'Running PhPP analysis','cli'); 0053 for i = 1:nPts %ind1 -0054 progress=pad(num2str(floor(i/nPts*100)),3,'left'); -0055 fprintf('\b\b\b\b\b\b\b\b\b\b\b\b\b%s%% complete',progress); -0056 for j = 1:nPts %ind2 -0057 model1 = setParam(model,'eq',controlRxn1,-1*ind1(i)); -0058 model1 = setParam(model1,'eq',controlRxn2,-1*ind2(j)); -0059 [fbasol,hsSol] = solveLP(model1,0,[],hsSol); -0060 try -0061 growthRates(j,i) = fbasol.x(logical(model1.c)); -0062 shadowPrices1(j,i) = fbasol.sPrice(metID1); -0063 shadowPrices2(j,i) = fbasol.sPrice(metID2); -0064 end -0065 end -0066 end -0067 fprintf('\b\b\b\b\b\b\b\b\b\b\b\b\bCOMPLETE\n'); -0068 -0069 % Plot the points -0070 figure(2); -0071 pcolor(ind1,ind2,shadowPrices1); -0072 xlabel(strrep(strcat(controlRxn1,' (mmol/g DW-hr)'),'_','\_')), ylabel(strrep(strcat(controlRxn2,' (mmol/g DW-hr)'),'_','\_')), zlabel('growth rate (1/hr)'); -0073 title(['Shadow price ' strrep(model.mets{metID1},'_','-')]); -0074 colorbar(); -0075 xticklabels(sprintfc('%d', -xticks)) -0076 yticklabels(sprintfc('%d', -yticks)) -0077 figure(3); -0078 pcolor(ind1,ind2,shadowPrices2); -0079 xlabel(strrep(strcat(controlRxn1,' (mmol/g DW-hr)'),'_','\_')), ylabel(strrep(strcat(controlRxn2,' (mmol/g DW-hr)'),'_','\_')), zlabel('growth rate (1/hr)'); -0080 title(['Shadow price ' strrep(model.mets{metID2},'_','-')]); -0081 colorbar(); -0082 xticklabels(sprintfc('%d', -xticks)) -0083 yticklabels(sprintfc('%d', -yticks)) -0084 figure(1); -0085 surfl(ind1,ind2,growthRates); -0086 xlabel(strrep(strcat(controlRxn1,' (mmol/g DW-hr)'),'_','\_')), ylabel(strrep(strcat(controlRxn2,' (mmol/g DW-hr)'),'_','\_')), zlabel('growth rate (1/hr)'); -0087 colormap(hsv(17)); -0088 xticklabels(sprintfc('%d', -xticks)) -0089 yticklabels(sprintfc('%d', -yticks)) -0090 end +0054 for j = 1:nPts %ind2 +0055 model1 = setParam(model,'eq',controlRxn1,-1*ind1(i)); +0056 model1 = setParam(model1,'eq',controlRxn2,-1*ind2(j)); +0057 [fbasol,hsSol] = solveLP(model1,0,[],hsSol); +0058 try +0059 growthRates(j,i) = fbasol.x(logical(model1.c)); +0060 shadowPrices1(j,i) = fbasol.sPrice(metID1); +0061 shadowPrices2(j,i) = fbasol.sPrice(metID2); +0062 end +0063 end +0064 count(PB); +0065 end +0066 fprintf('\b\b\b\b\b\b\b\b\b\b\b\b\bCOMPLETE\n'); +0067 +0068 % Plot the points +0069 figure(2); +0070 pcolor(ind1,ind2,shadowPrices1); +0071 xlabel(strrep(strcat(controlRxn1,' (mmol/g DW-hr)'),'_','\_')), ylabel(strrep(strcat(controlRxn2,' (mmol/g DW-hr)'),'_','\_')), zlabel('growth rate (1/hr)'); +0072 title(['Shadow price ' strrep(model.mets{metID1},'_','-')]); +0073 colorbar(); +0074 xticklabels(sprintfc('%d', -xticks)) +0075 yticklabels(sprintfc('%d', -yticks)) +0076 figure(3); +0077 pcolor(ind1,ind2,shadowPrices2); +0078 xlabel(strrep(strcat(controlRxn1,' (mmol/g DW-hr)'),'_','\_')), ylabel(strrep(strcat(controlRxn2,' (mmol/g DW-hr)'),'_','\_')), zlabel('growth rate (1/hr)'); +0079 title(['Shadow price ' strrep(model.mets{metID2},'_','-')]); +0080 colorbar(); +0081 xticklabels(sprintfc('%d', -xticks)) +0082 yticklabels(sprintfc('%d', -yticks)) +0083 figure(1); +0084 surfl(ind1,ind2,growthRates); +0085 xlabel(strrep(strcat(controlRxn1,' (mmol/g DW-hr)'),'_','\_')), ylabel(strrep(strcat(controlRxn2,' (mmol/g DW-hr)'),'_','\_')), zlabel('growth rate (1/hr)'); +0086 colormap(hsv(17)); +0087 xticklabels(sprintfc('%d', -xticks)) +0088 yticklabels(sprintfc('%d', -yticks)) +0089 end
    Generated by m2html © 2005
    \ No newline at end of file diff --git a/doc/core/runProductionEnvelope.html b/doc/core/runProductionEnvelope.html index e299243b..31f718cc 100644 --- a/doc/core/runProductionEnvelope.html +++ b/doc/core/runProductionEnvelope.html @@ -92,36 +92,34 @@

    SOURCE CODE ^'Creating production envelope... 0%% complete'); +0036 PB = ProgressBar2(length(biomassValues),'Creating production envelope','cli'); 0037 % Max/min for target production 0038 model = setParam(model,'obj',targetRxn,1); 0039 for i = 1:length(biomassValues) -0040 progress=pad(num2str(floor(i/numel(biomassValues)*100)),3,'left'); -0041 fprintf('\b\b\b\b\b\b\b\b\b\b\b\b\b%s%% complete',progress); -0042 model1 = setParam(model,'eq',biomassRxn,biomassValues(i)); -0043 sol = solveLP(model1,0,[],hsSol); -0044 if (sol.stat > 0) -0045 targetUpperBound(i) = sol.x(logical(model.c)); -0046 else -0047 targetUpperBound(i) = NaN; -0048 end -0049 model1.c = -model1.c; -0050 sol = solveLP(model1,0,[],hsSol); -0051 if (sol.stat > 0) -0052 targetLowerBound(i) = sol.x(logical(model1.c)); -0053 else -0054 targetLowerBound(i) = NaN; -0055 end -0056 end -0057 fprintf('\b\b\b\b\b\b\b\b\b\b\b\b\bCOMPLETE\n'); -0058 -0059 % Plot results -0060 plot([biomassValues fliplr(biomassValues)],[targetUpperBound fliplr(targetLowerBound)],'blue','LineWidth',2); -0061 axis tight; -0062 ylabel([strrep(targetRxn,'_','-') ' (mmol/gDW h)']); -0063 xlabel('Growth rate (1/h)'); -0064 targetValues = [targetLowerBound; targetUpperBound]; -0065 end +0040 model1 = setParam(model,'eq',biomassRxn,biomassValues(i)); +0041 sol = solveLP(model1,0,[],hsSol); +0042 if (sol.stat > 0) +0043 targetUpperBound(i) = sol.x(logical(model.c)); +0044 else +0045 targetUpperBound(i) = NaN; +0046 end +0047 model1.c = -model1.c; +0048 sol = solveLP(model1,0,[],hsSol); +0049 if (sol.stat > 0) +0050 targetLowerBound(i) = sol.x(logical(model1.c)); +0051 else +0052 targetLowerBound(i) = NaN; +0053 end +0054 count(PB); +0055 end +0056 +0057 % Plot results +0058 plot([biomassValues fliplr(biomassValues)],[targetUpperBound fliplr(targetLowerBound)],'blue','LineWidth',2); +0059 axis tight; +0060 ylabel([strrep(targetRxn,'_','-') ' (mmol/gDW h)']); +0061 xlabel('Growth rate (1/h)'); +0062 targetValues = [targetLowerBound; targetUpperBound]; +0063 end
    Generated by m2html © 2005
    \ No newline at end of file diff --git a/doc/core/runRobustnessAnalysis.html b/doc/core/runRobustnessAnalysis.html index 34e07da6..e339b889 100644 --- a/doc/core/runRobustnessAnalysis.html +++ b/doc/core/runRobustnessAnalysis.html @@ -115,27 +115,26 @@

    SOURCE CODE ^'Running robustness analysis... 0%% complete'); -0054 for i=1:length(controlFlux) -0055 progress=pad(num2str(floor(i/numel(controlFlux)*100)),3,'left'); -0056 fprintf('\b\b\b\b\b\b\b\b\b\b\b\b\b%s%% complete',progress); -0057 modelControlled = setParam(baseModel,'eq',controlRxnIdx,controlFlux(i)); -0058 solControlled = solveLP(modelControlled); -0059 objFlux(i) = solControlled.x(logical(modelControlled.c)); -0060 redCost(i) = solControlled.rCost(controlRxnIdx); +0053 +0054 PB = ProgressBar2(length(controlFlux),'Running robustness analysis','cli'); +0055 for i=1:length(controlFlux) +0056 modelControlled = setParam(baseModel,'eq',controlRxnIdx,controlFlux(i)); +0057 solControlled = solveLP(modelControlled); +0058 objFlux(i) = solControlled.x(logical(modelControlled.c)); +0059 redCost(i) = solControlled.rCost(controlRxnIdx); +0060 count(PB); 0061 end -0062 fprintf('\b\b\b\b\b\b\b\b\b\b\b\b\bCOMPLETE\n'); -0063 -0064 if plotRedCost -0065 yyaxis right -0066 plot(controlFlux,redCost) -0067 ylabel([strrep(controlRxn,'_','-') ' reduced cost']); -0068 yyaxis left -0069 end -0070 plot(controlFlux,objFlux) -0071 xlabel(strrep(controlRxn,'_','-')); -0072 ylabel('Objective'); -0073 end +0062 +0063 if plotRedCost +0064 yyaxis right +0065 plot(controlFlux,redCost) +0066 ylabel([strrep(controlRxn,'_','-') ' reduced cost']); +0067 yyaxis left +0068 end +0069 plot(controlFlux,objFlux) +0070 xlabel(strrep(controlRxn,'_','-')); +0071 ylabel('Objective'); +0072 end
    Generated by m2html © 2005
    \ No newline at end of file From f2c82781687f0cec4c1e8fe0862abf4c3a9e7588 Mon Sep 17 00:00:00 2001 From: Eduard Kerkhoven Date: Thu, 25 Apr 2024 16:52:05 +0200 Subject: [PATCH 19/23] refactor: predictLocalization builtin randsample --- core/predictLocalization.m | 119 ++++++++++++++++++++++++++ doc/core/predictLocalization.html | 135 ++++++++++++++++++++++++++++-- 2 files changed, 246 insertions(+), 8 deletions(-) diff --git a/core/predictLocalization.m b/core/predictLocalization.m index ccca5587..27da539d 100755 --- a/core/predictLocalization.m +++ b/core/predictLocalization.m @@ -1005,3 +1005,122 @@ transportCost=sum(transportCost(I)); score=geneScore-transportCost; end + +% To avoid dependency on stats toolbox, use this alternative implementation +% of randsample, source: +% https://github.com/gpeyre/numerical-tours/blob/dacee30081c04ef5f67b26b387ead85f2b193af9/matlab/toolbox_signal/randsample.m +function y = randsample(n, k, replace, w) +%RANDSAMPLE Random sample, with or without replacement. +% Y = RANDSAMPLE(N,K) returns Y as a vector of K values sampled uniformly +% at random, without replacement, from the integers 1:N. +% +% Y = RANDSAMPLE(POPULATION,K) returns K values sampled uniformly at +% random, without replacement, from the values in the vector POPULATION. +% +% Y = RANDSAMPLE(...,REPLACE) returns a sample taken with replacement if +% REPLACE is true, or without replacement if REPLACE is false (the default). +% +% Y = RANDSAMPLE(...,true,W) returns a weighted sample, using positive +% weights W, taken with replacement. W is often a vector of probabilities. +% This function does not support weighted sampling without replacement. +% +% Example: Generate a random sequence of the characters ACGT, with +% replacement, according to specified probabilities. +% +% R = randsample('ACGT',48,true,[0.15 0.35 0.35 0.15]) +% +% See also RAND, RANDPERM. + +% Copyright 1993-2008 The MathWorks, Inc. +% $Revision: 1.1.4.3 $ $Date: 2008/12/01 08:09:34 $ + +if nargin < 2 + error('stats:randsample:TooFewInputs','Requires two input arguments.'); +elseif numel(n) == 1 + population = []; +else + population = n; + n = numel(population); + if length(population)~=n + error('stats:randsample:BadPopulation','POPULATION must be a vector.'); + end +end + +if nargin < 3 + replace = false; +end + +if nargin < 4 + w = []; +elseif ~isempty(w) + if length(w) ~= n + if isempty(population) + error('stats:randsample:InputSizeMismatch',... + 'W must have length equal to N.'); + else + error('stats:randsample:InputSizeMismatch',... + 'W must have the same length as the population.'); + end + else + p = w(:)' / sum(w); + end +end + +switch replace + +% Sample with replacement +case {true, 'true', 1} + if isempty(w) + y = ceil(n .* rand(k,1)); + else + [dum, y] = histc(rand(k,1),[0 cumsum(p)]); + end + +% Sample without replacement +case {false, 'false', 0} + if k > n + if isempty(population) + error('stats:randsample:SampleTooLarge',... + 'K must be less than or equal to N for sampling without replacement.'); + else + error('stats:randsample:SampleTooLarge',... + 'K must be less than or equal to the population size.'); + end + end + + if isempty(w) + % If the sample is a sizeable fraction of the population, + % just randomize the whole population (which involves a full + % sort of n random values), and take the first k. + if 4*k > n + rp = randperm(n); + y = rp(1:k); + + % If the sample is a small fraction of the population, a full sort + % is wasteful. Repeatedly sample with replacement until there are + % k unique values. + else + x = zeros(1,n); % flags + sumx = 0; + while sumx < k + x(ceil(n * rand(1,k-sumx))) = 1; % sample w/replacement + sumx = sum(x); % count how many unique elements so far + end + y = find(x > 0); + y = y(randperm(k)); + end + else + error('stats:randsample:NoWeighting',... + 'Weighted sampling without replacement is not supported.'); + end +otherwise + error('stats:randsample:BadReplaceValue',... + 'REPLACE must be either true or false.'); +end + +if ~isempty(population) + y = population(y); +else + y = y(:); +end +end diff --git a/doc/core/predictLocalization.html b/doc/core/predictLocalization.html index 64bc0214..d51c94ac 100644 --- a/doc/core/predictLocalization.html +++ b/doc/core/predictLocalization.html @@ -100,7 +100,7 @@

    CROSS-REFERENCE INFORMATION ^
 
 <h2><a name=SUBFUNCTIONS ^

    +
  • function [S, g2c]=moveGene(S,model,g2c,geneToMove,toComp,nRxns,nMets)
  • function unconnected=findUnconnected(S,nEM,metsToCheck)
  • function [geneIndex, moveTo, deltaConnected, deltaScore]=selectGenes(S,nEM,nMets,nER,nRxns,model,unconnected,g2c,GSS)
  • function S=addTransport(S,nRxns,nER,nMets,nEM,nComps,metA,metB)
  • function [score, geneScore, transportCost]=scoreModel(S,g2c,GSS,transportCost)
  • function y = randsample(n, k, replace, w)
  • SOURCE CODE ^

    0001 function [outModel, geneLocalization, transportStruct, scores,...
    @@ -503,12 +503,12 @@ 

    SOURCE CODE ^%formulation never moves a gene from its best compartment. Therefore a 0399 %small uniform weight is added 0400 [I, J]=find(g2c); -0401 geneToMove=randsample(nGenes,1,true,max(GSS.scores(I,:),[],2)-GSS.scores(sub2ind(size(g2c),I,J))+0.1); +0401 geneToMove=randsample(nGenes,1,true,max(GSS.scores(I,:),[],2)-GSS.scores(sub2ind(size(g2c),I,J))+0.1); 0402 0403 %Sample among possible compartments to move to. Add a larger weight to 0404 %even out the odds a little. Also a way of getting rid of loops where 0405 %the same set of genes are moved back and forth several times -0406 toComp=randsample(nComps,1,true,GSS.scores(geneToMove,:)+0.2); +0406 toComp=randsample(nComps,1,true,GSS.scores(geneToMove,:)+0.2); 0407 0408 %Check that it moves to a new compartment 0409 if toComp==find(g2c(geneToMove,:)) @@ -555,7 +555,7 @@

    SOURCE CODE ^else 0451 %Choose a random unconnected metabolite that should be 0452 %connected -0453 transMet=unconnected(randsample(numel(unconnected),1)); +0453 transMet=unconnected(randsample(numel(unconnected),1)); 0454 0455 %First get where the metabolite is now 0456 comps=ceil((transMet-nEM)/((size(S,1)-nEM)/nComps)); @@ -589,13 +589,13 @@

    SOURCE CODE ^%If transMet is in the default compartment then everything 0485 %is fine, just connect it to a random one 0486 if transMet==dcIndex -0487 newS=addTransport(newS,nRxns,nER,nMets,nEM,nComps,transMet,connectedUsed(randsample(numel(connectedUsed),1))); +0487 newS=addTransport(newS,nRxns,nER,nMets,nEM,nComps,transMet,connectedUsed(randsample(numel(connectedUsed),1))); 0488 else 0489 %If one of the connectedUsed is in the default 0490 %compartment then connect to that one 0491 I=connectedUsed(connectedUsed<(nMets+nEM)); 0492 if any(I) -0493 newS=addTransport(newS,nRxns,nER,nMets,nEM,nComps,transMet,I(randsample(numel(I),1))); +0493 newS=addTransport(newS,nRxns,nER,nMets,nEM,nComps,transMet,I(randsample(numel(I),1))); 0494 else 0495 %This is if the only way to connect it is by adding 0496 %two transport reactions, going via the default @@ -1019,7 +1019,7 @@

    SOURCE CODE ^if numel(genes)>25 -0917 rGenes=genes(randsample(numel(genes),min(numel(genes),25),true,modGeneScores)); +0917 rGenes=genes(randsample(numel(genes),min(numel(genes),25),true,modGeneScores)); 0918 0919 %The sampling with weights could give duplicates 0920 rGenes=unique(rGenes); @@ -1109,7 +1109,126 @@

    SOURCE CODE ^end

    +1007 end +1008 +1009 % To avoid dependency on stats toolbox, use this alternative implementation +1010 % of randsample, source: +1011 % https://github.com/gpeyre/numerical-tours/blob/dacee30081c04ef5f67b26b387ead85f2b193af9/matlab/toolbox_signal/randsample.m +1012 function y = randsample(n, k, replace, w) +1013 %RANDSAMPLE Random sample, with or without replacement. +1014 % Y = RANDSAMPLE(N,K) returns Y as a vector of K values sampled uniformly +1015 % at random, without replacement, from the integers 1:N. +1016 % +1017 % Y = RANDSAMPLE(POPULATION,K) returns K values sampled uniformly at +1018 % random, without replacement, from the values in the vector POPULATION. +1019 % +1020 % Y = RANDSAMPLE(...,REPLACE) returns a sample taken with replacement if +1021 % REPLACE is true, or without replacement if REPLACE is false (the default). +1022 % +1023 % Y = RANDSAMPLE(...,true,W) returns a weighted sample, using positive +1024 % weights W, taken with replacement. W is often a vector of probabilities. +1025 % This function does not support weighted sampling without replacement. +1026 % +1027 % Example: Generate a random sequence of the characters ACGT, with +1028 % replacement, according to specified probabilities. +1029 % +1030 % R = randsample('ACGT',48,true,[0.15 0.35 0.35 0.15]) +1031 % +1032 % See also RAND, RANDPERM. +1033 +1034 % Copyright 1993-2008 The MathWorks, Inc. +1035 % $Revision: 1.1.4.3 $ $Date: 2008/12/01 08:09:34 $ +1036 +1037 if nargin < 2 +1038 error('stats:randsample:TooFewInputs','Requires two input arguments.'); +1039 elseif numel(n) == 1 +1040 population = []; +1041 else +1042 population = n; +1043 n = numel(population); +1044 if length(population)~=n +1045 error('stats:randsample:BadPopulation','POPULATION must be a vector.'); +1046 end +1047 end +1048 +1049 if nargin < 3 +1050 replace = false; +1051 end +1052 +1053 if nargin < 4 +1054 w = []; +1055 elseif ~isempty(w) +1056 if length(w) ~= n +1057 if isempty(population) +1058 error('stats:randsample:InputSizeMismatch',... +1059 'W must have length equal to N.'); +1060 else +1061 error('stats:randsample:InputSizeMismatch',... +1062 'W must have the same length as the population.'); +1063 end +1064 else +1065 p = w(:)' / sum(w); +1066 end +1067 end +1068 +1069 switch replace +1070 +1071 % Sample with replacement +1072 case {true, 'true', 1} +1073 if isempty(w) +1074 y = ceil(n .* rand(k,1)); +1075 else +1076 [dum, y] = histc(rand(k,1),[0 cumsum(p)]); +1077 end +1078 +1079 % Sample without replacement +1080 case {false, 'false', 0} +1081 if k > n +1082 if isempty(population) +1083 error('stats:randsample:SampleTooLarge',... +1084 'K must be less than or equal to N for sampling without replacement.'); +1085 else +1086 error('stats:randsample:SampleTooLarge',... +1087 'K must be less than or equal to the population size.'); +1088 end +1089 end +1090 +1091 if isempty(w) +1092 % If the sample is a sizeable fraction of the population, +1093 % just randomize the whole population (which involves a full +1094 % sort of n random values), and take the first k. +1095 if 4*k > n +1096 rp = randperm(n); +1097 y = rp(1:k); +1098 +1099 % If the sample is a small fraction of the population, a full sort +1100 % is wasteful. Repeatedly sample with replacement until there are +1101 % k unique values. +1102 else +1103 x = zeros(1,n); % flags +1104 sumx = 0; +1105 while sumx < k +1106 x(ceil(n * rand(1,k-sumx))) = 1; % sample w/replacement +1107 sumx = sum(x); % count how many unique elements so far +1108 end +1109 y = find(x > 0); +1110 y = y(randperm(k)); +1111 end +1112 else +1113 error('stats:randsample:NoWeighting',... +1114 'Weighted sampling without replacement is not supported.'); +1115 end +1116 otherwise +1117 error('stats:randsample:BadReplaceValue',... +1118 'REPLACE must be either true or false.'); +1119 end +1120 +1121 if ~isempty(population) +1122 y = population(y); +1123 else +1124 y = y(:); +1125 end +1126 end
    Generated by m2html © 2005
    \ No newline at end of file From 5af66b4c740f2fa8b60278eb0072750c97402461 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Simonas=20Marci=C5=A1auskas?= <11994076+simas232@users.noreply.github.com> Date: Fri, 26 Apr 2024 10:34:58 +0200 Subject: [PATCH 20/23] fix: mapCompartments correct horizontal concatenation also updated documentation --- core/mapCompartments.m | 2 +- doc/core/mapCompartments.html | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/core/mapCompartments.m b/core/mapCompartments.m index 0e93eff0..dfb8034f 100755 --- a/core/mapCompartments.m +++ b/core/mapCompartments.m @@ -69,7 +69,7 @@ %Check that there are no compartments in the rules that are not in the %geneScoreStructure. uComps=upper(geneScoreStructure.compartments); -J=[uComps;{'OTHER'}]; +J=[uComps,{'OTHER'}]; if ~isempty(setdiff([toKeep;toMerge],J)) EM='There are compartment in the rules that are not in geneScoreStructure.compartments'; diff --git a/doc/core/mapCompartments.html b/doc/core/mapCompartments.html index f54e3c59..f7860895 100644 --- a/doc/core/mapCompartments.html +++ b/doc/core/mapCompartments.html @@ -120,7 +120,7 @@

    SOURCE CODE ^%Check that there are no compartments in the rules that are not in the 0070 %geneScoreStructure. 0071 uComps=upper(geneScoreStructure.compartments); -0072 J=[uComps;{'OTHER'}]; +0072 J=[uComps,{'OTHER'}]; 0073 0074 if ~isempty(setdiff([toKeep;toMerge],J)) 0075 EM='There are compartment in the rules that are not in geneScoreStructure.compartments'; From b2ded2ecc77bf3958acb3f4c6e660ea88919c013 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Simonas=20Marci=C5=A1auskas?= <11994076+simas232@users.noreply.github.com> Date: Fri, 26 Apr 2024 11:12:24 +0200 Subject: [PATCH 21/23] feat: give execution rights in Terminal for new RAVEN functions --- core/convertCharArray.m | 0 core/findRAVENroot.m | 0 core/getGenesFromGrRules.m | 0 core/parallelPoolRAVEN.m | 0 core/printOrange.m | 0 core/runDynamicFBA.m | 0 core/runPhenotypePhasePlane.m | 0 core/runProductionEnvelope.m | 0 core/runRobustnessAnalysis.m | 0 core/runSimpleOptKnock.m | 0 external/kegg/getWSLpath.m | 0 installation/removeRavenFromPath.m | 0 io/readYAMLmodel.m | 0 io/writeYAMLmodel.m | 0 testing/manual_tests/ManualINITTests.m | 0 testing/unit_tests/checkTasksTests.m | 0 testing/unit_tests/fillGapsLargeTests.m | 0 testing/unit_tests/fillGapsSmallTests.m | 0 testing/unit_tests/importExportTests.m | 0 testing/unit_tests/miriamTests.m | 0 testing/unit_tests/modelAbilitiesTests.m | 0 testing/unit_tests/modelConversionTests.m | 0 testing/unit_tests/modelCurationTests.m | 0 testing/unit_tests/modelSortingTests.m | 0 testing/unit_tests/solverTests.m | 0 25 files changed, 0 insertions(+), 0 deletions(-) mode change 100644 => 100755 core/convertCharArray.m mode change 100644 => 100755 core/findRAVENroot.m mode change 100644 => 100755 core/getGenesFromGrRules.m mode change 100644 => 100755 core/parallelPoolRAVEN.m mode change 100644 => 100755 core/printOrange.m mode change 100644 => 100755 core/runDynamicFBA.m mode change 100644 => 100755 core/runPhenotypePhasePlane.m mode change 100644 => 100755 core/runProductionEnvelope.m mode change 100644 => 100755 core/runRobustnessAnalysis.m mode change 100644 => 100755 core/runSimpleOptKnock.m mode change 100644 => 100755 external/kegg/getWSLpath.m mode change 100644 => 100755 installation/removeRavenFromPath.m mode change 100644 => 100755 io/readYAMLmodel.m mode change 100644 => 100755 io/writeYAMLmodel.m mode change 100644 => 100755 testing/manual_tests/ManualINITTests.m mode change 100644 => 100755 testing/unit_tests/checkTasksTests.m mode change 100644 => 100755 testing/unit_tests/fillGapsLargeTests.m mode change 100644 => 100755 testing/unit_tests/fillGapsSmallTests.m mode change 100644 => 100755 testing/unit_tests/importExportTests.m mode change 100644 => 100755 testing/unit_tests/miriamTests.m mode change 100644 => 100755 testing/unit_tests/modelAbilitiesTests.m mode change 100644 => 100755 testing/unit_tests/modelConversionTests.m mode change 100644 => 100755 testing/unit_tests/modelCurationTests.m mode change 100644 => 100755 testing/unit_tests/modelSortingTests.m mode change 100644 => 100755 testing/unit_tests/solverTests.m diff --git a/core/convertCharArray.m b/core/convertCharArray.m old mode 100644 new mode 100755 diff --git a/core/findRAVENroot.m b/core/findRAVENroot.m old mode 100644 new mode 100755 diff --git a/core/getGenesFromGrRules.m b/core/getGenesFromGrRules.m old mode 100644 new mode 100755 diff --git a/core/parallelPoolRAVEN.m b/core/parallelPoolRAVEN.m old mode 100644 new mode 100755 diff --git a/core/printOrange.m b/core/printOrange.m old mode 100644 new mode 100755 diff --git a/core/runDynamicFBA.m b/core/runDynamicFBA.m old mode 100644 new mode 100755 diff --git a/core/runPhenotypePhasePlane.m b/core/runPhenotypePhasePlane.m old mode 100644 new mode 100755 diff --git a/core/runProductionEnvelope.m b/core/runProductionEnvelope.m old mode 100644 new mode 100755 diff --git a/core/runRobustnessAnalysis.m b/core/runRobustnessAnalysis.m old mode 100644 new mode 100755 diff --git a/core/runSimpleOptKnock.m b/core/runSimpleOptKnock.m old mode 100644 new mode 100755 diff --git a/external/kegg/getWSLpath.m b/external/kegg/getWSLpath.m old mode 100644 new mode 100755 diff --git a/installation/removeRavenFromPath.m b/installation/removeRavenFromPath.m old mode 100644 new mode 100755 diff --git a/io/readYAMLmodel.m b/io/readYAMLmodel.m old mode 100644 new mode 100755 diff --git a/io/writeYAMLmodel.m b/io/writeYAMLmodel.m old mode 100644 new mode 100755 diff --git a/testing/manual_tests/ManualINITTests.m b/testing/manual_tests/ManualINITTests.m old mode 100644 new mode 100755 diff --git a/testing/unit_tests/checkTasksTests.m b/testing/unit_tests/checkTasksTests.m old mode 100644 new mode 100755 diff --git a/testing/unit_tests/fillGapsLargeTests.m b/testing/unit_tests/fillGapsLargeTests.m old mode 100644 new mode 100755 diff --git a/testing/unit_tests/fillGapsSmallTests.m b/testing/unit_tests/fillGapsSmallTests.m old mode 100644 new mode 100755 diff --git a/testing/unit_tests/importExportTests.m b/testing/unit_tests/importExportTests.m old mode 100644 new mode 100755 diff --git a/testing/unit_tests/miriamTests.m b/testing/unit_tests/miriamTests.m old mode 100644 new mode 100755 diff --git a/testing/unit_tests/modelAbilitiesTests.m b/testing/unit_tests/modelAbilitiesTests.m old mode 100644 new mode 100755 diff --git a/testing/unit_tests/modelConversionTests.m b/testing/unit_tests/modelConversionTests.m old mode 100644 new mode 100755 diff --git a/testing/unit_tests/modelCurationTests.m b/testing/unit_tests/modelCurationTests.m old mode 100644 new mode 100755 diff --git a/testing/unit_tests/modelSortingTests.m b/testing/unit_tests/modelSortingTests.m old mode 100644 new mode 100755 diff --git a/testing/unit_tests/solverTests.m b/testing/unit_tests/solverTests.m old mode 100644 new mode 100755 From 5f723c7ab5c1b12aa0969427c6f498903f77b46f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Simonas=20Marci=C5=A1auskas?= <11994076+simas232@users.noreply.github.com> Date: Fri, 26 Apr 2024 11:28:54 +0200 Subject: [PATCH 22/23] doc: update GLPK readme file --- software/GLPKmex/README | 9 -- software/GLPKmex/README.md | 163 +++++++++++++++++++++++++++++++++++++ 2 files changed, 163 insertions(+), 9 deletions(-) delete mode 100644 software/GLPKmex/README create mode 100644 software/GLPKmex/README.md diff --git a/software/GLPKmex/README b/software/GLPKmex/README deleted file mode 100644 index 034da68d..00000000 --- a/software/GLPKmex/README +++ /dev/null @@ -1,9 +0,0 @@ -# These builds were made against GLPK 4.40 by Benoît Legat and Mélanie Sedda - -#to use one of these versions of glpkmex, copy the compiled the approiate verions -of glpkcc.mex to your glpkmex directory. - -please see their git-hub repositroy for any recent changes or more info: -https://github.com/blegat/glpkmex/ - - diff --git a/software/GLPKmex/README.md b/software/GLPKmex/README.md new file mode 100644 index 00000000..9fb2a746 --- /dev/null +++ b/software/GLPKmex/README.md @@ -0,0 +1,163 @@ +# GLPKMEX + +GLPKMEX is a Matlab MEX Interface for the GLPK library developed by +Andrew Makhorin. GLPKMEX is developed by Nicolo' Giorgetti, email +giorgetti at ieee.org. +GLPK is currently being mantained by Niels Klitgord, email +niels at bu.edu. + +This version is maintained by Benoît Legat, email +benoit.legat at gmail.com. + +To install mps2mat.py script, please see INSTALL_mps2mat file. + +## Precompiled binaries + +You don't need to compile GLPKMEX by yourself nor install GLPK. +They are both compiled into `glpkcc.mex*` files. + +* `a64` is for Linux 64 bits +* `glx` is for Linux 32 bits +* `maci64` is for Mac OS 64 bits +* `w32` is for Windows 32 bits (in the win32 subdir) +* `w64` is for Windows 64 bits (in the win64 subdir) + +On Linux 64 bits and Windows 64 bits, GLPK v4.62 is used, but Linux 32 bits and Mac OS versions use GLPK v4.48 (see [this issue](https://github.com/blegat/glpkmex/issues/3)). + +Extension | OS | Architecture | GLPK version | +--------- | ------- | ------------ | ------------ | +`a64` | Linux | 64 bits | v4.62 | +`glx` | Linux | 32 bits | v4.48 | +`maci64` | Mac OS | 64 bits | v4.48 | +`w32` | Windows | 32 bits | v4.60 | +`w64` | Windows | 64 bits | v4.62 | + +## Quick installation instructions + +Open MATLAB (for GNU/Linux user, you will need roots privileges so open a terminal (`CTRL+ALT+T`) and enter `sudo matlab` or `sudo matlab -glnx86` if you have problems with architecture (see [this wiki](https://help.ubuntu.com/community/MATLAB))). +Then click on _File/Set Path..._ and add the path to where you +put __glpkmex__. Then hit save. +For GNU/Linux users, you can now quit MATLAB, don't run it with `sudo` again except for _Set Path..._. + +To check everything, try the two commands below in MATLAB + + >> glpktest1 + >> glpktest2 +which should output a file `SimpleLP.mps` without error. + +## Instructions for compiling from source + +### Standard installation procedure (suitable for most 32-bit linux/windows users) + +1. Download and install GLPK version 4.60 or higher: + http://ftp.gnu.org/gnu/glpk/ + +2. Start Matlab and run makeglpkmex.m. Specify correct path to both GLPK + directory and eventually to the GLPK include and library directories. + +3. Test the interface on the examples included (`glpktest1.m`, `glpktest2.m`, `glpksparse.m`). Everything should works fine. + +### Linux 64bit machine +Niels's Install Notes + +1. if you plan on compling glpk with gmp, recompile gmp with `CFLAGS+=-fPIC`. Then recompile `glpk-4.60` (or newer) with `CFLAGS+=-fPIC`. + This is do deal with a weird issue with ld in 64bit format + +2. Directly compile glpkmex with (default): + + mex -I/include glpkcc.cpp /libglpk.a + +(with gmp compiled into glpk and large arrays (64bit stuff...)): + + mex -largeArrayDims -I/include glpkcc.cpp /libglpk.a /libgmp.a + +**note -largArrayDims is optional, but allows matlab to use large arrays with glpk on 64bit machines** + +this particular pipeline has worked for me on a number of different 64bit linux boxes: + +1. in the linux comandline cd to glpk dir +2. run (**note: update the dir install dir if you want, but be sure to do the same below**): + + make clean + ./configure + make CFLAGS+=-fPIC + make check + make prefix=/usr/local install + +3. cd glpkmex dir +4. run from the comand line: + + mex -largeArrayDims -I/usr/local/include glpkcc.cpp /usr/local/lib/libglpk.a + +5. start matlab, add glpkmex dir to path and run glpktest1 and glpktest2 in matlab environment. if these work you should be good to go. + +### Install GLPK on 64bit Linux with 32bit MATLAB +First, you will need to install GLPK. +Get the source [here](http://ftp.gnu.org/gnu/glpk/), unpack it with the ''Archive Manager'' and then open a terminal and go in the folder where you un packed it (for example, if it is in download, run `cd ~/Downloads/glpk-4.60`) +Then run + + make clean + ./configure --build=i686-pc-linux-gnu "CFLAGS=-m32" "CXXFLAGS=-m32" "LDFLAGS=-m32" + make CFLAGS+=-fPIC + make check + make prefix=/usr/local install +The `CFLAGS+=-fPIC` is needed if you plan to install it in 64 bits with gmp (if you're not sure, just use it). +The ` --build=i686-pc-linux-gnu "CFLAGS=-m32" "CXXFLAGS=-m32" "LDFLAGS=-m32"` is needed if you are running MATLAB 32 bits on a 64 bits machine. + +Open MATLAB and navigate to the folder of GLPKMEX and run + + mex CXXFLAGS='$CXXFLAGS -m32' -I/usr/local/include glpkcc.cpp /usr/local/lib/libglpk.a + +Only use `CXXFLAGS='$CXXFLAGS -m32'` if you have a 32 bits MATLAB. +I don't understand why it needs this option since `mex` is run inside MATLAB so it should know that it is in 32 bits however it is needed for me. + +### Installing on a PC +1. if you used winglpk, you still need to compile the `glpk.lib` file. + to do this go to w32 or w64 folder in winglpk and run `Build_GLPK_with_VC9.bat`. + see the `readme.txt` file in w32 or w64 for more details on how to do this. +2. note windows uses `.lib`, not `.a` files so change `libglpk.a` to `glpk.lib` (simular for gmp if used) +3. full paths to directions (like include) often need to be in quotes. + ex: + + mex -I'C:\\some path\include' glpkcc.cpp 'C:\\some other path\glpk.lib' + +### Installing with cygwin (alternate method on a pc): +Requirements: +A) The last version of cygwin, downloadable from http://www.cygwin.com + (or download mingw) +B) Gnumex: http://gnumex.sourceforge.net/ + +1. Download GLPK and install it by specifying CFLAGS="-O3 -mno-cygwin" as + argument of make, i.e.: + + ./configure; + make CFLAGS="-O3 -mno-cygwin" + make install + This avoid to build a glpk library which needs of cygwin1.dll to run. + +2. Start Matlab and run gnumex. Make a mexopts.bat with option 'cygwin-mingw' if + you are using cygwin or 'mingw' if you are using mingw. + +3. run makeglpkmex.m. Specify correct path to GLPK directory and eventually to + the GLPK include and library directories. Moreover, you have to specify the + location of mexopts.bat file generated at step 2). + +4. Test the interface on the examples included (glpktest1.m, glpktest2.m, + glpksparse.m). Everything should works fine. + + +### Installing on a MAC +On mac, it works out of the box with the file `glpkmex.mexmaci64`. +It was compiled with glpk-4.60. + +However, if you want to compile by yourself for whatever reason. +I'd like to mention that everything worked as expected for me except for mex for which +I had to change the compiler from gcc-4.2 to gcc and I had to remove `-syslibroot /Developer/SDKs/MacOSX10.6.sdk` +So here is the command I had to enter in MATLAB: + + mex -largeArrayDims -I/usr/local/include glpkcc.cpp /usr/local/lib/libglpk.a -v CC='gcc' CXX='g++' CFLAGS='-fno-common -no-cpp-precomp -arch x86_64 -mmacosx-version-min=10.5 -fexceptions' CXXFLAGS='-fno-common -no-cpp-precomp -fexceptions -arch x86_64 -mmacosx-version-min=10.5' LD='gcc' LDFLAGS='-Wl,-twolevel_namespace -undefined error -arch x86_64 -Wl -mmacosx-version-min=10.5 -bundle -Wl,-exported_symbols_list,/Applications/MATLAB_R2012a_Student.app/extern/lib/maci64/mexFunction.map' + +Another special notes for installing on a Mac,( worked for Leapard ) +add GLPK lib install directory to your DYLD_LIBRARY_PATH shell variable (before you start matlab) +example: 'export DYLD_LIBRARY_PATH=/usr/local/lib:$DYLD_LIBRARY_PATH' in .bashrc +continue as above for linux install. From 9bc343ff1254d77a69bdf897290b4d0876426b72 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Simonas=20Marci=C5=A1auskas?= <11994076+simas232@users.noreply.github.com> Date: Fri, 26 Apr 2024 11:33:33 +0200 Subject: [PATCH 23/23] feat: add GLPK compatibility with Apple Silicon --- software/GLPKmex/glpkcc.mexmaca64 | Bin 0 -> 1200992 bytes software/versions.txt | 3 ++- 2 files changed, 2 insertions(+), 1 deletion(-) create mode 100755 software/GLPKmex/glpkcc.mexmaca64 diff --git a/software/GLPKmex/glpkcc.mexmaca64 b/software/GLPKmex/glpkcc.mexmaca64 new file mode 100755 index 0000000000000000000000000000000000000000..e189f7ab624ecea35ba3c1874cfda8a091bc60d2 GIT binary patch literal 1200992 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

    D-;S*O;hQ~pDL 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

    x=J>A`YiTKwDXOC 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

    4kZ(_&f26*~vbAZTF1AcI*2>_&*)V*;GQaP~ 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%0Ana>ry?E35$ci@unGa*u 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

    ;0 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