From 079ae8ba0c4e0de4fc7ec5402f775065ed890ae0 Mon Sep 17 00:00:00 2001 From: Eduard Kerkhoven Date: Thu, 1 Aug 2024 00:40:34 +0200 Subject: [PATCH 1/3] feat: keep track of kcat curations (#385) * doc: README.md MATLAB badge * fix: setKcatForReactions correct source field * feat: sensitivityTuning note of preTuneKcat * doc: adapterTemplate set reviewed to false by default allow for more uniprot protein matches * fix: update tutorial ecYeastGEM.yml * doc: clarify params.enzyme_comp in model adapter --- README.md | 10 +- .../change_model/applyKcatConstraints.html | 3 +- .../change_model/setKcatForReactions.html | 2 +- .../sensitivityTuning.html | 263 ++++++++++-------- .../model_adapter/adapterTemplate.html | 2 +- .../change_model/applyKcatConstraints.m | 1 - .../change_model/setKcatForReactions.m | 2 +- .../sensitivityTuning.m | 15 +- src/geckomat/model_adapter/adapterTemplate.m | 7 +- .../manual_tests/TestYeastGEMSimpleWorkflow.m | 4 +- tutorials/full_ecModel/YeastGEMAdapter.m | 4 + tutorials/full_ecModel/models/ecYeastGEM.yml | 23 +- tutorials/light_ecModel/HumanGEMAdapter.m | 4 + 13 files changed, 192 insertions(+), 148 deletions(-) diff --git a/README.md b/README.md index d7c451e7f..62fdeaa83 100644 --- a/README.md +++ b/README.md @@ -1,14 +1,16 @@ -![Current version](https://badge.fury.io/gh/sysbiochalmers%2Fgecko.svg) +[![Current release](https://img.shields.io/github/release/SysBioChalmers/GECKO/all.svg)](https://GitHub.com/SysBioChalmers/GECKO/releases/) [![GitHub Discussions](https://img.shields.io/github/discussions-search?query=repo%3Asysbiochalmers%2Fgecko&label=GitHub%20Discussions)](https://github.com/SysBioChalmers/GECKO/discussions) [![Zenodo](https://zenodo.org/badge/DOI/10.5281/zenodo.7699818.svg)](https://doi.org/10.5281/zenodo.7699818) +[![MATLAB File Exchange](https://www.mathworks.com/matlabcentral/images/matlab-file-exchange.svg)](https://se.mathworks.com/matlabcentral/fileexchange/125960-gecko-toolbox) -## About GECKO 3.0 + +## About GECKO 3 The **GECKO** toolbox enhances a **G**enome-scale model to account for **E**nzyme **C**onstraints, using **K**inetics and **O**mics. The resulting enzyme-constrained model (**ecModel**) can be used to perform simulations where enzyme allocation is either drawn from a total protein pool, or constrained by measured protein levels from proteomics data. -💡 In the [`GECKO/tutorials`](https://github.com/SysBioChalmers/GECKO/tree/main/tutorials) folder there are examples of how GECKO can be applied to GEMs, in either of its _full_ or _light_ forms. Each `protocol.m` contains instructions on how to reconstruct and analyze an ecModel, demonstrating how different fuctions in GECKO can be used. These two scripts complement the [protocols paper](#citation). +💡 In the [`GECKO/tutorials`](https://github.com/SysBioChalmers/GECKO/tree/main/tutorials) folder there are examples of how GECKO can be applied to GEMs, in either of its _full_ or _light_ forms. Each `protocol.m` contains instructions on how to reconstruct and analyze an ecModel, demonstrating how different fuctions in GECKO can be used. These two scripts complement the [Nature Protocols](https://doi.org/10.1038/s41596-023-00931-7) paper ([**PDF**](https://drive.google.com/file/d/1_AGz6GmQPOyshfUZ6K-L2myzU43rQ6tu/view)). ### Significant changes since protocol publication - GECKO **3.2.0**: all protein usage reactions draw from the protein pool, even if they are constrained by proteomics data. This affects **Step 58** in the protocol, changing behaviour of `constrainEnzConcs` and making `updateProtPool` obsolete, `tutorials/full_ecModel/protocol.m` is updated to reflect this change. See [#357](https://github.com/SysBioChalmers/GECKO/issues/375) for more details. @@ -19,7 +21,7 @@ _**Note:** Regarding code and model compatibility with earlier GECKO versions, s If you have used GECKO in your work, please cite: -> Chen Y, Gustafsson J, Tafur Rangel A, Anton M, Domenzain I, Kittikunapong C, Li F, Yuan L, Nielsen J, Kerkhoven EJ. Reconstruction, simulation and analysis of enzyme-constrained metabolic models using GECKO Toolbox 3.0. Nature Protocols. 2024 Jan 18:1-39. doi: [10.1038/s41596-023-00931-7](https://doi.org/10.1038/s41596-023-00931-7) +> Chen Y, Gustafsson J, Tafur Rangel A, Anton M, Domenzain I, Kittikunapong C, Li F, Yuan L, Nielsen J & Kerkhoven EJ. Reconstruction, simulation and analysis of enzyme-constrained metabolic models using GECKO Toolbox 3.0. *Nature Protocols* **19**, 629-667 (2024). doi:[10.1038/s41596-023-00931-7](https://doi.org/10.1038/s41596-023-00931-7). ## Documentation **Installation instructions** and other information is available in the **[Wiki](https://github.com/SysBioChalmers/GECKO/wiki)**. The source code documentation is also available diff --git a/doc/src/geckomat/change_model/applyKcatConstraints.html b/doc/src/geckomat/change_model/applyKcatConstraints.html index 5f6114c79..f87a2f1e3 100644 --- a/doc/src/geckomat/change_model/applyKcatConstraints.html +++ b/doc/src/geckomat/change_model/applyKcatConstraints.html @@ -177,8 +177,7 @@

SOURCE CODE ^end 0117 end -0118 end -0119 +0118 end
Generated by m2html © 2005
\ No newline at end of file diff --git a/doc/src/geckomat/change_model/setKcatForReactions.html b/doc/src/geckomat/change_model/setKcatForReactions.html index 114a9f0bd..cdcb9ea1e 100644 --- a/doc/src/geckomat/change_model/setKcatForReactions.html +++ b/doc/src/geckomat/change_model/setKcatForReactions.html @@ -113,7 +113,7 @@

SOURCE CODE ^end 0048 end 0049 ecModel.ec.kcat(rxnsToChange) = kcat; -0050 ecModel.ec.source(rxnsToChange) = {'from setKcatForReactions'}; +0050 ecModel.ec.source(rxnsToChange) = {'setKcatForReactions'}; 0051 end
Generated by m2html © 2005
diff --git a/doc/src/geckomat/kcat_sensitivity_analysis/sensitivityTuning.html b/doc/src/geckomat/kcat_sensitivity_analysis/sensitivityTuning.html index 7d71baf63..411721bc7 100644 --- a/doc/src/geckomat/kcat_sensitivity_analysis/sensitivityTuning.html +++ b/doc/src/geckomat/kcat_sensitivity_analysis/sensitivityTuning.html @@ -55,6 +55,10 @@

DESCRIPTION ^SOURCE CODE ^% oldKcat kcat values in the input model 0028 % newKcat kcat values in the output model, after tuning 0029 % -0030 % Usage: -0031 % [model, tunedKcats] = sensitivityTuning(model, desiredGrowthRate, modelAdapter, foldChange, protToIgnore, verbose) -0032 -0033 if nargin < 6 || isempty(verbose) -0034 verbose = true; -0035 end -0036 if nargin < 5 || isempty(protToIgnore) -0037 protToIgnore = {}; -0038 end -0039 if nargin < 4 || isempty(foldChange) -0040 foldChange = 10; -0041 end -0042 if nargin < 3 || isempty(modelAdapter) -0043 modelAdapter = ModelAdapterManager.getDefault(); -0044 if isempty(modelAdapter) -0045 error('Either send in a modelAdapter or set the default model adapter in the ModelAdapterManager.') -0046 end -0047 end -0048 params = modelAdapter.params; -0049 if nargin < 2 || isempty(desiredGrowthRate) -0050 desiredGrowthRate = params.gR_exp; +0030 % Note: The model.ec.notes field will contain the original kcat value and +0031 % source, unless the kcat has previously been set by sensitivityTuning, in +0032 % which case the notes field remains unchanged. +0033 % +0034 % Usage: +0035 % [model, tunedKcats] = sensitivityTuning(model, desiredGrowthRate, modelAdapter, foldChange, protToIgnore, verbose) +0036 +0037 if nargin < 6 || isempty(verbose) +0038 verbose = true; +0039 end +0040 if nargin < 5 || isempty(protToIgnore) +0041 protToIgnore = {}; +0042 end +0043 if nargin < 4 || isempty(foldChange) +0044 foldChange = 10; +0045 end +0046 if nargin < 3 || isempty(modelAdapter) +0047 modelAdapter = ModelAdapterManager.getDefault(); +0048 if isempty(modelAdapter) +0049 error('Either send in a modelAdapter or set the default model adapter in the ModelAdapterManager.') +0050 end 0051 end -0052 -0053 kcatList = []; -0054 m = model; -0055 m.c = double(strcmp(m.rxns, params.bioRxn));% Make sure that growth is maximized +0052 params = modelAdapter.params; +0053 if nargin < 2 || isempty(desiredGrowthRate) +0054 desiredGrowthRate = params.gR_exp; +0055 end 0056 -0057 [res,hs] = solveLP(m); -0058 if isempty(res.x) -0059 error('FBA of input model gives no valid result. Reduce protein pool constraint with setProtPoolSize and/or check if exchange constraints are correctly defined.') -0060 end -0061 lastGrowth = 0; -0062 if ~m.ec.geckoLight -0063 %for the full model, we first find the draw reaction with the most flux -0064 drawRxns = startsWith(m.rxns, 'usage_prot_'); -0065 idxToIgnore = cellfun(@(x) find(strcmpi(model.rxns, ['usage_prot_' x])), protToIgnore); -0066 iteration = 1; -0067 while true -0068 [res,hs] = solveLP(m,0,[],hs); %skip parsimonius, only takes time -0069 if (lastGrowth == res.f) -0070 printOrange('WARNING: No growth increase from increased kcats - check if the constraints on the uptake reactions are too tight.\n') -0071 break; -0072 end -0073 lastGrowth = res.f; -0074 if verbose; disp(['Iteration ' num2str(iteration) ': Growth: ' num2str(lastGrowth)]); end -0075 if (lastGrowth >= desiredGrowthRate) -0076 break; -0077 end -0078 %If you get an error here, it is likely due to numerical issues in the solver -0079 %The trick where we don't allow low kcats is to fix that, but maybe -0080 %it is not enough. -0081 iteration = iteration + 1; -0082 %find the highest draw_prot rxn flux -0083 drawFluxes = zeros(length(drawRxns),1); -0084 drawFluxes(drawRxns) = res.x(drawRxns); -0085 % Remove from the list user defined proteins -0086 drawFluxes(idxToIgnore) = 0; -0087 [~,sel] = min(drawFluxes); % since bounds -1000 to 0 -0088 %Now get the metabolite -0089 metSel = m.S(:,sel) < 0; % negative coeff -0090 %now find the reaction with the largest consumption of this protein -0091 protFluxes = m.S(metSel,:).' .* res.x; %negative -0092 [~,rxnSel] = min(protFluxes); -0093 kcatList = [kcatList, rxnSel]; -0094 rxn = m.rxns(rxnSel); -0095 targetSubRxn = strcmp(m.ec.rxns, rxn); -0096 m.ec.kcat(targetSubRxn) = m.ec.kcat(targetSubRxn) .* foldChange; -0097 m = applyKcatConstraints(m,targetSubRxn); -0098 end -0099 -0100 else -0101 origRxns = extractAfter(m.ec.rxns,4); -0102 %find the reactions involved in proteins to be ignored -0103 idxToIgnore = cellfun(@(x) find(m.ec.rxnEnzMat(:, strcmpi(m.ec.enzymes, x))), protToIgnore, 'UniformOutput', false); -0104 %create an unique vector -0105 idxToIgnore = unique(cat(1, idxToIgnore{:})); -0106 %get the correct idx in model.rxns -0107 idxToIgnore = cellfun(@(x) find(strcmpi(m.rxns, x)), origRxns(idxToIgnore)); -0108 iteration = 1; -0109 while true -0110 res = solveLP(m,0); %skip parsimonius, only takes time -0111 if (lastGrowth == res.f) -0112 printOrange('No growth increase from increased kcats - check if the constraints on the uptake reactions are too tight.\n') -0113 break; -0114 end -0115 lastGrowth = res.f; -0116 if (lastGrowth >= desiredGrowthRate) -0117 break; -0118 end -0119 %If you get an error here, it is likely due to numerical issues in the solver -0120 %The trick where we don't allow low kcats is to fix that, but maybe -0121 %it is not enough. -0122 if verbose; disp(['Iteration ' num2str(iteration) ': Growth: ' num2str(lastGrowth)]); end -0123 iteration = iteration + 1; -0124 %find the highest protein usage flux -0125 protPoolStoich = m.S(strcmp(m.mets, 'prot_pool'),:).'; -0126 protPoolStoich(idxToIgnore) = 0; -0127 [~,sel] = min(res.x .* protPoolStoich); %max consumption -0128 kcatList = [kcatList, sel]; -0129 rxn = m.rxns(sel.'); -0130 targetSubRxns = strcmp(origRxns, rxn); -0131 m.ec.kcat(targetSubRxns) = m.ec.kcat(targetSubRxns) .* foldChange; -0132 m = applyKcatConstraints(m,rxn); -0133 end -0134 end -0135 -0136 kcatList = unique(kcatList); -0137 tunedKcats.rxns = m.rxns(kcatList); -0138 tunedKcats.rxnNames = m.rxnNames(kcatList); -0139 if ~model.ec.geckoLight -0140 [~, rxnIdx] = ismember(tunedKcats.rxns,m.ec.rxns); -0141 else -0142 [~, rxnIdx] = ismember(tunedKcats.rxns,origRxns); -0143 end -0144 tunedKcats.enzymes = cell(numel(kcatList),1); -0145 for i=1:numel(rxnIdx) -0146 [~, metIdx] = find(m.ec.rxnEnzMat(rxnIdx(i),:)); -0147 tunedKcats.enzymes{i} = strjoin(m.ec.enzymes(metIdx),';'); -0148 end -0149 tunedKcats.oldKcat = model.ec.kcat(rxnIdx); -0150 tunedKcats.newKcat = m.ec.kcat(rxnIdx); -0151 tunedKcats.source = model.ec.source(rxnIdx); -0152 -0153 model = m; -0154 end +0057 kcatList = []; +0058 m = model; +0059 m.c = double(strcmp(m.rxns, params.bioRxn));% Make sure that growth is maximized +0060 +0061 [res,hs] = solveLP(m); +0062 if isempty(res.x) +0063 error('FBA of input model gives no valid result. Reduce protein pool constraint with setProtPoolSize and/or check if exchange constraints are correctly defined.') +0064 end +0065 lastGrowth = 0; +0066 if ~m.ec.geckoLight +0067 %for the full model, we first find the draw reaction with the most flux +0068 drawRxns = startsWith(m.rxns, 'usage_prot_'); +0069 idxToIgnore = cellfun(@(x) find(strcmpi(model.rxns, ['usage_prot_' x])), protToIgnore); +0070 iteration = 1; +0071 while true +0072 [res,hs] = solveLP(m,0,[],hs); %skip parsimonius, only takes time +0073 if (lastGrowth == res.f) +0074 printOrange('WARNING: No growth increase from increased kcats - check if the constraints on the uptake reactions are too tight.\n') +0075 break; +0076 end +0077 lastGrowth = res.f; +0078 if verbose; disp(['Iteration ' num2str(iteration) ': Growth: ' num2str(lastGrowth)]); end +0079 if (lastGrowth >= desiredGrowthRate) +0080 break; +0081 end +0082 %If you get an error here, it is likely due to numerical issues in the solver +0083 %The trick where we don't allow low kcats is to fix that, but maybe +0084 %it is not enough. +0085 iteration = iteration + 1; +0086 %find the highest draw_prot rxn flux +0087 drawFluxes = zeros(length(drawRxns),1); +0088 drawFluxes(drawRxns) = res.x(drawRxns); +0089 % Remove from the list user defined proteins +0090 drawFluxes(idxToIgnore) = 0; +0091 [~,sel] = min(drawFluxes); % since bounds -1000 to 0 +0092 %Now get the metabolite +0093 metSel = m.S(:,sel) < 0; % negative coeff +0094 %now find the reaction with the largest consumption of this protein +0095 protFluxes = m.S(metSel,:).' .* res.x; %negative +0096 [~,rxnSel] = min(protFluxes); +0097 kcatList = [kcatList, rxnSel]; +0098 rxn = m.rxns(rxnSel); +0099 targetSubRxn = strcmp(m.ec.rxns, rxn); +0100 if ~strcmp(m.ec.source(targetSubRxn),'sensitivityTuning') +0101 oldNote = m.ec.notes{targetSubRxn}; +0102 newNote = ['preTuneKcat=' num2str(m.ec.kcat(targetSubRxn)) ' | source:' m.ec.source{targetSubRxn}]; +0103 if ~isempty(oldNote) +0104 newNote = [oldNote '; ' newNote]; +0105 end +0106 m.ec.notes{targetSubRxn} = newNote; +0107 end +0108 m.ec.kcat(targetSubRxn) = m.ec.kcat(targetSubRxn) .* foldChange; +0109 m.ec.source(targetSubRxn) = {'sensitivityTuning'}; +0110 m = applyKcatConstraints(m,targetSubRxn); +0111 end +0112 +0113 else +0114 origRxns = extractAfter(m.ec.rxns,4); +0115 %find the reactions involved in proteins to be ignored +0116 idxToIgnore = cellfun(@(x) find(m.ec.rxnEnzMat(:, strcmpi(m.ec.enzymes, x))), protToIgnore, 'UniformOutput', false); +0117 %create an unique vector +0118 idxToIgnore = unique(cat(1, idxToIgnore{:})); +0119 %get the correct idx in model.rxns +0120 idxToIgnore = cellfun(@(x) find(strcmpi(m.rxns, x)), origRxns(idxToIgnore)); +0121 iteration = 1; +0122 while true +0123 res = solveLP(m,0); %skip parsimonius, only takes time +0124 if (lastGrowth == res.f) +0125 printOrange('No growth increase from increased kcats - check if the constraints on the uptake reactions are too tight.\n') +0126 break; +0127 end +0128 lastGrowth = res.f; +0129 if (lastGrowth >= desiredGrowthRate) +0130 break; +0131 end +0132 %If you get an error here, it is likely due to numerical issues in the solver +0133 %The trick where we don't allow low kcats is to fix that, but maybe +0134 %it is not enough. +0135 if verbose; disp(['Iteration ' num2str(iteration) ': Growth: ' num2str(lastGrowth)]); end +0136 iteration = iteration + 1; +0137 %find the highest protein usage flux +0138 protPoolStoich = m.S(strcmp(m.mets, 'prot_pool'),:).'; +0139 protPoolStoich(idxToIgnore) = 0; +0140 [~,sel] = min(res.x .* protPoolStoich); %max consumption +0141 kcatList = [kcatList, sel]; +0142 rxn = m.rxns(sel.'); +0143 targetSubRxns = strcmp(origRxns, rxn); +0144 m.ec.kcat(targetSubRxns) = m.ec.kcat(targetSubRxns) .* foldChange; +0145 m = applyKcatConstraints(m,rxn); +0146 end +0147 end +0148 +0149 kcatList = unique(kcatList); +0150 tunedKcats.rxns = m.rxns(kcatList); +0151 tunedKcats.rxnNames = m.rxnNames(kcatList); +0152 if ~model.ec.geckoLight +0153 [~, rxnIdx] = ismember(tunedKcats.rxns,m.ec.rxns); +0154 else +0155 [~, rxnIdx] = ismember(tunedKcats.rxns,origRxns); +0156 end +0157 tunedKcats.enzymes = cell(numel(kcatList),1); +0158 for i=1:numel(rxnIdx) +0159 [~, metIdx] = find(m.ec.rxnEnzMat(rxnIdx(i),:)); +0160 tunedKcats.enzymes{i} = strjoin(m.ec.enzymes(metIdx),';'); +0161 end +0162 tunedKcats.oldKcat = model.ec.kcat(rxnIdx); +0163 tunedKcats.newKcat = m.ec.kcat(rxnIdx); +0164 tunedKcats.source = model.ec.source(rxnIdx); +0165 +0166 model = m; +0167 end
Generated by m2html © 2005
\ No newline at end of file diff --git a/doc/src/geckomat/model_adapter/adapterTemplate.html b/doc/src/geckomat/model_adapter/adapterTemplate.html index a331e49e4..f045cb472 100644 --- a/doc/src/geckomat/model_adapter/adapterTemplate.html +++ b/doc/src/geckomat/model_adapter/adapterTemplate.html @@ -100,7 +100,7 @@

SOURCE CODE ^% Whether only reviewed data from UniProt should be considered. 0055 % Reviewed data has highest confidence, but coverage might be (very) 0056 % low for non-model organisms -0057 obj.params.uniprot.reviewed = true; +0057 obj.params.uniprot.reviewed = false; 0058 0059 % Reaction ID for glucose exchange reaction (or other preferred carbon source) 0060 obj.params.c_source = 'r_1714'; diff --git a/src/geckomat/change_model/applyKcatConstraints.m b/src/geckomat/change_model/applyKcatConstraints.m index 947fd431b..648a1ed17 100644 --- a/src/geckomat/change_model/applyKcatConstraints.m +++ b/src/geckomat/change_model/applyKcatConstraints.m @@ -116,4 +116,3 @@ end end end - diff --git a/src/geckomat/change_model/setKcatForReactions.m b/src/geckomat/change_model/setKcatForReactions.m index f5804cc0c..ca62f315d 100644 --- a/src/geckomat/change_model/setKcatForReactions.m +++ b/src/geckomat/change_model/setKcatForReactions.m @@ -47,5 +47,5 @@ end end ecModel.ec.kcat(rxnsToChange) = kcat; -ecModel.ec.source(rxnsToChange) = {'from setKcatForReactions'}; +ecModel.ec.source(rxnsToChange) = {'setKcatForReactions'}; end diff --git a/src/geckomat/kcat_sensitivity_analysis/sensitivityTuning.m b/src/geckomat/kcat_sensitivity_analysis/sensitivityTuning.m index 169ae74a6..f595f1457 100644 --- a/src/geckomat/kcat_sensitivity_analysis/sensitivityTuning.m +++ b/src/geckomat/kcat_sensitivity_analysis/sensitivityTuning.m @@ -27,6 +27,10 @@ % oldKcat kcat values in the input model % newKcat kcat values in the output model, after tuning % +% Note: The model.ec.notes field will contain the original kcat value and +% source, unless the kcat has previously been set by sensitivityTuning, in +% which case the notes field remains unchanged. +% % Usage: % [model, tunedKcats] = sensitivityTuning(model, desiredGrowthRate, modelAdapter, foldChange, protToIgnore, verbose) @@ -93,7 +97,16 @@ kcatList = [kcatList, rxnSel]; rxn = m.rxns(rxnSel); targetSubRxn = strcmp(m.ec.rxns, rxn); - m.ec.kcat(targetSubRxn) = m.ec.kcat(targetSubRxn) .* foldChange; + if ~strcmp(m.ec.source(targetSubRxn),'sensitivityTuning') + oldNote = m.ec.notes{targetSubRxn}; + newNote = ['preTuneKcat=' num2str(m.ec.kcat(targetSubRxn)) ' | source:' m.ec.source{targetSubRxn}]; + if ~isempty(oldNote) + newNote = [oldNote '; ' newNote]; + end + m.ec.notes{targetSubRxn} = newNote; + end + m.ec.kcat(targetSubRxn) = m.ec.kcat(targetSubRxn) .* foldChange; + m.ec.source(targetSubRxn) = {'sensitivityTuning'}; m = applyKcatConstraints(m,targetSubRxn); end diff --git a/src/geckomat/model_adapter/adapterTemplate.m b/src/geckomat/model_adapter/adapterTemplate.m index 0405e94a9..ff7ed4c09 100644 --- a/src/geckomat/model_adapter/adapterTemplate.m +++ b/src/geckomat/model_adapter/adapterTemplate.m @@ -54,7 +54,7 @@ % Whether only reviewed data from UniProt should be considered. % Reviewed data has highest confidence, but coverage might be (very) % low for non-model organisms - obj.params.uniprot.reviewed = true; + obj.params.uniprot.reviewed = false; % Reaction ID for glucose exchange reaction (or other preferred carbon source) obj.params.c_source = 'r_1714'; @@ -62,7 +62,10 @@ % Reaction ID for biomass pseudoreaction obj.params.bioRxn = 'r_4041'; - % Compartment name in which the added enzymes should be located + % Name of the compartment where the protein pseudometabolites + % should be located (all be located in the same compartment, + % this does not interfere with them catalyzing reactions in + % different compartments). Typically, cytoplasm is chosen. obj.params.enzyme_comp = 'cytoplasm'; end diff --git a/test/manual_tests/TestYeastGEMSimpleWorkflow.m b/test/manual_tests/TestYeastGEMSimpleWorkflow.m index 3e3bfc461..7ebcf9f5c 100644 --- a/test/manual_tests/TestYeastGEMSimpleWorkflow.m +++ b/test/manual_tests/TestYeastGEMSimpleWorkflow.m @@ -2,8 +2,8 @@ GECKORoot = findGECKOroot(); -yeastAdapter = ModelAdapterManager.getAdapter(fullfile(GECKORoot, 'tutorials', 'tutorial_yeast-GEM', 'YeastGEMAdapter.m')); -yeastGEM = importModel(fullfile(yeastAdapter.getParameters().path,'models','yeast-GEM.yml')); +yeastAdapter = ModelAdapterManager.getAdapter(fullfile(GECKORoot, 'tutorials', 'full_ecModel', 'YeastGEMAdapter.m')); +yeastGEM = readYAMLmodel(fullfile(yeastAdapter.getParameters().path,'models','yeast-GEM.yml')); %Full model %%%%%%%%%%%% diff --git a/tutorials/full_ecModel/YeastGEMAdapter.m b/tutorials/full_ecModel/YeastGEMAdapter.m index e7ae4a58a..aa6a7d44c 100644 --- a/tutorials/full_ecModel/YeastGEMAdapter.m +++ b/tutorials/full_ecModel/YeastGEMAdapter.m @@ -33,6 +33,10 @@ obj.params.bioRxn = 'r_4041'; + % Name of the compartment where the protein pseudometabolites + % should be located (all be located in the same compartment, + % this does not interfere with them catalyzing reactions in + % different compartments). Typically, cytoplasm is chosen. obj.params.enzyme_comp = 'cytoplasm'; end diff --git a/tutorials/full_ecModel/models/ecYeastGEM.yml b/tutorials/full_ecModel/models/ecYeastGEM.yml index 1c25dcfd4..092bfadf9 100644 --- a/tutorials/full_ecModel/models/ecYeastGEM.yml +++ b/tutorials/full_ecModel/models/ecYeastGEM.yml @@ -4,7 +4,7 @@ id: "yeastGEM_v8.6.2" name: "The Consensus Genome-Scale Metabolic Model of Yeast" version: "" - date: "2024-06-06" + date: "2024-07-17" defaultLB: "-1000" defaultUB: "1000" givenName: "Eduard" @@ -40877,7 +40877,6 @@ - id: "prot_pool" - name: "prot_pool" - compartment: "c" - - charge: 0 - notes: "Enzyme-usage protein pool" - !!omap - id: "prot_standard" @@ -197765,7 +197764,8 @@ - !!omap - id: "r_0079" - kcat: 5.3357625 - - source: "from setKcatForReactions" + - source: "setKcatForReactions" + - notes: "preTuneKcat=0.05 | source:brenda" - eccodes: "6.3.5.3" - enzymes: !!omap - P38972: 1 @@ -198077,7 +198077,8 @@ - !!omap - id: "r_0109" - kcat: 12.3 - - source: "brenda" + - source: "sensitivityTuning" + - notes: "preTuneKcat=1.23 | source:brenda" - eccodes: "6.3.4.14" - enzymes: !!omap - P48445: 1 @@ -201233,8 +201234,8 @@ - !!omap - id: "r_0450" - kcat: 325 - - source: "custom" - - notes: "GECKO v2 manual_data.txt" + - source: "sensitivityTuning" + - notes: "GECKO v2 manual_data.txt; preTuneKcat=32.5 | source:custom" - eccodes: "4.1.2.13" - enzymes: !!omap - P14540: 1 @@ -201625,8 +201626,8 @@ - !!omap - id: "r_0486_EXP_2" - kcat: 290 - - source: "custom" - - notes: "GECKO v2 manualModifications.m growth limiting" + - source: "sensitivityTuning" + - notes: "GECKO v2 manualModifications.m growth limiting; preTuneKcat=29 | source:custom" - eccodes: "1.2.1.12" - enzymes: !!omap - P00360: 1 @@ -203466,7 +203467,8 @@ - !!omap - id: "r_0698" - kcat: 0.193666666666667 - - source: "brenda" + - source: "sensitivityTuning" + - notes: "preTuneKcat=0.0019367 | source:brenda" - eccodes: "5.4.99.7" - enzymes: !!omap - P38604: 1 @@ -207794,7 +207796,8 @@ - !!omap - id: "r_1166_EXP_11" - kcat: 192.645 - - source: "DLKcat" + - source: "sensitivityTuning" + - notes: "preTuneKcat=19.2645 | source:DLKcat" - enzymes: !!omap - P38695: 1 - !!omap diff --git a/tutorials/light_ecModel/HumanGEMAdapter.m b/tutorials/light_ecModel/HumanGEMAdapter.m index 4a9ae97ba..13756b806 100644 --- a/tutorials/light_ecModel/HumanGEMAdapter.m +++ b/tutorials/light_ecModel/HumanGEMAdapter.m @@ -47,6 +47,10 @@ obj.params.bioRxn = 'MAR13082'; + % Name of the compartment where the protein pseudometabolites + % should be located (all be located in the same compartment, + % this does not interfere with them catalyzing reactions in + % different compartments). Typically, cytoplasm is chosen. obj.params.enzyme_comp = 'Cytosol'; end From d461d3a8ab80bfc59045170b9f653e33653f63a2 Mon Sep 17 00:00:00 2001 From: Eduard Kerkhoven Date: Sun, 22 Sep 2024 15:47:28 +0200 Subject: [PATCH 2/3] fix: compatibility with RAVEN 2.10.0 (#391) * fix: compatible with next RAVEN release * fix: rename anaerobicModel A yeast-GEM-specific script that ideally should be refactored. For now, just rename to avoid conflict with the function in yeast-GEM repository --- doc/index.html | 2 +- .../Bayesian/abc_max.html | 4 +- ...icModel.html => anaerobicModel_GECKO.html} | 16 ++--- .../Bayesian/changeMedia.html | 4 +- .../Bayesian/index.html | 2 +- .../model_adapter/adapterTemplate.html | 27 ++++---- .../Bayesian/abc_max.m | 2 +- ...naerobicModel.m => anaerobicModel_GECKO.m} | 4 +- .../Bayesian/changeMedia.m | 2 +- test/unit_tests/ecTestGEM/data/smilesDB.tsv | 1 + .../unit_tests/ecTestGEM/models/testModel.xml | 69 ++++++++----------- test/unit_tests/getGeckoTestModel.m | 2 +- 12 files changed, 62 insertions(+), 73 deletions(-) rename doc/src/geckomat/kcat_sensitivity_analysis/Bayesian/{anaerobicModel.html => anaerobicModel_GECKO.html} (98%) rename src/geckomat/kcat_sensitivity_analysis/Bayesian/{anaerobicModel.m => anaerobicModel_GECKO.m} (99%) diff --git a/doc/index.html b/doc/index.html index f332bb806..63add7002 100644 --- a/doc/index.html +++ b/doc/index.html @@ -25,7 +25,7 @@

Matlab Files found in these Directories

adapterTemplate fillEnzConcs getrSample sensitivityTuning addCarbonNum findECInDB loadBRENDAdata setKcatForReactions addNewRxnsToEC findGECKOroot loadConventionalGEM setProtPoolSize - anaerobicModel findMaxValue loadDatabases sigmaFitter + anaerobicModel_GECKO findMaxValue loadDatabases sigmaFitter applyComplexData findMetSmiles loadEcModel startGECKOproject applyCustomKcats flexibilizeEnzConcs loadFluxData truncateValues applyKcatConstraints fuzzyKcatMatching loadProtData updateGECKOdoc diff --git a/doc/src/geckomat/kcat_sensitivity_analysis/Bayesian/abc_max.html b/doc/src/geckomat/kcat_sensitivity_analysis/Bayesian/abc_max.html index b077b3f2f..8b53eca43 100644 --- a/doc/src/geckomat/kcat_sensitivity_analysis/Bayesian/abc_max.html +++ b/doc/src/geckomat/kcat_sensitivity_analysis/Bayesian/abc_max.html @@ -54,7 +54,7 @@

DESCRIPTION ^CROSS-REFERENCE INFORMATION ^

This function calls: +
  • addCarbonNum addCarbonNum
  • anaerobicModel_GECKO %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
  • changeMedia changeMedia
  • This function is called by: @@ -152,7 +152,7 @@

    SOURCE CODE ^'r_1631',0,'b'); 0086 0087 if strcmp(data(i,14),'anaerobic') ||strcmp(data(i,14),'limited') -0088 model_tmp = anaerobicModel(model_tmp); +0088 model_tmp = anaerobicModel_GECKO(model_tmp); 0089 end 0090 if strcmp(data(i,14),'limited') 0091 model_tmp.lb(strcmp(model_tmp.rxnNames,'oxygen exchange')) = -5;%TODO: Currently hard-coded for yeast diff --git a/doc/src/geckomat/kcat_sensitivity_analysis/Bayesian/anaerobicModel.html b/doc/src/geckomat/kcat_sensitivity_analysis/Bayesian/anaerobicModel_GECKO.html similarity index 98% rename from doc/src/geckomat/kcat_sensitivity_analysis/Bayesian/anaerobicModel.html rename to doc/src/geckomat/kcat_sensitivity_analysis/Bayesian/anaerobicModel_GECKO.html index 77886c37d..897661008 100644 --- a/doc/src/geckomat/kcat_sensitivity_analysis/Bayesian/anaerobicModel.html +++ b/doc/src/geckomat/kcat_sensitivity_analysis/Bayesian/anaerobicModel_GECKO.html @@ -2,8 +2,8 @@ "http://www.w3.org/TR/REC-html40/loose.dtd"> - Description of anaerobicModel - + Description of anaerobicModel_GECKO + @@ -12,23 +12,23 @@ -
    Home > src > geckomat > kcat_sensitivity_analysis > Bayesian > anaerobicModel.m
    +
    Home > src > geckomat > kcat_sensitivity_analysis > Bayesian > anaerobicModel_GECKO.m
    -

    anaerobicModel +

    anaerobicModel_GECKO

    PURPOSE ^

    %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%

    SYNOPSIS ^

    -
    function model = anaerobicModel(model)
    +
    function model = anaerobicModel_GECKO(model)

    DESCRIPTION ^

    %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
    - anaerobicModel.m
    + anaerobicModel_GECKO.m
      Converts model to anaerobic
     
      Benjamin J. Sanchez
    @@ -52,14 +52,14 @@ 

    SUBFUNCTIONS ^SOURCE CODE ^

    0001 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
    -0002 % anaerobicModel.m
    +0002 % anaerobicModel_GECKO.m
     0003 % Converts model to anaerobic
     0004 %
     0005 % Benjamin J. Sanchez
     0006 % Feiran Li - 2019-09-24
     0007 % Feiran Li - Last update: 2019-10-02 modify the order of changes
     0008 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
    -0009 function model = anaerobicModel(model)
    +0009 function model = anaerobicModel_GECKO(model)
     0010 
     0011 %1th change: Refit GAM and NGAM to exp. data, change biomass composition
     0012 GAM   = 58.1988;  %Data from Nissen et al. 1997
    diff --git a/doc/src/geckomat/kcat_sensitivity_analysis/Bayesian/changeMedia.html b/doc/src/geckomat/kcat_sensitivity_analysis/Bayesian/changeMedia.html
    index f6d673531..f4202b402 100644
    --- a/doc/src/geckomat/kcat_sensitivity_analysis/Bayesian/changeMedia.html
    +++ b/doc/src/geckomat/kcat_sensitivity_analysis/Bayesian/changeMedia.html
    @@ -54,7 +54,7 @@ 

    DESCRIPTION ^CROSS-REFERENCE INFORMATION ^

    This function calls:
      -
    • anaerobicModel %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
    +
  • anaerobicModel_GECKO %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
  • This function is called by: @@ -180,7 +180,7 @@

    SOURCE CODE ^% change aeerobic or anaerobic 0114 if strcmp(anox,'anaerobic') 0115 1 -0116 model = anaerobicModel(model); +0116 model = anaerobicModel_GECKO(model); 0117 end 0118 end 0119 diff --git a/doc/src/geckomat/kcat_sensitivity_analysis/Bayesian/index.html b/doc/src/geckomat/kcat_sensitivity_analysis/Bayesian/index.html index c6a86815b..5cade9575 100644 --- a/doc/src/geckomat/kcat_sensitivity_analysis/Bayesian/index.html +++ b/doc/src/geckomat/kcat_sensitivity_analysis/Bayesian/index.html @@ -19,7 +19,7 @@

    Index for src\geckomat\kcat_sensitivity_analysis\Bayesian

    Matlab files in this directory:

    -
     abc_maxsetProtPoolSize
     addCarbonNumaddCarbonNum
     anaerobicModel%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
     bayesianSensitivityTuningbayesianSensitivityTuning
     changeMediachangeMedia
     getcarbonnumgetcarbonnum
     getrSamplegetrSample
     updatepriorupdateprior
    + abc_maxsetProtPoolSize  addCarbonNumaddCarbonNum  anaerobicModel_GECKO%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%  bayesianSensitivityTuningbayesianSensitivityTuning  changeMediachangeMedia  getcarbonnumgetcarbonnum  getrSamplegetrSample  updatepriorupdateprior diff --git a/doc/src/geckomat/model_adapter/adapterTemplate.html b/doc/src/geckomat/model_adapter/adapterTemplate.html index f045cb472..bec5513e6 100644 --- a/doc/src/geckomat/model_adapter/adapterTemplate.html +++ b/doc/src/geckomat/model_adapter/adapterTemplate.html @@ -108,18 +108,21 @@

    SOURCE CODE ^% Reaction ID for biomass pseudoreaction 0063 obj.params.bioRxn = 'r_4041'; 0064 -0065 % Compartment name in which the added enzymes should be located -0066 obj.params.enzyme_comp = 'cytoplasm'; -0067 end -0068 -0069 function [spont,spontRxnNames] = getSpontaneousReactions(obj,model) -0070 % Indicates how spontaneous reactions are identified. Here it -0071 % is done by the reaction have 'spontaneous' in its name. -0072 spont = contains(model.rxnNames,'spontaneous'); -0073 spontRxnNames = model.rxnNames(spont); -0074 end -0075 end -0076 end

    +0065 % Name of the compartment where the protein pseudometabolites +0066 % should be located (all be located in the same compartment, +0067 % this does not interfere with them catalyzing reactions in +0068 % different compartments). Typically, cytoplasm is chosen. +0069 obj.params.enzyme_comp = 'cytoplasm'; +0070 end +0071 +0072 function [spont,spontRxnNames] = getSpontaneousReactions(obj,model) +0073 % Indicates how spontaneous reactions are identified. Here it +0074 % is done by the reaction have 'spontaneous' in its name. +0075 spont = contains(model.rxnNames,'spontaneous'); +0076 spontRxnNames = model.rxnNames(spont); +0077 end +0078 end +0079 end

    Generated by m2html © 2005
    \ No newline at end of file diff --git a/src/geckomat/kcat_sensitivity_analysis/Bayesian/abc_max.m b/src/geckomat/kcat_sensitivity_analysis/Bayesian/abc_max.m index f2e2e1ca9..c9bf54254 100644 --- a/src/geckomat/kcat_sensitivity_analysis/Bayesian/abc_max.m +++ b/src/geckomat/kcat_sensitivity_analysis/Bayesian/abc_max.m @@ -85,7 +85,7 @@ model_tmp = changeRxnBounds(model_tmp,'r_1631',0,'b'); if strcmp(data(i,14),'anaerobic') ||strcmp(data(i,14),'limited') - model_tmp = anaerobicModel(model_tmp); + model_tmp = anaerobicModel_GECKO(model_tmp); end if strcmp(data(i,14),'limited') model_tmp.lb(strcmp(model_tmp.rxnNames,'oxygen exchange')) = -5;%TODO: Currently hard-coded for yeast diff --git a/src/geckomat/kcat_sensitivity_analysis/Bayesian/anaerobicModel.m b/src/geckomat/kcat_sensitivity_analysis/Bayesian/anaerobicModel_GECKO.m similarity index 99% rename from src/geckomat/kcat_sensitivity_analysis/Bayesian/anaerobicModel.m rename to src/geckomat/kcat_sensitivity_analysis/Bayesian/anaerobicModel_GECKO.m index d1e205b80..9cba35819 100644 --- a/src/geckomat/kcat_sensitivity_analysis/Bayesian/anaerobicModel.m +++ b/src/geckomat/kcat_sensitivity_analysis/Bayesian/anaerobicModel_GECKO.m @@ -1,12 +1,12 @@ %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% -% anaerobicModel.m +% anaerobicModel_GECKO.m % Converts model to anaerobic % % Benjamin J. Sanchez % Feiran Li - 2019-09-24 % Feiran Li - Last update: 2019-10-02 modify the order of changes %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% -function model = anaerobicModel(model) +function model = anaerobicModel_GECKO(model) %1th change: Refit GAM and NGAM to exp. data, change biomass composition GAM = 58.1988; %Data from Nissen et al. 1997 diff --git a/src/geckomat/kcat_sensitivity_analysis/Bayesian/changeMedia.m b/src/geckomat/kcat_sensitivity_analysis/Bayesian/changeMedia.m index ba493911d..67b25b8fa 100644 --- a/src/geckomat/kcat_sensitivity_analysis/Bayesian/changeMedia.m +++ b/src/geckomat/kcat_sensitivity_analysis/Bayesian/changeMedia.m @@ -113,7 +113,7 @@ % change aeerobic or anaerobic if strcmp(anox,'anaerobic') 1 - model = anaerobicModel(model); + model = anaerobicModel_GECKO(model); end end diff --git a/test/unit_tests/ecTestGEM/data/smilesDB.tsv b/test/unit_tests/ecTestGEM/data/smilesDB.tsv index 8629a01a1..859ca8a75 100644 --- a/test/unit_tests/ecTestGEM/data/smilesDB.tsv +++ b/test/unit_tests/ecTestGEM/data/smilesDB.tsv @@ -2,3 +2,4 @@ e1 C(C1C)O e2 C1C(=NC2) m1 C(C1C)O m2 C1C(=NC2) + diff --git a/test/unit_tests/ecTestGEM/models/testModel.xml b/test/unit_tests/ecTestGEM/models/testModel.xml index a845b969a..11a140c03 100644 --- a/test/unit_tests/ecTestGEM/models/testModel.xml +++ b/test/unit_tests/ecTestGEM/models/testModel.xml @@ -1,21 +1,6 @@ - - - - - - - - 2023-02-20T21:53:00Z - - - 2023-02-20T21:53:00Z - - - - @@ -30,10 +15,10 @@ - - - - + + + + @@ -41,23 +26,23 @@ - + - + - + - + - + - + - + @@ -67,10 +52,10 @@ - + - + @@ -82,10 +67,10 @@ - + - + @@ -95,27 +80,27 @@ - + - + - + - + - + - + - + @@ -125,25 +110,25 @@ - + - + - + - + - + diff --git a/test/unit_tests/getGeckoTestModel.m b/test/unit_tests/getGeckoTestModel.m index 1de61f94a..3d26e2f32 100644 --- a/test/unit_tests/getGeckoTestModel.m +++ b/test/unit_tests/getGeckoTestModel.m @@ -1,8 +1,8 @@ function testModel = getGeckoTestModel() testModel = struct(); -testModel.name = 'testModel'; testModel.id = 'testModel'; +testModel.name = 'testModel'; testModel.annotation.defaultLB = -Inf; testModel.annotation.defaultUB = Inf; testModel.date = datestr(now,29); From 6b3d9ba2c4f464a2c01216c5fa919eda40bffd02 Mon Sep 17 00:00:00 2001 From: Eduard Kerkhoven Date: Mon, 14 Oct 2024 21:00:08 +0200 Subject: [PATCH 3/3] feat: support for alternative location of DLKcat in/output (#394) * feat: alternative path of DLKcat in/output * fix: avoid double output with printOrange function * fix: remove mentions of Gitter * doc: makeEcModel informative error noUniprof * fix: check RAVEN version --- .github/CONTRIBUTING.md | 2 +- .github/ISSUE_TEMPLATE/config.yml | 6 +- GECKOInstaller.m | 18 +- .../change_model/applyCustomKcats.html | 2 +- .../change_model/applyKcatConstraints.html | 2 +- .../geckomat/change_model/getComplexData.html | 2 +- .../change_model/getKcatAcrossIsozymes.html | 2 +- .../geckomat/change_model/makeEcModel.html | 286 ++++++++--------- .../gather_kcats/getStandardKcat.html | 4 +- .../gather_kcats/readDLKcatOutput.html | 148 +++++---- doc/src/geckomat/gather_kcats/runDLKcat.html | 93 +++--- .../gather_kcats/writeDLKcatInput.html | 298 +++++++++--------- .../get_enzyme_data/loadDatabases.html | 4 +- .../sensitivityTuning.html | 4 +- .../limit_proteins/calculateFfactor.html | 2 +- .../limit_proteins/flexibilizeEnzConcs.html | 2 +- .../geckomat/utilities/addNewRxnsToEC.html | 2 +- doc/src/geckomat/utilities/ecFSEOF.html | 2 +- .../geckomat/utilities/getSubsetEcModel.html | 2 +- .../geckomat/utilities/startGECKOproject.html | 2 +- src/geckomat/change_model/applyCustomKcats.m | 2 +- .../change_model/applyKcatConstraints.m | 2 +- src/geckomat/change_model/getComplexData.m | 2 +- .../change_model/getKcatAcrossIsozymes.m | 2 +- src/geckomat/change_model/makeEcModel.m | 12 +- src/geckomat/gather_kcats/getStandardKcat.m | 4 +- src/geckomat/gather_kcats/readDLKcatOutput.m | 7 +- src/geckomat/gather_kcats/runDLKcat.m | 23 +- src/geckomat/gather_kcats/writeDLKcatInput.m | 7 +- src/geckomat/get_enzyme_data/loadDatabases.m | 4 +- .../sensitivityTuning.m | 4 +- .../limit_proteins/calculateFfactor.m | 2 +- .../limit_proteins/flexibilizeEnzConcs.m | 2 +- src/geckomat/utilities/addNewRxnsToEC.m | 2 +- src/geckomat/utilities/ecFSEOF.m | 2 +- src/geckomat/utilities/getSubsetEcModel.m | 2 +- src/geckomat/utilities/startGECKOproject.m | 2 +- 37 files changed, 502 insertions(+), 462 deletions(-) diff --git a/.github/CONTRIBUTING.md b/.github/CONTRIBUTING.md index 073837198..374584598 100644 --- a/.github/CONTRIBUTING.md +++ b/.github/CONTRIBUTING.md @@ -13,7 +13,7 @@ You can contribute in 2 main ways: by creating issues, and by sending pull reque * Lacking documentation. * Any type of feedback. -If you are unsure about the issue, consider asking first in our [Gitter chat room](https://gitter.im/SysBioChalmers/GECKO). +If you are unsure about the issue, consider asking first in the [GitHub Discussions page](https://github.com/SysBioChalmers/GECKO/discussions). When creating the issue, please make sure: diff --git a/.github/ISSUE_TEMPLATE/config.yml b/.github/ISSUE_TEMPLATE/config.yml index ae9f1590e..2bd78878c 100644 --- a/.github/ISSUE_TEMPLATE/config.yml +++ b/.github/ISSUE_TEMPLATE/config.yml @@ -1,5 +1,5 @@ blank_issues_enabled: true contact_links: - - name: Gitter Channel - url: https://gitter.im/SysBioChalmers/GECKO - about: You may also ask questions (or contribute with answers) at the GECKO Gitter channel. + - name: GitHub Discussions + url: https://github.com/SysBioChalmers/GECKO/discussions + about: You may also ask for support (or contribute with answers) at the GitHub Discussions page. diff --git a/GECKOInstaller.m b/GECKOInstaller.m index 9a088f465..210b8ee2c 100644 --- a/GECKOInstaller.m +++ b/GECKOInstaller.m @@ -66,14 +66,22 @@ function checkRAVENversion(minmVer) try [currVer, installType] = checkInstallation('versionOnly'); if strcmp(currVer,'develop') - printOrange('WARNING: Cannot determine your RAVEN version as it is in a development branch.\n') + printOrange('WARNING: Cannot determine your RAVEN version as it is in a development branch.\n'); else currVerNum = str2double(strsplit(currVer,'.')); minmVerNum = str2double(strsplit(minmVer,'.')); - for i=1:3 - if currVerNum(i) minmVerNum(1) + wrongVersion = false; + elseif currVerNum(2) < minmVerNum(2) + wrongVersion = true; + elseif currVerNum(2) > minmVerNum(2) + wrongVersion = false; + elseif currVerNum(3) < minmVerNum(3) + wrongVersion = true; + elseif currVerNum(3) >= minmVerNum(3) + wrongVersion = false; end end catch diff --git a/doc/src/geckomat/change_model/applyCustomKcats.html b/doc/src/geckomat/change_model/applyCustomKcats.html index 3f08d511c..05122e7b1 100644 --- a/doc/src/geckomat/change_model/applyCustomKcats.html +++ b/doc/src/geckomat/change_model/applyCustomKcats.html @@ -287,7 +287,7 @@

    SOURCE CODE ^if ~isempty(find(rxnToUpdate, 1)) 0186 model = applyKcatConstraints(model, rxnToUpdate); 0187 else -0188 printOrange('WARNING: No matches found. Consider checking the IDs or proteins in customKcats.') +0188 printOrange('WARNING: No matches found. Consider checking the IDs or proteins in customKcats.'); 0189 end 0190 0191 rxnUpdated = model.ec.rxns(find(rxnToUpdate)); diff --git a/doc/src/geckomat/change_model/applyKcatConstraints.html b/doc/src/geckomat/change_model/applyKcatConstraints.html index f87a2f1e3..a36e0e3bc 100644 --- a/doc/src/geckomat/change_model/applyKcatConstraints.html +++ b/doc/src/geckomat/change_model/applyKcatConstraints.html @@ -108,7 +108,7 @@

    SOURCE CODE ^' not a valid GECKO3 ecModel. First run makeEcModel(model).']) 0047 end 0048 if all(model.ec.kcat==0) -0049 printOrange('WARNING: No kcat values are provided in model.ec.kcat, model remains unchanged.\n') +0049 printOrange('WARNING: No kcat values are provided in model.ec.kcat, model remains unchanged.\n'); 0050 return 0051 end 0052 diff --git a/doc/src/geckomat/change_model/getComplexData.html b/doc/src/geckomat/change_model/getComplexData.html index c35e0e709..23a5cbbb2 100644 --- a/doc/src/geckomat/change_model/getComplexData.html +++ b/doc/src/geckomat/change_model/getComplexData.html @@ -118,7 +118,7 @@

    SOURCE CODE ^if isempty(taxonomicID) % Can be empty when gathered from model adapter -0047 printOrange('WARNING: No taxonomicID specified.') +0047 printOrange('WARNING: No taxonomicID specified.'); 0048 return 0049 elseif taxonomicID == 0 0050 taxonomicID = []; diff --git a/doc/src/geckomat/change_model/getKcatAcrossIsozymes.html b/doc/src/geckomat/change_model/getKcatAcrossIsozymes.html index 999a2c945..319a64adc 100644 --- a/doc/src/geckomat/change_model/getKcatAcrossIsozymes.html +++ b/doc/src/geckomat/change_model/getKcatAcrossIsozymes.html @@ -75,7 +75,7 @@

    SOURCE CODE ^'Provided model is a GECKO light version, this function is not relevant for such models') 0019 end 0020 if all(model.ec.kcat==0) -0021 printOrange('WARNING: No kcat values are provided in model.ec.kcat, model remains unchanged.\n') +0021 printOrange('WARNING: No kcat values are provided in model.ec.kcat, model remains unchanged.\n'); 0022 return 0023 end 0024 diff --git a/doc/src/geckomat/change_model/makeEcModel.html b/doc/src/geckomat/change_model/makeEcModel.html index cad1d0596..1b9277587 100644 --- a/doc/src/geckomat/change_model/makeEcModel.html +++ b/doc/src/geckomat/change_model/makeEcModel.html @@ -394,149 +394,151 @@

    SOURCE CODE ^end 0258 noUniprot = uniprotCompatibleGenes(~Lia); 0259 if all(~Lia) -0260 error('None of the proteins in uniprot.tsv match the genes in the model. Changes to the obj.params.uniprot parameters are likely required.') +0260 error('None of the proteins in uniprot.tsv match the genes in the model. Changes to the obj.params.uniprot parameters, or a data/uniprotConversion.tsv file are likely required.') 0261 elseif ~isempty(noUniprot) -0262 printOrange(['WARNING: The ' num2str(numel(noUniprot)) ' gene(s) reported in noUniprot cannot be found in data/uniprot.tsv, these will\n' ... -0263 'not be enzyme-constrained. If you intend to use different Uniprot data (e.g. from a\n'... -0264 'different proteome, make sure you first delete the existing data/uniprot.tsv file.\n']) -0265 end -0266 ec.genes = model.genes(Lia); %Will often be duplicate of model.genes, but is done here to prevent issues when it is not. -0267 ec.enzymes = uniprotDB.ID(Locb(Lia)); -0268 ec.mw = uniprotDB.MW(Locb(Lia)); -0269 ec.sequence = uniprotDB.seq(Locb(Lia)); -0270 %Additional info -0271 ec.concs = nan(numel(ec.genes),1); % To be filled with proteomics data when available -0272 -0273 %8: Only parse rxns associated to genes -0274 if ~geckoLight -0275 ec.rxnEnzMat = zeros(numel(rxnWithGene),numel(ec.genes)); % Non-zeros will indicate the number of subunits -0276 for r=1:numel(rxnWithGene) -0277 rxnGenes = model.genes(find(model.rxnGeneMat(rxnWithGene(r),:))); -0278 [~,locEnz] = ismember(rxnGenes,ec.genes); % Could also parse directly from rxnGeneMat, but some genes might be missing from Uniprot DB -0279 if locEnz ~= 0 -0280 ec.rxnEnzMat(r,locEnz) = 1; %Assume 1 copy per subunit or enzyme, can be modified later -0281 end -0282 end -0283 else -0284 %For light models, we need to split up all GPRs -0285 ec.rxnEnzMat = zeros(numel(ec.rxns),numel(ec.genes)); % Non-zeros will indicate the number of subunits -0286 nextIndex = 1; -0287 %For full model generation, the GPRs are controlled in expandModel, but -0288 %here we need to make an explicit format check -0289 indexes2check = findPotentialErrors(model.grRules,model); -0290 if ~isempty(indexes2check) -0291 printOrange('Run standardizeGrRules(model) for a more detailed warning.\n') -0292 printOrange('For Human-GEM, these reactions can be corrected using simplifyGrRules.\n'); -0293 end -0294 -0295 for i=1:prevNumRxns -0296 %ind is the index in the model, not to confuse with the index in the ec struct (i), -0297 %which only contains reactions with GPRs. -0298 ind = rxnWithGene(i); -0299 %Get rid of all '(' and ')' since I'm not looking at complex stuff -0300 %anyways -0301 geneString=model.grRules{ind}; -0302 geneString=strrep(geneString,'(',''); -0303 geneString=strrep(geneString,')',''); -0304 geneString=strrep(geneString,' or ',';'); -0305 -0306 if (numOrs(i) == 0) -0307 geneNames = {geneString}; -0308 else -0309 %Split the string into gene names -0310 geneNames=regexp(geneString,';','split'); -0311 end -0312 -0313 %Now loop through the isozymes and set the rxnGeneMat -0314 for j = 1:length(geneNames) -0315 %Find the gene in the gene list If ' and ' relationship, first -0316 %split the genes -0317 fnd = strfind(geneNames{j},' and '); -0318 if ~isempty(fnd) -0319 andGenes=regexp(geneNames{j},' and ','split'); -0320 ec.rxnEnzMat(nextIndex,ismember(ec.genes,andGenes)) = 1; %should be subunit stoichoimetry -0321 else -0322 ec.rxnEnzMat(nextIndex,ismember(ec.genes,geneNames(j)))=1;%should be subunit stoichoimetry -0323 end -0324 nextIndex = nextIndex + 1; -0325 end -0326 end -0327 end -0328 -0329 %9: Add proteins as pseudometabolites -0330 if ~geckoLight -0331 [proteinMets.mets, uniprotSortId] = unique(ec.enzymes); -0332 proteinMets.mets = strcat('prot_',proteinMets.mets); -0333 proteinMets.metNames = proteinMets.mets; -0334 proteinMets.compartments = compartmentID; -0335 if isfield(model,'metMiriams') -0336 proteinMets.metMiriams = repmat({struct('name',{{'sbo'}},'value',{{'SBO:0000252'}})},numel(proteinMets.mets),1); -0337 end -0338 if isfield(model,'metCharges') -0339 proteinMets.metCharges = zeros(numel(proteinMets.mets),1); -0340 end -0341 proteinMets.metNotes = repmat({'Enzyme-usage pseudometabolite'},numel(proteinMets.mets),1); -0342 model = addMets(model,proteinMets); -0343 end -0344 -0345 %10: Add protein pool pseudometabolite -0346 pool.mets = 'prot_pool'; -0347 pool.metNames = pool.mets; -0348 pool.compartments = compartmentID; -0349 pool.metNotes = 'Enzyme-usage protein pool'; -0350 model = addMets(model,pool); -0351 -0352 %11: Add protein usage reactions. -0353 if ~geckoLight -0354 usageRxns.rxns = strcat('usage_',proteinMets.mets); -0355 usageRxns.rxnNames = usageRxns.rxns; -0356 usageRxns.mets = cell(numel(usageRxns.rxns),1); -0357 usageRxns.stoichCoeffs = cell(numel(usageRxns.rxns),1); -0358 for i=1:numel(usageRxns.mets) -0359 usageRxns.mets{i} = {proteinMets.mets{i}, 'prot_pool'}; -0360 usageRxns.stoichCoeffs{i} = [-1,1]; -0361 end -0362 usageRxns.lb = zeros(numel(usageRxns.rxns),1) - 1000; -0363 usageRxns.ub = zeros(numel(usageRxns.rxns),1); -0364 usageRxns.rev = ones(numel(usageRxns.rxns),1); -0365 usageRxns.grRules = ec.genes(uniprotSortId); -0366 model = addRxns(model,usageRxns); -0367 end -0368 -0369 %12: Add protein pool reaction (with open UB) -0370 poolRxn.rxns = 'prot_pool_exchange'; -0371 poolRxn.rxnNames = poolRxn.rxns; -0372 poolRxn.mets = {'prot_pool'}; -0373 poolRxn.stoichCoeffs = {-1}; -0374 poolRxn.lb = -1000; -0375 poolRxn.ub = 0; -0376 poolRxn.rev = 1; -0377 model = addRxns(model,poolRxn); -0378 -0379 model.ec=ec; -0380 end -0381 -0382 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% -0383 %Function that gets the model field grRules and returns the indexes of the -0384 %rules in which the pattern ") and (" is present. -0385 %Copied from standardizeGrRules -0386 % TODO: Make this an accessible function in a separate file in RAVEN and remove this -0387 %implementation. -0388 function indexes2check = findPotentialErrors(grRules,model) -0389 indxs_l = find(~cellfun(@isempty,strfind(grRules,') and ('))); -0390 indxs_l_L = find(~cellfun(@isempty,strfind(grRules,') and'))); -0391 indxs_l_R = find(~cellfun(@isempty,strfind(grRules,'and ('))); -0392 indexes2check = vertcat(indxs_l,indxs_l_L,indxs_l_R); -0393 indexes2check = unique(indexes2check); -0394 -0395 if ~isempty(indexes2check) -0396 textToPrint = 'WARNING: Potentially problematic ") AND (" in the grRules for reaction(s):\n'; -0397 for i=1:numel(indexes2check) -0398 textToPrint=[textToPrint '\t' model.rxns{indexes2check(i)} '\n']; -0399 end -0400 printOrange(textToPrint); -0401 end -0402 end +0262 printOrange(['WARNING: The ' num2str(numel(noUniprot)) ' gene(s) reported '... +0263 'in "noUniprot" cannot be found in data/uniprot.tsv, these will ' ... +0264 'not be enzyme-constrained. If you intend to use different Uniprot '... +0265 'data (e.g. from a different proteome, make sure you first delete '... +0266 'the existing data/uniprot.tsv file.\n']); +0267 end +0268 ec.genes = model.genes(Lia); %Will often be duplicate of model.genes, but is done here to prevent issues when it is not. +0269 ec.enzymes = uniprotDB.ID(Locb(Lia)); +0270 ec.mw = uniprotDB.MW(Locb(Lia)); +0271 ec.sequence = uniprotDB.seq(Locb(Lia)); +0272 %Additional info +0273 ec.concs = nan(numel(ec.genes),1); % To be filled with proteomics data when available +0274 +0275 %8: Only parse rxns associated to genes +0276 if ~geckoLight +0277 ec.rxnEnzMat = zeros(numel(rxnWithGene),numel(ec.genes)); % Non-zeros will indicate the number of subunits +0278 for r=1:numel(rxnWithGene) +0279 rxnGenes = model.genes(find(model.rxnGeneMat(rxnWithGene(r),:))); +0280 [~,locEnz] = ismember(rxnGenes,ec.genes); % Could also parse directly from rxnGeneMat, but some genes might be missing from Uniprot DB +0281 if locEnz ~= 0 +0282 ec.rxnEnzMat(r,locEnz) = 1; %Assume 1 copy per subunit or enzyme, can be modified later +0283 end +0284 end +0285 else +0286 %For light models, we need to split up all GPRs +0287 ec.rxnEnzMat = zeros(numel(ec.rxns),numel(ec.genes)); % Non-zeros will indicate the number of subunits +0288 nextIndex = 1; +0289 %For full model generation, the GPRs are controlled in expandModel, but +0290 %here we need to make an explicit format check +0291 indexes2check = findPotentialErrors(model.grRules,model); +0292 if ~isempty(indexes2check) +0293 printOrange('Run standardizeGrRules(model) for a more detailed warning.\n'); +0294 printOrange('For Human-GEM, these reactions can be corrected using simplifyGrRules.\n'); +0295 end +0296 +0297 for i=1:prevNumRxns +0298 %ind is the index in the model, not to confuse with the index in the ec struct (i), +0299 %which only contains reactions with GPRs. +0300 ind = rxnWithGene(i); +0301 %Get rid of all '(' and ')' since I'm not looking at complex stuff +0302 %anyways +0303 geneString=model.grRules{ind}; +0304 geneString=strrep(geneString,'(',''); +0305 geneString=strrep(geneString,')',''); +0306 geneString=strrep(geneString,' or ',';'); +0307 +0308 if (numOrs(i) == 0) +0309 geneNames = {geneString}; +0310 else +0311 %Split the string into gene names +0312 geneNames=regexp(geneString,';','split'); +0313 end +0314 +0315 %Now loop through the isozymes and set the rxnGeneMat +0316 for j = 1:length(geneNames) +0317 %Find the gene in the gene list If ' and ' relationship, first +0318 %split the genes +0319 fnd = strfind(geneNames{j},' and '); +0320 if ~isempty(fnd) +0321 andGenes=regexp(geneNames{j},' and ','split'); +0322 ec.rxnEnzMat(nextIndex,ismember(ec.genes,andGenes)) = 1; %should be subunit stoichoimetry +0323 else +0324 ec.rxnEnzMat(nextIndex,ismember(ec.genes,geneNames(j)))=1;%should be subunit stoichoimetry +0325 end +0326 nextIndex = nextIndex + 1; +0327 end +0328 end +0329 end +0330 +0331 %9: Add proteins as pseudometabolites +0332 if ~geckoLight +0333 [proteinMets.mets, uniprotSortId] = unique(ec.enzymes); +0334 proteinMets.mets = strcat('prot_',proteinMets.mets); +0335 proteinMets.metNames = proteinMets.mets; +0336 proteinMets.compartments = compartmentID; +0337 if isfield(model,'metMiriams') +0338 proteinMets.metMiriams = repmat({struct('name',{{'sbo'}},'value',{{'SBO:0000252'}})},numel(proteinMets.mets),1); +0339 end +0340 if isfield(model,'metCharges') +0341 proteinMets.metCharges = zeros(numel(proteinMets.mets),1); +0342 end +0343 proteinMets.metNotes = repmat({'Enzyme-usage pseudometabolite'},numel(proteinMets.mets),1); +0344 model = addMets(model,proteinMets); +0345 end +0346 +0347 %10: Add protein pool pseudometabolite +0348 pool.mets = 'prot_pool'; +0349 pool.metNames = pool.mets; +0350 pool.compartments = compartmentID; +0351 pool.metNotes = 'Enzyme-usage protein pool'; +0352 model = addMets(model,pool); +0353 +0354 %11: Add protein usage reactions. +0355 if ~geckoLight +0356 usageRxns.rxns = strcat('usage_',proteinMets.mets); +0357 usageRxns.rxnNames = usageRxns.rxns; +0358 usageRxns.mets = cell(numel(usageRxns.rxns),1); +0359 usageRxns.stoichCoeffs = cell(numel(usageRxns.rxns),1); +0360 for i=1:numel(usageRxns.mets) +0361 usageRxns.mets{i} = {proteinMets.mets{i}, 'prot_pool'}; +0362 usageRxns.stoichCoeffs{i} = [-1,1]; +0363 end +0364 usageRxns.lb = zeros(numel(usageRxns.rxns),1) - 1000; +0365 usageRxns.ub = zeros(numel(usageRxns.rxns),1); +0366 usageRxns.rev = ones(numel(usageRxns.rxns),1); +0367 usageRxns.grRules = ec.genes(uniprotSortId); +0368 model = addRxns(model,usageRxns); +0369 end +0370 +0371 %12: Add protein pool reaction (with open UB) +0372 poolRxn.rxns = 'prot_pool_exchange'; +0373 poolRxn.rxnNames = poolRxn.rxns; +0374 poolRxn.mets = {'prot_pool'}; +0375 poolRxn.stoichCoeffs = {-1}; +0376 poolRxn.lb = -1000; +0377 poolRxn.ub = 0; +0378 poolRxn.rev = 1; +0379 model = addRxns(model,poolRxn); +0380 +0381 model.ec=ec; +0382 end +0383 +0384 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +0385 %Function that gets the model field grRules and returns the indexes of the +0386 %rules in which the pattern ") and (" is present. +0387 %Copied from standardizeGrRules +0388 % TODO: Make this an accessible function in a separate file in RAVEN and remove this +0389 %implementation. +0390 function indexes2check = findPotentialErrors(grRules,model) +0391 indxs_l = find(~cellfun(@isempty,strfind(grRules,') and ('))); +0392 indxs_l_L = find(~cellfun(@isempty,strfind(grRules,') and'))); +0393 indxs_l_R = find(~cellfun(@isempty,strfind(grRules,'and ('))); +0394 indexes2check = vertcat(indxs_l,indxs_l_L,indxs_l_R); +0395 indexes2check = unique(indexes2check); +0396 +0397 if ~isempty(indexes2check) +0398 textToPrint = 'WARNING: Potentially problematic ") AND (" in the grRules for reaction(s):\n'; +0399 for i=1:numel(indexes2check) +0400 textToPrint=[textToPrint '\t' model.rxns{indexes2check(i)} '\n']; +0401 end +0402 printOrange(textToPrint); +0403 end +0404 end
    Generated by m2html © 2005
    \ No newline at end of file diff --git a/doc/src/geckomat/gather_kcats/getStandardKcat.html b/doc/src/geckomat/gather_kcats/getStandardKcat.html index aff9e498a..b5b6ea32f 100644 --- a/doc/src/geckomat/gather_kcats/getStandardKcat.html +++ b/doc/src/geckomat/gather_kcats/getStandardKcat.html @@ -223,11 +223,11 @@

    SOURCE CODE ^else 0123 standard = true; -0124 printOrange('WARNING: No subSystem-specific kcat values can be calculated') +0124 printOrange('WARNING: No subSystem-specific kcat values can be calculated'); 0125 end 0126 else 0127 standard = true; -0128 printOrange('WARNING: No subSystem-specific kcat values can be calculated') +0128 printOrange('WARNING: No subSystem-specific kcat values can be calculated'); 0129 end 0130 0131 % Find reactions without GPR diff --git a/doc/src/geckomat/gather_kcats/readDLKcatOutput.html b/doc/src/geckomat/gather_kcats/readDLKcatOutput.html index 6afb8e597..cb45963fd 100644 --- a/doc/src/geckomat/gather_kcats/readDLKcatOutput.html +++ b/doc/src/geckomat/gather_kcats/readDLKcatOutput.html @@ -34,10 +34,9 @@

    DESCRIPTION ^SOURCE CODE ^% 0007 % Input: 0008 % model an ecModel in GECKO 3 format (with ecModel.ec structure) -0009 % outFile name and path of the DLKcat output file. If nothing is -0010 % provided, an attempt will be made to read -0011 % data/DLKcat.tsv from the obj.params.path folder -0012 % specified in the modelAdapter. -0013 % modelAdapter a loaded model adapter (Optional, will otherwise use the -0014 % default model adapter). -0015 % -0016 % Output: -0017 % kcatList structure array with list of DLKcat derived kcat values, -0018 % with separate entries for each kcat value -0019 % source 'DLKcat' -0020 % rxns reaction identifiers -0021 % genes gene identifiers -0022 % substrate substrate names -0023 % kcat predicted kcat value in /sec -0024 % -0025 % Usage: -0026 % kcatList = readDLKcatOutput(model, outFile, modelAdapter) -0027 -0028 if nargin < 3 || isempty(modelAdapter) -0029 modelAdapter = ModelAdapterManager.getDefault(); -0030 if isempty(modelAdapter) -0031 error('Either send in a modelAdapter or set the default model adapter in the ModelAdapterManager.') -0032 end -0033 end -0034 params = modelAdapter.params; -0035 -0036 if nargin<2 || isempty(outFile) -0037 fID = fopen(fullfile(params.path,'data','DLKcat.tsv'),'r'); -0038 else -0039 fID = fopen(outFile); -0040 end -0041 DLKcatOutput = textscan(fID,'%s %s %s %s %s %s','Delimiter','\t','HeaderLines',1); -0042 fclose(fID); -0043 -0044 % Check that DLKcat output file and model match (not fool proof, but good enough) -0045 [rxns, genes, subs, kcats] = deal(DLKcatOutput{[1,2,3,6]}); -0046 -0047 % Check if it contains any kcat values -0048 if all(cellfun(@isempty,kcats)) || all(strcmpi(kcats,'NA')) -0049 error('DLKcat file does not contain any kcat values, please run runDLKcat() first.') -0050 end -0051 -0052 % Check that all substrates are in the model -0053 matchMets = ismember(subs,model.metNames); -0054 if ~all(matchMets) -0055 errorText = 'DLKcat was likely run with an input file that was generated from another ecModel, as the following substrates from DLKcat output cannot be found in model.metNames:'; -0056 dispEM(errorText,true,subs(~matchMets),false) -0057 end -0058 -0059 % Check that all reactions are in model.ec.rxns -0060 matchRxns = ismember(rxns,model.ec.rxns); -0061 if ~all(matchRxns) -0062 errorText = 'DLKcat was likely run with an input file that was generated from another ecModel, as the following reactions from DLKcat output cannot be found in model.metNames:'; -0063 dispEM(errorText,true,rxns(~matchRxns),false) -0064 end -0065 -0066 % Filter out entries with no numeric value -0067 noOutput = cellfun(@isempty,regexpi(kcats,'[0-9]')); -0068 kcats = str2double(kcats(~noOutput)); -0069 rxns(noOutput) = []; -0070 genes(noOutput) = []; -0071 subs(noOutput) = []; -0072 -0073 % Make kcatList structure -0074 kcatList.source = 'DLKcat'; -0075 kcatList.rxns = rxns; -0076 kcatList.genes = genes; -0077 kcatList.substrates = subs; -0078 kcatList.kcats = kcats; -0079 end +0009 % outFile name and path of the DLKcat output file. (Optional, +0010 % default is data/DLKcat.tsv from the obj.params.path +0011 % folder specified in the modelAdapter) +0012 % modelAdapter a loaded model adapter (Optional, will otherwise use the +0013 % default model adapter). +0014 % +0015 % Output: +0016 % kcatList structure array with list of DLKcat derived kcat values, +0017 % with separate entries for each kcat value +0018 % source 'DLKcat' +0019 % rxns reaction identifiers +0020 % genes gene identifiers +0021 % substrate substrate names +0022 % kcat predicted kcat value in /sec +0023 % +0024 % Usage: +0025 % kcatList = readDLKcatOutput(model, outFile, modelAdapter) +0026 +0027 if nargin < 3 || isempty(modelAdapter) +0028 modelAdapter = ModelAdapterManager.getDefault(); +0029 if isempty(modelAdapter) +0030 error('Either send in a modelAdapter or set the default model adapter in the ModelAdapterManager.') +0031 end +0032 end +0033 params = modelAdapter.params; +0034 +0035 if nargin<2 || isempty(outFile) +0036 fID = fopen(fullfile(params.path,'data','DLKcat.tsv'),'r'); +0037 else +0038 fID = fopen(outFile); +0039 end +0040 DLKcatOutput = textscan(fID,'%s %s %s %s %s %s','Delimiter','\t','HeaderLines',1); +0041 fclose(fID); +0042 +0043 % Check that DLKcat output file and model match (not fool proof, but good enough) +0044 [rxns, genes, subs, kcats] = deal(DLKcatOutput{[1,2,3,6]}); +0045 +0046 % Check if it contains any kcat values +0047 if all(cellfun(@isempty,kcats)) || all(strcmpi(kcats,'NA')) +0048 error('DLKcat file does not contain any kcat values, please run runDLKcat() first.') +0049 end +0050 +0051 % Check that all substrates are in the model +0052 matchMets = ismember(subs,model.metNames); +0053 if ~all(matchMets) +0054 errorText = 'DLKcat was likely run with an input file that was generated from another ecModel, as the following substrates from DLKcat output cannot be found in model.metNames:'; +0055 dispEM(errorText,true,subs(~matchMets),false) +0056 end +0057 +0058 % Check that all reactions are in model.ec.rxns +0059 matchRxns = ismember(rxns,model.ec.rxns); +0060 if ~all(matchRxns) +0061 errorText = 'DLKcat was likely run with an input file that was generated from another ecModel, as the following reactions from DLKcat output cannot be found in model.metNames:'; +0062 dispEM(errorText,true,rxns(~matchRxns),false) +0063 end +0064 +0065 % Filter out entries with no numeric value +0066 noOutput = cellfun(@isempty,regexpi(kcats,'[0-9]')); +0067 kcats = str2double(kcats(~noOutput)); +0068 rxns(noOutput) = []; +0069 genes(noOutput) = []; +0070 subs(noOutput) = []; +0071 +0072 % Make kcatList structure +0073 kcatList.source = 'DLKcat'; +0074 kcatList.rxns = rxns; +0075 kcatList.genes = genes; +0076 kcatList.substrates = subs; +0077 kcatList.kcats = kcats; +0078 end
    Generated by m2html © 2005
    \ No newline at end of file diff --git a/doc/src/geckomat/gather_kcats/runDLKcat.html b/doc/src/geckomat/gather_kcats/runDLKcat.html index b11b22eef..313f2fbe8 100644 --- a/doc/src/geckomat/gather_kcats/runDLKcat.html +++ b/doc/src/geckomat/gather_kcats/runDLKcat.html @@ -24,7 +24,7 @@

    PURPOSE ^runDLKcat

    SYNOPSIS ^

    -
    function runDLKcat(modelAdapter)
    +
    function runDLKcat(modelAdapter,filePath)

    DESCRIPTION ^

     runDLKcat
    @@ -36,6 +36,8 @@ 

    DESCRIPTION ^CROSS-REFERENCE INFORMATION ^
 
 
 <h2><a name=SOURCE CODE ^

    -
    0001 function runDLKcat(modelAdapter)
    +
    0001 function runDLKcat(modelAdapter,filePath)
     0002 % runDLKcat
     0003 %   Runs DLKcat to predict kcat values from a Docker image. Once DLKcat is succesfully
     0004 %   run, the DLKcatFile will be overwritten with the DLKcat
    @@ -63,46 +65,57 @@ 

    SOURCE CODE ^% Input 0009 % modelAdapter a loaded model adapter. (Optional, will otherwise use 0010 % the default model adapter) -0011 % -0012 % NOTE: 1. Requires Docker to be installed, and Docker Desktop running. Visit "https://www.docker.com" -0013 % 2. Runtime will depend on whether the image is to be downloaded or not. -0014 -0015 if nargin < 1 || isempty(modelAdapter) -0016 modelAdapter = ModelAdapterManager.getDefault(); -0017 if isempty(modelAdapter) -0018 error('Either send in a modelAdapter or set the default model adapter in the ModelAdapterManager.') -0019 end -0020 end -0021 -0022 params = modelAdapter.params; -0023 % Make sure path is full, not relative -0024 [~, params.path] = fileattrib(params.path); -0025 params.path=params.path.Name; -0026 -0027 %% Check and install requirements -0028 % On macOS, Docker might not be properly loaded if MATLAB is started via -0029 % launcher and not terminal. -0030 if ismac -0031 setenv('PATH', strcat('/usr/local/bin', ':', getenv("PATH"))); +0011 % filePath path to the DLKcat.tsv file. (Optional, will otherwise +0012 % assume data/DLKcat.tsv) +0013 % +0014 % NOTE: 1. Requires Docker to be installed, and Docker Desktop running. Visit "https://www.docker.com" +0015 % 2. Runtime will depend on whether the image is to be downloaded or not. +0016 +0017 if nargin < 1 || isempty(modelAdapter) +0018 modelAdapter = ModelAdapterManager.getDefault(); +0019 if isempty(modelAdapter) +0020 error('Either send in a modelAdapter or set the default model adapter in the ModelAdapterManager.') +0021 end +0022 end +0023 params = modelAdapter.params; +0024 % Make sure path is full, not relative +0025 [~, params.path] = fileattrib(params.path); +0026 params.path=params.path.Name; +0027 +0028 if nargin < 2 || isempty(filePath) +0029 filePath = fullfile(params.path,'data','DLKcat.tsv'); +0030 elseif strcmp(filePath(end),{'\','/'}) +0031 filePath = fullfile(filePath,'DLKcat.tsv'); 0032 end -0033 -0034 % Check if Docker is installed -0035 [checks.docker.status, checks.docker.out] = system('docker --version'); -0036 if checks.docker.status ~= 0 -0037 error('Cannot find Docker, make sure it is installed. If it is, it might be required to start Matlab from the command-line instead of the launcher in order for Docker to be detected and used.') -0038 end -0039 -0040 disp('Running DLKcat prediction, this may take many minutes, especially the first time.') -0041 status = system(['docker run --rm -v "' fullfile(params.path,'/data') '":/data ghcr.io/sysbiochalmers/dlkcat-gecko:0.1 /bin/bash -c "python DLKcat.py /data/DLKcat.tsv /data/DLKcatOutput.tsv"']); -0042 -0043 if status == 0 && exist(fullfile(params.path,'data/DLKcatOutput.tsv')) -0044 delete(fullfile(params.path,'/data/DLKcat.tsv')); -0045 movefile(fullfile(params.path,'/data/DLKcatOutput.tsv'), fullfile(params.path,'/data/DLKcat.tsv')); -0046 disp('DKLcat prediction completed.'); -0047 else -0048 error('DLKcat encountered an error or it did not create any output file.') +0033 filePath = checkFileExistence(filePath,1); +0034 +0035 copyfile(filePath, fullfile(params.path,'data','tempDLKcat.tsv')); +0036 +0037 +0038 %% Check and install requirements +0039 % On macOS, Docker might not be properly loaded if MATLAB is started via +0040 % launcher and not terminal. +0041 if ismac +0042 setenv('PATH', strcat('/usr/local/bin', ':', getenv("PATH"))); +0043 end +0044 +0045 % Check if Docker is installed +0046 [checks.docker.status, checks.docker.out] = system('docker --version'); +0047 if checks.docker.status ~= 0 +0048 error('Cannot find Docker, make sure it is installed. If it is, it might be required to start Matlab from the command-line instead of the launcher in order for Docker to be detected and used.') 0049 end -0050

    +0050 +0051 disp('Running DLKcat prediction, this may take many minutes, especially the first time.') +0052 status = system(['docker run --rm -v "' fullfile(params.path,'/data') '":/data ghcr.io/sysbiochalmers/dlkcat-gecko:0.1 /bin/bash -c "python DLKcat.py /data/tempDLKcat.tsv /data/tempDLKcatOutput.tsv"']); +0053 delete(fullfile(params.path,'/data/tempDLKcat.tsv')); +0054 +0055 if status == 0 && exist(fullfile(params.path,'data/tempDLKcatOutput.tsv')) +0056 movefile(fullfile(params.path,'/data/tempDLKcatOutput.tsv'), filePath); +0057 disp('DKLcat prediction completed.'); +0058 else +0059 error('DLKcat encountered an error or it did not create any output file.') +0060 end +0061

    Generated by m2html © 2005
    \ No newline at end of file diff --git a/doc/src/geckomat/gather_kcats/writeDLKcatInput.html b/doc/src/geckomat/gather_kcats/writeDLKcatInput.html index 030c07d7b..b8a1b4ae2 100644 --- a/doc/src/geckomat/gather_kcats/writeDLKcatInput.html +++ b/doc/src/geckomat/gather_kcats/writeDLKcatInput.html @@ -41,8 +41,9 @@

    DESCRIPTION ^SOURCE CODE ^% default model adapter). 0014 % onlyWithSmiles logical whether to only include metabolites with SMILES 0015 % (optional, default true) -0016 % filename Filename (Optional). Normally this parameter should not be -0017 % supplied, but it is useful for test cases. -0018 % overwrite logical whether existing file should be overwritten. -0019 % (Optional, default false, to prevent overwriting file -0020 % that already contains DLKcat-predicted kcat values). -0021 % -0022 % Output: -0023 % writtenTable The table written, mainly to be used for testing purposes. -0024 % -0025 % Usage: -0026 % writtenTable = writeDLKcatInput(model, ecRxns, modelAdapter, onlyWithSmiles, filename, overwrite) -0027 -0028 [geckoPath, ~] = findGECKOroot(); -0029 -0030 if nargin<2 || isempty(ecRxns) -0031 ecRxns = true(numel(model.ec.rxns),1); -0032 elseif ~logical(ecRxns) -0033 error('ecRxns should be provided as logical vector') -0034 elseif numel(ecRxns)~=numel(model.ec.rxns) -0035 error('Length of ecRxns is not the same as model.ec.rxns') -0036 end -0037 ecRxns = find(ecRxns); % Change to indices -0038 -0039 if nargin < 3 || isempty(modelAdapter) -0040 modelAdapter = ModelAdapterManager.getDefault(); -0041 if isempty(modelAdapter) -0042 error('Either send in a modelAdapter or set the default model adapter in the ModelAdapterManager.') -0043 end -0044 end -0045 params = modelAdapter.params; -0046 -0047 if nargin<4 || isempty(onlyWithSmiles) -0048 onlyWithSmiles=true; -0049 end -0050 -0051 if nargin<5 || isempty(filename) -0052 filename = fullfile(params.path,'data','DLKcat.tsv'); -0053 end -0054 -0055 if nargin<6 || isempty(overwrite) || ~overwrite % If is true -0056 if exist(filename,'file') -0057 error([filename ' already exists, either delete it first, or set the overwrite input argument as true']) -0058 end -0059 end -0060 -0061 if ~model.ec.geckoLight -0062 origRxns = model.ec.rxns; -0063 else -0064 origRxns = extractAfter(model.ec.rxns,4); -0065 end -0066 origRxnsToInclude = origRxns(ecRxns); -0067 -0068 % Map back to original reactions, to extract substrates -0069 [sanityCheck,origRxnIdxs] = ismember(origRxnsToInclude,model.rxns); -0070 if ~all(sanityCheck) -0071 error('Not all reactions in model.ec.rxns are found in model.rxns') -0072 end -0073 -0074 % Ignore selected metabolites (metal ions, proteins etc.). First check by -0075 % name (case insensitive, without white spaces and special characters), -0076 % then also try to match with metSmiles (if available). -0077 metsNoSpecialChars = lower(regexprep(model.metNames,'[^0-9a-zA-Z]+','')); -0078 if exist(fullfile(params.path,'data','DLKcatIgnoreMets.tsv'),'file') -0079 fID = fopen(fullfile(params.path,'data','DLKcatIgnoreMets.tsv')); -0080 else -0081 fID = fopen(fullfile(geckoPath,'databases','DLKcatIgnoreMets.tsv')); -0082 end -0083 fileData = textscan(fID,'%s %s','delimiter','\t'); -0084 fclose(fID); -0085 [ignoreMets, ignoreSmiles] = deal(fileData{[1,2]}); -0086 ignoreMets = lower(regexprep(ignoreMets,'[^0-9a-zA-Z]+','')); -0087 ignoreSmiles(cellfun(@isempty,ignoreSmiles)) = []; -0088 -0089 ignoreMetsIdx = logical(ismember(metsNoSpecialChars,ignoreMets)); -0090 if isfield(model,'metSmiles') -0091 ignoreMetsIdx = ignoreMetsIdx | logical(ismember(model.metSmiles,ignoreSmiles)); -0092 end -0093 % Also leave out protein-usage pseudometabolites -0094 ignoreMetsIdx = ignoreMetsIdx | startsWith(model.mets,'prot_'); -0095 reducedS = model.S; -0096 reducedS(ignoreMetsIdx,:) = 0; -0097 -0098 % Ignore currency metabolites if they occur in pairs. First check by -0099 % name (case insensitive, without white spaces and special characters), -0100 % then also try to match with metSmiles (if available). -0101 if exist(fullfile(params.path,'data','DLKcatCurrencyMets.tsv'),'file') -0102 fID = fopen(fullfile(params.path,'data','DLKcatCurrencyMets.tsv')); -0103 else -0104 fID = fopen(fullfile(geckoPath,'databases','DLKcatCurrencyMets.tsv')); -0105 end -0106 fileData = textscan(fID,'%s %s','delimiter','\t'); -0107 fclose(fID); -0108 [currencyMets(:,1), currencyMets(:,2)] = deal(fileData{[1,2]}); -0109 currencyMets = lower(regexprep(currencyMets,'[^0-9a-zA-Z]+','')); -0110 -0111 for i=1:size(currencyMets,1) -0112 subs = strcmp(currencyMets(i,1),metsNoSpecialChars); -0113 prod = strcmp(currencyMets(i,2),metsNoSpecialChars); -0114 [~,subsRxns]=find(reducedS(subs,:)); -0115 [~,prodRxns]=find(reducedS(prod,:)); -0116 pairRxns = intersect(subsRxns,prodRxns); -0117 tempRedS=reducedS; -0118 tempRedS([find(subs);find(prod)],pairRxns) = 0; -0119 % Do not remove currency mets if no substrate remains -0120 rxnsWithRemainingSubstrates = any(tempRedS(:,pairRxns) < 0,1); -0121 reducedS([find(subs);find(prod)],intersect(pairRxns,pairRxns(rxnsWithRemainingSubstrates))) = 0; -0122 end -0123 -0124 %filter out the reactions we're not interested in - will solve the problem for both full and light -0125 clearedRedS = reducedS(:,origRxnIdxs); -0126 rxnsToClear = true(length(origRxnIdxs),1); -0127 rxnsToClear(ecRxns) = false; -0128 clearedRedS(:,rxnsToClear) = 0; -0129 -0130 % Enumerate all substrates for each reaction -0131 [substrates, reactions] = find(clearedRedS<0); %the reactions here are in model.ec.rxns space +0016 % filename path to the input file, including the filename and .tsv +0017 % extension (Optional, default is data/DLKcat.tsv from +0018 % the obj.params.path folder specified in the modelAdapter) +0019 % overwrite logical whether existing file should be overwritten. +0020 % (Optional, default false, to prevent overwriting file +0021 % that already contains DLKcat-predicted kcat values). +0022 % +0023 % Output: +0024 % writtenTable The table written, mainly to be used for testing purposes. +0025 % +0026 % Usage: +0027 % writtenTable = writeDLKcatInput(model, ecRxns, modelAdapter, onlyWithSmiles, filename, overwrite) +0028 +0029 [geckoPath, ~] = findGECKOroot(); +0030 +0031 if nargin<2 || isempty(ecRxns) +0032 ecRxns = true(numel(model.ec.rxns),1); +0033 elseif ~logical(ecRxns) +0034 error('ecRxns should be provided as logical vector') +0035 elseif numel(ecRxns)~=numel(model.ec.rxns) +0036 error('Length of ecRxns is not the same as model.ec.rxns') +0037 end +0038 ecRxns = find(ecRxns); % Change to indices +0039 +0040 if nargin < 3 || isempty(modelAdapter) +0041 modelAdapter = ModelAdapterManager.getDefault(); +0042 if isempty(modelAdapter) +0043 error('Either send in a modelAdapter or set the default model adapter in the ModelAdapterManager.') +0044 end +0045 end +0046 params = modelAdapter.params; +0047 +0048 if nargin<4 || isempty(onlyWithSmiles) +0049 onlyWithSmiles=true; +0050 end +0051 +0052 if nargin<5 || isempty(filename) +0053 filename = fullfile(params.path,'data','DLKcat.tsv'); +0054 elseif ~endsWith(filename,'.tsv') +0055 error('If filename is provided, it should include the .tsv extension.') +0056 end +0057 +0058 if nargin<6 || isempty(overwrite) || ~overwrite % If is true +0059 if exist(filename,'file') +0060 error([filename ' already exists, either delete it first, or set the overwrite input argument as true']) +0061 end +0062 end +0063 +0064 if ~model.ec.geckoLight +0065 origRxns = model.ec.rxns; +0066 else +0067 origRxns = extractAfter(model.ec.rxns,4); +0068 end +0069 origRxnsToInclude = origRxns(ecRxns); +0070 +0071 % Map back to original reactions, to extract substrates +0072 [sanityCheck,origRxnIdxs] = ismember(origRxnsToInclude,model.rxns); +0073 if ~all(sanityCheck) +0074 error('Not all reactions in model.ec.rxns are found in model.rxns') +0075 end +0076 +0077 % Ignore selected metabolites (metal ions, proteins etc.). First check by +0078 % name (case insensitive, without white spaces and special characters), +0079 % then also try to match with metSmiles (if available). +0080 metsNoSpecialChars = lower(regexprep(model.metNames,'[^0-9a-zA-Z]+','')); +0081 if exist(fullfile(params.path,'data','DLKcatIgnoreMets.tsv'),'file') +0082 fID = fopen(fullfile(params.path,'data','DLKcatIgnoreMets.tsv')); +0083 else +0084 fID = fopen(fullfile(geckoPath,'databases','DLKcatIgnoreMets.tsv')); +0085 end +0086 fileData = textscan(fID,'%s %s','delimiter','\t'); +0087 fclose(fID); +0088 [ignoreMets, ignoreSmiles] = deal(fileData{[1,2]}); +0089 ignoreMets = lower(regexprep(ignoreMets,'[^0-9a-zA-Z]+','')); +0090 ignoreSmiles(cellfun(@isempty,ignoreSmiles)) = []; +0091 +0092 ignoreMetsIdx = logical(ismember(metsNoSpecialChars,ignoreMets)); +0093 if isfield(model,'metSmiles') +0094 ignoreMetsIdx = ignoreMetsIdx | logical(ismember(model.metSmiles,ignoreSmiles)); +0095 end +0096 % Also leave out protein-usage pseudometabolites +0097 ignoreMetsIdx = ignoreMetsIdx | startsWith(model.mets,'prot_'); +0098 reducedS = model.S; +0099 reducedS(ignoreMetsIdx,:) = 0; +0100 +0101 % Ignore currency metabolites if they occur in pairs. First check by +0102 % name (case insensitive, without white spaces and special characters), +0103 % then also try to match with metSmiles (if available). +0104 if exist(fullfile(params.path,'data','DLKcatCurrencyMets.tsv'),'file') +0105 fID = fopen(fullfile(params.path,'data','DLKcatCurrencyMets.tsv')); +0106 else +0107 fID = fopen(fullfile(geckoPath,'databases','DLKcatCurrencyMets.tsv')); +0108 end +0109 fileData = textscan(fID,'%s %s','delimiter','\t'); +0110 fclose(fID); +0111 [currencyMets(:,1), currencyMets(:,2)] = deal(fileData{[1,2]}); +0112 currencyMets = lower(regexprep(currencyMets,'[^0-9a-zA-Z]+','')); +0113 +0114 for i=1:size(currencyMets,1) +0115 subs = strcmp(currencyMets(i,1),metsNoSpecialChars); +0116 prod = strcmp(currencyMets(i,2),metsNoSpecialChars); +0117 [~,subsRxns]=find(reducedS(subs,:)); +0118 [~,prodRxns]=find(reducedS(prod,:)); +0119 pairRxns = intersect(subsRxns,prodRxns); +0120 tempRedS=reducedS; +0121 tempRedS([find(subs);find(prod)],pairRxns) = 0; +0122 % Do not remove currency mets if no substrate remains +0123 rxnsWithRemainingSubstrates = any(tempRedS(:,pairRxns) < 0,1); +0124 reducedS([find(subs);find(prod)],intersect(pairRxns,pairRxns(rxnsWithRemainingSubstrates))) = 0; +0125 end +0126 +0127 %filter out the reactions we're not interested in - will solve the problem for both full and light +0128 clearedRedS = reducedS(:,origRxnIdxs); +0129 rxnsToClear = true(length(origRxnIdxs),1); +0130 rxnsToClear(ecRxns) = false; +0131 clearedRedS(:,rxnsToClear) = 0; 0132 -0133 % Enumerate all proteins for each reaction -0134 [proteins, ecRxns] = find(transpose(model.ec.rxnEnzMat(reactions,:))); +0133 % Enumerate all substrates for each reaction +0134 [substrates, reactions] = find(clearedRedS<0); %the reactions here are in model.ec.rxns space 0135 -0136 % Prepare output -0137 out(1,:) = model.ec.rxns(reactions(ecRxns)); -0138 out(2,:) = model.ec.genes(proteins); -0139 out(3,:) = model.metNames(substrates(ecRxns)); -0140 if isfield(model,'metSmiles') -0141 out(4,:) = model.metSmiles(substrates(ecRxns)); -0142 else -0143 out(4,:) = cell(numel(substrates(ecRxns)),1); -0144 end -0145 -0146 out(5,:) = model.ec.sequence(proteins); -0147 if onlyWithSmiles -0148 out(:,cellfun(@isempty,out(4,:))) = []; -0149 else -0150 out(4,cellfun(@isempty,out(4,:))) = {'None'}; -0151 end -0152 out(6,:) = cell(numel(out(1,:)),1); -0153 out(6,:) = {'NA'}; -0154 -0155 % Write file -0156 fID = fopen(filename,'w'); -0157 fprintf(fID,'%s\t%s\t%s\t%s\t%s\t%s\n',out{:}); -0158 fclose(fID); -0159 fprintf('Model-specific DLKcat input stored at %s\n',filename); -0160 -0161 writtenTable = out; -0162 end

    +0136 % Enumerate all proteins for each reaction +0137 [proteins, ecRxns] = find(transpose(model.ec.rxnEnzMat(reactions,:))); +0138 +0139 % Prepare output +0140 out(1,:) = model.ec.rxns(reactions(ecRxns)); +0141 out(2,:) = model.ec.genes(proteins); +0142 out(3,:) = model.metNames(substrates(ecRxns)); +0143 if isfield(model,'metSmiles') +0144 out(4,:) = model.metSmiles(substrates(ecRxns)); +0145 else +0146 out(4,:) = cell(numel(substrates(ecRxns)),1); +0147 end +0148 +0149 out(5,:) = model.ec.sequence(proteins); +0150 if onlyWithSmiles +0151 out(:,cellfun(@isempty,out(4,:))) = []; +0152 else +0153 out(4,cellfun(@isempty,out(4,:))) = {'None'}; +0154 end +0155 out(6,:) = cell(numel(out(1,:)),1); +0156 out(6,:) = {'NA'}; +0157 +0158 % Write file +0159 fID = fopen(filename,'w'); +0160 fprintf(fID,'%s\t%s\t%s\t%s\t%s\t%s\n',out{:}); +0161 fclose(fID); +0162 fprintf('Model-specific DLKcat input stored at %s\n',filename); +0163 +0164 writtenTable = out; +0165 end
    Generated by m2html © 2005
    \ No newline at end of file diff --git a/doc/src/geckomat/get_enzyme_data/loadDatabases.html b/doc/src/geckomat/get_enzyme_data/loadDatabases.html index 90cd975dc..8081de2bc 100644 --- a/doc/src/geckomat/get_enzyme_data/loadDatabases.html +++ b/doc/src/geckomat/get_enzyme_data/loadDatabases.html @@ -116,7 +116,7 @@

    SOURCE CODE ^'uniprot.tsv'); 0055 if ~exist(uniprotPath,'file') 0056 if isempty(uniprot.ID) -0057 printOrange('WARNING: No uniprot.ID is specified, unable to download UniProt DB.\n') +0057 printOrange('WARNING: No uniprot.ID is specified, unable to download UniProt DB.\n'); 0058 end 0059 disp(['Downloading Uniprot data for ' uniprot.type ' ' uniprot.ID '. This can take a few minutes.']) 0060 url = ['https://rest.uniprot.org/uniprotkb/stream?query=' uniprotRev ... @@ -158,7 +158,7 @@

    SOURCE CODE ^'kegg.tsv'); 0097 if ~exist(keggPath,'file') 0098 if isempty(kegg.ID) -0099 printOrange('WARNING: No kegg.ID is specified, unable to download KEGG DB.\n') +0099 printOrange('WARNING: No kegg.ID is specified, unable to download KEGG DB.\n'); 0100 else 0101 downloadKEGG(kegg.ID,keggPath,kegg.geneID); 0102 end diff --git a/doc/src/geckomat/kcat_sensitivity_analysis/sensitivityTuning.html b/doc/src/geckomat/kcat_sensitivity_analysis/sensitivityTuning.html index 411721bc7..93a4112f4 100644 --- a/doc/src/geckomat/kcat_sensitivity_analysis/sensitivityTuning.html +++ b/doc/src/geckomat/kcat_sensitivity_analysis/sensitivityTuning.html @@ -148,7 +148,7 @@

    SOURCE CODE ^while true 0072 [res,hs] = solveLP(m,0,[],hs); %skip parsimonius, only takes time 0073 if (lastGrowth == res.f) -0074 printOrange('WARNING: No growth increase from increased kcats - check if the constraints on the uptake reactions are too tight.\n') +0074 printOrange('WARNING: No growth increase from increased kcats - check if the constraints on the uptake reactions are too tight.\n'); 0075 break; 0076 end 0077 lastGrowth = res.f; @@ -199,7 +199,7 @@

    SOURCE CODE ^while true 0123 res = solveLP(m,0); %skip parsimonius, only takes time 0124 if (lastGrowth == res.f) -0125 printOrange('No growth increase from increased kcats - check if the constraints on the uptake reactions are too tight.\n') +0125 printOrange('No growth increase from increased kcats - check if the constraints on the uptake reactions are too tight.\n'); 0126 break; 0127 end 0128 lastGrowth = res.f; diff --git a/doc/src/geckomat/limit_proteins/calculateFfactor.html b/doc/src/geckomat/limit_proteins/calculateFfactor.html index 118fb54ee..ae81fe1df 100644 --- a/doc/src/geckomat/limit_proteins/calculateFfactor.html +++ b/doc/src/geckomat/limit_proteins/calculateFfactor.html @@ -94,7 +94,7 @@

    SOURCE CODE ^if exist(fullfile(params.path,'data','paxDB.tsv'),'file') 0035 protData = fullfile(params.path,'data','paxDB.tsv'); 0036 else -0037 printOrange('WARNING: No proteomics data is provided or can be found. Default f value of 0.5 is returned.\n') +0037 printOrange('WARNING: No proteomics data is provided or can be found. Default f value of 0.5 is returned.\n'); 0038 f = 0.5; 0039 end 0040 end diff --git a/doc/src/geckomat/limit_proteins/flexibilizeEnzConcs.html b/doc/src/geckomat/limit_proteins/flexibilizeEnzConcs.html index 8ef414ab0..539fa531b 100644 --- a/doc/src/geckomat/limit_proteins/flexibilizeEnzConcs.html +++ b/doc/src/geckomat/limit_proteins/flexibilizeEnzConcs.html @@ -237,7 +237,7 @@

    SOURCE CODE ^'Protein ' proteins{maxIdx} ' LB adjusted. Grow: ' num2str(predGrowth)]) 0143 end 0144 else -0145 printOrange(['WARNING: Limit has been reached. Protein ' proteins{maxIdx} ' seems to be problematic. Consider changing the kcat.\n']) +0145 printOrange(['WARNING: Limit has been reached. Protein ' proteins{maxIdx} ' seems to be problematic. Consider changing the kcat.\n']); 0146 flexBreak=true; 0147 break 0148 end diff --git a/doc/src/geckomat/utilities/addNewRxnsToEC.html b/doc/src/geckomat/utilities/addNewRxnsToEC.html index 703b38ee3..8a416f8d3 100644 --- a/doc/src/geckomat/utilities/addNewRxnsToEC.html +++ b/doc/src/geckomat/utilities/addNewRxnsToEC.html @@ -163,7 +163,7 @@

    SOURCE CODE ^% Remove from the list those enzymes that already present 0075 if any(toRemove) -0076 printOrange(['WARNING: Enzymes ' strjoin(newEnzymes.enzymes(toRemove),', ') ' are already present in the model and will not be added.\n']) +0076 printOrange(['WARNING: Enzymes ' strjoin(newEnzymes.enzymes(toRemove),', ') ' are already present in the model and will not be added.\n']); 0077 newEnzymes.enzymes(toRemove) = []; 0078 newEnzymes.genes(toRemove) = []; 0079 newEnzymes.mw(toRemove) = []; diff --git a/doc/src/geckomat/utilities/ecFSEOF.html b/doc/src/geckomat/utilities/ecFSEOF.html index c6aaab129..d6d4081fb 100644 --- a/doc/src/geckomat/utilities/ecFSEOF.html +++ b/doc/src/geckomat/utilities/ecFSEOF.html @@ -168,7 +168,7 @@

    SOURCE CODE ^if model.lb(csRxnIdx) < sol.x(csRxnIdx) 0082 printOrange(['WARNING: Carbon source lower bound was set to ' num2str(model.lb(csRxnIdx)) ... -0083 ', but the uptake rate after model optimization is ' num2str(sol.x(csRxnIdx)) '.\n']) +0083 ', but the uptake rate after model optimization is ' num2str(sol.x(csRxnIdx)) '.\n']); 0084 end 0085 0086 % run FSEOF analysis diff --git a/doc/src/geckomat/utilities/getSubsetEcModel.html b/doc/src/geckomat/utilities/getSubsetEcModel.html index 49359f00a..7ec9742dd 100644 --- a/doc/src/geckomat/utilities/getSubsetEcModel.html +++ b/doc/src/geckomat/utilities/getSubsetEcModel.html @@ -96,7 +96,7 @@

    SOURCE CODE ^% Check if original bigEcModel contains context-dependent protein constraints 0033 if any(bigEcModel.lb(startsWith(bigEcModel.rxns,'usage_prot_')) ~= -1000) 0034 printOrange(['WARNING: The bigEcModel is constraint by protein concentrations that are\n' ... -0035 'likely not relevant in the constructed smallEcModel.\n']) +0035 'likely not relevant in the constructed smallEcModel.\n']); 0036 end 0037 0038 % Remove genes (and associated reactions) that are absent in smallGEM diff --git a/doc/src/geckomat/utilities/startGECKOproject.html b/doc/src/geckomat/utilities/startGECKOproject.html index f51e357ec..190d5b0df 100644 --- a/doc/src/geckomat/utilities/startGECKOproject.html +++ b/doc/src/geckomat/utilities/startGECKOproject.html @@ -111,7 +111,7 @@

    SOURCE CODE ^else -0058 printOrange('WARNING: A project with the same name exits at the same location. The project was not created.\n') +0058 printOrange('WARNING: A project with the same name exits at the same location. The project was not created.\n'); 0059 end 0060 cd(fullPath) 0061 end diff --git a/src/geckomat/change_model/applyCustomKcats.m b/src/geckomat/change_model/applyCustomKcats.m index b3b3dce29..bf95deb0d 100644 --- a/src/geckomat/change_model/applyCustomKcats.m +++ b/src/geckomat/change_model/applyCustomKcats.m @@ -185,7 +185,7 @@ if ~isempty(find(rxnToUpdate, 1)) model = applyKcatConstraints(model, rxnToUpdate); else - printOrange('WARNING: No matches found. Consider checking the IDs or proteins in customKcats.') + printOrange('WARNING: No matches found. Consider checking the IDs or proteins in customKcats.'); end rxnUpdated = model.ec.rxns(find(rxnToUpdate)); diff --git a/src/geckomat/change_model/applyKcatConstraints.m b/src/geckomat/change_model/applyKcatConstraints.m index 648a1ed17..2073dbf7e 100644 --- a/src/geckomat/change_model/applyKcatConstraints.m +++ b/src/geckomat/change_model/applyKcatConstraints.m @@ -46,7 +46,7 @@ ' not a valid GECKO3 ecModel. First run makeEcModel(model).']) end if all(model.ec.kcat==0) - printOrange('WARNING: No kcat values are provided in model.ec.kcat, model remains unchanged.\n') + printOrange('WARNING: No kcat values are provided in model.ec.kcat, model remains unchanged.\n'); return end diff --git a/src/geckomat/change_model/getComplexData.m b/src/geckomat/change_model/getComplexData.m index 75a7f54f6..47fc57f64 100644 --- a/src/geckomat/change_model/getComplexData.m +++ b/src/geckomat/change_model/getComplexData.m @@ -44,7 +44,7 @@ params = modelAdapter.params; if isempty(taxonomicID) % Can be empty when gathered from model adapter - printOrange('WARNING: No taxonomicID specified.') + printOrange('WARNING: No taxonomicID specified.'); return elseif taxonomicID == 0 taxonomicID = []; diff --git a/src/geckomat/change_model/getKcatAcrossIsozymes.m b/src/geckomat/change_model/getKcatAcrossIsozymes.m index 5e514cda5..9b52b61ae 100644 --- a/src/geckomat/change_model/getKcatAcrossIsozymes.m +++ b/src/geckomat/change_model/getKcatAcrossIsozymes.m @@ -18,7 +18,7 @@ error('Provided model is a GECKO light version, this function is not relevant for such models') end if all(model.ec.kcat==0) - printOrange('WARNING: No kcat values are provided in model.ec.kcat, model remains unchanged.\n') + printOrange('WARNING: No kcat values are provided in model.ec.kcat, model remains unchanged.\n'); return end diff --git a/src/geckomat/change_model/makeEcModel.m b/src/geckomat/change_model/makeEcModel.m index 1e71b1815..aceddcda2 100644 --- a/src/geckomat/change_model/makeEcModel.m +++ b/src/geckomat/change_model/makeEcModel.m @@ -257,11 +257,13 @@ end noUniprot = uniprotCompatibleGenes(~Lia); if all(~Lia) - error('None of the proteins in uniprot.tsv match the genes in the model. Changes to the obj.params.uniprot parameters are likely required.') + error('None of the proteins in uniprot.tsv match the genes in the model. Changes to the obj.params.uniprot parameters, or a data/uniprotConversion.tsv file are likely required.') elseif ~isempty(noUniprot) - printOrange(['WARNING: The ' num2str(numel(noUniprot)) ' gene(s) reported in noUniprot cannot be found in data/uniprot.tsv, these will\n' ... - 'not be enzyme-constrained. If you intend to use different Uniprot data (e.g. from a\n'... - 'different proteome, make sure you first delete the existing data/uniprot.tsv file.\n']) + printOrange(['WARNING: The ' num2str(numel(noUniprot)) ' gene(s) reported '... + 'in "noUniprot" cannot be found in data/uniprot.tsv, these will ' ... + 'not be enzyme-constrained. If you intend to use different Uniprot '... + 'data (e.g. from a different proteome, make sure you first delete '... + 'the existing data/uniprot.tsv file.\n']); end ec.genes = model.genes(Lia); %Will often be duplicate of model.genes, but is done here to prevent issues when it is not. ec.enzymes = uniprotDB.ID(Locb(Lia)); @@ -288,7 +290,7 @@ %here we need to make an explicit format check indexes2check = findPotentialErrors(model.grRules,model); if ~isempty(indexes2check) - printOrange('Run standardizeGrRules(model) for a more detailed warning.\n') + printOrange('Run standardizeGrRules(model) for a more detailed warning.\n'); printOrange('For Human-GEM, these reactions can be corrected using simplifyGrRules.\n'); end diff --git a/src/geckomat/gather_kcats/getStandardKcat.m b/src/geckomat/gather_kcats/getStandardKcat.m index e11eb9819..0a5203b8f 100644 --- a/src/geckomat/gather_kcats/getStandardKcat.m +++ b/src/geckomat/gather_kcats/getStandardKcat.m @@ -121,11 +121,11 @@ kcatSubSystem(kcatsPerSubSystem < threshold) = standardKcat; else standard = true; - printOrange('WARNING: No subSystem-specific kcat values can be calculated') + printOrange('WARNING: No subSystem-specific kcat values can be calculated'); end else standard = true; - printOrange('WARNING: No subSystem-specific kcat values can be calculated') + printOrange('WARNING: No subSystem-specific kcat values can be calculated'); end % Find reactions without GPR diff --git a/src/geckomat/gather_kcats/readDLKcatOutput.m b/src/geckomat/gather_kcats/readDLKcatOutput.m index 1effd5fe8..290c7d012 100644 --- a/src/geckomat/gather_kcats/readDLKcatOutput.m +++ b/src/geckomat/gather_kcats/readDLKcatOutput.m @@ -6,10 +6,9 @@ % % Input: % model an ecModel in GECKO 3 format (with ecModel.ec structure) -% outFile name and path of the DLKcat output file. If nothing is -% provided, an attempt will be made to read -% data/DLKcat.tsv from the obj.params.path folder -% specified in the modelAdapter. +% outFile name and path of the DLKcat output file. (Optional, +% default is data/DLKcat.tsv from the obj.params.path +% folder specified in the modelAdapter) % modelAdapter a loaded model adapter (Optional, will otherwise use the % default model adapter). % diff --git a/src/geckomat/gather_kcats/runDLKcat.m b/src/geckomat/gather_kcats/runDLKcat.m index 4701cc268..3c9807acb 100644 --- a/src/geckomat/gather_kcats/runDLKcat.m +++ b/src/geckomat/gather_kcats/runDLKcat.m @@ -1,4 +1,4 @@ -function runDLKcat(modelAdapter) +function runDLKcat(modelAdapter,filePath) % runDLKcat % Runs DLKcat to predict kcat values from a Docker image. Once DLKcat is succesfully % run, the DLKcatFile will be overwritten with the DLKcat @@ -8,6 +8,8 @@ function runDLKcat(modelAdapter) % Input % modelAdapter a loaded model adapter. (Optional, will otherwise use % the default model adapter) +% filePath path to the DLKcat.tsv file. (Optional, will otherwise +% assume data/DLKcat.tsv) % % NOTE: 1. Requires Docker to be installed, and Docker Desktop running. Visit "https://www.docker.com" % 2. Runtime will depend on whether the image is to be downloaded or not. @@ -18,12 +20,21 @@ function runDLKcat(modelAdapter) error('Either send in a modelAdapter or set the default model adapter in the ModelAdapterManager.') end end - params = modelAdapter.params; % Make sure path is full, not relative [~, params.path] = fileattrib(params.path); params.path=params.path.Name; +if nargin < 2 || isempty(filePath) + filePath = fullfile(params.path,'data','DLKcat.tsv'); +elseif strcmp(filePath(end),{'\','/'}) + filePath = fullfile(filePath,'DLKcat.tsv'); +end +filePath = checkFileExistence(filePath,1); + +copyfile(filePath, fullfile(params.path,'data','tempDLKcat.tsv')); + + %% Check and install requirements % On macOS, Docker might not be properly loaded if MATLAB is started via % launcher and not terminal. @@ -38,11 +49,11 @@ function runDLKcat(modelAdapter) end disp('Running DLKcat prediction, this may take many minutes, especially the first time.') -status = system(['docker run --rm -v "' fullfile(params.path,'/data') '":/data ghcr.io/sysbiochalmers/dlkcat-gecko:0.1 /bin/bash -c "python DLKcat.py /data/DLKcat.tsv /data/DLKcatOutput.tsv"']); +status = system(['docker run --rm -v "' fullfile(params.path,'/data') '":/data ghcr.io/sysbiochalmers/dlkcat-gecko:0.1 /bin/bash -c "python DLKcat.py /data/tempDLKcat.tsv /data/tempDLKcatOutput.tsv"']); +delete(fullfile(params.path,'/data/tempDLKcat.tsv')); -if status == 0 && exist(fullfile(params.path,'data/DLKcatOutput.tsv')) - delete(fullfile(params.path,'/data/DLKcat.tsv')); - movefile(fullfile(params.path,'/data/DLKcatOutput.tsv'), fullfile(params.path,'/data/DLKcat.tsv')); +if status == 0 && exist(fullfile(params.path,'data/tempDLKcatOutput.tsv')) + movefile(fullfile(params.path,'/data/tempDLKcatOutput.tsv'), filePath); disp('DKLcat prediction completed.'); else error('DLKcat encountered an error or it did not create any output file.') diff --git a/src/geckomat/gather_kcats/writeDLKcatInput.m b/src/geckomat/gather_kcats/writeDLKcatInput.m index fd802746a..090b02e77 100644 --- a/src/geckomat/gather_kcats/writeDLKcatInput.m +++ b/src/geckomat/gather_kcats/writeDLKcatInput.m @@ -13,8 +13,9 @@ % default model adapter). % onlyWithSmiles logical whether to only include metabolites with SMILES % (optional, default true) -% filename Filename (Optional). Normally this parameter should not be -% supplied, but it is useful for test cases. +% filename path to the input file, including the filename and .tsv +% extension (Optional, default is data/DLKcat.tsv from +% the obj.params.path folder specified in the modelAdapter) % overwrite logical whether existing file should be overwritten. % (Optional, default false, to prevent overwriting file % that already contains DLKcat-predicted kcat values). @@ -50,6 +51,8 @@ if nargin<5 || isempty(filename) filename = fullfile(params.path,'data','DLKcat.tsv'); +elseif ~endsWith(filename,'.tsv') + error('If filename is provided, it should include the .tsv extension.') end if nargin<6 || isempty(overwrite) || ~overwrite % If is true diff --git a/src/geckomat/get_enzyme_data/loadDatabases.m b/src/geckomat/get_enzyme_data/loadDatabases.m index 3e4493257..2b6d6cfa2 100644 --- a/src/geckomat/get_enzyme_data/loadDatabases.m +++ b/src/geckomat/get_enzyme_data/loadDatabases.m @@ -54,7 +54,7 @@ uniprotPath = fullfile(filePath,'uniprot.tsv'); if ~exist(uniprotPath,'file') if isempty(uniprot.ID) - printOrange('WARNING: No uniprot.ID is specified, unable to download UniProt DB.\n') + printOrange('WARNING: No uniprot.ID is specified, unable to download UniProt DB.\n'); end disp(['Downloading Uniprot data for ' uniprot.type ' ' uniprot.ID '. This can take a few minutes.']) url = ['https://rest.uniprot.org/uniprotkb/stream?query=' uniprotRev ... @@ -96,7 +96,7 @@ keggPath = fullfile(filePath,'kegg.tsv'); if ~exist(keggPath,'file') if isempty(kegg.ID) - printOrange('WARNING: No kegg.ID is specified, unable to download KEGG DB.\n') + printOrange('WARNING: No kegg.ID is specified, unable to download KEGG DB.\n'); else downloadKEGG(kegg.ID,keggPath,kegg.geneID); end diff --git a/src/geckomat/kcat_sensitivity_analysis/sensitivityTuning.m b/src/geckomat/kcat_sensitivity_analysis/sensitivityTuning.m index f595f1457..574a11cf3 100644 --- a/src/geckomat/kcat_sensitivity_analysis/sensitivityTuning.m +++ b/src/geckomat/kcat_sensitivity_analysis/sensitivityTuning.m @@ -71,7 +71,7 @@ while true [res,hs] = solveLP(m,0,[],hs); %skip parsimonius, only takes time if (lastGrowth == res.f) - printOrange('WARNING: No growth increase from increased kcats - check if the constraints on the uptake reactions are too tight.\n') + printOrange('WARNING: No growth increase from increased kcats - check if the constraints on the uptake reactions are too tight.\n'); break; end lastGrowth = res.f; @@ -122,7 +122,7 @@ while true res = solveLP(m,0); %skip parsimonius, only takes time if (lastGrowth == res.f) - printOrange('No growth increase from increased kcats - check if the constraints on the uptake reactions are too tight.\n') + printOrange('No growth increase from increased kcats - check if the constraints on the uptake reactions are too tight.\n'); break; end lastGrowth = res.f; diff --git a/src/geckomat/limit_proteins/calculateFfactor.m b/src/geckomat/limit_proteins/calculateFfactor.m index cb7732ab5..b70c13f63 100644 --- a/src/geckomat/limit_proteins/calculateFfactor.m +++ b/src/geckomat/limit_proteins/calculateFfactor.m @@ -34,7 +34,7 @@ if exist(fullfile(params.path,'data','paxDB.tsv'),'file') protData = fullfile(params.path,'data','paxDB.tsv'); else - printOrange('WARNING: No proteomics data is provided or can be found. Default f value of 0.5 is returned.\n') + printOrange('WARNING: No proteomics data is provided or can be found. Default f value of 0.5 is returned.\n'); f = 0.5; end end diff --git a/src/geckomat/limit_proteins/flexibilizeEnzConcs.m b/src/geckomat/limit_proteins/flexibilizeEnzConcs.m index e4a10e371..fd69e1565 100644 --- a/src/geckomat/limit_proteins/flexibilizeEnzConcs.m +++ b/src/geckomat/limit_proteins/flexibilizeEnzConcs.m @@ -142,7 +142,7 @@ disp(['Protein ' proteins{maxIdx} ' LB adjusted. Grow: ' num2str(predGrowth)]) end else - printOrange(['WARNING: Limit has been reached. Protein ' proteins{maxIdx} ' seems to be problematic. Consider changing the kcat.\n']) + printOrange(['WARNING: Limit has been reached. Protein ' proteins{maxIdx} ' seems to be problematic. Consider changing the kcat.\n']); flexBreak=true; break end diff --git a/src/geckomat/utilities/addNewRxnsToEC.m b/src/geckomat/utilities/addNewRxnsToEC.m index eb1c45115..868826cde 100644 --- a/src/geckomat/utilities/addNewRxnsToEC.m +++ b/src/geckomat/utilities/addNewRxnsToEC.m @@ -73,7 +73,7 @@ % Remove from the list those enzymes that already present if any(toRemove) - printOrange(['WARNING: Enzymes ' strjoin(newEnzymes.enzymes(toRemove),', ') ' are already present in the model and will not be added.\n']) + printOrange(['WARNING: Enzymes ' strjoin(newEnzymes.enzymes(toRemove),', ') ' are already present in the model and will not be added.\n']); newEnzymes.enzymes(toRemove) = []; newEnzymes.genes(toRemove) = []; newEnzymes.mw(toRemove) = []; diff --git a/src/geckomat/utilities/ecFSEOF.m b/src/geckomat/utilities/ecFSEOF.m index 0940c827c..c74bcd67d 100644 --- a/src/geckomat/utilities/ecFSEOF.m +++ b/src/geckomat/utilities/ecFSEOF.m @@ -80,7 +80,7 @@ sol = solveLP(model); if model.lb(csRxnIdx) < sol.x(csRxnIdx) printOrange(['WARNING: Carbon source lower bound was set to ' num2str(model.lb(csRxnIdx)) ... - ', but the uptake rate after model optimization is ' num2str(sol.x(csRxnIdx)) '.\n']) + ', but the uptake rate after model optimization is ' num2str(sol.x(csRxnIdx)) '.\n']); end % run FSEOF analysis diff --git a/src/geckomat/utilities/getSubsetEcModel.m b/src/geckomat/utilities/getSubsetEcModel.m index f7c8f5cbd..90d176f17 100644 --- a/src/geckomat/utilities/getSubsetEcModel.m +++ b/src/geckomat/utilities/getSubsetEcModel.m @@ -32,7 +32,7 @@ % Check if original bigEcModel contains context-dependent protein constraints if any(bigEcModel.lb(startsWith(bigEcModel.rxns,'usage_prot_')) ~= -1000) printOrange(['WARNING: The bigEcModel is constraint by protein concentrations that are\n' ... - 'likely not relevant in the constructed smallEcModel.\n']) + 'likely not relevant in the constructed smallEcModel.\n']); end % Remove genes (and associated reactions) that are absent in smallGEM diff --git a/src/geckomat/utilities/startGECKOproject.m b/src/geckomat/utilities/startGECKOproject.m index f6f2c2c88..cb5c7b1ae 100644 --- a/src/geckomat/utilities/startGECKOproject.m +++ b/src/geckomat/utilities/startGECKOproject.m @@ -55,7 +55,7 @@ function startGECKOproject(name, path) fwrite(fid, f); fclose(fid); else - printOrange('WARNING: A project with the same name exits at the same location. The project was not created.\n') + printOrange('WARNING: A project with the same name exits at the same location. The project was not created.\n'); end cd(fullPath) end