diff --git a/doc/index.html b/doc/index.html index 3ab7d918..65aafbd2 100644 --- a/doc/index.html +++ b/doc/index.html @@ -3,8 +3,8 @@ Matlab Index - - + + @@ -15,26 +15,39 @@

Matlab Index

Matlab Directories

+
  • src/change_model
  • src/deprecated
  • src/download_databases
  • src/enzyme_usage
  • src/flux_analysis
  • src/gather_kcats
  • src/get_enzyme_data
  • src/io
  • src/kcat_tuning
  • src/kcat_tuning/evotune
  • src/limit_proteins
  • src/model_adapter
  • src/utilities
  • Matlab Files found in these Directories

    - - - - - - - - - - - - - - - -
    ModelAdapter ecFVA getStandardKcat removeStandardKcat
    ModelAdapterManager enzymeUsage getSubsetEcModel reportEnzymeUsage
    abc_max fillEnzConcs getrSample runDLKcat
    adapterTemplate findECInDB loadBRENDAdata saveEcModel
    addCarbonNum findGECKOroot loadBayesianData selectKcatValue
    addNewRxnsToEC findMaxValue loadConventionalGEM sensitivityTuning
    applyComplexData findMetSmiles loadDatabases setKcatForReactions
    applyCustomKcats flexibilizeEnzConcs loadEcModel setProtPoolSize
    applyKcatConstraints fuzzyKcatMatching loadFluxData sigmaFitter
    bayesianSensitivityTuning getComplexData loadProtData startGECKOproject
    calculateFfactor getConcControlCoeffs makeEcModel truncateValues
    calculateMW getECfromDatabase mapRxnsToConv updateGECKOdoc
    constrainEnzConcs getECfromGEM mergeDLKcatAndFuzzyKcats updateProtPool
    constrainFluxData getECstring mse updateprior
    copyECtoGEM getKcatAcrossIsozymes plotEcFVA writeDLKcatInput
    ecFSEOF getReactionsFromEnzyme readDLKcatOutput
    + ModelAdapter ecTreeEstimate kcatsFromDLKcat resolveKcatAggregation + ModelAdapterManager enzymeUsage kcatsFromECTree resolveOkpApiKey + TomlAdapter evotuneScore kcatsFromHomologs resolveTunableContext + adapterTemplate extractEnzymeSubstratePairs kcatsFromOKP reviewKcatAssignment + addCarbonNum fetchBrendaAsset loadAdapterParams runDLKcat + addNewRxnsToEC fetchOpenKineticsPredictor loadBRENDAdata saveEcModel + applyComplexData fillCarbonNum loadBrendaMeasurements saveKcatSource + applyCustomKcats fillEnzConcs loadConventionalGEM screenKcatLeverage + applyECcodes findECInDB loadDatabases selectKcatValue + applyKcatConstraints findGECKOroot loadEcModel selectTunableMask + assignKcatValues findMetSmiles loadEvotuneData sensitivityTuning + assignKcats flexibilizeEnzConcs loadFluxData setKcatForReactions + bestParsimonious fuzzyKcatMatching loadKcatSource setProtPoolSize + buildGECKOdoc getComplexData loadProtData sigmaFitter + calculateFfactor getConcControlCoeffs makeEcModel startGECKOproject + calculateMW getECfromDatabase mapRxnsToConv submitOpenKineticsPredictor + cmaesKcatTuning getECfromGEM mergeDLKcatAndFuzzyKcats truncateValues + collectKcats getECstring mergeKcats tunePriorPenaltyWeight + constrainEnzConcs getEcRxnKeys nChanged updateGECKOdoc + constrainFluxData getEnzymeBottlenecks parseGECKOargs updateKcatSources + convertAdapterToToml getEnzymeUsage parsimonyFrontier updateProtPool + convertCustomKcats getKcatAcrossIsozymes pfbaEnzymes upgradeEcModel + copyECtoGEM getPfbaEnzymes plotEcFVA upgradeGECKOproject + createGECKOproject getReactionsFromEnzyme readAdapterToml writeAdapterToml + downloadKEGG getStandardKcat readDLKcatOutput writeDLKcatInput + downloadUniProt getSubsetEcModel readOpenKineticsPredictorOutput writeOpenKineticsPredictorInput + ecFSEOF isozymeTieMap relaxProteomicsGreedy + ecFVA kcatAssignmentConfig removeStandardKcat + ecStatsFromBrenda kcatsFromBrenda reportEnzymeUsage
    Generated by m2html © 2005
    diff --git a/doc/src/change_model/addNewRxnsToEC.html b/doc/src/change_model/addNewRxnsToEC.html new file mode 100644 index 00000000..0d5c21ec --- /dev/null +++ b/doc/src/change_model/addNewRxnsToEC.html @@ -0,0 +1,437 @@ + + + + Description of addNewRxnsToEC + + + + + + + + + +
    Home > src > change_model > addNewRxnsToEC.m
    + + + +

    addNewRxnsToEC +

    + +

    PURPOSE ^

    +
    addNewRxnsToEC Add new reactions to an enzyme-constrained model.
    + +

    SYNOPSIS ^

    +
    function [model, rxnsAdded, enzAdded] = addNewRxnsToEC(model, newRxns, varargin)
    + +

    DESCRIPTION ^

    +
     addNewRxnsToEC  Add new reactions to an enzyme-constrained model.
    +
    + Adds new reactions to an enzyme-constrained model. This function is
    + useful to simulate metabolic manipulations done to an organism such as
    + integration of new genes that add a new reaction/pathway.
    +
    + Parameters
    + ----------
    + model : struct
    +     an ecModel in GECKO 3 format (with ecModel.ec structure).
    + newRxns : struct
    +     structure with the new reaction information (see Notes for fields).
    +
    + Name-Value Arguments
    + --------------------
    + newEnzymes : struct
    +     structure with the new enzymes information (see Notes for fields).
    + modelAdapter : ModelAdapter
    +     a loaded model adapter (default: the current default model adapter).
    +
    + Returns
    + -------
    + model : struct
    +     ecModel with new reactions.
    + rxnsAdded : cell
    +     cell array with the reactions added.
    + enzAdded : cell
    +     cell array with the enzymes added.
    +
    + Notes
    + -----
    + The newRxns structure has the following fields:
    +
    + - rxns : cell array with unique strings that identifies each reaction.
    + - rxnNames : cell array with the names of each reaction.
    + - equations : cell array with equation strings. Decimal coefficients are expressed as "1.2". Reversibility is indicated by "<=>" or "=>".
    + - grRules : cell array with the gene-reaction relationship for each reaction. For example "(A and B) or (C)" means that the reaction could be catalyzed by a complex between A & B or by C on its own. A rule with brackets is split into its isozymes in disjunctive normal form, so "A and (B or C)" is the two isozymes "A and B" and "A and C". All the genes have to be present in model.genes. Add genes with addGenesRaven before calling this function if needed (opt, default '').
    +
    + The newEnzymes structure has the following fields:
    +
    + - enzymes : cell array with uniprot id.
    + - genes : cell array with the respective gene.
    + - mw : cell array with the MW.
    +
    + Additional usage notes:
    +
    + 1. Write equations as follows:
    +        'xylitol[c] + NAD[c] => D-xylulose[c] + NADH[c] + H+[c]'
    +    Note that the reversibility defined in the equation will be used to
    +    split to construct irreversible reactions (add _REV) and the rules
    +    defined will be used to expand the model (add _EXP_n).
    + 2. After adding the new reactions, setKcatForReactions or
    +    applyCustomKcats should be run to add the kcat to the reactions, and
    +    subsequently applyKcatConstraints.
    +
    + Examples
    + --------
    +     % optional arguments may be given positionally or as name-value pairs:
    +     [model, rxnsAdded, enzAdded] = addNewRxnsToEC(model, newRxns, newEnzymes, modelAdapter);
    +     [model, rxnsAdded, enzAdded] = addNewRxnsToEC(model, newRxns, 'newEnzymes', newEnzymes);
    +
    + See also
    + --------
    + applyKcatConstraints, applyCustomKcats
    + + +

    CROSS-REFERENCE INFORMATION ^

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

    SUBFUNCTIONS ^

    + + +

    SOURCE CODE ^

    +
    0001 function [model, rxnsAdded, enzAdded] = addNewRxnsToEC(model, newRxns, varargin)
    +0002 % addNewRxnsToEC  Add new reactions to an enzyme-constrained model.
    +0003 %
    +0004 % Adds new reactions to an enzyme-constrained model. This function is
    +0005 % useful to simulate metabolic manipulations done to an organism such as
    +0006 % integration of new genes that add a new reaction/pathway.
    +0007 %
    +0008 % Parameters
    +0009 % ----------
    +0010 % model : struct
    +0011 %     an ecModel in GECKO 3 format (with ecModel.ec structure).
    +0012 % newRxns : struct
    +0013 %     structure with the new reaction information (see Notes for fields).
    +0014 %
    +0015 % Name-Value Arguments
    +0016 % --------------------
    +0017 % newEnzymes : struct
    +0018 %     structure with the new enzymes information (see Notes for fields).
    +0019 % modelAdapter : ModelAdapter
    +0020 %     a loaded model adapter (default: the current default model adapter).
    +0021 %
    +0022 % Returns
    +0023 % -------
    +0024 % model : struct
    +0025 %     ecModel with new reactions.
    +0026 % rxnsAdded : cell
    +0027 %     cell array with the reactions added.
    +0028 % enzAdded : cell
    +0029 %     cell array with the enzymes added.
    +0030 %
    +0031 % Notes
    +0032 % -----
    +0033 % The newRxns structure has the following fields:
    +0034 %
    +0035 % - rxns : cell array with unique strings that identifies each reaction.
    +0036 % - rxnNames : cell array with the names of each reaction.
    +0037 % - equations : cell array with equation strings. Decimal coefficients are expressed as "1.2". Reversibility is indicated by "<=>" or "=>".
    +0038 % - grRules : cell array with the gene-reaction relationship for each reaction. For example "(A and B) or (C)" means that the reaction could be catalyzed by a complex between A & B or by C on its own. A rule with brackets is split into its isozymes in disjunctive normal form, so "A and (B or C)" is the two isozymes "A and B" and "A and C". All the genes have to be present in model.genes. Add genes with addGenesRaven before calling this function if needed (opt, default '').
    +0039 %
    +0040 % The newEnzymes structure has the following fields:
    +0041 %
    +0042 % - enzymes : cell array with uniprot id.
    +0043 % - genes : cell array with the respective gene.
    +0044 % - mw : cell array with the MW.
    +0045 %
    +0046 % Additional usage notes:
    +0047 %
    +0048 % 1. Write equations as follows:
    +0049 %        'xylitol[c] + NAD[c] => D-xylulose[c] + NADH[c] + H+[c]'
    +0050 %    Note that the reversibility defined in the equation will be used to
    +0051 %    split to construct irreversible reactions (add _REV) and the rules
    +0052 %    defined will be used to expand the model (add _EXP_n).
    +0053 % 2. After adding the new reactions, setKcatForReactions or
    +0054 %    applyCustomKcats should be run to add the kcat to the reactions, and
    +0055 %    subsequently applyKcatConstraints.
    +0056 %
    +0057 % Examples
    +0058 % --------
    +0059 %     % optional arguments may be given positionally or as name-value pairs:
    +0060 %     [model, rxnsAdded, enzAdded] = addNewRxnsToEC(model, newRxns, newEnzymes, modelAdapter);
    +0061 %     [model, rxnsAdded, enzAdded] = addNewRxnsToEC(model, newRxns, 'newEnzymes', newEnzymes);
    +0062 %
    +0063 % See also
    +0064 % --------
    +0065 % applyKcatConstraints, applyCustomKcats
    +0066 
    +0067 p = parseGECKOargs(varargin, { ...
    +0068     'newEnzymes',   []; ...
    +0069     'modelAdapter', []});
    +0070 newEnzymes   = p.newEnzymes;
    +0071 modelAdapter = p.modelAdapter;
    +0072 
    +0073 if isempty(modelAdapter)
    +0074     modelAdapter = ModelAdapterManager.getDefault();
    +0075     if isempty(modelAdapter)
    +0076         error('Either send in a modelAdapter or set the default model adapter in the ModelAdapterManager.')
    +0077     end
    +0078 end
    +0079 params = modelAdapter.getParameters();
    +0080 
    +0081 if isempty(newEnzymes)
    +0082     newEnzymes = [];
    +0083 end
    +0084 
    +0085 % Validate if GECKO version 3
    +0086 if ~isfield(model, 'ec')
    +0087     error('Input model is not an ecModel in GECKO 3 format (with ecModel.ec structure)')
    +0088 end
    +0089 
    +0090 if model.ec.geckoLight
    +0091     error('addNewRxnsToEC only works on non-light ecModels')
    +0092 else
    +0093     % Check if the new proteins are not already present in the model
    +0094     if ~isempty(newEnzymes)
    +0095         [toRemove,~] = ismember(newEnzymes.enzymes, model.ec.enzymes);
    +0096 
    +0097         % Remove from the list those enzymes that already present
    +0098         if any(toRemove)
    +0099             printOrange(['WARNING: Enzymes ' strjoin(newEnzymes.enzymes(toRemove),', ') ' are already present in the model and will not be added.\n']);
    +0100             newEnzymes.enzymes(toRemove) = [];
    +0101             newEnzymes.genes(toRemove) = [];
    +0102             newEnzymes.mw(toRemove) = [];
    +0103         end
    +0104 
    +0105         if ~isempty(newEnzymes.enzymes)
    +0106             
    +0107             % 1. Add new genes
    +0108             genesToAdd.genes = newEnzymes.genes;
    +0109             genesToAdd.geneShortNames = genesToAdd.genes;
    +0110             model = addGenesRaven(model, genesToAdd);
    +0111 
    +0112             % 2. Add new Enzyme-usage pseudometabolite
    +0113 
    +0114             % Validate compartment to add protein pseudoreactions
    +0115             compartmentID = strcmp(model.compNames,params.enzyme_comp);
    +0116             if ~any(compartmentID)
    +0117                 error(['Compartment ' params.enzyme_comp ' (specified in params.enzyme_comp) '...
    +0118                     'cannot be found in model.compNames'])
    +0119             end
    +0120             compartmentID = model.comps(compartmentID);
    +0121 
    +0122             proteinMets.mets         = strcat('prot_', newEnzymes.enzymes);
    +0123             proteinMets.metNames     = proteinMets.mets;
    +0124             proteinMets.compartments = compartmentID;
    +0125             if isfield(model,'metMiriams')
    +0126                 proteinMets.metMiriams = repmat({struct('name',{{'sbo'}},'value',{{'SBO:0000252'}})},numel(proteinMets.mets),1);
    +0127             end
    +0128             if isfield(model,'metCharges')
    +0129                 proteinMets.metCharges = zeros(numel(proteinMets.mets),1);
    +0130             end
    +0131             proteinMets.metNotes = repmat({'Enzyme-usage pseudometabolite'},numel(proteinMets.mets),1);
    +0132             model = addMets(model,proteinMets);
    +0133         end
    +0134         enzAdded = newEnzymes.enzymes(:);  
    +0135     end
    +0136 
    +0137     % 3. Add new reactions
    +0138 
    +0139     % The operators of a gene rule are case insensitive: write them in lower
    +0140     % case, as the rest of the function and RAVEN's addRxns expect. Gene ids
    +0141     % that contain the letters (Sand1, andA, ORF1) are left as they are.
    +0142     newRxns.grRules = regexprep(convertCharArray(newRxns.grRules), ...
    +0143         '(?<![^\s()])(and|or)(?![^\s()])', '${lower($0)}', 'ignorecase');
    +0144 
    +0145     % Before add the reactions validate that all the genes in grRules are
    +0146     % present in the model.
    +0147     genesInRules = strjoin(newRxns.grRules);
    +0148     genesInRules = regexp(genesInRules,'[^\s()]+','match'); % Gene ids and the words 'and' and 'or', without spaces and brackets
    +0149     genesInRules = genesInRules(~ismember(lower(genesInRules),{'and','or'}));  % Only the gene ids
    +0150     genesInRules = setdiff(unique(genesInRules),model.genes); % Only keep new genes
    +0151 
    +0152     % If there is any gene which is not present, as to be pass as
    +0153     % newEnzymes input
    +0154     if ~isempty(genesInRules)
    +0155         errorText = 'The following genes from grRules are not present in the model, add them as newEnzymes input:';
    +0156         error('%s', ravenList(errorText,genesInRules,false))
    +0157     end
    +0158 
    +0159     % Get reversible reactions to split
    +0160     toIrrev = find(cellfun(@(x) contains(x,'<=>'),newRxns.equations));
    +0161     if ~isempty(toIrrev)
    +0162         for i=1:numel(toIrrev)
    +0163             idx = toIrrev(i);
    +0164             newEquation = split(newRxns.equations(idx),'<=>');
    +0165             % Remove directionality
    +0166             newRxns.equations(idx) = erase(newRxns.equations(idx), '<');
    +0167 
    +0168             % Add a new reaction to the list to be added
    +0169             newRxns.rxns{end+1} = [newRxns.rxns{idx} '_REV'];
    +0170             newRxns.rxnNames{end+1} = [newRxns.rxnNames{idx} ' (reversible)'];
    +0171             newRxns.equations{end+1} = [strtrim(newEquation{2, 1}) ' => ' strtrim(newEquation{1, 1})];
    +0172             newRxns.grRules{end+1} = newRxns.grRules{idx};
    +0173         end
    +0174     end
    +0175 
    +0176     % Get reactions to separate isozymes
    +0177     isozymes = cellfun(@gprToDnf, newRxns.grRules, 'UniformOutput', false);
    +0178     toSplit = find(cellfun(@numel,isozymes) > 1);
    +0179     if ~isempty(toSplit)
    +0180         splitRxns = {}; splitRxnNames = {}; splitEquations = {}; splitGrRules = {};
    +0181         for i=1:numel(toSplit)
    +0182             idx = toSplit(i);
    +0183             % One reaction per AND-clause of the gene rule in disjunctive normal form
    +0184             newRules = cellfun(@(x) strjoin(x,' and '), isozymes{idx}, 'UniformOutput', false);
    +0185 
    +0186             for j=1:numel(newRules)
    +0187                 splitRxns{end+1} = [newRxns.rxns{idx} '_EXP_' num2str(j)];
    +0188                 splitRxnNames(end+1) = newRxns.rxnNames(idx);
    +0189                 splitEquations(end+1) = newRxns.equations(idx);
    +0190                 splitGrRules(end+1) = newRules(j);
    +0191             end
    +0192         end
    +0193 
    +0194         % Remove every original that was split, in one indexed operation, then append
    +0195         % the replacements. Removing (or appending) one at a time while iterating a list
    +0196         % of indices computed up front lets each removal shift the indices of everything
    +0197         % after it, so a second (or later) original silently gets read from the wrong
    +0198         % position once more than one reaction needs splitting in the same call.
    +0199         newRxns.rxns(toSplit) = [];
    +0200         newRxns.rxnNames(toSplit) = [];
    +0201         newRxns.equations(toSplit) = [];
    +0202         newRxns.grRules(toSplit) = [];
    +0203 
    +0204         newRxns.rxns = [newRxns.rxns(:); splitRxns(:)];
    +0205         newRxns.rxnNames = [newRxns.rxnNames(:); splitRxnNames(:)];
    +0206         newRxns.equations = [newRxns.equations(:); splitEquations(:)];
    +0207         newRxns.grRules = [newRxns.grRules(:); splitGrRules(:)];
    +0208     end
    +0209 
    +0210     newRxns.lb = zeros(length(newRxns.rxns),1);
    +0211     newRxns.ub = zeros(length(newRxns.rxns),1) + 1000;
    +0212 
    +0213     model = addRxns(model, newRxns, 3, '', true, true);
    +0214 
    +0215     % 4. Add protein usage reactions.
    +0216     usageRxns.rxns            = strcat('usage_',proteinMets.mets);
    +0217     usageRxns.rxnNames        = usageRxns.rxns;
    +0218     usageRxns.mets            = cell(numel(usageRxns.rxns),1);
    +0219     usageRxns.stoichCoeffs    = cell(numel(usageRxns.rxns),1);
    +0220     for i=1:numel(usageRxns.mets)
    +0221         usageRxns.mets{i}         = {proteinMets.mets{i}, 'prot_pool'};
    +0222         usageRxns.stoichCoeffs{i} = [1,-1];
    +0223     end
    +0224     usageRxns.lb              = zeros(numel(usageRxns.rxns),1);
    +0225     usageRxns.ub              = zeros(numel(usageRxns.rxns),1) + 1000;
    +0226     usageRxns.rev             = ones(numel(usageRxns.rxns),1);
    +0227     usageRxns.grRules         = newEnzymes.genes;
    +0228     model = addRxns(model,usageRxns);
    +0229 
    +0230     % 5. Update .ec field with enzyme data
    +0231     model.ec.enzymes    = [model.ec.enzymes; newEnzymes.enzymes(:)];
    +0232     model.ec.genes      = [model.ec.genes; newEnzymes.genes(:)];
    +0233     model.ec.mw         = [model.ec.mw; newEnzymes.mw(:)];
    +0234     model.ec.sequence   = [model.ec.sequence; repmat({''},numel(newEnzymes.enzymes),1)]; 
    +0235     if isfield(model.ec,'concs')
    +0236         model.ec.concs  = [model.ec.concs; NaN(numel(newEnzymes.enzymes),1)];
    +0237     end
    +0238 
    +0239     % 6. Expand the enzyme rxns matrix
    +0240     rxnWithRule = find(~cellfun('isempty',newRxns.grRules));
    +0241 
    +0242     model.ec.rxnEnzMat =  [model.ec.rxnEnzMat, zeros(length(model.ec.rxns), length(newEnzymes.enzymes))]; % add n new enzymes
    +0243     model.ec.rxnEnzMat =  [model.ec.rxnEnzMat; zeros(length(rxnWithRule), length(model.ec.enzymes))]; % add n new rxns
    +0244 
    +0245     % 7. Update .ec field with rxn data
    +0246 
    +0247     % Get reactions to add
    +0248     numRxns = length(model.ec.rxns);
    +0249     for i = 1:numel(rxnWithRule)
    +0250         rxnIdx = rxnWithRule(i);
    +0251 
    +0252         model.ec.rxns(end+1)    = newRxns.rxns(rxnIdx);
    +0253         model.ec.kcat(end+1)    = 0;
    +0254         model.ec.source(end+1)  = {''};
    +0255         model.ec.notes(end+1)   = {''};
    +0256         model.ec.eccodes(end+1) = {''};
    +0257 
    +0258         % Get rules
    +0259         genes = regexp(newRxns.grRules{rxnIdx},'[^\s()]+','match'); % Gene ids and the word 'and', without spaces and brackets
    +0260         genes = genes(~ismember(lower(genes),{'and','or'}));
    +0261         [~,enzIdx] = ismember(genes, model.ec.genes);
    +0262 
    +0263         % Update the enzyme rxns matrix
    +0264         model.ec.rxnEnzMat(numRxns+i, enzIdx) = 1;
    +0265     end
    +0266     
    +0267     rxnsAdded = newRxns.rxns(:);
    +0268 end
    +0269 end
    +0270 
    +0271 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
    +0272 %Function that expands a gene rule into disjunctive normal form: a cell array
    +0273 %with one cell per isozyme, each holding the gene ids that are ANDed in it.
    +0274 %Gene ids are whole words, so an id that contains 'or' or 'and' is kept
    +0275 %intact. An empty rule gives an empty cell array.
    +0276 function dnf = gprToDnf(rule)
    +0277 tokens = regexp(rule,'\(|\)|[^\s()]+','match');
    +0278 isOperator = strcmpi(tokens,'and') | strcmpi(tokens,'or');
    +0279 tokens(isOperator) = lower(tokens(isOperator)); % Operators are case insensitive
    +0280 if isempty(tokens)
    +0281     dnf = {};
    +0282     return
    +0283 end
    +0284 [dnf,pos] = parseOr(tokens,1,rule);
    +0285 if pos <= numel(tokens)
    +0286     error('Cannot parse the gene rule "%s"',rule)
    +0287 end
    +0288 end
    +0289 
    +0290 function [dnf,pos] = parseOr(tokens,pos,rule)
    +0291 [dnf,pos] = parseAnd(tokens,pos,rule);
    +0292 while pos <= numel(tokens) && strcmp(tokens{pos},'or')
    +0293     [rhs,pos] = parseAnd(tokens,pos+1,rule);
    +0294     dnf = [dnf,rhs];
    +0295 end
    +0296 end
    +0297 
    +0298 function [dnf,pos] = parseAnd(tokens,pos,rule)
    +0299 [dnf,pos] = parseAtom(tokens,pos,rule);
    +0300 while pos <= numel(tokens) && strcmp(tokens{pos},'and')
    +0301     [rhs,pos] = parseAtom(tokens,pos+1,rule);
    +0302     product = cell(1,0);
    +0303     for a = 1:numel(dnf)
    +0304         for b = 1:numel(rhs)
    +0305             product{end+1} = [dnf{a},rhs{b}]; %#ok<AGROW>
    +0306         end
    +0307     end
    +0308     dnf = product;
    +0309 end
    +0310 end
    +0311 
    +0312 function [dnf,pos] = parseAtom(tokens,pos,rule)
    +0313 if pos > numel(tokens) || any(strcmp(tokens{pos},{')','and','or'}))
    +0314     error('Cannot parse the gene rule "%s"',rule)
    +0315 elseif strcmp(tokens{pos},'(')
    +0316     [dnf,pos] = parseOr(tokens,pos+1,rule);
    +0317     if pos > numel(tokens) || ~strcmp(tokens{pos},')')
    +0318         error('Cannot parse the gene rule "%s"',rule)
    +0319     end
    +0320     pos = pos + 1;
    +0321 else
    +0322     dnf = {tokens(pos)};
    +0323     pos = pos + 1;
    +0324 end
    +0325 end
    +
    Generated by m2html © 2005
    + + \ No newline at end of file diff --git a/doc/src/change_model/applyComplexData.html b/doc/src/change_model/applyComplexData.html new file mode 100644 index 00000000..22229c30 --- /dev/null +++ b/doc/src/change_model/applyComplexData.html @@ -0,0 +1,321 @@ + + + + Description of applyComplexData + + + + + + + + + +
    Home > src > change_model > applyComplexData.m
    + + + +

    applyComplexData +

    + +

    PURPOSE ^

    +
    applyComplexData Apply complex subunit stoichiometry to an ecModel.
    + +

    SYNOPSIS ^

    +
    function [model, foundComplex, proposedComplex] = applyComplexData(model, varargin)
    + +

    DESCRIPTION ^

    +
     applyComplexData  Apply complex subunit stoichiometry to an ecModel.
    +
    + Populates model.ec.rxnEnzMat with subunit stochiometries for protein
    + complexes, based on curated data from the EMBL-EBI Complex Portal.
    +
    + Parameters
    + ----------
    + model : struct
    +     an ecModel in GECKO 3 format (with ecModel.ec structure).
    +
    + Name-Value Arguments
    + --------------------
    + complexInfo : struct
    +     structure as generated by getComplexData. If nothing is provided, an
    +     attempt will be made to read data/ComplexPortal.json from the
    +     obj.params.path folder specified in the modelAdapter.
    + modelAdapter : ModelAdapter
    +     a loaded model adapter (default: the current default model adapter).
    + verbose : logical
    +     true if a summary should be shown in the Command Window (default
    +     true).
    +
    + Returns
    + -------
    + model : struct
    +     ecModel where model.ec.rxnEnzMat is populated with subunit
    +     stochiometries.
    + foundComplex : table
    +     complexes that fully matched between the model and the complex data
    +     (columns described under Notes).
    + proposedComplex : table
    +     complexes where the model contained >75% but <100% of the proteins
    +     indicated by Complex Portal, or where the model contained more
    +     proteins than indicated for that complex in Complex Portal (same
    +     columns as foundComplex, plus a percentage match column).
    +
    + Notes
    + -----
    + The subunit stoichiometry is assigned per protein ID: the proteins of a
    + complex need not be listed in the order of model.ec.enzymes.
    +
    + foundComplex and proposedComplex share the following columns: rxn
    + (reaction identifier), complexID and name (Complex Portal identifiers),
    + genes (gene names of the complex subunits), protID_model (matched protein
    + IDs from the model), protID_complex (protein IDs listed by Complex
    + Portal), and stochiometry (subunit stoichiometry from Complex Portal).
    + proposedComplex has an additional match column with the percentage match
    + between the model proteins and the proposed complex.
    +
    + Examples
    + --------
    +     % optional arguments may be given positionally or as name-value pairs:
    +     [model, foundComplex, proposedComplex] = applyComplexData(ecModel, complexInfo, modelAdapter);
    +     [model, foundComplex, proposedComplex] = applyComplexData(ecModel, 'complexInfo', complexInfo);
    +
    + See also
    + --------
    + getComplexData, makeEcModel
    + + +

    CROSS-REFERENCE INFORMATION ^

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

    SOURCE CODE ^

    +
    0001 function [model, foundComplex, proposedComplex] = applyComplexData(model, varargin)
    +0002 % applyComplexData  Apply complex subunit stoichiometry to an ecModel.
    +0003 %
    +0004 % Populates model.ec.rxnEnzMat with subunit stochiometries for protein
    +0005 % complexes, based on curated data from the EMBL-EBI Complex Portal.
    +0006 %
    +0007 % Parameters
    +0008 % ----------
    +0009 % model : struct
    +0010 %     an ecModel in GECKO 3 format (with ecModel.ec structure).
    +0011 %
    +0012 % Name-Value Arguments
    +0013 % --------------------
    +0014 % complexInfo : struct
    +0015 %     structure as generated by getComplexData. If nothing is provided, an
    +0016 %     attempt will be made to read data/ComplexPortal.json from the
    +0017 %     obj.params.path folder specified in the modelAdapter.
    +0018 % modelAdapter : ModelAdapter
    +0019 %     a loaded model adapter (default: the current default model adapter).
    +0020 % verbose : logical
    +0021 %     true if a summary should be shown in the Command Window (default
    +0022 %     true).
    +0023 %
    +0024 % Returns
    +0025 % -------
    +0026 % model : struct
    +0027 %     ecModel where model.ec.rxnEnzMat is populated with subunit
    +0028 %     stochiometries.
    +0029 % foundComplex : table
    +0030 %     complexes that fully matched between the model and the complex data
    +0031 %     (columns described under Notes).
    +0032 % proposedComplex : table
    +0033 %     complexes where the model contained >75% but <100% of the proteins
    +0034 %     indicated by Complex Portal, or where the model contained more
    +0035 %     proteins than indicated for that complex in Complex Portal (same
    +0036 %     columns as foundComplex, plus a percentage match column).
    +0037 %
    +0038 % Notes
    +0039 % -----
    +0040 % The subunit stoichiometry is assigned per protein ID: the proteins of a
    +0041 % complex need not be listed in the order of model.ec.enzymes.
    +0042 %
    +0043 % foundComplex and proposedComplex share the following columns: rxn
    +0044 % (reaction identifier), complexID and name (Complex Portal identifiers),
    +0045 % genes (gene names of the complex subunits), protID_model (matched protein
    +0046 % IDs from the model), protID_complex (protein IDs listed by Complex
    +0047 % Portal), and stochiometry (subunit stoichiometry from Complex Portal).
    +0048 % proposedComplex has an additional match column with the percentage match
    +0049 % between the model proteins and the proposed complex.
    +0050 %
    +0051 % Examples
    +0052 % --------
    +0053 %     % optional arguments may be given positionally or as name-value pairs:
    +0054 %     [model, foundComplex, proposedComplex] = applyComplexData(ecModel, complexInfo, modelAdapter);
    +0055 %     [model, foundComplex, proposedComplex] = applyComplexData(ecModel, 'complexInfo', complexInfo);
    +0056 %
    +0057 % See also
    +0058 % --------
    +0059 % getComplexData, makeEcModel
    +0060 
    +0061 p = parseGECKOargs(varargin, { ...
    +0062     'complexInfo',  []; ...
    +0063     'modelAdapter', []; ...
    +0064     'verbose',      true});
    +0065 complexInfo  = p.complexInfo;
    +0066 modelAdapter = p.modelAdapter;
    +0067 verbose      = p.verbose;
    +0068 if isempty(verbose); verbose = true; end
    +0069 
    +0070 if isempty(modelAdapter)
    +0071     modelAdapter = ModelAdapterManager.getDefault();
    +0072     if isempty(modelAdapter)
    +0073         error('Either send in a modelAdapter or set the default model adapter in the ModelAdapterManager.')
    +0074     end
    +0075 end
    +0076 params = modelAdapter.params;
    +0077 
    +0078 if isempty(complexInfo)
    +0079     complexInfo = fullfile(params.path,'data','ComplexPortal.json');
    +0080     if ~isfile(complexInfo)
    +0081         complexInfo = getComplexData([], modelAdapter);
    +0082     end
    +0083 end
    +0084 
    +0085 if ischar(complexInfo) || isstring(complexInfo)
    +0086     jsonStr = fileread(complexInfo);
    +0087     complexData = jsondecode(jsonStr);
    +0088 else
    +0089     complexData = complexInfo;
    +0090 end
    +0091 
    +0092 %Remove prefixes on rxn names for gecko light
    +0093 if ~model.ec.geckoLight
    +0094     rxnNames = model.ec.rxns;
    +0095 else
    +0096     rxnNames = extractAfter(model.ec.rxns,4);
    +0097 end
    +0098 
    +0099 foundComplex = cell(numel(rxnNames),7);
    +0100 foundComplexCount = 0;
    +0101 proposedComplex = cell(numel(rxnNames)*2,8); % Might propose more
    +0102 proposedComplexCount = 0;
    +0103 
    +0104 complexProts = repmat({''}, numel({complexData.complexID})*10, 1);
    +0105 complexMatrix = zeros(numel({complexData.complexID}),numel(complexProts));
    +0106 lastProt = 0;
    +0107 for i=1:size(complexMatrix,1)
    +0108     % Locate proteins (and add if new)
    +0109     protIDs     = complexData(i).protID;
    +0110     [isOld, protMatIdx] = ismember(protIDs,complexProts);
    +0111     newProts    = protIDs(~isOld);
    +0112     complexProts(lastProt+1:lastProt+numel(newProts))=newProts;
    +0113     protMatIdx(~isOld)  = lastProt+1 : lastProt+numel(newProts);
    +0114     lastProt = lastProt + numel(newProts);
    +0115     % Add subunit numbers
    +0116     if all(complexData(i).stochiometry == 0)
    +0117         complexData(i).stochiometry(:) = 1;
    +0118     end
    +0119     complexMatrix(i,protMatIdx) = complexData(i).stochiometry;
    +0120 end
    +0121 
    +0122 % Remove excess space
    +0123 complexMatrix(:,lastProt+1:end) = [];
    +0124 complexProts(lastProt+1:end) = [];
    +0125 PB = progressReport(numel(rxnNames), 'Assign complexes to reactions');
    +0126 for i = 1:numel(rxnNames)
    +0127     PB.count;
    +0128     % Get the proteins from the model
    +0129     modelProts = model.ec.enzymes(find(model.ec.rxnEnzMat(i,:)));
    +0130     [protsInMat, protsIdx] = ismember(modelProts,complexProts);
    +0131     if ~any(protsInMat)
    +0132         continue
    +0133     end
    +0134     % Find complexes that includes the model proteins
    +0135     [potComplex,~] = find(complexMatrix(:,protsIdx(protsInMat)));
    +0136     potComplex = unique(potComplex);
    +0137     % Some stats on number of subunits, percentage match etc.
    +0138     matchComplexUnits = sum(logical(complexMatrix(potComplex,protsIdx(protsInMat))),2);
    +0139     totalComplexUnits = sum(logical(complexMatrix(potComplex,:)),2);
    +0140     modComplexUnits = numel(modelProts);
    +0141     percMatch  = matchComplexUnits/modComplexUnits;
    +0142     totalMatch = totalComplexUnits/modComplexUnits;
    +0143     if any(percMatch == 1 & totalMatch == 1)
    +0144         % Exact match
    +0145         complexMatch = find(percMatch == 1 & totalMatch == 1);
    +0146         if numel(complexMatch)>1 % If more than one match, take first match
    +0147             complexMatch = complexMatch(1);
    +0148         end
    +0149         complexMatch = potComplex(complexMatch);
    +0150         foundComplexCount = foundComplexCount + 1;
    +0151         foundComplex{foundComplexCount,1} = model.ec.rxns{i};
    +0152         foundComplex{foundComplexCount,2} = complexData(complexMatch).complexID;
    +0153         foundComplex{foundComplexCount,3} = complexData(complexMatch).name;
    +0154         foundComplex{foundComplexCount,4} = complexData(complexMatch).geneName;
    +0155         foundComplex{foundComplexCount,5} = modelProts;
    +0156         foundComplex{foundComplexCount,6} = complexData(complexMatch).protID;
    +0157         foundComplex{foundComplexCount,7} = complexData(complexMatch).stochiometry;
    +0158 
    +0159         % Apply in rxnEnzMat
    +0160         % The stoichiometry is taken per protein ID, as the proteins of the
    +0161         % complex need not be listed in the order of model.ec.enzymes
    +0162         [~, modelProtsIdx] = ismember(modelProts, model.ec.enzymes);
    +0163         [~, complexPos] = ismember(modelProts, complexData(complexMatch).protID);
    +0164         model.ec.rxnEnzMat(i,modelProtsIdx) = complexData(complexMatch).stochiometry(complexPos);
    +0165     
    +0166     elseif modComplexUnits > 1 % Only suggest potential complex if grRule > 1 protein
    +0167         moreUnitsInData = find(percMatch == 1 & totalMatch > 1);
    +0168         if any(moreUnitsInData)
    +0169             % All ecModel subunits match, but Complex Portal has more subunits
    +0170             % Take the complex with the minimum number of extra subunits
    +0171             [~,propComplex] = min(totalMatch(moreUnitsInData));
    +0172             propComplex     = moreUnitsInData(propComplex);
    +0173             selectComplex   = potComplex(propComplex);
    +0174             proposedComplexCount = proposedComplexCount + 1;
    +0175             proposedComplex{proposedComplexCount,1} = model.ec.rxns{i};
    +0176             proposedComplex{proposedComplexCount,2} = complexData(selectComplex).complexID;
    +0177             proposedComplex{proposedComplexCount,3} = complexData(selectComplex).name;
    +0178             proposedComplex{proposedComplexCount,4} = complexData(selectComplex).geneName;
    +0179             proposedComplex{proposedComplexCount,5} = modelProts;
    +0180             proposedComplex{proposedComplexCount,6} = complexData(selectComplex).protID;
    +0181             proposedComplex{proposedComplexCount,7} = complexData(selectComplex).stochiometry;
    +0182             proposedComplex{proposedComplexCount,8} = totalMatch(propComplex)*100;
    +0183         end
    +0184         otherUnits = find(percMatch >= 0.75 & percMatch < 1 & totalMatch <= 1);
    +0185         if any(otherUnits)
    +0186             % At least 75% of ecModels subunits match, Complex Portal maybe have less or different subunits
    +0187             % Take the complex with highest % match.
    +0188             [~,propComplex] = max(percMatch(otherUnits));
    +0189             propComplex     = otherUnits(propComplex);
    +0190             selectComplex   = potComplex(propComplex);
    +0191             proposedComplexCount = proposedComplexCount + 1;
    +0192             proposedComplex{proposedComplexCount,1} = model.ec.rxns{i};
    +0193             proposedComplex{proposedComplexCount,2} = complexData(selectComplex).complexID;
    +0194             proposedComplex{proposedComplexCount,3} = complexData(selectComplex).name;
    +0195             proposedComplex{proposedComplexCount,4} = complexData(selectComplex).geneName;
    +0196             proposedComplex{proposedComplexCount,5} = modelProts;
    +0197             proposedComplex{proposedComplexCount,6} = complexData(selectComplex).protID;
    +0198             proposedComplex{proposedComplexCount,7} = complexData(selectComplex).stochiometry;
    +0199             proposedComplex{proposedComplexCount,8} = percMatch(propComplex)*100;
    +0200         end
    +0201     end
    +0202 end
    +0203 PB.done;
    +0204 
    +0205 % Remove empty space
    +0206 foundComplex(foundComplexCount+1:end,:) = [];
    +0207 proposedComplex(proposedComplexCount+1:end,:) = [];
    +0208 
    +0209 rowHeadings = {'rxn', 'complexID','name','genes','protID_model','protID_complex','stochiometry'};
    +0210 
    +0211 foundComplex = cell2table(foundComplex, 'VariableNames', rowHeadings);
    +0212 
    +0213 proposedComplex = cell2table(proposedComplex, 'VariableNames', [rowHeadings 'match']);
    +0214 if verbose
    +0215     disp(['A total of ' int2str(numel(foundComplex(:,1))) ' complex have full match, and ' int2str(numel(proposedComplex(:,1))) ' proposed.'])
    +0216 end
    +0217 end
    +
    Generated by m2html © 2005
    + + \ No newline at end of file diff --git a/doc/src/change_model/applyCustomKcats.html b/doc/src/change_model/applyCustomKcats.html new file mode 100644 index 00000000..4d23acea --- /dev/null +++ b/doc/src/change_model/applyCustomKcats.html @@ -0,0 +1,394 @@ + + + + Description of applyCustomKcats + + + + + + + + + +
    Home > src > change_model > applyCustomKcats.m
    + + + +

    applyCustomKcats +

    + +

    PURPOSE ^

    +
    applyCustomKcats Apply user-defined kcats to an ecModel.
    + +

    SYNOPSIS ^

    +
    function [model, rxnUpdated, notMatch] = applyCustomKcats(model, varargin)
    + +

    DESCRIPTION ^

    +
     applyCustomKcats  Apply user-defined kcats to an ecModel.
    +
    + Reads data/customKcats.tsv in the obj.params.path specified in the model
    + adapter. Alternatively, a customKcats structure can be provided, as
    + specified below.
    +
    + Parameters
    + ----------
    + model : struct
    +     an ecModel in GECKO 3 format (with ecModel.ec structure).
    +
    + Name-Value Arguments
    + --------------------
    + customKcats : struct
    +     structure with custom kcat information (fields described under Notes).
    +     If nothing is provided, an attempt will be made to read
    +     data/customKcats.tsv from the obj.params.path folder specified in the
    +     modelAdapter.
    + modelAdapter : ModelAdapter
    +     a loaded model adapter (default: the current default model adapter).
    +
    + Returns
    + -------
    + model : struct
    +     ecModel where kcats for defined proteins have been changed.
    + rxnUpdated : cell
    +     ids list of updated reactions, where new kcats were applied.
    + notMatch : table
    +     reactions for which the custom information provided has a partial
    +     match (at least 50%, but not 100%) with the reaction's GPR rule, for
    +     the user to curate manually. Columns: rxns and name (reaction
    +     identifier and name), custom enzymes (the proteins specified in
    +     customKcats), enzymes in model (the enzymes annotated to the reaction
    +     in the model), and rules (the reaction's GPR rule).
    +
    + Notes
    + -----
    + The customKcats structure has the following fields:
    +
    + - proteins : protein identifiers, multiple for the same kcat (in case of a protein complex) are separated by ' + '.
    + - genes : gene identifiers (optional, not used in matching).
    + - gene_name : short gene name (optional, not used in matching).
    + - kcat : new kcat value (one per entry).
    + - rxns : reaction identifiers, multiple for the same kcat are separated by ',' (see further explanation below).
    + - notes : will be appended to model.ec.notes, separated by ', ' from an existing note; an empty note changes nothing (optional).
    + - stoicho : complex stoichiometry, separated by ' + ' (examples: '1' or '3 + 1'), matching the order in proteins field.
    +
    + An entry with an empty kcat is skipped. Protein and reaction identifiers
    + are matched exactly, including their letter case. Light ecModels are
    + supported: the rows of model.ec are matched by their ec reaction ids.
    +
    + Matching order:
    +
    + 1. reactions are identified by .proteins and .rxns.
    + 2. reactions are identified by .proteins only (empty .rxns entry); no
    +    additional checks are made: is a reaction annotated with these
    +    proteins? => its kcat will be updated, irrespective of the exact
    +    reaction, direction, substrate, etc.
    + 3. reactions are identified by .rxns only (empty .proteins entry); no
    +    additional checks are made: is a reaction derived from the original
    +    reaction identifier => its kcat will be updated, irrespective of the
    +    annotated protein.
    +
    + The customKcats.rxns field reaction identifiers are from the ORIGINAL
    + model, before _EXP_ suffixes were added by makeEcModel. Reaction
    + directionality IS however specified, with a _REV suffix. Example entries:
    +
    + - 'r_0001' will match r_0001, r_0001_EXP_1, r_0001_EXP_2 etc., but not r_0001_REV, r_0001_EXP_1_REV etc.
    + - 'r_0001_REV' will match r_0001_REV, r_0001_EXP_1_REV, r_0001_EXP_2_REV, etc., but not r_0001, r_0001_EXP_1 etc.
    +
    + Multiple identifiers should be comma separated (e.g. r_0001, r_0002).
    +
    + Examples
    + --------
    +     % optional arguments may be given positionally or as name-value pairs:
    +     [model, rxnUpdated, notMatch] = applyCustomKcats(model, customKcats, modelAdapter);
    +     [model, rxnUpdated, notMatch] = applyCustomKcats(model, 'customKcats', customKcats);
    +
    + See also
    + --------
    + applyKcatConstraints, makeEcModel
    + + +

    CROSS-REFERENCE INFORMATION ^

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

    SUBFUNCTIONS ^

    + + +

    SOURCE CODE ^

    +
    0001 function [model, rxnUpdated, notMatch] = applyCustomKcats(model, varargin)
    +0002 % applyCustomKcats  Apply user-defined kcats to an ecModel.
    +0003 %
    +0004 % Reads data/customKcats.tsv in the obj.params.path specified in the model
    +0005 % adapter. Alternatively, a customKcats structure can be provided, as
    +0006 % specified below.
    +0007 %
    +0008 % Parameters
    +0009 % ----------
    +0010 % model : struct
    +0011 %     an ecModel in GECKO 3 format (with ecModel.ec structure).
    +0012 %
    +0013 % Name-Value Arguments
    +0014 % --------------------
    +0015 % customKcats : struct
    +0016 %     structure with custom kcat information (fields described under Notes).
    +0017 %     If nothing is provided, an attempt will be made to read
    +0018 %     data/customKcats.tsv from the obj.params.path folder specified in the
    +0019 %     modelAdapter.
    +0020 % modelAdapter : ModelAdapter
    +0021 %     a loaded model adapter (default: the current default model adapter).
    +0022 %
    +0023 % Returns
    +0024 % -------
    +0025 % model : struct
    +0026 %     ecModel where kcats for defined proteins have been changed.
    +0027 % rxnUpdated : cell
    +0028 %     ids list of updated reactions, where new kcats were applied.
    +0029 % notMatch : table
    +0030 %     reactions for which the custom information provided has a partial
    +0031 %     match (at least 50%, but not 100%) with the reaction's GPR rule, for
    +0032 %     the user to curate manually. Columns: rxns and name (reaction
    +0033 %     identifier and name), custom enzymes (the proteins specified in
    +0034 %     customKcats), enzymes in model (the enzymes annotated to the reaction
    +0035 %     in the model), and rules (the reaction's GPR rule).
    +0036 %
    +0037 % Notes
    +0038 % -----
    +0039 % The customKcats structure has the following fields:
    +0040 %
    +0041 % - proteins : protein identifiers, multiple for the same kcat (in case of a protein complex) are separated by ' + '.
    +0042 % - genes : gene identifiers (optional, not used in matching).
    +0043 % - gene_name : short gene name (optional, not used in matching).
    +0044 % - kcat : new kcat value (one per entry).
    +0045 % - rxns : reaction identifiers, multiple for the same kcat are separated by ',' (see further explanation below).
    +0046 % - notes : will be appended to model.ec.notes, separated by ', ' from an existing note; an empty note changes nothing (optional).
    +0047 % - stoicho : complex stoichiometry, separated by ' + ' (examples: '1' or '3 + 1'), matching the order in proteins field.
    +0048 %
    +0049 % An entry with an empty kcat is skipped. Protein and reaction identifiers
    +0050 % are matched exactly, including their letter case. Light ecModels are
    +0051 % supported: the rows of model.ec are matched by their ec reaction ids.
    +0052 %
    +0053 % Matching order:
    +0054 %
    +0055 % 1. reactions are identified by .proteins and .rxns.
    +0056 % 2. reactions are identified by .proteins only (empty .rxns entry); no
    +0057 %    additional checks are made: is a reaction annotated with these
    +0058 %    proteins? => its kcat will be updated, irrespective of the exact
    +0059 %    reaction, direction, substrate, etc.
    +0060 % 3. reactions are identified by .rxns only (empty .proteins entry); no
    +0061 %    additional checks are made: is a reaction derived from the original
    +0062 %    reaction identifier => its kcat will be updated, irrespective of the
    +0063 %    annotated protein.
    +0064 %
    +0065 % The customKcats.rxns field reaction identifiers are from the ORIGINAL
    +0066 % model, before _EXP_ suffixes were added by makeEcModel. Reaction
    +0067 % directionality IS however specified, with a _REV suffix. Example entries:
    +0068 %
    +0069 % - 'r_0001' will match r_0001, r_0001_EXP_1, r_0001_EXP_2 etc., but not r_0001_REV, r_0001_EXP_1_REV etc.
    +0070 % - 'r_0001_REV' will match r_0001_REV, r_0001_EXP_1_REV, r_0001_EXP_2_REV, etc., but not r_0001, r_0001_EXP_1 etc.
    +0071 %
    +0072 % Multiple identifiers should be comma separated (e.g. r_0001, r_0002).
    +0073 %
    +0074 % Examples
    +0075 % --------
    +0076 %     % optional arguments may be given positionally or as name-value pairs:
    +0077 %     [model, rxnUpdated, notMatch] = applyCustomKcats(model, customKcats, modelAdapter);
    +0078 %     [model, rxnUpdated, notMatch] = applyCustomKcats(model, 'customKcats', customKcats);
    +0079 %
    +0080 % See also
    +0081 % --------
    +0082 % applyKcatConstraints, makeEcModel
    +0083 
    +0084 p = parseGECKOargs(varargin, { ...
    +0085     'customKcats',  []; ...
    +0086     'modelAdapter', []});
    +0087 customKcats  = p.customKcats;
    +0088 modelAdapter = p.modelAdapter;
    +0089 
    +0090 if isempty(modelAdapter)
    +0091     modelAdapter = ModelAdapterManager.getDefault();
    +0092     if isempty(modelAdapter)
    +0093         error('Either send in a modelAdapter or set the default model adapter in the ModelAdapterManager.')
    +0094     end
    +0095 end
    +0096 
    +0097 params = modelAdapter.params;
    +0098 
    +0099 if isempty(customKcats)
    +0100     customKcats = fullfile(params.path,'data','customKcats.tsv');
    +0101 end
    +0102 if isstruct(customKcats)
    +0103     if ~all(isfield(customKcats,{'proteins','kcat','rxns'}))
    +0104         error('The customKcats structure does not have all essential fields.');
    +0105     end
    +0106 elseif isfile(customKcats)
    +0107     fID = fopen(customKcats, 'r');
    +0108     fileContent = textscan(fID, '%s %s %s %f %q %s %s', 'Delimiter', '\t', 'HeaderLines', 1);
    +0109     fclose(fID);
    +0110     clear customKcats
    +0111     customKcats.proteins    = fileContent{1};
    +0112     customKcats.genes       = fileContent{2};
    +0113     customKcats.gene_name   = fileContent{3};
    +0114     customKcats.kcat        = fileContent{4};
    +0115     customKcats.rxns        = fileContent{5};
    +0116     customKcats.notes       = fileContent{6};
    +0117     customKcats.stoicho     = fileContent{7};
    +0118 else
    +0119     error(['Cannot find file: ' customKcats]);
    +0120 end
    +0121 
    +0122 rxnToUpdate = false(length(model.ec.rxns),1);
    +0123 rxnNotMatch = false(length(model.ec.rxns),1);
    +0124 evaluatedRule = cell(length(model.ec.rxns),1);
    +0125 enzInModel = cell(length(model.ec.rxns),1);
    +0126 ecRxnNoSuffix = regexprep(model.ec.rxns,'_EXP_\d+$','');
    +0127 
    +0128 for i = 1:numel(customKcats.proteins)
    +0129     if isnan(customKcats.kcat(i))
    +0130         printOrange(['WARNING: Entry ' num2str(i) ' has no kcat; it is skipped.']);
    +0131         continue
    +0132     end
    +0133     if isempty(customKcats.proteins{i})
    +0134         %If only reaction ID(s) is/are specified (and no proteins),
    +0135         %then apply the kcat to all isozymic reactions
    +0136         rxns    = strtrim(strsplit(customKcats.rxns{i}, ','));
    +0137         rxnIdxs = ismember(ecRxnNoSuffix,rxns);
    +0138         rxnToUpdate(rxnIdxs) = 1;
    +0139         model.ec.kcat(rxnIdxs) = customKcats.kcat(i);
    +0140 
    +0141         % Add note mentioning manual kcat change
    +0142         model.ec.source(rxnIdxs) = {'custom'};
    +0143         if isfield(customKcats,'notes')
    +0144             matchedIdxs = find(rxnIdxs);
    +0145             for j = 1:numel(matchedIdxs)
    +0146                 model.ec.notes{matchedIdxs(j), 1} = appendNote(model.ec.notes{matchedIdxs(j), 1}, customKcats.notes{i});
    +0147             end
    +0148         end
    +0149     else
    +0150         prots = strtrim(strsplit(customKcats.proteins{i}, '+'));
    +0151 
    +0152         % Find the index for the enzymes which kcat will be changed. In
    +0153         % case the protein is not in the model generate a warning.
    +0154         try
    +0155             enzIdx = cellfun(@(x) find(strcmp(model.ec.enzymes, x)), prots);
    +0156         catch
    +0157             enzIdx = [];
    +0158             printOrange(['WARNING: Protein(s) ' customKcats.proteins{i} ' were not found in the model.']);
    +0159         end
    +0160 
    +0161         % if not specific reactions are defined, find all the reaction
    +0162         % index where the enzyme is used
    +0163         if isempty(customKcats.rxns{i})
    +0164             temp_rxnIdxs = arrayfun(@(x) find(model.ec.rxnEnzMat(:, x)), enzIdx, 'UniformOutput', false);
    +0165             % otherwhise, If a set of reactions if defined, only get the index for those
    +0166             % but ignore any _EXP_ suffixes
    +0167         else
    +0168             rxns = strtrim(strsplit(customKcats.rxns{i}, ','));
    +0169             temp_rxnIdxs = cellfun(@(x) find(strcmp(ecRxnNoSuffix, x)), rxns, 'UniformOutput', false);
    +0170         end
    +0171 
    +0172         if ~isempty(temp_rxnIdxs)
    +0173             rxnIdxs = [];
    +0174             for j = 1:numel(temp_rxnIdxs)
    +0175                 rxnIdxs = [rxnIdxs; temp_rxnIdxs{j}];
    +0176             end
    +0177 
    +0178             % Check when multiple proteins are involved, since it can return same rxn n times
    +0179             rxnIdxs = unique(rxnIdxs); %unique(rxnIdxs{1, :});
    +0180 
    +0181             for j = 1:numel(rxnIdxs)
    +0182                 % Get all the enzymes involved in the reaction
    +0183                 allEnzInRxn = find(model.ec.rxnEnzMat(rxnIdxs(j),:));
    +0184 
    +0185                 C = intersect(enzIdx, allEnzInRxn);
    +0186 
    +0187                 % Determine the match percentage bewteen the rules
    +0188                 if numel(C) == numel(enzIdx) && numel(C) == numel(allEnzInRxn)
    +0189                     match = 1;
    +0190                 else
    +0191                     if numel(enzIdx) < numel(allEnzInRxn)
    +0192                         match = numel(C) / numel(allEnzInRxn);
    +0193                     else
    +0194                         match = numel(C) / numel(enzIdx);
    +0195                     end
    +0196                 end
    +0197 
    +0198                 % Update the kcat value stored in the model, if match 100%,
    +0199                 % otherwhise if >= 0.5 inform to the user to be validated
    +0200                 if match == 1
    +0201                     rxnToUpdate(rxnIdxs(j)) = 1;
    +0202                     model.ec.kcat(rxnIdxs(j)) = customKcats.kcat(i);
    +0203 
    +0204                     % Add note mentioning manual kcat change
    +0205                     model.ec.source{rxnIdxs(j),1} = 'custom';
    +0206                     if isfield(customKcats,'notes')
    +0207                         model.ec.notes{rxnIdxs(j), 1} = appendNote(model.ec.notes{rxnIdxs(j), 1}, customKcats.notes{i});
    +0208                     end
    +0209                 elseif match >= 0.5 && match < 1
    +0210                     rxnNotMatch(rxnIdxs(j)) = 1;
    +0211                     evaluatedRule{rxnIdxs(j), 1} = customKcats.proteins{i};
    +0212                     enzInModel{rxnIdxs(j), 1} = strjoin(model.ec.enzymes(allEnzInRxn), ' + ');
    +0213                 end
    +0214             end
    +0215         end
    +0216     end
    +0217 end
    +0218 
    +0219 % Apply the new kcat values to the model
    +0220 if ~isempty(find(rxnToUpdate, 1))
    +0221     if model.ec.geckoLight
    +0222         %Light ecModels update by reaction of the model, not by ec row
    +0223         updateRxns = ismember(model.rxns, extractAfter(model.ec.rxns(rxnToUpdate), 4));
    +0224     else
    +0225         updateRxns = rxnToUpdate;
    +0226     end
    +0227     model = applyKcatConstraints(model, updateRxns);
    +0228 else
    +0229     printOrange('WARNING: No matches found. Consider checking the IDs or proteins in customKcats.');
    +0230 end
    +0231 
    +0232 rxnUpdated = model.ec.rxns(find(rxnToUpdate));
    +0233 
    +0234 % Remove from notMatch those reactions already updated
    +0235 remove = and(rxnToUpdate, rxnNotMatch);
    +0236 rxnNotMatch(remove) = 0;
    +0237 evaluatedRule(remove) = '';
    +0238 enzInModel(remove) = '';
    +0239 
    +0240 idRxns = model.ec.rxns(find(rxnNotMatch));
    +0241 if model.ec.geckoLight
    +0242     modelRxnIds = extractAfter(idRxns, 4);
    +0243 else
    +0244     modelRxnIds = idRxns;
    +0245 end
    +0246 fullIdx = cellfun(@(x) find(strcmpi(model.rxns, x), 1), modelRxnIds);
    +0247 rxnsNames = model.rxnNames(fullIdx);
    +0248 evaluatedRule = evaluatedRule(~cellfun('isempty', evaluatedRule));
    +0249 enzInModel = enzInModel(~cellfun('isempty', enzInModel));
    +0250 rules = model.grRules(fullIdx);
    +0251 notMatch = table(idRxns, rxnsNames, evaluatedRule, enzInModel, rules, ...
    +0252     'VariableNames',{'rxns', 'name', 'custom enzymes', 'enzymes in model', 'rules'});
    +0253 end
    +0254 
    +0255 function notes = appendNote(notes, note)
    +0256 % An empty note changes nothing; a note is separated by ', ' from an existing one.
    +0257 note = strtrim(note);
    +0258 if isempty(note)
    +0259     return
    +0260 elseif isempty(notes)
    +0261     notes = note;
    +0262 else
    +0263     notes = [notes ', ' note];
    +0264 end
    +0265 end
    +
    Generated by m2html © 2005
    + + \ No newline at end of file diff --git a/doc/src/change_model/applyKcatConstraints.html b/doc/src/change_model/applyKcatConstraints.html new file mode 100644 index 00000000..b9264430 --- /dev/null +++ b/doc/src/change_model/applyKcatConstraints.html @@ -0,0 +1,249 @@ + + + + Description of applyKcatConstraints + + + + + + + + + +
    Home > src > change_model > applyKcatConstraints.m
    + + + +

    applyKcatConstraints +

    + +

    PURPOSE ^

    +
    applyKcatConstraints Apply kcat-derived enzyme constraints to an ecModel.
    + +

    SYNOPSIS ^

    +
    function model = applyKcatConstraints(model,varargin)
    + +

    DESCRIPTION ^

    +
     applyKcatConstraints  Apply kcat-derived enzyme constraints to an ecModel.
    +
    + Existing enzyme constraints are first removed (unless updateRxns is
    + provided), and new constraints are defined based on the content of
    + model.ec.kcat. When every kcat is 0, the existing constraints of a full
    + ecModel are removed and no new ones are written; a light ecModel is
    + returned unchanged.
    +
    + Parameters
    + ----------
    + model : struct
    +     an ecModel in GECKO 3 format (with ecModel.ec structure).
    +
    + Name-Value Arguments
    + --------------------
    + updateRxns : logical or double or cell or char or string
    +     if not all enzyme constraints should be updated, this can be given as
    +     either a logical vector of length model.ec.rxns, a vector of
    +     model.ec.rxns indices, or a (cell array of) string(s) with
    +     model.ec.rxns identifiers. For light models, these reactions should
    +     match model.rxns.
    +
    + Returns
    + -------
    + model : struct
    +     ecModel where reactions are constrained by enzyme usage if a kcat
    +     value was provided for the reaction-enzyme pair in model.ec.kcat.
    +
    + Examples
    + --------
    +     % optional arguments may be given positionally or as name-value pairs:
    +     model = applyKcatConstraints(model, updateRxns);
    +     model = applyKcatConstraints(model, 'updateRxns', updateRxns);
    +
    + See also
    + --------
    + makeEcModel, getKcatAcrossIsozymes, setKcatForReactions
    + + +

    CROSS-REFERENCE INFORMATION ^

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

    SOURCE CODE ^

    +
    0001 function model = applyKcatConstraints(model,varargin)
    +0002 % applyKcatConstraints  Apply kcat-derived enzyme constraints to an ecModel.
    +0003 %
    +0004 % Existing enzyme constraints are first removed (unless updateRxns is
    +0005 % provided), and new constraints are defined based on the content of
    +0006 % model.ec.kcat. When every kcat is 0, the existing constraints of a full
    +0007 % ecModel are removed and no new ones are written; a light ecModel is
    +0008 % returned unchanged.
    +0009 %
    +0010 % Parameters
    +0011 % ----------
    +0012 % model : struct
    +0013 %     an ecModel in GECKO 3 format (with ecModel.ec structure).
    +0014 %
    +0015 % Name-Value Arguments
    +0016 % --------------------
    +0017 % updateRxns : logical or double or cell or char or string
    +0018 %     if not all enzyme constraints should be updated, this can be given as
    +0019 %     either a logical vector of length model.ec.rxns, a vector of
    +0020 %     model.ec.rxns indices, or a (cell array of) string(s) with
    +0021 %     model.ec.rxns identifiers. For light models, these reactions should
    +0022 %     match model.rxns.
    +0023 %
    +0024 % Returns
    +0025 % -------
    +0026 % model : struct
    +0027 %     ecModel where reactions are constrained by enzyme usage if a kcat
    +0028 %     value was provided for the reaction-enzyme pair in model.ec.kcat.
    +0029 %
    +0030 % Examples
    +0031 % --------
    +0032 %     % optional arguments may be given positionally or as name-value pairs:
    +0033 %     model = applyKcatConstraints(model, updateRxns);
    +0034 %     model = applyKcatConstraints(model, 'updateRxns', updateRxns);
    +0035 %
    +0036 % See also
    +0037 % --------
    +0038 % makeEcModel, getKcatAcrossIsozymes, setKcatForReactions
    +0039 
    +0040 p = parseGECKOargs(varargin, { ...
    +0041     'updateRxns', []});
    +0042 updateRxns = p.updateRxns;
    +0043 
    +0044 %these lines are for the updateRxns handling below only
    +0045 if (model.ec.geckoLight)
    +0046     rxns = model.rxns;
    +0047 else
    +0048     rxns = model.ec.rxns;
    +0049 end
    +0050 
    +0051 if isempty(updateRxns)
    +0052     updateRxns = true(numel(rxns),1);
    +0053 elseif isnumeric(updateRxns)
    +0054     updateRxnsLog = false(numel(rxns),1);
    +0055     updateRxnsLog(updateRxns) = true;
    +0056     updateRxns = updateRxnsLog;
    +0057 elseif iscellstr(updateRxns) || ischar(updateRxns) || isstring(updateRxns)
    +0058     updateRxnsIds = convertCharArray(updateRxns);
    +0059     updateRxns = ismember(rxns,updateRxnsIds);
    +0060 end
    +0061  
    +0062 if isempty(find(updateRxns, 1)) || isempty(updateRxns)
    +0063      error('No reaction to update or updateRxns is logical but without any true value')
    +0064 end
    +0065 
    +0066 if ~isfield(model,'ec')
    +0067     error(['No model.ec structure could be found: the provided model is'...
    +0068            ' not a valid GECKO3 ecModel. First run makeEcModel(model).'])
    +0069 end
    +0070 if all(model.ec.kcat==0)
    +0071     if model.ec.geckoLight
    +0072         printOrange('WARNING: No kcat values are provided in model.ec.kcat, model remains unchanged.\n');
    +0073         return
    +0074     end
    +0075     % In a full model the existing enzyme constraints of the selected
    +0076     % reactions are still cleared below, and no new ones are written.
    +0077     printOrange('WARNING: No kcat values are provided in model.ec.kcat, existing enzyme constraints are cleared and no new ones are written.\n');
    +0078 end
    +0079 
    +0080 %Clear existing incorporation of enzyme usage
    +0081 if ~model.ec.geckoLight
    +0082     protMetIdx = startsWith(model.mets,'prot_') & ~strcmp(model.mets,'prot_pool');
    +0083     metabolRxn = unique(model.ec.rxns(updateRxns));
    +0084     metabolRxn = ismember(model.rxns,metabolRxn);
    +0085     model.S(protMetIdx,metabolRxn) = 0;
    +0086 end %no clearing needed for GECKO Light, will be overwritten below
    +0087 %For normal GECKO formulation (full model), where each enzyme is explicitly considered
    +0088 if ~model.ec.geckoLight 
    +0089     %Column 1 = rxn idx; 2 = enzyme idx; 3 = subunit copies; 4 = kcat; 5 = MW
    +0090     newKcats=zeros(numel(updateRxns)*10,5);
    +0091     updateRxns=find(updateRxns);
    +0092     kcatFirst=0;
    +0093     for i=1:numel(updateRxns)
    +0094         j=updateRxns(i);
    +0095         if model.ec.kcat(j) ~= 0
    +0096             enzymes   = find(model.ec.rxnEnzMat(j,:));
    +0097             kcatLast  = kcatFirst+numel(enzymes);
    +0098             kcatFirst = kcatFirst+1;
    +0099             newKcats(kcatFirst:kcatLast,1) = j;
    +0100             newKcats(kcatFirst:kcatLast,2) = enzymes;
    +0101             newKcats(kcatFirst:kcatLast,3) = model.ec.rxnEnzMat(j,enzymes);
    +0102             newKcats(kcatFirst:kcatLast,4) = model.ec.kcat(j);
    +0103             newKcats(kcatFirst:kcatLast,5) = model.ec.mw(enzymes);
    +0104             kcatFirst = kcatLast;
    +0105         end
    +0106     end
    +0107     if exist('kcatLast','var') % If it does not, then no kcats are found
    +0108         newKcats(kcatLast+1:end,:)=[];
    +0109 
    +0110         sel = newKcats(:,4) > 0; %Only apply to non-zero kcat
    +0111         newKcats(sel,4) = newKcats(sel,4) * 3600; %per second -> per hour
    +0112         newKcats(sel,4) = newKcats(sel,5) ./ newKcats(sel,4); %MW/kcat
    +0113         newKcats(sel,4) = newKcats(sel,3) .* newKcats(sel,4); %Multicopy subunits.
    +0114         newKcats(~sel,4) = 0; %Results in zero-cost
    +0115 
    +0116         %Replace rxns and enzymes with their location in model
    +0117         [~,newKcats(:,1)] = ismember(model.ec.rxns(newKcats(:,1)),model.rxns);
    +0118         [~,newKcats(:,2)] = ismember(strcat('prot_',model.ec.enzymes(newKcats(:,2))),model.mets);
    +0119         linearIndices     = sub2ind(size(model.S),newKcats(:,2),newKcats(:,1));
    +0120         %Two enzyme rows can map to the same prot_<accession> metabolite (distinct
    +0121         %genes sharing one UniProt entry), giving a repeated linear index here. A
    +0122         %plain indexed assignment on a repeated index keeps only the last value
    +0123         %written, silently dropping the other enzyme's contribution instead of
    +0124         %adding it, so accumulate per unique index instead.
    +0125         [uniqueIndices,~,linearIndicesToUnique] = unique(linearIndices);
    +0126         summedValues = accumarray(linearIndicesToUnique,-newKcats(:,4));
    +0127         model.S(uniqueIndices) = summedValues; %Substrate = negative
    +0128     end
    +0129 else %GECKO light formulation, where prot_pool represents all usages
    +0130     prot_pool_idx = find(ismember(model.mets,'prot_pool'));
    +0131     %first remove the prefix of all rxns
    +0132     modRxns     = extractAfter(model.ec.rxns,4);
    +0133     % Map ec-reactions to model.rxns
    +0134     [hasEc,~]   = ismember(model.rxns,modRxns);
    +0135     hasEc       = find(hasEc & updateRxns);
    +0136     [~,rxnIdx]   = ismember(modRxns,model.rxns);
    +0137     for i = 1:numel(hasEc)
    +0138         % Get all isozymes per reaction
    +0139         ecIdx = find(rxnIdx == hasEc(i));
    +0140         % ecIdx = strcmp(model.rxns(hasEc(i)),modRxns);
    +0141         % Multiply enzymes with their MW (they are then automatically
    +0142         % summed per reaction), and divide by their kcat, to get a vector
    +0143         % of MW/kcat values.
    +0144         MWkcat = (model.ec.rxnEnzMat(ecIdx,:) * model.ec.mw) ./ model.ec.kcat(ecIdx);
    +0145         % If kcat was zero, MWkcat is Inf (or NaN without enzymes). An
    +0146         % isozyme row without any enzyme has MWkcat zero. Drop those
    +0147         % isozymes *before* selecting the cheapest one: including them in
    +0148         % the min() below would let an isozyme with no kcat or no enzyme
    +0149         % always win over a real kcat on another isozyme of the same reaction.
    +0150         % A row with a kcat that is not positive or an enzyme mass that is not
    +0151         % positive has no usable cost either.
    +0152         hasEnzyme = full(sum(model.ec.rxnEnzMat(ecIdx,:) ~= 0,2)) > 0;
    +0153         enzMass   = full(model.ec.rxnEnzMat(ecIdx,:) * model.ec.mw);
    +0154         validKcat = ~isinf(MWkcat) & ~isnan(MWkcat) & hasEnzyme & ...
    +0155             model.ec.kcat(ecIdx) > 0 & enzMass > 0;
    +0156         if any(validKcat)
    +0157             % Select the lowest MW/kcat (= most efficient), and convert to /hour
    +0158             model.S(prot_pool_idx, hasEc(i)) = -min(MWkcat(validKcat)/3600);
    +0159         else
    +0160             % No isozyme of this reaction has a usable kcat; leave it
    +0161             % unconstrained by enzyme usage.
    +0162             model.S(prot_pool_idx, hasEc(i)) = 0;
    +0163         end
    +0164     end
    +0165 end
    +0166 end
    +
    Generated by m2html © 2005
    + + \ No newline at end of file diff --git a/doc/src/change_model/findMetSmiles.html b/doc/src/change_model/findMetSmiles.html new file mode 100644 index 00000000..0b5a10a0 --- /dev/null +++ b/doc/src/change_model/findMetSmiles.html @@ -0,0 +1,192 @@ + + + + Description of findMetSmiles + + + + + + + + + +
    Home > src > change_model > findMetSmiles.m
    + + + +

    findMetSmiles +

    + +

    PURPOSE ^

    +
    findMetSmiles Query PubChem by metabolite names to obtain SMILES.
    + +

    SYNOPSIS ^

    +
    function [model,noSMILES] = findMetSmiles(model, varargin)
    + +

    DESCRIPTION ^

    +
     findMetSmiles  Query PubChem by metabolite names to obtain SMILES.
    +
    + Matches are cached in tutorials/***/data/smilesDB.tsv, which is checked
    + first on subsequent runs so repeated queries are avoided. If the model
    + already has a metSmiles field, non-empty entries are left unchanged.
    +
    + Parameters
    + ----------
    + model : struct
    +     a model whose metNames field is used to find the relevant SMILES.
    +
    + Name-Value Arguments
    + --------------------
    + modelAdapter : ModelAdapter
    +     a loaded model adapter (default: the current default model adapter).
    + verbose : logical
    +     whether progress should be reported (default true).
    +
    + Returns
    + -------
    + model : struct
    +     model with model.metSmiles specified.
    + noSMILES : cell
    +     metabolite names for which no SMILES could be found.
    + + +

    CROSS-REFERENCE INFORMATION ^

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

    SOURCE CODE ^

    +
    0001 function [model,noSMILES] = findMetSmiles(model, varargin)
    +0002 % findMetSmiles  Query PubChem by metabolite names to obtain SMILES.
    +0003 %
    +0004 % Matches are cached in tutorials/***/data/smilesDB.tsv, which is checked
    +0005 % first on subsequent runs so repeated queries are avoided. If the model
    +0006 % already has a metSmiles field, non-empty entries are left unchanged.
    +0007 %
    +0008 % Parameters
    +0009 % ----------
    +0010 % model : struct
    +0011 %     a model whose metNames field is used to find the relevant SMILES.
    +0012 %
    +0013 % Name-Value Arguments
    +0014 % --------------------
    +0015 % modelAdapter : ModelAdapter
    +0016 %     a loaded model adapter (default: the current default model adapter).
    +0017 % verbose : logical
    +0018 %     whether progress should be reported (default true).
    +0019 %
    +0020 % Returns
    +0021 % -------
    +0022 % model : struct
    +0023 %     model with model.metSmiles specified.
    +0024 % noSMILES : cell
    +0025 %     metabolite names for which no SMILES could be found.
    +0026 %
    +0027 p = parseGECKOargs(varargin, { ...
    +0028     'modelAdapter', []; ...
    +0029     'verbose',      true});
    +0030 modelAdapter = p.modelAdapter;
    +0031 verbose      = p.verbose;
    +0032 if isempty(verbose); verbose = true; end
    +0033 
    +0034 if isempty(modelAdapter)
    +0035     modelAdapter = ModelAdapterManager.getDefault();
    +0036     if isempty(modelAdapter)
    +0037         error('Either send in a modelAdapter or set the default model adapter in the ModelAdapterManager.')
    +0038     end
    +0039 end
    +0040 params = modelAdapter.params;
    +0041 
    +0042 [uniqueNames, ~, uniqueIdx] = unique(regexprep(model.metNames,'^prot_.*',''));
    +0043 uniqueSmiles(1:numel(uniqueNames),1) = {''};
    +0044 metMatch = false(length(uniqueNames),1);
    +0045 metMatch(strcmp(uniqueNames,'')) = 1; % No need trying to match empty fields
    +0046 if verbose; fprintf('Check for local SMILES database... '); end
    +0047 smilesDBfile = (fullfile(params.path,'data','smilesDB.tsv'));
    +0048 if exist(smilesDBfile,'file')==2
    +0049     fID = fopen(smilesDBfile,'r');
    +0050     raw = textscan(fID,'%s %s','Delimiter','\t','HeaderLines',0);
    +0051     fclose(fID);
    +0052     smilesDB.names = raw{1};
    +0053     smilesDB.smile = raw{2};
    +0054     [metMatch, metIdx] = ismember(uniqueNames,smilesDB.names);
    +0055     uniqueSmiles(metMatch) = smilesDB.smile(metIdx(metMatch));
    +0056     if verbose; fprintf('done.\n'); end
    +0057 else
    +0058     if verbose; fprintf('not found.\n'); end
    +0059 end
    +0060 
    +0061 if any(~metMatch)
    +0062     PB = progressReport(numel(uniqueNames), 'Querying PubChem for SMILES by metabolite names');
    +0063     webOptions = weboptions('Timeout', 30);
    +0064     for i = 1:numel(uniqueNames)
    +0065         PB.count;
    +0066         if metMatch(i)
    +0067             continue;
    +0068         end
    +0069         retry = 0;
    +0070         while retry < 10
    +0071             try
    +0072                 smileResult       = webread(['https://pubchem.ncbi.nlm.nih.gov/rest/pug/compound/name/' uniqueNames{i} '/property/CanonicalSMILES/TXT'], webOptions);
    +0073                 %Sometimes multiple lines are given, with alternative SMILES. Only
    +0074                 %keep the first suggestion.
    +0075                 smileResult       = regexp(smileResult,'(^\S*)\n','once','tokens');
    +0076                 uniqueSmiles{i,1} = smileResult{1,1};
    +0077                 retry = 15; % success: no retry
    +0078             catch exception
    +0079                 %Sometimes the call fails, for example since the server is busy. In those cases
    +0080                 %we will try 10 times. Some errors however are because the metabolite
    +0081                 %name does no exist in the database (404) or some other error (the metabolite contains
    +0082                 %a slash or similar, 400 or 500). In those cases we can
    +0083                 %immediately give up.
    +0084                 if (strcmp(exception.identifier, 'MATLAB:webservices:HTTP404StatusCodeError') || ...
    +0085                         strcmp(exception.identifier, 'MATLAB:webservices:HTTP400StatusCodeError') || ...
    +0086                         strcmp(exception.identifier, 'MATLAB:webservices:HTTP500StatusCodeError'))
    +0087                     uniqueSmiles(i) = {''};
    +0088                     retry = 15;
    +0089                 else
    +0090                     retry = retry + 1;
    +0091                 end
    +0092             end
    +0093         if retry == 10
    +0094             error('Cannot reach PubChem. Check your internet connection and try again.')
    +0095         end
    +0096         end
    +0097         % Append one line each time, in case internet connection is lost
    +0098         % halfway. Open & close file each time to avoid leaving the file
    +0099         % open when breaking the function.
    +0100         out = [uniqueNames(i), uniqueSmiles(i)];
    +0101         fID = fopen(smilesDBfile,'a');
    +0102         fprintf(fID,'%s\t%s\n',out{:});
    +0103         fclose(fID);
    +0104     end
    +0105     PB.done;
    +0106     if verbose
    +0107         fprintf('Model-specific SMILES database stored at %s\n',smilesDBfile);
    +0108     end
    +0109 end
    +0110 newSmiles = uniqueSmiles(uniqueIdx);
    +0111 noSMILES = cellfun(@isempty,uniqueSmiles);
    +0112 successRatio = 1-(numel(find(noSMILES))/numel(uniqueSmiles));
    +0113 fprintf('SMILES could be found for %s%% of the unique metabolite names.\n',num2str(successRatio*100,'%.0f'))
    +0114 noSMILES = uniqueNames(noSMILES);
    +0115 
    +0116 if ~isfield(model,'metSmiles') || all(cellfun(@isempty,model.metSmiles))
    +0117     model.metSmiles = newSmiles;
    +0118 else
    +0119     emptySmiles = cellfun(@isempty,model.metSmiles);
    +0120     model.metSmiles(emptySmiles) = newSmiles(emptySmiles);
    +0121 end
    +0122 end
    +
    Generated by m2html © 2005
    + + \ No newline at end of file diff --git a/doc/src/change_model/getComplexData.html b/doc/src/change_model/getComplexData.html new file mode 100644 index 00000000..6809fddc --- /dev/null +++ b/doc/src/change_model/getComplexData.html @@ -0,0 +1,273 @@ + + + + Description of getComplexData + + + + + + + + + +
    Home > src > change_model > getComplexData.m
    + + + +

    getComplexData +

    + +

    PURPOSE ^

    +
    getComplexData Download curated complex stochiometries from Complex Portal.
    + +

    SYNOPSIS ^

    +
    function complexInfo = getComplexData(varargin)
    + +

    DESCRIPTION ^

    +
     getComplexData  Download curated complex stochiometries from Complex Portal.
    +
    + Downloads curated complex stochiometries from the EMBL-EBI Complex Portal
    + database. Writes data/ComplexPortal.json in the obj.params.path specified
    + in the model adapter.
    +
    + Name-Value Arguments
    + --------------------
    + taxonomicID : double
    +     taxonomic identifier for which complex data should be downloaded. Only
    +     taxonomic identifiers allowed are those included on Complex Portal:
    +     https://www.ebi.ac.uk/complexportal/complex/organisms. If empty, no
    +     complex data is downloaded; if 0 (zero), complex data from all
    +     organisms in Complex Portal is downloaded.
    + modelAdapter : ModelAdapter
    +     a loaded model adapter (default: the current default model adapter).
    +
    + Returns
    + -------
    + complexInfo : struct
    +     structure with data downloaded from Complex Portal (fields described
    +     under Notes).
    +
    + Notes
    + -----
    + The complexInfo structure has the following fields:
    +
    + - complexID : id of the complex on Complex Portal.
    + - name : name of the complex on Complex Portal.
    + - species : organism containing the complex.
    + - geneName : names of the genes in the complex.
    + - protID : Uniprot IDs of the proteins in the complex.
    + - stochiometry : the complex stochiometry given in the same order as the genes and proteins in geneName and protID.
    + - defined : 0 if Complex Portal has no defined stochiometry, 1 if defined subunit stochiometry is given, 2 if complex consists of sub-complexes, whose subunit stochiometries are given.
    +
    + Examples
    + --------
    +     % optional arguments may be given positionally or as name-value pairs:
    +     complexInfo = getComplexData(organism, modelAdapter);
    +     complexInfo = getComplexData('taxonomicID', organism);
    +
    + See also
    + --------
    + applyComplexData, makeEcModel
    + + +

    CROSS-REFERENCE INFORMATION ^

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

    SOURCE CODE ^

    +
    0001 function complexInfo = getComplexData(varargin)
    +0002 % getComplexData  Download curated complex stochiometries from Complex Portal.
    +0003 %
    +0004 % Downloads curated complex stochiometries from the EMBL-EBI Complex Portal
    +0005 % database. Writes data/ComplexPortal.json in the obj.params.path specified
    +0006 % in the model adapter.
    +0007 %
    +0008 % Name-Value Arguments
    +0009 % --------------------
    +0010 % taxonomicID : double
    +0011 %     taxonomic identifier for which complex data should be downloaded. Only
    +0012 %     taxonomic identifiers allowed are those included on Complex Portal:
    +0013 %     https://www.ebi.ac.uk/complexportal/complex/organisms. If empty, no
    +0014 %     complex data is downloaded; if 0 (zero), complex data from all
    +0015 %     organisms in Complex Portal is downloaded.
    +0016 % modelAdapter : ModelAdapter
    +0017 %     a loaded model adapter (default: the current default model adapter).
    +0018 %
    +0019 % Returns
    +0020 % -------
    +0021 % complexInfo : struct
    +0022 %     structure with data downloaded from Complex Portal (fields described
    +0023 %     under Notes).
    +0024 %
    +0025 % Notes
    +0026 % -----
    +0027 % The complexInfo structure has the following fields:
    +0028 %
    +0029 % - complexID : id of the complex on Complex Portal.
    +0030 % - name : name of the complex on Complex Portal.
    +0031 % - species : organism containing the complex.
    +0032 % - geneName : names of the genes in the complex.
    +0033 % - protID : Uniprot IDs of the proteins in the complex.
    +0034 % - stochiometry : the complex stochiometry given in the same order as the genes and proteins in geneName and protID.
    +0035 % - defined : 0 if Complex Portal has no defined stochiometry, 1 if defined subunit stochiometry is given, 2 if complex consists of sub-complexes, whose subunit stochiometries are given.
    +0036 %
    +0037 % Examples
    +0038 % --------
    +0039 %     % optional arguments may be given positionally or as name-value pairs:
    +0040 %     complexInfo = getComplexData(organism, modelAdapter);
    +0041 %     complexInfo = getComplexData('taxonomicID', organism);
    +0042 %
    +0043 % See also
    +0044 % --------
    +0045 % applyComplexData, makeEcModel
    +0046 
    +0047 p = parseGECKOargs(varargin, { ...
    +0048     'taxonomicID',  []; ...
    +0049     'modelAdapter', []});
    +0050 taxonomicID  = p.taxonomicID;
    +0051 modelAdapter = p.modelAdapter;
    +0052 
    +0053 if isempty(modelAdapter)
    +0054     modelAdapter = ModelAdapterManager.getDefault();
    +0055     if isempty(modelAdapter)
    +0056         error('Either send in a modelAdapter or set the default model adapter in the ModelAdapterManager.')
    +0057     end
    +0058 end
    +0059 
    +0060 if isempty(taxonomicID)
    +0061     taxonomicID = modelAdapter.getParameters().complex.taxonomicID;
    +0062 end
    +0063 
    +0064 params = modelAdapter.params;
    +0065 if isempty(taxonomicID) % Can be empty when gathered from model adapter
    +0066     printOrange('WARNING: No taxonomicID specified.');
    +0067     return
    +0068 elseif taxonomicID == 0
    +0069     taxonomicID = [];
    +0070 end
    +0071 
    +0072 webOptions = weboptions('Timeout', 30);
    +0073 try
    +0074     url1 = 'https://www.ebi.ac.uk/intact/complex-ws/search/*';
    +0075     if ~isempty(taxonomicID)
    +0076         url1 = [url1 '?facets=species&filters=species:("' num2str(taxonomicID) '")'];
    +0077     end
    +0078     data = webread(url1,webOptions);
    +0079 catch ME
    +0080     if (strcmp(ME.identifier,'MATLAB:webservices:HTTP404StatusCodeError'))
    +0081         error('Cannot connect to the Complex Portal, perhaps the server is not responding');
    +0082     end
    +0083 end
    +0084 if data.size == 0
    +0085     error('No data could be gathered from Complex Portal for the specified taxonomicID.')
    +0086 end
    +0087 complexData = cell(data.size,7);
    +0088 
    +0089 PB = progressReport(data.size, 'Retrieving information for complexes');
    +0090 for i = 1:data.size
    +0091     PB.count;
    +0092     url2 = 'https://www.ebi.ac.uk/intact/complex-ws/complex/';
    +0093     complexID = data.elements(i,1).complexAC;
    +0094     try
    +0095         temp = webread([url2 complexID],webOptions);
    +0096     catch ME
    +0097         if (strcmp(ME.identifier,'MATLAB:webservices:HTTP404StatusCodeError'))
    +0098             printOrange(['WARNING: Cannot retrieve the information for ' complexID '.\n']);
    +0099         end
    +0100         temp = [];
    +0101     end
    +0102 
    +0103     if ~isempty(temp)
    +0104         complexData(i,1) = {temp.complexAc};
    +0105         complexData(i,2) = {temp.name};
    +0106         complexData(i,3) = {temp.species};
    +0107 
    +0108         idxIntType = find(strcmpi({temp.participants.interactorType}, 'protein'));
    +0109 
    +0110         % Some complex reported are 'stable complex', then, save the id
    +0111         % complex and but set the genes and protein to a empty string.
    +0112         if numel(idxIntType) > 0
    +0113             complexData(i,4) = {{temp.participants(idxIntType).name}};
    +0114             complexData(i,5) = {{temp.participants(idxIntType).identifier}};
    +0115         else
    +0116             complexData(i,4) = {{temp.participants.name}};
    +0117             complexData(i,5) = {{temp.participants.identifier}};
    +0118         end
    +0119 
    +0120         % Portal complex has two stochiometry values, a minimum and
    +0121         % maximum value. Only minimum will be store. In some cases,
    +0122         % some complex does not have stochiometry coefficient, then, it
    +0123         % will be fill with zeros
    +0124         if ~cellfun('isempty',{temp.participants.stochiometry})
    +0125             % For some reason, if there is only one protein in the complex
    +0126             % split function does nor return a cell nx2, instead is 2x1,
    +0127             % then assign an incorrect stochiometry
    +0128             switch numel(idxIntType)
    +0129                 case 0 % Contains complexes
    +0130                     stochiometry = split({temp.participants.stochiometry}.', ',');
    +0131                     complexData(i,7) = {2};
    +0132                 case 1 % Contains one protein
    +0133                     stochiometry = split({temp.participants(idxIntType).stochiometry}.', ',').';
    +0134                     complexData(i,7) = {1};
    +0135                 otherwise
    +0136                     stochiometry = split({temp.participants(idxIntType).stochiometry}.', ',');
    +0137                     complexData(i,7) = {1};
    +0138             end
    +0139             values = str2double(erase(stochiometry(:,1),"minValue: ")).';
    +0140             complexData(i,6) = {values};
    +0141         else
    +0142             complexData(i,6) = {repelem(0,numel(complexData{i,4}))};
    +0143             complexData(i,7) = {0};
    +0144         end
    +0145     end
    +0146 end
    +0147 fprintf('\n');
    +0148 
    +0149 % Expand complexes of complexes
    +0150 complexComplex = find([complexData{:,7}]==2);
    +0151 if ~isempty(complexComplex)
    +0152     for i=1:numel(complexComplex)
    +0153         subComplex    = complexData{complexComplex(i),5};
    +0154         subComplexS   = complexData{complexComplex(i),6};
    +0155         subComplexIdx = find(ismember(complexData(:,1),subComplex));
    +0156         allGenes = horzcat(complexData{subComplexIdx,4});
    +0157         allProts = horzcat(complexData{subComplexIdx,5});
    +0158         allStoch = {complexData{subComplexIdx,6}};
    +0159         for j=1:numel(subComplex)
    +0160             allStoch{j}=allStoch{j}*subComplexS(j);
    +0161         end
    +0162         allStoch = horzcat(allStoch{:});
    +0163         [allGenes,ia,ic] = unique(allGenes,'stable');
    +0164         allProts = allProts(ia);
    +0165         allStoch = splitapply(@sum, allStoch', ic);
    +0166         complexData{complexComplex(i),4} = allGenes;
    +0167         complexData{complexComplex(i),5} = allProts;
    +0168         complexData{complexComplex(i),6} = allStoch;
    +0169     end
    +0170 end
    +0171 
    +0172 rowHeadings = {'complexID','name','species','geneName','protID','stochiometry','defined'};
    +0173 
    +0174 complexInfo = cell2struct(complexData, rowHeadings, 2);
    +0175 
    +0176 % Convert to a JSON file
    +0177 jsontxt = jsonencode(cell2table(complexData, 'VariableNames', rowHeadings));
    +0178 % Write to a JSON file
    +0179 fid = fopen(fullfile(params.path,'data','ComplexPortal.json'), 'w');
    +0180 fprintf(fid, '%s', jsontxt);
    +0181 fclose(fid);
    +0182 fprintf('Model-specific ComplexPortal database stored at %s\n',fullfile(params.path,'data','ComplexPortal.json'));
    +0183 end
    +
    Generated by m2html © 2005
    + + \ No newline at end of file diff --git a/doc/src/change_model/getKcatAcrossIsozymes.html b/doc/src/change_model/getKcatAcrossIsozymes.html new file mode 100644 index 00000000..afc79e45 --- /dev/null +++ b/doc/src/change_model/getKcatAcrossIsozymes.html @@ -0,0 +1,129 @@ + + + + Description of getKcatAcrossIsozymes + + + + + + + + + +
    Home > src > change_model > getKcatAcrossIsozymes.m
    + + + +

    getKcatAcrossIsozymes +

    + +

    PURPOSE ^

    +
    getKcatAcrossIsozymes Fill missing kcats from isozymes of the same reaction.
    + +

    SYNOPSIS ^

    +
    function model = getKcatAcrossIsozymes(model)
    + +

    DESCRIPTION ^

    +
     getKcatAcrossIsozymes  Fill missing kcats from isozymes of the same reaction.
    +
    + For reactions without kcat value (0 in model.ec.kcat), isozymes are found
    + (being based on the same reaction in the conventional GEM), that do have a
    + kcat value assigned. The mean kcat value of these isozymes is then used to
    + fill in model.ec.kcat. Only isozymes with a kcat above 0 enter the mean: a
    + NaN or negative kcat of an isozyme is left out, and an entry whose kcat is
    + NaN is not filled.
    +
    + Parameters
    + ----------
    + model : struct
    +     an ecModel in full GECKO 3 format (with ecModel.ec structure), not
    +     GECKO light.
    +
    + Returns
    + -------
    + model : struct
    +     an ecModel with kcat values assigned to isozymes in model.ec.kcat.
    +
    + Examples
    + --------
    +     model = getKcatAcrossIsozymes(model);
    +
    + See also
    + --------
    + applyKcatConstraints, setKcatForReactions
    + + +

    CROSS-REFERENCE INFORMATION ^

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

    SOURCE CODE ^

    +
    0001 function model = getKcatAcrossIsozymes(model)
    +0002 % getKcatAcrossIsozymes  Fill missing kcats from isozymes of the same reaction.
    +0003 %
    +0004 % For reactions without kcat value (0 in model.ec.kcat), isozymes are found
    +0005 % (being based on the same reaction in the conventional GEM), that do have a
    +0006 % kcat value assigned. The mean kcat value of these isozymes is then used to
    +0007 % fill in model.ec.kcat. Only isozymes with a kcat above 0 enter the mean: a
    +0008 % NaN or negative kcat of an isozyme is left out, and an entry whose kcat is
    +0009 % NaN is not filled.
    +0010 %
    +0011 % Parameters
    +0012 % ----------
    +0013 % model : struct
    +0014 %     an ecModel in full GECKO 3 format (with ecModel.ec structure), not
    +0015 %     GECKO light.
    +0016 %
    +0017 % Returns
    +0018 % -------
    +0019 % model : struct
    +0020 %     an ecModel with kcat values assigned to isozymes in model.ec.kcat.
    +0021 %
    +0022 % Examples
    +0023 % --------
    +0024 %     model = getKcatAcrossIsozymes(model);
    +0025 %
    +0026 % See also
    +0027 % --------
    +0028 % applyKcatConstraints, setKcatForReactions
    +0029 
    +0030 if model.ec.geckoLight
    +0031     error('Provided model is a GECKO light version, this function is not relevant for such models')
    +0032 end
    +0033 if all(model.ec.kcat==0)
    +0034     printOrange('WARNING: No kcat values are provided in model.ec.kcat, model remains unchanged.\n');
    +0035     return
    +0036 end
    +0037 
    +0038 noKcats     = model.ec.kcat==0;
    +0039 hasKcat     = model.ec.kcat>0; % NaN and negative kcats are not isozyme values
    +0040 rxnIDs      = regexprep(model.ec.rxns,'_EXP_\d+','');
    +0041 noKcatID    = rxnIDs(noKcats);
    +0042 yesKcatID   = rxnIDs(hasKcat);
    +0043 yesKcatVal  = model.ec.kcat(hasKcat);
    +0044 
    +0045 noKcatVal   = cellfun(@(x) strcmp(x, yesKcatID), noKcatID, 'UniformOutput', false);
    +0046 noKcatVal   = cell2mat(cellfun(@(x) mean(yesKcatVal(x)), noKcatVal, 'UniformOutput', false));
    +0047 
    +0048 newKcat     = find(~isnan(noKcatVal));
    +0049 newKcatIdx  = find(noKcats);
    +0050 newKcatIdx  = newKcatIdx(newKcat);
    +0051 newKcat     = noKcatVal(newKcat);
    +0052 
    +0053 model.ec.kcat(newKcatIdx) = newKcat;
    +0054 model.ec.source(newKcatIdx) = {'isozymes'};
    +0055 end
    +0056
    +
    Generated by m2html © 2005
    + + \ No newline at end of file diff --git a/doc/src/change_model/getReactionsFromEnzyme.html b/doc/src/change_model/getReactionsFromEnzyme.html new file mode 100644 index 00000000..4153a532 --- /dev/null +++ b/doc/src/change_model/getReactionsFromEnzyme.html @@ -0,0 +1,121 @@ + + + + Description of getReactionsFromEnzyme + + + + + + + + + +
    Home > src > change_model > getReactionsFromEnzyme.m
    + + + +

    getReactionsFromEnzyme +

    + +

    PURPOSE ^

    +
    getReactionsFromEnzyme Get all reactions annotated to a particular enzyme.
    + +

    SYNOPSIS ^

    +
    function [rxns, kcat, idx, rxnNames, grRules] = getReactionsFromEnzyme(ecModel,proteinId)
    + +

    DESCRIPTION ^

    +
     getReactionsFromEnzyme  Get all reactions annotated to a particular enzyme.
    +
    + Parameters
    + ----------
    + ecModel : struct
    +     an ecModel in GECKO 3 format (with ecModel.ec structure).
    + proteinId : char
    +     protein identifier, matching ecModel.ec.enzymes case-insensitively.
    +
    + Returns
    + -------
    + rxns : cell
    +     reactions that are associated with this enzyme.
    + kcat : double
    +     kcat values of the corresponding reactions.
    + idx : double
    +     index of the reactions in ecModel.ec.rxns.
    + rxnNames : cell
    +     names of the reactions.
    + grRules : cell
    +     grRules of the reactions.
    +
    + Notes
    + -----
    + An unmatched proteinId is not an error: all five outputs are returned
    + empty, with no warning. Matching against ecModel.ec.enzymes is
    + case-insensitive.
    +
    + Examples
    + --------
    +     [rxns, kcat, idx, rxnNames, grRules] = getReactionsFromEnzyme(ecModel, proteinId);
    + + +

    CROSS-REFERENCE INFORMATION ^

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

    SOURCE CODE ^

    +
    0001 function [rxns, kcat, idx, rxnNames, grRules] = getReactionsFromEnzyme(ecModel,proteinId)
    +0002 % getReactionsFromEnzyme  Get all reactions annotated to a particular enzyme.
    +0003 %
    +0004 % Parameters
    +0005 % ----------
    +0006 % ecModel : struct
    +0007 %     an ecModel in GECKO 3 format (with ecModel.ec structure).
    +0008 % proteinId : char
    +0009 %     protein identifier, matching ecModel.ec.enzymes case-insensitively.
    +0010 %
    +0011 % Returns
    +0012 % -------
    +0013 % rxns : cell
    +0014 %     reactions that are associated with this enzyme.
    +0015 % kcat : double
    +0016 %     kcat values of the corresponding reactions.
    +0017 % idx : double
    +0018 %     index of the reactions in ecModel.ec.rxns.
    +0019 % rxnNames : cell
    +0020 %     names of the reactions.
    +0021 % grRules : cell
    +0022 %     grRules of the reactions.
    +0023 %
    +0024 % Notes
    +0025 % -----
    +0026 % An unmatched proteinId is not an error: all five outputs are returned
    +0027 % empty, with no warning. Matching against ecModel.ec.enzymes is
    +0028 % case-insensitive.
    +0029 %
    +0030 % Examples
    +0031 % --------
    +0032 %     [rxns, kcat, idx, rxnNames, grRules] = getReactionsFromEnzyme(ecModel, proteinId);
    +0033 
    +0034 protIdx     = find(strcmpi(ecModel.ec.enzymes,proteinId));
    +0035 ecRxnIdx    = find(ecModel.ec.rxnEnzMat(:,protIdx));
    +0036 rxns        = ecModel.ec.rxns(ecRxnIdx);
    +0037 kcat        = ecModel.ec.kcat(ecRxnIdx);
    +0038 
    +0039 idx         = ecRxnIdx;
    +0040 
    +0041 [~,rxnIdx]  = ismember(rxns,ecModel.rxns);
    +0042 rxnNames    = ecModel.rxnNames(rxnIdx);
    +0043 grRules     =  ecModel.grRules(rxnIdx);
    +0044 end
    +
    Generated by m2html © 2005
    + + \ No newline at end of file diff --git a/doc/src/change_model/getSubsetEcModel.html b/doc/src/change_model/getSubsetEcModel.html new file mode 100644 index 00000000..e306ad73 --- /dev/null +++ b/doc/src/change_model/getSubsetEcModel.html @@ -0,0 +1,155 @@ + + + + Description of getSubsetEcModel + + + + + + + + + +
    Home > src > change_model > getSubsetEcModel.m
    + + + +

    getSubsetEcModel +

    + +

    PURPOSE ^

    +
    getSubsetEcModel Generate a context-specific ecModel from a general one.
    + +

    SYNOPSIS ^

    +
    function smallEcModel = getSubsetEcModel(bigEcModel,smallGEM)
    + +

    DESCRIPTION ^

    +
     getSubsetEcModel  Generate a context-specific ecModel from a general one.
    +
    + Generate a context-specific ecModel (strain/cell-line/tissue) by mapping
    + reactions and genes from a conventional context-specific GEM to a general
    + ecModel (bigEcModel), to yield a context-specific ecModel.
    +
    + Both models (bigEcModel and the smallGEM) should have derived from the
    + same starting model. If an ecModel with human-GEM 1.15.0 is made
    + (yielding the bigEcModel), then human-GEM 1.15.0 should also be the basis
    + from which the context-specific GEM (smallGEM) was generated by for
    + instance tINIT.
    +
    + Parameters
    + ----------
    + bigEcModel : struct
    +     enzyme-constrained version of conventional model of metabolism for a
    +     given species.
    + smallGEM : struct
    +     reduced model (subset of the general model) for a specific strain
    +     (microbes) or cell-line/tissues (mammals).
    +
    + Returns
    + -------
    + smallEcModel : struct
    +     enzyme-constrained version of the context-specific model.
    +
    + Examples
    + --------
    +     smallEcModel = getSubsetEcModel(bigEcModel,smallGEM);
    + + +

    CROSS-REFERENCE INFORMATION ^

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

    SOURCE CODE ^

    +
    0001 function smallEcModel = getSubsetEcModel(bigEcModel,smallGEM)
    +0002 % getSubsetEcModel  Generate a context-specific ecModel from a general one.
    +0003 %
    +0004 % Generate a context-specific ecModel (strain/cell-line/tissue) by mapping
    +0005 % reactions and genes from a conventional context-specific GEM to a general
    +0006 % ecModel (bigEcModel), to yield a context-specific ecModel.
    +0007 %
    +0008 % Both models (bigEcModel and the smallGEM) should have derived from the
    +0009 % same starting model. If an ecModel with human-GEM 1.15.0 is made
    +0010 % (yielding the bigEcModel), then human-GEM 1.15.0 should also be the basis
    +0011 % from which the context-specific GEM (smallGEM) was generated by for
    +0012 % instance tINIT.
    +0013 %
    +0014 % Parameters
    +0015 % ----------
    +0016 % bigEcModel : struct
    +0017 %     enzyme-constrained version of conventional model of metabolism for a
    +0018 %     given species.
    +0019 % smallGEM : struct
    +0020 %     reduced model (subset of the general model) for a specific strain
    +0021 %     (microbes) or cell-line/tissues (mammals).
    +0022 %
    +0023 % Returns
    +0024 % -------
    +0025 % smallEcModel : struct
    +0026 %     enzyme-constrained version of the context-specific model.
    +0027 %
    +0028 % Examples
    +0029 % --------
    +0030 %     smallEcModel = getSubsetEcModel(bigEcModel,smallGEM);
    +0031 
    +0032 % Check if models were derived from the same starting GEM
    +0033 Rxn_format = regexprep(bigEcModel.rxns,'_REV|_EXP_\d+','');
    +0034 rxnsDiff = find(~ismember(smallGEM.rxns,Rxn_format));
    +0035 if numel(rxnsDiff) > 0
    +0036     error('%s', ravenList(['While both models should have derived from the same starting ',...
    +0037             'GEM, the following reactions from smallGEM could not be found ',...
    +0038             'in bigEcModel:'],smallGEM.rxns(rxnsDiff),false));
    +0039 end
    +0040 
    +0041 % Check if original bigEcModel contains context-dependent protein constraints
    +0042 if any(bigEcModel.ub(startsWith(bigEcModel.rxns,'usage_prot_')) ~= 1000)
    +0043     printOrange(['WARNING: The bigEcModel is constraint by protein concentrations that are\n' ...
    +0044                  'likely not relevant in the constructed smallEcModel.\n']);
    +0045 end
    +0046 
    +0047 % Remove genes (and associated reactions) that are absent in smallGEM
    +0048 genesToRemove  = setdiff(bigEcModel.genes,smallGEM.genes);
    +0049 % If genesToRemove contains "standard", then remove this entry
    +0050 if ismember('standard', genesToRemove)
    +0051     genesToRemove(strcmp(genesToRemove, 'standard')) = [];
    +0052 end
    +0053 smallEcModel = removeGenes(bigEcModel,genesToRemove,true,true,false);
    +0054 
    +0055 % Remove genes from ec-structure
    +0056 enzToRemove = ismember(smallEcModel.ec.genes,genesToRemove);
    +0057 smallEcModel.ec.genes(enzToRemove)       = [];
    +0058 smallEcModel.ec.enzymes(enzToRemove)     = [];
    +0059 smallEcModel.ec.concs(enzToRemove)       = [];
    +0060 smallEcModel.ec.mw(enzToRemove)          = [];
    +0061 smallEcModel.ec.sequence(enzToRemove)    = [];
    +0062 smallEcModel.ec.rxnEnzMat(:,enzToRemove) = [];
    +0063 
    +0064 % Remove any reaction (except prot_ associated) that is absent from smallGEM
    +0065 trimRxns = regexprep(smallEcModel.rxns,'_REV|_EXP_\d+','');
    +0066 protRxns = startsWith(smallEcModel.rxns,{'usage_prot_','prot_pool_exchange'});
    +0067 keepRxns = ismember(trimRxns,smallGEM.rxns) | protRxns;
    +0068 smallEcModel = removeReactions(smallEcModel,~keepRxns, true, true, true);
    +0069 
    +0070 % Remove reactions from ec-structure
    +0071 ecRxnsToRemove = ~ismember(smallEcModel.ec.rxns,smallEcModel.rxns);
    +0072 
    +0073 smallEcModel.ec.rxns(ecRxnsToRemove)        = [];
    +0074 smallEcModel.ec.kcat(ecRxnsToRemove)        = [];
    +0075 smallEcModel.ec.source(ecRxnsToRemove)      = [];
    +0076 smallEcModel.ec.notes(ecRxnsToRemove)       = [];
    +0077 smallEcModel.ec.eccodes(ecRxnsToRemove)     = [];
    +0078 smallEcModel.ec.rxnEnzMat(ecRxnsToRemove,:) = [];
    +0079 end
    +0080
    +
    Generated by m2html © 2005
    + + \ No newline at end of file diff --git a/doc/src/change_model/index.html b/doc/src/change_model/index.html new file mode 100644 index 00000000..66f0ed8f --- /dev/null +++ b/doc/src/change_model/index.html @@ -0,0 +1,29 @@ + + + + Index for Directory src/change_model + + + + + + + + + + +
    < Master indexIndex for src/change_model >
    + +

    Index for src/change_model

    + +

    Matlab files in this directory:

    + +
     addNewRxnsToECaddNewRxnsToEC Add new reactions to an enzyme-constrained model.
     applyComplexDataapplyComplexData Apply complex subunit stoichiometry to an ecModel.
     applyCustomKcatsapplyCustomKcats Apply user-defined kcats to an ecModel.
     applyKcatConstraintsapplyKcatConstraints Apply kcat-derived enzyme constraints to an ecModel.
     findMetSmilesfindMetSmiles Query PubChem by metabolite names to obtain SMILES.
     getComplexDatagetComplexData Download curated complex stochiometries from Complex Portal.
     getKcatAcrossIsozymesgetKcatAcrossIsozymes Fill missing kcats from isozymes of the same reaction.
     getReactionsFromEnzymegetReactionsFromEnzyme Get all reactions annotated to a particular enzyme.
     getSubsetEcModelgetSubsetEcModel Generate a context-specific ecModel from a general one.
     makeEcModelmakeEcModel Expand a conventional GEM into a basic ecModel.
     mapRxnsToConvmapRxnsToConv Map ecModel fluxes back to the conventional starting model.
     setKcatForReactionssetKcatForReactions Change the kcat value for selected reactions.
     setProtPoolSizesetProtPoolSize Set the limit of the total protein usage in the model.
     upgradeEcModelupgradeEcModel Bring an ecModel made with GECKO 3 to the GECKO 4 format.
    + + + + +
    Generated by m2html © 2005
    + + \ No newline at end of file diff --git a/doc/src/change_model/makeEcModel.html b/doc/src/change_model/makeEcModel.html new file mode 100644 index 00000000..f0870aea --- /dev/null +++ b/doc/src/change_model/makeEcModel.html @@ -0,0 +1,669 @@ + + + + Description of makeEcModel + + + + + + + + + +
    Home > src > change_model > makeEcModel.m
    + + + +

    makeEcModel +

    + +

    PURPOSE ^

    +
    makeEcModel Expand a conventional GEM into a basic ecModel.
    + +

    SYNOPSIS ^

    +
    function [model, noUniprot] = makeEcModel(model, varargin)
    + +

    DESCRIPTION ^

    +
     makeEcModel  Expand a conventional GEM into a basic ecModel.
    +
    + Expands a conventional genome-scale model (in RAVEN format) with enzyme
    + information and prepares the reactions for integration of enzyme usage
    + coefficients. This function contains all the steps that need to be done to
    + get a basic ecModel, without incorporating any kcat values or constraints
    + yet. This function should only have to be run once for a model.
    +
    + Parameters
    + ----------
    + model : struct
    +     a model in RAVEN format.
    +
    + Name-Value Arguments
    + --------------------
    + geckoLight : logical
    +     true if a simplified GECKO light model should be generated (default
    +     false).
    + modelAdapter : ModelAdapter
    +     a loaded model adapter (default: the current default model adapter).
    +
    + Returns
    + -------
    + model : struct
    +     an ecModel in GECKO 3 format, with a model.ec structure where enzyme
    +     and kcat information are stored. Protein pseudometabolites and their
    +     draw reactions are added to the model, but their usage is not yet
    +     implemented (due to absent kcat values at this stage).
    + noUniprot : cell
    +     genes for which no information could be found in either the Uniprot
    +     or, as fallback, the KEGG database.
    +
    + Notes
    + -----
    + The function goes through the following steps:
    +
    + 1.  Remove gene associations from pseudoreactions.
    + 2.  Invert irreversible backwards reactions.
    + 3.  Correct 'rev' vector to match lb and ub vectors.
    + 4.  Convert to irreversible model (splits reversible reactions).
    + 5.  [Skipped with geckoLight:] Expand model to split reactions with 'OR'
    +     in grRules (each reaction is then catalyzed by one enzyme (complex)).
    + 6.  Make empty model.ec structure, that will contain enzyme and kcat
    +     information. One entry per reaction, where isozymes have multiple
    +     entries. This model.ec structure will later be populated with kcat
    +     values. For geckoLight the structure is different, where each reaction
    +     can have multiple isozymes.
    + 7.  Add enzyme information fields to model.ec structure: MW, sequence.
    +     Data is gathered from UniProt, with KEGG used as a fallback for genes
    +     that UniProt does not match.
    + 8.  Populate model.ec structure with information from each reaction.
    + 9.  [Skipped with geckoLight:] Add proteins as pseudometabolites.
    + 10. Add prot_pool pseudometabolite.
    + 11. [Skipped with geckoLight:] Add usage reactions for the protein
    +     pseudometabolites, replenishing from the protein pool (default, can be
    +     changed to consider proteomics data at later stage).
    + 12. Add protein pool reaction, without upper bound.
    +
    + Note that while protein pseudometabolites, draw & pool reactions might be
    + added to the model, the enzyme usage is not yet incorporated in each
    + metabolic reaction, so enzymes will not be used. applyKcatConstraints
    + incorporates protein pseudometabolites in reactions as enzyme usages by
    + applying the specified kcats as constraints.
    +
    + The model.ec structure has the following fields:
    +
    + - geckoLight : 0 if full model, 1 if light.
    + - rxns : reaction identifiers that correspond to model.rxns.
    + - kcat : kcat values - not set here.
    + - source : specifies where the kcats come from - not set here.
    + - notes : notes that can be set by downstream functions - not set here.
    + - eccodes : enzyme codes for each enzyme - not set here.
    + - genes : the genes involved in the kcats - not necessarily the same as model.genes, since some genes may not be found in databases etc.
    + - enzymes : Uniprot protein identifiers for the genes; for a gene that
    +   was only matched via the KEGG fallback and has no UniProt accession on
    +   its KEGG entry, the bare KEGG gene identifier is used instead.
    + - mw : molecular weights of the enzymes.
    + - sequence : sequence of the genes/enzymes.
    + - concs : concentrations of the enzymes - not set here.
    + - rxnEnzMat : matrix of enzymes and rxns.
    +
    + The full model is split on all ORs in the GPRs, meaning that the reactions
    + will be duplicated for each isozyme. Only the rxns with genes are added.
    + The fields rxns, eccodes, kcat, source and notes will therefore have one
    + entry per reaction. The fields genes, enzymes, mw, sequence and concs will
    + have one entry per gene. The rxnEnzMat is a matrix with reactions and
    + genes, mapping which genes are connected to which reaction (where isozymes
    + have different reactions).
    +
    + The light model works a bit differently. The model has the same number of
    + rxns as the original model, but expanded since it is reversible + one the
    + extra prot maintenance rxn and one extra prot_pool rxn. However, the ec
    + fields rxns, eccodes, kcat, source and notes are duplicated for each
    + isozyme, sorted the same way as model.rxns. So, in model.ec.rxns, the same
    + reaction will appear several times after one another, one entry per
    + izozyme, with corresponding values for that isozyme. These fields
    + therefore have the same length as for the full model. The fields genes,
    + enzymes, mw, sequence and concs are the same here as in the full model.
    + The rxnEnzMat maps the model.ec.rxns entries to genes and is therefore of
    + the same size as for the full model.
    +
    + Examples
    + --------
    +     % optional arguments may be given positionally or as name-value pairs:
    +     [model, noUniprot] = makeEcModel(model);
    +     [model, noUniprot] = makeEcModel(model, 'geckoLight', true);
    +
    + See also
    + --------
    + applyKcatConstraints, applyComplexData
    + + +

    CROSS-REFERENCE INFORMATION ^

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

    SUBFUNCTIONS ^

    + + +

    SOURCE CODE ^

    +
    0001 function [model, noUniprot] = makeEcModel(model, varargin)
    +0002 % makeEcModel  Expand a conventional GEM into a basic ecModel.
    +0003 %
    +0004 % Expands a conventional genome-scale model (in RAVEN format) with enzyme
    +0005 % information and prepares the reactions for integration of enzyme usage
    +0006 % coefficients. This function contains all the steps that need to be done to
    +0007 % get a basic ecModel, without incorporating any kcat values or constraints
    +0008 % yet. This function should only have to be run once for a model.
    +0009 %
    +0010 % Parameters
    +0011 % ----------
    +0012 % model : struct
    +0013 %     a model in RAVEN format.
    +0014 %
    +0015 % Name-Value Arguments
    +0016 % --------------------
    +0017 % geckoLight : logical
    +0018 %     true if a simplified GECKO light model should be generated (default
    +0019 %     false).
    +0020 % modelAdapter : ModelAdapter
    +0021 %     a loaded model adapter (default: the current default model adapter).
    +0022 %
    +0023 % Returns
    +0024 % -------
    +0025 % model : struct
    +0026 %     an ecModel in GECKO 3 format, with a model.ec structure where enzyme
    +0027 %     and kcat information are stored. Protein pseudometabolites and their
    +0028 %     draw reactions are added to the model, but their usage is not yet
    +0029 %     implemented (due to absent kcat values at this stage).
    +0030 % noUniprot : cell
    +0031 %     genes for which no information could be found in either the Uniprot
    +0032 %     or, as fallback, the KEGG database.
    +0033 %
    +0034 % Notes
    +0035 % -----
    +0036 % The function goes through the following steps:
    +0037 %
    +0038 % 1.  Remove gene associations from pseudoreactions.
    +0039 % 2.  Invert irreversible backwards reactions.
    +0040 % 3.  Correct 'rev' vector to match lb and ub vectors.
    +0041 % 4.  Convert to irreversible model (splits reversible reactions).
    +0042 % 5.  [Skipped with geckoLight:] Expand model to split reactions with 'OR'
    +0043 %     in grRules (each reaction is then catalyzed by one enzyme (complex)).
    +0044 % 6.  Make empty model.ec structure, that will contain enzyme and kcat
    +0045 %     information. One entry per reaction, where isozymes have multiple
    +0046 %     entries. This model.ec structure will later be populated with kcat
    +0047 %     values. For geckoLight the structure is different, where each reaction
    +0048 %     can have multiple isozymes.
    +0049 % 7.  Add enzyme information fields to model.ec structure: MW, sequence.
    +0050 %     Data is gathered from UniProt, with KEGG used as a fallback for genes
    +0051 %     that UniProt does not match.
    +0052 % 8.  Populate model.ec structure with information from each reaction.
    +0053 % 9.  [Skipped with geckoLight:] Add proteins as pseudometabolites.
    +0054 % 10. Add prot_pool pseudometabolite.
    +0055 % 11. [Skipped with geckoLight:] Add usage reactions for the protein
    +0056 %     pseudometabolites, replenishing from the protein pool (default, can be
    +0057 %     changed to consider proteomics data at later stage).
    +0058 % 12. Add protein pool reaction, without upper bound.
    +0059 %
    +0060 % Note that while protein pseudometabolites, draw & pool reactions might be
    +0061 % added to the model, the enzyme usage is not yet incorporated in each
    +0062 % metabolic reaction, so enzymes will not be used. applyKcatConstraints
    +0063 % incorporates protein pseudometabolites in reactions as enzyme usages by
    +0064 % applying the specified kcats as constraints.
    +0065 %
    +0066 % The model.ec structure has the following fields:
    +0067 %
    +0068 % - geckoLight : 0 if full model, 1 if light.
    +0069 % - rxns : reaction identifiers that correspond to model.rxns.
    +0070 % - kcat : kcat values - not set here.
    +0071 % - source : specifies where the kcats come from - not set here.
    +0072 % - notes : notes that can be set by downstream functions - not set here.
    +0073 % - eccodes : enzyme codes for each enzyme - not set here.
    +0074 % - genes : the genes involved in the kcats - not necessarily the same as model.genes, since some genes may not be found in databases etc.
    +0075 % - enzymes : Uniprot protein identifiers for the genes; for a gene that
    +0076 %   was only matched via the KEGG fallback and has no UniProt accession on
    +0077 %   its KEGG entry, the bare KEGG gene identifier is used instead.
    +0078 % - mw : molecular weights of the enzymes.
    +0079 % - sequence : sequence of the genes/enzymes.
    +0080 % - concs : concentrations of the enzymes - not set here.
    +0081 % - rxnEnzMat : matrix of enzymes and rxns.
    +0082 %
    +0083 % The full model is split on all ORs in the GPRs, meaning that the reactions
    +0084 % will be duplicated for each isozyme. Only the rxns with genes are added.
    +0085 % The fields rxns, eccodes, kcat, source and notes will therefore have one
    +0086 % entry per reaction. The fields genes, enzymes, mw, sequence and concs will
    +0087 % have one entry per gene. The rxnEnzMat is a matrix with reactions and
    +0088 % genes, mapping which genes are connected to which reaction (where isozymes
    +0089 % have different reactions).
    +0090 %
    +0091 % The light model works a bit differently. The model has the same number of
    +0092 % rxns as the original model, but expanded since it is reversible + one the
    +0093 % extra prot maintenance rxn and one extra prot_pool rxn. However, the ec
    +0094 % fields rxns, eccodes, kcat, source and notes are duplicated for each
    +0095 % isozyme, sorted the same way as model.rxns. So, in model.ec.rxns, the same
    +0096 % reaction will appear several times after one another, one entry per
    +0097 % izozyme, with corresponding values for that isozyme. These fields
    +0098 % therefore have the same length as for the full model. The fields genes,
    +0099 % enzymes, mw, sequence and concs are the same here as in the full model.
    +0100 % The rxnEnzMat maps the model.ec.rxns entries to genes and is therefore of
    +0101 % the same size as for the full model.
    +0102 %
    +0103 % Examples
    +0104 % --------
    +0105 %     % optional arguments may be given positionally or as name-value pairs:
    +0106 %     [model, noUniprot] = makeEcModel(model);
    +0107 %     [model, noUniprot] = makeEcModel(model, 'geckoLight', true);
    +0108 %
    +0109 % See also
    +0110 % --------
    +0111 % applyKcatConstraints, applyComplexData
    +0112 
    +0113 p = parseGECKOargs(varargin, { ...
    +0114     'geckoLight',   false; ...
    +0115     'modelAdapter', []});
    +0116 geckoLight   = p.geckoLight;
    +0117 modelAdapter = p.modelAdapter;
    +0118 
    +0119 if ~islogical(geckoLight) && ~(geckoLight == 0) && ~(geckoLight == 1)
    +0120     error('geckoLight should be either true or false')
    +0121 end
    +0122 
    +0123 if isempty(modelAdapter)
    +0124     modelAdapter = ModelAdapterManager.getDefault();
    +0125     if isempty(modelAdapter)
    +0126         error('Either send in a modelAdapter or set the default model adapter in the ModelAdapterManager.')
    +0127     end
    +0128 end
    +0129 params = modelAdapter.getParameters();
    +0130 compartmentID = strcmp(model.compNames,params.enzyme_comp);
    +0131 if ~any(compartmentID)
    +0132     error(['Compartment ' params.enzyme_comp ' (specified in params.enzyme_comp) '...
    +0133            'cannot be found in model.compNames'])
    +0134 end
    +0135 compartmentID = model.comps(compartmentID);
    +0136 
    +0137 if geckoLight
    +0138     ec.geckoLight=true;
    +0139 else
    +0140     ec.geckoLight=false;
    +0141 end
    +0142 
    +0143 %Check if model is in RAVEN format
    +0144 if any(isfield(model,{'rules','modelID'}))
    +0145     error(['The model is likely loaded using COBRA Toolbox readCbModel(). Instead, use ' ...
    +0146            'RAVEN Toolbox importModel(). Alternatively, you can also convert the ', ...
    +0147            'model in MATLAB using ravenCobraWrapper().'])
    +0148 end
    +0149 
    +0150 %Check for conflicting reaction and metabolite identifiers
    +0151 conflictId = startsWith(model.mets,'prot_');
    +0152 if any(conflictId)
    +0153     error('The identifiers in model.mets are not allowed to start with ''prot_''.')
    +0154 end
    +0155 conflictId = startsWith(model.rxns,{'usage_prot_','prot_pool'}) | ...
    +0156              endsWith(model.rxns,'_REV') | ...
    +0157              ~cellfun(@isempty,regexp(model.rxns,'_EXP_\d+$'));
    +0158 if any(conflictId)
    +0159     error(['The identifiers in model.rxns are not allowed to start with ''usage_prot'' ' ...
    +0160            'or ''prot_pool'', or end with ''_REV'' or ''_EXP_[digit]''.'])
    +0161 end
    +0162 
    +0163 databases = loadDatabases('both', modelAdapter);
    +0164 uniprotDB = databases.uniprot;
    +0165 keggDB    = databases.kegg;
    +0166 
    +0167 %1: Remove gene rules from pseudoreactions (if any):
    +0168 if exist(fullfile(params.path,'data','pseudoRxns.tsv'),'file')
    +0169     fID        = fopen(fullfile(params.path,'data','pseudoRxns.tsv'));
    +0170     fileData   = textscan(fID,'%s %s','delimiter','\t');
    +0171     fclose(fID);
    +0172     pseudoRxns = fileData{1};
    +0173     pseudoRxns = ismember(model.rxns,pseudoRxns);
    +0174 else
    +0175     pseudoRxns = false(numel(model.rxns),1);
    +0176 end
    +0177 pseudoRxns = find(pseudoRxns | contains(model.rxnNames,'pseudoreaction'));
    +0178 model.grRules(pseudoRxns)       = {''};
    +0179 model.rxnGeneMat(pseudoRxns,:)  = zeros(numel(pseudoRxns), numel(model.genes));
    +0180 
    +0181 %2: Swap direction of reactions that are defined to only carry negative flux
    +0182 to_swap=model.lb < 0 & model.ub == 0;
    +0183 model.S(:,to_swap)=-model.S(:,to_swap);
    +0184 model.ub(to_swap)=-model.lb(to_swap);
    +0185 model.lb(to_swap)=0;
    +0186 
    +0187 %3: Correct rev vector: true if LB < 0 & UB > 0, or it is an exchange reaction:
    +0188 model.rev = false(size(model.rxns));
    +0189 for i = 1:length(model.rxns)
    +0190     if (model.lb(i) < 0 && model.ub(i) > 0) || sum(model.S(:,i) ~= 0) == 1
    +0191         model.rev(i) = true;
    +0192     end
    +0193 end
    +0194 
    +0195 %4: Make irreversible model (appends _REV to reaction IDs to indicate reverse
    +0196 %reactions)
    +0197 [~,exchRxns] = getExchangeRxns(model);
    +0198 nonExchRxns = model.rxns;
    +0199 nonExchRxns(exchRxns) = [];
    +0200 model=convertToIrrev(model, nonExchRxns);
    +0201 
    +0202 %5: Expand model, to separate isozymes (appends _EXP_* to reaction IDs to
    +0203 %indicate duplication)
    +0204 if ~geckoLight
    +0205     model=expandModel(model);
    +0206 end
    +0207 % Sort reactions, so that reversible and isozymic reactions are kept near
    +0208 if ~geckoLight
    +0209     model=sortIdentifiers(model);
    +0210 end
    +0211 
    +0212 %6: Make ec-extension structure, one for gene-associated reaction.
    +0213 %   The structure is different for light and full models
    +0214 rxnWithGene  = find(sum(model.rxnGeneMat,2));
    +0215 if ~geckoLight
    +0216     ec.rxns      = model.rxns(rxnWithGene);
    +0217     emptyCell    = cell(numel(rxnWithGene),1);
    +0218     emptyCell(:) = {''};
    +0219     emptyVect    = zeros(numel(rxnWithGene),1);
    +0220     
    +0221     ec.kcat      = emptyVect;
    +0222     ec.source    = emptyCell; % Strings, like 'dlkcat', 'manual', 'brenda', etc.
    +0223     ec.notes     = emptyCell; % Additional comments
    +0224     ec.eccodes   = emptyCell;
    +0225     ec.concs     = emptyVect;
    +0226 else
    +0227     %Different strategy for GECKO light: Each reaction can exist multiple times in
    +0228     %ec.rxns and similar fields - one time per isozyme. The number of copies is
    +0229     %the number of AND-clauses of the GPR in disjunctive normal form, so
    +0230     %'G1 and (G2 or G3)' gives the isozymes {G1,G2} and {G1,G3}.
    +0231     isozymes = cellfun(@gprToDnf, model.grRules(rxnWithGene), 'UniformOutput', false);
    +0232     % A reaction with gene entries but an empty rule keeps one isozyme without enzymes
    +0233     isozymes(cellfun(@isempty,isozymes)) = {{cell(1,0)}};
    +0234     cpys = cellfun(@numel, isozymes);
    +0235     prevNumRxns = numel(isozymes);
    +0236     cpyIndices = repelem(rxnWithGene, cpys).'; %.' only matter when number of rxns is 1
    +0237     %loop through and add a prefix with an isozyme index to the rxns
    +0238     %we just give a fixed-length number as prefix, and assume that 999 is enough
    +0239     tmpRxns = model.rxns(cpyIndices); %now they have no prefix
    +0240     newRxns = tmpRxns;
    +0241     
    +0242     %add the prefix
    +0243     nextIndex = 1;
    +0244     for i = 1:numel(model.rxns)
    +0245         localRxnIndex = 1;
    +0246         if nextIndex <= length(tmpRxns) && strcmp(model.rxns(i), tmpRxns(nextIndex))
    +0247             while true
    +0248                 tmp = compose('%03d_',localRxnIndex);
    +0249                 newRxns{nextIndex} = [tmp{1} tmpRxns{nextIndex}];
    +0250                 localRxnIndex = localRxnIndex + 1;
    +0251                 if (localRxnIndex >= 1000)
    +0252                     error('Increase index size to 10000 - error in the code.'); %this should never happen, we don't have > 999 isozymes
    +0253                 end
    +0254                 nextIndex = nextIndex + 1;
    +0255                 if  nextIndex > length(tmpRxns) || ~strcmp(model.rxns(i), tmpRxns(nextIndex))
    +0256                     break;
    +0257                 end
    +0258             end
    +0259         end
    +0260     end
    +0261 
    +0262     ec.rxns      = newRxns;
    +0263     
    +0264     emptyCell    = cell(numel(ec.rxns),1);
    +0265     emptyCell(:) = {''};
    +0266     emptyVect    = zeros(numel(ec.rxns),1);
    +0267 
    +0268     ec.kcat      = emptyVect;
    +0269     ec.source    = emptyCell; % Strings, like 'dlkcat', 'manual', 'brenda', etc.
    +0270     ec.notes     = emptyCell; % Additional comments
    +0271     ec.eccodes   = emptyCell;
    +0272     ec.concs     = emptyVect;
    +0273 end
    +0274     
    +0275 %7: Gather enzyme information via UniprotDB (with optional KEGG fallback)
    +0276 uniprotCompatibleGenes = modelAdapter.getUniprotCompatibleGenes(model.genes);
    +0277 [Lia,Locb] = ismember(uniprotCompatibleGenes,uniprotDB.genes);
    +0278 
    +0279 uniprot = modelAdapter.getUniprotIDsFromTable(uniprotCompatibleGenes);
    +0280 if ~isequal(uniprot,uniprotCompatibleGenes)
    +0281     uniprot(cellfun(@isempty,uniprot)) = {''};
    +0282     [Lia,Locb] = ismember(uniprot,uniprotDB.ID);
    +0283 end
    +0284 
    +0285 %KEGG fallback for genes UniProt could not match.
    +0286 keggMatched = false(numel(model.genes),1);
    +0287 keggIdx     = zeros(numel(model.genes),1);
    +0288 if ~isempty(keggDB) && any(~Lia)
    +0289     notLia              = find(~Lia);
    +0290     keggCompatibleGenes = modelAdapter.getKeggCompatibleGenes(model.genes(notLia));
    +0291     [keggHit, kLocb]    = ismember(keggCompatibleGenes,keggDB.genes);
    +0292     keggMatched(notLia(keggHit)) = true;
    +0293     keggIdx(notLia(keggHit))     = kLocb(keggHit);
    +0294 end
    +0295 
    +0296 %noUniprot is now: gene unmatched in both UniProt and KEGG.
    +0297 noUniprot = uniprotCompatibleGenes(~Lia & ~keggMatched);
    +0298 if all(~Lia & ~keggMatched)
    +0299     error('None of the proteins in uniprot.tsv or kegg.tsv match the genes in the model. Changes to the obj.params.uniprot / obj.params.kegg parameters, or a data/uniprotConversion.tsv file are likely required.')
    +0300 elseif ~isempty(noUniprot)
    +0301     printOrange(['WARNING: The ' num2str(numel(noUniprot)) ' gene(s) reported '...
    +0302         'in "noUniprot" cannot be found in data/uniprot.tsv or data/kegg.tsv, these will ' ...
    +0303         'not be enzyme-constrained. If you intend to use different Uniprot '...
    +0304         'data (e.g. from a different proteome, make sure you first delete '...
    +0305         'the existing data/uniprot.tsv file.\n']);
    +0306 end
    +0307 
    +0308 %Build the per-gene enzyme/MW/sequence arrays in two passes: (a)
    +0309 %UniProt-matched, (b) KEGG-fallback-matched. Then concatenate and sort
    +0310 %alphabetically so ec.genes has a stable order across runs.
    +0311 ecGenesUni  = model.genes(Lia); %Will often be duplicate of model.genes, but is done here to prevent issues when it is not.
    +0312 LocbUni     = Locb(Lia);
    +0313 enzUni      = uniprotDB.ID(LocbUni);
    +0314 mwUni       = uniprotDB.MW(LocbUni);
    +0315 seqUni      = uniprotDB.seq(LocbUni);
    +0316 
    +0317 ecGenesKegg = model.genes(keggMatched);
    +0318 LocbKegg    = keggIdx(keggMatched);
    +0319 if isempty(LocbKegg)
    +0320     enzKegg = {};
    +0321     mwKegg  = [];
    +0322     seqKegg = {};
    +0323 else
    +0324     %ec.enzymes gets the UniProt accession stored on the KEGG row; if
    +0325     %that is empty, fall back to the bare KEGG gene id.
    +0326     enzKegg = keggDB.uniprot(LocbKegg);
    +0327     keggFallback = cellfun(@isempty,enzKegg);
    +0328     enzKegg(keggFallback) = keggDB.keggGene(LocbKegg(keggFallback));
    +0329     mwKegg  = keggDB.MW(LocbKegg);
    +0330     seqKegg = keggDB.seq(LocbKegg);
    +0331     if any(keggFallback)
    +0332         fallbackGenes = ecGenesKegg(keggFallback);
    +0333         fallbackIDs   = enzKegg(keggFallback);
    +0334         previewN = min(numel(fallbackGenes),10);
    +0335         previewParts = cell(1,previewN);
    +0336         for ii = 1:previewN
    +0337             previewParts{ii} = [fallbackGenes{ii} '->' fallbackIDs{ii}];
    +0338         end
    +0339         more = '';
    +0340         if numel(fallbackGenes) > 10
    +0341             more = [' (and ' num2str(numel(fallbackGenes)-10) ' more)'];
    +0342         end
    +0343         printOrange(['WARNING: ' num2str(numel(fallbackGenes)) ...
    +0344             ' KEGG-resolved gene(s) had no UniProt accession on the KEGG '...
    +0345             'row; the bare KEGG gene id is used in ec.enzymes instead: '...
    +0346             strjoin(previewParts,', ') more '\n']);
    +0347     end
    +0348 end
    +0349 
    +0350 allGenes   = [ecGenesUni; ecGenesKegg];
    +0351 allEnzymes = [enzUni; enzKegg];
    +0352 allMW      = [mwUni; mwKegg];
    +0353 allSeq     = [seqUni; seqKegg];
    +0354 
    +0355 [ec.genes,sIdx] = sort(allGenes);
    +0356 ec.enzymes      = allEnzymes(sIdx);
    +0357 ec.mw           = allMW(sIdx);
    +0358 ec.sequence     = allSeq(sIdx);
    +0359 %Additional info
    +0360 ec.concs        = nan(numel(ec.genes),1); % To be filled with proteomics data when available
    +0361 
    +0362 %8: Only parse rxns associated to genes
    +0363 if ~geckoLight
    +0364     ec.rxnEnzMat = zeros(numel(rxnWithGene),numel(ec.genes)); % Non-zeros will indicate the number of subunits
    +0365     for r=1:numel(rxnWithGene)
    +0366         rxnGenes   = model.genes(find(model.rxnGeneMat(rxnWithGene(r),:)));
    +0367         [~,locEnz] = ismember(rxnGenes,ec.genes); % Could also parse directly from rxnGeneMat, but some genes might be missing from Uniprot DB
    +0368         locEnz = locEnz(locEnz ~= 0); % Subunits missing from the databases are left out; the others still couple the reaction
    +0369         ec.rxnEnzMat(r,locEnz) = 1; %Assume 1 copy per subunit or enzyme, can be modified later
    +0370     end
    +0371 else
    +0372     %For light models, we need to split up all GPRs
    +0373     ec.rxnEnzMat = zeros(numel(ec.rxns),numel(ec.genes)); % Non-zeros will indicate the number of subunits
    +0374     nextIndex = 1;
    +0375     for i=1:prevNumRxns
    +0376         %Each isozyme is one AND-clause of the GPR and gets its own row of
    +0377         %ec.rxnEnzMat, in the order of the copies of the reaction in ec.rxns.
    +0378         for j = 1:numel(isozymes{i})
    +0379             ec.rxnEnzMat(nextIndex,ismember(ec.genes,isozymes{i}{j})) = 1;%should be subunit stoichoimetry
    +0380             nextIndex = nextIndex + 1;
    +0381         end
    +0382     end
    +0383 end
    +0384 
    +0385 %9: Add proteins as pseudometabolites
    +0386 if ~geckoLight
    +0387     [proteinMets.mets, uniprotSortId] = unique(ec.enzymes);
    +0388     proteinMets.mets         = strcat('prot_',proteinMets.mets);
    +0389     proteinMets.metNames     = proteinMets.mets;
    +0390     proteinMets.compartments = compartmentID;
    +0391     if isfield(model,'metMiriams')
    +0392         proteinMets.metMiriams   = repmat({struct('name',{{'sbo'}},'value',{{'SBO:0000252'}})},numel(proteinMets.mets),1);
    +0393     end
    +0394     if isfield(model,'metCharges')
    +0395         proteinMets.metCharges   = zeros(numel(proteinMets.mets),1);
    +0396     end
    +0397     proteinMets.metNotes     = repmat({'Enzyme-usage pseudometabolite'},numel(proteinMets.mets),1);
    +0398     model = addMets(model,proteinMets);
    +0399 end
    +0400 
    +0401 %10: Add protein pool pseudometabolite
    +0402 pool.mets         = 'prot_pool';
    +0403 pool.metNames     = pool.mets;
    +0404 pool.compartments = compartmentID;
    +0405 pool.metNotes     = 'Enzyme-usage protein pool';
    +0406 model = addMets(model,pool);
    +0407 
    +0408 %11: Add protein usage reactions.
    +0409 % Match the model's own subSystems convention (a cell array of chars, or a
    +0410 % cell array of cell arrays of chars -- RAVEN's checkModelStruct requires
    +0411 % the whole field to be consistently one or the other) rather than always
    +0412 % assuming one shape: mixing the two here is what left new ecModels unable
    +0413 % to be saved once RAVEN's own reconciliation in addRxns stopped papering
    +0414 % over the mismatch.
    +0415 if isfield(model,'subSystems') && ~isempty(model.subSystems) && ...
    +0416         ~any(cellfun(@iscell,model.subSystems))
    +0417     protUsageSubSystem = {'Protein usage'};
    +0418 else
    +0419     protUsageSubSystem = {{'Protein usage'}};
    +0420 end
    +0421 if ~geckoLight
    +0422     rxnNum                    = numel(proteinMets.mets);
    +0423     usageRxns.rxns            = strcat('usage_',proteinMets.mets);
    +0424     usageRxns.rxnNames        = usageRxns.rxns;
    +0425     usageRxns.mets            = cell(rxnNum,1);
    +0426     usageRxns.stoichCoeffs    = cell(rxnNum,1);
    +0427     for i=1:numel(usageRxns.mets)
    +0428         usageRxns.mets{i}         = {proteinMets.mets{i}, 'prot_pool'};
    +0429         usageRxns.stoichCoeffs{i} = [1,-1];
    +0430     end
    +0431     usageRxns.lb              = zeros(rxnNum,1);
    +0432     usageRxns.ub              = zeros(rxnNum,1) + 1000;
    +0433     usageRxns.rev             = ones(rxnNum,1);
    +0434     usageRxns.grRules         = ec.genes(uniprotSortId);
    +0435     if isfield(model,'subSystems')
    +0436         usageRxns.subSystems  = repmat(protUsageSubSystem, rxnNum, 1);
    +0437     end
    +0438     model = addRxns(model,usageRxns);
    +0439 end
    +0440 
    +0441 %12: Add protein pool reaction (forward: -> prot_pool; UB set by setProtPoolSize)
    +0442 poolRxn.rxns            = 'prot_pool_exchange';
    +0443 poolRxn.rxnNames        = poolRxn.rxns;
    +0444 poolRxn.mets            = {'prot_pool'};
    +0445 poolRxn.stoichCoeffs    = {1};
    +0446 poolRxn.lb              = 0;
    +0447 poolRxn.ub              = 1000;
    +0448 poolRxn.rev             = 1;
    +0449 if isfield(model,'subSystems')
    +0450     poolRxn.subSystems  = protUsageSubSystem;
    +0451 end
    +0452 model = addRxns(model,poolRxn);
    +0453 
    +0454 model.ec=ec;
    +0455 end
    +0456 
    +0457 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
    +0458 %Function that expands a gene rule into disjunctive normal form: a cell array
    +0459 %with one cell per isozyme, each holding the gene ids that are ANDed in it.
    +0460 %Gene ids are whole words, so an id that contains 'or' or 'and' is kept
    +0461 %intact. An empty rule gives an empty cell array.
    +0462 function dnf = gprToDnf(rule)
    +0463 tokens = regexp(rule,'\(|\)|[^\s()]+','match');
    +0464 isOperator = strcmpi(tokens,'and') | strcmpi(tokens,'or');
    +0465 tokens(isOperator) = lower(tokens(isOperator)); % Operators are case insensitive
    +0466 if isempty(tokens)
    +0467     dnf = {};
    +0468     return
    +0469 end
    +0470 [dnf,pos] = parseOr(tokens,1,rule);
    +0471 if pos <= numel(tokens)
    +0472     error('Cannot parse the gene rule "%s"',rule)
    +0473 end
    +0474 end
    +0475 
    +0476 function [dnf,pos] = parseOr(tokens,pos,rule)
    +0477 [dnf,pos] = parseAnd(tokens,pos,rule);
    +0478 while pos <= numel(tokens) && strcmp(tokens{pos},'or')
    +0479     [rhs,pos] = parseAnd(tokens,pos+1,rule);
    +0480     dnf = [dnf,rhs];
    +0481 end
    +0482 end
    +0483 
    +0484 function [dnf,pos] = parseAnd(tokens,pos,rule)
    +0485 [dnf,pos] = parseAtom(tokens,pos,rule);
    +0486 while pos <= numel(tokens) && strcmp(tokens{pos},'and')
    +0487     [rhs,pos] = parseAtom(tokens,pos+1,rule);
    +0488     product = cell(1,0);
    +0489     for a = 1:numel(dnf)
    +0490         for b = 1:numel(rhs)
    +0491             product{end+1} = [dnf{a},rhs{b}]; %#ok<AGROW>
    +0492         end
    +0493     end
    +0494     dnf = product;
    +0495 end
    +0496 end
    +0497 
    +0498 function [dnf,pos] = parseAtom(tokens,pos,rule)
    +0499 if pos > numel(tokens) || any(strcmp(tokens{pos},{')','and','or'}))
    +0500     error('Cannot parse the gene rule "%s"',rule)
    +0501 elseif strcmp(tokens{pos},'(')
    +0502     [dnf,pos] = parseOr(tokens,pos+1,rule);
    +0503     if pos > numel(tokens) || ~strcmp(tokens{pos},')')
    +0504         error('Cannot parse the gene rule "%s"',rule)
    +0505     end
    +0506     pos = pos + 1;
    +0507 else
    +0508     dnf = {tokens(pos)};
    +0509     pos = pos + 1;
    +0510 end
    +0511 end
    +
    Generated by m2html © 2005
    + + \ No newline at end of file diff --git a/doc/src/change_model/mapRxnsToConv.html b/doc/src/change_model/mapRxnsToConv.html new file mode 100644 index 00000000..f8769bc1 --- /dev/null +++ b/doc/src/change_model/mapRxnsToConv.html @@ -0,0 +1,151 @@ + + + + Description of mapRxnsToConv + + + + + + + + + +
    Home > src > change_model > mapRxnsToConv.m
    + + + +

    mapRxnsToConv +

    + +

    PURPOSE ^

    +
    mapRxnsToConv Map ecModel fluxes back to the conventional starting model.
    + +

    SYNOPSIS ^

    +
    function [mappedFlux, enzUsageFlux, usageEnz] = mapRxnsToConv(ecModel, model, fluxVect)
    + +

    DESCRIPTION ^

    +
     mapRxnsToConv  Map ecModel fluxes back to the conventional starting model.
    +
    + A vector (or matrix) of fluxes is mapped to the reactions in the
    + conventional starting model that was used to construct the ecModel. It is
    + essential that the provided conventional model is indeed the model that
    + was used to initiate ecModel reconstruction.
    +
    + Parameters
    + ----------
    + ecModel : struct
    +     an ecModel in GECKO 3 format (with ecModel.ec structure), that was
    +     used to obtain fluxVect.
    + model : struct
    +     the starting model for ecModel, to which the reactions should be
    +     mapped.
    + fluxVect : double
    +     vector or matrix of flux values, matching ecModel.rxns.
    +
    + Returns
    + -------
    + mappedFlux : double
    +     vector or matrix of flux values, matching model.rxns.
    + enzUsageFlux : double
    +     vector or matrix of flux values from enzyme usage reactions, as these
    +     are absent from mappedFlux.
    + usageEnz : cell
    +     cell array with protein IDs, matching enzUsageFlux.
    +
    + Examples
    + --------
    +     [mappedFlux, enzUsageFlux, usageEnz] = mapRxnsToConv(ecModel, model, fluxVect);
    +
    + See also
    + --------
    + ecFVA
    + + +

    CROSS-REFERENCE INFORMATION ^

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

    SOURCE CODE ^

    +
    0001 function [mappedFlux, enzUsageFlux, usageEnz] = mapRxnsToConv(ecModel, model, fluxVect)
    +0002 % mapRxnsToConv  Map ecModel fluxes back to the conventional starting model.
    +0003 %
    +0004 % A vector (or matrix) of fluxes is mapped to the reactions in the
    +0005 % conventional starting model that was used to construct the ecModel. It is
    +0006 % essential that the provided conventional model is indeed the model that
    +0007 % was used to initiate ecModel reconstruction.
    +0008 %
    +0009 % Parameters
    +0010 % ----------
    +0011 % ecModel : struct
    +0012 %     an ecModel in GECKO 3 format (with ecModel.ec structure), that was
    +0013 %     used to obtain fluxVect.
    +0014 % model : struct
    +0015 %     the starting model for ecModel, to which the reactions should be
    +0016 %     mapped.
    +0017 % fluxVect : double
    +0018 %     vector or matrix of flux values, matching ecModel.rxns.
    +0019 %
    +0020 % Returns
    +0021 % -------
    +0022 % mappedFlux : double
    +0023 %     vector or matrix of flux values, matching model.rxns.
    +0024 % enzUsageFlux : double
    +0025 %     vector or matrix of flux values from enzyme usage reactions, as these
    +0026 %     are absent from mappedFlux.
    +0027 % usageEnz : cell
    +0028 %     cell array with protein IDs, matching enzUsageFlux.
    +0029 %
    +0030 % Examples
    +0031 % --------
    +0032 %     [mappedFlux, enzUsageFlux, usageEnz] = mapRxnsToConv(ecModel, model, fluxVect);
    +0033 %
    +0034 % See also
    +0035 % --------
    +0036 % ecFVA
    +0037 
    +0038 if isempty(fluxVect)
    +0039     error('No or empty flux vector provided')
    +0040 end
    +0041 
    +0042 fluxes = fluxVect;
    +0043 rxnIDs = ecModel.rxns;
    +0044 
    +0045 % Invert flux of _REV reactions
    +0046 % The suffixes are added in the order _REV, _EXP_n, so strip _EXP_n first and
    +0047 % then _REV, each only at the end of the id (an id like R_REVX is left intact).
    +0048 rxnIDs = regexprep(rxnIDs,'_EXP_\d+$','');
    +0049 revRxns = endsWith(rxnIDs,'_REV');
    +0050 fluxes(revRxns,:) = -fluxes(revRxns,:);
    +0051 rxnIDs(revRxns) = regexprep(rxnIDs(revRxns),'_REV$','');
    +0052 
    +0053 % Map and sum fluxes to converted reaction IDs
    +0054 [rxnIDmap, convRxnID] = findgroups(rxnIDs);
    +0055 newVect = splitapply(@(x){sum(x,1)}, fluxes, rxnIDmap);
    +0056 newVect = cell2mat(newVect);
    +0057 
    +0058 % Place in same order as in original model
    +0059 [mapCheck,origIdx] = ismember(model.rxns,convRxnID);
    +0060 if ~all(mapCheck)
    +0061     error('Not all reactions from model.rxns can be found in the ecModel. Are you sure that ecModel is derived from model?')
    +0062 end
    +0063 mappedFlux=newVect(origIdx,:);
    +0064 
    +0065 % Separately report enzyme usages
    +0066 usageEnz = startsWith(ecModel.rxns,{'usage_prot_','prot_pool_exchange'});
    +0067 enzUsageFlux = fluxVect(usageEnz,:);
    +0068 usageEnz = regexprep(ecModel.rxns(usageEnz),'usage_prot_','');
    +0069 usageEnz = regexprep(usageEnz,'prot_pool_exchange','pool');
    +0070 end
    +
    Generated by m2html © 2005
    + + \ No newline at end of file diff --git a/doc/src/change_model/setKcatForReactions.html b/doc/src/change_model/setKcatForReactions.html new file mode 100644 index 00000000..365fca0b --- /dev/null +++ b/doc/src/change_model/setKcatForReactions.html @@ -0,0 +1,144 @@ + + + + Description of setKcatForReactions + + + + + + + + + +
    Home > src > change_model > setKcatForReactions.m
    + + + +

    setKcatForReactions +

    + +

    PURPOSE ^

    +
    setKcatForReactions Change the kcat value for selected reactions.
    + +

    SYNOPSIS ^

    +
    function ecModel = setKcatForReactions(ecModel,rxnIds,kcat)
    + +

    DESCRIPTION ^

    +
     setKcatForReactions  Change the kcat value for selected reactions.
    +
    + Changes the kcat value in ecModel.ec.kcat for selected reactions.
    + applyKcatConstraints needs to be run afterwards to transfer the kcat
    + values into the S-matrix.
    +
    + Parameters
    + ----------
    + ecModel : struct
    +     an ecModel in GECKO 3 format (with ecModel.ec structure).
    + rxnIds : char or cell
    +     reaction identifier matching ecModel.ec.rxns. If the _EXP_ suffix is
    +     not included, and there are multiple expanded (isozymic) reactions,
    +     then all of those will have their kcat changed. If rxnIds includes a
    +     _EXP_ suffix, then only that specific reaction will have its kcat
    +     changed. If multiple rxnIds are provided as a cell array, then the
    +     above applies to each rxnIds individually.
    + kcat : double
    +     the new kcat value.
    +
    + Returns
    + -------
    + ecModel : struct
    +     ecModel where selected kcat values in ecModel.ec.kcat are changed, but
    +     not yet applied to the S-matrix (will require to run
    +     applyKcatConstraints). ecModel.ec.source for the changed reactions
    +     will read 'setKcatForReactions'.
    +
    + Examples
    + --------
    +     ecModel = setKcatForReactions(ecModel, rxnIds, kcat);
    +
    + See also
    + --------
    + applyKcatConstraints, getKcatAcrossIsozymes
    + + +

    CROSS-REFERENCE INFORMATION ^

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

    SOURCE CODE ^

    +
    0001 function ecModel = setKcatForReactions(ecModel,rxnIds,kcat)
    +0002 % setKcatForReactions  Change the kcat value for selected reactions.
    +0003 %
    +0004 % Changes the kcat value in ecModel.ec.kcat for selected reactions.
    +0005 % applyKcatConstraints needs to be run afterwards to transfer the kcat
    +0006 % values into the S-matrix.
    +0007 %
    +0008 % Parameters
    +0009 % ----------
    +0010 % ecModel : struct
    +0011 %     an ecModel in GECKO 3 format (with ecModel.ec structure).
    +0012 % rxnIds : char or cell
    +0013 %     reaction identifier matching ecModel.ec.rxns. If the _EXP_ suffix is
    +0014 %     not included, and there are multiple expanded (isozymic) reactions,
    +0015 %     then all of those will have their kcat changed. If rxnIds includes a
    +0016 %     _EXP_ suffix, then only that specific reaction will have its kcat
    +0017 %     changed. If multiple rxnIds are provided as a cell array, then the
    +0018 %     above applies to each rxnIds individually.
    +0019 % kcat : double
    +0020 %     the new kcat value.
    +0021 %
    +0022 % Returns
    +0023 % -------
    +0024 % ecModel : struct
    +0025 %     ecModel where selected kcat values in ecModel.ec.kcat are changed, but
    +0026 %     not yet applied to the S-matrix (will require to run
    +0027 %     applyKcatConstraints). ecModel.ec.source for the changed reactions
    +0028 %     will read 'setKcatForReactions'.
    +0029 %
    +0030 % Examples
    +0031 % --------
    +0032 %     ecModel = setKcatForReactions(ecModel, rxnIds, kcat);
    +0033 %
    +0034 % See also
    +0035 % --------
    +0036 % applyKcatConstraints, getKcatAcrossIsozymes
    +0037 rxnIds = convertCharArray(rxnIds);
    +0038 
    +0039 hasExp       = ~cellfun(@isempty,regexp(rxnIds,'_EXP_\d+$'));
    +0040 nonExpRxns   = regexprep(ecModel.ec.rxns,'_EXP_\d+$','');
    +0041 rxnsToChange = [];
    +0042 for i=1:numel(hasExp)
    +0043     if hasExp(i) == 1
    +0044         rxnsToChange = [rxnsToChange; find(strcmpi(ecModel.ec.rxns,rxnIds{i}))];
    +0045     else
    +0046         nonExpRxn    = regexprep(rxnIds(i),'_EXP_\d+$','');
    +0047         rxnsToChange = [rxnsToChange; find(strcmpi(nonExpRxns,nonExpRxn))];
    +0048     end
    +0049 end
    +0050 if isscalar(rxnsToChange)
    +0051     if length(kcat) ~= 1
    +0052         error('Found one reaction whose kcat should change, you should provide one kcat value only.')
    +0053     end
    +0054 else
    +0055     if isscalar(kcat)
    +0056         % Is fine, all reactions get the same kcat
    +0057     elseif length(kcat) ~= length(rxnsToChange)
    +0058         error('Found %d reactions whose kcat should change, the new kcat should be either a single value, or a vector of length %d.', length(rxnsToChange), length(rxnsToChange))
    +0059     end
    +0060 end
    +0061 ecModel.ec.kcat(rxnsToChange)   = kcat;
    +0062 ecModel.ec.source(rxnsToChange) = {'setKcatForReactions'};
    +0063 end
    +
    Generated by m2html © 2005
    + + \ No newline at end of file diff --git a/doc/src/change_model/setProtPoolSize.html b/doc/src/change_model/setProtPoolSize.html new file mode 100644 index 00000000..6cc7a855 --- /dev/null +++ b/doc/src/change_model/setProtPoolSize.html @@ -0,0 +1,154 @@ + + + + Description of setProtPoolSize + + + + + + + + + +
    Home > src > change_model > setProtPoolSize.m
    + + + +

    setProtPoolSize +

    + +

    PURPOSE ^

    +
    setProtPoolSize Set the limit of the total protein usage in the model.
    + +

    SYNOPSIS ^

    +
    function model = setProtPoolSize(model, varargin)
    + +

    DESCRIPTION ^

    +
     setProtPoolSize  Set the limit of the total protein usage in the model.
    +
    + Parameters
    + ----------
    + model : struct
    +     an ecModel in GECKO 3 format (with ecModel.ec structure).
    +
    + Name-Value Arguments
    + --------------------
    + Ptot : double
    +     total cellular protein content in g/gDCW. If not specified, the value
    +     will be read from the model adapter. If not specified in model
    +     adapter, 0.5 g/gDCW is assumed.
    + f : double
    +     estimated fraction of enzymes in the model. If not specified, the
    +     value will be read from the model adapter. If not specified in model
    +     adapter, 0.5 is assumed.
    + sigma : double
    +     estimated saturation factor. If not specified, the value will be read
    +     from the model adapter. If not specified in model adapter, 0.5 is
    +     assumed.
    + modelAdapter : ModelAdapter
    +     a loaded model adapter (default: the current default model adapter).
    +
    + Returns
    + -------
    + model : struct
    +     ecModel with protein pool constraint set.
    +
    + Examples
    + --------
    +     % optional arguments may be given positionally or as name-value pairs:
    +     model = setProtPoolSize(model, Ptot, f, sigma, modelAdapter);
    +     model = setProtPoolSize(model, 'Ptot', Ptot);
    +
    + See also
    + --------
    + makeEcModel
    + + +

    CROSS-REFERENCE INFORMATION ^

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

    SOURCE CODE ^

    +
    0001 function model = setProtPoolSize(model, varargin)
    +0002 % setProtPoolSize  Set the limit of the total protein usage in the model.
    +0003 %
    +0004 % Parameters
    +0005 % ----------
    +0006 % model : struct
    +0007 %     an ecModel in GECKO 3 format (with ecModel.ec structure).
    +0008 %
    +0009 % Name-Value Arguments
    +0010 % --------------------
    +0011 % Ptot : double
    +0012 %     total cellular protein content in g/gDCW. If not specified, the value
    +0013 %     will be read from the model adapter. If not specified in model
    +0014 %     adapter, 0.5 g/gDCW is assumed.
    +0015 % f : double
    +0016 %     estimated fraction of enzymes in the model. If not specified, the
    +0017 %     value will be read from the model adapter. If not specified in model
    +0018 %     adapter, 0.5 is assumed.
    +0019 % sigma : double
    +0020 %     estimated saturation factor. If not specified, the value will be read
    +0021 %     from the model adapter. If not specified in model adapter, 0.5 is
    +0022 %     assumed.
    +0023 % modelAdapter : ModelAdapter
    +0024 %     a loaded model adapter (default: the current default model adapter).
    +0025 %
    +0026 % Returns
    +0027 % -------
    +0028 % model : struct
    +0029 %     ecModel with protein pool constraint set.
    +0030 %
    +0031 % Examples
    +0032 % --------
    +0033 %     % optional arguments may be given positionally or as name-value pairs:
    +0034 %     model = setProtPoolSize(model, Ptot, f, sigma, modelAdapter);
    +0035 %     model = setProtPoolSize(model, 'Ptot', Ptot);
    +0036 %
    +0037 % See also
    +0038 % --------
    +0039 % makeEcModel
    +0040 
    +0041 p = parseGECKOargs(varargin, { ...
    +0042     'Ptot',         []; ...
    +0043     'f',            []; ...
    +0044     'sigma',        []; ...
    +0045     'modelAdapter', []});
    +0046 Ptot         = p.Ptot;
    +0047 f            = p.f;
    +0048 sigma        = p.sigma;
    +0049 modelAdapter = p.modelAdapter;
    +0050 
    +0051 if isempty(modelAdapter)
    +0052     modelAdapter = ModelAdapterManager.getDefault();
    +0053     if isempty(modelAdapter) && (isempty(Ptot) || isempty(f) || isempty(sigma))
    +0054         error('Either send in a modelAdapter or set the default model adapter in the ModelAdapterManager.')
    +0055     end
    +0056 end
    +0057 
    +0058 if isempty(sigma)
    +0059     sigma = modelAdapter.getParameters().sigma;
    +0060 end
    +0061 if isempty(f)
    +0062     f = modelAdapter.getParameters().f;
    +0063 end
    +0064 if isempty(Ptot)
    +0065     Ptot = modelAdapter.getParameters().Ptot;
    +0066 end
    +0067 
    +0068 model.ub(strcmp(model.rxns, 'prot_pool_exchange')) = Ptot*f*sigma*1000;
    +0069 end
    +0070
    +
    Generated by m2html © 2005
    + + \ No newline at end of file diff --git a/doc/src/change_model/upgradeEcModel.html b/doc/src/change_model/upgradeEcModel.html new file mode 100644 index 00000000..7a55cea5 --- /dev/null +++ b/doc/src/change_model/upgradeEcModel.html @@ -0,0 +1,143 @@ + + + + Description of upgradeEcModel + + + + + + + + + +
    Home > src > change_model > upgradeEcModel.m
    + + + +

    upgradeEcModel +

    + +

    PURPOSE ^

    +
    upgradeEcModel Bring an ecModel made with GECKO 3 to the GECKO 4 format.
    + +

    SYNOPSIS ^

    +
    function [model, changed] = upgradeEcModel(model)
    + +

    DESCRIPTION ^

    +
     upgradeEcModel  Bring an ecModel made with GECKO 3 to the GECKO 4 format.
    +
    + GECKO 3 defined the protein usage reactions (usage_prot_<id>, prot_<id>
    + -> prot_pool) and the protein pool exchange (prot_pool_exchange,
    + prot_pool ->) in the reverse direction, used with negative flux. GECKO 4
    + defines them forward (prot_pool -> prot_<id>, -> prot_pool), so that an
    + enzyme's usage is the positive flux of its usage reaction. This turns
    + each reaction that is still reverse: its column of S, its bounds and its
    + objective coefficient change sign. Reactions already forward are left as
    + they are, so calling it again changes nothing. Flux values of the model
    + (fluxes of usage reactions and the pool exchange) change sign with it.
    + The ecModel format (annotation.gecko_format, see saveEcModel) becomes 4
    + when it is missing or lower.
    + geckopy has the same (upgrade_ec_model).
    +
    + Parameters
    + ----------
    + model : struct
    +     an ecModel.
    +
    + Returns
    + -------
    + model : struct
    +     the ecModel in the GECKO 4 format.
    + changed : cell
    +     the reactions that were turned.
    +
    + Examples
    + --------
    +     ecModel = upgradeEcModel(readYAMLmodel('ecYeastGEM_GECKO3.yml'));
    +
    + See also
    + --------
    + upgradeGECKOproject, makeEcModel, setProtPoolSize
    + + +

    CROSS-REFERENCE INFORMATION ^

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

    SOURCE CODE ^

    +
    0001 function [model, changed] = upgradeEcModel(model)
    +0002 % upgradeEcModel  Bring an ecModel made with GECKO 3 to the GECKO 4 format.
    +0003 %
    +0004 % GECKO 3 defined the protein usage reactions (usage_prot_<id>, prot_<id>
    +0005 % -> prot_pool) and the protein pool exchange (prot_pool_exchange,
    +0006 % prot_pool ->) in the reverse direction, used with negative flux. GECKO 4
    +0007 % defines them forward (prot_pool -> prot_<id>, -> prot_pool), so that an
    +0008 % enzyme's usage is the positive flux of its usage reaction. This turns
    +0009 % each reaction that is still reverse: its column of S, its bounds and its
    +0010 % objective coefficient change sign. Reactions already forward are left as
    +0011 % they are, so calling it again changes nothing. Flux values of the model
    +0012 % (fluxes of usage reactions and the pool exchange) change sign with it.
    +0013 % The ecModel format (annotation.gecko_format, see saveEcModel) becomes 4
    +0014 % when it is missing or lower.
    +0015 % geckopy has the same (upgrade_ec_model).
    +0016 %
    +0017 % Parameters
    +0018 % ----------
    +0019 % model : struct
    +0020 %     an ecModel.
    +0021 %
    +0022 % Returns
    +0023 % -------
    +0024 % model : struct
    +0025 %     the ecModel in the GECKO 4 format.
    +0026 % changed : cell
    +0027 %     the reactions that were turned.
    +0028 %
    +0029 % Examples
    +0030 % --------
    +0031 %     ecModel = upgradeEcModel(readYAMLmodel('ecYeastGEM_GECKO3.yml'));
    +0032 %
    +0033 % See also
    +0034 % --------
    +0035 % upgradeGECKOproject, makeEcModel, setProtPoolSize
    +0036 
    +0037 pool = find(strcmp(model.mets, 'prot_pool'));
    +0038 changed = {};
    +0039 if isempty(pool)
    +0040     return
    +0041 end
    +0042 if ~isfield(model, 'annotation') || ~isfield(model.annotation, 'gecko_format') ...
    +0043         || str2double(model.annotation.gecko_format) < 4
    +0044     model.annotation.gecko_format = '4';
    +0045 end
    +0046 usage = find(startsWith(model.rxns, 'usage_prot_'));
    +0047 reverse = usage(full(model.S(pool, usage)) > 0);
    +0048 exchange = find(strcmp(model.rxns, 'prot_pool_exchange'));
    +0049 if ~isempty(exchange) && full(model.S(pool, exchange)) < 0
    +0050     reverse(end+1, 1) = exchange;
    +0051 end
    +0052 if isempty(reverse)
    +0053     return
    +0054 end
    +0055 model.S(:, reverse) = -model.S(:, reverse);
    +0056 lb = model.lb(reverse);
    +0057 model.lb(reverse) = -model.ub(reverse);
    +0058 model.ub(reverse) = -lb;
    +0059 if isfield(model, 'c')
    +0060     model.c(reverse) = -model.c(reverse);
    +0061 end
    +0062 changed = model.rxns(reverse);
    +0063 end
    +
    Generated by m2html © 2005
    + + \ No newline at end of file diff --git a/doc/src/deprecated/addCarbonNum.html b/doc/src/deprecated/addCarbonNum.html new file mode 100644 index 00000000..7abc05d8 --- /dev/null +++ b/doc/src/deprecated/addCarbonNum.html @@ -0,0 +1,68 @@ + + + + Description of addCarbonNum + + + + + + + + + +
    Home > src > deprecated > addCarbonNum.m
    + + + +

    addCarbonNum +

    + +

    PURPOSE ^

    +
    addCarbonNum Deprecated alias for fillCarbonNum.
    + +

    SYNOPSIS ^

    +
    function varargout = addCarbonNum(varargin)
    + +

    DESCRIPTION ^

    +
     addCarbonNum  Deprecated alias for fillCarbonNum.
    +
    + Kept for backward compatibility with pre-GECKO4 code. Will be removed
    + in a future release; switch to fillCarbonNum.
    +
    + See also
    + --------
    + fillCarbonNum
    + + +

    CROSS-REFERENCE INFORMATION ^

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

    SOURCE CODE ^

    +
    0001 function varargout = addCarbonNum(varargin)
    +0002 % addCarbonNum  Deprecated alias for fillCarbonNum.
    +0003 %
    +0004 % Kept for backward compatibility with pre-GECKO4 code. Will be removed
    +0005 % in a future release; switch to fillCarbonNum.
    +0006 %
    +0007 % See also
    +0008 % --------
    +0009 % fillCarbonNum
    +0010 
    +0011 warning('GECKO:deprecatedName', ...
    +0012     'addCarbonNum is deprecated; use fillCarbonNum instead. The old name will be removed in a future release.');
    +0013 [varargout{1:nargout}] = fillCarbonNum(varargin{:});
    +0014 end
    +
    Generated by m2html © 2005
    + + \ No newline at end of file diff --git a/doc/src/deprecated/copyECtoGEM.html b/doc/src/deprecated/copyECtoGEM.html new file mode 100644 index 00000000..40d95119 --- /dev/null +++ b/doc/src/deprecated/copyECtoGEM.html @@ -0,0 +1,68 @@ + + + + Description of copyECtoGEM + + + + + + + + + +
    Home > src > deprecated > copyECtoGEM.m
    + + + +

    copyECtoGEM +

    + +

    PURPOSE ^

    +
    copyECtoGEM Deprecated alias for applyECcodes.
    + +

    SYNOPSIS ^

    +
    function varargout = copyECtoGEM(varargin)
    + +

    DESCRIPTION ^

    +
     copyECtoGEM  Deprecated alias for applyECcodes.
    +
    + Kept for backward compatibility with pre-GECKO4 code. Will be removed
    + in a future release; switch to applyECcodes.
    +
    + See also
    + --------
    + applyECcodes
    + + +

    CROSS-REFERENCE INFORMATION ^

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

    SOURCE CODE ^

    +
    0001 function varargout = copyECtoGEM(varargin)
    +0002 % copyECtoGEM  Deprecated alias for applyECcodes.
    +0003 %
    +0004 % Kept for backward compatibility with pre-GECKO4 code. Will be removed
    +0005 % in a future release; switch to applyECcodes.
    +0006 %
    +0007 % See also
    +0008 % --------
    +0009 % applyECcodes
    +0010 
    +0011 warning('GECKO:deprecatedName', ...
    +0012     'copyECtoGEM is deprecated; use applyECcodes instead. The old name will be removed in a future release.');
    +0013 [varargout{1:nargout}] = applyECcodes(varargin{:});
    +0014 end
    +
    Generated by m2html © 2005
    + + \ No newline at end of file diff --git a/doc/src/deprecated/enzymeUsage.html b/doc/src/deprecated/enzymeUsage.html new file mode 100644 index 00000000..e68be605 --- /dev/null +++ b/doc/src/deprecated/enzymeUsage.html @@ -0,0 +1,68 @@ + + + + Description of enzymeUsage + + + + + + + + + +
    Home > src > deprecated > enzymeUsage.m
    + + + +

    enzymeUsage +

    + +

    PURPOSE ^

    +
    enzymeUsage Deprecated alias for getEnzymeUsage.
    + +

    SYNOPSIS ^

    +
    function varargout = enzymeUsage(varargin)
    + +

    DESCRIPTION ^

    +
     enzymeUsage  Deprecated alias for getEnzymeUsage.
    +
    + Kept for backward compatibility with pre-GECKO4 code. Will be removed
    + in a future release; switch to getEnzymeUsage.
    +
    + See also
    + --------
    + getEnzymeUsage
    + + +

    CROSS-REFERENCE INFORMATION ^

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

    SOURCE CODE ^

    +
    0001 function varargout = enzymeUsage(varargin)
    +0002 % enzymeUsage  Deprecated alias for getEnzymeUsage.
    +0003 %
    +0004 % Kept for backward compatibility with pre-GECKO4 code. Will be removed
    +0005 % in a future release; switch to getEnzymeUsage.
    +0006 %
    +0007 % See also
    +0008 % --------
    +0009 % getEnzymeUsage
    +0010 
    +0011 warning('GECKO:deprecatedName', ...
    +0012     'enzymeUsage is deprecated; use getEnzymeUsage instead. The old name will be removed in a future release.');
    +0013 [varargout{1:nargout}] = getEnzymeUsage(varargin{:});
    +0014 end
    +
    Generated by m2html © 2005
    + + \ No newline at end of file diff --git a/doc/src/deprecated/index.html b/doc/src/deprecated/index.html new file mode 100644 index 00000000..9ecdc7c3 --- /dev/null +++ b/doc/src/deprecated/index.html @@ -0,0 +1,29 @@ + + + + Index for Directory src/deprecated + + + + + + + + + + +
    < Master indexIndex for src/deprecated >
    + +

    Index for src/deprecated

    + +

    Matlab files in this directory:

    + +
     addCarbonNumaddCarbonNum Deprecated alias for fillCarbonNum.
     copyECtoGEMcopyECtoGEM Deprecated alias for applyECcodes.
     enzymeUsageenzymeUsage Deprecated alias for getEnzymeUsage.
     pfbaEnzymespfbaEnzymes Deprecated alias for getPfbaEnzymes.
     selectKcatValueselectKcatValue Deprecated alias for assignKcatValues.
     startGECKOprojectstartGECKOproject Deprecated alias for createGECKOproject.
     updateGECKOdocupdateGECKOdoc Deprecated alias for buildGECKOdoc.
    + + + + +
    Generated by m2html © 2005
    + + \ No newline at end of file diff --git a/doc/src/deprecated/pfbaEnzymes.html b/doc/src/deprecated/pfbaEnzymes.html new file mode 100644 index 00000000..b0ffb15b --- /dev/null +++ b/doc/src/deprecated/pfbaEnzymes.html @@ -0,0 +1,68 @@ + + + + Description of pfbaEnzymes + + + + + + + + + +
    Home > src > deprecated > pfbaEnzymes.m
    + + + +

    pfbaEnzymes +

    + +

    PURPOSE ^

    +
    pfbaEnzymes Deprecated alias for getPfbaEnzymes.
    + +

    SYNOPSIS ^

    +
    function varargout = pfbaEnzymes(varargin)
    + +

    DESCRIPTION ^

    +
     pfbaEnzymes  Deprecated alias for getPfbaEnzymes.
    +
    + Kept for backward compatibility with pre-GECKO4 code. Will be removed
    + in a future release; switch to getPfbaEnzymes.
    +
    + See also
    + --------
    + getPfbaEnzymes
    + + +

    CROSS-REFERENCE INFORMATION ^

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

    SOURCE CODE ^

    +
    0001 function varargout = pfbaEnzymes(varargin)
    +0002 % pfbaEnzymes  Deprecated alias for getPfbaEnzymes.
    +0003 %
    +0004 % Kept for backward compatibility with pre-GECKO4 code. Will be removed
    +0005 % in a future release; switch to getPfbaEnzymes.
    +0006 %
    +0007 % See also
    +0008 % --------
    +0009 % getPfbaEnzymes
    +0010 
    +0011 warning('GECKO:deprecatedName', ...
    +0012     'pfbaEnzymes is deprecated; use getPfbaEnzymes instead. The old name will be removed in a future release.');
    +0013 [varargout{1:nargout}] = getPfbaEnzymes(varargin{:});
    +0014 end
    +
    Generated by m2html © 2005
    + + \ No newline at end of file diff --git a/doc/src/deprecated/selectKcatValue.html b/doc/src/deprecated/selectKcatValue.html new file mode 100644 index 00000000..b7650aad --- /dev/null +++ b/doc/src/deprecated/selectKcatValue.html @@ -0,0 +1,68 @@ + + + + Description of selectKcatValue + + + + + + + + + +
    Home > src > deprecated > selectKcatValue.m
    + + + +

    selectKcatValue +

    + +

    PURPOSE ^

    +
    selectKcatValue Deprecated alias for assignKcatValues.
    + +

    SYNOPSIS ^

    +
    function varargout = selectKcatValue(varargin)
    + +

    DESCRIPTION ^

    +
     selectKcatValue  Deprecated alias for assignKcatValues.
    +
    + Kept for backward compatibility with pre-GECKO4 code. Will be removed
    + in a future release; switch to assignKcatValues.
    +
    + See also
    + --------
    + assignKcatValues
    + + +

    CROSS-REFERENCE INFORMATION ^

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

    SOURCE CODE ^

    +
    0001 function varargout = selectKcatValue(varargin)
    +0002 % selectKcatValue  Deprecated alias for assignKcatValues.
    +0003 %
    +0004 % Kept for backward compatibility with pre-GECKO4 code. Will be removed
    +0005 % in a future release; switch to assignKcatValues.
    +0006 %
    +0007 % See also
    +0008 % --------
    +0009 % assignKcatValues
    +0010 
    +0011 warning('GECKO:deprecatedName', ...
    +0012     'selectKcatValue is deprecated; use assignKcatValues instead. The old name will be removed in a future release.');
    +0013 [varargout{1:nargout}] = assignKcatValues(varargin{:});
    +0014 end
    +
    Generated by m2html © 2005
    + + \ No newline at end of file diff --git a/doc/src/deprecated/startGECKOproject.html b/doc/src/deprecated/startGECKOproject.html new file mode 100644 index 00000000..53614657 --- /dev/null +++ b/doc/src/deprecated/startGECKOproject.html @@ -0,0 +1,68 @@ + + + + Description of startGECKOproject + + + + + + + + + +
    Home > src > deprecated > startGECKOproject.m
    + + + +

    startGECKOproject +

    + +

    PURPOSE ^

    +
    startGECKOproject Deprecated alias for createGECKOproject.
    + +

    SYNOPSIS ^

    +
    function varargout = startGECKOproject(varargin)
    + +

    DESCRIPTION ^

    +
     startGECKOproject  Deprecated alias for createGECKOproject.
    +
    + Kept for backward compatibility with pre-GECKO4 code. Will be removed
    + in a future release; switch to createGECKOproject.
    +
    + See also
    + --------
    + createGECKOproject
    + + +

    CROSS-REFERENCE INFORMATION ^

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

    SOURCE CODE ^

    +
    0001 function varargout = startGECKOproject(varargin)
    +0002 % startGECKOproject  Deprecated alias for createGECKOproject.
    +0003 %
    +0004 % Kept for backward compatibility with pre-GECKO4 code. Will be removed
    +0005 % in a future release; switch to createGECKOproject.
    +0006 %
    +0007 % See also
    +0008 % --------
    +0009 % createGECKOproject
    +0010 
    +0011 warning('GECKO:deprecatedName', ...
    +0012     'startGECKOproject is deprecated; use createGECKOproject instead. The old name will be removed in a future release.');
    +0013 [varargout{1:nargout}] = createGECKOproject(varargin{:});
    +0014 end
    +
    Generated by m2html © 2005
    + + \ No newline at end of file diff --git a/doc/src/deprecated/updateGECKOdoc.html b/doc/src/deprecated/updateGECKOdoc.html new file mode 100644 index 00000000..b6a6aad3 --- /dev/null +++ b/doc/src/deprecated/updateGECKOdoc.html @@ -0,0 +1,68 @@ + + + + Description of updateGECKOdoc + + + + + + + + + +
    Home > src > deprecated > updateGECKOdoc.m
    + + + +

    updateGECKOdoc +

    + +

    PURPOSE ^

    +
    updateGECKOdoc Deprecated alias for buildGECKOdoc.
    + +

    SYNOPSIS ^

    +
    function varargout = updateGECKOdoc(varargin)
    + +

    DESCRIPTION ^

    +
     updateGECKOdoc  Deprecated alias for buildGECKOdoc.
    +
    + Kept for backward compatibility with pre-GECKO4 code. Will be removed
    + in a future release; switch to buildGECKOdoc.
    +
    + See also
    + --------
    + buildGECKOdoc
    + + +

    CROSS-REFERENCE INFORMATION ^

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

    SOURCE CODE ^

    +
    0001 function varargout = updateGECKOdoc(varargin)
    +0002 % updateGECKOdoc  Deprecated alias for buildGECKOdoc.
    +0003 %
    +0004 % Kept for backward compatibility with pre-GECKO4 code. Will be removed
    +0005 % in a future release; switch to buildGECKOdoc.
    +0006 %
    +0007 % See also
    +0008 % --------
    +0009 % buildGECKOdoc
    +0010 
    +0011 warning('GECKO:deprecatedName', ...
    +0012     'updateGECKOdoc is deprecated; use buildGECKOdoc instead. The old name will be removed in a future release.');
    +0013 [varargout{1:nargout}] = buildGECKOdoc(varargin{:});
    +0014 end
    +
    Generated by m2html © 2005
    + + \ No newline at end of file diff --git a/doc/src/download_databases/downloadKEGG.html b/doc/src/download_databases/downloadKEGG.html new file mode 100644 index 00000000..781f34eb --- /dev/null +++ b/doc/src/download_databases/downloadKEGG.html @@ -0,0 +1,222 @@ + + + + Description of downloadKEGG + + + + + + + + + +
    Home > src > download_databases > downloadKEGG.m
    + + + +

    downloadKEGG +

    + +

    PURPOSE ^

    +
    downloadKEGG Download a KEGG organism's gene data and write a CSV.
    + +

    SYNOPSIS ^

    +
    function downloadKEGG(keggID, filePath, keggGeneID)
    + +

    DESCRIPTION ^

    +
     downloadKEGG  Download a KEGG organism's gene data and write a CSV.
    +
    + Downloads gene information for every gene of a KEGG organism code, and
    + writes the result to a CSV file. Used by loadDatabases when its
    + expected kegg.tsv is missing; can also be called directly to refresh
    + one organism's KEGG snapshot without re-running loadDatabases for
    + everything else.
    +
    + Parameters
    + ----------
    + keggID : char
    +     KEGG organism code, e.g. 'sce' for Saccharomyces cerevisiae.
    + filePath : char
    +     destination CSV path (overwritten if it exists).
    + keggGeneID : char
    +     which KEGG gene identifier field becomes the output's gene-name
    +     column. 'kegg' (or empty, the default) uses the bare KEGG gene id;
    +     any other value is looked up as a cross-reference identifier on
    +     each KEGG entry (e.g. 'UniProt').
    +
    + Examples
    + --------
    +     downloadKEGG('sce', 'kegg.tsv', 'UniProt');
    +
    + See also
    + --------
    + loadDatabases, downloadUniProt
    + + +

    CROSS-REFERENCE INFORMATION ^

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

    SOURCE CODE ^

    +
    0001 function downloadKEGG(keggID, filePath, keggGeneID)
    +0002 % downloadKEGG  Download a KEGG organism's gene data and write a CSV.
    +0003 %
    +0004 % Downloads gene information for every gene of a KEGG organism code, and
    +0005 % writes the result to a CSV file. Used by loadDatabases when its
    +0006 % expected kegg.tsv is missing; can also be called directly to refresh
    +0007 % one organism's KEGG snapshot without re-running loadDatabases for
    +0008 % everything else.
    +0009 %
    +0010 % Parameters
    +0011 % ----------
    +0012 % keggID : char
    +0013 %     KEGG organism code, e.g. 'sce' for Saccharomyces cerevisiae.
    +0014 % filePath : char
    +0015 %     destination CSV path (overwritten if it exists).
    +0016 % keggGeneID : char
    +0017 %     which KEGG gene identifier field becomes the output's gene-name
    +0018 %     column. 'kegg' (or empty, the default) uses the bare KEGG gene id;
    +0019 %     any other value is looked up as a cross-reference identifier on
    +0020 %     each KEGG entry (e.g. 'UniProt').
    +0021 %
    +0022 % Examples
    +0023 % --------
    +0024 %     downloadKEGG('sce', 'kegg.tsv', 'UniProt');
    +0025 %
    +0026 % See also
    +0027 % --------
    +0028 % loadDatabases, downloadUniProt
    +0029 
    +0030 if nargin < 3 || isempty(keggGeneID)
    +0031     keggGeneID = 'kegg';
    +0032 end
    +0033 
    +0034 %% Download gene information
    +0035 webOptions = weboptions('Timeout',30);
    +0036 try
    +0037     gene_list = webread(['http://rest.kegg.jp/list/' keggID],webOptions);
    +0038 catch ME
    +0039     switch ME.identifier
    +0040         case 'MATLAB:webservices:HTTP400StatusCodeError'
    +0041             error(['Unable to download data form KEGG with a potentially invalid ID: ' keggID ])
    +0042         otherwise
    +0043             rethrow(ME)
    +0044     end
    +0045 end
    +0046 gene_list = regexpi(gene_list, '[^\n]+','match')';
    +0047 gene_id   = regexpi(gene_list,['(?<=' keggID ':)\S+'],'match');
    +0048 
    +0049 % Retrieve information for every gene in the list, 10 genes per query
    +0050 genesPerQuery = 10;
    +0051 queries = ceil(numel(gene_id)/genesPerQuery);
    +0052 keggData  = cell(numel(gene_id),1);
    +0053 PB = progressReport(queries, ['Downloading KEGG data for organism code ' keggID]);
    +0054 for i = 1:queries
    +0055     PB.count;
    +0056     % Download batches of genes
    +0057     firstIdx = i*genesPerQuery-(genesPerQuery-1);
    +0058     lastIdx  = i*genesPerQuery;
    +0059     if lastIdx > numel(gene_id) % Last query has probably less genes
    +0060         lastIdx = numel(gene_id);
    +0061     end
    +0062     url      = ['http://rest.kegg.jp/get/' keggID ':' strjoin([gene_id{firstIdx:lastIdx}],['+' keggID ':'])];
    +0063 
    +0064     % KEGG may be temporarily unresponsive, retry with exponential backoff
    +0065     maxRetries = 5;
    +0066     for attempt = 1:maxRetries
    +0067         try
    +0068             out = webread(url,webOptions);
    +0069             break
    +0070         catch ME
    +0071             % A malformed or non-existing query will not succeed on retry
    +0072             noRetry = ismember(ME.identifier,{'MATLAB:webservices:HTTP400StatusCodeError', ...
    +0073                                               'MATLAB:webservices:HTTP404StatusCodeError'});
    +0074             if noRetry || attempt == maxRetries
    +0075                 error(['Unable to download KEGG data (attempt %d of %d).\n' ...
    +0076                        'URL: %s\n' ...
    +0077                        'Check your internet connection and the status of the KEGG ' ...
    +0078                        'REST API, then try again.\nOriginal error: %s'], ...
    +0079                        attempt, maxRetries, url, ME.message);
    +0080             end
    +0081             pause(min(2^attempt,30)) % Wait 2, 4, 8 and 16 seconds before retrying
    +0082         end
    +0083     end
    +0084     outSplit = strsplit(out,['///' 10]); %10 is new line character
    +0085     if numel(outSplit) < lastIdx-firstIdx+2
    +0086         error('KEGG returns less genes per query') %Reduce genesPerQuery
    +0087     end
    +0088     keggData(firstIdx:lastIdx) = outSplit(1:end-1);
    +0089 end
    +0090 
    +0091 %% Parsing of info to keggDB format
    +0092 % Entries returned by KEGG are separated by '///' followed by an empty line,
    +0093 % leaving a stray newline at the start of each entry after splitting. This
    +0094 % would break the startsWith(...,'ENTRY ') checks below, which detect entries
    +0095 % where the regular expression did not match and returned the entry unchanged
    +0096 keggData  = strtrim(keggData);
    +0097 
    +0098 sequence  = regexprep(keggData,'.*AASEQ\s+\d+\s+([A-Z\s])+?\s+NTSEQ.*','$1');
    +0099 %No AASEQ -> no protein -> not of interest
    +0100 noProt    = startsWith(sequence,'ENTRY ');
    +0101 uni       = regexprep(keggData,'.*UniProt: (\S+?)\s.*','$1');
    +0102 noUni     = startsWith(uni,'ENTRY ');
    +0103 uni(noProt | noUni)       = [];
    +0104 keggData(noProt | noUni) = [];
    +0105 sequence(noProt | noUni)  = [];
    +0106 sequence  = regexprep(sequence,'\s+','');
    +0107 keggGene  = regexprep(keggData,'ENTRY\s+(\S+?)\s.+','$1');
    +0108 
    +0109 switch keggGeneID
    +0110     case {'kegg',''}
    +0111         gene_name = keggGene;
    +0112     otherwise
    +0113         % In case there are special characters:
    +0114         keggGeneIDT = regexptranslate('escape',keggGeneID);
    +0115         gene_name = regexprep(keggData,['.+' keggGeneIDT ': (\S+?)\n.+'],'$1');
    +0116         noID = ~contains(keggData,keggGeneIDT);
    +0117         if all(noID)
    +0118             error(['None of the KEGG entries are annotated with the gene identifier ' keggGeneID])
    +0119         else
    +0120             gene_name(noID)= [];
    +0121             keggData(noID) = [];
    +0122             keggGene(noID) = [];
    +0123             sequence(noID) = [];
    +0124             uni(noID)      = [];
    +0125         end
    +0126 end
    +0127 
    +0128 EC_names  = regexprep(keggData,'.*ORTHOLOGY.*\[EC:(.*?)\].*','$1');
    +0129 EC_names(startsWith(EC_names,'ENTRY ')) = {''};
    +0130 
    +0131 MW = cell(numel(sequence),1);
    +0132 for i=1:numel(sequence)
    +0133     if ~isempty(sequence{i})
    +0134         MW{i} = num2str(round(calculateMW(sequence{i})));
    +0135     end
    +0136 end
    +0137 
    +0138 pathway   = regexprep(keggData,'.*PATHWAY\s+(.*?)(BRITE|MODULE).*','$1');
    +0139 pathway(startsWith(pathway,'ENTRY ')) = {''};
    +0140 pathway   = strrep(pathway,[keggID '01100  Metabolic pathways'],'');
    +0141 pathway   = regexprep(pathway,'\n','');
    +0142 pathway   = regexprep(pathway,'           ','');
    +0143 
    +0144 out = [uni, gene_name, keggGene, EC_names, MW, pathway, sequence];
    +0145 out = cell2table(out);
    +0146 
    +0147 writetable(out, filePath, 'FileType', 'text', 'WriteVariableNames',false);
    +0148 fprintf('Model-specific KEGG database stored at %s\n',filePath);
    +0149 end
    +
    Generated by m2html © 2005
    + + \ No newline at end of file diff --git a/doc/src/download_databases/downloadUniProt.html b/doc/src/download_databases/downloadUniProt.html new file mode 100644 index 00000000..8156ae35 --- /dev/null +++ b/doc/src/download_databases/downloadUniProt.html @@ -0,0 +1,146 @@ + + + + Description of downloadUniProt + + + + + + + + + +
    Home > src > download_databases > downloadUniProt.m
    + + + +

    downloadUniProt +

    + +

    PURPOSE ^

    +
    downloadUniProt Download UniProt protein data for an organism and write a TSV.
    + +

    SYNOPSIS ^

    +
    function downloadUniProt(uniprotID, filePath, geneIDfield, type, reviewed)
    + +

    DESCRIPTION ^

    +
     downloadUniProt  Download UniProt protein data for an organism and write a TSV.
    +
    + Downloads accession, gene name, EC number, mass and sequence for every
    + protein matching the given organism identifier, and writes the result
    + to a TSV file. Used by loadDatabases when its expected uniprot.tsv is
    + missing; can also be called directly to refresh one organism's UniProt
    + snapshot without re-running loadDatabases for everything else.
    +
    + Parameters
    + ----------
    + uniprotID : char
    +     UniProt-side identifier whose meaning depends on type, e.g. an NCBI
    +     taxonomy ID such as 559292 for Saccharomyces cerevisiae S288C.
    + filePath : char
    +     destination TSV path (overwritten if it exists).
    + geneIDfield : char
    +     UniProt field that becomes the second column (the gene matching
    +     key) (optional, default 'gene_oln', Ordered Locus Names, which
    +     works for most prokaryotes and budding yeast).
    + type : char
    +     UniProt query field for uniprotID (optional, default
    +     'taxonomy_id'). 'taxonomy' is accepted as an alias.
    + reviewed : logical
    +     whether to restrict the query to reviewed (Swiss-Prot) entries
    +     (optional, default true).
    +
    + Examples
    + --------
    +     downloadUniProt(559292, 'uniprot.tsv');
    +     downloadUniProt(559292, 'uniprot.tsv', 'gene_oln', 'taxonomy_id', true);
    +
    + See also
    + --------
    + loadDatabases, downloadKEGG
    + + +

    CROSS-REFERENCE INFORMATION ^

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

    SOURCE CODE ^

    +
    0001 function downloadUniProt(uniprotID, filePath, geneIDfield, type, reviewed)
    +0002 % downloadUniProt  Download UniProt protein data for an organism and write a TSV.
    +0003 %
    +0004 % Downloads accession, gene name, EC number, mass and sequence for every
    +0005 % protein matching the given organism identifier, and writes the result
    +0006 % to a TSV file. Used by loadDatabases when its expected uniprot.tsv is
    +0007 % missing; can also be called directly to refresh one organism's UniProt
    +0008 % snapshot without re-running loadDatabases for everything else.
    +0009 %
    +0010 % Parameters
    +0011 % ----------
    +0012 % uniprotID : char
    +0013 %     UniProt-side identifier whose meaning depends on type, e.g. an NCBI
    +0014 %     taxonomy ID such as 559292 for Saccharomyces cerevisiae S288C.
    +0015 % filePath : char
    +0016 %     destination TSV path (overwritten if it exists).
    +0017 % geneIDfield : char
    +0018 %     UniProt field that becomes the second column (the gene matching
    +0019 %     key) (optional, default 'gene_oln', Ordered Locus Names, which
    +0020 %     works for most prokaryotes and budding yeast).
    +0021 % type : char
    +0022 %     UniProt query field for uniprotID (optional, default
    +0023 %     'taxonomy_id'). 'taxonomy' is accepted as an alias.
    +0024 % reviewed : logical
    +0025 %     whether to restrict the query to reviewed (Swiss-Prot) entries
    +0026 %     (optional, default true).
    +0027 %
    +0028 % Examples
    +0029 % --------
    +0030 %     downloadUniProt(559292, 'uniprot.tsv');
    +0031 %     downloadUniProt(559292, 'uniprot.tsv', 'gene_oln', 'taxonomy_id', true);
    +0032 %
    +0033 % See also
    +0034 % --------
    +0035 % loadDatabases, downloadKEGG
    +0036 
    +0037 if nargin < 3 || isempty(geneIDfield)
    +0038     geneIDfield = 'gene_oln';
    +0039 end
    +0040 if nargin < 4 || isempty(type)
    +0041     type = 'taxonomy_id';
    +0042 end
    +0043 if nargin < 5 || isempty(reviewed)
    +0044     reviewed = true;
    +0045 end
    +0046 if strcmp(type,'taxonomy')
    +0047     type = 'taxonomy_id';
    +0048 end
    +0049 if reviewed
    +0050     uniprotRev = 'reviewed:true+AND+';
    +0051 else
    +0052     uniprotRev = '';
    +0053 end
    +0054 
    +0055 disp(['Downloading Uniprot data for ' type ' ' num2str(uniprotID) '. This can take a few minutes.'])
    +0056 url = ['https://rest.uniprot.org/uniprotkb/stream?query=' uniprotRev ...
    +0057        type ':' num2str(uniprotID) '&fields=accession%2C' geneIDfield ...
    +0058     '%2Cec%2Cmass%2Csequence&format=tsv&compressed=false&sort=protein_name%20asc'];
    +0059 try
    +0060     urlwrite(url,filePath,'Timeout',30);
    +0061     fprintf('Model-specific UniProt database stored at %s\n',filePath);
    +0062 catch
    +0063     error(['Download failed, check your internet connection and try again, or manually download: ' url ...
    +0064         ' After downloading, store the file as ' filePath])
    +0065 end
    +0066 end
    +
    Generated by m2html © 2005
    + + \ No newline at end of file diff --git a/doc/src/download_databases/fetchBrendaAsset.html b/doc/src/download_databases/fetchBrendaAsset.html new file mode 100644 index 00000000..82e2ff1b --- /dev/null +++ b/doc/src/download_databases/fetchBrendaAsset.html @@ -0,0 +1,138 @@ + + + + Description of fetchBrendaAsset + + + + + + + + + +
    Home > src > download_databases > fetchBrendaAsset.m
    + + + +

    fetchBrendaAsset +

    + +

    PURPOSE ^

    +
    fetchBrendaAsset Download (once) GECKO's BRENDA files and return their folder.
    + +

    SYNOPSIS ^

    +
    function folder = fetchBrendaAsset(files)
    + +

    DESCRIPTION ^

    +
     fetchBrendaAsset  Download (once) GECKO's BRENDA files and return their folder.
    +
    + GECKO does not ship BRENDA data. The files of the toolbox-assets release
    + brenda-2026.1-1 (BRENDA 2026.1, CC BY 4.0) are downloaded on first use
    + with RAVEN's fetchToolboxAsset, which checks them against the checksums
    + of the toolbox-assets manifest, and are unpacked into
    + databases/brenda-2026.1-1 in the GECKO folder. geckopy reads the same
    + release (fetch_brenda_asset). A project can use its own BRENDA files
    + instead, in data/brenda (see ModelAdapter.getBrendaDBFolder).
    +
    + Parameters
    + ----------
    + files : cell
    +     file names (default: kcat.tsv, sa.tsv, mw.tsv and measurements.tsv);
    +     the release also has sequences.fasta, substrates.tsv and
    +     kcatCombineParams.tsv.
    +
    + Returns
    + -------
    + folder : char
    +     the folder with the files, unpacked.
    +
    + Examples
    + --------
    +     folder = fetchBrendaAsset();
    +     folder = fetchBrendaAsset({'kcatCombineParams.tsv'});
    +
    + See also
    + --------
    + loadBRENDAdata, loadBrendaMeasurements, ModelAdapter
    + + +

    CROSS-REFERENCE INFORMATION ^

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

    SOURCE CODE ^

    +
    0001 function folder = fetchBrendaAsset(files)
    +0002 % fetchBrendaAsset  Download (once) GECKO's BRENDA files and return their folder.
    +0003 %
    +0004 % GECKO does not ship BRENDA data. The files of the toolbox-assets release
    +0005 % brenda-2026.1-1 (BRENDA 2026.1, CC BY 4.0) are downloaded on first use
    +0006 % with RAVEN's fetchToolboxAsset, which checks them against the checksums
    +0007 % of the toolbox-assets manifest, and are unpacked into
    +0008 % databases/brenda-2026.1-1 in the GECKO folder. geckopy reads the same
    +0009 % release (fetch_brenda_asset). A project can use its own BRENDA files
    +0010 % instead, in data/brenda (see ModelAdapter.getBrendaDBFolder).
    +0011 %
    +0012 % Parameters
    +0013 % ----------
    +0014 % files : cell
    +0015 %     file names (default: kcat.tsv, sa.tsv, mw.tsv and measurements.tsv);
    +0016 %     the release also has sequences.fasta, substrates.tsv and
    +0017 %     kcatCombineParams.tsv.
    +0018 %
    +0019 % Returns
    +0020 % -------
    +0021 % folder : char
    +0022 %     the folder with the files, unpacked.
    +0023 %
    +0024 % Examples
    +0025 % --------
    +0026 %     folder = fetchBrendaAsset();
    +0027 %     folder = fetchBrendaAsset({'kcatCombineParams.tsv'});
    +0028 %
    +0029 % See also
    +0030 % --------
    +0031 % loadBRENDAdata, loadBrendaMeasurements, ModelAdapter
    +0032 
    +0033 release = 'brenda-2026.1-1';
    +0034 if nargin < 1 || isempty(files)
    +0035     files = {'kcat.tsv', 'sa.tsv', 'mw.tsv', 'measurements.tsv'};
    +0036 end
    +0037 files = cellstr(files);
    +0038 packed = struct('kcat_tsv', 1, 'sa_tsv', 1, 'mw_tsv', 1, 'measurements_tsv', 1, ...
    +0039     'sequences_fasta', 1, 'substrates_tsv', 1, 'kcatCombineParams_tsv', 0);
    +0040 folder = fullfile(findGECKOroot(), 'databases', release);
    +0041 if exist('fetchToolboxAsset', 'file') ~= 2
    +0042     error('fetchBrendaAsset:raven', ['GECKO downloads its BRENDA files with RAVEN''s ' ...
    +0043         'fetchToolboxAsset, which this RAVEN does not have. Update RAVEN to version 3.'])
    +0044 end
    +0045 for i = 1:numel(files)
    +0046     name = files{i};
    +0047     key = matlab.lang.makeValidName(name);
    +0048     if ~isfield(packed, key)
    +0049         error('fetchBrendaAsset:file', '%s is not a file of %s.', name, release)
    +0050     end
    +0051     target = fullfile(folder, name);
    +0052     if isfile(target)
    +0053         continue
    +0054     end
    +0055     if packed.(key)
    +0056         gz = fetchToolboxAsset(folder, release, [name '.gz']);
    +0057         gunzip(gz, folder);
    +0058     else
    +0059         fetchToolboxAsset(folder, release, name);
    +0060     end
    +0061 end
    +0062 end
    +
    Generated by m2html © 2005
    + + \ No newline at end of file diff --git a/doc/src/download_databases/index.html b/doc/src/download_databases/index.html new file mode 100644 index 00000000..59e9b01c --- /dev/null +++ b/doc/src/download_databases/index.html @@ -0,0 +1,29 @@ + + + + Index for Directory src/download_databases + + + + + + + + + + +
    < Master indexIndex for src/download_databases >
    + +

    Index for src/download_databases

    + +

    Matlab files in this directory:

    + +
     downloadKEGGdownloadKEGG Download a KEGG organism's gene data and write a CSV.
     downloadUniProtdownloadUniProt Download UniProt protein data for an organism and write a TSV.
     fetchBrendaAssetfetchBrendaAsset Download (once) GECKO's BRENDA files and return their folder.
     loadBRENDAdata%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
     loadDatabasesloadDatabases Load the organism-specific KEGG and UniProt databases.
     resolveKcatAggregation%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
    + + + + +
    Generated by m2html © 2005
    + + \ No newline at end of file diff --git a/doc/src/download_databases/loadBRENDAdata.html b/doc/src/download_databases/loadBRENDAdata.html new file mode 100644 index 00000000..1b37fea5 --- /dev/null +++ b/doc/src/download_databases/loadBRENDAdata.html @@ -0,0 +1,311 @@ + + + + Description of loadBRENDAdata + + + + + + + + + +
    Home > src > download_databases > loadBRENDAdata.m
    + + + +

    loadBRENDAdata +

    + +

    PURPOSE ^

    +
    %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
    + +

    SYNOPSIS ^

    +
    function [KCATcell, SAcell] = loadBRENDAdata(varargin)
    + +

    DESCRIPTION ^

    +
    %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
    + loadBRENDAdata  Load kcat and specific activity data from BRENDA files.
    +
    + Reads the BRENDA data files (kcat.tsv, sa.tsv and mw.tsv) from the BRENDA
    + database folder defined by the model adapter, and returns the kcat values
    + and specific activities (the latter converted to kcat values using the
    + molecular weights).
    +
    + kcat.tsv and sa.tsv each carry both a max and a median aggregate per
    + (EC, substrate, organism) triple; kcatAggregation selects which of the
    + two is read. Each file starts with a `#`-prefixed release-version line
    + followed by a tab-delimited column header, both skipped on read.
    +
    + Name-Value Arguments
    + --------------------
    + modelAdapter : ModelAdapter
    +     a loaded model adapter (default: the current default model adapter).
    + kcatAggregation : char
    +     which aggregate to read from kcat.tsv and sa.tsv, 'max' or
    +     'median' (default: params.kcatAggregation from the model adapter,
    +     or 'max' if the adapter does not set it). A triple's max is the
    +     highest turnover reported for it; its median is the middle one.
    + filterOutlierKcats : logical
    +     whether to drop a row whose kcat is implausibly low for its EC
    +     (default: true). A row is dropped when its kcat is more than four
    +     orders of magnitude below the median kcat of its EC. The reference
    +     median of an EC is taken over the positive kcat values of the max and
    +     median views of kcat.tsv and of the kcat values derived from sa.tsv
    +     and mw.tsv, before any row is dropped, so it does not depend on
    +     kcatAggregation. Wildcard ECs (containing '-') do not contribute to a
    +     reference. The EC level widens from w.x.y.z to w.x.y, w.x and w while
    +     fewer than five values are available. Set to false to keep every row.
    +
    + Returns
    + -------
    + KCATcell : cell
    +     kcat data extracted from BRENDA.
    + SAcell : cell
    +     specific activity data extracted from BRENDA.
    +
    + Examples
    + --------
    +     % optional arguments may be given positionally or as name-value pairs:
    +     [KCATcell, SAcell] = loadBRENDAdata();
    +     [KCATcell, SAcell] = loadBRENDAdata('modelAdapter', adapter);
    +     [KCATcell, SAcell] = loadBRENDAdata('kcatAggregation', 'median');
    +     [KCATcell, SAcell] = loadBRENDAdata('filterOutlierKcats', false);
    +
    + See also
    + --------
    + loadDatabases, getECfromDatabase
    + + +

    CROSS-REFERENCE INFORMATION ^

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

    SUBFUNCTIONS ^

    + + +

    SOURCE CODE ^

    +
    0001 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
    +0002 function [KCATcell, SAcell] = loadBRENDAdata(varargin)
    +0003 % loadBRENDAdata  Load kcat and specific activity data from BRENDA files.
    +0004 %
    +0005 % Reads the BRENDA data files (kcat.tsv, sa.tsv and mw.tsv) from the BRENDA
    +0006 % database folder defined by the model adapter, and returns the kcat values
    +0007 % and specific activities (the latter converted to kcat values using the
    +0008 % molecular weights).
    +0009 %
    +0010 % kcat.tsv and sa.tsv each carry both a max and a median aggregate per
    +0011 % (EC, substrate, organism) triple; kcatAggregation selects which of the
    +0012 % two is read. Each file starts with a `#`-prefixed release-version line
    +0013 % followed by a tab-delimited column header, both skipped on read.
    +0014 %
    +0015 % Name-Value Arguments
    +0016 % --------------------
    +0017 % modelAdapter : ModelAdapter
    +0018 %     a loaded model adapter (default: the current default model adapter).
    +0019 % kcatAggregation : char
    +0020 %     which aggregate to read from kcat.tsv and sa.tsv, 'max' or
    +0021 %     'median' (default: params.kcatAggregation from the model adapter,
    +0022 %     or 'max' if the adapter does not set it). A triple's max is the
    +0023 %     highest turnover reported for it; its median is the middle one.
    +0024 % filterOutlierKcats : logical
    +0025 %     whether to drop a row whose kcat is implausibly low for its EC
    +0026 %     (default: true). A row is dropped when its kcat is more than four
    +0027 %     orders of magnitude below the median kcat of its EC. The reference
    +0028 %     median of an EC is taken over the positive kcat values of the max and
    +0029 %     median views of kcat.tsv and of the kcat values derived from sa.tsv
    +0030 %     and mw.tsv, before any row is dropped, so it does not depend on
    +0031 %     kcatAggregation. Wildcard ECs (containing '-') do not contribute to a
    +0032 %     reference. The EC level widens from w.x.y.z to w.x.y, w.x and w while
    +0033 %     fewer than five values are available. Set to false to keep every row.
    +0034 %
    +0035 % Returns
    +0036 % -------
    +0037 % KCATcell : cell
    +0038 %     kcat data extracted from BRENDA.
    +0039 % SAcell : cell
    +0040 %     specific activity data extracted from BRENDA.
    +0041 %
    +0042 % Examples
    +0043 % --------
    +0044 %     % optional arguments may be given positionally or as name-value pairs:
    +0045 %     [KCATcell, SAcell] = loadBRENDAdata();
    +0046 %     [KCATcell, SAcell] = loadBRENDAdata('modelAdapter', adapter);
    +0047 %     [KCATcell, SAcell] = loadBRENDAdata('kcatAggregation', 'median');
    +0048 %     [KCATcell, SAcell] = loadBRENDAdata('filterOutlierKcats', false);
    +0049 %
    +0050 % See also
    +0051 % --------
    +0052 % loadDatabases, getECfromDatabase
    +0053 
    +0054 p = parseGECKOargs(varargin, { ...
    +0055     'modelAdapter',    [], @(x) assert(isempty(x) || isa(x,'ModelAdapter'), ...
    +0056                                 'loadBRENDAdata:invalidModelAdapter', ...
    +0057                                 'modelAdapter must be a ModelAdapter.'); ...
    +0058     'kcatAggregation', [], @(x) assert(isempty(x) || any(strcmpi(x, ...
    +0059                                 {'max','median'})), ...
    +0060                                 'loadBRENDAdata:invalidKcatAggregation', ...
    +0061                                 'kcatAggregation must be ''max'' or ''median''.'); ...
    +0062     'filterOutlierKcats', true, @(x) assert((islogical(x) || isnumeric(x)) && ...
    +0063                                 isscalar(x), ...
    +0064                                 'loadBRENDAdata:invalidFilterOutlierKcats', ...
    +0065                                 'filterOutlierKcats must be a logical scalar.')});
    +0066 modelAdapter       = p.modelAdapter;
    +0067 kcatAggregation    = p.kcatAggregation;
    +0068 filterOutlierKcats = logical(p.filterOutlierKcats);
    +0069 
    +0070 if isempty(modelAdapter)
    +0071     modelAdapter = ModelAdapterManager.getDefault();
    +0072     if isempty(modelAdapter)
    +0073         error('Either send in a modelAdapter or set the default model adapter in the ModelAdapterManager.')
    +0074     end
    +0075 end
    +0076 
    +0077 kcatAggregation = resolveKcatAggregation(kcatAggregation, modelAdapter);
    +0078 %Column 4 holds the per-triple maximum and column 5 the median; both are
    +0079 %read, so that the outlier filter can use the max and the median views.
    +0080 valueCol = 4 + strcmpi(kcatAggregation,'median');
    +0081 
    +0082 basePath      = modelAdapter.getBrendaDBFolder();
    +0083 KCAT_file      = fullfile(basePath,'kcat.tsv');
    +0084 SA_file        = fullfile(basePath,'sa.tsv');
    +0085 MW_file        = fullfile(basePath,'mw.tsv');
    +0086 
    +0087 %Extract BRENDA DATA from files information. kcat.tsv/sa.tsv are seven
    +0088 %columns (ec_code, substrate, organism, value_max, value_median, n,
    +0089 %references); the data cells hold ec_code, substrate, organism, the max and
    +0090 %the median. mw.tsv is six columns (no substrate-level aggregation choice):
    +0091 %ec_code, substrate, organism, value, n, references.
    +0092 KCAT          = openDataFile(KCAT_file,1,'%q %q %q %f %f %f %q',[4 5]);
    +0093 scalingFactor = 1/60;    %[umol/min/mg] -> [mmol/s/g]
    +0094 SA            = openDataFile(SA_file,scalingFactor,'%q %q %q %f %f %f %q',[4 5]);
    +0095 scalingFactor = 1/1000;  %[g/mol] -> [g/mmol]
    +0096 MW            = openDataFile(MW_file,scalingFactor,'%q %q %q %f %f %q',4);
    +0097 
    +0098 %build an index on MW{1} to speed things up a bit
    +0099 %first just extract the genus (i.e. the first part of the name)
    +0100 MWECNum = unique(upper(MW{1}));
    +0101 MWECNumIndices = cell(length(MWECNum),1);
    +0102 MWECNumHashMap = containers.Map(MWECNum,1:length(MWECNum));
    +0103 for i = 1:length(MW{1})
    +0104     matchInd = cell2mat(values(MWECNumHashMap, upper(MW{1}(i))));
    +0105     MWECNumIndices{matchInd} = [MWECNumIndices{matchInd};i];
    +0106 end
    +0107 
    +0108 %Match each specific activity to the molecular weight of its EC and
    +0109 %organism. The first match is used.
    +0110 previousEC = []; EC_indexes = [];
    +0111 saRows = zeros(length(SA{1}),1);
    +0112 mwVals = zeros(length(SA{1}),1);
    +0113 nMatched = 0;
    +0114 for i=1:length(SA{1})
    +0115     %Gets the indexes of the EC repetitions in the MW cell for every
    +0116     %new (different) EC
    +0117     if ~strcmpi(SA{1}(i), previousEC)
    +0118         key = upper(SA{1}(i));
    +0119         if isKey(MWECNumHashMap,key) %annoyingly, this seems to be needed
    +0120             matchInd = cell2mat(values(MWECNumHashMap,key));
    +0121             EC_indexes = MWECNumIndices{matchInd};
    +0122         else
    +0123             EC_indexes = [];
    +0124         end
    +0125     end
    +0126     mwEC{1} = MW{3}(EC_indexes); mwEC{2} = MW{4}(EC_indexes);
    +0127     % just looks for the first match because just the maximal value for
    +0128     % each EC# / Orgaism is reported on the file
    +0129     org_index = find(strcmpi(SA{3}(i),mwEC{1}),1);
    +0130     if ~isempty(org_index)
    +0131         nMatched = nMatched + 1;
    +0132         saRows(nMatched) = i;
    +0133         mwVals(nMatched) = mwEC{2}(org_index);
    +0134     end
    +0135     previousEC = SA{1}(i);
    +0136 end
    +0137 saRows = saRows(1:nMatched);
    +0138 mwVals = mwVals(1:nMatched);
    +0139 
    +0140 %Specific activities as kcat values [1/s], for the max and the median
    +0141 saEC     = SA{1}(saRows);
    +0142 saMax    = SA{4}(saRows).*mwVals;
    +0143 saMedian = SA{5}(saRows).*mwVals;
    +0144 
    +0145 if valueCol == 4
    +0146     saSelected = saMax;
    +0147 else
    +0148     saSelected = saMedian;
    +0149 end
    +0150 
    +0151 %Drop kcats that are implausibly low for their EC
    +0152 keepKcat = true(size(KCAT{1}));
    +0153 keepSA   = true(size(saEC));
    +0154 if filterOutlierKcats
    +0155     ecPool  = [KCAT{1}; KCAT{1}; saEC; saEC];
    +0156     valPool = [KCAT{4}; KCAT{5}; saMax; saMedian];
    +0157     keepKcat = ~isOutlier(KCAT{1},KCAT{valueCol},ecPool,valPool);
    +0158     keepSA   = ~isOutlier(saEC,saSelected,ecPool,valPool);
    +0159 end
    +0160 
    +0161 KCATcell = {KCAT{1}(keepKcat), KCAT{2}(keepKcat), KCAT{3}(keepKcat), ...
    +0162             KCAT{valueCol}(keepKcat)};
    +0163 if nMatched > 0
    +0164     SAcell = {saEC(keepSA), SA{3}(saRows(keepSA)), saSelected(keepSA), ...
    +0165               mwVals(keepSA)};
    +0166 else
    +0167     SAcell = {[],[],[],[]};
    +0168 end
    +0169 end
    +0170 
    +0171 function data_cell = openDataFile(fileName,scalingFactor,formatSpec,valueCols)
    +0172 fID          = fopen(fileName);
    +0173 raw          = textscan(fID,formatSpec,'delimiter','\t','HeaderLines',2);
    +0174 fclose(fID);
    +0175 data_cell    = [raw(1:3), cellfun(@(c) raw{c}*scalingFactor, num2cell(valueCols), ...
    +0176                                   'UniformOutput', false)];
    +0177 end
    +0178 
    +0179 function outlier = isOutlier(ecs,vals,ecPool,valPool)
    +0180 %A value is an outlier if it is more than 'decades' orders of magnitude below
    +0181 %the median kcat of its own EC, taken over the pool of values. The EC widens
    +0182 %from the full code to its 3-, 2- and 1-level prefix while fewer than minRef
    +0183 %values are available.
    +0184 decades = 4;
    +0185 minRef  = 5;
    +0186 usePool = valPool > 0 & ~contains(ecPool,'-');
    +0187 ecPool  = ecPool(usePool);
    +0188 logPool = log10(valPool(usePool));
    +0189 refLog  = NaN(size(ecs));
    +0190 if isempty(ecs) || isempty(logPool)
    +0191     outlier = false(size(ecs));
    +0192     return
    +0193 end
    +0194 for level = 4:-1:1
    +0195     poolKey = ecPrefix(ecPool,level);
    +0196     [grp,keys] = findgroups(poolKey);
    +0197     nPerKey    = accumarray(grp,1);
    +0198     medPerKey  = splitapply(@median,logPool,grp);
    +0199     [found,loc] = ismember(ecPrefix(ecs,level),keys);
    +0200     use = isnan(refLog) & found;
    +0201     use(use) = nPerKey(loc(use)) >= minRef;
    +0202     refLog(use) = medPerKey(loc(use));
    +0203 end
    +0204 outlier = vals > 0 & ~isnan(refLog) & log10(vals) < refLog - decades;
    +0205 end
    +0206 
    +0207 function prefix = ecPrefix(ecs,level)
    +0208 %The first 'level' dot-separated parts of each EC code
    +0209 prefix = regexp(ecs,['^[^.]*(?:\.[^.]*){0,' num2str(level-1) '}'],'match','once');
    +0210 prefix(cellfun(@isempty,prefix)) = {''};
    +0211 prefix = reshape(prefix,size(ecs));
    +0212 end
    +
    Generated by m2html © 2005
    + + \ No newline at end of file diff --git a/doc/src/download_databases/loadDatabases.html b/doc/src/download_databases/loadDatabases.html new file mode 100644 index 00000000..b736ff63 --- /dev/null +++ b/doc/src/download_databases/loadDatabases.html @@ -0,0 +1,192 @@ + + + + Description of loadDatabases + + + + + + + + + +
    Home > src > download_databases > loadDatabases.m
    + + + +

    loadDatabases +

    + +

    PURPOSE ^

    +
    loadDatabases Load the organism-specific KEGG and UniProt databases.
    + +

    SYNOPSIS ^

    +
    function databases = loadDatabases(varargin)
    + +

    DESCRIPTION ^

    +
     loadDatabases  Load the organism-specific KEGG and UniProt databases.
    +
    + Loads (and downloads if necessary) the organism-specific KEGG and UniProt
    + databases that are required to extract protein information. The uniprot.ID
    + and kegg.ID are taken from the ModelAdapter.
    +
    + Name-Value Arguments
    + --------------------
    + selectDatabase : char
    +     which databases should be loaded, either 'uniprot', 'kegg' or 'both'
    +     (default 'both').
    + modelAdapter : ModelAdapter
    +     a loaded model adapter (default: the current default model adapter;
    +     send in [] for default).
    +
    + Returns
    + -------
    + databases : struct
    +     contains .uniprot and .kegg structures, dependent on which databases
    +     were selected.
    +
    + Examples
    + --------
    +     % optional arguments may be given positionally or as name-value pairs:
    +     databases = loadDatabases('both', adapter);
    +     databases = loadDatabases('selectDatabase', 'both');
    +
    + See also
    + --------
    + getECfromDatabase, loadBRENDAdata, downloadKEGG, downloadUniProt
    + + +

    CROSS-REFERENCE INFORMATION ^

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

    SOURCE CODE ^

    +
    0001 function databases = loadDatabases(varargin)
    +0002 % loadDatabases  Load the organism-specific KEGG and UniProt databases.
    +0003 %
    +0004 % Loads (and downloads if necessary) the organism-specific KEGG and UniProt
    +0005 % databases that are required to extract protein information. The uniprot.ID
    +0006 % and kegg.ID are taken from the ModelAdapter.
    +0007 %
    +0008 % Name-Value Arguments
    +0009 % --------------------
    +0010 % selectDatabase : char
    +0011 %     which databases should be loaded, either 'uniprot', 'kegg' or 'both'
    +0012 %     (default 'both').
    +0013 % modelAdapter : ModelAdapter
    +0014 %     a loaded model adapter (default: the current default model adapter;
    +0015 %     send in [] for default).
    +0016 %
    +0017 % Returns
    +0018 % -------
    +0019 % databases : struct
    +0020 %     contains .uniprot and .kegg structures, dependent on which databases
    +0021 %     were selected.
    +0022 %
    +0023 % Examples
    +0024 % --------
    +0025 %     % optional arguments may be given positionally or as name-value pairs:
    +0026 %     databases = loadDatabases('both', adapter);
    +0027 %     databases = loadDatabases('selectDatabase', 'both');
    +0028 %
    +0029 % See also
    +0030 % --------
    +0031 % getECfromDatabase, loadBRENDAdata, downloadKEGG, downloadUniProt
    +0032 
    +0033 p = parseGECKOargs(varargin, { ...
    +0034     'selectDatabase', 'both'; ...
    +0035     'modelAdapter',   []});
    +0036 selectDatabase = p.selectDatabase;
    +0037 modelAdapter   = p.modelAdapter;
    +0038 
    +0039 if 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 
    +0046 params      = modelAdapter.getParameters();
    +0047 kegg.ID      = params.kegg.ID;
    +0048 uniprot.ID   = params.uniprot.ID;
    +0049 filePath    = fullfile(params.path,'data');
    +0050 uniprot.geneIDfield = params.uniprot.geneIDfield;
    +0051 uniprot.type = params.uniprot.type;
    +0052 kegg.geneID = params.kegg.geneID;
    +0053 
    +0054 warning('off', 'MATLAB:MKDIR:DirectoryExists');
    +0055 
    +0056 databases.uniprot = [];
    +0057 databases.kegg = [];
    +0058 
    +0059 %% Uniprot
    +0060 if any(strcmp(selectDatabase,{'uniprot','both'}))
    +0061     uniprotPath = fullfile(filePath,'uniprot.tsv');
    +0062     if ~exist(uniprotPath,'file')
    +0063         if isempty(uniprot.ID)
    +0064             printOrange('WARNING: No uniprot.ID is specified, unable to download UniProt DB.\n');
    +0065         end
    +0066         downloadUniProt(uniprot.ID, uniprotPath, uniprot.geneIDfield, uniprot.type, params.uniprot.reviewed);
    +0067     end
    +0068     if exist(uniprotPath,'file')
    +0069         fid         = fopen(uniprotPath,'r');
    +0070         fileContent = textscan(fid,'%q %q %q %q %q','Delimiter','\t','HeaderLines',1);
    +0071         fclose(fid);
    +0072         databases.uniprot.ID      = fileContent{1};
    +0073         databases.uniprot.genes   = fileContent{2};
    +0074         databases.uniprot.eccodes = fileContent{3};
    +0075         databases.uniprot.MW      = str2double(fileContent{4});
    +0076         databases.uniprot.seq     = fileContent{5};
    +0077     else
    +0078         databases.uniprot = [];
    +0079     end
    +0080     if ~isempty(databases.uniprot)
    +0081         [uniqueIDs,uniqueIdx] = unique(databases.uniprot.ID,'stable');
    +0082         if numel(uniqueIDs) < numel(databases.uniprot.ID)
    +0083             duplID = setdiff(1:numel(databases.uniprot.ID),uniqueIdx);
    +0084             error('%s', ravenList(['Duplicate entries are found for the following proteins. '...
    +0085                     'Manually curate the ''uniprot.tsv'' file, or adjust the uniprot parameters '...
    +0086                     'in the model adapter:'],databases.uniprot.ID(duplID)));
    +0087         end
    +0088     end
    +0089 end
    +0090 
    +0091 %% KEGG
    +0092 if any(strcmp(selectDatabase,{'kegg','both'}))
    +0093     keggPath = fullfile(filePath,'kegg.tsv');
    +0094     if ~exist(keggPath,'file')
    +0095         if isempty(kegg.ID)
    +0096             printOrange('WARNING: No kegg.ID is specified, unable to download KEGG DB.\n');
    +0097         else
    +0098             downloadKEGG(kegg.ID,keggPath,kegg.geneID);
    +0099         end
    +0100     end
    +0101     if exist(keggPath,'file')
    +0102         fid         = fopen(keggPath,'r');
    +0103         fileContent = textscan(fid,'%q %q %q %q %q %q %q','Delimiter',',','HeaderLines',0);
    +0104         fclose(fid);
    +0105         databases.kegg.uniprot    = fileContent{1};
    +0106         databases.kegg.genes      = fileContent{2};
    +0107         databases.kegg.keggGene   = fileContent{3};
    +0108         databases.kegg.eccodes    = fileContent{4};
    +0109         databases.kegg.MW         = str2double(fileContent{5});
    +0110         databases.kegg.pathway    = fileContent{6};
    +0111         databases.kegg.seq        = fileContent{7};
    +0112     else
    +0113         databases.kegg = [];
    +0114     end
    +0115 end
    +0116 end
    +
    Generated by m2html © 2005
    + + \ No newline at end of file diff --git a/doc/src/download_databases/resolveKcatAggregation.html b/doc/src/download_databases/resolveKcatAggregation.html new file mode 100644 index 00000000..034c9fd3 --- /dev/null +++ b/doc/src/download_databases/resolveKcatAggregation.html @@ -0,0 +1,112 @@ + + + + Description of resolveKcatAggregation + + + + + + + + + +
    Home > src > download_databases > resolveKcatAggregation.m
    + + + +

    resolveKcatAggregation +

    + +

    PURPOSE ^

    +
    %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
    + +

    SYNOPSIS ^

    +
    function kcatAggregation = resolveKcatAggregation(kcatAggregation, modelAdapter)
    + +

    DESCRIPTION ^

    +
    %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
    + resolveKcatAggregation  Settle which BRENDA aggregate to read.
    +
    + The BRENDA snapshot records both a maximum and a median per
    + (EC, substrate, organism) triple. Which one a run uses can be given per
    + call, or once on the model adapter as params.kcatAggregation; an
    + adapter that sets neither gets 'max', which is what GECKO has always
    + used.
    +
    + Input Arguments
    + ---------------
    + kcatAggregation : char
    +     the per-call choice, or empty to fall back to the adapter.
    + modelAdapter : ModelAdapter
    +     a loaded model adapter.
    +
    + Returns
    + -------
    + kcatAggregation : char
    +     'max' or 'median'.
    +
    + See also
    + --------
    + loadBRENDAdata, fuzzyKcatMatching
    + + +

    CROSS-REFERENCE INFORMATION ^

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

    SOURCE CODE ^

    +
    0001 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
    +0002 function kcatAggregation = resolveKcatAggregation(kcatAggregation, modelAdapter)
    +0003 % resolveKcatAggregation  Settle which BRENDA aggregate to read.
    +0004 %
    +0005 % The BRENDA snapshot records both a maximum and a median per
    +0006 % (EC, substrate, organism) triple. Which one a run uses can be given per
    +0007 % call, or once on the model adapter as params.kcatAggregation; an
    +0008 % adapter that sets neither gets 'max', which is what GECKO has always
    +0009 % used.
    +0010 %
    +0011 % Input Arguments
    +0012 % ---------------
    +0013 % kcatAggregation : char
    +0014 %     the per-call choice, or empty to fall back to the adapter.
    +0015 % modelAdapter : ModelAdapter
    +0016 %     a loaded model adapter.
    +0017 %
    +0018 % Returns
    +0019 % -------
    +0020 % kcatAggregation : char
    +0021 %     'max' or 'median'.
    +0022 %
    +0023 % See also
    +0024 % --------
    +0025 % loadBRENDAdata, fuzzyKcatMatching
    +0026 
    +0027 if isempty(kcatAggregation)
    +0028     params = modelAdapter.getParameters();
    +0029     if isfield(params,'kcatAggregation') && ~isempty(params.kcatAggregation)
    +0030         kcatAggregation = params.kcatAggregation;
    +0031     else
    +0032         kcatAggregation = 'max';
    +0033     end
    +0034 end
    +0035 
    +0036 if ~(ischar(kcatAggregation) || isstring(kcatAggregation)) || ...
    +0037         ~any(strcmpi(kcatAggregation,{'max','median'}))
    +0038     error('resolveKcatAggregation:invalidKcatAggregation', ...
    +0039         'kcatAggregation must be ''max'' or ''median''.')
    +0040 end
    +0041 kcatAggregation = lower(char(kcatAggregation));
    +0042 end
    +
    Generated by m2html © 2005
    + + \ No newline at end of file diff --git a/doc/src/enzyme_usage/getEnzymeBottlenecks.html b/doc/src/enzyme_usage/getEnzymeBottlenecks.html new file mode 100644 index 00000000..845d1271 --- /dev/null +++ b/doc/src/enzyme_usage/getEnzymeBottlenecks.html @@ -0,0 +1,147 @@ + + + + Description of getEnzymeBottlenecks + + + + + + + + + +
    Home > src > enzyme_usage > getEnzymeBottlenecks.m
    + + + +

    getEnzymeBottlenecks +

    + +

    PURPOSE ^

    +
    getEnzymeBottlenecks Top-N enzymes limiting the current objective.
    + +

    SYNOPSIS ^

    +
    function bottlenecks = getEnzymeBottlenecks(model, varargin)
    + +

    DESCRIPTION ^

    +
     getEnzymeBottlenecks  Top-N enzymes limiting the current objective.
    +
    + Solves the model and ranks every enzyme by the absolute shadow price of
    + its prot_<id> mass-balance constraint --- the enzymes whose extra
    + availability would help the objective the most.
    +
    + Parameters
    + ----------
    + model : struct
    +     a full ecModel in GECKO 3 format (with ecModel.ec structure). Not
    +     supported for gecko-light models, which have no per-enzyme
    +     prot_<id> / usage_prot_<id> machinery.
    +
    + Name-Value Arguments
    + --------------------
    + top : double
    +     number of enzymes to return (default 10).
    +
    + Returns
    + -------
    + bottlenecks : table
    +     one row per returned enzyme, sorted by descending absolute shadow
    +     price, with columns uniprot, gene, shadowPrice, flux, capUsage
    +     (abs(flux)/upperBound, NaN if upperBound is 0) and upperBound.
    +
    + Examples
    + --------
    +     bottlenecks = getEnzymeBottlenecks(ecModel);
    +     bottlenecks = getEnzymeBottlenecks(ecModel, 'top', 5);
    + + +

    CROSS-REFERENCE INFORMATION ^

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

    SOURCE CODE ^

    +
    0001 function bottlenecks = getEnzymeBottlenecks(model, varargin)
    +0002 % getEnzymeBottlenecks  Top-N enzymes limiting the current objective.
    +0003 %
    +0004 % Solves the model and ranks every enzyme by the absolute shadow price of
    +0005 % its prot_<id> mass-balance constraint --- the enzymes whose extra
    +0006 % availability would help the objective the most.
    +0007 %
    +0008 % Parameters
    +0009 % ----------
    +0010 % model : struct
    +0011 %     a full ecModel in GECKO 3 format (with ecModel.ec structure). Not
    +0012 %     supported for gecko-light models, which have no per-enzyme
    +0013 %     prot_<id> / usage_prot_<id> machinery.
    +0014 %
    +0015 % Name-Value Arguments
    +0016 % --------------------
    +0017 % top : double
    +0018 %     number of enzymes to return (default 10).
    +0019 %
    +0020 % Returns
    +0021 % -------
    +0022 % bottlenecks : table
    +0023 %     one row per returned enzyme, sorted by descending absolute shadow
    +0024 %     price, with columns uniprot, gene, shadowPrice, flux, capUsage
    +0025 %     (abs(flux)/upperBound, NaN if upperBound is 0) and upperBound.
    +0026 %
    +0027 % Examples
    +0028 % --------
    +0029 %     bottlenecks = getEnzymeBottlenecks(ecModel);
    +0030 %     bottlenecks = getEnzymeBottlenecks(ecModel, 'top', 5);
    +0031 
    +0032 p = parseGECKOargs(varargin, {'top', []});
    +0033 top = p.top;
    +0034 if isempty(top)
    +0035     top = 10;
    +0036 end
    +0037 
    +0038 if isfield(model.ec, 'geckoLight') && model.ec.geckoLight
    +0039     error(['getEnzymeBottlenecks requires a full ecModel, not gecko-light: ' ...
    +0040         'light models have no per-enzyme prot_<id> / usage_prot_<id> machinery.'])
    +0041 end
    +0042 
    +0043 sol = solveLP(model);
    +0044 if sol.stat ~= 1
    +0045     error('getEnzymeBottlenecks: solver status %d; cannot rank bottlenecks.', sol.stat)
    +0046 end
    +0047 
    +0048 uniprot = model.ec.enzymes(:);
    +0049 gene    = model.ec.genes(:);
    +0050 
    +0051 protMets  = strcat('prot_', uniprot);
    +0052 [found, metIdx] = ismember(protMets, model.mets);
    +0053 if ~all(found)
    +0054     error('Cannot find prot_<id> metabolites for all enzymes. This is done by makeEcModel.')
    +0055 end
    +0056 usageRxns = strcat('usage_prot_', uniprot);
    +0057 [found, rxnIdx] = ismember(usageRxns, model.rxns);
    +0058 if ~all(found)
    +0059     error('Usage reactions are not defined for all enzymes. This is done by makeEcModel.')
    +0060 end
    +0061 
    +0062 shadowPrice = sol.sPrice(metIdx);
    +0063 flux        = sol.x(rxnIdx);
    +0064 upperBound  = model.ub(rxnIdx);
    +0065 capUsage    = abs(flux) ./ upperBound;
    +0066 capUsage(upperBound == 0) = NaN;
    +0067 
    +0068 bottlenecks = table(uniprot, gene, shadowPrice, flux, capUsage, upperBound);
    +0069 [~, order] = sort(abs(bottlenecks.shadowPrice), 'descend');
    +0070 bottlenecks = bottlenecks(order, :);
    +0071 bottlenecks = bottlenecks(1:min(top, height(bottlenecks)), :);
    +0072 end
    +
    Generated by m2html © 2005
    + + \ No newline at end of file diff --git a/doc/src/enzyme_usage/getEnzymeUsage.html b/doc/src/enzyme_usage/getEnzymeUsage.html new file mode 100644 index 00000000..1e0af77c --- /dev/null +++ b/doc/src/enzyme_usage/getEnzymeUsage.html @@ -0,0 +1,174 @@ + + + + Description of getEnzymeUsage + + + + + + + + + +
    Home > src > enzyme_usage > getEnzymeUsage.m
    + + + +

    getEnzymeUsage +

    + +

    PURPOSE ^

    +
    getEnzymeUsage Compute enzyme usages from a provided flux distribution.
    + +

    SYNOPSIS ^

    +
    function usageData = getEnzymeUsage(ecModel,fluxes,varargin)
    + +

    DESCRIPTION ^

    +
     getEnzymeUsage  Compute enzyme usages from a provided flux distribution.
    +
    + Gives enzyme usages based on a provided flux distribution, as obtained
    + from a full GECKO model. It can give:
    +
    + 1. absolute usage: the specific enzyme usage in mg/gDCW, which can be
    +    given for enzymes with- and without concentration information;
    + 2. capacity usage: the ratio of available enzyme that is used, calculated
    +    by (absUsage/UB) (note that capacity usage is 0 if an enzyme
    +    concentration was not constrained in the model);
    + 3. UB: the upper bound of each enzyme exchange reaction, which may not be
    +    the same as the enzyme concentration, if it has been flexibilized;
    + 4. protID: the protein identifiers for each enzyme, in the same order as
    +    ecModel.ec.enzymes.
    +
    + Parameters
    + ----------
    + ecModel : struct
    +     an ecModel in GECKO 3 format (with ecModel.ec structure).
    + fluxes : double
    +     vector of fluxes, for instance sol.x.
    +
    + Name-Value Arguments
    + --------------------
    + zero : logical
    +     whether also enzymes with zero absolute usage should be included
    +     (default true).
    +
    + Returns
    + -------
    + usageData : struct
    +     structure with enzyme usage data.
    +
    + Notes
    + -----
    + The usageData structure has the following fields:
    +
    + - capUsage : vector of enzyme capacity usages.
    + - absUsage : vector of absolute enzyme usages.
    + - UB : vector of enzyme exchange reaction upper bounds.
    + - protID : string array of matching protein IDs.
    + - fluxes : vector of fluxes, copy of input fluxes.
    +
    + Examples
    + --------
    +     % optional arguments may be given positionally or as name-value pairs:
    +     usageData = getEnzymeUsage(ecModel,fluxes,zero);
    +     usageData = getEnzymeUsage(ecModel,fluxes,'zero',false);
    +
    + See also
    + --------
    + reportEnzymeUsage
    + + +

    CROSS-REFERENCE INFORMATION ^

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

    SOURCE CODE ^

    +
    0001 function usageData = getEnzymeUsage(ecModel,fluxes,varargin)
    +0002 % getEnzymeUsage  Compute enzyme usages from a provided flux distribution.
    +0003 %
    +0004 % Gives enzyme usages based on a provided flux distribution, as obtained
    +0005 % from a full GECKO model. It can give:
    +0006 %
    +0007 % 1. absolute usage: the specific enzyme usage in mg/gDCW, which can be
    +0008 %    given for enzymes with- and without concentration information;
    +0009 % 2. capacity usage: the ratio of available enzyme that is used, calculated
    +0010 %    by (absUsage/UB) (note that capacity usage is 0 if an enzyme
    +0011 %    concentration was not constrained in the model);
    +0012 % 3. UB: the upper bound of each enzyme exchange reaction, which may not be
    +0013 %    the same as the enzyme concentration, if it has been flexibilized;
    +0014 % 4. protID: the protein identifiers for each enzyme, in the same order as
    +0015 %    ecModel.ec.enzymes.
    +0016 %
    +0017 % Parameters
    +0018 % ----------
    +0019 % ecModel : struct
    +0020 %     an ecModel in GECKO 3 format (with ecModel.ec structure).
    +0021 % fluxes : double
    +0022 %     vector of fluxes, for instance sol.x.
    +0023 %
    +0024 % Name-Value Arguments
    +0025 % --------------------
    +0026 % zero : logical
    +0027 %     whether also enzymes with zero absolute usage should be included
    +0028 %     (default true).
    +0029 %
    +0030 % Returns
    +0031 % -------
    +0032 % usageData : struct
    +0033 %     structure with enzyme usage data.
    +0034 %
    +0035 % Notes
    +0036 % -----
    +0037 % The usageData structure has the following fields:
    +0038 %
    +0039 % - capUsage : vector of enzyme capacity usages.
    +0040 % - absUsage : vector of absolute enzyme usages.
    +0041 % - UB : vector of enzyme exchange reaction upper bounds.
    +0042 % - protID : string array of matching protein IDs.
    +0043 % - fluxes : vector of fluxes, copy of input fluxes.
    +0044 %
    +0045 % Examples
    +0046 % --------
    +0047 %     % optional arguments may be given positionally or as name-value pairs:
    +0048 %     usageData = getEnzymeUsage(ecModel,fluxes,zero);
    +0049 %     usageData = getEnzymeUsage(ecModel,fluxes,'zero',false);
    +0050 %
    +0051 % See also
    +0052 % --------
    +0053 % reportEnzymeUsage
    +0054 
    +0055 p = parseGECKOargs(varargin, { ...
    +0056     'zero', true});
    +0057 zero = p.zero;
    +0058 if ecModel.ec.geckoLight
    +0059     error('This function does not work on GECKO light models.')
    +0060 end
    +0061 usageData.protID      = ecModel.ec.enzymes;
    +0062 [~,rxnIdx] = ismember(strcat('usage_prot_',ecModel.ec.enzymes),ecModel.rxns);
    +0063 
    +0064 usageData.UB          = ecModel.ub(rxnIdx);
    +0065 usageData.absUsage    = abs(fluxes(rxnIdx));
    +0066 usageData.capUsage    = abs(usageData.absUsage./usageData.UB);
    +0067 usageData.fluxes      = fluxes;
    +0068 
    +0069 if ~zero
    +0070     nonzero               = usageData.absUsage>0;
    +0071     usageData.absUsage    = usageData.absUsage(nonzero);
    +0072     usageData.capUsage    = usageData.capUsage(nonzero);
    +0073     usageData.UB          = usageData.UB(nonzero);
    +0074     usageData.protID      = usageData.protID(nonzero);
    +0075 end
    +0076 end
    +
    Generated by m2html © 2005
    + + \ No newline at end of file diff --git a/doc/src/enzyme_usage/index.html b/doc/src/enzyme_usage/index.html new file mode 100644 index 00000000..6a4c8eac --- /dev/null +++ b/doc/src/enzyme_usage/index.html @@ -0,0 +1,29 @@ + + + + Index for Directory src/enzyme_usage + + + + + + + + + + +
    < Master indexIndex for src/enzyme_usage >
    + +

    Index for src/enzyme_usage

    + +

    Matlab files in this directory:

    + +
     getEnzymeBottlenecksgetEnzymeBottlenecks Top-N enzymes limiting the current objective.
     getEnzymeUsagegetEnzymeUsage Compute enzyme usages from a provided flux distribution.
     reportEnzymeUsagereportEnzymeUsage Summarize the results from getEnzymeUsage.
    + + + + +
    Generated by m2html © 2005
    + + \ No newline at end of file diff --git a/doc/src/enzyme_usage/reportEnzymeUsage.html b/doc/src/enzyme_usage/reportEnzymeUsage.html new file mode 100644 index 00000000..ff32b83a --- /dev/null +++ b/doc/src/enzyme_usage/reportEnzymeUsage.html @@ -0,0 +1,285 @@ + + + + Description of reportEnzymeUsage + + + + + + + + + +
    Home > src > enzyme_usage > reportEnzymeUsage.m
    + + + +

    reportEnzymeUsage +

    + +

    PURPOSE ^

    +
    reportEnzymeUsage Summarize the results from getEnzymeUsage.
    + +

    SYNOPSIS ^

    +
    function usageReport = reportEnzymeUsage(ecModel, usageData, varargin)
    + +

    DESCRIPTION ^

    +
     reportEnzymeUsage  Summarize the results from getEnzymeUsage.
    +
    + Ranks the enzymes from getEnzymeUsage into two tables: those with the
    + highest capacity usage, and those with the highest absolute usage.
    +
    + Parameters
    + ----------
    + ecModel : struct
    +     a GECKO3 ecModel.
    + usageData : struct
    +     output from getEnzymeUsage.
    +
    + Name-Value Arguments
    + --------------------
    + highCapUsage : double
    +     minimum fraction of enzyme capacity usage to be listed as high usage
    +     (default 0.9, i.e. at least 90% capacity usage).
    + topAbsUsage : double
    +     how many top enzymes by absolute usage to list (default 10). Use 0
    +     or Inf to list all enzymes instead. Enzymes whose reactions carry no
    +     flux are never listed here, as they do not contribute to the
    +     solution.
    +
    + Returns
    + -------
    + usageReport : struct
    +     highCapUsage : table
    +         enzymes at or above the highCapUsage threshold.
    +     topAbsUsage : table
    +         the topAbsUsage enzymes with the highest absolute usage.
    +     totalUsageFlux : double
    +         total protein pool used, i.e. the upper bound of prot_pool_exchange.
    +
    + Examples
    + --------
    +     % optional arguments may be given positionally or as name-value pairs:
    +     usageReport = reportEnzymeUsage(ecModel, usageData, highCapUsage, topAbsUsage);
    +     usageReport = reportEnzymeUsage(ecModel, usageData, 'topAbsUsage', 20);
    +
    + See also
    + --------
    + getEnzymeUsage
    + + +

    CROSS-REFERENCE INFORMATION ^

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

    SOURCE CODE ^

    +
    0001 function usageReport = reportEnzymeUsage(ecModel, usageData, varargin)
    +0002 % reportEnzymeUsage  Summarize the results from getEnzymeUsage.
    +0003 %
    +0004 % Ranks the enzymes from getEnzymeUsage into two tables: those with the
    +0005 % highest capacity usage, and those with the highest absolute usage.
    +0006 %
    +0007 % Parameters
    +0008 % ----------
    +0009 % ecModel : struct
    +0010 %     a GECKO3 ecModel.
    +0011 % usageData : struct
    +0012 %     output from getEnzymeUsage.
    +0013 %
    +0014 % Name-Value Arguments
    +0015 % --------------------
    +0016 % highCapUsage : double
    +0017 %     minimum fraction of enzyme capacity usage to be listed as high usage
    +0018 %     (default 0.9, i.e. at least 90% capacity usage).
    +0019 % topAbsUsage : double
    +0020 %     how many top enzymes by absolute usage to list (default 10). Use 0
    +0021 %     or Inf to list all enzymes instead. Enzymes whose reactions carry no
    +0022 %     flux are never listed here, as they do not contribute to the
    +0023 %     solution.
    +0024 %
    +0025 % Returns
    +0026 % -------
    +0027 % usageReport : struct
    +0028 %     highCapUsage : table
    +0029 %         enzymes at or above the highCapUsage threshold.
    +0030 %     topAbsUsage : table
    +0031 %         the topAbsUsage enzymes with the highest absolute usage.
    +0032 %     totalUsageFlux : double
    +0033 %         total protein pool used, i.e. the upper bound of prot_pool_exchange.
    +0034 %
    +0035 % Examples
    +0036 % --------
    +0037 %     % optional arguments may be given positionally or as name-value pairs:
    +0038 %     usageReport = reportEnzymeUsage(ecModel, usageData, highCapUsage, topAbsUsage);
    +0039 %     usageReport = reportEnzymeUsage(ecModel, usageData, 'topAbsUsage', 20);
    +0040 %
    +0041 % See also
    +0042 % --------
    +0043 % getEnzymeUsage
    +0044 
    +0045 p = parseGECKOargs(varargin, { ...
    +0046     'highCapUsage', []; ...
    +0047     'topAbsUsage',  []});
    +0048 highCapUsage = p.highCapUsage;
    +0049 topAbsUsage  = p.topAbsUsage;
    +0050 if isempty(highCapUsage); highCapUsage = 0.9; end
    +0051 if isempty(topAbsUsage);  topAbsUsage  = 10;  end
    +0052 % 0 or Inf means "all enzymes", per the docstring above -- and any topAbsUsage at or
    +0053 % above the enzyme count means the same thing in practice, but unlike those two special
    +0054 % values it used to reach the indexing below unclamped: usageData.protID(topUse(1:N))
    +0055 % with N > numel(topUse) is an out-of-bounds index, so any model with fewer than 10
    +0056 % enzymes (ecTestGEM has 5) crashed on the default call.
    +0057 if topAbsUsage == 0 || isinf(topAbsUsage) || topAbsUsage > numel(usageData.protID)
    +0058     topAbsUsage = numel(usageData.protID);
    +0059 end
    +0060 
    +0061 usageReport = {};
    +0062 
    +0063 % Highest capacity usage
    +0064 highUsageProt = find(usageData.capUsage > highCapUsage);
    +0065 highEnzyme    = usageData.protID(highUsageProt);
    +0066 [~,enzIdx]    = ismember(highEnzyme,ecModel.ec.enzymes);
    +0067 geneIDs       = ecModel.ec.genes(enzIdx);
    +0068 
    +0069 highUsage.protID     = {};
    +0070 highUsage.geneID     = {};
    +0071 highUsage.absUsage   = [];
    +0072 highUsage.capUsage   = [];
    +0073 highUsage.kcat       = [];
    +0074 highUsage.source     = {};
    +0075 highUsage.rxnID      = {};
    +0076 highUsage.rxnNames   = {};
    +0077 highUsage.grRules    = {};
    +0078 
    +0079 for i=1:numel(enzIdx)
    +0080     [rxns, kcat, idx, rxnNames, grRules] = getReactionsFromEnzyme(ecModel,ecModel.ec.enzymes(enzIdx(i)));
    +0081     % See if all reactions carried flux
    +0082     [~,rIdx] = ismember(rxns,ecModel.rxns);
    +0083     carriedFlux = usageData.fluxes(rIdx) > 1e-7;
    +0084     if isscalar(find(carriedFlux))
    +0085         highUsage.protID(end+1,1)      = highEnzyme(i);
    +0086         highUsage.geneID(end+1,1)      = geneIDs(i);
    +0087         highUsage.absUsage(end+1,1)    = usageData.absUsage(enzIdx(i));
    +0088         highUsage.capUsage(end+1,1)    = usageData.capUsage(enzIdx(i));
    +0089         highUsage.kcat(end+1,1)        = kcat(carriedFlux);
    +0090         highUsage.source(end+1,1)      = ecModel.ec.source(idx(carriedFlux));
    +0091         highUsage.rxnID(end+1,1)       = rxns(carriedFlux);
    +0092         highUsage.rxnNames(end+1,1)    = rxnNames(carriedFlux);
    +0093         highUsage.grRules(end+1,1)     = grRules(carriedFlux);
    +0094     else
    +0095         % Add one entry for combined usage
    +0096         highUsage.protID(end+1,1)      = highEnzyme(i);
    +0097         highUsage.geneID(end+1,1)      = geneIDs(i);
    +0098         highUsage.absUsage(end+1,1)    = usageData.absUsage(enzIdx(i));
    +0099         highUsage.capUsage(end+1,1)    = usageData.capUsage(enzIdx(i));
    +0100         highUsage.kcat(end+1,1)        = nan;
    +0101         highUsage.source{end+1,1}      = '===';
    +0102         highUsage.rxnID{end+1,1}       = '===';
    +0103         highUsage.rxnNames{end+1,1}    = 'involved in multiple rxns, usage combined, individual rxns below';
    +0104         highUsage.grRules{end+1,1}     = '===';
    +0105         % Recalculate reaction-specific usage
    +0106 
    +0107         rIdx = rIdx(carriedFlux);
    +0108         enzFlux = usageData.fluxes(rIdx);
    +0109         enzMet = strcat('prot_',highEnzyme{i});
    +0110         [~, enzEcIdx] = ismember(enzMet,ecModel.mets);
    +0111         indAbsUse = full(transpose(-ecModel.S(enzEcIdx,rIdx)).*enzFlux);
    +0112         indCapUse = (indAbsUse /sum(indAbsUse)) * usageData.capUsage(enzIdx(i));
    +0113 
    +0114         rxnNumber = length(rIdx);
    +0115         highUsage.protID(end+1:end+rxnNumber,1)      = highEnzyme(i);
    +0116         highUsage.geneID(end+1:end+rxnNumber,1)      = geneIDs(i);
    +0117         highUsage.absUsage(end+1:end+rxnNumber,1)    = indAbsUse;
    +0118         highUsage.capUsage(end+1:end+rxnNumber,1)    = indCapUse;
    +0119         highUsage.kcat(end+1:end+rxnNumber,1)        = kcat(carriedFlux);
    +0120         highUsage.source(end+1:end+rxnNumber,1)      = ecModel.ec.source(idx(carriedFlux));
    +0121         highUsage.rxnID(end+1:end+rxnNumber,1)       = rxns(carriedFlux);
    +0122         highUsage.rxnNames(end+1:end+rxnNumber,1)    = rxnNames(carriedFlux);
    +0123         highUsage.grRules(end+1:end+rxnNumber,1)     = grRules(carriedFlux);
    +0124     end    
    +0125 end
    +0126 
    +0127 usageReport.highCapUsage = struct2table(highUsage);
    +0128 
    +0129 % Highest absolute usage
    +0130 [~,topUse]          = sort(usageData.absUsage,'descend');
    +0131 topEnzyme           = usageData.protID(topUse(1:topAbsUsage));
    +0132 [~,b]       = ismember(topEnzyme,ecModel.ec.enzymes);
    +0133 geneIDs     = ecModel.ec.genes(b);
    +0134 topUsage.protID     = {};
    +0135 topUsage.geneID     = {};
    +0136 topUsage.absUsage   = [];
    +0137 topUsage.percUsage  = [];
    +0138 topUsage.kcat       = [];
    +0139 topUsage.source     = {};
    +0140 topUsage.rxnID      = {};
    +0141 topUsage.rxnNames   = {};
    +0142 topUsage.grRules    = {};
    +0143 
    +0144 protPool = ecModel.ub(strcmp(ecModel.rxns,'prot_pool_exchange'));
    +0145 
    +0146 for i=1:numel(topEnzyme)
    +0147     [rxns, kcat, idx, rxnNames, grRules] = getReactionsFromEnzyme(ecModel,topEnzyme{i});
    +0148     % See if all reactions carried flux
    +0149     [~,rIdx] = ismember(rxns,ecModel.rxns);
    +0150     carriedFlux = usageData.fluxes(rIdx) > 1e-7;
    +0151     if ~any(carriedFlux)
    +0152         % None of this enzyme's reactions carry flux -- skip it rather than
    +0153         % padding the table with a placeholder row for an enzyme that is not
    +0154         % actually active.
    +0155         continue
    +0156     elseif isscalar(find(carriedFlux))
    +0157         topUsage.protID(end+1,1)      = topEnzyme(i);
    +0158         topUsage.geneID(end+1,1)      = geneIDs(i);
    +0159         topUsage.absUsage(end+1,1)    = usageData.absUsage(topUse(i));
    +0160         topUsage.percUsage(end+1,1)   = topUsage.absUsage(end,1)/protPool*100;
    +0161         topUsage.kcat(end+1,1)        = kcat(carriedFlux);
    +0162         topUsage.source(end+1,1)      = ecModel.ec.source(idx(carriedFlux));
    +0163         topUsage.rxnID(end+1,1)       = rxns(carriedFlux);
    +0164         topUsage.rxnNames(end+1,1)    = rxnNames(carriedFlux);
    +0165         topUsage.grRules(end+1,1)     = grRules(carriedFlux);
    +0166     else
    +0167         % Add one entry for combined usage
    +0168         topUsage.protID(end+1,1)      = topEnzyme(i);
    +0169         topUsage.geneID(end+1,1)      = geneIDs(i);
    +0170         topUsage.absUsage(end+1,1)    = usageData.absUsage(topUse(i));
    +0171         topUsage.percUsage(end+1,1)   = topUsage.absUsage(end,1)/protPool*100;
    +0172         topUsage.kcat(end+1,1)        = nan;
    +0173         topUsage.source{end+1,1}      = '===';
    +0174         topUsage.rxnID{end+1,1}       = '===';
    +0175         topUsage.rxnNames{end+1,1}    = 'involved in multiple rxns, usage combined, individual rxns below';
    +0176         topUsage.grRules{end+1,1}     = '===';
    +0177         % Recalculate reaction-specific usage
    +0178         rIdx = rIdx(carriedFlux);
    +0179         enzFlux = usageData.fluxes(rIdx);
    +0180         enzMet = strcat('prot_',topEnzyme{i});
    +0181         [~, enzIdx] = ismember(enzMet,ecModel.mets);
    +0182         indUse = full(transpose(-ecModel.S(enzIdx,rIdx)).*enzFlux);
    +0183         rxnNumber = length(rIdx);
    +0184         topUsage.protID(end+1:end+rxnNumber,1)      = topEnzyme(i);
    +0185         topUsage.geneID(end+1:end+rxnNumber,1)      = geneIDs(i);
    +0186         topUsage.absUsage(end+1:end+rxnNumber,1)    = indUse;
    +0187         topUsage.percUsage(end+1:end+rxnNumber,1)   = topUsage.absUsage(end-(rxnNumber-1):end,1)/protPool*100;
    +0188         topUsage.kcat(end+1:end+rxnNumber,1)        = kcat(carriedFlux);
    +0189         topUsage.source(end+1:end+rxnNumber,1)      = ecModel.ec.source(idx(carriedFlux));
    +0190         topUsage.rxnID(end+1:end+rxnNumber,1)       = rxns(carriedFlux);
    +0191         topUsage.rxnNames(end+1:end+rxnNumber,1)    = rxnNames(carriedFlux);
    +0192         topUsage.grRules(end+1:end+rxnNumber,1)     = grRules(carriedFlux);
    +0193     end
    +0194 end
    +0195 usageReport.topAbsUsage     = struct2table(topUsage);
    +0196 usageReport.totalUsageFlux  = protPool;
    +0197 end
    +
    Generated by m2html © 2005
    + + \ No newline at end of file diff --git a/doc/src/flux_analysis/ecFSEOF.html b/doc/src/flux_analysis/ecFSEOF.html new file mode 100644 index 00000000..2db4959d --- /dev/null +++ b/doc/src/flux_analysis/ecFSEOF.html @@ -0,0 +1,457 @@ + + + + Description of ecFSEOF + + + + + + + + + +
    Home > src > flux_analysis > ecFSEOF.m
    + + + +

    ecFSEOF +

    + +

    PURPOSE ^

    +
    ecFSEOF Run Flux-Scanning with Enforced Objective Function for a target.
    + +

    SYNOPSIS ^

    +
    function fseof = ecFSEOF(model,prodTargetRxn,csRxn,varargin)
    + +

    DESCRIPTION ^

    +
     ecFSEOF  Run Flux-Scanning with Enforced Objective Function for a target.
    +
    + Runs Flux-Scanning with Enforced Objective Function (FSEOF) for a
    + specified production target, to identify reaction and gene targets for
    + metabolic engineering. Reactions are classified as targets with the same
    + rule as RAVEN's FSEOF: the correlation between the absolute flux of a
    + reaction and the enforced production flux.
    +
    + Parameters
    + ----------
    + model : struct
    +     an ecModel in GECKO 3 format (with ecModel.ec structure).
    + prodTargetRxn : char
    +     rxn ID for the production target reaction, an exchange reaction is
    +     recommended.
    + csRxn : char
    +     rxn ID for the main carbon source uptake reaction.
    +
    + Name-Value Arguments
    + --------------------
    + nSteps : double
    +     number of steps for suboptimal objective in FSEOF (default 16).
    + outputFile : logical
    +     boolean option to save results in a file (default false).
    + filePath : char
    +     file path for results output. It will store two files: at the genes
    +     level, ecFSEOF_genes.tsv; and at the reactions level,
    +     ecFSEOF_rxns.tsv (default: the 'output' sub-folder taken from
    +     modelAdapter, e.g. output/ecFSEOF_rxns.tsv).
    + modelAdapter : ModelAdapter
    +     a loaded model adapter (default: the current default model adapter).
    + corrThreshold : double
    +     minimum absolute Pearson correlation between the absolute flux of a
    +     reaction and the enforced production flux for the reaction to be a
    +     target (default 0.9).
    +
    + Returns
    + -------
    + fseof : struct
    +     a structure with all results.
    +
    + Notes
    + -----
    + The fseof structure has the following fields:
    +
    + - alpha : target production used for enforced objective limits (from minimum to maximum production).
    + - v_matrix : fluxes for each target reaction predicted and each alpha.
    + - rxnTargets : a list with all reactions whose absolute flux is correlated with the enforced production, with an absolute correlation of at least corrThreshold. Contains ID, name, slope, gene rule, and equation. The slope is the absolute slope of the regression of the absolute flux on the enforced production flux. The list is ordered by the product of slope and correlation, highest first.
    + - transportTargets : the same for transport reactions.
    + - geneTargets : a list with all genes of the targets. Contains gene, shortName, slope, action, and essentiality.
    +
    + Only reactions with a gene rule are considered, and not those that are
    + assigned to the standard enzyme. The enforced production reaction is
    + included when it has a gene rule, as its flux follows the enforced
    + production by definition. The reactions that draw enzyme usage
    + (usage_prot_*) take part in the classification and are not reported.
    + A reaction is over expressed (OE) when its flux increases with production,
    + knocked out (KO) when it decreases and is at most 1e-8 at the last step,
    + and knocked down (KD) when it decreases otherwise.
    +
    + Examples
    + --------
    +     % optional arguments may be given positionally or as name-value pairs:
    +     fseof = ecFSEOF(model,prodTargetRxn,csRxn,nSteps,outputFile,filePath,modelAdapter,corrThreshold);
    +     fseof = ecFSEOF(model,prodTargetRxn,csRxn,'nSteps',32);
    + + +

    CROSS-REFERENCE INFORMATION ^

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

    SOURCE CODE ^

    +
    0001 function fseof = ecFSEOF(model,prodTargetRxn,csRxn,varargin)
    +0002 % ecFSEOF  Run Flux-Scanning with Enforced Objective Function for a target.
    +0003 %
    +0004 % Runs Flux-Scanning with Enforced Objective Function (FSEOF) for a
    +0005 % specified production target, to identify reaction and gene targets for
    +0006 % metabolic engineering. Reactions are classified as targets with the same
    +0007 % rule as RAVEN's FSEOF: the correlation between the absolute flux of a
    +0008 % reaction and the enforced production flux.
    +0009 %
    +0010 % Parameters
    +0011 % ----------
    +0012 % model : struct
    +0013 %     an ecModel in GECKO 3 format (with ecModel.ec structure).
    +0014 % prodTargetRxn : char
    +0015 %     rxn ID for the production target reaction, an exchange reaction is
    +0016 %     recommended.
    +0017 % csRxn : char
    +0018 %     rxn ID for the main carbon source uptake reaction.
    +0019 %
    +0020 % Name-Value Arguments
    +0021 % --------------------
    +0022 % nSteps : double
    +0023 %     number of steps for suboptimal objective in FSEOF (default 16).
    +0024 % outputFile : logical
    +0025 %     boolean option to save results in a file (default false).
    +0026 % filePath : char
    +0027 %     file path for results output. It will store two files: at the genes
    +0028 %     level, ecFSEOF_genes.tsv; and at the reactions level,
    +0029 %     ecFSEOF_rxns.tsv (default: the 'output' sub-folder taken from
    +0030 %     modelAdapter, e.g. output/ecFSEOF_rxns.tsv).
    +0031 % modelAdapter : ModelAdapter
    +0032 %     a loaded model adapter (default: the current default model adapter).
    +0033 % corrThreshold : double
    +0034 %     minimum absolute Pearson correlation between the absolute flux of a
    +0035 %     reaction and the enforced production flux for the reaction to be a
    +0036 %     target (default 0.9).
    +0037 %
    +0038 % Returns
    +0039 % -------
    +0040 % fseof : struct
    +0041 %     a structure with all results.
    +0042 %
    +0043 % Notes
    +0044 % -----
    +0045 % The fseof structure has the following fields:
    +0046 %
    +0047 % - alpha : target production used for enforced objective limits (from minimum to maximum production).
    +0048 % - v_matrix : fluxes for each target reaction predicted and each alpha.
    +0049 % - rxnTargets : a list with all reactions whose absolute flux is correlated with the enforced production, with an absolute correlation of at least corrThreshold. Contains ID, name, slope, gene rule, and equation. The slope is the absolute slope of the regression of the absolute flux on the enforced production flux. The list is ordered by the product of slope and correlation, highest first.
    +0050 % - transportTargets : the same for transport reactions.
    +0051 % - geneTargets : a list with all genes of the targets. Contains gene, shortName, slope, action, and essentiality.
    +0052 %
    +0053 % Only reactions with a gene rule are considered, and not those that are
    +0054 % assigned to the standard enzyme. The enforced production reaction is
    +0055 % included when it has a gene rule, as its flux follows the enforced
    +0056 % production by definition. The reactions that draw enzyme usage
    +0057 % (usage_prot_*) take part in the classification and are not reported.
    +0058 % A reaction is over expressed (OE) when its flux increases with production,
    +0059 % knocked out (KO) when it decreases and is at most 1e-8 at the last step,
    +0060 % and knocked down (KD) when it decreases otherwise.
    +0061 %
    +0062 % Examples
    +0063 % --------
    +0064 %     % optional arguments may be given positionally or as name-value pairs:
    +0065 %     fseof = ecFSEOF(model,prodTargetRxn,csRxn,nSteps,outputFile,filePath,modelAdapter,corrThreshold);
    +0066 %     fseof = ecFSEOF(model,prodTargetRxn,csRxn,'nSteps',32);
    +0067 
    +0068 p = parseGECKOargs(varargin, { ...
    +0069     'nSteps',       16; ...
    +0070     'outputFile',   false; ...
    +0071     'filePath',     []; ...
    +0072     'modelAdapter', []; ...
    +0073     'corrThreshold',0.9});
    +0074 nSteps       = p.nSteps;
    +0075 outputFile   = p.outputFile;
    +0076 filePath     = p.filePath;
    +0077 modelAdapter  = p.modelAdapter;
    +0078 corrThreshold = p.corrThreshold;
    +0079 
    +0080 if isempty(modelAdapter)
    +0081     modelAdapter = ModelAdapterManager.getDefault();
    +0082     if isempty(modelAdapter)
    +0083         error('Either send in a modelAdapter or set the default model adapter in the ModelAdapterManager.')
    +0084     end
    +0085 end
    +0086 params = modelAdapter.getParameters();
    +0087 
    +0088 if isempty(filePath)
    +0089     filePath = fullfile(params.path,'output');
    +0090 end
    +0091 
    +0092 % Get relevant rxn indexes
    +0093 prodTargetRxnIdx = getIndexes(model, prodTargetRxn,'rxns');
    +0094 csRxnIdx         = getIndexes(model, csRxn,'rxns');
    +0095 bioRxnIdx        = getIndexes(model, params.bioRxn,'rxns');
    +0096 
    +0097 % Standardize grRules and rxnGeneMat in model
    +0098 [grRules,rxnGeneMat] = standardizeGrRules(model,true);
    +0099 model.grRules        = grRules;
    +0100 model.rxnGeneMat     = rxnGeneMat;
    +0101 
    +0102 % Check carbon source uptake rate and LB defined
    +0103 model = setParam(model, 'obj', params.bioRxn, 1);
    +0104 sol   = solveLP(model);
    +0105 if model.lb(csRxnIdx) < sol.x(csRxnIdx)
    +0106     printOrange(['WARNING: Carbon source lower bound was set to ' num2str(model.lb(csRxnIdx)) ...
    +0107         ', but the uptake rate after model optimization is ' num2str(sol.x(csRxnIdx)) '.\n']);
    +0108 end
    +0109 
    +0110 % run FSEOF analysis
    +0111 
    +0112 % Find out the initial target production.
    +0113 iniTarget = sol.x(prodTargetRxnIdx);
    +0114 
    +0115 % Find out the maximum theoretical yield of target reaction.
    +0116 model     = setParam(model,'obj',prodTargetRxn,1);
    +0117 sol       = solveLP(model,1);
    +0118 % Set to 90%% based on https://doi.org/10.1128/AEM.00115-10
    +0119 maxTarget = sol.x(prodTargetRxnIdx) * 0.9;
    +0120 
    +0121 % Define alpha vector for suboptimal enforced objective values between
    +0122 % minimal production and 90%% of the maximum theoretical yield, initialize
    +0123 % fluxes matriz
    +0124 alpha    = iniTarget:((maxTarget-iniTarget)/(nSteps-1)):maxTarget;
    +0125 v_matrix = zeros(length(model.rxns),length(alpha));
    +0126 
    +0127 % Enforce objective flux iteratively
    +0128 PB = progressReport(nSteps, 'Flux Scanning with Enforced Objective Function');
    +0129 for i = 1:nSteps
    +0130     PB.count;
    +0131     % Enforce the objetive flux of product formation
    +0132     model = setParam(model,'eq',prodTargetRxnIdx,alpha(i));
    +0133 
    +0134     % Restore minimum biomass lb to zero and set it as objective
    +0135     model.lb(bioRxnIdx) = 0;
    +0136     model = setParam(model,'obj',params.bioRxn,1);
    +0137     sol   = solveLP(model,1);
    +0138 
    +0139     % Store flux distribution
    +0140     v_matrix(:,i) = sol.x;
    +0141 
    +0142 end
    +0143 PB.done;
    +0144 
    +0145 % Take out rxns with no grRule and standard gene
    +0146 withGR         = ~cellfun(@isempty,model.grRules);
    +0147 stdIdx         = contains(model.grRules,'standard');
    +0148 withGR(stdIdx) = 0;
    +0149 target_rxns    = model.rxns(withGR);
    +0150 v_matrix       = v_matrix(withGR,:);
    +0151 rxnGeneM       = model.rxnGeneMat(withGR,:);
    +0152 
    +0153 % Classify the reactions as in RAVEN's FSEOF. Slope and correlation are taken
    +0154 % on the absolute flux against the enforced production flux, so a reversible
    +0155 % reaction running backwards counts by its magnitude. A reaction is a target
    +0156 % when some absolute flux exceeds 1e-10, the standard deviation of its
    +0157 % absolute flux is above 0 and the absolute Pearson correlation reaches
    +0158 % corrThreshold. It is suggested for over expression (OE) when the slope is
    +0159 % positive, for knock out (KO) when the slope is negative and the absolute
    +0160 % flux at the last step is at most 1e-8, and for knock down (KD) for any
    +0161 % other negative slope.
    +0162 absV        = abs(v_matrix);
    +0163 slope_rxns  = zeros(size(target_rxns));
    +0164 corr_rxns   = zeros(size(target_rxns));
    +0165 target_type = cell(size(target_rxns));
    +0166 targets     = false(size(target_rxns));
    +0167 if numel(alpha) > 1 && std(alpha) > 0
    +0168     for i = 1:length(target_rxns)
    +0169         track = absV(i,:);
    +0170         if any(track > 1e-10) && std(track) > 0
    +0171             fit = polyfit(alpha,track,1);
    +0172             r   = corrcoef(alpha,track);
    +0173             if abs(r(1,2)) >= corrThreshold && fit(1) ~= 0
    +0174                 targets(i)     = true;
    +0175                 slope_rxns(i)  = abs(fit(1));
    +0176                 corr_rxns(i)   = abs(r(1,2));
    +0177                 if fit(1) > 0
    +0178                     target_type(i) = {'OE'};
    +0179                 elseif track(end) <= 1e-8
    +0180                     target_type(i) = {'KO'};
    +0181                 else
    +0182                     target_type(i) = {'KD'};
    +0183                 end
    +0184             end
    +0185         end
    +0186     end
    +0187 end
    +0188 
    +0189 % Only keep those reactions that are classified as a target
    +0190 target_rxns = target_rxns(targets);
    +0191 v_matrix    = v_matrix(targets,:);
    +0192 rxnGeneM    = rxnGeneM(targets,:);
    +0193 slope_rxns  = slope_rxns(targets);
    +0194 corr_rxns   = corr_rxns(targets);
    +0195 target_type = target_type(targets);
    +0196 
    +0197 % Order from highest to lowest score, the product of slope and correlation
    +0198 [~,order]   = sort(slope_rxns .* corr_rxns,'descend');
    +0199 target_rxns = target_rxns(order);
    +0200 v_matrix    = v_matrix(order,:);
    +0201 rxnGeneM    = rxnGeneM(order,:);
    +0202 slope_rxns  = slope_rxns(order);
    +0203 target_type = target_type(order);
    +0204 
    +0205 % Exclude enzyme usage reactions: they are not reported, and they would otherwise
    +0206 % enter the gene slopes and the choice of the action per gene
    +0207 notUsage    = ~startsWith(target_rxns,'usage_prot_');
    +0208 target_rxns = target_rxns(notUsage);
    +0209 v_matrix    = v_matrix(notUsage,:);
    +0210 rxnGeneM    = rxnGeneM(notUsage,:);
    +0211 slope_rxns  = slope_rxns(notUsage);
    +0212 target_type = target_type(notUsage);
    +0213 
    +0214 % Create gene list of those connected to the remaining rxns
    +0215 genes             = model.genes(sum(rxnGeneM,1) > 0);
    +0216 slope_genes       = zeros(size(genes));
    +0217 rxnGeneM          = rxnGeneM(:,sum(rxnGeneM,1) > 0);
    +0218 target_type_genes = cell(size(genes));
    +0219 essentiality      = cell(size(genes));
    +0220 
    +0221 % Validate for gene essentiality
    +0222 PB = progressReport(numel(genes), 'Checking for gene essentiality');
    +0223 for i = 1:numel(genes)
    +0224     PB.count;
    +0225 
    +0226     % Block protein usage to KO al the reactions associated to it.
    +0227     usage_rxn_idx = strcmpi(model.ec.genes, genes{i});
    +0228     usage_rxn = strcat('usage_prot_', model.ec.enzymes(usage_rxn_idx));
    +0229     tempModel = setParam(model, 'eq', usage_rxn, 0);
    +0230     solKO     = solveLP(tempModel);
    +0231     % Check if no feasible solution was found
    +0232     if solKO.stat == -1 || solKO.x(bioRxnIdx) < 1e-8
    +0233         essentiality(i) = {'essential'};
    +0234     end
    +0235 
    +0236     % Since a gene can be involved in multiple reactions, multiple
    +0237     % engineering manipulations can be suggested for the same gene
    +0238     % e.g. (OE and KD). So, reconcilie them, and report only one.
    +0239     
    +0240     % Get reaction index, in targets set, for each gene
    +0241     rxns_for_gene = find(rxnGeneM(:,i) > 0);
    +0242     actions = unique(target_type(rxns_for_gene));
    +0243     if numel(actions) > 1
    +0244         % If any OE is suggested give the highest priority over KD or KO
    +0245         if any(startsWith(actions, 'OE'))
    +0246             target_type_genes(i) = {'OE'};
    +0247             % Otherwise change to KO if not essential
    +0248         elseif ~any(startsWith(actions, 'OE')) && ~isequal(essentiality(i),{'essential'})
    +0249             target_type_genes(i) = {'KO'};
    +0250         else
    +0251             target_type_genes(i) = {'KD'};
    +0252         end
    +0253     else
    +0254         target_type_genes(i) = actions;
    +0255     end
    +0256     % Extract all the slope (from rxns across alphas) conected to
    +0257     % each remaining gene
    +0258     slope_set      = slope_rxns(rxns_for_gene);
    +0259     slope_genes(i) = mean(slope_set);
    +0260 
    +0261 end
    +0262 PB.done;
    +0263 
    +0264 % Order genes from highest to lowest slope:
    +0265 [~,order]         = sort(slope_genes,'descend');
    +0266 genes             = genes(order,:);
    +0267 slope_genes       = slope_genes(order,:);
    +0268 target_type_genes = target_type_genes(order,:);
    +0269 essentiality      = essentiality(order,:);
    +0270 
    +0271 % Create output:
    +0272 
    +0273 % Report values used to enforce objective target production
    +0274 fseof.alpha = alpha;
    +0275 
    +0276 rxnIdx = getIndexes(model,target_rxns,'rxns');
    +0277 
    +0278 % Report the fluxes at each alpha
    +0279 fseof.v_matrix = array2table(v_matrix, ...
    +0280     'VariableNames', string(alpha), 'RowNames', model.rxns(rxnIdx));
    +0281 
    +0282 % Report reaction targets
    +0283 fseof.rxnTargets(:,1) = model.rxns(rxnIdx);
    +0284 fseof.rxnTargets(:,2) = model.rxnNames(rxnIdx);
    +0285 fseof.rxnTargets(:,3) = num2cell(slope_rxns);
    +0286 fseof.rxnTargets(:,4) = model.grRules(rxnIdx);
    +0287 if isempty(rxnIdx)
    +0288     fseof.rxnTargets(:,5) = cell(0,1); % constructEquations would give all reactions
    +0289 else
    +0290     fseof.rxnTargets(:,5) = constructEquations(model,rxnIdx);
    +0291 end
    +0292 
    +0293 % Identify transport reactions; defined as reactions involving (at least)
    +0294 % one metabolite name in more than one compartment.
    +0295 transportRxns = false(numel(rxnIdx),1);
    +0296 for i = 1:numel(rxnIdx)
    +0297     % Get the involved metabolites in each reaction
    +0298     mets = model.metNames(model.S(:,rxnIdx(i))~=0);
    +0299     % Remove enzyme metabolite
    +0300     mets(startsWith(mets,'prot_')) = [];
    +0301     % Validate if it is a transport reaciton
    +0302     transportRxns(i) = numel(mets) ~= numel(unique(mets));
    +0303 end
    +0304 
    +0305 % Create separate table for transport reactions
    +0306 fseof.transportTargets = fseof.rxnTargets(transportRxns,:);
    +0307 fseof.rxnTargets(transportRxns,:) = [];
    +0308 
    +0309 % Report gene targets
    +0310 geneIdx              = cellfun(@(x) find(strcmpi(model.genes,x)),genes);
    +0311 fseof.geneTargets(:,1) = genes;
    +0312 fseof.geneTargets(:,2) = model.geneShortNames(geneIdx);
    +0313 fseof.geneTargets(:,3) = num2cell(slope_genes);
    +0314 fseof.geneTargets(:,4) = target_type_genes;
    +0315 fseof.geneTargets(:,5) = essentiality;
    +0316 
    +0317 % Save results in a file if defined
    +0318 if outputFile
    +0319     % Write file with gene targets
    +0320     writetable(cell2table(fseof.geneTargets, ...
    +0321         'VariableNames', {'gene_IDs' 'gene_names' 'slope' 'action' 'essentiality'}), ...
    +0322         fullfile(filePath, 'ecFSEOF_genes.tsv'), ...
    +0323         'FileType', 'text', ...
    +0324         'Delimiter', '\t', ...
    +0325         'QuoteStrings', false);
    +0326 
    +0327     % Write file with rxn targets
    +0328     writetable(cell2table(fseof.rxnTargets, ...
    +0329         'VariableNames', {'rxn_IDs' 'rxnNames' 'slope' 'grRules' 'rxn_formula'}), ...
    +0330         fullfile(filePath, 'ecFSEOF_rxns.tsv'), ...
    +0331         'FileType', 'text', ...
    +0332         'Delimiter', '\t', ...
    +0333         'QuoteStrings', false);
    +0334 
    +0335     % Write file with transport targets
    +0336     writetable(cell2table(fseof.transportTargets, ...
    +0337         'VariableNames', {'rxn_IDs' 'rxnNames' 'slope' 'grRules' 'rxn_formula'}), ...
    +0338         fullfile(filePath, 'ecFSEOF_transporter.tsv'), ...
    +0339         'FileType', 'text', ...
    +0340         'Delimiter', '\t', ...
    +0341         'QuoteStrings', false);
    +0342 
    +0343     disp(['ecFSEOF results stored at: ' newline filePath]);
    +0344 end
    +0345 
    +0346 end
    +
    Generated by m2html © 2005
    + + \ No newline at end of file diff --git a/doc/src/flux_analysis/ecFVA.html b/doc/src/flux_analysis/ecFVA.html new file mode 100644 index 00000000..0dc2355f --- /dev/null +++ b/doc/src/flux_analysis/ecFVA.html @@ -0,0 +1,188 @@ + + + + Description of ecFVA + + + + + + + + + +
    Home > src > flux_analysis > ecFVA.m
    + + + +

    ecFVA +

    + +

    PURPOSE ^

    +
    ecFVA Run flux variability analysis on an ecModel.
    + +

    SYNOPSIS ^

    +
    function [minFlux, maxFlux] = ecFVA(ecModel, model, varargin)
    + +

    DESCRIPTION ^

    +
     ecFVA  Run flux variability analysis on an ecModel.
    +
    + Flux variability analysis is performed on the ecModel, and isozymic
    + reactions are combined to construct output minFlux and maxFlux vectors,
    + which follow the same order of model.rxns. The output from this function
    + does not include enzyme usage reactions; to observe these, one could
    + consider running flux variability directly on the ecModel.
    +
    + Parameters
    + ----------
    + ecModel : struct
    +     an ecModel in GECKO 3 format (with ecModel.ec structure).
    + model : struct
    +     non-ecModel variant of the ecModel, to which the minFlux and maxFlux
    +     will be mapped.
    +
    + Name-Value Arguments
    + --------------------
    + runParallel : logical
    +     speed up calculations by parallel processing. Requires the MATLAB
    +     Parallel Computing Toolbox. If this is not installed, the
    +     calculations will not be parallelized, regardless of what is
    +     indicated as runParallel (default true).
    +
    + Returns
    + -------
    + minFlux : double
    +     vector of minimum flux rates, corresponding to model.rxns.
    + maxFlux : double
    +     vector of maximum flux rates, corresponding to model.rxns.
    +
    + Examples
    + --------
    +     [minFlux, maxFlux] = ecFVA(ecModel, model);
    +
    + See also
    + --------
    + mapRxnsToConv, plotEcFVA
    + + +

    CROSS-REFERENCE INFORMATION ^

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

    SOURCE CODE ^

    +
    0001 function [minFlux, maxFlux] = ecFVA(ecModel, model, varargin)
    +0002 % ecFVA  Run flux variability analysis on an ecModel.
    +0003 %
    +0004 % Flux variability analysis is performed on the ecModel, and isozymic
    +0005 % reactions are combined to construct output minFlux and maxFlux vectors,
    +0006 % which follow the same order of model.rxns. The output from this function
    +0007 % does not include enzyme usage reactions; to observe these, one could
    +0008 % consider running flux variability directly on the ecModel.
    +0009 %
    +0010 % Parameters
    +0011 % ----------
    +0012 % ecModel : struct
    +0013 %     an ecModel in GECKO 3 format (with ecModel.ec structure).
    +0014 % model : struct
    +0015 %     non-ecModel variant of the ecModel, to which the minFlux and maxFlux
    +0016 %     will be mapped.
    +0017 %
    +0018 % Name-Value Arguments
    +0019 % --------------------
    +0020 % runParallel : logical
    +0021 %     speed up calculations by parallel processing. Requires the MATLAB
    +0022 %     Parallel Computing Toolbox. If this is not installed, the
    +0023 %     calculations will not be parallelized, regardless of what is
    +0024 %     indicated as runParallel (default true).
    +0025 %
    +0026 % Returns
    +0027 % -------
    +0028 % minFlux : double
    +0029 %     vector of minimum flux rates, corresponding to model.rxns.
    +0030 % maxFlux : double
    +0031 %     vector of maximum flux rates, corresponding to model.rxns.
    +0032 %
    +0033 % Examples
    +0034 % --------
    +0035 %     [minFlux, maxFlux] = ecFVA(ecModel, model);
    +0036 %
    +0037 % See also
    +0038 % --------
    +0039 % mapRxnsToConv, plotEcFVA
    +0040 
    +0041 p = parseGECKOargs(varargin, { ...
    +0042     'runParallel', true});
    +0043 runParallel = p.runParallel;
    +0044 
    +0045 rxnIDs = regexprep(ecModel.rxns,'(_REV)?(_EXP_\d+)?$','');
    +0046 [rxnIDmap, convRxnID] = findgroups(rxnIDs);
    +0047 
    +0048 N = numel(convRxnID);
    +0049 maxFluxByGroup = nan(N,1);
    +0050 minFluxByGroup = nan(N,1);
    +0051 
    +0052 % nW == 0 forces parfor to run as a plain for loop (no pool required or
    +0053 % created); nW == Inf lets Parallel Computing Toolbox manage the pool.
    +0054 % Falls back to serial automatically when the toolbox isn't installed,
    +0055 % rather than erroring the way an unconditional gcp/parpool call would.
    +0056 nW = parallelWorkersRAVEN(runParallel);
    +0057 
    +0058 PB = progressReport(N, 'Running ecFVA');
    +0059 
    +0060 parfor (i=1:N, nW)
    +0061     tmpModel = ecModel;
    +0062     tmpModel.c = zeros(numel(tmpModel.rxns),1);
    +0063 
    +0064     rxnsToOptim = find(rxnIDmap == i);
    +0065     rxnsOptIDs  = ecModel.rxns(rxnsToOptim);
    +0066     rxnsToMin = endsWith(rxnsOptIDs,'_REV') | contains(rxnsOptIDs,'_REV_EXP_');
    +0067     rxnsToMax = rxnsToOptim(~rxnsToMin);
    +0068     rxnsToMin = rxnsToOptim(rxnsToMin);
    +0069 
    +0070     tmpModel.c(rxnsToMax) = 1;
    +0071     tmpModel.c(rxnsToMin) = -1;
    +0072     solMax=solveLP(tmpModel);
    +0073     if ~isempty(solMax.x)
    +0074         % Exact bound for this canonical reaction, read directly off this
    +0075         % group's own solve (the "diagonal"): forward minus reverse
    +0076         % variants from the one LP that jointly optimised them, not the
    +0077         % best value each variant happened to reach in whichever group's
    +0078         % solve maximised it -- an "envelope" that can combine values from
    +0079         % different, not necessarily jointly feasible, flux distributions.
    +0080         maxFluxByGroup(i) = sum(solMax.x(rxnsToMax)) - sum(solMax.x(rxnsToMin));
    +0081     end
    +0082     tmpModel.c(rxnsToMax) = -1;
    +0083     tmpModel.c(rxnsToMin) = 1;
    +0084     solMin=solveLP(tmpModel);
    +0085     if ~isempty(solMin.x)
    +0086         minFluxByGroup(i) = sum(solMin.x(rxnsToMax)) - sum(solMin.x(rxnsToMin));
    +0087     end
    +0088     count(PB);
    +0089 end
    +0090 PB.done;
    +0091 
    +0092 % Reorder from canonical-id order to model.rxns order. No min/max swap
    +0093 % correction is needed here (unlike a row-reduced envelope): both bounds
    +0094 % come from the same group's LP over the same feasible region with only
    +0095 % the objective direction flipped, so minFluxByGroup(i) <= maxFluxByGroup(i)
    +0096 % always holds whenever both solves succeeded.
    +0097 [mapCheck, origIdx] = ismember(model.rxns, convRxnID);
    +0098 if ~all(mapCheck)
    +0099     error('Not all reactions from model.rxns can be found in the ecModel. Are you sure that ecModel is derived from model?')
    +0100 end
    +0101 minFlux = minFluxByGroup(origIdx);
    +0102 maxFlux = maxFluxByGroup(origIdx);
    +0103 
    +0104 end
    +
    Generated by m2html © 2005
    + + \ No newline at end of file diff --git a/doc/src/flux_analysis/getPfbaEnzymes.html b/doc/src/flux_analysis/getPfbaEnzymes.html new file mode 100644 index 00000000..f848d076 --- /dev/null +++ b/doc/src/flux_analysis/getPfbaEnzymes.html @@ -0,0 +1,210 @@ + + + + Description of getPfbaEnzymes + + + + + + + + + +
    Home > src > flux_analysis > getPfbaEnzymes.m
    + + + +

    getPfbaEnzymes +

    + +

    PURPOSE ^

    +
    getPfbaEnzymes Parsimonious FBA minimising total enzyme usage.
    + +

    SYNOPSIS ^

    +
    function solution = getPfbaEnzymes(model, varargin)
    + +

    DESCRIPTION ^

    +
     getPfbaEnzymes  Parsimonious FBA minimising total enzyme usage.
    +
    + Among all flux distributions at (or within a fraction of) the optimal
    + value of the current objective, finds the one that minimises total
    + enzyme usage: the smallest sum of usage_prot_* fluxes. This is the
    + enzyme-aware analogue of classical pFBA, which minimises total flux
    + instead --- for ecModels this usually picks the most parsimonious
    + *proteome*, not just the most parsimonious fluxes.
    +
    + Parameters
    + ----------
    + model : struct
    +     a full ecModel in GECKO 3 format (with ecModel.ec structure and
    +     usage_prot_<id> reactions). Not supported for gecko-light models.
    +
    + Name-Value Arguments
    + --------------------
    + rxnId : char
    +     reaction id to use as the objective instead of model.c as given
    +     (default: use model.c as given).
    + fractionOfOptimum : double
    +     fraction of the optimal objective value to fix before minimising
    +     enzyme usage (default 1.0).
    +
    + Returns
    + -------
    + solution : struct
    +     - x : flux distribution (indexed by model.rxns) at the
    +       enzyme-usage-minimising solution.
    +     - getEnzymeUsage : the minimised sum of usage_prot_* fluxes.
    +     - objectiveValue : the fixed objective's own value at this solution.
    +     - stat : solveLP exit flag.
    +
    + Examples
    + --------
    +     solution = getPfbaEnzymes(ecModel);
    +     solution = getPfbaEnzymes(ecModel, 'fractionOfOptimum', 0.9);
    +
    + Notes
    + -----
    + usage_prot_<id> reactions must be forward-only (lb=0), the standard
    + GECKO 3 layout; if any has a negative lower bound (reverse flux enabled),
    + getPfbaEnzymes errors instead of building an objective that would fail to
    + minimise |flux| for that reaction.
    +
    + See also
    + --------
    + getEnzymeBottlenecks
    + + +

    CROSS-REFERENCE INFORMATION ^

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

    SOURCE CODE ^

    +
    0001 function solution = getPfbaEnzymes(model, varargin)
    +0002 % getPfbaEnzymes  Parsimonious FBA minimising total enzyme usage.
    +0003 %
    +0004 % Among all flux distributions at (or within a fraction of) the optimal
    +0005 % value of the current objective, finds the one that minimises total
    +0006 % enzyme usage: the smallest sum of usage_prot_* fluxes. This is the
    +0007 % enzyme-aware analogue of classical pFBA, which minimises total flux
    +0008 % instead --- for ecModels this usually picks the most parsimonious
    +0009 % *proteome*, not just the most parsimonious fluxes.
    +0010 %
    +0011 % Parameters
    +0012 % ----------
    +0013 % model : struct
    +0014 %     a full ecModel in GECKO 3 format (with ecModel.ec structure and
    +0015 %     usage_prot_<id> reactions). Not supported for gecko-light models.
    +0016 %
    +0017 % Name-Value Arguments
    +0018 % --------------------
    +0019 % rxnId : char
    +0020 %     reaction id to use as the objective instead of model.c as given
    +0021 %     (default: use model.c as given).
    +0022 % fractionOfOptimum : double
    +0023 %     fraction of the optimal objective value to fix before minimising
    +0024 %     enzyme usage (default 1.0).
    +0025 %
    +0026 % Returns
    +0027 % -------
    +0028 % solution : struct
    +0029 %     - x : flux distribution (indexed by model.rxns) at the
    +0030 %       enzyme-usage-minimising solution.
    +0031 %     - getEnzymeUsage : the minimised sum of usage_prot_* fluxes.
    +0032 %     - objectiveValue : the fixed objective's own value at this solution.
    +0033 %     - stat : solveLP exit flag.
    +0034 %
    +0035 % Examples
    +0036 % --------
    +0037 %     solution = getPfbaEnzymes(ecModel);
    +0038 %     solution = getPfbaEnzymes(ecModel, 'fractionOfOptimum', 0.9);
    +0039 %
    +0040 % Notes
    +0041 % -----
    +0042 % usage_prot_<id> reactions must be forward-only (lb=0), the standard
    +0043 % GECKO 3 layout; if any has a negative lower bound (reverse flux enabled),
    +0044 % getPfbaEnzymes errors instead of building an objective that would fail to
    +0045 % minimise |flux| for that reaction.
    +0046 %
    +0047 % See also
    +0048 % --------
    +0049 % getEnzymeBottlenecks
    +0050 
    +0051 p = parseGECKOargs(varargin, {'rxnId', []; 'fractionOfOptimum', []});
    +0052 rxnId             = p.rxnId;
    +0053 fractionOfOptimum = p.fractionOfOptimum;
    +0054 if isempty(fractionOfOptimum)
    +0055     fractionOfOptimum = 1.0;
    +0056 end
    +0057 
    +0058 if isfield(model.ec, 'geckoLight') && model.ec.geckoLight
    +0059     error(['getPfbaEnzymes requires a full ecModel, not gecko-light: light models have no ' ...
    +0060         'usage_prot_<id> reactions.'])
    +0061 end
    +0062 
    +0063 if ~isempty(rxnId)
    +0064     rxnIdx = find(strcmp(model.rxns, rxnId));
    +0065     if isempty(rxnIdx)
    +0066         error('getPfbaEnzymes: reaction %s not found in model.rxns.', rxnId)
    +0067     end
    +0068     model.c = zeros(numel(model.rxns), 1);
    +0069     model.c(rxnIdx) = 1;
    +0070 end
    +0071 if ~any(model.c)
    +0072     error('getPfbaEnzymes: model.c is empty; nothing to fix before minimising enzyme usage.')
    +0073 end
    +0074 
    +0075 usageIdx = find(startsWith(model.rxns, 'usage_prot_'));
    +0076 if isempty(usageIdx)
    +0077     error('getPfbaEnzymes: no usage_prot_<id> reactions found. This is done by makeEcModel.')
    +0078 end
    +0079 if any(model.lb(usageIdx) < 0)
    +0080     error(['getPfbaEnzymes does not support usage_prot_<id> reactions with a negative lower ' ...
    +0081         'bound (reverse flux enabled): minimising raw flux would not minimise |flux| for ' ...
    +0082         'those reactions.'])
    +0083 end
    +0084 
    +0085 solOrig = solveLP(model);
    +0086 if solOrig.stat ~= 1
    +0087     error('getPfbaEnzymes: solver status %d on the original objective; cannot fix it as a constraint.', solOrig.stat)
    +0088 end
    +0089 
    +0090 % Fix the objective as a constraint, same "fake metabolite" technique
    +0091 % solveLP's own minFlux=1 option uses (see solveLP.m).
    +0092 target = fractionOfOptimum * solOrig.f;
    +0093 if target > 0
    +0094     target = target * 0.999999;
    +0095 else
    +0096     target = target * 1.000001;
    +0097 end
    +0098 fixModel = model;
    +0099 fixModel.S(end+1, :) = model.c';
    +0100 fixModel.mets{end+1, 1} = 'getPfbaEnzymes_objective';
    +0101 if size(fixModel.b, 2) == 1
    +0102     fixModel.b = [fixModel.b fixModel.b];
    +0103 end
    +0104 fixModel.b(end+1, :) = [target inf];
    +0105 
    +0106 fixModel.c = zeros(numel(fixModel.rxns), 1);
    +0107 fixModel.c(usageIdx) = -1;
    +0108 
    +0109 solution = solveLP(fixModel);
    +0110 if solution.stat ~= 1
    +0111     error('getPfbaEnzymes: minimising enzyme usage was infeasible at fractionOfOptimum=%g.', fractionOfOptimum)
    +0112 end
    +0113 
    +0114 solution.enzymeUsage    = -solution.f;
    +0115 solution.objectiveValue = model.c' * solution.x;
    +0116 end
    +
    Generated by m2html © 2005
    + + \ No newline at end of file diff --git a/doc/src/flux_analysis/index.html b/doc/src/flux_analysis/index.html new file mode 100644 index 00000000..24f9f67f --- /dev/null +++ b/doc/src/flux_analysis/index.html @@ -0,0 +1,29 @@ + + + + Index for Directory src/flux_analysis + + + + + + + + + + +
    < Master indexIndex for src/flux_analysis >
    + +

    Index for src/flux_analysis

    + +

    Matlab files in this directory:

    + +
     ecFSEOFecFSEOF Run Flux-Scanning with Enforced Objective Function for a target.
     ecFVAecFVA Run flux variability analysis on an ecModel.
     getPfbaEnzymesgetPfbaEnzymes Parsimonious FBA minimising total enzyme usage.
     plotEcFVAplotEcFVA Plot cumulative distribution functions of ecFVA results.
    + + + + +
    Generated by m2html © 2005
    + + \ No newline at end of file diff --git a/doc/src/flux_analysis/plotEcFVA.html b/doc/src/flux_analysis/plotEcFVA.html new file mode 100644 index 00000000..34fc9ded --- /dev/null +++ b/doc/src/flux_analysis/plotEcFVA.html @@ -0,0 +1,156 @@ + + + + Description of plotEcFVA + + + + + + + + + +
    Home > src > flux_analysis > plotEcFVA.m
    + + + +

    plotEcFVA +

    + +

    PURPOSE ^

    +
    plotEcFVA Plot cumulative distribution functions of ecFVA results.
    + +

    SYNOPSIS ^

    +
    function plotEcFVA(minFlux, maxFlux)
    + +

    DESCRIPTION ^

    +
     plotEcFVA  Plot cumulative distribution functions of ecFVA results.
    +
    + Plots cumulative distribution functions of ecFVA results from one or
    + more ecModel(s) and/or GEM(s).
    +
    + Parameters
    + ----------
    + minFlux : double
    +     vector of minimum flux values, coming from ecFVA. If multiple
    +     ecModels/GEMs are to be visualized, then each column represents a
    +     separate model.
    + maxFlux : double
    +     vector of maximum flux values, matching minFlux.
    +
    + See also
    + --------
    + ecFVA
    + + +

    CROSS-REFERENCE INFORMATION ^

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

    SUBFUNCTIONS ^

    + + +

    SOURCE CODE ^

    +
    0001 function plotEcFVA(minFlux, maxFlux)
    +0002 % plotEcFVA  Plot cumulative distribution functions of ecFVA results.
    +0003 %
    +0004 % Plots cumulative distribution functions of ecFVA results from one or
    +0005 % more ecModel(s) and/or GEM(s).
    +0006 %
    +0007 % Parameters
    +0008 % ----------
    +0009 % minFlux : double
    +0010 %     vector of minimum flux values, coming from ecFVA. If multiple
    +0011 %     ecModels/GEMs are to be visualized, then each column represents a
    +0012 %     separate model.
    +0013 % maxFlux : double
    +0014 %     vector of maximum flux values, matching minFlux.
    +0015 %
    +0016 % See also
    +0017 % --------
    +0018 % ecFVA
    +0019 
    +0020 numMods = size(minFlux,2);
    +0021 fluxRanges = cell(3,1);
    +0022 % Ignore zero flux reactions
    +0023 for i=1:numMods
    +0024     zeroFlux = abs(minFlux(:,i)) < 1e-10 & abs(maxFlux(:,i)) < 1e-10;
    +0025     minFlux(zeroFlux,i) = NaN;
    +0026     maxFlux(zeroFlux,i) = NaN;
    +0027     fluxRange = maxFlux(:,i) - minFlux(:,i);
    +0028     fluxRange(isnan(fluxRange)) = [];
    +0029     fluxRanges{i} = fluxRange;
    +0030 end
    +0031 
    +0032 % Plot all together
    +0033 hold on
    +0034 legendText = cell(1,numel(numMods));
    +0035 for i=1:numMods
    +0036     fluxRange = fluxRanges{i};
    +0037     cdfplot(fluxRange)
    +0038     legendText{i} = (['Model #' num2str(i) ' (median: ' num2str(median(fluxRange,'omitnan')) ')']);
    +0039 end
    +0040 set(gca, 'XScale', 'log', 'Xlim', [1e-7 1e4])
    +0041 set(findall(gca, 'Type', 'Line'), 'LineWidth', 2)
    +0042 legend(legendText,  'Location','northwest')
    +0043 title('Flux variability (cumulative distribution)');
    +0044 xlabel('Variability range (mmol/gDCWh)');
    +0045 ylabel('Cumulative distribution');
    +0046 hold off
    +0047 end
    +0048 
    +0049 function cdfplot(X)
    +0050 % cdfplot(X)
    +0051 % displays a plot of the Empirical Cumulative Distribution Function
    +0052 % (CDF) of the input array X in the current figure. The empirical
    +0053 % CDF y=F(x) is defined as the proportion of X values less than or equal to x.
    +0054 % If input X is a matrix, then cdfplot(X) parses it to the vector and
    +0055 % displays CDF of all values.
    +0056 %
    +0057 % EXAMPLE:
    +0058 % figure;
    +0059 % cdfplot(randn(1,100));
    +0060 % hold on;
    +0061 % cdfplot(-log(1-rand(1,100)));
    +0062 % cdfplot(sqrt(randn(1,100).^2 + randn(1,100).^2))
    +0063 % legend('Normal(0,1) CDF', 'Exponential(1) CDF', 'Rayleigh(1) CDF', 4)
    +0064 
    +0065 % Version 1.0
    +0066 % Alex Podgaetsky, September 2003
    +0067 % alex@wavion.co.il
    +0068 %
    +0069 % Revisions:
    +0070 %       Version 1.0 -   initial version
    +0071 
    +0072 tmp = sort(reshape(X,prod(size(X)),1));
    +0073 Xplot = reshape([tmp tmp].',2*length(tmp),1);
    +0074 
    +0075 tmp = [1:length(X)].'/length(X);
    +0076 Yplot = reshape([tmp tmp].',2*length(tmp),1);
    +0077 Yplot = [0; Yplot(1:(end-1))];
    +0078 
    +0079 figure(gcf);
    +0080 hp = plot(Xplot, Yplot);
    +0081 
    +0082 ColOrd = get(gca, 'ColorOrder'); 
    +0083 ord = mod(length(get(gca,'Children')), size(ColOrd,1)); 
    +0084 set(hp, 'Color', ColOrd((ord==0) + (ord>0)*ord, :));
    +0085 if ~ishold
    +0086      xlabel('X', 'FontWeight','b','FontSize',12);
    +0087      ylabel('F(X)', 'FontWeight','b','FontSize',12);
    +0088      title('Empirical CDF', 'FontWeight','b','FontSize',12);
    +0089      grid on;
    +0090 end
    +0091 end
    +
    Generated by m2html © 2005
    + + \ No newline at end of file diff --git a/doc/src/gather_kcats/assignKcatValues.html b/doc/src/gather_kcats/assignKcatValues.html new file mode 100644 index 00000000..a987c42d --- /dev/null +++ b/doc/src/gather_kcats/assignKcatValues.html @@ -0,0 +1,244 @@ + + + + Description of assignKcatValues + + + + + + + + + +
    Home > src > gather_kcats > assignKcatValues.m
    + + + +

    assignKcatValues +

    + +

    PURPOSE ^

    +
    assignKcatValues Select one kcat value per reaction and write to model.ec.
    + +

    SYNOPSIS ^

    +
    function [model, rxnIdx] = assignKcatValues(model,kcatList,varargin)
    + +

    DESCRIPTION ^

    +
     assignKcatValues  Select one kcat value per reaction and write to model.ec.
    +
    + From a kcatList with predicted or suggested kcat values, where each
    + reaction may have multiple entries, one kcat value is selected and written
    + to model.ec.kcat. Zero values are discarded from the start. By default,
    + the maximum value is chosen, but alternatives are available. The kcatList
    + structure is an output of e.g. readDLKcatOutput, readGotEnzymesOutput,
    + readManualKcatList.
    +
    + Parameters
    + ----------
    + model : struct
    +     an ecModel in GECKO 3 format (with ecModel.ec structure).
    + kcatList : struct
    +     structure array with separate entries for each kcat value, with the
    +     following fields:
    +
    +     - source : e.g. 'DLKcat' or 'gotenzymes'.
    +     - rxns : reaction identifiers, matching model.ec.rxns.
    +     - genes : gene identifiers, matching model.ec.genes.
    +     - substrates : substrate names, matching model.metNames.
    +     - kcats : predicted kcat value in /sec.
    +     - kcatSource : optional, the source of each entry; entries with a zero
    +       kcat are discarded together with their source.
    +
    + Name-Value Arguments
    + --------------------
    + criteria : char
    +     which kcat value should be selected if multiple values are provided.
    +     Options: 'max', 'min', 'median', 'mean' (default 'max'). The written
    +     model.ec.source is taken from the matching entry for 'max'/'min'; for
    +     'median'/'mean', where the selected value need not equal any single
    +     input, it is taken from the first entry instead (arbitrary but
    +     deterministic, since an aggregate has no single "winning" source).
    + overwrite : char
    +     whether existing kcat values should be overwritten. Options: 'true',
    +     'false', 'ifHigher'. The last option will overwrite only if the new
    +     kcat value is higher (default 'true').
    +
    + Returns
    + -------
    + model : struct
    +     ecModel with updated model.ec.kcat and model.ec.source.
    + rxnIdx : double
    +     list of reaction indices (matching model.ec.rxns), to indicate which
    +     kcat values have been changed.
    +
    + Examples
    + --------
    +     % optional arguments may be given positionally or as name-value pairs:
    +     [model, rxnIdx] = assignKcatValues(model, kcatList);
    +     [model, rxnIdx] = assignKcatValues(model, kcatList, 'criteria', 'mean');
    +
    + See also
    + --------
    + readDLKcatOutput, mergeDLKcatAndFuzzyKcats, applyKcatConstraints
    + + +

    CROSS-REFERENCE INFORMATION ^

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

    SOURCE CODE ^

    +
    0001 function [model, rxnIdx] = assignKcatValues(model,kcatList,varargin)
    +0002 % assignKcatValues  Select one kcat value per reaction and write to model.ec.
    +0003 %
    +0004 % From a kcatList with predicted or suggested kcat values, where each
    +0005 % reaction may have multiple entries, one kcat value is selected and written
    +0006 % to model.ec.kcat. Zero values are discarded from the start. By default,
    +0007 % the maximum value is chosen, but alternatives are available. The kcatList
    +0008 % structure is an output of e.g. readDLKcatOutput, readGotEnzymesOutput,
    +0009 % readManualKcatList.
    +0010 %
    +0011 % Parameters
    +0012 % ----------
    +0013 % model : struct
    +0014 %     an ecModel in GECKO 3 format (with ecModel.ec structure).
    +0015 % kcatList : struct
    +0016 %     structure array with separate entries for each kcat value, with the
    +0017 %     following fields:
    +0018 %
    +0019 %     - source : e.g. 'DLKcat' or 'gotenzymes'.
    +0020 %     - rxns : reaction identifiers, matching model.ec.rxns.
    +0021 %     - genes : gene identifiers, matching model.ec.genes.
    +0022 %     - substrates : substrate names, matching model.metNames.
    +0023 %     - kcats : predicted kcat value in /sec.
    +0024 %     - kcatSource : optional, the source of each entry; entries with a zero
    +0025 %       kcat are discarded together with their source.
    +0026 %
    +0027 % Name-Value Arguments
    +0028 % --------------------
    +0029 % criteria : char
    +0030 %     which kcat value should be selected if multiple values are provided.
    +0031 %     Options: 'max', 'min', 'median', 'mean' (default 'max'). The written
    +0032 %     model.ec.source is taken from the matching entry for 'max'/'min'; for
    +0033 %     'median'/'mean', where the selected value need not equal any single
    +0034 %     input, it is taken from the first entry instead (arbitrary but
    +0035 %     deterministic, since an aggregate has no single "winning" source).
    +0036 % overwrite : char
    +0037 %     whether existing kcat values should be overwritten. Options: 'true',
    +0038 %     'false', 'ifHigher'. The last option will overwrite only if the new
    +0039 %     kcat value is higher (default 'true').
    +0040 %
    +0041 % Returns
    +0042 % -------
    +0043 % model : struct
    +0044 %     ecModel with updated model.ec.kcat and model.ec.source.
    +0045 % rxnIdx : double
    +0046 %     list of reaction indices (matching model.ec.rxns), to indicate which
    +0047 %     kcat values have been changed.
    +0048 %
    +0049 % Examples
    +0050 % --------
    +0051 %     % optional arguments may be given positionally or as name-value pairs:
    +0052 %     [model, rxnIdx] = assignKcatValues(model, kcatList);
    +0053 %     [model, rxnIdx] = assignKcatValues(model, kcatList, 'criteria', 'mean');
    +0054 %
    +0055 % See also
    +0056 % --------
    +0057 % readDLKcatOutput, mergeDLKcatAndFuzzyKcats, applyKcatConstraints
    +0058 
    +0059 p = parseGECKOargs(varargin, { ...
    +0060     'criteria',  []; ...
    +0061     'overwrite', []});
    +0062 criteria  = p.criteria;
    +0063 overwrite = p.overwrite;
    +0064 
    +0065 if isempty(overwrite)
    +0066     overwrite = 'true';
    +0067 elseif islogical(overwrite)
    +0068     if overwrite
    +0069         overwrite = 'true';
    +0070     else
    +0071         overwrite = 'false';
    +0072     end
    +0073 end
    +0074 if isempty(criteria)
    +0075     criteria = 'max';
    +0076 end
    +0077 
    +0078 % Remove zero kcat values. Only adjusting fields that are used later.
    +0079 removeZero                      = kcatList.kcats == 0;
    +0080 kcatList.kcats(removeZero)      = [];
    +0081 kcatList.rxns(removeZero)       = [];
    +0082 if isfield(kcatList,'kcatSource')
    +0083     kcatList.kcatSource(removeZero) = [];
    +0084 end
    +0085 
    +0086 % Map to model.ec.rxns
    +0087 [sanityCheck,idxInModel] = ismember(kcatList.rxns,model.ec.rxns);
    +0088 if ~all(sanityCheck)
    +0089     error('Not all reactions in kcatList are found in model.ec.rxns')
    +0090 end
    +0091 % Make vector with single kcat value per reaction
    +0092 idxInModelUnique = unique(idxInModel);
    +0093 selectedKcats    = zeros(numel(idxInModelUnique),1);
    +0094 selectedSource   = cell(numel(selectedKcats),1);
    +0095 if ~isfield(kcatList,'kcatSource')
    +0096     kcatList.kcatSource = cell(numel(kcatList.kcats),1);
    +0097     kcatList.kcatSource(:) = {kcatList.source};
    +0098 end
    +0099 for i=1:numel(idxInModelUnique)
    +0100     ind = idxInModelUnique(i);
    +0101     idxMatch = find(idxInModel == ind);
    +0102     % Choose the maximum number
    +0103     switch criteria
    +0104         case 'max'
    +0105             [selectedKcats(i),j] = max(kcatList.kcats(idxMatch));
    +0106         case 'min'
    +0107             [selectedKcats(i),j] = min(kcatList.kcats(idxMatch));
    +0108         case 'median'
    +0109             selectedKcats(i) = median(kcatList.kcats(idxMatch));
    +0110             j = 1;
    +0111         case 'mean'
    +0112             selectedKcats(i) = mean(kcatList.kcats(idxMatch));
    +0113             j = 1;
    +0114         otherwise
    +0115             error('Invalid criteria specified')
    +0116     end
    +0117     selectedSource(i)    = kcatList.kcatSource(idxMatch(j));
    +0118 end
    +0119 
    +0120 % Populate model.ec.kcat
    +0121 switch overwrite
    +0122     case 'true'
    +0123         model.ec.kcat(idxInModelUnique) = selectedKcats;
    +0124         model.ec.source(idxInModelUnique) = selectedSource;
    +0125     case 'false'
    +0126         emptyKcats = find(model.ec.kcat == 0);
    +0127         [idxInModelUnique,whickKcats] = intersect(idxInModelUnique,emptyKcats,'stable');
    +0128         model.ec.kcat(idxInModelUnique) = selectedKcats(whickKcats);
    +0129         model.ec.source(idxInModelUnique) = selectedSource(whickKcats);
    +0130         
    +0131     case 'ifHigher'
    +0132         higherKcats = model.ec.kcat(idxInModelUnique) < selectedKcats;
    +0133         selectedKcats(~higherKcats) = [];
    +0134         selectedSource(~higherKcats) = [];
    +0135         idxInModelUnique(~higherKcats) = [];
    +0136         model.ec.kcat(idxInModelUnique) = selectedKcats;
    +0137         model.ec.source(idxInModelUnique) = selectedSource;
    +0138     otherwise
    +0139         error('Invalid overwrite flag specified')
    +0140 end
    +0141 rxnIdx = idxInModelUnique;
    +0142 end
    +
    Generated by m2html © 2005
    + + \ No newline at end of file diff --git a/doc/src/gather_kcats/assignKcats.html b/doc/src/gather_kcats/assignKcats.html new file mode 100644 index 00000000..8338f833 --- /dev/null +++ b/doc/src/gather_kcats/assignKcats.html @@ -0,0 +1,141 @@ + + + + Description of assignKcats + + + + + + + + + +
    Home > src > gather_kcats > assignKcats.m
    + + + +

    assignKcats +

    + +

    PURPOSE ^

    +
    assignKcats Assign kcats from the kcat source files and apply them.
    + +

    SYNOPSIS ^

    +
    function [model, decisions, report] = assignKcats(model, varargin)
    + +

    DESCRIPTION ^

    +
     assignKcats  Assign kcats from the kcat source files and apply them.
    +
    + Decides one kcat per reaction from the kcat source files in data/kcats,
    + as [kcat_assignment] in model_adapter.toml sets (see collectKcats), writes
    + model.ec.kcat and model.ec.source, and applies the kcat constraints
    + (applyKcatConstraints). Any kcats the model had are replaced: the source
    + files are the input, and nothing in the model is written back to them.
    +
    + Parameters
    + ----------
    + model : struct
    +     an ecModel in GECKO 3 format (with ecModel.ec structure).
    +
    + Name-Value Arguments
    + --------------------
    + modelAdapter : ModelAdapter
    +     a loaded model adapter (default: the current default model adapter).
    + writeReport : logical
    +     write the decisions to output/<model id>_kcatDecisions.tsv (default
    +     true).
    +
    + Returns
    + -------
    + model : struct
    +     the ecModel with the assigned kcats applied.
    + decisions, report
    +     as returned by collectKcats.
    +
    + Examples
    + --------
    +     updateKcatSources(ecModel);   % gather what the configuration needs
    +     ecModel = assignKcats(ecModel);
    +
    + See also
    + --------
    + collectKcats, updateKcatSources, applyKcatConstraints
    + + +

    CROSS-REFERENCE INFORMATION ^

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

    SUBFUNCTIONS ^

    + + +

    SOURCE CODE ^

    +
    0001 function [model, decisions, report] = assignKcats(model, varargin)
    +0002 % assignKcats  Assign kcats from the kcat source files and apply them.
    +0003 %
    +0004 % Decides one kcat per reaction from the kcat source files in data/kcats,
    +0005 % as [kcat_assignment] in model_adapter.toml sets (see collectKcats), writes
    +0006 % model.ec.kcat and model.ec.source, and applies the kcat constraints
    +0007 % (applyKcatConstraints). Any kcats the model had are replaced: the source
    +0008 % files are the input, and nothing in the model is written back to them.
    +0009 %
    +0010 % Parameters
    +0011 % ----------
    +0012 % model : struct
    +0013 %     an ecModel in GECKO 3 format (with ecModel.ec structure).
    +0014 %
    +0015 % Name-Value Arguments
    +0016 % --------------------
    +0017 % modelAdapter : ModelAdapter
    +0018 %     a loaded model adapter (default: the current default model adapter).
    +0019 % writeReport : logical
    +0020 %     write the decisions to output/<model id>_kcatDecisions.tsv (default
    +0021 %     true).
    +0022 %
    +0023 % Returns
    +0024 % -------
    +0025 % model : struct
    +0026 %     the ecModel with the assigned kcats applied.
    +0027 % decisions, report
    +0028 %     as returned by collectKcats.
    +0029 %
    +0030 % Examples
    +0031 % --------
    +0032 %     updateKcatSources(ecModel);   % gather what the configuration needs
    +0033 %     ecModel = assignKcats(ecModel);
    +0034 %
    +0035 % See also
    +0036 % --------
    +0037 % collectKcats, updateKcatSources, applyKcatConstraints
    +0038 
    +0039 checkOptions(varargin, {'modelAdapter','writeReport'}, 'assignKcats');
    +0040 [decisions, report, model] = collectKcats(model, varargin{:});
    +0041 model = applyKcatConstraints(model);
    +0042 end
    +0043 
    +0044 function checkOptions(args, names, functionName)
    +0045 % Options are name-value pairs with known names, so a misspelled option is
    +0046 % an error instead of being taken as a positional argument.
    +0047 id = [functionName ':arguments'];
    +0048 given = args(1:2:end);
    +0049 if mod(numel(args), 2) ~= 0 || ~all(cellfun(@(x) ischar(x) || (isstring(x) && isscalar(x)), given))
    +0050     error(id, 'Options of %s are name-value pairs. Options: %s.', functionName, strjoin(names, ', '))
    +0051 end
    +0052 unknown = setdiff(cellfun(@char, given, 'UniformOutput', false), names);
    +0053 if ~isempty(unknown)
    +0054     error(id, 'Unknown option of %s: %s. Options: %s.', functionName, strjoin(unknown, ', '), ...
    +0055         strjoin(names, ', '))
    +0056 end
    +0057 end
    +
    Generated by m2html © 2005
    + + \ No newline at end of file diff --git a/doc/src/gather_kcats/collectKcats.html b/doc/src/gather_kcats/collectKcats.html new file mode 100644 index 00000000..1ef11037 --- /dev/null +++ b/doc/src/gather_kcats/collectKcats.html @@ -0,0 +1,628 @@ + + + + Description of collectKcats + + + + + + + + + +
    Home > src > gather_kcats > collectKcats.m
    + + + +

    collectKcats +

    + +

    PURPOSE ^

    +
    collectKcats Decide one kcat per reaction from the kcat source files.
    + +

    SYNOPSIS ^

    +
    function [decisions, report, ecModel] = collectKcats(model, varargin)
    + +

    DESCRIPTION ^

    +
     collectKcats  Decide one kcat per reaction from the kcat source files.
    +
    + Combines the kcat source files in data/kcats (see kcatsFromBrenda,
    + kcatsFromDLKcat, kcatsFromOKP and saveKcatSource) as [kcat_assignment] in
    + model_adapter.toml sets, without changing the model given. assignKcats
    + applies the decisions.
    +
    + The order is a preset or a list of stages:
    +
    +     [kcat_assignment]
    +     preset = "brenda_ec_tree"    # the default; or ec_tree_homologs, ec_tree_okp, okp,
    +                                  # gecko_median, gecko_classic
    +     isozymes = true              # fill from isozymes after the stages
    +     standard = true              # standard kcat for the rest
    +
    +     # instead of a preset:
    +     [[kcat_assignment.stage]]
    +     action = "select"            # or "combine"
    +     sources = ["custom", "database_top", "ec_tree"]
    +     criteria = "max"             # select: among several values of one source
    +     top_origin_limit = 1
    +
    +     [kcat_sources.okp]
    +     methods = ["CataPro", "UniKP"]   # the okp source group
    +
    + A stage decides the reactions that are still open:
    + - select: the first listed source with a value (see mergeKcats). Sources
    +   are the names of source files (custom, ec_tree, dlkcat, okp_catapro,
    +   ...) and the BRENDA quality tiers database_exact, database_top and
    +   database_bottom, which read brenda.tsv.
    + - combine: all listed sources with a value, each corrected for its bias
    +   and weighted by 1 / its error variance, both for the source's evidence
    +   for that reaction (the EC tree: measurements of the EC and its EC
    +   level; an OKP method: the enzyme's similarity to the method's training
    +   sequences). The parameters come with the BRENDA files
    +   (kcatCombineParams.tsv). model.ec.source reads 'combined (sd=<log10
    +   sd>, n=<sources>)'; sd is the uncertainty for a new measurement.
    + In both, okp stands for the OKP methods of [kcat_sources.okp] methods
    + (default: all methods with combination parameters).
    +
    + The presets:
    + - brenda_ec_tree (the default): custom kcats, the BRENDA median of
    +   measurements of the organism on the reaction's substrate (origin 1,
    +   without EC wildcards), the EC tree (kcatsFromECTree); then the OKP
    +   methods combined for the reactions left (without an EC number).
    + - ec_tree_homologs: custom kcats, the organism's own BRENDA value; then
    +   the EC tree and homologs (kcatsFromHomologs) combined; then the OKP
    +   methods combined.
    + - ec_tree_okp: custom kcats, the organism's own BRENDA value; then the EC
    +   tree, homologs and the OKP methods combined; then the OKP methods
    +   combined.
    + - okp: custom kcats; then the OKP methods combined.
    + - gecko_median: custom kcats, the BRENDA median of matches without EC
    +   wildcards from the organism or other organisms, with or without the
    +   substrate (origin 1 to 4), DLKcat, then the other BRENDA matches (EC
    +   wildcards, and specific activities, origin 5 and 6).
    + - gecko_classic: as gecko_median with the BRENDA maximum and the
    +   specific-activity matches above DLKcat (origin up to 6), as the GECKO 3
    +   tutorial.
    + Against measured kcats hidden from the search, the EC tree was closer
    + than the BRENDA median at origins 2 and 4 and with EC wildcards and as
    + close at origins 1 and 3; the EC tree combined with the OKP methods was
    + slightly closer than the EC tree, and the OKP methods combined as close.
    + In ecModels, values combined with predictions set high-turnover enzymes
    + such as ATP synthase too low, which is why the default uses predictions
    + only where there is no value from measurements. The BRENDA aggregation is
    + [kcat_sources.brenda] aggregation (see updateKcatSources).
    +
    + After the stages:
    + - custom kcats of data/customKcats.tsv are applied (applyCustomKcats),
    +   when a stage lists custom but there is no data/kcats/custom.tsv;
    + - with isozymes, reactions without a kcat take one from their isozymes
    +   (getKcatAcrossIsozymes);
    + - with standard, the remaining reactions get the standard kcat
    +   (getStandardKcat).
    +
    + A source file a stage names that does not exist is reported and left out.
    +
    + Parameters
    + ----------
    + model : struct
    +     an ecModel in GECKO 3 format (with ecModel.ec structure).
    +
    + Name-Value Arguments
    + --------------------
    + modelAdapter : ModelAdapter
    +     a loaded model adapter (default: the current default model adapter).
    + writeReport : logical
    +     write the decisions to output/<model id>_kcatDecisions.tsv (default
    +     true).
    +
    + Returns
    + -------
    + decisions : table
    +     one row per model.ec reaction: ecRxn, stage (the stage number, or
    +     custom, isozymes, standard, or empty when no kcat was found), source
    +     (as in model.ec.source), kcat, candidates (the number of values the
    +     deciding source had for the reaction, or of sources combined),
    +     spreadLog10 (their range, in log10 units) and sdLog10 (the
    +     uncertainty of a combined value).
    + report : struct
    +     - preset: the preset used, or '' with stages;
    +     - missing: source files the stages name that do not exist;
    +     - sources: per source file loaded, its unmatched, partial and invalid
    +       rows (see loadKcatSource).
    + ecModel : struct
    +     the model with the decided kcats, before applyKcatConstraints; this
    +     is what assignKcats returns, after applying the constraints.
    +
    + Examples
    + --------
    +     decisions = collectKcats(ecModel);
    +     decisions(strcmp(decisions.stage, ''), :)   % reactions without a kcat
    +
    + See also
    + --------
    + assignKcats, updateKcatSources, loadKcatSource, mergeKcats, assignKcatValues
    + + +

    CROSS-REFERENCE INFORMATION ^

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

    SUBFUNCTIONS ^

    + + +

    SOURCE CODE ^

    +
    0001 function [decisions, report, ecModel] = collectKcats(model, varargin)
    +0002 % collectKcats  Decide one kcat per reaction from the kcat source files.
    +0003 %
    +0004 % Combines the kcat source files in data/kcats (see kcatsFromBrenda,
    +0005 % kcatsFromDLKcat, kcatsFromOKP and saveKcatSource) as [kcat_assignment] in
    +0006 % model_adapter.toml sets, without changing the model given. assignKcats
    +0007 % applies the decisions.
    +0008 %
    +0009 % The order is a preset or a list of stages:
    +0010 %
    +0011 %     [kcat_assignment]
    +0012 %     preset = "brenda_ec_tree"    # the default; or ec_tree_homologs, ec_tree_okp, okp,
    +0013 %                                  # gecko_median, gecko_classic
    +0014 %     isozymes = true              # fill from isozymes after the stages
    +0015 %     standard = true              # standard kcat for the rest
    +0016 %
    +0017 %     # instead of a preset:
    +0018 %     [[kcat_assignment.stage]]
    +0019 %     action = "select"            # or "combine"
    +0020 %     sources = ["custom", "database_top", "ec_tree"]
    +0021 %     criteria = "max"             # select: among several values of one source
    +0022 %     top_origin_limit = 1
    +0023 %
    +0024 %     [kcat_sources.okp]
    +0025 %     methods = ["CataPro", "UniKP"]   # the okp source group
    +0026 %
    +0027 % A stage decides the reactions that are still open:
    +0028 % - select: the first listed source with a value (see mergeKcats). Sources
    +0029 %   are the names of source files (custom, ec_tree, dlkcat, okp_catapro,
    +0030 %   ...) and the BRENDA quality tiers database_exact, database_top and
    +0031 %   database_bottom, which read brenda.tsv.
    +0032 % - combine: all listed sources with a value, each corrected for its bias
    +0033 %   and weighted by 1 / its error variance, both for the source's evidence
    +0034 %   for that reaction (the EC tree: measurements of the EC and its EC
    +0035 %   level; an OKP method: the enzyme's similarity to the method's training
    +0036 %   sequences). The parameters come with the BRENDA files
    +0037 %   (kcatCombineParams.tsv). model.ec.source reads 'combined (sd=<log10
    +0038 %   sd>, n=<sources>)'; sd is the uncertainty for a new measurement.
    +0039 % In both, okp stands for the OKP methods of [kcat_sources.okp] methods
    +0040 % (default: all methods with combination parameters).
    +0041 %
    +0042 % The presets:
    +0043 % - brenda_ec_tree (the default): custom kcats, the BRENDA median of
    +0044 %   measurements of the organism on the reaction's substrate (origin 1,
    +0045 %   without EC wildcards), the EC tree (kcatsFromECTree); then the OKP
    +0046 %   methods combined for the reactions left (without an EC number).
    +0047 % - ec_tree_homologs: custom kcats, the organism's own BRENDA value; then
    +0048 %   the EC tree and homologs (kcatsFromHomologs) combined; then the OKP
    +0049 %   methods combined.
    +0050 % - ec_tree_okp: custom kcats, the organism's own BRENDA value; then the EC
    +0051 %   tree, homologs and the OKP methods combined; then the OKP methods
    +0052 %   combined.
    +0053 % - okp: custom kcats; then the OKP methods combined.
    +0054 % - gecko_median: custom kcats, the BRENDA median of matches without EC
    +0055 %   wildcards from the organism or other organisms, with or without the
    +0056 %   substrate (origin 1 to 4), DLKcat, then the other BRENDA matches (EC
    +0057 %   wildcards, and specific activities, origin 5 and 6).
    +0058 % - gecko_classic: as gecko_median with the BRENDA maximum and the
    +0059 %   specific-activity matches above DLKcat (origin up to 6), as the GECKO 3
    +0060 %   tutorial.
    +0061 % Against measured kcats hidden from the search, the EC tree was closer
    +0062 % than the BRENDA median at origins 2 and 4 and with EC wildcards and as
    +0063 % close at origins 1 and 3; the EC tree combined with the OKP methods was
    +0064 % slightly closer than the EC tree, and the OKP methods combined as close.
    +0065 % In ecModels, values combined with predictions set high-turnover enzymes
    +0066 % such as ATP synthase too low, which is why the default uses predictions
    +0067 % only where there is no value from measurements. The BRENDA aggregation is
    +0068 % [kcat_sources.brenda] aggregation (see updateKcatSources).
    +0069 %
    +0070 % After the stages:
    +0071 % - custom kcats of data/customKcats.tsv are applied (applyCustomKcats),
    +0072 %   when a stage lists custom but there is no data/kcats/custom.tsv;
    +0073 % - with isozymes, reactions without a kcat take one from their isozymes
    +0074 %   (getKcatAcrossIsozymes);
    +0075 % - with standard, the remaining reactions get the standard kcat
    +0076 %   (getStandardKcat).
    +0077 %
    +0078 % A source file a stage names that does not exist is reported and left out.
    +0079 %
    +0080 % Parameters
    +0081 % ----------
    +0082 % model : struct
    +0083 %     an ecModel in GECKO 3 format (with ecModel.ec structure).
    +0084 %
    +0085 % Name-Value Arguments
    +0086 % --------------------
    +0087 % modelAdapter : ModelAdapter
    +0088 %     a loaded model adapter (default: the current default model adapter).
    +0089 % writeReport : logical
    +0090 %     write the decisions to output/<model id>_kcatDecisions.tsv (default
    +0091 %     true).
    +0092 %
    +0093 % Returns
    +0094 % -------
    +0095 % decisions : table
    +0096 %     one row per model.ec reaction: ecRxn, stage (the stage number, or
    +0097 %     custom, isozymes, standard, or empty when no kcat was found), source
    +0098 %     (as in model.ec.source), kcat, candidates (the number of values the
    +0099 %     deciding source had for the reaction, or of sources combined),
    +0100 %     spreadLog10 (their range, in log10 units) and sdLog10 (the
    +0101 %     uncertainty of a combined value).
    +0102 % report : struct
    +0103 %     - preset: the preset used, or '' with stages;
    +0104 %     - missing: source files the stages name that do not exist;
    +0105 %     - sources: per source file loaded, its unmatched, partial and invalid
    +0106 %       rows (see loadKcatSource).
    +0107 % ecModel : struct
    +0108 %     the model with the decided kcats, before applyKcatConstraints; this
    +0109 %     is what assignKcats returns, after applying the constraints.
    +0110 %
    +0111 % Examples
    +0112 % --------
    +0113 %     decisions = collectKcats(ecModel);
    +0114 %     decisions(strcmp(decisions.stage, ''), :)   % reactions without a kcat
    +0115 %
    +0116 % See also
    +0117 % --------
    +0118 % assignKcats, updateKcatSources, loadKcatSource, mergeKcats, assignKcatValues
    +0119 
    +0120 checkOptions(varargin, {'modelAdapter','writeReport'}, 'collectKcats');
    +0121 p = parseGECKOargs(varargin, {'modelAdapter', []; 'writeReport', true});
    +0122 modelAdapter = p.modelAdapter;
    +0123 if isempty(modelAdapter)
    +0124     modelAdapter = ModelAdapterManager.getDefault();
    +0125     if isempty(modelAdapter)
    +0126         error('Either send in a modelAdapter or set the default model adapter in the ModelAdapterManager.')
    +0127     end
    +0128 end
    +0129 params = modelAdapter.params;
    +0130 config = kcatAssignmentConfig(params);
    +0131 kcatDir = fullfile(params.path, 'data', 'kcats');
    +0132 
    +0133 ecModel = model;
    +0134 nEc = numel(ecModel.ec.rxns);
    +0135 ecModel.ec.kcat(:) = 0;
    +0136 ecModel.ec.source(:) = {''};
    +0137 stage = repmat({''}, nEc, 1);
    +0138 candidates = zeros(nEc, 1);
    +0139 spread = nan(nEc, 1);
    +0140 sd = nan(nEc, 1);
    +0141 combineParams = [];
    +0142 
    +0143 report.preset = config.preset;
    +0144 report.missing = {};
    +0145 report.sources = struct();
    +0146 loaded = struct();
    +0147 legacyCustom = false;
    +0148 
    +0149     function list = loadSource(name)
    +0150         % The kcat list of a source file, or [] when it does not exist.
    +0151         list = [];
    +0152         file = fullfile(kcatDir, [name '.tsv']);
    +0153         if isfile(file)
    +0154             [list, rep] = loadKcatSource(ecModel, file);
    +0155             report.sources.(name) = rep;
    +0156         elseif strcmp(name, 'custom') && isfile(fullfile(params.path, 'data', 'customKcats.tsv'))
    +0157             legacyCustom = true;
    +0158         else
    +0159             report.missing{end+1} = name;
    +0160             printOrange(sprintf(['No kcat source file %s; it is left out. ' ...
    +0161                 'updateKcatSources gathers it.\n'], file));
    +0162         end
    +0163     end
    +0164 
    +0165 for s = 1:numel(config.stages)
    +0166     st = config.stages(s);
    +0167     if strcmp(st.action, 'combine')
    +0168         names = {};
    +0169         lists = {};
    +0170         for t = 1:numel(st.files)
    +0171             name = st.files{t};
    +0172             if ~isfield(loaded, name)
    +0173                 loaded.(name) = loadSource(name);
    +0174             end
    +0175             if ~isempty(loaded.(name))
    +0176                 names{end+1} = name; %#ok<AGROW>
    +0177                 lists{end+1} = loaded.(name); %#ok<AGROW>
    +0178             end
    +0179         end
    +0180         if isempty(names)
    +0181             continue
    +0182         end
    +0183         if isempty(combineParams)
    +0184             combineParams = loadCombineParams(modelAdapter);
    +0185         end
    +0186         openRxns = ecModel.ec.rxns(ecModel.ec.kcat == 0);
    +0187         c = combineKcats(names, lists, openRxns, combineParams);
    +0188         if isempty(c.rxns)
    +0189             continue
    +0190         end
    +0191         [~, idx] = ismember(c.rxns, ecModel.ec.rxns);
    +0192         ecModel.ec.kcat(idx) = c.kcats;
    +0193         ecModel.ec.source(idx) = cellstr(compose('combined (sd=%.2f, n=%d)', c.sd, c.n));
    +0194         stage(idx) = {sprintf('%d', s)};
    +0195         candidates(idx) = c.n;
    +0196         spread(idx) = c.spread;
    +0197         sd(idx) = c.sd;
    +0198         continue
    +0199     end
    +0200     lists = {};
    +0201     priority = {};
    +0202     for t = 1:numel(st.files)
    +0203         token = st.files{t};
    +0204         name = sourceFile(token);
    +0205         if ~isfield(loaded, name)
    +0206             loaded.(name) = loadSource(name);
    +0207         end
    +0208         list = loaded.(name);
    +0209         if isempty(list)
    +0210             continue
    +0211         end
    +0212         if ~any(cellfun(@(l) isequal(l, list), lists))
    +0213             lists{end+1} = list; %#ok<AGROW>
    +0214         end
    +0215         if startsWith(token, 'database_')
    +0216             priority{end+1} = token; %#ok<AGROW>
    +0217         else
    +0218             % The labels of the file's rows, at the file's place in the order.
    +0219             labels = unique(cellfun(@normalizeSource, list.kcatSource, 'UniformOutput', false), 'stable');
    +0220             priority = [priority, labels(~ismember(labels, {'brenda','sabio_rk'}))']; %#ok<AGROW>
    +0221         end
    +0222     end
    +0223     if isempty(lists) || isempty(priority)
    +0224         continue
    +0225     end
    +0226     merged = mergeKcats(lists, priority, 'topOriginLimit', st.topOriginLimit, ...
    +0227         'bottomOriginLimit', st.bottomOriginLimit, 'wildcardLimit', st.wildcardLimit);
    +0228     if isempty(merged.rxns)
    +0229         continue
    +0230     end
    +0231     open = ecModel.ec.kcat == 0;
    +0232     [ecModel, idx] = assignKcatValues(ecModel, merged, 'criteria', st.criteria, 'overwrite', 'false');
    +0233     idx = idx(open(idx));
    +0234     stage(idx) = {sprintf('%d', s)};
    +0235     [~, where] = ismember(merged.rxns, ecModel.ec.rxns);
    +0236     valid = merged.kcats > 0;
    +0237     for i = idx(:)'
    +0238         values = merged.kcats(where == i & valid);
    +0239         candidates(i) = numel(values);
    +0240         spread(i) = log10(max(values)) - log10(min(values));
    +0241     end
    +0242 end
    +0243 
    +0244 if legacyCustom
    +0245     before = ecModel.ec.kcat;
    +0246     ecModel = applyCustomKcats(ecModel, 'modelAdapter', modelAdapter);
    +0247     changed = ecModel.ec.kcat ~= before;
    +0248     stage(changed) = {'custom'};
    +0249     candidates(changed) = 1;
    +0250     spread(changed) = 0;
    +0251 end
    +0252 if config.isozymes && ~ecModel.ec.geckoLight
    +0253     before = ecModel.ec.kcat == 0;
    +0254     ecModel = getKcatAcrossIsozymes(ecModel);
    +0255     stage(before & ecModel.ec.kcat > 0) = {'isozymes'};
    +0256 end
    +0257 if config.standard
    +0258     ecModel = getStandardKcat(ecModel, 'modelAdapter', modelAdapter);
    +0259     n = numel(ecModel.ec.rxns);
    +0260     stage(end+1:n) = {''};
    +0261     candidates(end+1:n) = 0;
    +0262     spread(end+1:n) = NaN;
    +0263     sd(end+1:n) = NaN;
    +0264     stage(strcmp(ecModel.ec.source, 'standard') & ecModel.ec.kcat > 0) = {'standard'};
    +0265 end
    +0266 
    +0267 decisions = table(ecModel.ec.rxns(:), stage(:), ecModel.ec.source(:), ecModel.ec.kcat(:), ...
    +0268     candidates(:), spread(:), sd(:), 'VariableNames', {'ecRxn','stage','source','kcat','candidates', ...
    +0269     'spreadLog10','sdLog10'});
    +0270 if p.writeReport
    +0271     outDir = fullfile(params.path, 'output');
    +0272     if ~isfolder(outDir)
    +0273         mkdir(outDir);
    +0274     end
    +0275     id = 'ecModel';
    +0276     if isfield(model, 'id') && ~isempty(model.id)
    +0277         id = char(model.id);
    +0278     end
    +0279     writetable(decisions, fullfile(outDir, [id '_kcatDecisions.tsv']), 'FileType', 'text', ...
    +0280         'Delimiter', '\t');
    +0281 end
    +0282 nOpen = sum(strcmp(stage, ''));
    +0283 fprintf('Kcats decided for %d of %d reactions.\n', numel(stage) - nOpen, numel(stage));
    +0284 end
    +0285 
    +0286 function s = normalizeSource(label)
    +0287 % As mergeKcats folds source labels: lower case, other characters as '_'.
    +0288 s = lower(strtrim(char(label)));
    +0289 s = regexprep(s, '[^0-9a-z]+', '_');
    +0290 s = regexprep(s, '^_+|_+$', '');
    +0291 end
    +0292 
    +0293 function name = sourceFile(token)
    +0294 % The source file a stage token reads: the BRENDA tiers read brenda.tsv.
    +0295 if startsWith(token, 'database_')
    +0296     name = 'brenda';
    +0297 else
    +0298     name = token;
    +0299 end
    +0300 end
    +0301 
    +0302 function checkOptions(args, names, functionName)
    +0303 % Options are name-value pairs with known names, so a misspelled option is
    +0304 % an error instead of being taken as a positional argument.
    +0305 id = [functionName ':arguments'];
    +0306 given = args(1:2:end);
    +0307 if mod(numel(args), 2) ~= 0 || ~all(cellfun(@(x) ischar(x) || (isstring(x) && isscalar(x)), given))
    +0308     error(id, 'Options of %s are name-value pairs. Options: %s.', functionName, strjoin(names, ', '))
    +0309 end
    +0310 unknown = setdiff(cellfun(@char, given, 'UniformOutput', false), names);
    +0311 if ~isempty(unknown)
    +0312     error(id, 'Unknown option of %s: %s. Options: %s.', functionName, strjoin(unknown, ', '), ...
    +0313         strjoin(names, ', '))
    +0314 end
    +0315 end
    +0316 
    +0317 function params = loadCombineParams(modelAdapter)
    +0318 % kcatCombineParams.tsv of the BRENDA folder, or of GECKO's BRENDA release.
    +0319 file = fullfile(modelAdapter.getBrendaDBFolder(), 'kcatCombineParams.tsv');
    +0320 if ~isfile(file)
    +0321     file = fullfile(fetchBrendaAsset({'kcatCombineParams.tsv'}), 'kcatCombineParams.tsv');
    +0322 end
    +0323 lines = strsplit(fileread(file), {'\r\n', '\n'});
    +0324 params.measurementSd = 0.48;
    +0325 params.minVariance = 0.01;
    +0326 params.scaleKeys = {};
    +0327 params.scales = [];
    +0328 k = 1;
    +0329 while k <= numel(lines) && startsWith(lines{k}, '#')
    +0330     tok = regexp(lines{k}, '^#\s*([^:]+):\s*(.*)$', 'tokens', 'once');
    +0331     if ~isempty(tok)
    +0332         key = strtrim(tok{1});
    +0333         value = str2double(strtrim(tok{2}));
    +0334         if strcmp(key, 'measurement_sd')
    +0335             params.measurementSd = value;
    +0336         elseif strcmp(key, 'min_variance')
    +0337             params.minVariance = value;
    +0338         elseif startsWith(key, 'interval_scale ')
    +0339             params.scaleKeys{end+1} = key(numel('interval_scale ')+1:end);
    +0340             params.scales(end+1) = value;
    +0341         end
    +0342     end
    +0343     k = k + 1;
    +0344 end
    +0345 header = strsplit(lines{k}, '\t');
    +0346 rows = lines(k+1:end);
    +0347 rows = rows(~cellfun(@isempty, strtrim(rows)));
    +0348 fields = cellfun(@(r) strsplit(r, '\t', 'CollapseDelimiters', false), rows, 'UniformOutput', false);
    +0349 fields = vertcat(fields{:});
    +0350 col = @(name) fields(:, strcmp(header, name));
    +0351 params.source = col('source');
    +0352 params.bin = col('bin');
    +0353 params.bias = str2double(col('bias'));
    +0354 params.variance = str2double(col('variance'));
    +0355 end
    +0356 
    +0357 function c = combineKcats(names, lists, openRxns, params)
    +0358 % One kcat per reaction from several sources: each source's value corrected
    +0359 % for its bias and weighted by 1 / its error variance, both for the
    +0360 % source's evidence bin (see evidenceBin). Several rows of one source for a
    +0361 % reaction give their median, with the bin of best evidence; a value
    +0362 % without a known bin gets the source's largest variance. geckopy's
    +0363 % combine_kcats does the same.
    +0364 unknown = setdiff(names, params.source);
    +0365 if ~isempty(unknown)
    +0366     error('collectKcats:combine', 'No combination parameters for %s; known sources: %s.', ...
    +0367         strjoin(unknown, ', '), strjoin(unique(params.source), ', '))
    +0368 end
    +0369 R = {}; S = {}; X = []; W = []; V = [];
    +0370 for k = 1:numel(names)
    +0371     name = names{k};
    +0372     list = lists{k};
    +0373     keep = ismember(list.rxns, openRxns) & list.kcats > 0 & isfinite(list.kcats);
    +0374     rxns = list.rxns(keep);
    +0375     values = log10(list.kcats(keep));
    +0376     details = list.detail(keep);
    +0377     mine = strcmp(params.source, name);
    +0378     srcBins = params.bin(mine);
    +0379     srcBias = params.bias(mine);
    +0380     srcVar = params.variance(mine);
    +0381     [~, worst] = max(srcVar);
    +0382     [u, ~, g] = unique(rxns, 'stable');
    +0383     for r = 1:numel(u)
    +0384         rows = find(g == r);
    +0385         bins = cellfun(@(d) evidenceBin(name, d), details(rows), 'UniformOutput', false);
    +0386         [found, where] = ismember(bins, srcBins);
    +0387         if any(found)
    +0388             [~, best] = min(srcVar(where(found)));
    +0389             pick = where(found);
    +0390             pick = pick(best);
    +0391         else
    +0392             pick = worst;
    +0393         end
    +0394         R{end+1, 1} = u{r}; %#ok<AGROW>
    +0395         S{end+1, 1} = name; %#ok<AGROW>
    +0396         V(end+1, 1) = median(values(rows)); %#ok<AGROW>
    +0397         X(end+1, 1) = median(values(rows)) - srcBias(pick); %#ok<AGROW>
    +0398         W(end+1, 1) = 1 / max(srcVar(pick), params.minVariance); %#ok<AGROW>
    +0399     end
    +0400 end
    +0401 [u, ~, g] = unique(R, 'stable');
    +0402 c.rxns = u;
    +0403 n = numel(u);
    +0404 c.kcats = zeros(n, 1); c.sd = zeros(n, 1); c.n = zeros(n, 1); c.spread = zeros(n, 1);
    +0405 for r = 1:n
    +0406     rows = g == r;
    +0407     w = W(rows);
    +0408     c.kcats(r) = 10 ^ (sum(w .* X(rows)) / sum(w));
    +0409     srcs = S(rows);
    +0410     hasOkp = any(startsWith(srcs, 'okp_'));
    +0411     hasTree = any(strcmp(srcs, 'ec_tree'));
    +0412     if hasTree && hasOkp
    +0413         key = 'ec_tree+okp';
    +0414     elseif hasOkp
    +0415         key = 'okp';
    +0416     elseif hasTree
    +0417         key = 'ec_tree+homologs';
    +0418     else
    +0419         key = '';
    +0420     end
    +0421     scale = 1;
    +0422     hit = strcmp(params.scaleKeys, key);
    +0423     if any(hit)
    +0424         scale = params.scales(find(hit, 1));
    +0425     end
    +0426     c.sd(r) = sqrt(1 / sum(w) + params.measurementSd ^ 2) * scale;
    +0427     c.n(r) = sum(rows);
    +0428     c.spread(r) = max(V(rows)) - min(V(rows));
    +0429 end
    +0430 end
    +0431 
    +0432 function b = evidenceBin(source, detail)
    +0433 % The evidence bin of a source's value, from its detail column.
    +0434 b = '';
    +0435 if strcmp(source, 'ec_tree')
    +0436     n = regexp(detail, 'n=(\d+)', 'tokens', 'once');
    +0437     depth = regexp(detail, 'depth=(\d)', 'tokens', 'once');
    +0438     if ~isempty(depth) && strcmp(depth{1}, '4') && ~isempty(n)
    +0439         v = str2double(n{1});
    +0440         edges = [2 5 20 100];
    +0441         labels = {'1-2', '3-5', '6-20', '21-100', '>100'};
    +0442         b = ['ec4:' labels{find([v <= edges, true], 1)}];
    +0443     elseif ~isempty(depth)
    +0444         b = ['ec' depth{1}];
    +0445     else
    +0446         b = 'ec0';
    +0447     end
    +0448 elseif strcmp(source, 'homologs')
    +0449     t = regexp(detail, 'identity=([\d.]+)', 'tokens', 'once');
    +0450     if ~isempty(t) && str2double(t{1}) >= 0.95
    +0451         b = 'exact'; % the same protein: an assumed bin, see kcatCombineParams.tsv
    +0452     elseif ~isempty(t)
    +0453         labels = {'40', '50', '60', '70', '80', '90'};
    +0454         b = labels{find([str2double(t{1}) <= [0.5 0.6 0.7 0.8 0.9], true], 1)};
    +0455     end
    +0456 elseif startsWith(source, 'okp_')
    +0457     t = regexp(detail, 'similarity=([\d.]+)', 'tokens', 'once');
    +0458     if ~isempty(t)
    +0459         labels = {'<40', '40-60', '60-80', '>80'};
    +0460         b = labels{find([str2double(t{1}) <= [40 60 80], true], 1)};
    +0461     end
    +0462 end
    +0463 end
    +
    Generated by m2html © 2005
    + + \ No newline at end of file diff --git a/doc/src/gather_kcats/convertCustomKcats.html b/doc/src/gather_kcats/convertCustomKcats.html new file mode 100644 index 00000000..8d6b2950 --- /dev/null +++ b/doc/src/gather_kcats/convertCustomKcats.html @@ -0,0 +1,233 @@ + + + + Description of convertCustomKcats + + + + + + + + + +
    Home > src > gather_kcats > convertCustomKcats.m
    + + + +

    convertCustomKcats +

    + +

    PURPOSE ^

    +
    convertCustomKcats Convert data/customKcats.tsv into data/kcats/custom.tsv.
    + +

    SYNOPSIS ^

    +
    function [file, report] = convertCustomKcats(model, varargin)
    + +

    DESCRIPTION ^

    +
     convertCustomKcats  Convert data/customKcats.tsv into data/kcats/custom.tsv.
    +
    + Writes the custom kcats of a GECKO 3 project as the curated kcat source
    + file data/kcats/custom.tsv, which collectKcats reads first. The kcats are
    + those applyCustomKcats gives the ecModel, including which of two entries
    + for the same reaction wins: one row per reaction, keyed by conventional
    + reaction and enzyme set (see getEcRxnKeys), with the entry's notes in the
    + note column. The stoicho column is left out: complex stoichiometry comes
    + from applyComplexData. Unlike applyCustomKcats, custom.tsv also applies to
    + light ecModels. geckopy has the same (convert_custom_kcats).
    +
    + Parameters
    + ----------
    + model : struct
    +     the full ecModel the custom kcats are for (with EC data).
    +
    + Name-Value Arguments
    + --------------------
    + modelAdapter : ModelAdapter
    +     a loaded model adapter (default: the current default model adapter).
    + customKcats : char
    +     the file to convert (default: data/customKcats.tsv in the project).
    + outFile : char
    +     the file to write (default: data/kcats/custom.tsv in the project). An
    +     existing file is not overwritten.
    +
    + Returns
    + -------
    + file : char
    +     the file written.
    + report : struct
    +     - rows: number of rows written;
    +     - partial: reactions whose enzymes only partly match an entry, which
    +       applyCustomKcats does not change either (its notMatch).
    +
    + Examples
    + --------
    +     convertCustomKcats(ecModel);   % then collectKcats/assignKcats read custom.tsv
    +
    + See also
    + --------
    + collectKcats, applyCustomKcats, getEcRxnKeys, upgradeGECKOproject
    + + +

    CROSS-REFERENCE INFORMATION ^

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

    SUBFUNCTIONS ^

    + + +

    SOURCE CODE ^

    +
    0001 function [file, report] = convertCustomKcats(model, varargin)
    +0002 % convertCustomKcats  Convert data/customKcats.tsv into data/kcats/custom.tsv.
    +0003 %
    +0004 % Writes the custom kcats of a GECKO 3 project as the curated kcat source
    +0005 % file data/kcats/custom.tsv, which collectKcats reads first. The kcats are
    +0006 % those applyCustomKcats gives the ecModel, including which of two entries
    +0007 % for the same reaction wins: one row per reaction, keyed by conventional
    +0008 % reaction and enzyme set (see getEcRxnKeys), with the entry's notes in the
    +0009 % note column. The stoicho column is left out: complex stoichiometry comes
    +0010 % from applyComplexData. Unlike applyCustomKcats, custom.tsv also applies to
    +0011 % light ecModels. geckopy has the same (convert_custom_kcats).
    +0012 %
    +0013 % Parameters
    +0014 % ----------
    +0015 % model : struct
    +0016 %     the full ecModel the custom kcats are for (with EC data).
    +0017 %
    +0018 % Name-Value Arguments
    +0019 % --------------------
    +0020 % modelAdapter : ModelAdapter
    +0021 %     a loaded model adapter (default: the current default model adapter).
    +0022 % customKcats : char
    +0023 %     the file to convert (default: data/customKcats.tsv in the project).
    +0024 % outFile : char
    +0025 %     the file to write (default: data/kcats/custom.tsv in the project). An
    +0026 %     existing file is not overwritten.
    +0027 %
    +0028 % Returns
    +0029 % -------
    +0030 % file : char
    +0031 %     the file written.
    +0032 % report : struct
    +0033 %     - rows: number of rows written;
    +0034 %     - partial: reactions whose enzymes only partly match an entry, which
    +0035 %       applyCustomKcats does not change either (its notMatch).
    +0036 %
    +0037 % Examples
    +0038 % --------
    +0039 %     convertCustomKcats(ecModel);   % then collectKcats/assignKcats read custom.tsv
    +0040 %
    +0041 % See also
    +0042 % --------
    +0043 % collectKcats, applyCustomKcats, getEcRxnKeys, upgradeGECKOproject
    +0044 
    +0045 checkOptions(varargin, {'modelAdapter','customKcats','outFile'}, 'convertCustomKcats');
    +0046 p = parseGECKOargs(varargin, {'modelAdapter', []; 'customKcats', []; 'outFile', []});
    +0047 modelAdapter = p.modelAdapter;
    +0048 if isempty(modelAdapter)
    +0049     modelAdapter = ModelAdapterManager.getDefault();
    +0050     if isempty(modelAdapter)
    +0051         error('Either send in a modelAdapter or set the default model adapter in the ModelAdapterManager.')
    +0052     end
    +0053 end
    +0054 if model.ec.geckoLight
    +0055     error('convertCustomKcats:light', ['applyCustomKcats does not work on light ecModels; give ' ...
    +0056         'the full ecModel. The custom.tsv written applies to light ecModels too.'])
    +0057 end
    +0058 inFile = p.customKcats;
    +0059 if isempty(inFile)
    +0060     inFile = fullfile(modelAdapter.params.path, 'data', 'customKcats.tsv');
    +0061 end
    +0062 file = p.outFile;
    +0063 if isempty(file)
    +0064     file = fullfile(modelAdapter.params.path, 'data', 'kcats', 'custom.tsv');
    +0065 end
    +0066 if ~isfile(inFile)
    +0067     error('convertCustomKcats:missing', 'No custom kcats file %s.', inFile)
    +0068 end
    +0069 if isfile(file)
    +0070     error('convertCustomKcats:exists', '%s exists and is not overwritten.', file)
    +0071 end
    +0072 
    +0073 base = model;
    +0074 base.ec.notes(:) = {''};
    +0075 [applied, rxnUpdated, notMatch] = applyCustomKcats(base, 'customKcats', inFile, 'modelAdapter', modelAdapter);
    +0076 idx = find(ismember(applied.ec.rxns, rxnUpdated));
    +0077 [baseRxns, enzymeSets] = getEcRxnKeys(applied);
    +0078 rows = strings(numel(idx), 9);
    +0079 for k = 1:numel(idx)
    +0080     i = idx(k);
    +0081     note = regexprep(applied.ec.notes{i}, '[\t\r\n]', ' ');
    +0082     rows(k, :) = [string(baseRxns{i}), string(enzymeSets{i}), "", formatNumber(applied.ec.kcat(i)), ...
    +0083         "", "custom", "", "", string(note)];
    +0084 end
    +0085 % Isozymic copies of one conventional reaction share a key and a value.
    +0086 if ~isempty(rows)
    +0087     [~, first] = unique(join(rows(:, 1:2), char(1), 2), 'stable');
    +0088     rows = rows(sort(first), :);
    +0089     [~, order] = sort(join(rows(:, [1 2 3 6 4 5 7 8 9]), char(1), 2));
    +0090     rows = rows(order, :);
    +0091 end
    +0092 
    +0093 folder = fileparts(file);
    +0094 if ~isfolder(folder)
    +0095     mkdir(folder);
    +0096 end
    +0097 gecko = strtrim(fileread(fullfile(findGECKOroot(), 'version.txt')));
    +0098 [~, name, ext] = fileparts(inFile);
    +0099 fid = fopen(file, 'w', 'n', 'UTF-8');
    +0100 fprintf(fid, '# source: custom\n');
    +0101 fprintf(fid, '# generator: convertCustomKcats (GECKO %s)\n', gecko);
    +0102 fprintf(fid, '# parameters: {}\n');
    +0103 fprintf(fid, '# data: %s\n', [name ext]);
    +0104 fprintf(fid, '# kind: curated\n');
    +0105 fprintf(fid, '# created: %s\n', char(datetime('now', 'TimeZone', 'UTC', 'Format', 'yyyy-MM-dd''T''HH:mm:ss''Z''')));
    +0106 fprintf(fid, 'rxn\tenzymes\tsubstrate\tkcat\tlog10_sd\tsource\tdetail\tec_code\tnote\n');
    +0107 if ~isempty(rows)
    +0108     fprintf(fid, '%s\n', join(rows, sprintf('\t'), 2));
    +0109 end
    +0110 fclose(fid);
    +0111 report.rows = size(rows, 1);
    +0112 report.partial = notMatch;
    +0113 fprintf('%d custom kcats written to %s.\n', report.rows, file);
    +0114 end
    +0115 
    +0116 function t = formatNumber(x)
    +0117 % The shortest text that reads back as x, as saveKcatSource writes numbers.
    +0118 if x == round(x) && abs(x) < 1e15
    +0119     t = string(sprintf('%d', x));
    +0120     return
    +0121 end
    +0122 for digits = 1:17
    +0123     t = string(sprintf(sprintf('%%.%dg', digits), x));
    +0124     if str2double(t) == x
    +0125         return
    +0126     end
    +0127 end
    +0128 end
    +0129 
    +0130 function checkOptions(args, names, functionName)
    +0131 % Options are name-value pairs with known names, so a misspelled option is
    +0132 % an error instead of being taken as a positional argument.
    +0133 id = [functionName ':arguments'];
    +0134 given = args(1:2:end);
    +0135 if mod(numel(args), 2) ~= 0 || ~all(cellfun(@(x) ischar(x) || (isstring(x) && isscalar(x)), given))
    +0136     error(id, 'Options of %s are name-value pairs. Options: %s.', functionName, strjoin(names, ', '))
    +0137 end
    +0138 unknown = setdiff(cellfun(@char, given, 'UniformOutput', false), names);
    +0139 if ~isempty(unknown)
    +0140     error(id, 'Unknown option of %s: %s. Options: %s.', functionName, strjoin(unknown, ', '), ...
    +0141         strjoin(names, ', '))
    +0142 end
    +0143 end
    +
    Generated by m2html © 2005
    + + \ No newline at end of file diff --git a/doc/src/gather_kcats/ecStatsFromBrenda.html b/doc/src/gather_kcats/ecStatsFromBrenda.html new file mode 100644 index 00000000..adfb6845 --- /dev/null +++ b/doc/src/gather_kcats/ecStatsFromBrenda.html @@ -0,0 +1,134 @@ + + + + Description of ecStatsFromBrenda + + + + + + + + + +
    Home > src > gather_kcats > ecStatsFromBrenda.m
    + + + +

    ecStatsFromBrenda +

    + +

    PURPOSE ^

    +
    ecStatsFromBrenda Summarise loadBRENDAdata's output per EC number, for
    + +

    SYNOPSIS ^

    +
    function ecStats = ecStatsFromBrenda(KCATcell,SAcell)
    + +

    DESCRIPTION ^

    +
     ecStatsFromBrenda  Summarise loadBRENDAdata's output per EC number, for
    + reviewKcatAssignment's ecStats argument.
    +
    + TODO: verify against a real BRENDA pull before relying on this. Ported
    + from geckopy's ec_stats_from_brenda without being able to run it
    + against real BRENDA data in this environment. In particular,
    + loadBRENDAdata's KCATcell only carries the BRENDA *max* aggregate per
    + (EC, substrate, organism) triple (column 4 of kcat.tsv) -- the median
    + column is read internally but discarded before KCATcell is returned --
    + so kcatMedian below is always NaN, and reviewKcatAssignment's
    + "ec-maximum" check (which needs a finite kcatMedian) will never fire
    + until loadBRENDAdata is extended to also expose it.
    +
    + Parameters
    + ----------
    + KCATcell : cell
    +     as returned by loadBRENDAdata's first output: {ecCode, substrate,
    +     organism, kcatMax}.
    + SAcell : cell
    +     as returned by loadBRENDAdata's second output: {ecCode, organism,
    +     kcatFromSA, mw}.
    +
    + Returns
    + -------
    + ecStats : containers.Map
    +     EC code -> struct(nKcat,kcatMax,kcatMedian,values,nSa), keyed by
    +     the same (uppercased) EC strings BRENDA uses.
    +
    + See also
    + --------
    + reviewKcatAssignment, loadBRENDAdata
    + + +

    CROSS-REFERENCE INFORMATION ^

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

    SOURCE CODE ^

    +
    0001 function ecStats = ecStatsFromBrenda(KCATcell,SAcell)
    +0002 % ecStatsFromBrenda  Summarise loadBRENDAdata's output per EC number, for
    +0003 % reviewKcatAssignment's ecStats argument.
    +0004 %
    +0005 % TODO: verify against a real BRENDA pull before relying on this. Ported
    +0006 % from geckopy's ec_stats_from_brenda without being able to run it
    +0007 % against real BRENDA data in this environment. In particular,
    +0008 % loadBRENDAdata's KCATcell only carries the BRENDA *max* aggregate per
    +0009 % (EC, substrate, organism) triple (column 4 of kcat.tsv) -- the median
    +0010 % column is read internally but discarded before KCATcell is returned --
    +0011 % so kcatMedian below is always NaN, and reviewKcatAssignment's
    +0012 % "ec-maximum" check (which needs a finite kcatMedian) will never fire
    +0013 % until loadBRENDAdata is extended to also expose it.
    +0014 %
    +0015 % Parameters
    +0016 % ----------
    +0017 % KCATcell : cell
    +0018 %     as returned by loadBRENDAdata's first output: {ecCode, substrate,
    +0019 %     organism, kcatMax}.
    +0020 % SAcell : cell
    +0021 %     as returned by loadBRENDAdata's second output: {ecCode, organism,
    +0022 %     kcatFromSA, mw}.
    +0023 %
    +0024 % Returns
    +0025 % -------
    +0026 % ecStats : containers.Map
    +0027 %     EC code -> struct(nKcat,kcatMax,kcatMedian,values,nSa), keyed by
    +0028 %     the same (uppercased) EC strings BRENDA uses.
    +0029 %
    +0030 % See also
    +0031 % --------
    +0032 % reviewKcatAssignment, loadBRENDAdata
    +0033 ecCol  = upper(KCATcell{1});
    +0034 maxCol = KCATcell{4};
    +0035 
    +0036 saEcCol = {};
    +0037 if ~isempty(SAcell) && numel(SAcell) >= 1 && ~isempty(SAcell{1})
    +0038     saEcCol = upper(SAcell{1});
    +0039 end
    +0040 
    +0041 ecList = unique([ecCol(:); saEcCol(:)]);
    +0042 ecStats = containers.Map('KeyType','char','ValueType','any');
    +0043 for i = 1:numel(ecList)
    +0044     ec = char(ecList{i});
    +0045     rows = strcmp(ecCol,ec);
    +0046     nKcat = sum(rows);
    +0047     if nKcat > 0
    +0048         kcatMax = max(maxCol(rows));
    +0049         values  = unique(round(maxCol(rows),6));
    +0050     else
    +0051         kcatMax = NaN;
    +0052         values  = [];
    +0053     end
    +0054     nSa = sum(strcmp(saEcCol,ec));
    +0055     ecStats(ec) = struct('nKcat',nKcat,'kcatMax',kcatMax,'kcatMedian',NaN,'values',values,'nSa',nSa);
    +0056 end
    +0057 end
    +
    Generated by m2html © 2005
    + + \ No newline at end of file diff --git a/doc/src/gather_kcats/ecTreeEstimate.html b/doc/src/gather_kcats/ecTreeEstimate.html new file mode 100644 index 00000000..49c12867 --- /dev/null +++ b/doc/src/gather_kcats/ecTreeEstimate.html @@ -0,0 +1,212 @@ + + + + Description of ecTreeEstimate + + + + + + + + + +
    Home > src > gather_kcats > ecTreeEstimate.m
    + + + +

    ecTreeEstimate +

    + +

    PURPOSE ^

    +
    ecTreeEstimate EC-tree kcat estimates for EC numbers.
    + +

    SYNOPSIS ^

    +
    function [log10kcat, n, depth, ecUsed] = ecTreeEstimate(eccodes, measurements, k)
    + +

    DESCRIPTION ^

    +
     ecTreeEstimate  EC-tree kcat estimates for EC numbers.
    +
    + For each EC number, the median log10 kcat of its measurements is pulled
    + toward the estimate of its parent class with weight n / (n + k), where n
    + is the number of measurements: the global median, then the 2-digit
    + class, the 3-digit class and the full EC number, in that order. A
    + well-measured EC keeps its own median; a sparsely measured one leans on
    + its class. geckopy has the same (geckopy.gather_kcats.ec_tree.ECTree).
    +
    + Parameters
    + ----------
    + eccodes : cell
    +     per query one or more EC numbers separated by ';'. The one with most
    +     measurements of its full EC is used (the first on a tie).
    + measurements : struct
    +     BRENDA measurement table with fields ec and log10kcat (see
    +     loadBrendaMeasurements).
    + k : double
    +     shrinkage constant (default 5): the number of measurements at which
    +     an EC's own median and its class count equally.
    +
    + Returns
    + -------
    + log10kcat : double
    +     the estimates; the global median for queries without measurements.
    + n : double
    +     number of measurements of the full EC number used.
    + depth : double
    +     deepest EC level with measurements: 4, 3, 2, or 0 when there are
    +     none (or no EC number).
    + ecUsed : cell
    +     the EC number used.
    +
    + Examples
    + --------
    +     m = loadBrendaMeasurements();
    +     [v, n, depth] = ecTreeEstimate({'1.1.1.1'; '2.7.1.1;2.7.1.2'}, m);
    +     kcat = 10.^v;
    +
    + See also
    + --------
    + kcatsFromECTree, loadBrendaMeasurements
    + + +

    CROSS-REFERENCE INFORMATION ^

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

    SUBFUNCTIONS ^

    + + +

    SOURCE CODE ^

    +
    0001 function [log10kcat, n, depth, ecUsed] = ecTreeEstimate(eccodes, measurements, k)
    +0002 % ecTreeEstimate  EC-tree kcat estimates for EC numbers.
    +0003 %
    +0004 % For each EC number, the median log10 kcat of its measurements is pulled
    +0005 % toward the estimate of its parent class with weight n / (n + k), where n
    +0006 % is the number of measurements: the global median, then the 2-digit
    +0007 % class, the 3-digit class and the full EC number, in that order. A
    +0008 % well-measured EC keeps its own median; a sparsely measured one leans on
    +0009 % its class. geckopy has the same (geckopy.gather_kcats.ec_tree.ECTree).
    +0010 %
    +0011 % Parameters
    +0012 % ----------
    +0013 % eccodes : cell
    +0014 %     per query one or more EC numbers separated by ';'. The one with most
    +0015 %     measurements of its full EC is used (the first on a tie).
    +0016 % measurements : struct
    +0017 %     BRENDA measurement table with fields ec and log10kcat (see
    +0018 %     loadBrendaMeasurements).
    +0019 % k : double
    +0020 %     shrinkage constant (default 5): the number of measurements at which
    +0021 %     an EC's own median and its class count equally.
    +0022 %
    +0023 % Returns
    +0024 % -------
    +0025 % log10kcat : double
    +0026 %     the estimates; the global median for queries without measurements.
    +0027 % n : double
    +0028 %     number of measurements of the full EC number used.
    +0029 % depth : double
    +0030 %     deepest EC level with measurements: 4, 3, 2, or 0 when there are
    +0031 %     none (or no EC number).
    +0032 % ecUsed : cell
    +0033 %     the EC number used.
    +0034 %
    +0035 % Examples
    +0036 % --------
    +0037 %     m = loadBrendaMeasurements();
    +0038 %     [v, n, depth] = ecTreeEstimate({'1.1.1.1'; '2.7.1.1;2.7.1.2'}, m);
    +0039 %     kcat = 10.^v;
    +0040 %
    +0041 % See also
    +0042 % --------
    +0043 % kcatsFromECTree, loadBrendaMeasurements
    +0044 
    +0045 if nargin < 3 || isempty(k)
    +0046     k = 5;
    +0047 end
    +0048 if ~(isnumeric(k) && isscalar(k) && k > 0)
    +0049     error('ecTreeEstimate:k', 'k must be a positive number.')
    +0050 end
    +0051 if ischar(eccodes) || isstring(eccodes)
    +0052     eccodes = cellstr(eccodes);
    +0053 end
    +0054 ec = measurements.ec(:);
    +0055 v = measurements.log10kcat(:);
    +0056 globalMedian = median(v);
    +0057 lv = cell(4, 1);
    +0058 for d = [2 3 4]
    +0059     if d == 4
    +0060         key = ec;
    +0061     else
    +0062         key = cellfun(@(e) parentEC(e, d), ec, 'UniformOutput', false);
    +0063     end
    +0064     [keys, ~, g] = unique(key);
    +0065     lv{d} = struct('keys', {keys}, 'median', accumarray(g, v, [], @median), ...
    +0066         'n', accumarray(g, 1));
    +0067 end
    +0068 
    +0069 nq = numel(eccodes);
    +0070 log10kcat = repmat(globalMedian, nq, 1);
    +0071 n = zeros(nq, 1);
    +0072 depth = zeros(nq, 1);
    +0073 ecUsed = repmat({''}, nq, 1);
    +0074 for q = 1:nq
    +0075     ecs = strtrim(strsplit(char(eccodes{q}), ';'));
    +0076     ecs = ecs(~cellfun(@isempty, ecs));
    +0077     if isempty(ecs)
    +0078         continue
    +0079     end
    +0080     best = ecs{1};
    +0081     bestN = -1;
    +0082     for e = 1:numel(ecs)
    +0083         c = countOf(lv{4}, ecs{e});
    +0084         if c > bestN
    +0085             best = ecs{e};
    +0086             bestN = c;
    +0087         end
    +0088     end
    +0089     value = globalMedian;
    +0090     for d = [2 3 4]
    +0091         if d == 4
    +0092             key = best;
    +0093         else
    +0094             key = parentEC(best, d);
    +0095         end
    +0096         [c, med] = countOf(lv{d}, key);
    +0097         if c > 0
    +0098             w = c / (c + k);
    +0099             value = w * med + (1 - w) * value;
    +0100             depth(q) = d;
    +0101         end
    +0102     end
    +0103     log10kcat(q) = value;
    +0104     n(q) = bestN;
    +0105     ecUsed{q} = best;
    +0106 end
    +0107 end
    +0108 
    +0109 function p = parentEC(ec, d)
    +0110 parts = strsplit(ec, '.');
    +0111 p = strjoin(parts(1:min(d, numel(parts))), '.');
    +0112 end
    +0113 
    +0114 function [c, med] = countOf(level, key)
    +0115 [found, i] = ismember(key, level.keys);
    +0116 c = 0;
    +0117 med = NaN;
    +0118 if found
    +0119     c = level.n(i);
    +0120     med = level.median(i);
    +0121 end
    +0122 end
    +
    Generated by m2html © 2005
    + + \ No newline at end of file diff --git a/doc/src/gather_kcats/extractEnzymeSubstratePairs.html b/doc/src/gather_kcats/extractEnzymeSubstratePairs.html new file mode 100644 index 00000000..707d7f79 --- /dev/null +++ b/doc/src/gather_kcats/extractEnzymeSubstratePairs.html @@ -0,0 +1,225 @@ + + + + Description of extractEnzymeSubstratePairs + + + + + + + + + +
    Home > src > gather_kcats > extractEnzymeSubstratePairs.m
    + + + +

    extractEnzymeSubstratePairs +

    + +

    PURPOSE ^

    +
    extractEnzymeSubstratePairs The enzyme-substrate pairs of an ecModel's reactions.
    + +

    SYNOPSIS ^

    +
    function pairs = extractEnzymeSubstratePairs(model, varargin)
    + +

    DESCRIPTION ^

    +
     extractEnzymeSubstratePairs  The enzyme-substrate pairs of an ecModel's reactions.
    +
    + Lists, for each model.ec reaction, its enzymes and its substrates as
    + DLKcat and the homolog search use them: the reactants of the reaction,
    + without the metabolites of DLKcatIgnoreMets.tsv (metal ions, small
    + molecules), without protein pseudometabolites, and without currency
    + metabolites of DLKcatCurrencyMets.tsv where both members of a pair take
    + part (unless no other substrate remains). Both files are read from the
    + data folder of the project, or else from the databases folder of GECKO.
    + geckopy has the same (extract_enzyme_substrate_pairs).
    +
    + Parameters
    + ----------
    + model : struct
    +     an ecModel in GECKO 3 format (with ecModel.ec structure).
    +
    + Name-Value Arguments
    + --------------------
    + ecRxns : logical
    +     which model.ec.rxns to list (default: all).
    + modelAdapter : ModelAdapter
    +     a loaded model adapter (default: the current default model adapter).
    +
    + Returns
    + -------
    + pairs : struct
    +     ecRxn (index into model.ec.rxns), protein (index into model.ec.genes,
    +     model.ec.enzymes and model.ec.sequence) and met (index into
    +     model.mets), one entry per pair, reaction by reaction.
    +
    + Examples
    + --------
    +     pairs = extractEnzymeSubstratePairs(ecModel);
    +     model.metNames(pairs.met(1:5))
    +
    + See also
    + --------
    + writeDLKcatInput, kcatsFromHomologs
    + + +

    CROSS-REFERENCE INFORMATION ^

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

    SOURCE CODE ^

    +
    0001 function pairs = extractEnzymeSubstratePairs(model, varargin)
    +0002 % extractEnzymeSubstratePairs  The enzyme-substrate pairs of an ecModel's reactions.
    +0003 %
    +0004 % Lists, for each model.ec reaction, its enzymes and its substrates as
    +0005 % DLKcat and the homolog search use them: the reactants of the reaction,
    +0006 % without the metabolites of DLKcatIgnoreMets.tsv (metal ions, small
    +0007 % molecules), without protein pseudometabolites, and without currency
    +0008 % metabolites of DLKcatCurrencyMets.tsv where both members of a pair take
    +0009 % part (unless no other substrate remains). Both files are read from the
    +0010 % data folder of the project, or else from the databases folder of GECKO.
    +0011 % geckopy has the same (extract_enzyme_substrate_pairs).
    +0012 %
    +0013 % Parameters
    +0014 % ----------
    +0015 % model : struct
    +0016 %     an ecModel in GECKO 3 format (with ecModel.ec structure).
    +0017 %
    +0018 % Name-Value Arguments
    +0019 % --------------------
    +0020 % ecRxns : logical
    +0021 %     which model.ec.rxns to list (default: all).
    +0022 % modelAdapter : ModelAdapter
    +0023 %     a loaded model adapter (default: the current default model adapter).
    +0024 %
    +0025 % Returns
    +0026 % -------
    +0027 % pairs : struct
    +0028 %     ecRxn (index into model.ec.rxns), protein (index into model.ec.genes,
    +0029 %     model.ec.enzymes and model.ec.sequence) and met (index into
    +0030 %     model.mets), one entry per pair, reaction by reaction.
    +0031 %
    +0032 % Examples
    +0033 % --------
    +0034 %     pairs = extractEnzymeSubstratePairs(ecModel);
    +0035 %     model.metNames(pairs.met(1:5))
    +0036 %
    +0037 % See also
    +0038 % --------
    +0039 % writeDLKcatInput, kcatsFromHomologs
    +0040 
    +0041 [geckoPath, ~] = findGECKOroot();
    +0042 p = parseGECKOargs(varargin, {'ecRxns', []; 'modelAdapter', []});
    +0043 ecRxnsSel = p.ecRxns;
    +0044 if isempty(ecRxnsSel)
    +0045     ecRxnsSel = true(numel(model.ec.rxns),1);
    +0046 elseif ~islogical(ecRxnsSel)
    +0047     error('ecRxns should be provided as logical vector')
    +0048 elseif numel(ecRxnsSel)~=numel(model.ec.rxns)
    +0049     error('Length of ecRxns is not the same as model.ec.rxns')
    +0050 end
    +0051 ecRxnsSel = find(ecRxnsSel);
    +0052 modelAdapter = p.modelAdapter;
    +0053 if isempty(modelAdapter)
    +0054     modelAdapter = ModelAdapterManager.getDefault();
    +0055     if isempty(modelAdapter)
    +0056         error('Either send in a modelAdapter or set the default model adapter in the ModelAdapterManager.')
    +0057     end
    +0058 end
    +0059 params = modelAdapter.params;
    +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(ecRxnsSel);
    +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 % origRxnIdxs already selects exactly the model.rxns columns for the requested
    +0125 % ecRxns subset (one column per requested reaction, via origRxns(ecRxns) above), so
    +0126 % clearedRedS needs no further filtering here.
    +0127 clearedRedS = reducedS(:,origRxnIdxs);
    +0128 
    +0129 % Enumerate all substrates for each reaction. clearedRedS has one column per entry
    +0130 % of ecRxnsSel, in that same order, so `reactions` here indexes *that subset*, not
    +0131 % model.ec.rxns directly --- translate back to a real model.ec.rxns index before
    +0132 % using it against model.ec.rxns / model.ec.rxnEnzMat, which are always full-length.
    +0133 [substrates, reactions] = find(clearedRedS<0);
    +0134 globalEcRxns = ecRxnsSel(reactions);
    +0135 
    +0136 % Enumerate all proteins for each reaction
    +0137 [proteins, enzRows] = find(transpose(model.ec.rxnEnzMat(globalEcRxns,:)));
    +0138 pairs.ecRxn   = reshape(globalEcRxns(enzRows), [], 1);
    +0139 pairs.protein = reshape(proteins, [], 1);
    +0140 pairs.met     = reshape(substrates(enzRows), [], 1);
    +0141 end
    +
    Generated by m2html © 2005
    + + \ No newline at end of file diff --git a/doc/src/gather_kcats/fetchOpenKineticsPredictor.html b/doc/src/gather_kcats/fetchOpenKineticsPredictor.html new file mode 100644 index 00000000..0291aaba --- /dev/null +++ b/doc/src/gather_kcats/fetchOpenKineticsPredictor.html @@ -0,0 +1,266 @@ + + + + Description of fetchOpenKineticsPredictor + + + + + + + + + +
    Home > src > gather_kcats > fetchOpenKineticsPredictor.m
    + + + +

    fetchOpenKineticsPredictor +

    + +

    PURPOSE ^

    +
    fetchOpenKineticsPredictor Fetch and parse an OpenKineticsPredictor job.
    + +

    SYNOPSIS ^

    +
    function [done, kcatList] = fetchOpenKineticsPredictor(model, varargin)
    + +

    DESCRIPTION ^

    +
     fetchOpenKineticsPredictor  Fetch and parse an OpenKineticsPredictor job.
    +
    + Checks the status of an OpenKineticsPredictor job and, when it has
    + finished, downloads the result to data/OKP_output.csv and parses it (via
    + readOpenKineticsPredictorOutput) into a kcatList consumable by
    + assignKcatValues.
    +
    + The API key (only needed when useStored=false) is resolved from the
    + OKP_API_KEY environment variable or data/okpApiKey.txt; see
    + submitOpenKineticsPredictor for how to obtain and store a key.
    +
    + Parameters
    + ----------
    + model : struct
    +     ecModel in GECKO 3 format (with ecModel.ec structure; model.metSmiles
    +     is required to map results back).
    +
    + Name-Value Arguments
    + --------------------
    + useStored : logical
    +     if true, skip the API entirely and parse the already-downloaded
    +     data/OKP_output.csv. If false, query the API (default false).
    + jobId : char
    +     OKP job id (default: read from data/OKP_job.txt, written by
    +     submitOpenKineticsPredictor).
    + wait : logical
    +     if true, poll until the job finishes; if false, report once and
    +     return (default false).
    + pollInterval : double
    +     seconds between polls when wait=true (default 30).
    + outFile : char
    +     where the result is stored, and read from with useStored=true
    +     (default: data/OKP_output.csv).
    + modelAdapter : ModelAdapter
    +     a loaded model adapter (default: the current default model adapter).
    +
    + Returns
    + -------
    + done : logical
    +     true if a result was obtained (downloaded or loaded from disk).
    + kcatList : struct
    +     structure with kcat values (empty when not done); see
    +     readOpenKineticsPredictorOutput for its fields (source, rxns, genes,
    +     substrates, kcats, kcatSource).
    +
    + Examples
    + --------
    +     [done, kcatList] = fetchOpenKineticsPredictor(model);                        % check once
    +     [done, kcatList] = fetchOpenKineticsPredictor(model, 'wait', true);          % poll
    +     [done, kcatList] = fetchOpenKineticsPredictor(model, 'useStored', true);     % parse stored file
    +
    + See also
    + --------
    + submitOpenKineticsPredictor, readOpenKineticsPredictorOutput
    + + +

    CROSS-REFERENCE INFORMATION ^

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

    SUBFUNCTIONS ^

    + + +

    SOURCE CODE ^

    +
    0001 function [done, kcatList] = fetchOpenKineticsPredictor(model, varargin)
    +0002 % fetchOpenKineticsPredictor  Fetch and parse an OpenKineticsPredictor job.
    +0003 %
    +0004 % Checks the status of an OpenKineticsPredictor job and, when it has
    +0005 % finished, downloads the result to data/OKP_output.csv and parses it (via
    +0006 % readOpenKineticsPredictorOutput) into a kcatList consumable by
    +0007 % assignKcatValues.
    +0008 %
    +0009 % The API key (only needed when useStored=false) is resolved from the
    +0010 % OKP_API_KEY environment variable or data/okpApiKey.txt; see
    +0011 % submitOpenKineticsPredictor for how to obtain and store a key.
    +0012 %
    +0013 % Parameters
    +0014 % ----------
    +0015 % model : struct
    +0016 %     ecModel in GECKO 3 format (with ecModel.ec structure; model.metSmiles
    +0017 %     is required to map results back).
    +0018 %
    +0019 % Name-Value Arguments
    +0020 % --------------------
    +0021 % useStored : logical
    +0022 %     if true, skip the API entirely and parse the already-downloaded
    +0023 %     data/OKP_output.csv. If false, query the API (default false).
    +0024 % jobId : char
    +0025 %     OKP job id (default: read from data/OKP_job.txt, written by
    +0026 %     submitOpenKineticsPredictor).
    +0027 % wait : logical
    +0028 %     if true, poll until the job finishes; if false, report once and
    +0029 %     return (default false).
    +0030 % pollInterval : double
    +0031 %     seconds between polls when wait=true (default 30).
    +0032 % outFile : char
    +0033 %     where the result is stored, and read from with useStored=true
    +0034 %     (default: data/OKP_output.csv).
    +0035 % modelAdapter : ModelAdapter
    +0036 %     a loaded model adapter (default: the current default model adapter).
    +0037 %
    +0038 % Returns
    +0039 % -------
    +0040 % done : logical
    +0041 %     true if a result was obtained (downloaded or loaded from disk).
    +0042 % kcatList : struct
    +0043 %     structure with kcat values (empty when not done); see
    +0044 %     readOpenKineticsPredictorOutput for its fields (source, rxns, genes,
    +0045 %     substrates, kcats, kcatSource).
    +0046 %
    +0047 % Examples
    +0048 % --------
    +0049 %     [done, kcatList] = fetchOpenKineticsPredictor(model);                        % check once
    +0050 %     [done, kcatList] = fetchOpenKineticsPredictor(model, 'wait', true);          % poll
    +0051 %     [done, kcatList] = fetchOpenKineticsPredictor(model, 'useStored', true);     % parse stored file
    +0052 %
    +0053 % See also
    +0054 % --------
    +0055 % submitOpenKineticsPredictor, readOpenKineticsPredictorOutput
    +0056 
    +0057 p = parseGECKOargs(varargin, { ...
    +0058     'useStored',    []; ...
    +0059     'jobId',        []; ...
    +0060     'wait',         []; ...
    +0061     'pollInterval', []; ...
    +0062     'modelAdapter', []; ...
    +0063     'outFile',      []});
    +0064 useStored    = p.useStored;
    +0065 jobId        = p.jobId;
    +0066 wait         = p.wait;
    +0067 pollInterval = p.pollInterval;
    +0068 modelAdapter = p.modelAdapter;
    +0069 
    +0070 if isempty(useStored); useStored = false; end
    +0071 if isempty(modelAdapter)
    +0072     modelAdapter = ModelAdapterManager.getDefault();
    +0073     if isempty(modelAdapter)
    +0074         error('Either send in a modelAdapter or set the default model adapter in the ModelAdapterManager.')
    +0075     end
    +0076 end
    +0077 params = modelAdapter.params;
    +0078 if isempty(wait); wait = false; end
    +0079 if isempty(pollInterval); pollInterval = 30; end
    +0080 
    +0081 outFile = p.outFile;
    +0082 if isempty(outFile)
    +0083     outFile = fullfile(params.path,'data','OKP_output.csv');
    +0084 end
    +0085 
    +0086 %% Stored-result mode: parse the saved file, no API call
    +0087 if useStored
    +0088     if ~exist(outFile,'file')
    +0089         error('useStored=true but no stored result found at %s. Run fetchOpenKineticsPredictor with useStored=false first.', outFile);
    +0090     end
    +0091     kcatList = readOpenKineticsPredictorOutput(model, 'outFile', outFile, 'modelAdapter', modelAdapter);
    +0092     done = true;
    +0093     return
    +0094 end
    +0095 
    +0096 %% API mode
    +0097 apiKey = resolveOkpApiKey('', params.path);
    +0098 
    +0099 if isempty(jobId)
    +0100     jobId = readJobIdFromMeta(fullfile(params.path,'data','OKP_job.txt'));
    +0101 end
    +0102 
    +0103 base = 'https://predictor.openkinetics.org/api/v1';
    +0104 opts = weboptions('HeaderFields', {'Authorization', ['Bearer ' apiKey]}, ...
    +0105                    'Timeout', 60, 'ContentType', 'json');
    +0106 
    +0107 while true
    +0108     statusResp = webread([base '/status/' jobId '/'], opts);
    +0109     state = lower(string(statusResp.status));
    +0110 
    +0111     switch state
    +0112         case "completed"
    +0113             csvText = webread([base '/result/' jobId '/'], ...
    +0114                 weboptions('HeaderFields', {'Authorization', ['Bearer ' apiKey]}, ...
    +0115                            'Timeout', 120, 'ContentType', 'text'));
    +0116             fID = fopen(outFile,'w');
    +0117             fwrite(fID, csvText);
    +0118             fclose(fID);
    +0119             fprintf('OKP job %s completed; result stored at %s\n', jobId, outFile);
    +0120             kcatList = readOpenKineticsPredictorOutput(model, 'outFile', outFile, 'modelAdapter', modelAdapter);
    +0121             done = true;
    +0122             return
    +0123 
    +0124         case "failed"
    +0125             error('OKP job %s failed. Check https://predictor.openkinetics.org/ for details.', jobId);
    +0126 
    +0127         otherwise % pending / running / queued
    +0128             pct = '';
    +0129             if isfield(statusResp,'progress') && isfield(statusResp.progress,'predictionsMade') ...
    +0130                     && isfield(statusResp.progress,'predictionsTotal') && statusResp.progress.predictionsTotal > 0
    +0131                 pct = sprintf(' (%d/%d predictions)', statusResp.progress.predictionsMade, statusResp.progress.predictionsTotal);
    +0132             end
    +0133             if wait
    +0134                 fprintf('OKP job %s status: %s%s. Waiting %d s...\n', jobId, char(statusResp.status), pct, pollInterval);
    +0135                 pause(pollInterval);
    +0136             else
    +0137                 fprintf(['OKP job %s not finished (status: %s%s).\n' ...
    +0138                          'Try again later with fetchOpenKineticsPredictor, ' ...
    +0139                          'or check https://predictor.openkinetics.org/.\n'], ...
    +0140                          jobId, char(statusResp.status), pct);
    +0141                 done = false;
    +0142                 kcatList = [];
    +0143                 return
    +0144             end
    +0145     end
    +0146 end
    +0147 end
    +0148 
    +0149 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
    +0150 function jobId = readJobIdFromMeta(metaFile)
    +0151 if ~exist(metaFile,'file')
    +0152     error(['No jobId provided and no metadata file at %s. Run ' ...
    +0153            'submitOpenKineticsPredictor first, or pass jobId explicitly.'], metaFile);
    +0154 end
    +0155 lines = strsplit(fileread(metaFile), newline);
    +0156 jobId = '';
    +0157 for i=1:numel(lines)
    +0158     tok = regexp(strtrim(lines{i}), '^jobId:\s*(\S+)$', 'tokens', 'once');
    +0159     if ~isempty(tok); jobId = tok{1}; break; end
    +0160 end
    +0161 if isempty(jobId)
    +0162     error('Could not read a jobId from %s.', metaFile);
    +0163 end
    +0164 end
    +
    Generated by m2html © 2005
    + + \ No newline at end of file diff --git a/doc/src/gather_kcats/fuzzyKcatMatching.html b/doc/src/gather_kcats/fuzzyKcatMatching.html new file mode 100644 index 00000000..7d535bb6 --- /dev/null +++ b/doc/src/gather_kcats/fuzzyKcatMatching.html @@ -0,0 +1,770 @@ + + + + Description of fuzzyKcatMatching + + + + + + + + + +
    Home > src > gather_kcats > fuzzyKcatMatching.m
    + + + +

    fuzzyKcatMatching +

    + +

    PURPOSE ^

    +
    fuzzyKcatMatching Match model EC numbers and substrates to BRENDA kcats.
    + +

    SYNOPSIS ^

    +
    function kcatList = fuzzyKcatMatching(model, varargin)
    + +

    DESCRIPTION ^

    +
     fuzzyKcatMatching  Match model EC numbers and substrates to BRENDA kcats.
    +
    + Matches the model EC numbers and substrates to the BRENDA database, to
    + return the corresponding kcats for each reaction. If no exact match is
    + found, less specific kcat values are found from (a) evolutionary closely
    + related organism; (b) different substrate; (c) calculated from specific
    + activities; (d) wildcards in the EC number. The model organism is provided
    + in the model adapter as obj.params.org_name, and evolutionary distance to
    + other organisms is determined via KEGG phylogeny. If an organism name
    + occurs multiple times in KEGG, the first instance will be used when
    + determining evolutionary distance.
    +
    + Parameters
    + ----------
    + model : struct
    +     an ecModel in GECKO 3 format (with ecModel.ec structure).
    +
    + Name-Value Arguments
    + --------------------
    + ecRxns : logical or double
    +     for which reactions (from model.ec.rxns) kcat values should be found,
    +     provided as a logical vector with the same length as model.ec.rxns
    +     (the reactions are returned in model order), or as indices into
    +     model.ec.rxns (the reactions are returned in the order given, and an
    +     index given twice is returned twice). The literal [] selects all
    +     reactions, which is the default; any other empty selection, such as
    +     find(mask) without true entries, selects none and returns an empty
    +     kcatList.
    + modelAdapter : ModelAdapter
    +     a loaded model adapter (default: the current default model adapter).
    + forceWClvl : double
    +     number of extra levels, from the right, replaced by a wildcard (on top
    +     of any wildcard already in the code; default 0).
    +
    + Returns
    + -------
    + kcatList : struct
    +     structure array with list of BRENDA derived kcat values, with separate
    +     entries for each kcat value.
    +
    + Notes
    + -----
    + The kcatList structure has the following fields:
    +
    + - source : 'brenda'.
    + - rxns : reaction identifiers.
    + - substrates : substrate names.
    + - kcats : proposed kcat value in /sec.
    + - eccodes : as used to query BRENDA.
    + - wildcardLvl : which level of EC wild-card was necessary to find a match
    +   (0: w.x.y.z; 1: w.x.y.-; 2: w.x.-.-; 3: w.-.-.-; 4: -.-.-.-, which
    +   matches every EC number in BRENDA).
    + - origin : which level of specificity was necessary to find a match
    +   (1: correct organism, correct substrate, kcat; 2: any organism, correct
    +   substrate, kcat; 3: correct organism, any substrate, kcat; 4: any
    +   organism, any substrate, kcat; 5: correct organism, specific activity;
    +   6: any organism, specific activity). Levels are tried in the order
    +   1, 2, 3, 5, 4, 6: a specific activity from the correct organism is
    +   preferred over a kcat from any organism with any substrate. When a
    +   reaction has multiple EC numbers, the EC with the fewest wildcards and
    +   the earliest-tried level is selected, and among those the highest kcat
    +   (the first one when several EC numbers share it); the wildcardLvl and
    +   origin are those of the selected EC.
    +
    + If a wildcard is used, origin levels 1 and 2 are ignored. The last digits
    + in the E.C. number indicate the substrate specificity, so if this should
    + be ignored, then correct substrate matches should not be prioritized.
    +
    + Examples
    + --------
    +     % optional arguments may be given positionally or as name-value pairs:
    +     kcatList = fuzzyKcatMatching(model);
    +     kcatList = fuzzyKcatMatching(model, 'forceWClvl', 1);
    +
    + See also
    + --------
    + mergeDLKcatAndFuzzyKcats, assignKcatValues
    + + +

    CROSS-REFERENCE INFORMATION ^

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

    SUBFUNCTIONS ^

    + + +

    SOURCE CODE ^

    +
    0001 function kcatList = fuzzyKcatMatching(model, varargin)
    +0002 % fuzzyKcatMatching  Match model EC numbers and substrates to BRENDA kcats.
    +0003 %
    +0004 % Matches the model EC numbers and substrates to the BRENDA database, to
    +0005 % return the corresponding kcats for each reaction. If no exact match is
    +0006 % found, less specific kcat values are found from (a) evolutionary closely
    +0007 % related organism; (b) different substrate; (c) calculated from specific
    +0008 % activities; (d) wildcards in the EC number. The model organism is provided
    +0009 % in the model adapter as obj.params.org_name, and evolutionary distance to
    +0010 % other organisms is determined via KEGG phylogeny. If an organism name
    +0011 % occurs multiple times in KEGG, the first instance will be used when
    +0012 % determining evolutionary distance.
    +0013 %
    +0014 % Parameters
    +0015 % ----------
    +0016 % model : struct
    +0017 %     an ecModel in GECKO 3 format (with ecModel.ec structure).
    +0018 %
    +0019 % Name-Value Arguments
    +0020 % --------------------
    +0021 % ecRxns : logical or double
    +0022 %     for which reactions (from model.ec.rxns) kcat values should be found,
    +0023 %     provided as a logical vector with the same length as model.ec.rxns
    +0024 %     (the reactions are returned in model order), or as indices into
    +0025 %     model.ec.rxns (the reactions are returned in the order given, and an
    +0026 %     index given twice is returned twice). The literal [] selects all
    +0027 %     reactions, which is the default; any other empty selection, such as
    +0028 %     find(mask) without true entries, selects none and returns an empty
    +0029 %     kcatList.
    +0030 % modelAdapter : ModelAdapter
    +0031 %     a loaded model adapter (default: the current default model adapter).
    +0032 % forceWClvl : double
    +0033 %     number of extra levels, from the right, replaced by a wildcard (on top
    +0034 %     of any wildcard already in the code; default 0).
    +0035 %
    +0036 % Returns
    +0037 % -------
    +0038 % kcatList : struct
    +0039 %     structure array with list of BRENDA derived kcat values, with separate
    +0040 %     entries for each kcat value.
    +0041 %
    +0042 % Notes
    +0043 % -----
    +0044 % The kcatList structure has the following fields:
    +0045 %
    +0046 % - source : 'brenda'.
    +0047 % - rxns : reaction identifiers.
    +0048 % - substrates : substrate names.
    +0049 % - kcats : proposed kcat value in /sec.
    +0050 % - eccodes : as used to query BRENDA.
    +0051 % - wildcardLvl : which level of EC wild-card was necessary to find a match
    +0052 %   (0: w.x.y.z; 1: w.x.y.-; 2: w.x.-.-; 3: w.-.-.-; 4: -.-.-.-, which
    +0053 %   matches every EC number in BRENDA).
    +0054 % - origin : which level of specificity was necessary to find a match
    +0055 %   (1: correct organism, correct substrate, kcat; 2: any organism, correct
    +0056 %   substrate, kcat; 3: correct organism, any substrate, kcat; 4: any
    +0057 %   organism, any substrate, kcat; 5: correct organism, specific activity;
    +0058 %   6: any organism, specific activity). Levels are tried in the order
    +0059 %   1, 2, 3, 5, 4, 6: a specific activity from the correct organism is
    +0060 %   preferred over a kcat from any organism with any substrate. When a
    +0061 %   reaction has multiple EC numbers, the EC with the fewest wildcards and
    +0062 %   the earliest-tried level is selected, and among those the highest kcat
    +0063 %   (the first one when several EC numbers share it); the wildcardLvl and
    +0064 %   origin are those of the selected EC.
    +0065 %
    +0066 % If a wildcard is used, origin levels 1 and 2 are ignored. The last digits
    +0067 % in the E.C. number indicate the substrate specificity, so if this should
    +0068 % be ignored, then correct substrate matches should not be prioritized.
    +0069 %
    +0070 % Examples
    +0071 % --------
    +0072 %     % optional arguments may be given positionally or as name-value pairs:
    +0073 %     kcatList = fuzzyKcatMatching(model);
    +0074 %     kcatList = fuzzyKcatMatching(model, 'forceWClvl', 1);
    +0075 %
    +0076 % See also
    +0077 % --------
    +0078 % mergeDLKcatAndFuzzyKcats, assignKcatValues
    +0079 
    +0080 % Validators reject a name that landed in a positional slot, which
    +0081 % happens when positional and name-value arguments are mixed. Without
    +0082 % them `while forceWClvl > 0` on a char array is all-true and silently
    +0083 % wildcards every EC number.
    +0084 p = parseGECKOargs(varargin, { ...
    +0085     'ecRxns',          [], @(x) assert(isempty(x) || isnumeric(x) || ...
    +0086                                 islogical(x), ...
    +0087                                 'fuzzyKcatMatching:invalidEcRxns', ...
    +0088                                 'ecRxns must be numeric or logical.'); ...
    +0089     'modelAdapter',    [], @(x) assert(isempty(x) || isa(x,'ModelAdapter'), ...
    +0090                                 'fuzzyKcatMatching:invalidModelAdapter', ...
    +0091                                 'modelAdapter must be a ModelAdapter.'); ...
    +0092     'forceWClvl',      [], @(x) assert(isempty(x) || (isnumeric(x) && ...
    +0093                                 isscalar(x) && x >= 0), ...
    +0094                                 'fuzzyKcatMatching:invalidForceWClvl', ...
    +0095                                 'forceWClvl must be a nonnegative scalar.'); ...
    +0096     'kcatAggregation', [], @(x) assert(isempty(x) || any(strcmpi(x, ...
    +0097                                 {'max','median'})), ...
    +0098                                 'fuzzyKcatMatching:invalidKcatAggregation', ...
    +0099                                 'kcatAggregation must be ''max'' or ''median''.')});
    +0100 ecRxns          = p.ecRxns;
    +0101 modelAdapter    = p.modelAdapter;
    +0102 forceWClvl      = p.forceWClvl;
    +0103 kcatAggregation = p.kcatAggregation;
    +0104 
    +0105 % Get indices: [] selects all reactions, a logical vector the true entries (in
    +0106 % model order) and indices are used as given (order and repeats kept).
    +0107 if isnumeric(ecRxns) && isequal(size(ecRxns),[0 0])
    +0108     ecRxns = (1:numel(model.ec.rxns)).';
    +0109 elseif islogical(ecRxns)
    +0110     ecRxns = find(ecRxns(:));
    +0111 else
    +0112     ecRxns = ecRxns(:);
    +0113     if any(ecRxns < 1 | ecRxns > numel(model.ec.rxns) | ecRxns ~= round(ecRxns))
    +0114         error('fuzzyKcatMatching:invalidEcRxns', ...
    +0115             'ecRxns must hold indices of model.ec.rxns.');
    +0116     end
    +0117 end
    +0118 
    +0119 if isempty(modelAdapter)
    +0120     modelAdapter = ModelAdapterManager.getDefault();
    +0121     if isempty(modelAdapter)
    +0122         error('Either send in a modelAdapter or set the default model adapter in the ModelAdapterManager.')
    +0123     end
    +0124 end
    +0125 params = modelAdapter.params;
    +0126 
    +0127 if isempty(forceWClvl)
    +0128     forceWClvl = 0;
    +0129 end
    +0130 
    +0131 if ~isfield(model.ec,'eccodes')
    +0132     error('No EC codes defined in model.ec.eccodes. First run getECfromGEM() and/or getECfromDatabase().')
    +0133 end
    +0134 eccodes      = model.ec.eccodes(ecRxns);
    +0135 if isempty(ecRxns)
    +0136     %No reactions selected: nothing to match, and BRENDA is not read
    +0137     kcatList.source      = 'brenda';
    +0138     kcatList.rxns        = cell(0,1);
    +0139     kcatList.substrates  = cell(0,1);
    +0140     kcatList.kcats       = zeros(0,1);
    +0141     kcatList.eccodes     = cell(0,1);
    +0142     kcatList.wildcardLvl = NaN(0,1);
    +0143     kcatList.origin      = NaN(0,1);
    +0144     return
    +0145 end
    +0146 substrates   = cell(numel(ecRxns),1);
    +0147 substrCoeffs = cell(numel(ecRxns),1);
    +0148 
    +0149 %Need to remove the prefix of GECKO light rxn names in the ec structure
    +0150 if ~model.ec.geckoLight
    +0151     rxnNames = model.ec.rxns;
    +0152 else
    +0153     rxnNames = extractAfter(model.ec.rxns, 4);
    +0154 end
    +0155 [~,originalRxns] = ismember(rxnNames(ecRxns),model.rxns);
    +0156 for i = 1:length(ecRxns)
    +0157     sel = find(model.S(:,originalRxns(i)) < 0);
    +0158     substrates{i}  = model.metNames(sel); 
    +0159     substrCoeffs{i} = -model.S(sel,originalRxns(i));
    +0160 end
    +0161 
    +0162 %Load BRENDA data:
    +0163 kcatAggregation = resolveKcatAggregation(kcatAggregation, modelAdapter);
    +0164 [KCATcell, SAcell] = loadBRENDAdata('modelAdapter', modelAdapter, ...
    +0165     'kcatAggregation', kcatAggregation);
    +0166 
    +0167 %Creates a Structure with KEGG codes for organisms, names and taxonomical
    +0168 %distance matrix and extract the organism index in the KEGG struct
    +0169 phylDistStruct =  KEGG_struct(modelAdapter.getPhylDistStructPath());
    +0170 %Get the KEGG code for the model's organism
    +0171 org_name       = params.org_name;
    +0172 org_index      = find_inKEGG(org_name,phylDistStruct.names);
    +0173 %build an index for genus in the phyl dist struct
    +0174 %first just extract the genus (i.e. the first part of the name)
    +0175 phylDistStruct.genus = lower(regexprep(phylDistStruct.names,'\s.*',''));
    +0176 %create a map for the genuses
    +0177 phylDistStruct.uniqueGenusList = unique(phylDistStruct.genus);
    +0178 phylDistStruct.genusHashMap = containers.Map(phylDistStruct.uniqueGenusList,1:length(phylDistStruct.uniqueGenusList));
    +0179 phylDistStruct.uniqueGenusIndices = cell(length(phylDistStruct.uniqueGenusList),1);
    +0180 
    +0181 %Then for each genus create a list with indices to the names
    +0182 for i = 1:length(phylDistStruct.genus)
    +0183     matchInd = cell2mat(values(phylDistStruct.genusHashMap,phylDistStruct.genus(i)));
    +0184     phylDistStruct.uniqueGenusIndices{matchInd} = [phylDistStruct.uniqueGenusIndices{matchInd};i];
    +0185 end
    +0186 
    +0187 %Allocate output
    +0188 kcats = zeros(length(eccodes),1);
    +0189 mM = length(eccodes);
    +0190 
    +0191 %Create empty kcatInfo
    +0192 %Not returned as an output; used only internally to construct
    +0193 %kcatList.wildcardLvl and kcatList.origin.
    +0194 kcatInfo.info.org_s   = zeros(mM,1);
    +0195 kcatInfo.info.rest_s  = zeros(mM,1);
    +0196 kcatInfo.info.org_ns  = zeros(mM,1);
    +0197 kcatInfo.info.rest_ns = zeros(mM,1);
    +0198 kcatInfo.info.org_sa  = zeros(mM,1);
    +0199 kcatInfo.info.rest_sa = zeros(mM,1);
    +0200 kcatInfo.info.wcLevel = NaN(mM,1);
    +0201 kcatInfo.stats.queries  = 0;
    +0202 kcatInfo.stats.org_s    = 0;
    +0203 kcatInfo.stats.rest_s   = 0;
    +0204 kcatInfo.stats.org_ns   = 0;
    +0205 kcatInfo.stats.rest_ns  = 0;
    +0206 kcatInfo.stats.org_sa   = 0;
    +0207 kcatInfo.stats.rest_sa  = 0;
    +0208 kcatInfo.stats.wc0      = 0;
    +0209 kcatInfo.stats.wc1      = 0;
    +0210 kcatInfo.stats.wc2      = 0;
    +0211 kcatInfo.stats.wc3      = 0;
    +0212 kcatInfo.stats.wc4      = 0;
    +0213 kcatInfo.stats.matrix   = zeros(6,5);
    +0214 
    +0215 %build an EC index to speed things up a bit - many of the ECs appear
    +0216 %many times - unnecessary to compare them all
    +0217 %so, here, each EC string appears only once, and you get a vector with
    +0218 %indices to the rows in KCATcell
    +0219 [ECIndexIds,~,ic] = unique(KCATcell{1});
    +0220 EcIndexIndices = cell(length(ECIndexIds),1);
    +0221 for i = 1:length(EcIndexIndices)
    +0222     EcIndexIndices{i} = find(ic == i).';
    +0223 end
    +0224 
    +0225 %Apply force wildcard level
    +0226 eccodes = forceWildcards(eccodes,forceWClvl);
    +0227 
    +0228 PB = progressReport(mM, 'Gathering kcat values by fuzzy matching to BRENDA database');
    +0229 %Main loop:
    +0230 for i = 1:mM
    +0231     PB.count;
    +0232     %Match:
    +0233     EC = eccodes{i};
    +0234     if ~isempty(EC)
    +0235         EC = strsplit(EC,';');
    +0236         %Try to match direct reaction:
    +0237         if ~isempty(substrates{i})
    +0238             [kcats(i), kcatInfo.info,kcatInfo.stats] = iterativeMatch(EC,substrates{i},substrCoeffs{i},i,KCATcell,...
    +0239                 kcatInfo.info,kcatInfo.stats,org_name,...
    +0240                 phylDistStruct,org_index,SAcell,ECIndexIds,EcIndexIndices,kcatAggregation);
    +0241         end
    +0242     end
    +0243 end
    +0244 
    +0245 kcatList.source      = 'brenda';
    +0246 kcatList.rxns        = model.ec.rxns(ecRxns);
    +0247 kcatList.substrates  = substrates;
    +0248 kcatList.kcats       = kcats;
    +0249 kcatList.eccodes     = eccodes;
    +0250 kcatList.wildcardLvl = kcatInfo.info.wcLevel;
    +0251 kcatList.origin      = NaN(numel(model.ec.rxns(ecRxns)),1);
    +0252 % This can be refactored, iterativeMatch and their nested functions can
    +0253 % just directly report the origin number.
    +0254 origin = [kcatInfo.info.org_s kcatInfo.info.rest_s kcatInfo.info.org_ns kcatInfo.info.rest_ns kcatInfo.info.org_sa kcatInfo.info.rest_sa];
    +0255 for i=1:6
    +0256     kcatList.origin(find(origin(:,i))) = i;
    +0257 end
    +0258 end
    +0259 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
    +0260 %Replaces the rightmost level of each EC code that is not a wildcard yet with
    +0261 %a wildcard, forceWClvl times, so that level 4 gives -.-.-.- . The codes of one
    +0262 %entry are separated by ';'. A code that does not have four levels is kept.
    +0263 function eccodes = forceWildcards(eccodes,forceWClvl)
    +0264 if forceWClvl <= 0
    +0265     return
    +0266 end
    +0267 for i = 1:numel(eccodes)
    +0268     if isempty(eccodes{i})
    +0269         continue
    +0270     end
    +0271     codes = strsplit(eccodes{i},';');
    +0272     for j = 1:numel(codes)
    +0273         parts = strsplit(codes{j},'.');
    +0274         if numel(parts) ~= 4
    +0275             continue
    +0276         end
    +0277         for k = 1:forceWClvl
    +0278             last = find(~strcmp(parts,'-'),1,'last');
    +0279             if isempty(last)
    +0280                 break
    +0281             end
    +0282             parts{last} = '-';
    +0283         end
    +0284         codes{j} = strjoin(parts,'.');
    +0285     end
    +0286     eccodes{i} = strjoin(codes,';');
    +0287 end
    +0288 end
    +0289 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
    +0290 function [kcat,dir,tot] =iterativeMatch(EC,subs,substrCoeff,i,KCATcell,dir,tot,...
    +0291     name,phylDist,org_index,SAcell,ECIndexIds,EcIndexIndices,kcatAggregation)
    +0292 %Will iteratively try to match the EC number to some registry in BRENDA,
    +0293 %using each time one additional wildcard.
    +0294 
    +0295 kcat    = zeros(size(EC));
    +0296 origin  = zeros(size(EC));
    +0297 matches = zeros(size(EC));
    +0298 wc_num  = ones(size(EC)).*1000;
    +0299 for k = 1:length(EC)
    +0300     success  = false;
    +0301     while ~success
    +0302         %Atempt match:
    +0303         [kcat(k),origin(k),matches(k)] = mainMatch(EC{k},subs,substrCoeff,KCATcell,...
    +0304             name,phylDist,...
    +0305             org_index,SAcell,ECIndexIds,EcIndexIndices,kcatAggregation);
    +0306         %If any match found, ends. If not, introduces one extra wild card and
    +0307         %tries again:
    +0308         if origin(k) > 0
    +0309             success   = true;
    +0310             wc_num(k) = sum(EC{k}=='-');
    +0311         else
    +0312             wild_num = sum(EC{k}=='-');
    +0313             if numel(strsplit(EC{k},'.')) ~= 4
    +0314                 %An EC code without four levels (for example '1.1.1') cannot be
    +0315                 %escalated level by level: stop with the no-match values, as
    +0316                 %geckopy does.
    +0317                 success = true;
    +0318             elseif wild_num >= 4
    +0319                 %Already fully wildcarded ('-.-.-.-') and still no match --
    +0320                 %stop here instead of computing dot_pos(4-wild_num) with
    +0321                 %wild_num==4, an out-of-range index. kcat(k)/origin(k) keep
    +0322                 %their zero-initialised "no match" values.
    +0323                 success = true;
    +0324             elseif wild_num == 3
    +0325                 %Last escalation: '-.-.-.-' matches every EC number in BRENDA
    +0326                 EC{k} = '-.-.-.-';
    +0327             else
    +0328                 dot_pos  = [2 strfind(EC{k},'.')];
    +0329                 wc_text  = '-.-.-.-';
    +0330                 EC{k}    = [EC{k}(1:dot_pos(4-wild_num)) wc_text(1:2*wild_num+1)];
    +0331             end
    +0332         end
    +0333     end
    +0334 end
    +0335 
    +0336 if sum(origin) > 0
    +0337     %For more than one EC: Choose the maximum value among the ones with the
    +0338     %less amount of wildcards and the better origin:
    +0339     best_pos    = (wc_num == min(wc_num));
    +0340     new_origin  = origin(best_pos);
    +0341     best_origin = min(new_origin(new_origin~=0));
    +0342     %Intersect with the wildcard filter above -- comparing origin==best_origin
    +0343     %against the full (unfiltered) origin vector would let an EC with a worse
    +0344     %(higher) wildcard count back in whenever it happens to share best_origin,
    +0345     %defeating the wildcard-count filter entirely.
    +0346     best_pos    = best_pos & (origin == best_origin);
    +0347     %Highest kcat among those, the first one if several share it
    +0348     best_idx   = find(best_pos);
    +0349     [~,j]      = max(kcat(best_idx));
    +0350     max_pos    = best_idx(j);
    +0351     wc_num     = wc_num(max_pos);
    +0352     origin     = origin(max_pos);
    +0353     matches    = matches(max_pos);
    +0354     kcat       = kcat(max_pos);
    +0355 
    +0356     %Update dir and tot:
    +0357     dir.org_s(i)   = matches*(origin == 1);
    +0358     dir.rest_s(i)  = matches*(origin == 2);
    +0359     dir.org_ns(i)  = matches*(origin == 3);
    +0360     dir.org_sa(i)  = matches*(origin == 4);
    +0361     dir.rest_ns(i) = matches*(origin == 5);
    +0362     dir.rest_sa(i) = matches*(origin == 6);
    +0363     dir.wcLevel(i) = wc_num;
    +0364     tot.org_s        = tot.org_s   + (origin == 1);
    +0365     tot.rest_s       = tot.rest_s  + (origin == 2);
    +0366     tot.org_ns       = tot.org_ns  + (origin == 3);
    +0367     tot.org_sa       = tot.org_sa  + (origin == 4);
    +0368     tot.rest_ns      = tot.rest_ns + (origin == 5);
    +0369     tot.rest_sa      = tot.rest_sa + (origin == 6);
    +0370     tot.wc0          = tot.wc0     + (wc_num == 0);
    +0371     tot.wc1          = tot.wc1     + (wc_num == 1);
    +0372     tot.wc2          = tot.wc2     + (wc_num == 2);
    +0373     tot.wc3          = tot.wc3     + (wc_num == 3);
    +0374     tot.wc4          = tot.wc4     + (wc_num == 4);
    +0375     tot.queries      = tot.queries + 1;
    +0376     tot.matrix(origin,wc_num+1) = tot.matrix(origin,wc_num+1) + 1;
    +0377 end
    +0378 
    +0379 end
    +0380 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
    +0381 
    +0382 function [kcat,origin,matches] = mainMatch(EC,subs,substrCoeff,KCATcell,...
    +0383     name,phylDist,org_index,SAcell,ECIndexIds,EcIndexIndices,kcatAggregation)
    +0384 
    +0385 %First make the string matching. This takes time, so we only want to do
    +0386 %this once:
    +0387 %Relaxes matching if wild cards are present:
    +0388 wild     = false;
    +0389 wild_pos = strfind(EC,'-');
    +0390 if ~isempty(wild_pos)
    +0391     EC   = EC(1:wild_pos(1)-1);
    +0392     wild = true;
    +0393 end
    +0394 stringMatchesEC_cell = extract_string_matches(EC,KCATcell{1},wild,ECIndexIds,EcIndexIndices);
    +0395 
    +0396 % Matching function prioritizing organism and substrate specificity when
    +0397 % available.
    +0398 
    +0399 origin = 0;
    +0400 %First try to match organism and substrate:
    +0401 [kcat,matches] = matchKcat(EC,subs,substrCoeff,KCATcell,name,true,false,...
    +0402     phylDist,org_index,SAcell,stringMatchesEC_cell,[],kcatAggregation);
    +0403 if matches > 0 && ~wild % If wildcard, ignore substrate match
    +0404     origin = 1;
    +0405     %If no match, try the closest organism but match the substrate:
    +0406 else
    +0407     [kcat,matches] = matchKcat(EC,subs,substrCoeff,KCATcell,'',true,false,...
    +0408         phylDist,org_index,SAcell,stringMatchesEC_cell,[],kcatAggregation);
    +0409     if matches > 0 && ~wild % If wildcard, ignore substrate match
    +0410         origin = 2;
    +0411         %If no match, try to match organism but with any substrate:
    +0412     else
    +0413         [kcat,matches] = matchKcat(EC,subs,substrCoeff,KCATcell,name,false,false,...
    +0414             phylDist,org_index,SAcell,stringMatchesEC_cell,[],kcatAggregation);
    +0415         if matches > 0
    +0416             origin = 3;
    +0417             %If no match, try to match organism but for any substrate (SA*MW):
    +0418         else
    +0419             %create matching index for SA, has not been needed until now
    +0420             stringMatchesSA = extract_string_matches(EC,SAcell{1},wild,[],[]);
    +0421 
    +0422             [kcat,matches] = matchKcat(EC,subs,substrCoeff,KCATcell,name,false,...
    +0423                 true,phylDist,org_index,...
    +0424                 SAcell,stringMatchesEC_cell,stringMatchesSA,kcatAggregation);
    +0425             if matches > 0
    +0426                 origin = 4;
    +0427                 %If no match, try any organism and any substrate:
    +0428             else
    +0429                 [kcat,matches] = matchKcat(EC,subs,substrCoeff,KCATcell,'',false,...
    +0430                     false,phylDist,...
    +0431                     org_index,SAcell,stringMatchesEC_cell,stringMatchesSA,kcatAggregation);
    +0432                 if matches > 0
    +0433                     origin = 5;
    +0434                     %Again if no match, look for any org and SA*MW
    +0435                 else
    +0436                     [kcat,matches] = matchKcat(EC,subs,substrCoeff,KCATcell,'',...
    +0437                         false,true,phylDist,...
    +0438                         org_index,SAcell,stringMatchesEC_cell,stringMatchesSA,kcatAggregation);
    +0439                     if matches > 0
    +0440                         origin = 6;
    +0441                     end
    +0442                 end
    +0443 
    +0444             end
    +0445         end
    +0446     end
    +0447 end
    +0448 end
    +0449 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
    +0450 function [kcat,matches] = matchKcat(EC,subs,substrCoeff,KCATcell,organism,...
    +0451     substrate,SA,phylDist,...
    +0452     org_index,SAcell,KCATcellMatches,SAcellMatches,kcatAggregation)
    +0453 
    +0454 %Will go through BRENDA and will record any match. Afterwards, it will
    +0455 %return the maximum value and the number of matches attained.
    +0456 kcat    = [];
    +0457 matches = 0;
    +0458 
    +0459 if SA
    +0460     %SAcell{1},wild,[],[]
    +0461     EC_indexes = extract_indexes(SAcellMatches,[],SAcell{2},subs,substrate,...
    +0462         organism,org_index,phylDist);
    +0463 
    +0464     kcat       = SAcell{3}(EC_indexes);
    +0465     org_cell   = SAcell{2}(EC_indexes);
    +0466     MW_BRENDA  = SAcell{4}(EC_indexes);
    +0467 
    +0468 else
    +0469     %KCATcell{1},wild,ECIndexIds,EcIndexIndices
    +0470     EC_indexes = extract_indexes(KCATcellMatches,KCATcell{2},KCATcell{3},...
    +0471         subs,substrate,organism,org_index,...
    +0472         phylDist);
    +0473     if substrate
    +0474         for j = 1:length(EC_indexes)
    +0475             indx = EC_indexes(j);
    +0476             for k = 1:length(subs)
    +0477                 if (isempty(subs{k}))
    +0478                     break;
    +0479                 end
    +0480                 %l = logical(strcmpi(model.metNames,subs{k}).*(model.S(:,i)~=0)); %I don't understand the .* (model.S(:,i)~=0) part, it shouldn't be needed?/JG;
    +0481                 if ~isempty(subs{k}) && strcmpi(subs{k},KCATcell{2}(indx))
    +0482                     if KCATcell{4}(indx) > 0
    +0483                         coeff = substrCoeff(k);
    +0484                         kCatTmp = KCATcell{4}(indx);
    +0485                         kcat  = [kcat;kCatTmp/coeff];
    +0486                     end
    +0487                 end
    +0488             end
    +0489         end
    +0490     else
    +0491         kcat = KCATcell{4}(EC_indexes);
    +0492     end
    +0493 end
    +0494 %Collapse the matched entries to one value, by the chosen aggregation:
    +0495 if isempty(kcat)
    +0496     kcat = 0;
    +0497 else
    +0498     matches = length(kcat);
    +0499     if strcmpi(kcatAggregation,'median')
    +0500         kcat = median(kcat);
    +0501     else
    +0502         kcat = max(kcat);
    +0503     end
    +0504 end
    +0505 %Avoid SA*Mw values over the diffusion limit rate  [Bar-Even et al. 2011]
    +0506 if kcat>(1E7)
    +0507     kcat = 1E7;
    +0508 end
    +0509 end
    +0510 
    +0511 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
    +0512 %Make the string matches of the ECs. This is heavy, so only do it once!
    +0513 %
    +0514 function EC_indexes = extract_string_matches(EC,EC_cell,wild,ECIndexIds,EcIndexIndices)
    +0515 EC_indexes = [];
    +0516 EC_indexesOld = [];
    +0517 if wild
    +0518     if (~isempty(ECIndexIds)) %In some cases the EC_cell is not from KCatCell
    +0519         % startsWith, not contains: EC is a truncated prefix like '1.' (everything
    +0520         % before the first wildcard dash), and an anchored match is what the
    +0521         % non-optimized branch below already does (strfind(...)==1). contains()
    +0522         % would match that same '1.' substring anywhere in the string, not just at
    +0523         % the start -- '4.2.1.1' contains '1.' between its third and fourth levels,
    +0524         % so a '1.-.-.-' wildcard query for enzyme class 1 would also match entries
    +0525         % from unrelated classes whose EC code happens to contain the same two
    +0526         % characters.
    +0527         X = find(startsWith(ECIndexIds, EC));
    +0528         for j = 1:length(X)
    +0529             EC_indexes = [EC_indexes,EcIndexIndices{X(j)}];
    +0530         end
    +0531     elseif isempty(EC) %Not optimized, fully wildcarded: every entry matches
    +0532         EC_indexes = 1:length(EC_cell);
    +0533     else %Not optimized
    +0534         for j=1:length(EC_cell)
    +0535             if strfind(EC_cell{j},EC)==1
    +0536                 EC_indexes = [EC_indexes,j];
    +0537             end
    +0538         end
    +0539     end
    +0540 else
    +0541     if (~isempty(ECIndexIds)) %In some cases the EC_cell is not from KCatCell
    +0542         mtch = find(strcmpi(EC,ECIndexIds));
    +0543         if (~isempty(mtch))
    +0544             EC_indexes = EcIndexIndices{mtch};
    +0545         end
    +0546     else %%Not optimized
    +0547         if ~isempty(EC_cell)
    +0548             EC_indexes = transpose(find(strcmpi(EC,EC_cell)));
    +0549         end
    +0550     end
    +0551 end
    +0552 
    +0553 end
    +0554 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
    +0555 %Extract the indexes of the entries in the BRENDA data that meet the
    +0556 %conditions specified by the search criteria
    +0557 function EC_indexes = extract_indexes(EC_indCellStringMatches,subs_cell,orgs_cell,subs,...
    +0558     substrate,organism, org_index,...
    +0559     phylDist)
    +0560 
    +0561 EC_indexes = EC_indCellStringMatches;%reuse so the string comparisons are not run many times
    +0562 
    +0563 %If substrate=true then it will extract only the substrates appereances
    +0564 %indexes in the EC subset from the BRENDA cell array
    +0565 
    +0566 if substrate
    +0567     if (~isempty(EC_indexes)) %optimization
    +0568         Subs_indexes = [];
    +0569         for l = 1:length(subs)
    +0570             if (isempty(subs{l}))
    +0571                 break;
    +0572             end
    +0573             Subs_indexes = horzcat(Subs_indexes,EC_indexes(strcmpi(subs(l),...
    +0574                 subs_cell(EC_indexes))));
    +0575         end
    +0576         EC_indexes = Subs_indexes;
    +0577     end
    +0578 end
    +0579 
    +0580 EC_orgs = orgs_cell(EC_indexes);
    +0581 %If specific organism values are requested looks for all the organism
    +0582 %repetitions on the subset BRENDA cell array(EC_indexes)
    +0583 if string(organism) ~= ''
    +0584     EC_indexes = EC_indexes(strcmpi(string(organism),EC_orgs));
    +0585 
    +0586     %If KEGG code was assigned to the organism (model) then it will look for
    +0587     %the Kcat value for the closest organism
    +0588 elseif org_index~='*' %&& org_index~=''
    +0589     KEGG_indexes = [];temp = [];
    +0590 
    +0591     %For relating a phyl dist between the modelled organism and the organisms
    +0592     %on the BRENDA cell array it should search for a KEGG code for each of
    +0593     %these
    +0594     for j=1:length(EC_indexes)
    +0595         %Assigns a KEGG index for those found on the KEGG struct
    +0596         orgs_index = find(strcmpi(orgs_cell(EC_indexes(j)),phylDist.names),1);
    +0597         if ~isempty(orgs_index)
    +0598             KEGG_indexes = [KEGG_indexes; orgs_index];
    +0599             temp         = [temp;EC_indexes(j)];
    +0600             %For values related to organisms without KEGG code, then it will
    +0601             %look for KEGG code for the first organism with the same genus
    +0602         else
    +0603             org = orgs_cell{EC_indexes(j)};
    +0604             orgGenus = lower(regexprep(org,'\s.*',''));
    +0605             if isKey(phylDist.genusHashMap,orgGenus) %annoyingly, this seems to be needed
    +0606                 matchInd = cell2mat(values(phylDist.genusHashMap,{orgGenus}));
    +0607                 matches = phylDist.uniqueGenusIndices{matchInd};
    +0608                 k = matches(1);
    +0609                 KEGG_indexes = [KEGG_indexes;k];
    +0610                 temp         = [temp;EC_indexes(j)];
    +0611             end
    +0612         end
    +0613     end
    +0614     %Update the EC_indexes cell array
    +0615     EC_indexes = temp;
    +0616     %Looks for the taxonomically closest organism and saves the index of
    +0617     %its appearences in the BRENDA cell
    +0618     if ~isempty(EC_indexes)
    +0619         distances = phylDist.distMat(org_index,KEGG_indexes);
    +0620         EC_indexes = EC_indexes(distances == min(distances));
    +0621     end
    +0622 end
    +0623 end
    +0624 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
    +0625 function org_index = find_inKEGG(org_name,names)
    +0626 org_index      = find(strcmpi(org_name,names));
    +0627 if numel(org_index)>1
    +0628     org_index = org_index(1);
    +0629 elseif isempty(org_index)
    +0630     org_name    = regexprep(org_name,'\s.*','');
    +0631     org_index   = find(strcmpi(org_name,names));
    +0632     if numel(org_index)>1
    +0633         org_index = org_index(1);
    +0634     elseif isempty(org_index)
    +0635         org_index = '*';
    +0636     end
    +0637 end
    +0638 end
    +0639 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
    +0640 function phylDistStruct =  KEGG_struct(phylpath)
    +0641 load(phylpath)
    +0642 phylDistStruct.ids   = transpose(phylDistStruct.ids);
    +0643 phylDistStruct.names = transpose(phylDistStruct.names);
    +0644 phylDistStruct.names = regexprep(phylDistStruct.names,'\s*\(.*','');
    +0645 end
    +
    Generated by m2html © 2005
    + + \ No newline at end of file diff --git a/doc/src/gather_kcats/getEcRxnKeys.html b/doc/src/gather_kcats/getEcRxnKeys.html new file mode 100644 index 00000000..81685081 --- /dev/null +++ b/doc/src/gather_kcats/getEcRxnKeys.html @@ -0,0 +1,127 @@ + + + + Description of getEcRxnKeys + + + + + + + + + +
    Home > src > gather_kcats > getEcRxnKeys.m
    + + + +

    getEcRxnKeys +

    + +

    PURPOSE ^

    +
    getEcRxnKeys Build-independent keys of the model.ec reactions.
    + +

    SYNOPSIS ^

    +
    function [baseRxns, enzymeSets] = getEcRxnKeys(model)
    + +

    DESCRIPTION ^

    +
     getEcRxnKeys  Build-independent keys of the model.ec reactions.
    +
    + A kcat source file (see saveKcatSource) identifies a reaction by its
    + conventional reaction and its enzyme set, not by model.ec.rxns, whose
    + identifiers depend on how the ecModel was built. This function gives
    + both keys for every model.ec row.
    +
    + Parameters
    + ----------
    + model : struct
    +     an ecModel in GECKO 3 format (with ecModel.ec structure).
    +
    + Returns
    + -------
    + baseRxns : cell
    +     per model.ec.rxns entry, the conventional reaction: without a
    +     trailing _EXP_<n> (full model) or a leading <nnn>_ (light model). A
    +     reverse direction keeps its _REV.
    + enzymeSets : cell
    +     per model.ec.rxns entry, the UniProt accessions of its enzymes
    +     (model.ec.rxnEnzMat), sorted and joined by ' + '; empty without
    +     enzymes.
    +
    + Examples
    + --------
    +     [baseRxns, enzymeSets] = getEcRxnKeys(ecModel);
    +
    + See also
    + --------
    + saveKcatSource, loadKcatSource
    + + +

    CROSS-REFERENCE INFORMATION ^

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

    SOURCE CODE ^

    +
    0001 function [baseRxns, enzymeSets] = getEcRxnKeys(model)
    +0002 % getEcRxnKeys  Build-independent keys of the model.ec reactions.
    +0003 %
    +0004 % A kcat source file (see saveKcatSource) identifies a reaction by its
    +0005 % conventional reaction and its enzyme set, not by model.ec.rxns, whose
    +0006 % identifiers depend on how the ecModel was built. This function gives
    +0007 % both keys for every model.ec row.
    +0008 %
    +0009 % Parameters
    +0010 % ----------
    +0011 % model : struct
    +0012 %     an ecModel in GECKO 3 format (with ecModel.ec structure).
    +0013 %
    +0014 % Returns
    +0015 % -------
    +0016 % baseRxns : cell
    +0017 %     per model.ec.rxns entry, the conventional reaction: without a
    +0018 %     trailing _EXP_<n> (full model) or a leading <nnn>_ (light model). A
    +0019 %     reverse direction keeps its _REV.
    +0020 % enzymeSets : cell
    +0021 %     per model.ec.rxns entry, the UniProt accessions of its enzymes
    +0022 %     (model.ec.rxnEnzMat), sorted and joined by ' + '; empty without
    +0023 %     enzymes.
    +0024 %
    +0025 % Examples
    +0026 % --------
    +0027 %     [baseRxns, enzymeSets] = getEcRxnKeys(ecModel);
    +0028 %
    +0029 % See also
    +0030 % --------
    +0031 % saveKcatSource, loadKcatSource
    +0032 
    +0033 if model.ec.geckoLight
    +0034     baseRxns = regexprep(model.ec.rxns, '^\d+_', '');
    +0035 else
    +0036     baseRxns = regexprep(model.ec.rxns, '_EXP_\d+$', '');
    +0037 end
    +0038 baseRxns = baseRxns(:);
    +0039 
    +0040 n = numel(model.ec.rxns);
    +0041 enzymeSets = repmat({''}, n, 1);
    +0042 [rows, cols] = find(model.ec.rxnEnzMat);
    +0043 if ~isempty(rows)
    +0044     % Enzymes per reaction in one pass, rather than a search per reaction.
    +0045     perRxn = accumarray(rows(:), cols(:), [n 1], @(c) {c});
    +0046     for i = find(~cellfun(@isempty, perRxn))'
    +0047         enzymes = unique(model.ec.enzymes(perRxn{i}));
    +0048         enzymeSets{i} = strjoin(enzymes(:)', ' + ');
    +0049     end
    +0050 end
    +0051 end
    +
    Generated by m2html © 2005
    + + \ No newline at end of file diff --git a/doc/src/gather_kcats/getStandardKcat.html b/doc/src/gather_kcats/getStandardKcat.html new file mode 100644 index 00000000..bc9f3d9f --- /dev/null +++ b/doc/src/gather_kcats/getStandardKcat.html @@ -0,0 +1,483 @@ + + + + Description of getStandardKcat + + + + + + + + + +
    Home > src > gather_kcats > getStandardKcat.m
    + + + +

    getStandardKcat +

    + +

    PURPOSE ^

    +
    getStandardKcat Assign standard kcat and MW to reactions without enzymes.
    + +

    SYNOPSIS ^

    +
    function [model, rxnsMissingGPR, standardMW, standardKcat, rxnsNoKcat] = getStandardKcat(model, varargin)
    + +

    DESCRIPTION ^

    +
     getStandardKcat  Assign standard kcat and MW to reactions without enzymes.
    +
    + Calculates a standard kcat and standard molecular weight (MW) that can be
    + used to apply enzyme constraints to reactions without any associated
    + enzymes. Such reactions have either an empty model.grRules field, or they
    + have no match in model.ec.rxns (which can be the case if the genes in the
    + model.grRules field could not be mapped to enzymes). This is done by
    + adding those reactions to model.ec, assigning a "standard" pseudoenzyme
    + with the standard MW (median of all proteins in the organism) and standard
    + kcat (median from all kcat, or subsystem specific kcat).
    +
    + A reaction is assigned a subSystem specific kcat value if the model has a
    + subSystems field and the reaction is annotated with a subSystem. Only the
    + first subSystem will be considered if multiple are annotated to the same
    + reaction.
    +
    + Exchange, transport and pseudoreactions are filtered out, plus any
    + reaction identifiers specified in /data/pseudoRxns.tsv in the model
    + adapter folder.
    +
    + In addition, reactions that are annotated with an enzyme (and therefore
    + already in model.ec), but not assigned any reaction-specific kcat value
    + (their model.ec.kcat entry is either 0 or NaN), can be assigned standard
    + kcat values by a similar approach. However, those reactions will not be
    + linked to the "standard" pseudoenzyme, but will use the enzyme that they
    + had already been associated with.
    +
    + Any pre-existing standard kcat assignments (identified by 'standard'
    + entries in model.ec.source) are removed when applying this function.
    +
    + Parameters
    + ----------
    + model : struct
    +     an ecModel in GECKO 3 format (with ecModel.ec structure).
    +
    + Name-Value Arguments
    + --------------------
    + modelAdapter : ModelAdapter
    +     a loaded model adapter (default: the current default model adapter).
    + threshold : double
    +     a threshold to determine whether to use a kcat value based on the
    +     median kcat of the reactions in the same subSystem or based on the
    +     median value of all the kcat in the model. The second option is used
    +     when the number of reactions in a determined subSystem with a real
    +     (nonzero, non-NaN) kcat value is < threshold (default 10).
    + fillZeroKcat : logical
    +     whether zero kcat values should be replaced with standard kcat values
    +     (default true).
    +
    + Returns
    + -------
    + model : struct
    +     ecModel where model.ec is expanded with a standard protein with
    +     standard kcat and standard MW, assigned to reactions without gene
    +     associations.
    + rxnsMissingGPR : cell
    +     a list of updated rxns identifiers with a standard value.
    + standardMW : double
    +     the standard MW value calculated.
    + standardKcat : double
    +     the standard kcat value calculated.
    + rxnsNoKcat : cell
    +     a list of rxns identifiers whose zero kcat has been replaced.
    +
    + Notes
    + -----
    + While model.ec.kcat is populated, applyKcatConstraints would still need to
    + be run to apply the new constraints to the S-matrix.
    +
    + Examples
    + --------
    +     % optional arguments may be given positionally or as name-value pairs:
    +     [model, rxnsMissingGPR, standardMW, standardKcat, rxnsNoKcat] = getStandardKcat(model);
    +     [model, rxnsMissingGPR, standardMW, standardKcat, rxnsNoKcat] = getStandardKcat(model, 'threshold', 20);
    +
    + See also
    + --------
    + removeStandardKcat, applyKcatConstraints
    + + +

    CROSS-REFERENCE INFORMATION ^

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

    SUBFUNCTIONS ^

    + + +

    SOURCE CODE ^

    +
    0001 function [model, rxnsMissingGPR, standardMW, standardKcat, rxnsNoKcat] = getStandardKcat(model, varargin)
    +0002 % getStandardKcat  Assign standard kcat and MW to reactions without enzymes.
    +0003 %
    +0004 % Calculates a standard kcat and standard molecular weight (MW) that can be
    +0005 % used to apply enzyme constraints to reactions without any associated
    +0006 % enzymes. Such reactions have either an empty model.grRules field, or they
    +0007 % have no match in model.ec.rxns (which can be the case if the genes in the
    +0008 % model.grRules field could not be mapped to enzymes). This is done by
    +0009 % adding those reactions to model.ec, assigning a "standard" pseudoenzyme
    +0010 % with the standard MW (median of all proteins in the organism) and standard
    +0011 % kcat (median from all kcat, or subsystem specific kcat).
    +0012 %
    +0013 % A reaction is assigned a subSystem specific kcat value if the model has a
    +0014 % subSystems field and the reaction is annotated with a subSystem. Only the
    +0015 % first subSystem will be considered if multiple are annotated to the same
    +0016 % reaction.
    +0017 %
    +0018 % Exchange, transport and pseudoreactions are filtered out, plus any
    +0019 % reaction identifiers specified in /data/pseudoRxns.tsv in the model
    +0020 % adapter folder.
    +0021 %
    +0022 % In addition, reactions that are annotated with an enzyme (and therefore
    +0023 % already in model.ec), but not assigned any reaction-specific kcat value
    +0024 % (their model.ec.kcat entry is either 0 or NaN), can be assigned standard
    +0025 % kcat values by a similar approach. However, those reactions will not be
    +0026 % linked to the "standard" pseudoenzyme, but will use the enzyme that they
    +0027 % had already been associated with.
    +0028 %
    +0029 % Any pre-existing standard kcat assignments (identified by 'standard'
    +0030 % entries in model.ec.source) are removed when applying this function.
    +0031 %
    +0032 % Parameters
    +0033 % ----------
    +0034 % model : struct
    +0035 %     an ecModel in GECKO 3 format (with ecModel.ec structure).
    +0036 %
    +0037 % Name-Value Arguments
    +0038 % --------------------
    +0039 % modelAdapter : ModelAdapter
    +0040 %     a loaded model adapter (default: the current default model adapter).
    +0041 % threshold : double
    +0042 %     a threshold to determine whether to use a kcat value based on the
    +0043 %     median kcat of the reactions in the same subSystem or based on the
    +0044 %     median value of all the kcat in the model. The second option is used
    +0045 %     when the number of reactions in a determined subSystem with a real
    +0046 %     (nonzero, non-NaN) kcat value is < threshold (default 10).
    +0047 % fillZeroKcat : logical
    +0048 %     whether zero kcat values should be replaced with standard kcat values
    +0049 %     (default true).
    +0050 %
    +0051 % Returns
    +0052 % -------
    +0053 % model : struct
    +0054 %     ecModel where model.ec is expanded with a standard protein with
    +0055 %     standard kcat and standard MW, assigned to reactions without gene
    +0056 %     associations.
    +0057 % rxnsMissingGPR : cell
    +0058 %     a list of updated rxns identifiers with a standard value.
    +0059 % standardMW : double
    +0060 %     the standard MW value calculated.
    +0061 % standardKcat : double
    +0062 %     the standard kcat value calculated.
    +0063 % rxnsNoKcat : cell
    +0064 %     a list of rxns identifiers whose zero kcat has been replaced.
    +0065 %
    +0066 % Notes
    +0067 % -----
    +0068 % While model.ec.kcat is populated, applyKcatConstraints would still need to
    +0069 % be run to apply the new constraints to the S-matrix.
    +0070 %
    +0071 % Examples
    +0072 % --------
    +0073 %     % optional arguments may be given positionally or as name-value pairs:
    +0074 %     [model, rxnsMissingGPR, standardMW, standardKcat, rxnsNoKcat] = getStandardKcat(model);
    +0075 %     [model, rxnsMissingGPR, standardMW, standardKcat, rxnsNoKcat] = getStandardKcat(model, 'threshold', 20);
    +0076 %
    +0077 % See also
    +0078 % --------
    +0079 % removeStandardKcat, applyKcatConstraints
    +0080 
    +0081 p = parseGECKOargs(varargin, { ...
    +0082     'modelAdapter', []; ...
    +0083     'threshold',    []; ...
    +0084     'fillZeroKcat', []});
    +0085 modelAdapter = p.modelAdapter;
    +0086 threshold    = p.threshold;
    +0087 fillZeroKcat = p.fillZeroKcat;
    +0088 
    +0089 if isempty(modelAdapter)
    +0090     modelAdapter = ModelAdapterManager.getDefault();
    +0091     if isempty(modelAdapter)
    +0092         error('Either send in a modelAdapter or set the default model adapter in the ModelAdapterManager.')
    +0093     end
    +0094 end
    +0095 params = modelAdapter.getParameters();
    +0096 
    +0097 if isempty(threshold)
    +0098     threshold = 10;
    +0099 end
    +0100 
    +0101 if isempty(fillZeroKcat)
    +0102     fillZeroKcat = true;
    +0103 end
    +0104 
    +0105 databases = loadDatabases('uniprot', modelAdapter);
    +0106 
    +0107 % An standard MW is defined for all the rxns which does not have a GPR
    +0108 % rule defined. This is based in all the proteins reported for the specific
    +0109 % organism in uniprot
    +0110 standardMW = median(databases.uniprot.MW, 'omitnan');
    +0111 
    +0112 % An standard Kcat is defined for all the rxns which does not have a GPR
    +0113 % rule defined. In this case, the kcat value for a particular reaction is
    +0114 % defined as the median of the kcat values of the reactions (with a real,
    +0115 % nonzero, non-NaN kcat) involved in the same subsystem in which the given
    +0116 % reaction is involved. Nevertheless, if a subSystem have a number of such
    +0117 % reactions lower than a treshold, the kcat value will be the median of the
    +0118 % kcat in all the reactions of the model.
    +0119 
    +0120 % Remove from the list those with kcat zero
    +0121 rxnsKcatZero = model.ec.kcat > 0;
    +0122 
    +0123 % Get the kcat value based on all the kcats in the model
    +0124 standardKcat = median(model.ec.kcat(rxnsKcatZero), 'omitnan');
    +0125 
    +0126 % If the model have subSystems assigned calculate kcat based on subSystem
    +0127 if isfield(model,'subSystems') && ~all(cellfun(@isempty, model.subSystems))
    +0128     standard = false;
    +0129     if model.ec.geckoLight
    +0130         modRxns = extractAfter(model.ec.rxns,4);
    +0131     else
    +0132         modRxns = model.ec.rxns;
    +0133     end
    +0134     % Map ec-rxns to model.rxns
    +0135     [~,rxnIdx]  = ismember(modRxns,model.rxns);
    +0136     % Choose first subSystem
    +0137     enzSubSystems = flattenCell(model.subSystems(rxnIdx));
    +0138     enzSubSystems = enzSubSystems(:,1);
    +0139     if ~all(cellfun(@isempty, enzSubSystems))
    +0140 
    +0141     % Make list of unique subsystems, and which rxns are linked to them
    +0142     [enzSubSystem_names, ~, rxnToSub] = unique(enzSubSystems);
    +0143     % Calculate the median kcat per subSystem, counting only reactions
    +0144     % with a real (nonzero, non-NaN) kcat toward both the median itself
    +0145     % and the threshold that decides whether a subSystem-specific value
    +0146     % is used at all.
    +0147     numSubSystem = numel(enzSubSystem_names);
    +0148     kcatsPerSubSystem = zeros(numSubSystem,1);
    +0149     kcatSubSystem = zeros(numSubSystem,1);
    +0150     for i = 1:numSubSystem
    +0151         subKcat = model.ec.kcat(rxnToSub == i);
    +0152         subKcat = subKcat(subKcat ~= 0 & ~isnan(subKcat));
    +0153         kcatsPerSubSystem(i) = numel(subKcat);
    +0154         if kcatsPerSubSystem(i) >= threshold
    +0155             kcatSubSystem(i) = median(subKcat);
    +0156         else
    +0157             kcatSubSystem(i) = standardKcat;
    +0158         end
    +0159     end
    +0160     else
    +0161         standard = true;
    +0162         printOrange('WARNING: No subSystem-specific kcat values can be calculated');
    +0163     end
    +0164 else
    +0165     standard = true;
    +0166     printOrange('WARNING: No subSystem-specific kcat values can be calculated');
    +0167 end
    +0168 
    +0169 % Find reactions without GPR
    +0170 rxnsMissingGPR = find(cellfun(@isempty, model.grRules));
    +0171 
    +0172 % Find reactions with GPR but without model.ec entry (for instance due to
    +0173 % no protein matching)
    +0174 rxnsMissingEnzyme = find(~cellfun(@isempty, model.grRules));
    +0175 if model.ec.geckoLight
    +0176     ecRxnsList = unique(extractAfter(model.ec.rxns,4));
    +0177 else
    +0178     ecRxnsList = model.ec.rxns;
    +0179 end
    +0180 rxnsMissingEnzyme = find(and(~ismember(model.rxns(rxnsMissingEnzyme),ecRxnsList), ~contains(model.rxns(rxnsMissingEnzyme),'usage_prot_')));
    +0181 rxnsMissingGPR = [rxnsMissingGPR;rxnsMissingEnzyme];
    +0182 
    +0183 % Get custom list of reaction IDs to ignore, if existing. First column
    +0184 % contains reaction IDs, second column contains reaction names for
    +0185 % reference only.
    +0186 if exist(fullfile(params.path,'data','pseudoRxns.tsv'),'file')
    +0187     fID        = fopen(fullfile(params.path,'data','pseudoRxns.tsv'));
    +0188     fileData   = textscan(fID,'%s %s','delimiter','\t');
    +0189     fclose(fID);
    +0190     customRxns = fileData{1};
    +0191     customRxns = find(ismember(model.rxns,customRxns));
    +0192 else
    +0193     customRxns = [];
    +0194 end
    +0195 % Get and remove exchange, transport, spontaneous and pseudo reactions
    +0196 [~, exchangeRxns]  = getExchangeRxns(model);
    +0197 transportRxns = getTransportRxns(model);
    +0198 [spontaneousRxns, ~] = modelAdapter.getSpontaneousReactions(model);
    +0199 pseudoRxns = contains(model.rxnNames,'pseudoreaction');
    +0200 slimeRxns = contains(model.rxnNames,'SLIME rxn');
    +0201 rxnsToIgnore = [customRxns; exchangeRxns; find(transportRxns); ...
    +0202                 find(spontaneousRxns); find(pseudoRxns); find(slimeRxns)];
    +0203 rxnsMissingGPR(ismember(rxnsMissingGPR, rxnsToIgnore)) = [];
    +0204 
    +0205 % Only add if not geckoLight & getStandardKcat was not run earlier
    +0206 if ~any(strcmp(model.mets,'prot_standard'))
    +0207     % Add a new gene to be consistent with ec field named standard
    +0208     proteinStdGenes.genes = 'standard';
    +0209     if isfield(model,'geneShortNames')
    +0210         proteinStdGenes.geneShortNames = 'std';
    +0211     end
    +0212     model = addGenesRaven(model, proteinStdGenes);
    +0213 
    +0214     if ~model.ec.geckoLight
    +0215         % Add a new metabolite named prot_standard
    +0216         proteinStdMets.mets         = 'prot_standard';
    +0217         proteinStdMets.metNames     = proteinStdMets.mets;
    +0218         % Validate compartment
    +0219         compartmentID = strcmp(model.compNames,params.enzyme_comp);
    +0220         if ~any(compartmentID)
    +0221             error(['Compartment ' params.enzyme_comp ' (specified in params.enzyme_comp) '...
    +0222                 'cannot be found in model.compNames'])
    +0223         end
    +0224         proteinStdMets.compartments = model.comps(compartmentID);
    +0225 
    +0226         if isfield(model,'metNotes')
    +0227             proteinStdMets.metNotes = 'Standard enzyme-usage pseudometabolite';
    +0228         end
    +0229         model = addMets(model, proteinStdMets);
    +0230 
    +0231         % Add a protein usage reaction if not a light version
    +0232         proteinStdUsageRxn.rxns         = {'usage_prot_standard'};
    +0233         proteinStdUsageRxn.rxnNames     = proteinStdUsageRxn.rxns;
    +0234         proteinStdUsageRxn.mets         = {proteinStdMets.mets, 'prot_pool'};
    +0235         proteinStdUsageRxn.stoichCoeffs = [1, -1];
    +0236         proteinStdUsageRxn.lb           = 0;
    +0237         proteinStdUsageRxn.ub           = 1000;
    +0238         proteinStdUsageRxn.grRules      = proteinStdGenes.genes;
    +0239 
    +0240         model = addRxns(model, proteinStdUsageRxn);
    +0241     end
    +0242     % Update .ec structure in model
    +0243     model.ec.genes(end+1)      = {'standard'};
    +0244     model.ec.enzymes(end+1)    = {'standard'};
    +0245     model.ec.mw(end+1)         = standardMW;
    +0246     model.ec.sequence(end+1)   = {''};
    +0247     % Additional info
    +0248     if isfield(model.ec,'concs')
    +0249         model.ec.concs(end+1)  = nan();
    +0250     end
    +0251 
    +0252     % Expand the enzyme rxns matrix
    +0253     model.ec.rxnEnzMat =  [model.ec.rxnEnzMat, zeros(length(model.ec.rxns), 1)]; % 1 new enzyme
    +0254     model.ec.rxnEnzMat =  [model.ec.rxnEnzMat; zeros(length(rxnsMissingGPR), length(model.ec.enzymes))]; % new rxns
    +0255 end
    +0256 stdMetIdx = find(strcmpi(model.ec.enzymes, 'standard'));
    +0257 
    +0258 % Remove previous standard kcat assignment
    +0259 oldStandardEnz = find(strcmp(model.ec.source,'standard'));
    +0260 if ~isempty(oldStandardEnz)
    +0261     oldStandardProt = logical(model.ec.rxnEnzMat(oldStandardEnz,stdMetIdx));
    +0262     % If annotated with real enzyme => set kcat to zero
    +0263     model.ec.kcat(oldStandardEnz(~oldStandardProt))        = 0;
    +0264     model.ec.source(oldStandardEnz(~oldStandardProt))      = {''};
    +0265     % If annotated with standard protein => remove entry
    +0266     model.ec.rxns(oldStandardEnz(oldStandardProt))        = [];
    +0267     model.ec.kcat(oldStandardEnz(oldStandardProt))        = [];
    +0268     model.ec.source(oldStandardEnz(oldStandardProt))      = [];
    +0269     model.ec.notes(oldStandardEnz(oldStandardProt))       = [];
    +0270     model.ec.eccodes(oldStandardEnz(oldStandardProt))     = [];
    +0271     model.ec.rxnEnzMat(oldStandardEnz(oldStandardProt),:) = [];
    +0272 end
    +0273 
    +0274 numRxns = length(model.ec.rxns);
    +0275 for i = 1:numel(rxnsMissingGPR)
    +0276     rxnIdx = rxnsMissingGPR(i);
    +0277 
    +0278     % Update .ec structure in model
    +0279     if ~model.ec.geckoLight
    +0280         model.ec.rxns(end+1)     = model.rxns(rxnIdx);
    +0281         % Add prefix in case is light version
    +0282     else
    +0283         model.ec.rxns{end+1}     = ['001_' model.rxns{rxnIdx}];
    +0284     end
    +0285 
    +0286     if ~standard
    +0287         % kcatSubSystemIdx is a one-hot vector (the reaction's first subSystem
    +0288         % matched against every subSystem that has a computed kcat); any(), not
    +0289         % all(), is the right test -- all() only ever succeeds when the model
    +0290         % has exactly one subSystem in total, silently falling back to the
    +0291         % model-wide standardKcat for every reaction otherwise.
    +0292         kcatSubSystemIdx = strcmpi(enzSubSystem_names, model.subSystems{rxnIdx}(1));
    +0293         if any(kcatSubSystemIdx)
    +0294             model.ec.kcat(end+1) = kcatSubSystem(kcatSubSystemIdx);
    +0295         else
    +0296             model.ec.kcat(end+1) = standardKcat;
    +0297         end
    +0298     else
    +0299         model.ec.kcat(end+1) = standardKcat;
    +0300     end
    +0301 
    +0302     model.ec.source(end+1)   = {'standard'};
    +0303     model.ec.notes(end+1)    = {''};
    +0304     model.ec.eccodes(end+1)  = {''};
    +0305 
    +0306     % Update the enzyme rxns matrix
    +0307     model.ec.rxnEnzMat(numRxns+i, stdMetIdx) = 1;
    +0308 end
    +0309 % Get the rxns identifiers of the updated rxns
    +0310 rxnsMissingGPR = model.rxns(rxnsMissingGPR);
    +0311 
    +0312 if fillZeroKcat
    +0313     zeroKcat = model.ec.kcat == 0 | isnan(model.ec.kcat);
    +0314     model.ec.kcat(zeroKcat)     = standardKcat;
    +0315     model.ec.source(zeroKcat)   = {'standard'};
    +0316     rxnsNoKcat = model.ec.rxns(zeroKcat);
    +0317 else
    +0318     rxnsNoKcat = [];
    +0319 end
    +0320 end
    +0321 
    +0322 function Cflat = flattenCell(C,strFlag)
    +0323 %FLATTENCELL  Flatten a nested column cell array into a matrix cell array.
    +0324 %
    +0325 % CFLAT = FLATTENCELL(C) takes a column cell array in which one or more
    +0326 % entries is a nested cell array, and flattens it into a 2D matrix cell
    +0327 % array, where the nested entries are spread across new columns.
    +0328 %
    +0329 % CFLAT = FLATTENCELL(C,STRFLAG) if STRFLAG is TRUE, empty entries in the
    +0330 % resulting CFLAT will be replaced with empty strings {''}. Default = FALSE
    +0331 if nargin < 2
    +0332     strFlag = false;
    +0333 end
    +0334 
    +0335 % determine which entries are cells
    +0336 cells = cellfun(@iscell,C);
    +0337 
    +0338 % determine number of elements in each nested cell
    +0339 cellsizes = cellfun(@numel,C);
    +0340 cellsizes(~cells) = 1;  % ignore non-cell entries
    +0341 
    +0342 % flatten single-entry cells
    +0343 Cflat = C;
    +0344 Cflat(cells & (cellsizes == 1)) = cellfun(@(x) x{1},Cflat(cells & (cellsizes == 1)),'UniformOutput',false);
    +0345 
    +0346 % iterate through multi-entry cells
    +0347 multiCells = find(cellsizes > 1);
    +0348 for i = 1:length(multiCells)
    +0349     cellContents = Cflat{multiCells(i)};
    +0350     Cflat(multiCells(i),1:length(cellContents)) = cellContents;
    +0351 end
    +0352 
    +0353 % change empty elements to strings, if specified
    +0354 if ( strFlag )
    +0355     Cflat(cellfun(@isempty,Cflat)) = {''};
    +0356 end
    +0357 end
    +
    Generated by m2html © 2005
    + + \ No newline at end of file diff --git a/doc/src/gather_kcats/index.html b/doc/src/gather_kcats/index.html new file mode 100644 index 00000000..b2b58186 --- /dev/null +++ b/doc/src/gather_kcats/index.html @@ -0,0 +1,29 @@ + + + + Index for Directory src/gather_kcats + + + + + + + + + + +
    < Master indexIndex for src/gather_kcats >
    + +

    Index for src/gather_kcats

    + +

    Matlab files in this directory:

    + +
     assignKcatValuesassignKcatValues Select one kcat value per reaction and write to model.ec.
     assignKcatsassignKcats Assign kcats from the kcat source files and apply them.
     collectKcatscollectKcats Decide one kcat per reaction from the kcat source files.
     convertCustomKcatsconvertCustomKcats Convert data/customKcats.tsv into data/kcats/custom.tsv.
     ecStatsFromBrendaecStatsFromBrenda Summarise loadBRENDAdata's output per EC number, for
     ecTreeEstimateecTreeEstimate EC-tree kcat estimates for EC numbers.
     extractEnzymeSubstratePairsextractEnzymeSubstratePairs The enzyme-substrate pairs of an ecModel's reactions.
     fetchOpenKineticsPredictorfetchOpenKineticsPredictor Fetch and parse an OpenKineticsPredictor job.
     fuzzyKcatMatchingfuzzyKcatMatching Match model EC numbers and substrates to BRENDA kcats.
     getEcRxnKeysgetEcRxnKeys Build-independent keys of the model.ec reactions.
     getStandardKcatgetStandardKcat Assign standard kcat and MW to reactions without enzymes.
     kcatAssignmentConfigkcatAssignmentConfig The kcat assignment settings of a model adapter.
     kcatsFromBrendakcatsFromBrenda Gather kcats from BRENDA and keep them as a source file.
     kcatsFromDLKcatkcatsFromDLKcat Gather kcats from DLKcat and keep them as a source file.
     kcatsFromECTreekcatsFromECTree Estimate kcats from the EC tree and keep them as a source file.
     kcatsFromHomologskcatsFromHomologs Estimate kcats from measured homologs and keep them as a source file.
     kcatsFromOKPkcatsFromOKP Gather kcats from OpenKineticsPredictor and keep them as a source file.
     loadBrendaMeasurementsloadBrendaMeasurements Load the BRENDA measurement table.
     loadKcatSourceloadKcatSource Read a kcat source file and map its rows to an ecModel.
     mergeDLKcatAndFuzzyKcatsmergeDLKcatAndFuzzyKcats Merge DLKcat and BRENDA fuzzy matching results.
     mergeKcatsmergeKcats Merge any number of kcatLists, keeping the highest-priority
     readDLKcatOutputreadDLKcatOutput Read the DLKcat output file into a kcatList structure.
     readOpenKineticsPredictorOutputreadOpenKineticsPredictorOutput Read OpenKineticsPredictor output to kcatList.
     removeStandardKcatremoveStandardKcat Remove the standard pseudoenzyme and standard kcats.
     resolveOkpApiKeyresolveOkpApiKey Resolve the OpenKineticsPredictor API key.
     reviewKcatAssignmentreviewKcatAssignment Flag kcat assignments that deserve a second look.
     runDLKcatrunDLKcat Run DLKcat to predict kcat values from a Docker image.
     saveKcatSourcesaveKcatSource Write a kcatList to a kcat source file of the project.
     submitOpenKineticsPredictorsubmitOpenKineticsPredictor Submit a kcat prediction job to OpenKineticsPredictor.
     updateKcatSourcesupdateKcatSources Gather the kcat sources that the configuration needs.
     writeDLKcatInputwriteDLKcatInput Prepare and write the input file for DLKcat.
     writeOpenKineticsPredictorInputwriteOpenKineticsPredictorInput Write input file for OpenKineticsPredictor.
    + + + + +
    Generated by m2html © 2005
    + + \ No newline at end of file diff --git a/doc/src/gather_kcats/kcatAssignmentConfig.html b/doc/src/gather_kcats/kcatAssignmentConfig.html new file mode 100644 index 00000000..7f3636b9 --- /dev/null +++ b/doc/src/gather_kcats/kcatAssignmentConfig.html @@ -0,0 +1,244 @@ + + + + Description of kcatAssignmentConfig + + + + + + + + + +
    Home > src > gather_kcats > kcatAssignmentConfig.m
    + + + +

    kcatAssignmentConfig +

    + +

    PURPOSE ^

    +
    kcatAssignmentConfig The kcat assignment settings of a model adapter.
    + +

    SYNOPSIS ^

    +
    function config = kcatAssignmentConfig(params)
    + +

    DESCRIPTION ^

    +
     kcatAssignmentConfig  The kcat assignment settings of a model adapter.
    +
    + Reads [kcat_assignment] and [kcat_sources.*] of model_adapter.toml (or
    + params.kcat_assignment and params.kcat_sources of an adapter class), and
    + expands a preset into its stages, as collectKcats and updateKcatSources
    + use them. Without a preset or stages the preset is brenda_ec_tree.
    + geckopy's kcat_assignment_config gives the same settings.
    +
    + Parameters
    + ----------
    + params : struct
    +     the parameters of a model adapter (modelAdapter.params).
    +
    + Returns
    + -------
    + config : struct
    +     - preset: the preset name, or '' when stages are given;
    +     - isozymes, standard: logical;
    +     - stages: struct array with action ('select' or 'combine'), sources
    +       (cell, as given), files (the source files they read, with okp
    +       replaced by the files of its methods), criteria, topOriginLimit,
    +       bottomOriginLimit and wildcardLimit;
    +     - okpMethods: the OKP methods of the okp source group ([kcat_sources.okp]
    +       methods; default all methods with combination parameters);
    +     - sources: per source name its options (from [kcat_sources] and the
    +       preset).
    +
    + Examples
    + --------
    +     config = kcatAssignmentConfig(modelAdapter.params);
    +     config.stages(1).sources   % the order of the sources
    +
    + See also
    + --------
    + collectKcats, assignKcats, updateKcatSources
    + + +

    CROSS-REFERENCE INFORMATION ^

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

    SUBFUNCTIONS ^

    + + +

    SOURCE CODE ^

    +
    0001 function config = kcatAssignmentConfig(params)
    +0002 % kcatAssignmentConfig  The kcat assignment settings of a model adapter.
    +0003 %
    +0004 % Reads [kcat_assignment] and [kcat_sources.*] of model_adapter.toml (or
    +0005 % params.kcat_assignment and params.kcat_sources of an adapter class), and
    +0006 % expands a preset into its stages, as collectKcats and updateKcatSources
    +0007 % use them. Without a preset or stages the preset is brenda_ec_tree.
    +0008 % geckopy's kcat_assignment_config gives the same settings.
    +0009 %
    +0010 % Parameters
    +0011 % ----------
    +0012 % params : struct
    +0013 %     the parameters of a model adapter (modelAdapter.params).
    +0014 %
    +0015 % Returns
    +0016 % -------
    +0017 % config : struct
    +0018 %     - preset: the preset name, or '' when stages are given;
    +0019 %     - isozymes, standard: logical;
    +0020 %     - stages: struct array with action ('select' or 'combine'), sources
    +0021 %       (cell, as given), files (the source files they read, with okp
    +0022 %       replaced by the files of its methods), criteria, topOriginLimit,
    +0023 %       bottomOriginLimit and wildcardLimit;
    +0024 %     - okpMethods: the OKP methods of the okp source group ([kcat_sources.okp]
    +0025 %       methods; default all methods with combination parameters);
    +0026 %     - sources: per source name its options (from [kcat_sources] and the
    +0027 %       preset).
    +0028 %
    +0029 % Examples
    +0030 % --------
    +0031 %     config = kcatAssignmentConfig(modelAdapter.params);
    +0032 %     config.stages(1).sources   % the order of the sources
    +0033 %
    +0034 % See also
    +0035 % --------
    +0036 % collectKcats, assignKcats, updateKcatSources
    +0037 
    +0038 a = struct();
    +0039 if isfield(params, 'kcat_assignment') && isstruct(params.kcat_assignment)
    +0040     a = params.kcat_assignment;
    +0041 end
    +0042 config.preset = '';
    +0043 config.isozymes = getOr(a, 'isozymes', true);
    +0044 config.standard = getOr(a, 'standard', true);
    +0045 config.sources = struct();
    +0046 hasPreset = isfield(a, 'preset') && ~isempty(a.preset);
    +0047 hasStages = isfield(a, 'stage') && ~isempty(a.stage);
    +0048 if hasPreset && hasStages
    +0049     error('kcatAssignment:config', ['[kcat_assignment] gives both a preset and stages; ' ...
    +0050         'give one of the two.'])
    +0051 end
    +0052 if hasStages
    +0053     config.stages = arrayfun(@readStage, a.stage(:)');
    +0054 else
    +0055     preset = 'brenda_ec_tree';
    +0056     if hasPreset
    +0057         preset = char(a.preset);
    +0058     end
    +0059     [config.stages, config.sources] = presetStages(preset);
    +0060     config.preset = preset;
    +0061 end
    +0062 if isfield(params, 'kcat_sources') && isstruct(params.kcat_sources)
    +0063     names = fieldnames(params.kcat_sources);
    +0064     for k = 1:numel(names)
    +0065         config.sources.(names{k}) = params.kcat_sources.(names{k});
    +0066     end
    +0067 end
    +0068 % The okp group: the OKP methods of [kcat_sources.okp] methods.
    +0069 known = {'CataPro','CatPred','CatRange','DLKcat','EITLEM','KinForm-H','KinForm-L', ...
    +0070     'OmniESI','OmniESI-O2DENet','TurNup','UniKP'};
    +0071 % The default: methods that read enzyme-substrate pairs and have combination
    +0072 % parameters (CatRange predicts classes; CatPred and TurNup read whole
    +0073 % reactions, which kcatsFromOKP does not submit).
    +0074 config.okpMethods = known(~ismember(known, {'CatRange', 'CatPred', 'TurNup'}));
    +0075 if isfield(config.sources, 'okp') && isfield(config.sources.okp, 'methods') && ~isempty(config.sources.okp.methods)
    +0076     config.okpMethods = cellstr(config.sources.okp.methods);
    +0077     config.okpMethods = config.okpMethods(:)';
    +0078 end
    +0079 unknown = setdiff(config.okpMethods, known);
    +0080 if ~isempty(unknown)
    +0081     error('kcatAssignment:config', 'Unknown OKP methods in [kcat_sources.okp] methods: %s; methods: %s.', ...
    +0082         strjoin(unknown, ', '), strjoin(known, ', '))
    +0083 end
    +0084 okpFiles = cellfun(@(m) ['okp_' lower(regexprep(regexprep(m, '[^A-Za-z0-9]+', '_'), '^_+|_+$', ''))], ...
    +0085     config.okpMethods, 'UniformOutput', false);
    +0086 for s = 1:numel(config.stages)
    +0087     files = {};
    +0088     for t = config.stages(s).sources
    +0089         if strcmp(t{1}, 'okp')
    +0090             files = [files, okpFiles]; %#ok<AGROW>
    +0091         else
    +0092             files{end+1} = t{1}; %#ok<AGROW>
    +0093         end
    +0094     end
    +0095     [~, first] = unique(files, 'stable');
    +0096     config.stages(s).files = files(sort(first));
    +0097 end
    +0098 end
    +0099 
    +0100 function [stages, sources] = presetStages(preset)
    +0101 % The presets of kcat assignment; geckopy defines the same.
    +0102 stage = @(action, srcs, top) struct('action', action, 'sources', {srcs}, 'criteria', 'max', ...
    +0103     'topOriginLimit', top, 'bottomOriginLimit', 6, 'wildcardLimit', 3);
    +0104 order = {'custom', 'database_top', 'dlkcat', 'database_bottom'};
    +0105 own = {'custom', 'database_top'}; % with topOriginLimit 1: the organism's own BRENDA value
    +0106 sources = struct();
    +0107 switch preset
    +0108     case 'brenda_ec_tree'
    +0109         stages = [stage('select', [own, {'ec_tree'}], 1), stage('combine', {'okp'}, 4)];
    +0110         sources.brenda = struct('aggregation', 'median');
    +0111         sources.ec_tree = struct('k', 5);
    +0112     case 'ec_tree_homologs'
    +0113         stages = [stage('select', own, 1), stage('combine', {'ec_tree', 'homologs'}, 4), ...
    +0114             stage('combine', {'okp'}, 4)];
    +0115         sources.brenda = struct('aggregation', 'median');
    +0116         sources.ec_tree = struct('k', 5);
    +0117     case 'ec_tree_okp'
    +0118         stages = [stage('select', own, 1), stage('combine', {'ec_tree', 'homologs', 'okp'}, 4), ...
    +0119             stage('combine', {'okp'}, 4)];
    +0120         sources.brenda = struct('aggregation', 'median');
    +0121         sources.ec_tree = struct('k', 5);
    +0122     case 'okp'
    +0123         stages = [stage('select', {'custom'}, 4), stage('combine', {'okp'}, 4)];
    +0124     case 'gecko_median'
    +0125         stages = stage('select', order, 4);
    +0126         sources.brenda = struct('aggregation', 'median');
    +0127     case 'gecko_classic'
    +0128         stages = stage('select', order, 6);
    +0129         sources.brenda = struct('aggregation', 'max');
    +0130     otherwise
    +0131         error('kcatAssignment:config', 'Unknown kcat assignment preset "%s". Presets: %s.', ...
    +0132             preset, 'brenda_ec_tree, ec_tree_homologs, ec_tree_okp, okp, gecko_median, gecko_classic')
    +0133 end
    +0134 end
    +0135 
    +0136 function stage = readStage(s)
    +0137 stage.action = getOr(s, 'action', 'select');
    +0138 if ~any(strcmp(stage.action, {'select', 'combine'}))
    +0139     error('kcatAssignment:config', ['Unknown stage action "%s"; this GECKO version knows ' ...
    +0140         '"select" and "combine".'], stage.action)
    +0141 end
    +0142 sources = getOr(s, 'sources', {});
    +0143 if ischar(sources)
    +0144     sources = {sources};
    +0145 end
    +0146 if isempty(sources)
    +0147     error('kcatAssignment:config', 'A [[kcat_assignment.stage]] needs sources.')
    +0148 end
    +0149 stage.sources = sources(:)';
    +0150 stage.criteria = validatestring(getOr(s, 'criteria', 'max'), {'max','min','median','mean'});
    +0151 stage.topOriginLimit = getOr(s, 'top_origin_limit', 4);
    +0152 stage.bottomOriginLimit = getOr(s, 'bottom_origin_limit', 6);
    +0153 stage.wildcardLimit = getOr(s, 'wildcard_limit', 3);
    +0154 end
    +0155 
    +0156 function v = getOr(s, field, default)
    +0157 v = default;
    +0158 if isstruct(s) && isfield(s, field) && ~isempty(s.(field))
    +0159     v = s.(field);
    +0160 end
    +0161 end
    +
    Generated by m2html © 2005
    + + \ No newline at end of file diff --git a/doc/src/gather_kcats/kcatsFromBrenda.html b/doc/src/gather_kcats/kcatsFromBrenda.html new file mode 100644 index 00000000..20aead8a --- /dev/null +++ b/doc/src/gather_kcats/kcatsFromBrenda.html @@ -0,0 +1,243 @@ + + + + Description of kcatsFromBrenda + + + + + + + + + +
    Home > src > gather_kcats > kcatsFromBrenda.m
    + + + +

    kcatsFromBrenda +

    + +

    PURPOSE ^

    +
    kcatsFromBrenda Gather kcats from BRENDA and keep them as a source file.
    + +

    SYNOPSIS ^

    +
    function kcatList = kcatsFromBrenda(model, varargin)
    + +

    DESCRIPTION ^

    +
     kcatsFromBrenda  Gather kcats from BRENDA and keep them as a source file.
    +
    + Matches the model's EC numbers and substrates to BRENDA by fuzzy
    + matching (see fuzzyKcatMatching), and writes the result to
    + data/kcats/brenda.tsv in the project folder (see saveKcatSource). The
    + matching runs locally on the BRENDA files of GECKO.
    +
    + Parameters
    + ----------
    + model : struct
    +     an ecModel in GECKO 3 format (with ecModel.ec structure), with EC
    +     numbers (getECfromDatabase or getECfromGEM).
    +
    + Name-Value Arguments
    + --------------------
    + aggregation : char
    +     which BRENDA value per EC number, substrate and organism is used:
    +     'max' or 'median' (default: params.kcatAggregation of the model
    +     adapter, or 'max').
    + forceWClvl : double
    +     number of extra levels, from the right, replaced by a wildcard in the
    +     EC numbers (on top of any wildcard already in the code; default 0).
    + ecRxns : logical or double
    +     for which model.ec.rxns kcats are gathered (default: all). A logical
    +     vector or indices of model.ec.rxns, see fuzzyKcatMatching; [] selects
    +     all reactions and any other empty selection is an error.
    + save : logical
    +     write the source file (default true).
    + saveAs : char
    +     name of the source file, without .tsv (default 'brenda'). With
    +     ecRxns, the file then only holds those reactions.
    + modelAdapter : ModelAdapter
    +     a loaded model adapter (default: the current default model adapter).
    +
    + Returns
    + -------
    + kcatList : struct
    +     the kcat values, as returned by fuzzyKcatMatching.
    +
    + Examples
    + --------
    +     kcatsFromBrenda(ecModel);
    +     kcatList = kcatsFromBrenda(ecModel, 'aggregation', 'median');
    +
    + See also
    + --------
    + fuzzyKcatMatching, kcatsFromDLKcat, kcatsFromOKP, saveKcatSource, loadKcatSource
    + + +

    CROSS-REFERENCE INFORMATION ^

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

    SUBFUNCTIONS ^

    + + +

    SOURCE CODE ^

    +
    0001 function kcatList = kcatsFromBrenda(model, varargin)
    +0002 % kcatsFromBrenda  Gather kcats from BRENDA and keep them as a source file.
    +0003 %
    +0004 % Matches the model's EC numbers and substrates to BRENDA by fuzzy
    +0005 % matching (see fuzzyKcatMatching), and writes the result to
    +0006 % data/kcats/brenda.tsv in the project folder (see saveKcatSource). The
    +0007 % matching runs locally on the BRENDA files of GECKO.
    +0008 %
    +0009 % Parameters
    +0010 % ----------
    +0011 % model : struct
    +0012 %     an ecModel in GECKO 3 format (with ecModel.ec structure), with EC
    +0013 %     numbers (getECfromDatabase or getECfromGEM).
    +0014 %
    +0015 % Name-Value Arguments
    +0016 % --------------------
    +0017 % aggregation : char
    +0018 %     which BRENDA value per EC number, substrate and organism is used:
    +0019 %     'max' or 'median' (default: params.kcatAggregation of the model
    +0020 %     adapter, or 'max').
    +0021 % forceWClvl : double
    +0022 %     number of extra levels, from the right, replaced by a wildcard in the
    +0023 %     EC numbers (on top of any wildcard already in the code; default 0).
    +0024 % ecRxns : logical or double
    +0025 %     for which model.ec.rxns kcats are gathered (default: all). A logical
    +0026 %     vector or indices of model.ec.rxns, see fuzzyKcatMatching; [] selects
    +0027 %     all reactions and any other empty selection is an error.
    +0028 % save : logical
    +0029 %     write the source file (default true).
    +0030 % saveAs : char
    +0031 %     name of the source file, without .tsv (default 'brenda'). With
    +0032 %     ecRxns, the file then only holds those reactions.
    +0033 % modelAdapter : ModelAdapter
    +0034 %     a loaded model adapter (default: the current default model adapter).
    +0035 %
    +0036 % Returns
    +0037 % -------
    +0038 % kcatList : struct
    +0039 %     the kcat values, as returned by fuzzyKcatMatching.
    +0040 %
    +0041 % Examples
    +0042 % --------
    +0043 %     kcatsFromBrenda(ecModel);
    +0044 %     kcatList = kcatsFromBrenda(ecModel, 'aggregation', 'median');
    +0045 %
    +0046 % See also
    +0047 % --------
    +0048 % fuzzyKcatMatching, kcatsFromDLKcat, kcatsFromOKP, saveKcatSource, loadKcatSource
    +0049 
    +0050 checkOptions(varargin, {'aggregation','forceWClvl','ecRxns','save','saveAs','modelAdapter'}, 'kcatsFromBrenda');
    +0051 p = parseGECKOargs(varargin, { ...
    +0052     'aggregation',  []; ...
    +0053     'forceWClvl',   0; ...
    +0054     'ecRxns',       []; ...
    +0055     'save',         true; ...
    +0056     'saveAs',       'brenda'; ...
    +0057     'modelAdapter', []});
    +0058 modelAdapter = p.modelAdapter;
    +0059 if isempty(modelAdapter)
    +0060     modelAdapter = ModelAdapterManager.getDefault();
    +0061     if isempty(modelAdapter)
    +0062         error('Either send in a modelAdapter or set the default model adapter in the ModelAdapterManager.')
    +0063     end
    +0064 end
    +0065 aggregation = resolveKcatAggregation(p.aggregation, modelAdapter);
    +0066 if isSubset(p.ecRxns) && countSelected(p.ecRxns) == 0
    +0067     error('kcatsFromBrenda:emptySubset', ...
    +0068         'ecRxns selects no reactions; leave it out to gather for all reactions.');
    +0069 end
    +0070 if p.save
    +0071     file = fullfile(modelAdapter.params.path, 'data', 'kcats', [char(p.saveAs) '.tsv']);
    +0072     warnSubset(p.ecRxns, numel(model.ec.rxns), file);
    +0073 end
    +0074 
    +0075 kcatList = fuzzyKcatMatching(model, 'ecRxns', p.ecRxns, 'modelAdapter', modelAdapter, ...
    +0076     'forceWClvl', p.forceWClvl, 'kcatAggregation', aggregation);
    +0077 
    +0078 if p.save
    +0079     parameters = struct('aggregation', aggregation, 'force_wildcard_level', p.forceWClvl);
    +0080     if isSubset(p.ecRxns)
    +0081         parameters.ec_rxns = numel(kcatList.rxns);
    +0082     end
    +0083     saveKcatSource(model, kcatList, p.saveAs, 'modelAdapter', modelAdapter, ...
    +0084         'generator', 'kcatsFromBrenda', 'parameters', parameters, ...
    +0085         'data', brendaRelease(modelAdapter));
    +0086     fprintf('BRENDA kcats for %d reactions written to %s\n', sum(kcatList.kcats > 0), file);
    +0087 end
    +0088 end
    +0089 
    +0090 function release = brendaRelease(modelAdapter)
    +0091 % The release line at the top of kcat.tsv, e.g. 'BRENDA release 2026.1'.
    +0092 release = '';
    +0093 file = fullfile(modelAdapter.getBrendaDBFolder(), 'kcat.tsv');
    +0094 fid = fopen(file, 'r');
    +0095 if fid < 0
    +0096     return
    +0097 end
    +0098 line = fgetl(fid);
    +0099 fclose(fid);
    +0100 tok = regexp(line, '^#\s*(BRENDA release [^ ]+)', 'tokens', 'once');
    +0101 if ~isempty(tok)
    +0102     release = tok{1};
    +0103 end
    +0104 end
    +0105 
    +0106 function tf = isSubset(ecRxns)
    +0107 % [] selects all reactions; any other value selects the reactions it names.
    +0108 tf = ~(isnumeric(ecRxns) && isequal(size(ecRxns),[0 0]));
    +0109 end
    +0110 
    +0111 function n = countSelected(ecRxns)
    +0112 if islogical(ecRxns)
    +0113     n = sum(ecRxns);
    +0114 else
    +0115     n = numel(ecRxns);
    +0116 end
    +0117 end
    +0118 
    +0119 function n = countRxns(ecRxns)
    +0120 if islogical(ecRxns)
    +0121     n = sum(ecRxns);
    +0122 else
    +0123     n = numel(unique(ecRxns));
    +0124 end
    +0125 end
    +0126 
    +0127 function warnSubset(ecRxns, nRxns, file)
    +0128 % A subset written under the default name replaces the full file.
    +0129 if isSubset(ecRxns) && countRxns(ecRxns) < nRxns && isfile(file)
    +0130     printOrange(sprintf(['%s is replaced by kcats for %d reactions only. Give saveAs ' ...
    +0131         'to keep it.\n'], file, countRxns(ecRxns)));
    +0132 end
    +0133 end
    +0134 
    +0135 function checkOptions(args, names, functionName)
    +0136 % Options are name-value pairs with known names, so a misspelled option is
    +0137 % an error instead of being taken as a positional argument.
    +0138 id = [functionName ':arguments'];
    +0139 given = args(1:2:end);
    +0140 if mod(numel(args), 2) ~= 0 || ~all(cellfun(@(x) ischar(x) || (isstring(x) && isscalar(x)), given))
    +0141     error(id, 'Options of %s are name-value pairs. Options: %s.', functionName, strjoin(names, ', '))
    +0142 end
    +0143 unknown = setdiff(cellfun(@char, given, 'UniformOutput', false), names);
    +0144 if ~isempty(unknown)
    +0145     error(id, 'Unknown option of %s: %s. Options: %s.', functionName, strjoin(unknown, ', '), ...
    +0146         strjoin(names, ', '))
    +0147 end
    +0148 end
    +
    Generated by m2html © 2005
    + + \ No newline at end of file diff --git a/doc/src/gather_kcats/kcatsFromDLKcat.html b/doc/src/gather_kcats/kcatsFromDLKcat.html new file mode 100644 index 00000000..81610980 --- /dev/null +++ b/doc/src/gather_kcats/kcatsFromDLKcat.html @@ -0,0 +1,237 @@ + + + + Description of kcatsFromDLKcat + + + + + + + + + +
    Home > src > gather_kcats > kcatsFromDLKcat.m
    + + + +

    kcatsFromDLKcat +

    + +

    PURPOSE ^

    +
    kcatsFromDLKcat Gather kcats from DLKcat and keep them as a source file.
    + +

    SYNOPSIS ^

    +
    function kcatList = kcatsFromDLKcat(model, varargin)
    + +

    DESCRIPTION ^

    +
     kcatsFromDLKcat  Gather kcats from DLKcat and keep them as a source file.
    +
    + Predicts kcats with DLKcat and writes them to data/kcats/dlkcat.tsv in
    + the project folder (see saveKcatSource). With 'run', true it writes the
    + DLKcat input (writeDLKcatInput) and runs DLKcat through its Docker image
    + (runDLKcat), which needs Docker; otherwise it reads the output of an
    + earlier run (readDLKcatOutput). A run records how many reactions it
    + covered in data/DLKcat_run.txt, so that the source file says so also when
    + the output is read later.
    +
    + Parameters
    + ----------
    + model : struct
    +     an ecModel in GECKO 3 format (with ecModel.ec structure), with
    +     metabolite SMILES (findMetSmiles) and protein sequences.
    +
    + Name-Value Arguments
    + --------------------
    + run : logical
    +     write the input and run DLKcat; false reads the existing output in
    +     data/DLKcat.tsv (default false).
    + ecRxns : logical
    +     for which model.ec.rxns DLKcat is run (default: all). Only used with
    +     'run', true.
    + save : logical
    +     write the source file (default true).
    + saveAs : char
    +     name of the source file, without .tsv (default 'dlkcat').
    + modelAdapter : ModelAdapter
    +     a loaded model adapter (default: the current default model adapter).
    +
    + Returns
    + -------
    + kcatList : struct
    +     the kcat values, as returned by readDLKcatOutput.
    +
    + Examples
    + --------
    +     kcatsFromDLKcat(ecModel, 'run', true);
    +     kcatList = kcatsFromDLKcat(ecModel);
    +
    + See also
    + --------
    + writeDLKcatInput, runDLKcat, readDLKcatOutput, kcatsFromBrenda, saveKcatSource
    + + +

    CROSS-REFERENCE INFORMATION ^

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

    SUBFUNCTIONS ^

    + + +

    SOURCE CODE ^

    +
    0001 function kcatList = kcatsFromDLKcat(model, varargin)
    +0002 % kcatsFromDLKcat  Gather kcats from DLKcat and keep them as a source file.
    +0003 %
    +0004 % Predicts kcats with DLKcat and writes them to data/kcats/dlkcat.tsv in
    +0005 % the project folder (see saveKcatSource). With 'run', true it writes the
    +0006 % DLKcat input (writeDLKcatInput) and runs DLKcat through its Docker image
    +0007 % (runDLKcat), which needs Docker; otherwise it reads the output of an
    +0008 % earlier run (readDLKcatOutput). A run records how many reactions it
    +0009 % covered in data/DLKcat_run.txt, so that the source file says so also when
    +0010 % the output is read later.
    +0011 %
    +0012 % Parameters
    +0013 % ----------
    +0014 % model : struct
    +0015 %     an ecModel in GECKO 3 format (with ecModel.ec structure), with
    +0016 %     metabolite SMILES (findMetSmiles) and protein sequences.
    +0017 %
    +0018 % Name-Value Arguments
    +0019 % --------------------
    +0020 % run : logical
    +0021 %     write the input and run DLKcat; false reads the existing output in
    +0022 %     data/DLKcat.tsv (default false).
    +0023 % ecRxns : logical
    +0024 %     for which model.ec.rxns DLKcat is run (default: all). Only used with
    +0025 %     'run', true.
    +0026 % save : logical
    +0027 %     write the source file (default true).
    +0028 % saveAs : char
    +0029 %     name of the source file, without .tsv (default 'dlkcat').
    +0030 % modelAdapter : ModelAdapter
    +0031 %     a loaded model adapter (default: the current default model adapter).
    +0032 %
    +0033 % Returns
    +0034 % -------
    +0035 % kcatList : struct
    +0036 %     the kcat values, as returned by readDLKcatOutput.
    +0037 %
    +0038 % Examples
    +0039 % --------
    +0040 %     kcatsFromDLKcat(ecModel, 'run', true);
    +0041 %     kcatList = kcatsFromDLKcat(ecModel);
    +0042 %
    +0043 % See also
    +0044 % --------
    +0045 % writeDLKcatInput, runDLKcat, readDLKcatOutput, kcatsFromBrenda, saveKcatSource
    +0046 
    +0047 checkOptions(varargin, {'run','ecRxns','save','saveAs','modelAdapter'}, 'kcatsFromDLKcat');
    +0048 p = parseGECKOargs(varargin, { ...
    +0049     'run',          false; ...
    +0050     'ecRxns',       []; ...
    +0051     'save',         true; ...
    +0052     'saveAs',       'dlkcat'; ...
    +0053     'modelAdapter', []});
    +0054 modelAdapter = p.modelAdapter;
    +0055 if isempty(modelAdapter)
    +0056     modelAdapter = ModelAdapterManager.getDefault();
    +0057     if isempty(modelAdapter)
    +0058         error('Either send in a modelAdapter or set the default model adapter in the ModelAdapterManager.')
    +0059     end
    +0060 end
    +0061 if ~p.run && ~isempty(p.ecRxns)
    +0062     error('kcatsFromDLKcat:ecRxns', ['ecRxns selects the reactions DLKcat is run for, so ' ...
    +0063         'it needs ''run'', true.'])
    +0064 end
    +0065 if p.save
    +0066     file = fullfile(modelAdapter.params.path, 'data', 'kcats', [char(p.saveAs) '.tsv']);
    +0067     if p.run
    +0068         warnSubset(p.ecRxns, numel(model.ec.rxns), file);
    +0069     end
    +0070 end
    +0071 
    +0072 runFile = fullfile(modelAdapter.params.path, 'data', 'DLKcat_run.txt');
    +0073 if p.run
    +0074     % As runDLKcat: on macOS, MATLAB started from the launcher may not
    +0075     % have Docker on its path.
    +0076     if ismac
    +0077         setenv('PATH', strcat('/usr/local/bin', ':', getenv("PATH")));
    +0078     end
    +0079     [status, ~] = system('docker --version');
    +0080     if status ~= 0
    +0081         error('kcatsFromDLKcat:noDocker', ['DLKcat runs in a Docker image, but Docker was ' ...
    +0082             'not found. Install it from https://www.docker.com, or call kcatsFromDLKcat ' ...
    +0083             'without ''run'' to read an earlier DLKcat output.'])
    +0084     end
    +0085     writeDLKcatInput(model, 'ecRxns', p.ecRxns, 'modelAdapter', modelAdapter, 'overwrite', true);
    +0086     runDLKcat('modelAdapter', modelAdapter);
    +0087     fid = fopen(runFile, 'w');
    +0088     if ~isempty(p.ecRxns)
    +0089         fprintf(fid, 'ecRxns: %d\n', countRxns(p.ecRxns));
    +0090     end
    +0091     fclose(fid);
    +0092 else
    +0093     outFile = fullfile(modelAdapter.params.path, 'data', 'DLKcat.tsv');
    +0094     if ~isfile(outFile)
    +0095         error('kcatsFromDLKcat:noOutput', ['No DLKcat output at %s. Run ' ...
    +0096             'kcatsFromDLKcat(model, ''run'', true) first.'], outFile)
    +0097     end
    +0098 end
    +0099 kcatList = readDLKcatOutput(model, 'modelAdapter', modelAdapter);
    +0100 
    +0101 if p.save
    +0102     parameters = struct('run', logical(p.run));
    +0103     if isfile(runFile)
    +0104         tok = regexp(fileread(runFile), 'ecRxns:\s*(\d+)', 'tokens', 'once');
    +0105         if ~isempty(tok)
    +0106             parameters.ec_rxns = str2double(tok{1});
    +0107         end
    +0108     end
    +0109     saveKcatSource(model, kcatList, p.saveAs, 'modelAdapter', modelAdapter, ...
    +0110         'generator', 'kcatsFromDLKcat', 'parameters', parameters);
    +0111     fprintf('DLKcat kcats for %d reactions written to %s\n', ...
    +0112         numel(unique(kcatList.rxns(kcatList.kcats > 0))), file);
    +0113 end
    +0114 end
    +0115 
    +0116 function n = countRxns(ecRxns)
    +0117 if islogical(ecRxns)
    +0118     n = sum(ecRxns);
    +0119 else
    +0120     n = numel(unique(ecRxns));
    +0121 end
    +0122 end
    +0123 
    +0124 function warnSubset(ecRxns, nRxns, file)
    +0125 % A subset written under the default name replaces the full file.
    +0126 if ~isempty(ecRxns) && countRxns(ecRxns) < nRxns && isfile(file)
    +0127     printOrange(sprintf(['%s is replaced by kcats for %d reactions only. Give saveAs ' ...
    +0128         'to keep it.\n'], file, countRxns(ecRxns)));
    +0129 end
    +0130 end
    +0131 
    +0132 function checkOptions(args, names, functionName)
    +0133 % Options are name-value pairs with known names, so a misspelled option is
    +0134 % an error instead of being taken as a positional argument.
    +0135 id = [functionName ':arguments'];
    +0136 given = args(1:2:end);
    +0137 if mod(numel(args), 2) ~= 0 || ~all(cellfun(@(x) ischar(x) || (isstring(x) && isscalar(x)), given))
    +0138     error(id, 'Options of %s are name-value pairs. Options: %s.', functionName, strjoin(names, ', '))
    +0139 end
    +0140 unknown = setdiff(cellfun(@char, given, 'UniformOutput', false), names);
    +0141 if ~isempty(unknown)
    +0142     error(id, 'Unknown option of %s: %s. Options: %s.', functionName, strjoin(unknown, ', '), ...
    +0143         strjoin(names, ', '))
    +0144 end
    +0145 end
    +
    Generated by m2html © 2005
    + + \ No newline at end of file diff --git a/doc/src/gather_kcats/kcatsFromECTree.html b/doc/src/gather_kcats/kcatsFromECTree.html new file mode 100644 index 00000000..33a11e70 --- /dev/null +++ b/doc/src/gather_kcats/kcatsFromECTree.html @@ -0,0 +1,234 @@ + + + + Description of kcatsFromECTree + + + + + + + + + +
    Home > src > gather_kcats > kcatsFromECTree.m
    + + + +

    kcatsFromECTree +

    + +

    PURPOSE ^

    +
    kcatsFromECTree Estimate kcats from the EC tree and keep them as a source file.
    + +

    SYNOPSIS ^

    +
    function kcatList = kcatsFromECTree(model, varargin)
    + +

    DESCRIPTION ^

    +
     kcatsFromECTree  Estimate kcats from the EC tree and keep them as a source file.
    +
    + Each reaction gets the median kcat of all wild-type BRENDA measurements
    + of its EC number, from any organism and substrate, shrunk toward the
    + median of the EC's 3-digit and 2-digit classes with weight n / (n + k)
    + for n measurements (see ecTreeEstimate). A reaction with several EC
    + numbers uses the one with most measurements. Reactions without an EC
    + number, or whose EC classes have no measurements, get no value. The
    + result is written to data/kcats/ec_tree.tsv in the project folder (see
    + saveKcatSource).
    +
    + Parameters
    + ----------
    + model : struct
    +     an ecModel in GECKO 3 format (with ecModel.ec structure), with EC
    +     numbers (getECfromDatabase or getECfromGEM).
    +
    + Name-Value Arguments
    + --------------------
    + k : double
    +     shrinkage constant (default 5): the number of measurements at which
    +     an EC's own median and its class count equally.
    + ecRxns : logical
    +     for which model.ec.rxns kcats are estimated (default: all).
    + measurements : struct
    +     BRENDA measurement table (default: loadBrendaMeasurements with the
    +     model adapter).
    + save : logical
    +     write the source file (default true).
    + saveAs : char
    +     name of the source file, without .tsv (default 'ec_tree'). With
    +     ecRxns, the file then only holds those reactions.
    + modelAdapter : ModelAdapter
    +     a loaded model adapter (default: the current default model adapter).
    +
    + Returns
    + -------
    + kcatList : struct
    +     the kcat values, with fields source, rxns, eccodes, kcats and detail
    +     (the number of measurements of the EC, n, and the deepest EC level
    +     with measurements, depth).
    +
    + Examples
    + --------
    +     kcatsFromECTree(ecModel);
    +     kcatList = kcatsFromECTree(ecModel, 'k', 10, 'save', false);
    +
    + See also
    + --------
    + ecTreeEstimate, loadBrendaMeasurements, kcatsFromBrenda, saveKcatSource, assignKcats
    + + +

    CROSS-REFERENCE INFORMATION ^

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

    SUBFUNCTIONS ^

    + + +

    SOURCE CODE ^

    +
    0001 function kcatList = kcatsFromECTree(model, varargin)
    +0002 % kcatsFromECTree  Estimate kcats from the EC tree and keep them as a source file.
    +0003 %
    +0004 % Each reaction gets the median kcat of all wild-type BRENDA measurements
    +0005 % of its EC number, from any organism and substrate, shrunk toward the
    +0006 % median of the EC's 3-digit and 2-digit classes with weight n / (n + k)
    +0007 % for n measurements (see ecTreeEstimate). A reaction with several EC
    +0008 % numbers uses the one with most measurements. Reactions without an EC
    +0009 % number, or whose EC classes have no measurements, get no value. The
    +0010 % result is written to data/kcats/ec_tree.tsv in the project folder (see
    +0011 % saveKcatSource).
    +0012 %
    +0013 % Parameters
    +0014 % ----------
    +0015 % model : struct
    +0016 %     an ecModel in GECKO 3 format (with ecModel.ec structure), with EC
    +0017 %     numbers (getECfromDatabase or getECfromGEM).
    +0018 %
    +0019 % Name-Value Arguments
    +0020 % --------------------
    +0021 % k : double
    +0022 %     shrinkage constant (default 5): the number of measurements at which
    +0023 %     an EC's own median and its class count equally.
    +0024 % ecRxns : logical
    +0025 %     for which model.ec.rxns kcats are estimated (default: all).
    +0026 % measurements : struct
    +0027 %     BRENDA measurement table (default: loadBrendaMeasurements with the
    +0028 %     model adapter).
    +0029 % save : logical
    +0030 %     write the source file (default true).
    +0031 % saveAs : char
    +0032 %     name of the source file, without .tsv (default 'ec_tree'). With
    +0033 %     ecRxns, the file then only holds those reactions.
    +0034 % modelAdapter : ModelAdapter
    +0035 %     a loaded model adapter (default: the current default model adapter).
    +0036 %
    +0037 % Returns
    +0038 % -------
    +0039 % kcatList : struct
    +0040 %     the kcat values, with fields source, rxns, eccodes, kcats and detail
    +0041 %     (the number of measurements of the EC, n, and the deepest EC level
    +0042 %     with measurements, depth).
    +0043 %
    +0044 % Examples
    +0045 % --------
    +0046 %     kcatsFromECTree(ecModel);
    +0047 %     kcatList = kcatsFromECTree(ecModel, 'k', 10, 'save', false);
    +0048 %
    +0049 % See also
    +0050 % --------
    +0051 % ecTreeEstimate, loadBrendaMeasurements, kcatsFromBrenda, saveKcatSource, assignKcats
    +0052 
    +0053 checkOptions(varargin, {'k','ecRxns','measurements','save','saveAs','modelAdapter'}, 'kcatsFromECTree');
    +0054 p = parseGECKOargs(varargin, { ...
    +0055     'k',            5; ...
    +0056     'ecRxns',       []; ...
    +0057     'measurements', []; ...
    +0058     'save',         true; ...
    +0059     'saveAs',       'ec_tree'; ...
    +0060     'modelAdapter', []});
    +0061 modelAdapter = p.modelAdapter;
    +0062 if isempty(modelAdapter)
    +0063     modelAdapter = ModelAdapterManager.getDefault();
    +0064     if isempty(modelAdapter)
    +0065         error('Either send in a modelAdapter or set the default model adapter in the ModelAdapterManager.')
    +0066     end
    +0067 end
    +0068 if ~isfield(model.ec, 'eccodes')
    +0069     error('No EC codes defined in model.ec.eccodes. First run getECfromGEM() and/or getECfromDatabase().')
    +0070 end
    +0071 if p.save
    +0072     file = fullfile(modelAdapter.params.path, 'data', 'kcats', [char(p.saveAs) '.tsv']);
    +0073     warnSubset(p.ecRxns, numel(model.ec.rxns), file);
    +0074 end
    +0075 measurements = p.measurements;
    +0076 if isempty(measurements)
    +0077     measurements = loadBrendaMeasurements('modelAdapter', modelAdapter);
    +0078 end
    +0079 
    +0080 idx = (1:numel(model.ec.rxns))';
    +0081 if ~isempty(p.ecRxns)
    +0082     idx = idx(p.ecRxns(:));
    +0083 end
    +0084 eccodes = model.ec.eccodes(idx);
    +0085 eccodes(cellfun(@(e) ~ischar(e) && ~isstring(e), eccodes)) = {''};
    +0086 [values, n, depth, ecUsed] = ecTreeEstimate(eccodes, measurements, p.k);
    +0087 found = depth > 0;
    +0088 idx = idx(found);
    +0089 kcatList.source  = 'ec_tree';
    +0090 kcatList.rxns    = model.ec.rxns(idx);
    +0091 kcatList.eccodes = ecUsed(found);
    +0092 kcatList.kcats   = 10 .^ values(found);
    +0093 kcatList.detail  = cellstr("n=" + string(n(found)) + "; depth=" + string(depth(found)));
    +0094 
    +0095 if p.save
    +0096     parameters = struct('k', p.k);
    +0097     if ~isempty(p.ecRxns)
    +0098         parameters.ec_rxns = countRxns(p.ecRxns);
    +0099     end
    +0100     saveKcatSource(model, kcatList, p.saveAs, 'modelAdapter', modelAdapter, ...
    +0101         'generator', 'kcatsFromECTree', 'parameters', parameters, ...
    +0102         'data', measurements.release);
    +0103     fprintf('EC-tree kcats for %d reactions written to %s\n', numel(kcatList.rxns), file);
    +0104 end
    +0105 end
    +0106 
    +0107 function n = countRxns(ecRxns)
    +0108 if islogical(ecRxns)
    +0109     n = sum(ecRxns);
    +0110 else
    +0111     n = numel(unique(ecRxns));
    +0112 end
    +0113 end
    +0114 
    +0115 function warnSubset(ecRxns, nRxns, file)
    +0116 % A subset written under the default name replaces the full file.
    +0117 if ~isempty(ecRxns) && countRxns(ecRxns) < nRxns && isfile(file)
    +0118     printOrange(sprintf(['%s is replaced by kcats for %d reactions only. Give saveAs ' ...
    +0119         'to keep it.\n'], file, countRxns(ecRxns)));
    +0120 end
    +0121 end
    +0122 
    +0123 function checkOptions(args, names, functionName)
    +0124 % Options are name-value pairs with known names, so a misspelled option is
    +0125 % an error instead of being taken as a positional argument.
    +0126 id = [functionName ':arguments'];
    +0127 given = args(1:2:end);
    +0128 if mod(numel(args), 2) ~= 0 || ~all(cellfun(@(x) ischar(x) || (isstring(x) && isscalar(x)), given))
    +0129     error(id, 'Options of %s are name-value pairs. Options: %s.', functionName, strjoin(names, ', '))
    +0130 end
    +0131 unknown = setdiff(cellfun(@char, given, 'UniformOutput', false), names);
    +0132 if ~isempty(unknown)
    +0133     error(id, 'Unknown option of %s: %s. Options: %s.', functionName, strjoin(unknown, ', '), ...
    +0134         strjoin(names, ', '))
    +0135 end
    +0136 end
    +
    Generated by m2html © 2005
    + + \ No newline at end of file diff --git a/doc/src/gather_kcats/kcatsFromHomologs.html b/doc/src/gather_kcats/kcatsFromHomologs.html new file mode 100644 index 00000000..2e1bc272 --- /dev/null +++ b/doc/src/gather_kcats/kcatsFromHomologs.html @@ -0,0 +1,403 @@ + + + + Description of kcatsFromHomologs + + + + + + + + + +
    Home > src > gather_kcats > kcatsFromHomologs.m
    + + + +

    kcatsFromHomologs +

    + +

    PURPOSE ^

    +
    kcatsFromHomologs Estimate kcats from measured homologs and keep them as a source file.
    + +

    SYNOPSIS ^

    +
    function kcatList = kcatsFromHomologs(model, varargin)
    + +

    DESCRIPTION ^

    +
     kcatsFromHomologs  Estimate kcats from measured homologs and keep them as a source file.
    +
    + For each reaction, enzyme and substrate (the substrates DLKcat would use,
    + see extractEnzymeSubstratePairs), the enzyme's sequence is searched with
    + DIAMOND against the sequences of the BRENDA measurements (at least 40%
    + identity, 80% coverage of both sequences). Each homolog measured on the
    + same substrate (same InChIKey, without the protonation flag) contributes
    + the median of its measurements; the estimate is the mean of the k most
    + identical such homologs, weighted by identity. Homologs at 95% identity or
    + more are measurements of (nearly) the same protein: when there are any,
    + the estimate is the median of those alone. For an enzyme complex the
    + estimate is the median over its subunits. Model metabolites are matched to
    + InChIKeys through substrates.tsv of the BRENDA files: their ChEBI
    + annotations, then MetaNetX annotations (model.metMiriams), then their
    + names. Reactions without a homolog measured on one of their substrates get
    + no value. The result is written to data/kcats/homologs.tsv (see
    + saveKcatSource). DIAMOND is RAVEN's (getDiamond; downloaded when
    + missing). geckopy has the same (kcats_from_homologs).
    +
    + Parameters
    + ----------
    + model : struct
    +     an ecModel in GECKO 3 format (with ecModel.ec structure), with enzyme
    +     sequences (model.ec.sequence).
    +
    + Name-Value Arguments
    + --------------------
    + k : double
    +     the number of most identical homologs averaged (default 10).
    + minIdentity : double
    +     DIAMOND identity threshold, as a fraction (default 0.4).
    + coverage : double
    +     DIAMOND coverage threshold of both sequences, as a fraction (default 0.8).
    + threads : double
    +     DIAMOND threads (default: DIAMOND's).
    + save : logical
    +     write the source file (default true).
    + saveAs : char
    +     name of the source file, without .tsv (default 'homologs').
    + modelAdapter : ModelAdapter
    +     a loaded model adapter (default: the current default model adapter).
    +
    + Returns
    + -------
    + kcatList : struct
    +     the kcat values, with fields source, rxns, substrates, kcats and
    +     detail (the identity of the nearest homolog, identity, and the number
    +     of homologs used, n).
    +
    + Examples
    + --------
    +     kcatsFromHomologs(ecModel);
    +
    + See also
    + --------
    + kcatsFromECTree, extractEnzymeSubstratePairs, saveKcatSource, collectKcats
    + + +

    CROSS-REFERENCE INFORMATION ^

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

    SUBFUNCTIONS ^

    + + +

    SOURCE CODE ^

    +
    0001 function kcatList = kcatsFromHomologs(model, varargin)
    +0002 % kcatsFromHomologs  Estimate kcats from measured homologs and keep them as a source file.
    +0003 %
    +0004 % For each reaction, enzyme and substrate (the substrates DLKcat would use,
    +0005 % see extractEnzymeSubstratePairs), the enzyme's sequence is searched with
    +0006 % DIAMOND against the sequences of the BRENDA measurements (at least 40%
    +0007 % identity, 80% coverage of both sequences). Each homolog measured on the
    +0008 % same substrate (same InChIKey, without the protonation flag) contributes
    +0009 % the median of its measurements; the estimate is the mean of the k most
    +0010 % identical such homologs, weighted by identity. Homologs at 95% identity or
    +0011 % more are measurements of (nearly) the same protein: when there are any,
    +0012 % the estimate is the median of those alone. For an enzyme complex the
    +0013 % estimate is the median over its subunits. Model metabolites are matched to
    +0014 % InChIKeys through substrates.tsv of the BRENDA files: their ChEBI
    +0015 % annotations, then MetaNetX annotations (model.metMiriams), then their
    +0016 % names. Reactions without a homolog measured on one of their substrates get
    +0017 % no value. The result is written to data/kcats/homologs.tsv (see
    +0018 % saveKcatSource). DIAMOND is RAVEN's (getDiamond; downloaded when
    +0019 % missing). geckopy has the same (kcats_from_homologs).
    +0020 %
    +0021 % Parameters
    +0022 % ----------
    +0023 % model : struct
    +0024 %     an ecModel in GECKO 3 format (with ecModel.ec structure), with enzyme
    +0025 %     sequences (model.ec.sequence).
    +0026 %
    +0027 % Name-Value Arguments
    +0028 % --------------------
    +0029 % k : double
    +0030 %     the number of most identical homologs averaged (default 10).
    +0031 % minIdentity : double
    +0032 %     DIAMOND identity threshold, as a fraction (default 0.4).
    +0033 % coverage : double
    +0034 %     DIAMOND coverage threshold of both sequences, as a fraction (default 0.8).
    +0035 % threads : double
    +0036 %     DIAMOND threads (default: DIAMOND's).
    +0037 % save : logical
    +0038 %     write the source file (default true).
    +0039 % saveAs : char
    +0040 %     name of the source file, without .tsv (default 'homologs').
    +0041 % modelAdapter : ModelAdapter
    +0042 %     a loaded model adapter (default: the current default model adapter).
    +0043 %
    +0044 % Returns
    +0045 % -------
    +0046 % kcatList : struct
    +0047 %     the kcat values, with fields source, rxns, substrates, kcats and
    +0048 %     detail (the identity of the nearest homolog, identity, and the number
    +0049 %     of homologs used, n).
    +0050 %
    +0051 % Examples
    +0052 % --------
    +0053 %     kcatsFromHomologs(ecModel);
    +0054 %
    +0055 % See also
    +0056 % --------
    +0057 % kcatsFromECTree, extractEnzymeSubstratePairs, saveKcatSource, collectKcats
    +0058 
    +0059 checkOptions(varargin, {'k','minIdentity','coverage','threads','save','saveAs','modelAdapter'}, 'kcatsFromHomologs');
    +0060 p = parseGECKOargs(varargin, { ...
    +0061     'k',            10; ...
    +0062     'minIdentity',  0.4; ...
    +0063     'coverage',     0.8; ...
    +0064     'threads',      []; ...
    +0065     'save',         true; ...
    +0066     'saveAs',       'homologs'; ...
    +0067     'modelAdapter', []});
    +0068 modelAdapter = p.modelAdapter;
    +0069 if isempty(modelAdapter)
    +0070     modelAdapter = ModelAdapterManager.getDefault();
    +0071     if isempty(modelAdapter)
    +0072         error('Either send in a modelAdapter or set the default model adapter in the ModelAdapterManager.')
    +0073     end
    +0074 end
    +0075 
    +0076 measurements = loadBrendaMeasurements('folder', fileparts(brendaFile(modelAdapter, 'measurements.tsv')));
    +0077 substrates = readSubstrates(brendaFile(modelAdapter, 'substrates.tsv'));
    +0078 sequencesFile = brendaFile(modelAdapter, 'sequences.fasta');
    +0079 
    +0080 pairs = extractEnzymeSubstratePairs(model, 'modelAdapter', modelAdapter);
    +0081 iks = metaboliteInchikeys(model, substrates);
    +0082 pairIk = iks(pairs.met);
    +0083 seqs = model.ec.sequence(pairs.protein);
    +0084 keep = ~cellfun(@isempty, pairIk) & ~cellfun(@isempty, seqs);
    +0085 rxnIdx = pairs.ecRxn(keep); metIdx = pairs.met(keep); pairIk = pairIk(keep); seqs = seqs(keep);
    +0086 
    +0087 kcatList.source = 'homologs';
    +0088 kcatList.rxns = cell(0, 1);
    +0089 kcatList.substrates = cell(0, 1);
    +0090 kcatList.kcats = zeros(0, 1);
    +0091 kcatList.detail = cell(0, 1);
    +0092 if ~isempty(seqs)
    +0093     [useqs, ~, seqNo] = unique(seqs, 'stable');
    +0094     queryIds = cellstr(compose('q%d', (0:numel(useqs)-1)'));
    +0095     hits = diamondHits(queryIds, useqs, sequencesFile, p.minIdentity, p.coverage, p.threads);
    +0096     % Median log10 kcat per measured sequence and substrate.
    +0097     hasSeq = ~cellfun(@isempty, measurements.seq_id) & ~cellfun(@isempty, measurements.substrate_inchikey);
    +0098     key = strcat(measurements.seq_id(hasSeq), '|', cellfun(@(s) s(1:min(25, end)), ...
    +0099         measurements.substrate_inchikey(hasSeq), 'UniformOutput', false));
    +0100     [ukey, ~, g] = unique(key);
    +0101     med = containers.Map(ukey, num2cell(accumarray(g, measurements.log10kcat(hasSeq), [], @median)));
    +0102     % Estimate per enzyme sequence and substrate.
    +0103     [up, ~, pairNo] = unique(strcat(queryIds(seqNo), '|', pairIk), 'stable');
    +0104     est = nan(numel(up), 1); best = nan(numel(up), 1); nHom = zeros(numel(up), 1);
    +0105     for u = 1:numel(up)
    +0106         parts = strsplit(up{u}, '|');
    +0107         rows = find(strcmp(hits.query, parts{1}));
    +0108         found = zeros(0, 2);
    +0109         for r = rows(:)'
    +0110             mk = [hits.target{r} '|' parts{2}];
    +0111             if isKey(med, mk)
    +0112                 found(end+1, :) = [hits.identity(r), med(mk)]; %#ok<AGROW>
    +0113             end
    +0114         end
    +0115         if isempty(found)
    +0116             continue
    +0117         end
    +0118         exact = found(found(:, 1) >= 0.95, 2);
    +0119         best(u) = found(1, 1);
    +0120         if ~isempty(exact)
    +0121             est(u) = median(exact);
    +0122             nHom(u) = numel(exact);
    +0123         else
    +0124             found = found(1:min(p.k, end), :);
    +0125             est(u) = sum(found(:, 1) .* found(:, 2)) / sum(found(:, 1));
    +0126             nHom(u) = size(found, 1);
    +0127         end
    +0128     end
    +0129     % One row per reaction and substrate: the median over its enzymes.
    +0130     [ur, ~, rs] = unique(strcat(model.ec.rxns(rxnIdx), '|', model.metNames(metIdx)), 'stable');
    +0131     for r = 1:numel(ur)
    +0132         members = unique(pairNo(rs == r));
    +0133         members = members(~isnan(est(members)));
    +0134         if isempty(members)
    +0135             continue
    +0136         end
    +0137         [~, b] = max(best(members));
    +0138         first = find(rs == r, 1);
    +0139         kcatList.rxns{end+1, 1} = model.ec.rxns{rxnIdx(first)};
    +0140         kcatList.substrates{end+1, 1} = model.metNames{metIdx(first)};
    +0141         kcatList.kcats(end+1, 1) = 10 ^ median(est(members));
    +0142         kcatList.detail{end+1, 1} = sprintf('identity=%.3f; n=%d', best(members(b)), nHom(members(b)));
    +0143     end
    +0144 end
    +0145 
    +0146 if p.save
    +0147     parameters = struct('coverage', p.coverage, 'k', p.k, 'min_identity', p.minIdentity);
    +0148     file = saveKcatSource(model, kcatList, p.saveAs, 'modelAdapter', modelAdapter, ...
    +0149         'generator', 'kcatsFromHomologs', 'parameters', parameters, 'data', measurements.release);
    +0150     fprintf('Homolog kcats for %d reactions written to %s\n', numel(unique(kcatList.rxns)), file);
    +0151 end
    +0152 end
    +0153 
    +0154 function file = brendaFile(modelAdapter, name)
    +0155 % A file of the adapter's BRENDA folder, or of GECKO's BRENDA release.
    +0156 file = fullfile(modelAdapter.getBrendaDBFolder(), name);
    +0157 if ~isfile(file)
    +0158     file = fullfile(fetchBrendaAsset({name}), name);
    +0159 end
    +0160 end
    +0161 
    +0162 function s = readSubstrates(file)
    +0163 fid = fopen(file, 'r', 'n', 'UTF-8');
    +0164 c = textscan(fid, '%s %s %s', 'Delimiter', '\t', 'CommentStyle', '#', 'HeaderLines', 0);
    +0165 fclose(fid);
    +0166 header = strcmp(c{1}, 'inchikey');
    +0167 s.inchikey = c{1}(~header); s.kind = c{2}(~header); s.value = c{3}(~header);
    +0168 end
    +0169 
    +0170 function iks = metaboliteInchikeys(model, substrates)
    +0171 % InChIKey (first 25 characters) per model metabolite, '' when unknown:
    +0172 % from its ChEBI annotations, then its MetaNetX annotations, then its name.
    +0173 maps = struct();
    +0174 for kind = {'chebi', 'metanetx', 'name'}
    +0175     k = strcmp(substrates.kind, kind{1});
    +0176     [values, first] = unique(substrates.value(k), 'stable');
    +0177     ik = substrates.inchikey(k);
    +0178     maps.(kind{1}) = containers.Map('KeyType', 'char', 'ValueType', 'char');
    +0179     if ~isempty(values)
    +0180         maps.(kind{1}) = containers.Map(values, ik(first));
    +0181     end
    +0182 end
    +0183 iks = repmat({''}, numel(model.mets), 1);
    +0184 for i = 1:numel(model.mets)
    +0185     for pair = {{'chebi', 'chebi'}, {'metanetx', 'metanetx.chemical'}}
    +0186         kind = pair{1}{1};
    +0187         for v = annotations(model, i, pair{1}{2})
    +0188             if isKey(maps.(kind), v{1})
    +0189                 iks{i} = maps.(kind)(v{1});
    +0190                 break
    +0191             end
    +0192         end
    +0193         if ~isempty(iks{i})
    +0194             break
    +0195         end
    +0196     end
    +0197     if isempty(iks{i}) && isKey(maps.name, compactName(model.metNames{i}))
    +0198         iks{i} = maps.name(compactName(model.metNames{i}));
    +0199     end
    +0200 end
    +0201 end
    +0202 
    +0203 function values = annotations(model, i, key)
    +0204 % The identifiers of one annotation of a metabolite, without their prefix.
    +0205 values = {};
    +0206 if ~isfield(model, 'metMiriams') || numel(model.metMiriams) < i || ~isstruct(model.metMiriams{i})
    +0207     return
    +0208 end
    +0209 m = model.metMiriams{i};
    +0210 hit = strcmpi(m.name, key);
    +0211 values = regexprep(strtrim(m.value(hit)), '^.*:', '');
    +0212 values = values(:)';
    +0213 end
    +0214 
    +0215 function s = compactName(name)
    +0216 % A name as the compact keys of substrates.tsv: without markup, Greek letters
    +0217 % spelled out, accents dropped, lower case, only letters, digits and +.
    +0218 s = regexprep(char(name), '<[^>]+>', '');
    +0219 s = strrep(strrep(strrep(strrep(strrep(s, '&amp;', '&'), '&lt;', '<'), '&gt;', '>'), '&quot;', '"'), '&#39;', '''');
    +0220 greek = {char(945), 'alpha'; char(946), 'beta'; char(947), 'gamma'; char(948), 'delta'; char(949), 'epsilon'; ...
    +0221     char(969), 'omega'; char(954), 'kappa'; char(955), 'lambda'; char(956), 'mu'; char(968), 'psi'; ...
    +0222     char(958), 'xi'; char(950), 'zeta'};
    +0223 for g = 1:size(greek, 1)
    +0224     s = strrep(strrep(s, greek{g, 1}, greek{g, 2}), upper(greek{g, 1}), greek{g, 2});
    +0225 end
    +0226 s = char(javaMethod('normalize', 'java.text.Normalizer', java.lang.String(s), ...
    +0227     javaMethod('valueOf', 'java.text.Normalizer$Form', 'NFKD')));
    +0228 s = s(double(s) < 128);
    +0229 s = regexprep(lower(s), '[^a-z0-9+]', '');
    +0230 end
    +0231 
    +0232 function hits = diamondHits(ids, sequences, targetFasta, minIdentity, coverage, threads)
    +0233 % DIAMOND hits of the query sequences against a FASTA file: query, target,
    +0234 % identity (a fraction), best identity first per query, then by target.
    +0235 ravenPath = findRAVENroot();
    +0236 if ismac
    +0237     binEnd = '.mac';
    +0238 elseif ispc
    +0239     binEnd = '.exe';
    +0240 else
    +0241     binEnd = '';
    +0242 end
    +0243 exe = fullfile(ravenPath, 'src', 'external', 'diamond', ['diamond' binEnd]);
    +0244 if ~isfile(exe)
    +0245     downloadRavenBinaries({'diamond'});
    +0246 end
    +0247 tmp = tempname; mkdir(tmp);
    +0248 cleanup = onCleanup(@() rmdir(tmp, 's'));
    +0249 fid = fopen(fullfile(tmp, 'queries.fasta'), 'w');
    +0250 entries = [cellstr(ids(:))'; cellstr(sequences(:))'];
    +0251 fprintf(fid, '>%s\n%s\n', entries{:});
    +0252 fclose(fid);
    +0253 run = @(args) system(['"' exe '" ' args]);
    +0254 [status, out] = run(sprintf('makedb --in "%s" --db "%s" --quiet', targetFasta, fullfile(tmp, 'targets')));
    +0255 if status ~= 0
    +0256     error('kcatsFromHomologs:diamond', 'DIAMOND makedb failed: %s', out)
    +0257 end
    +0258 args = sprintf(['blastp --query "%s" --db "%s" --out "%s" --ultra-sensitive --id %g --query-cover %g ' ...
    +0259     '--subject-cover %g --evalue 0.001 --max-target-seqs 0 --outfmt 6 qseqid sseqid pident --quiet'], ...
    +0260     fullfile(tmp, 'queries.fasta'), fullfile(tmp, 'targets'), fullfile(tmp, 'hits.tsv'), ...
    +0261     100 * minIdentity, 100 * coverage, 100 * coverage);
    +0262 if ~isempty(threads)
    +0263     args = sprintf('%s --threads %d', args, threads);
    +0264 end
    +0265 [status, out] = run(args);
    +0266 if status ~= 0
    +0267     error('kcatsFromHomologs:diamond', 'DIAMOND blastp failed: %s', out)
    +0268 end
    +0269 fid = fopen(fullfile(tmp, 'hits.tsv'), 'r');
    +0270 c = textscan(fid, '%s %s %f', 'Delimiter', '\t');
    +0271 fclose(fid);
    +0272 q = c{1}; t = c{2}; ident = c{3} / 100;
    +0273 % Best identity per query and target.
    +0274 [pairKeys, ~, g] = unique(strcat(q, '|', t));
    +0275 ident = accumarray(g, ident, [], @max);
    +0276 parts = split(pairKeys, '|');
    +0277 if isempty(pairKeys)
    +0278     parts = cell(0, 2);
    +0279 end
    +0280 parts = reshape(parts, [], 2);
    +0281 T = table(parts(:, 1), parts(:, 2), ident, 'VariableNames', {'query', 'target', 'identity'});
    +0282 T = sortrows(T, {'query', 'identity', 'target'}, {'ascend', 'descend', 'ascend'});
    +0283 hits = struct('query', {T.query}, 'target', {T.target}, 'identity', T.identity);
    +0284 end
    +0285 
    +0286 function checkOptions(args, names, functionName)
    +0287 % Options are name-value pairs with known names, so a misspelled option is
    +0288 % an error instead of being taken as a positional argument.
    +0289 id = [functionName ':arguments'];
    +0290 given = args(1:2:end);
    +0291 if mod(numel(args), 2) ~= 0 || ~all(cellfun(@(x) ischar(x) || (isstring(x) && isscalar(x)), given))
    +0292     error(id, 'Options of %s are name-value pairs. Options: %s.', functionName, strjoin(names, ', '))
    +0293 end
    +0294 unknown = setdiff(cellfun(@char, given, 'UniformOutput', false), names);
    +0295 if ~isempty(unknown)
    +0296     error(id, 'Unknown option of %s: %s. Options: %s.', functionName, strjoin(unknown, ', '), ...
    +0297         strjoin(names, ', '))
    +0298 end
    +0299 end
    +
    Generated by m2html © 2005
    + + \ No newline at end of file diff --git a/doc/src/gather_kcats/kcatsFromOKP.html b/doc/src/gather_kcats/kcatsFromOKP.html new file mode 100644 index 00000000..de090b9d --- /dev/null +++ b/doc/src/gather_kcats/kcatsFromOKP.html @@ -0,0 +1,369 @@ + + + + Description of kcatsFromOKP + + + + + + + + + +
    Home > src > gather_kcats > kcatsFromOKP.m
    + + + +

    kcatsFromOKP +

    + +

    PURPOSE ^

    +
    kcatsFromOKP Gather kcats from OpenKineticsPredictor and keep them as a source file.
    + +

    SYNOPSIS ^

    +
    function [kcatList, done] = kcatsFromOKP(model, varargin)
    + +

    DESCRIPTION ^

    +
     kcatsFromOKP  Gather kcats from OpenKineticsPredictor and keep them as a source file.
    +
    + Predicts kcats with one OpenKineticsPredictor (OKP) method and writes
    + them to data/kcats/okp_<method>.tsv in the project folder (see
    + saveKcatSource). OKP is a web service with a job queue, so this function
    + can be called repeatedly:
    +
    + - without a job for this method, it submits one
    +   (submitOpenKineticsPredictor);
    + - with a job, it fetches the result (fetchOpenKineticsPredictor). When
    +   the job is done the file is written; otherwise it reports the job's
    +   status and writes nothing.
    +
    + Each method keeps its own job in data/OKP_job_<method>.txt and its own
    + result in data/OKP_output_<method>.csv, so jobs of several methods can
    + run at the same time. The job file records which job the stored result
    + came from; useStored only uses a result of the current job. An API key
    + is needed (see resolveOkpApiKey).
    +
    + Parameters
    + ----------
    + model : struct
    +     an ecModel in GECKO 3 format (with ecModel.ec structure), with
    +     metabolite SMILES (findMetSmiles) and protein sequences.
    +
    + Name-Value Arguments
    + --------------------
    + method : char
    +     OKP method, e.g. 'CataPro', 'CatPred', 'CatRange', 'DLKcat',
    +     'EITLEM', 'KinForm-H', 'KinForm-L', 'OmniESI', 'TurNup', 'UniKP'
    +     (default: params.okp.method of the model adapter, or 'CataPro').
    + wait : logical
    +     wait until the job is done (default false).
    + resubmit : logical
    +     submit a new job even if one exists for this method; its earlier
    +     result is removed (default false).
    + useStored : logical
    +     read the stored result of this method's job, without contacting OKP
    +     (default false).
    + ecRxns : logical
    +     for which model.ec.rxns kcats are predicted (default: all). Only
    +     used when a job is submitted.
    + save : logical
    +     write the source file (default true).
    + saveAs : char
    +     name of the source file, without .tsv (default 'okp_<method>', in
    +     lower case, with other characters than letters and digits as '_').
    + modelAdapter : ModelAdapter
    +     a loaded model adapter (default: the current default model adapter).
    +
    + Returns
    + -------
    + kcatList : struct
    +     the kcat values, as returned by readOpenKineticsPredictorOutput;
    +     empty while the job is not done.
    + done : logical
    +     whether the result was available.
    +
    + Examples
    + --------
    +     kcatsFromOKP(ecModel, 'method', 'CataPro');          % submits
    +     kcatsFromOKP(ecModel, 'method', 'CataPro');          % later: fetches and writes
    +     kcatsFromOKP(ecModel, 'method', 'UniKP', 'wait', true);
    +
    + See also
    + --------
    + submitOpenKineticsPredictor, fetchOpenKineticsPredictor, kcatsFromBrenda, saveKcatSource
    + + +

    CROSS-REFERENCE INFORMATION ^

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

    SUBFUNCTIONS ^

    + + +

    SOURCE CODE ^

    +
    0001 function [kcatList, done] = kcatsFromOKP(model, varargin)
    +0002 % kcatsFromOKP  Gather kcats from OpenKineticsPredictor and keep them as a source file.
    +0003 %
    +0004 % Predicts kcats with one OpenKineticsPredictor (OKP) method and writes
    +0005 % them to data/kcats/okp_<method>.tsv in the project folder (see
    +0006 % saveKcatSource). OKP is a web service with a job queue, so this function
    +0007 % can be called repeatedly:
    +0008 %
    +0009 % - without a job for this method, it submits one
    +0010 %   (submitOpenKineticsPredictor);
    +0011 % - with a job, it fetches the result (fetchOpenKineticsPredictor). When
    +0012 %   the job is done the file is written; otherwise it reports the job's
    +0013 %   status and writes nothing.
    +0014 %
    +0015 % Each method keeps its own job in data/OKP_job_<method>.txt and its own
    +0016 % result in data/OKP_output_<method>.csv, so jobs of several methods can
    +0017 % run at the same time. The job file records which job the stored result
    +0018 % came from; useStored only uses a result of the current job. An API key
    +0019 % is needed (see resolveOkpApiKey).
    +0020 %
    +0021 % Parameters
    +0022 % ----------
    +0023 % model : struct
    +0024 %     an ecModel in GECKO 3 format (with ecModel.ec structure), with
    +0025 %     metabolite SMILES (findMetSmiles) and protein sequences.
    +0026 %
    +0027 % Name-Value Arguments
    +0028 % --------------------
    +0029 % method : char
    +0030 %     OKP method, e.g. 'CataPro', 'CatPred', 'CatRange', 'DLKcat',
    +0031 %     'EITLEM', 'KinForm-H', 'KinForm-L', 'OmniESI', 'TurNup', 'UniKP'
    +0032 %     (default: params.okp.method of the model adapter, or 'CataPro').
    +0033 % wait : logical
    +0034 %     wait until the job is done (default false).
    +0035 % resubmit : logical
    +0036 %     submit a new job even if one exists for this method; its earlier
    +0037 %     result is removed (default false).
    +0038 % useStored : logical
    +0039 %     read the stored result of this method's job, without contacting OKP
    +0040 %     (default false).
    +0041 % ecRxns : logical
    +0042 %     for which model.ec.rxns kcats are predicted (default: all). Only
    +0043 %     used when a job is submitted.
    +0044 % save : logical
    +0045 %     write the source file (default true).
    +0046 % saveAs : char
    +0047 %     name of the source file, without .tsv (default 'okp_<method>', in
    +0048 %     lower case, with other characters than letters and digits as '_').
    +0049 % modelAdapter : ModelAdapter
    +0050 %     a loaded model adapter (default: the current default model adapter).
    +0051 %
    +0052 % Returns
    +0053 % -------
    +0054 % kcatList : struct
    +0055 %     the kcat values, as returned by readOpenKineticsPredictorOutput;
    +0056 %     empty while the job is not done.
    +0057 % done : logical
    +0058 %     whether the result was available.
    +0059 %
    +0060 % Examples
    +0061 % --------
    +0062 %     kcatsFromOKP(ecModel, 'method', 'CataPro');          % submits
    +0063 %     kcatsFromOKP(ecModel, 'method', 'CataPro');          % later: fetches and writes
    +0064 %     kcatsFromOKP(ecModel, 'method', 'UniKP', 'wait', true);
    +0065 %
    +0066 % See also
    +0067 % --------
    +0068 % submitOpenKineticsPredictor, fetchOpenKineticsPredictor, kcatsFromBrenda, saveKcatSource
    +0069 
    +0070 checkOptions(varargin, {'method','wait','resubmit','useStored','ecRxns','save','saveAs','modelAdapter'}, 'kcatsFromOKP');
    +0071 p = parseGECKOargs(varargin, { ...
    +0072     'method',       []; ...
    +0073     'wait',         false; ...
    +0074     'resubmit',     false; ...
    +0075     'useStored',    false; ...
    +0076     'ecRxns',       []; ...
    +0077     'save',         true; ...
    +0078     'saveAs',       []; ...
    +0079     'modelAdapter', []});
    +0080 modelAdapter = p.modelAdapter;
    +0081 if isempty(modelAdapter)
    +0082     modelAdapter = ModelAdapterManager.getDefault();
    +0083     if isempty(modelAdapter)
    +0084         error('Either send in a modelAdapter or set the default model adapter in the ModelAdapterManager.')
    +0085     end
    +0086 end
    +0087 params = modelAdapter.params;
    +0088 method = char(p.method);
    +0089 if isempty(method)
    +0090     if isfield(params, 'okp') && isfield(params.okp, 'method') && ~isempty(params.okp.method)
    +0091         method = char(params.okp.method);
    +0092     else
    +0093         method = 'CataPro';
    +0094     end
    +0095 end
    +0096 if any(strcmp(method, {'CatPred', 'TurNup'}))
    +0097     error('kcatsFromOKP:method', ['%s reads whole reactions (its substrate set, and products ' ...
    +0098         'for TurNup); kcatsFromOKP submits enzyme-substrate pairs only.'], method)
    +0099 end
    +0100 tag = lower(regexprep(method, '[^A-Za-z0-9]+', '_'));
    +0101 dataDir = fullfile(params.path, 'data');
    +0102 jobFile = fullfile(dataDir, ['OKP_job_' tag '.txt']);
    +0103 outFile = fullfile(dataDir, ['OKP_output_' tag '.csv']);
    +0104 name = char(p.saveAs);
    +0105 if isempty(name)
    +0106     name = ['okp_' tag];
    +0107 end
    +0108 job = readJobFile(jobFile);
    +0109 submitting = ~p.useStored && (p.resubmit || ~isfield(job, 'jobId'));
    +0110 if ~isempty(p.ecRxns) && ~submitting
    +0111     error('kcatsFromOKP:ecRxns', ['ecRxns selects the reactions of a new job, but this call ' ...
    +0112         'submits none (a job for %s exists; use ''resubmit'', true for a new one).'], method)
    +0113 end
    +0114 if p.save
    +0115     file = fullfile(modelAdapter.params.path, 'data', 'kcats', [char(name) '.tsv']);
    +0116     if submitting
    +0117         warnSubset(p.ecRxns, numel(model.ec.rxns), file);
    +0118     end
    +0119 end
    +0120 
    +0121 if p.useStored
    +0122     if ~isfield(job, 'jobId')
    +0123         adoptSharedResult(model, modelAdapter, dataDir, method, jobFile, outFile);
    +0124         job = readJobFile(jobFile);
    +0125     end
    +0126     if ~isfile(outFile) || ~isfield(job, 'resultOf') || ~strcmp(job.resultOf, job.jobId)
    +0127         error('kcatsFromOKP:noStored', ['No stored result of the current %s job (%s). Call ' ...
    +0128             'kcatsFromOKP without ''useStored'' to fetch it.'], method, jobFile)
    +0129     end
    +0130     kcatList = readOpenKineticsPredictorOutput(model, 'outFile', outFile, 'modelAdapter', modelAdapter);
    +0131     done = true;
    +0132 else
    +0133     if submitting
    +0134         if isfile(outFile)
    +0135             delete(outFile);
    +0136         end
    +0137         jobId = submitOpenKineticsPredictor(model, 'method', method, 'ecRxns', p.ecRxns, ...
    +0138             'overwrite', true, 'modelAdapter', modelAdapter);
    +0139         job = struct('jobId', jobId, 'method', method, 'submittedAt', ...
    +0140             char(datetime('now', 'TimeZone', 'UTC', 'Format', 'yyyy-MM-dd''T''HH:mm:ss''Z''')));
    +0141         if ~isempty(p.ecRxns)
    +0142             job.ecRxns = sprintf('%d', countRxns(p.ecRxns));
    +0143         end
    +0144         writeJobFile(jobFile, job);
    +0145     end
    +0146     [done, kcatList] = fetchOpenKineticsPredictor(model, 'jobId', job.jobId, 'wait', p.wait, ...
    +0147         'outFile', outFile, 'modelAdapter', modelAdapter);
    +0148     if done
    +0149         job.resultOf = job.jobId;
    +0150         writeJobFile(jobFile, job);
    +0151     end
    +0152 end
    +0153 
    +0154 if ~done
    +0155     fprintf('Call kcatsFromOKP(model, ''method'', ''%s'') again later to collect the result.\n', method);
    +0156     return
    +0157 end
    +0158 if p.save
    +0159     parameters = struct('method', method);
    +0160     if isfield(job, 'ecRxns')
    +0161         parameters.ec_rxns = str2double(job.ecRxns);
    +0162     end
    +0163     if isfield(kcatList, 'similarity')
    +0164         kcatList.detail = repmat({''}, numel(kcatList.rxns), 1);
    +0165         has = ~isnan(kcatList.similarity);
    +0166         kcatList.detail(has) = cellstr("similarity=" + string(kcatList.similarity(has)));
    +0167     end
    +0168     saveKcatSource(model, kcatList, name, 'modelAdapter', modelAdapter, ...
    +0169         'generator', 'kcatsFromOKP', 'parameters', parameters, 'data', ['OKP job ' job.jobId]);
    +0170     fprintf('OKP (%s) kcats for %d reactions written to %s\n', method, ...
    +0171         numel(unique(kcatList.rxns(kcatList.kcats > 0))), file);
    +0172 end
    +0173 end
    +0174 
    +0175 function adoptSharedResult(model, modelAdapter, dataDir, method, jobFile, outFile)
    +0176 % A result that fetchOpenKineticsPredictor stored by itself, in
    +0177 % data/OKP_output.csv with data/OKP_job.txt, is taken over for this method
    +0178 % only when its job is for this method and its predictions are labelled
    +0179 % with this method.
    +0180 shared = fullfile(dataDir, 'OKP_output.csv');
    +0181 sharedJob = readJobFile(fullfile(dataDir, 'OKP_job.txt'));
    +0182 ok = isfile(shared) && isfield(sharedJob, 'jobId') && isfield(sharedJob, 'method') && ...
    +0183     strcmpi(sharedJob.method, method);
    +0184 if ok
    +0185     list = readOpenKineticsPredictorOutput(model, 'outFile', shared, 'modelAdapter', modelAdapter);
    +0186     predicted = list.kcatSource(startsWith(list.kcatSource, 'OKP-') & ...
    +0187         ~ismember(lower(list.kcatSource), {'okp-brenda','okp-sabio-rk','okp-uniprot'}));
    +0188     ok = ~isempty(predicted) && all(strcmpi(predicted, ['OKP-' method]));
    +0189 end
    +0190 if ~ok
    +0191     error('kcatsFromOKP:noStored', ['No stored OKP result for %s (%s). Call kcatsFromOKP ' ...
    +0192         'without ''useStored'' to submit or fetch a job.'], method, outFile)
    +0193 end
    +0194 copyfile(shared, outFile);
    +0195 sharedJob.method = method;
    +0196 sharedJob.resultOf = sharedJob.jobId;
    +0197 writeJobFile(jobFile, sharedJob);
    +0198 end
    +0199 
    +0200 function job = readJobFile(file)
    +0201 % Fields of an OKP job file ('key: value' per line), as a struct.
    +0202 job = struct();
    +0203 if ~isfile(file)
    +0204     return
    +0205 end
    +0206 lines = strsplit(fileread(file), newline);
    +0207 for i = 1:numel(lines)
    +0208     tok = regexp(lines{i}, '^([A-Za-z]\w*):\s*(.*?)\s*$', 'tokens', 'once');
    +0209     if ~isempty(tok)
    +0210         job.(tok{1}) = tok{2};
    +0211     end
    +0212 end
    +0213 end
    +0214 
    +0215 function writeJobFile(file, job)
    +0216 fid = fopen(file, 'w');
    +0217 for f = {'jobId','method','submittedAt','ecRxns','resultOf'}
    +0218     if isfield(job, f{1})
    +0219         fprintf(fid, '%s: %s\n', f{1}, job.(f{1}));
    +0220     end
    +0221 end
    +0222 fclose(fid);
    +0223 end
    +0224 
    +0225 function n = countRxns(ecRxns)
    +0226 if islogical(ecRxns)
    +0227     n = sum(ecRxns);
    +0228 else
    +0229     n = numel(unique(ecRxns));
    +0230 end
    +0231 end
    +0232 
    +0233 function warnSubset(ecRxns, nRxns, file)
    +0234 % A subset written under the default name replaces the full file.
    +0235 if ~isempty(ecRxns) && countRxns(ecRxns) < nRxns && isfile(file)
    +0236     printOrange(sprintf(['%s is replaced by kcats for %d reactions only. Give saveAs ' ...
    +0237         'to keep it.\n'], file, countRxns(ecRxns)));
    +0238 end
    +0239 end
    +0240 
    +0241 function checkOptions(args, names, functionName)
    +0242 % Options are name-value pairs with known names, so a misspelled option is
    +0243 % an error instead of being taken as a positional argument.
    +0244 id = [functionName ':arguments'];
    +0245 given = args(1:2:end);
    +0246 if mod(numel(args), 2) ~= 0 || ~all(cellfun(@(x) ischar(x) || (isstring(x) && isscalar(x)), given))
    +0247     error(id, 'Options of %s are name-value pairs. Options: %s.', functionName, strjoin(names, ', '))
    +0248 end
    +0249 unknown = setdiff(cellfun(@char, given, 'UniformOutput', false), names);
    +0250 if ~isempty(unknown)
    +0251     error(id, 'Unknown option of %s: %s. Options: %s.', functionName, strjoin(unknown, ', '), ...
    +0252         strjoin(names, ', '))
    +0253 end
    +0254 end
    +
    Generated by m2html © 2005
    + + \ No newline at end of file diff --git a/doc/src/gather_kcats/loadBrendaMeasurements.html b/doc/src/gather_kcats/loadBrendaMeasurements.html new file mode 100644 index 00000000..d3b2f56f --- /dev/null +++ b/doc/src/gather_kcats/loadBrendaMeasurements.html @@ -0,0 +1,169 @@ + + + + Description of loadBrendaMeasurements + + + + + + + + + +
    Home > src > gather_kcats > loadBrendaMeasurements.m
    + + + +

    loadBrendaMeasurements +

    + +

    PURPOSE ^

    +
    loadBrendaMeasurements Load the BRENDA measurement table.
    + +

    SYNOPSIS ^

    +
    function measurements = loadBrendaMeasurements(varargin)
    + +

    DESCRIPTION ^

    +
     loadBrendaMeasurements  Load the BRENDA measurement table.
    +
    + Reads measurements.tsv from the BRENDA database folder of the model
    + adapter (next to kcat.tsv, sa.tsv and mw.tsv): one row per wild-type
    + BRENDA kcat with an EC number, after the outlier screen, with the
    + substrate, organism, UniProt accession and sequence id of each
    + measurement. geckopy reads the same file (load_brenda_measurements).
    +
    + Name-Value Arguments
    + --------------------
    + modelAdapter : ModelAdapter
    +     a loaded model adapter (default: the current default model adapter).
    + folder : char
    +     folder with measurements.tsv, instead of the adapter's BRENDA folder.
    +
    + Returns
    + -------
    + measurements : struct
    +     one field per column of the file (ec, substrate, substrate_inchikey,
    +     organism, taxid, uniprot, seq_id, temperature, ph and pmid as cell
    +     arrays of char; kcat as double), plus log10kcat and release (the
    +     release line of the file, e.g. 'BRENDA release 2026.1').
    +
    + Examples
    + --------
    +     measurements = loadBrendaMeasurements();
    +
    + See also
    + --------
    + kcatsFromECTree, ecTreeEstimate, loadBRENDAdata
    + + +

    CROSS-REFERENCE INFORMATION ^

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

    SUBFUNCTIONS ^

    + + +

    SOURCE CODE ^

    +
    0001 function measurements = loadBrendaMeasurements(varargin)
    +0002 % loadBrendaMeasurements  Load the BRENDA measurement table.
    +0003 %
    +0004 % Reads measurements.tsv from the BRENDA database folder of the model
    +0005 % adapter (next to kcat.tsv, sa.tsv and mw.tsv): one row per wild-type
    +0006 % BRENDA kcat with an EC number, after the outlier screen, with the
    +0007 % substrate, organism, UniProt accession and sequence id of each
    +0008 % measurement. geckopy reads the same file (load_brenda_measurements).
    +0009 %
    +0010 % Name-Value Arguments
    +0011 % --------------------
    +0012 % modelAdapter : ModelAdapter
    +0013 %     a loaded model adapter (default: the current default model adapter).
    +0014 % folder : char
    +0015 %     folder with measurements.tsv, instead of the adapter's BRENDA folder.
    +0016 %
    +0017 % Returns
    +0018 % -------
    +0019 % measurements : struct
    +0020 %     one field per column of the file (ec, substrate, substrate_inchikey,
    +0021 %     organism, taxid, uniprot, seq_id, temperature, ph and pmid as cell
    +0022 %     arrays of char; kcat as double), plus log10kcat and release (the
    +0023 %     release line of the file, e.g. 'BRENDA release 2026.1').
    +0024 %
    +0025 % Examples
    +0026 % --------
    +0027 %     measurements = loadBrendaMeasurements();
    +0028 %
    +0029 % See also
    +0030 % --------
    +0031 % kcatsFromECTree, ecTreeEstimate, loadBRENDAdata
    +0032 
    +0033 checkOptions(varargin, {'modelAdapter','folder'}, 'loadBrendaMeasurements');
    +0034 p = parseGECKOargs(varargin, {'modelAdapter', []; 'folder', []});
    +0035 folder = p.folder;
    +0036 if isempty(folder)
    +0037     modelAdapter = p.modelAdapter;
    +0038     if isempty(modelAdapter)
    +0039         modelAdapter = ModelAdapterManager.getDefault();
    +0040         if isempty(modelAdapter)
    +0041             error('Either send in a modelAdapter or set the default model adapter in the ModelAdapterManager.')
    +0042         end
    +0043     end
    +0044     folder = modelAdapter.getBrendaDBFolder();
    +0045 end
    +0046 file = fullfile(folder, 'measurements.tsv');
    +0047 if ~isfile(file)
    +0048     error('loadBrendaMeasurements:missing', ['No BRENDA measurement table (measurements.tsv) in %s. ' ...
    +0049         'It comes with the BRENDA files of GECKO (databases folder).'], folder)
    +0050 end
    +0051 fid = fopen(file, 'r', 'n', 'UTF-8');
    +0052 first = fgetl(fid);
    +0053 header = strsplit(fgetl(fid), '\t');
    +0054 data = textscan(fid, repmat('%s', 1, numel(header)), 'Delimiter', '\t', 'Whitespace', '', ...
    +0055     'ReturnOnError', false);
    +0056 fclose(fid);
    +0057 if ~all(ismember({'ec', 'kcat'}, header))
    +0058     error('loadBrendaMeasurements:columns', '%s lacks the columns ec and kcat.', file)
    +0059 end
    +0060 measurements = struct();
    +0061 for c = 1:numel(header)
    +0062     measurements.(matlab.lang.makeValidName(header{c})) = data{c};
    +0063 end
    +0064 measurements.kcat = str2double(measurements.kcat);
    +0065 keep = measurements.kcat > 0 & ~cellfun(@isempty, measurements.ec);
    +0066 for f = fieldnames(measurements)'
    +0067     measurements.(f{1}) = measurements.(f{1})(keep);
    +0068 end
    +0069 measurements.ec = strtrim(measurements.ec);
    +0070 measurements.log10kcat = log10(measurements.kcat);
    +0071 tok = regexp(first, '^#\s*(BRENDA release [^ ]+)', 'tokens', 'once');
    +0072 measurements.release = '';
    +0073 if ~isempty(tok)
    +0074     measurements.release = tok{1};
    +0075 end
    +0076 end
    +0077 
    +0078 function checkOptions(args, names, functionName)
    +0079 % Options are name-value pairs with known names, so a misspelled option is
    +0080 % an error instead of being taken as a positional argument.
    +0081 id = [functionName ':arguments'];
    +0082 given = args(1:2:end);
    +0083 if mod(numel(args), 2) ~= 0 || ~all(cellfun(@(x) ischar(x) || (isstring(x) && isscalar(x)), given))
    +0084     error(id, 'Options of %s are name-value pairs. Options: %s.', functionName, strjoin(names, ', '))
    +0085 end
    +0086 unknown = setdiff(cellfun(@char, given, 'UniformOutput', false), names);
    +0087 if ~isempty(unknown)
    +0088     error(id, 'Unknown option of %s: %s. Options: %s.', functionName, strjoin(unknown, ', '), ...
    +0089         strjoin(names, ', '))
    +0090 end
    +0091 end
    +
    Generated by m2html © 2005
    + + \ No newline at end of file diff --git a/doc/src/gather_kcats/loadKcatSource.html b/doc/src/gather_kcats/loadKcatSource.html new file mode 100644 index 00000000..a0812da3 --- /dev/null +++ b/doc/src/gather_kcats/loadKcatSource.html @@ -0,0 +1,489 @@ + + + + Description of loadKcatSource + + + + + + + + + +
    Home > src > gather_kcats > loadKcatSource.m
    + + + +

    loadKcatSource +

    + +

    PURPOSE ^

    +
    loadKcatSource Read a kcat source file and map its rows to an ecModel.
    + +

    SYNOPSIS ^

    +
    function [kcatList, report] = loadKcatSource(model, name, varargin)
    + +

    DESCRIPTION ^

    +
     loadKcatSource  Read a kcat source file and map its rows to an ecModel.
    +
    + Reads data/kcats/<name>.tsv (see saveKcatSource) and maps every row to
    + the model.ec reactions it applies to, by conventional reaction and
    + enzyme set (see getEcRxnKeys):
    +
    + 1. A row with rxn and enzymes applies to the model.ec rows with that
    +    conventional reaction and that enzyme set.
    + 2. A row with only enzymes applies to every model.ec row with that
    +    enzyme set; a row with only rxn to every model.ec row of that
    +    conventional reaction (curated rows; saveKcatSource always writes
    +    both).
    + 3. A row whose kcat is missing, not a number, infinite, or not above 0
    +    is reported as invalid and not applied.
    + 4. A row that matches nothing is reported, never dropped silently. If a
    +    model.ec row has at least half of the row's enzymes, that partial
    +    match is reported as well, but not applied.
    +
    + The enzymes of a row may be listed in any order.
    +
    + The file is read as UTF-8 (a leading byte-order mark is ignored). The
    + '#' lines before the column header are the header; '#' lines and blank
    + lines further down are skipped. Fields wrapped in double quotes, as a
    + spreadsheet may save them, are unwrapped. kcat and log10_sd must be plain
    + numbers (12, 0.5, 1e-05); other text, such as '5,5' with a decimal comma,
    + is reported as invalid. A row with more filled fields than there are
    + columns is an error.
    +
    + Parameters
    + ----------
    + model : struct
    +     an ecModel in GECKO 3 format (with ecModel.ec structure).
    + name : char
    +     name of the source (data/kcats/<name>.tsv in the project folder), or
    +     the path to a kcat source file.
    +
    + Name-Value Arguments
    + --------------------
    + modelAdapter : ModelAdapter
    +     a loaded model adapter (default: the current default model adapter).
    +
    + Returns
    + -------
    + kcatList : struct
    +     kcat values per model.ec reaction, as used by mergeKcats and
    +     assignKcatValues: source (the source name), rxns, kcats,
    +     substrates, eccodes, wildcardLvl and origin (from the detail
    +     column), kcatSource (the per-row source), log10sd, detail (the detail
    +     column), and line (the line of the file each entry comes from).
    + report : struct
    +     - invalid: table of the file rows with a missing or invalid kcat;
    +     - unmatched: table of the file rows that apply to no model.ec row;
    +     - partial: table of rows that only partly match an enzyme set, with
    +       the model.ec reaction and its enzymes;
    +     - header: the '#' header lines of the file, as field: value (for
    +       instance header.source, header.parameters);
    +     - records: the rows of the file as read, one field per column (kcat
    +       and log10_sd as double, other columns as cell of char) and line,
    +       the line number of each row.
    +
    + Examples
    + --------
    +     kcatList = loadKcatSource(ecModel, 'brenda');
    +     [kcatList, report] = loadKcatSource(ecModel, 'custom');
    +
    + See also
    + --------
    + saveKcatSource, kcatsFromBrenda, getEcRxnKeys
    + + +

    CROSS-REFERENCE INFORMATION ^

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

    SUBFUNCTIONS ^

    + + +

    SOURCE CODE ^

    +
    0001 function [kcatList, report] = loadKcatSource(model, name, varargin)
    +0002 % loadKcatSource  Read a kcat source file and map its rows to an ecModel.
    +0003 %
    +0004 % Reads data/kcats/<name>.tsv (see saveKcatSource) and maps every row to
    +0005 % the model.ec reactions it applies to, by conventional reaction and
    +0006 % enzyme set (see getEcRxnKeys):
    +0007 %
    +0008 % 1. A row with rxn and enzymes applies to the model.ec rows with that
    +0009 %    conventional reaction and that enzyme set.
    +0010 % 2. A row with only enzymes applies to every model.ec row with that
    +0011 %    enzyme set; a row with only rxn to every model.ec row of that
    +0012 %    conventional reaction (curated rows; saveKcatSource always writes
    +0013 %    both).
    +0014 % 3. A row whose kcat is missing, not a number, infinite, or not above 0
    +0015 %    is reported as invalid and not applied.
    +0016 % 4. A row that matches nothing is reported, never dropped silently. If a
    +0017 %    model.ec row has at least half of the row's enzymes, that partial
    +0018 %    match is reported as well, but not applied.
    +0019 %
    +0020 % The enzymes of a row may be listed in any order.
    +0021 %
    +0022 % The file is read as UTF-8 (a leading byte-order mark is ignored). The
    +0023 % '#' lines before the column header are the header; '#' lines and blank
    +0024 % lines further down are skipped. Fields wrapped in double quotes, as a
    +0025 % spreadsheet may save them, are unwrapped. kcat and log10_sd must be plain
    +0026 % numbers (12, 0.5, 1e-05); other text, such as '5,5' with a decimal comma,
    +0027 % is reported as invalid. A row with more filled fields than there are
    +0028 % columns is an error.
    +0029 %
    +0030 % Parameters
    +0031 % ----------
    +0032 % model : struct
    +0033 %     an ecModel in GECKO 3 format (with ecModel.ec structure).
    +0034 % name : char
    +0035 %     name of the source (data/kcats/<name>.tsv in the project folder), or
    +0036 %     the path to a kcat source file.
    +0037 %
    +0038 % Name-Value Arguments
    +0039 % --------------------
    +0040 % modelAdapter : ModelAdapter
    +0041 %     a loaded model adapter (default: the current default model adapter).
    +0042 %
    +0043 % Returns
    +0044 % -------
    +0045 % kcatList : struct
    +0046 %     kcat values per model.ec reaction, as used by mergeKcats and
    +0047 %     assignKcatValues: source (the source name), rxns, kcats,
    +0048 %     substrates, eccodes, wildcardLvl and origin (from the detail
    +0049 %     column), kcatSource (the per-row source), log10sd, detail (the detail
    +0050 %     column), and line (the line of the file each entry comes from).
    +0051 % report : struct
    +0052 %     - invalid: table of the file rows with a missing or invalid kcat;
    +0053 %     - unmatched: table of the file rows that apply to no model.ec row;
    +0054 %     - partial: table of rows that only partly match an enzyme set, with
    +0055 %       the model.ec reaction and its enzymes;
    +0056 %     - header: the '#' header lines of the file, as field: value (for
    +0057 %       instance header.source, header.parameters);
    +0058 %     - records: the rows of the file as read, one field per column (kcat
    +0059 %       and log10_sd as double, other columns as cell of char) and line,
    +0060 %       the line number of each row.
    +0061 %
    +0062 % Examples
    +0063 % --------
    +0064 %     kcatList = loadKcatSource(ecModel, 'brenda');
    +0065 %     [kcatList, report] = loadKcatSource(ecModel, 'custom');
    +0066 %
    +0067 % See also
    +0068 % --------
    +0069 % saveKcatSource, kcatsFromBrenda, getEcRxnKeys
    +0070 
    +0071 checkOptions(varargin, {'modelAdapter'}, 'loadKcatSource');
    +0072 p = parseGECKOargs(varargin, {'modelAdapter', []});
    +0073 
    +0074 if isfile(name)
    +0075     filename = name;
    +0076 else
    +0077     modelAdapter = p.modelAdapter;
    +0078     if isempty(modelAdapter)
    +0079         modelAdapter = ModelAdapterManager.getDefault();
    +0080         if isempty(modelAdapter)
    +0081             error('Either send in a modelAdapter or set the default model adapter in the ModelAdapterManager.')
    +0082         end
    +0083     end
    +0084     filename = fullfile(modelAdapter.params.path, 'data', 'kcats', [name '.tsv']);
    +0085     if ~isfile(filename)
    +0086         error('loadKcatSource:missing', ['No kcat source file %s. Make it with the ' ...
    +0087             'kcatsFrom<Source> function of this source (kcatsFromBrenda, kcatsFromDLKcat, ' ...
    +0088             'kcatsFromOKP), or with saveKcatSource.'], filename)
    +0089     end
    +0090 end
    +0091 [records, meta] = readSourceFile(filename);
    +0092 sourceName = '';
    +0093 if isfield(meta, 'source')
    +0094     sourceName = meta.source;
    +0095 end
    +0096 
    +0097 [baseRxns, enzymeSets] = getEcRxnKeys(model);
    +0098 nEc = numel(baseRxns);
    +0099 nRec = numel(records.kcat);
    +0100 
    +0101 % Lookup tables: key -> model.ec rows.
    +0102 byPair = groupIndex(strcat(baseRxns, '|', enzymeSets));
    +0103 byBase = groupIndex(baseRxns);
    +0104 byEnz  = groupIndex(enzymeSets);
    +0105 % accession -> model.ec rows containing it, for partial matches.
    +0106 accRows = cell(nEc, 1);
    +0107 for i = 1:nEc
    +0108     if ~isempty(enzymeSets{i})
    +0109         accRows{i} = strsplit(enzymeSets{i}, ' + ');
    +0110     end
    +0111 end
    +0112 accIdx = repelem((1:nEc)', cellfun(@numel, accRows));
    +0113 byAcc = groupIndex([accRows{:}]', accIdx);
    +0114 
    +0115 invalid = ~(records.kcat > 0) | ~isfinite(records.kcat);
    +0116 matchRec = cell(nRec, 1);
    +0117 matchEc  = cell(nRec, 1);
    +0118 unmatched = false(nRec, 1);
    +0119 partialRec = zeros(0, 1); partialEc = zeros(0, 1);
    +0120 for r = find(~invalid)'
    +0121     rxn = records.rxn{r};
    +0122     enz = normalizeEnzymes(records.enzymes{r});
    +0123     if ~isempty(rxn) && ~isempty(enz)
    +0124         hit = lookup(byPair, [rxn '|' enz]);
    +0125     elseif ~isempty(enz)
    +0126         hit = lookup(byEnz, enz);
    +0127     elseif ~isempty(rxn)
    +0128         hit = lookup(byBase, rxn);
    +0129     else
    +0130         hit = [];
    +0131     end
    +0132     if isempty(hit)
    +0133         unmatched(r) = true;
    +0134         if ~isempty(enz)
    +0135             wanted = strsplit(enz, ' + ');
    +0136             candidates = unique(cell2mat(cellfun(@(a) lookup(byAcc, a), wanted(:), 'UniformOutput', false)));
    +0137             if ~isempty(rxn)
    +0138                 candidates = intersect(candidates, lookup(byBase, rxn));
    +0139             end
    +0140             for c = candidates(:)'
    +0141                 if mean(ismember(wanted, accRows{c})) >= 0.5
    +0142                     partialRec(end+1, 1) = r; %#ok<AGROW>
    +0143                     partialEc(end+1, 1) = c; %#ok<AGROW>
    +0144                 end
    +0145             end
    +0146         end
    +0147     else
    +0148         matchRec{r} = repmat(r, numel(hit), 1);
    +0149         matchEc{r} = hit(:);
    +0150     end
    +0151 end
    +0152 rec = vertcat(matchRec{:}, zeros(0, 1));
    +0153 ec  = vertcat(matchEc{:}, zeros(0, 1));
    +0154 
    +0155 kcatList.source      = sourceName;
    +0156 kcatList.rxns        = reshape(model.ec.rxns(ec), [], 1);
    +0157 kcatList.kcats       = records.kcat(rec);
    +0158 kcatList.substrates  = records.substrate(rec);
    +0159 kcatList.eccodes     = records.ec_code(rec);
    +0160 kcatList.kcatSource  = records.source(rec);
    +0161 kcatList.log10sd     = records.log10_sd(rec);
    +0162 kcatList.detail      = records.detail(rec);
    +0163 [kcatList.wildcardLvl, kcatList.origin] = parseDetail(records.detail(rec));
    +0164 kcatList.line        = records.line(rec);
    +0165 
    +0166 report.invalid = table(records.line(invalid), records.rxn(invalid), records.enzymes(invalid), ...
    +0167     records.kcat(invalid), 'VariableNames', {'line','rxn','enzymes','kcat'});
    +0168 report.unmatched = table(records.line(unmatched), records.rxn(unmatched), records.enzymes(unmatched), ...
    +0169     records.kcat(unmatched), 'VariableNames', {'line','rxn','enzymes','kcat'});
    +0170 report.partial = table(records.line(partialRec), records.rxn(partialRec), records.enzymes(partialRec), ...
    +0171     reshape(model.ec.rxns(partialEc), [], 1), enzymeSets(partialEc), ...
    +0172     'VariableNames', {'line','rxn','enzymes','ecRxn','ecEnzymes'});
    +0173 if any(invalid)
    +0174     printOrange(sprintf('%d of %d rows of %s have no valid kcat; see report.invalid.\n', ...
    +0175         sum(invalid), nRec, filename));
    +0176 end
    +0177 if any(unmatched)
    +0178     printOrange(sprintf('%d of %d rows of %s apply to no reaction of this model; see report.unmatched.\n', ...
    +0179         sum(unmatched), nRec, filename));
    +0180 end
    +0181 report.header = meta;
    +0182 report.records = records;
    +0183 end
    +0184 
    +0185 function map = groupIndex(keys, rows)
    +0186 % containers.Map from each key to the rows (default 1:n) that have it.
    +0187 if nargin < 2
    +0188     rows = (1:numel(keys))';
    +0189 end
    +0190 map = containers.Map('KeyType', 'char', 'ValueType', 'any');
    +0191 if isempty(keys)
    +0192     return
    +0193 end
    +0194 [u, ~, g] = unique(keys(:));
    +0195 groups = accumarray(g, rows(:), [], @(x) {sort(x)});
    +0196 for i = 1:numel(u)
    +0197     if ~isempty(u{i})
    +0198         map(u{i}) = groups{i};
    +0199     end
    +0200 end
    +0201 end
    +0202 
    +0203 function rows = lookup(map, key)
    +0204 if isKey(map, key)
    +0205     rows = map(key);
    +0206 else
    +0207     rows = zeros(0, 1);
    +0208 end
    +0209 end
    +0210 
    +0211 function enz = normalizeEnzymes(enz)
    +0212 % Sorted and joined as getEcRxnKeys does, so hand-written rows match too.
    +0213 if isempty(enz)
    +0214     return
    +0215 end
    +0216 parts = strtrim(strsplit(enz, '+'));
    +0217 parts = unique(parts(~cellfun(@isempty, parts)));
    +0218 enz = strjoin(sort(parts(:)'), ' + ');
    +0219 end
    +0220 
    +0221 function [wc, origin] = parseDetail(detail)
    +0222 wc = nan(numel(detail), 1);
    +0223 origin = nan(numel(detail), 1);
    +0224 for i = 1:numel(detail)
    +0225     t = regexp(detail{i}, 'wc=(\d+)', 'tokens', 'once');
    +0226     if ~isempty(t)
    +0227         wc(i) = str2double(t{1});
    +0228     end
    +0229     t = regexp(detail{i}, 'origin=(\d+)', 'tokens', 'once');
    +0230     if ~isempty(t)
    +0231         origin(i) = str2double(t{1});
    +0232     end
    +0233 end
    +0234 end
    +0235 
    +0236 function [records, meta] = readSourceFile(filename)
    +0237 % The rows and '#' header lines of a kcat source file, as they are.
    +0238 text = readUtf8(filename);
    +0239 lines = regexp(text, '\r?\n', 'split');
    +0240 
    +0241 meta = struct();
    +0242 k = 1;
    +0243 while k <= numel(lines) && (isempty(strtrim(lines{k})) || startsWith(unquoteField(lines{k}), '#'))
    +0244     [key, value] = parseHeaderLine(lines{k});
    +0245     if ~isempty(key)
    +0246         meta.(key) = value;
    +0247     end
    +0248     k = k + 1;
    +0249 end
    +0250 if k > numel(lines)
    +0251     error('loadKcatSource:noHeader', '%s has no column header.', filename)
    +0252 end
    +0253 columns = cellfun(@unquoteField, strsplit(lines{k}, sprintf('\t'), ...
    +0254     'CollapseDelimiters', false), 'UniformOutput', false);
    +0255 if ~all(ismember({'kcat','source'}, columns)) || ~any(ismember({'rxn','enzymes'}, columns))
    +0256     error('loadKcatSource:columns', ['%s needs the columns kcat and source, and rxn ' ...
    +0257         'and/or enzymes.'], filename)
    +0258 end
    +0259 named = columns(~cellfun(@isempty, columns));
    +0260 if numel(unique(named)) < numel(named) || any(strcmp(columns, 'line'))
    +0261     error('loadKcatSource:columns', '%s has a column name twice, or a column named line.', filename)
    +0262 end
    +0263 nCol = numel(columns);
    +0264 
    +0265 trimmed = strtrim(lines);
    +0266 skip = cellfun(@isempty, trimmed) | startsWith(trimmed, '#') | startsWith(trimmed, '"#');
    +0267 skip(1:k) = true;
    +0268 kept = find(~skip);
    +0269 L = string(lines(kept));
    +0270 L = L(:);
    +0271 F = strings(numel(kept), nCol);
    +0272 nTabs = count(L, sprintf('\t'));
    +0273 regular = nTabs == nCol - 1;
    +0274 if any(regular)
    +0275     % Rows with exactly one field per column, split in one go.
    +0276     F(regular, :) = reshape(split(L(regular), sprintf('\t'), 2), [], nCol);
    +0277 end
    +0278 for r = find(~regular)'
    +0279     fields = strsplit(char(L(r)), sprintf('\t'), 'CollapseDelimiters', false);
    +0280     if numel(fields) > nCol
    +0281         if any(~cellfun(@isempty, strtrim(fields(nCol+1:end))))
    +0282             error('loadKcatSource:fields', '%s, line %d has more fields than the %d columns.', ...
    +0283                 filename, kept(r), nCol)
    +0284         end
    +0285         fields = fields(1:nCol);
    +0286     end
    +0287     fields(end+1:nCol) = {''};
    +0288     F(r, :) = string(fields);
    +0289 end
    +0290 F = strtrim(F);
    +0291 quoted = find(startsWith(F, '"'));
    +0292 for q = quoted(:)'
    +0293     F(q) = unquoteField(char(F(q)));
    +0294 end
    +0295 filled = any(F ~= "", 2); % a row of tabs only is skipped
    +0296 values = cellstr(F(filled, :));
    +0297 if isempty(values)
    +0298     values = cell(0, nCol);
    +0299 end
    +0300 lineNo = kept(filled);
    +0301 lineNo = lineNo(:);
    +0302 n = numel(lineNo);
    +0303 
    +0304 records = struct();
    +0305 for c = 1:nCol
    +0306     if isempty(columns{c})
    +0307         continue
    +0308     end
    +0309     name = matlab.lang.makeValidName(columns{c});
    +0310     v = values(:, c);
    +0311     if any(strcmp(columns{c}, {'kcat','log10_sd'}))
    +0312         v = parseKcatNumber(v);
    +0313     end
    +0314     records.(name) = v;
    +0315 end
    +0316 for c = {'rxn','enzymes','substrate','source','detail','ec_code','note'}
    +0317     if ~isfield(records, c{1})
    +0318         records.(c{1}) = repmat({''}, n, 1);
    +0319     end
    +0320 end
    +0321 if ~isfield(records, 'log10_sd')
    +0322     records.log10_sd = nan(n, 1);
    +0323 end
    +0324 records.line = lineNo;
    +0325 end
    +0326 
    +0327 function text = readUtf8(filename)
    +0328 fid = fopen(filename, 'r', 'n', 'UTF-8');
    +0329 if fid < 0
    +0330     error('loadKcatSource:read', 'Cannot read %s', filename)
    +0331 end
    +0332 cleanup = onCleanup(@() fclose(fid));
    +0333 text = fread(fid, [1 Inf], '*char');
    +0334 text = regexprep(text, ['^' char(65279)], '');
    +0335 end
    +0336 
    +0337 function x = parseKcatNumber(texts)
    +0338 % Plain numbers only: '5,5' or '12 /s' read as NaN.
    +0339 x = nan(numel(texts), 1);
    +0340 ok = ~cellfun(@isempty, regexp(texts(:), '^[-+]?(\d+\.?\d*|\.\d+)([eE][-+]?\d+)?$|^[-+]?Inf$', 'once'));
    +0341 x(ok) = str2double(texts(ok));
    +0342 end
    +0343 
    +0344 function [key, value] = parseHeaderLine(line)
    +0345 key = ''; value = '';
    +0346 tok = regexp(unquoteField(line), '^\s*#\s*([A-Za-z][A-Za-z0-9_]{0,62})\s*:\s?(.*)$', 'tokens', 'once');
    +0347 if ~isempty(tok)
    +0348     key = lower(tok{1});
    +0349     value = strtrim(tok{2});
    +0350 end
    +0351 end
    +0352 
    +0353 function t = unquoteField(t)
    +0354 t = strtrim(t);
    +0355 if numel(t) >= 2 && t(1) == '"' && t(end) == '"'
    +0356     t = strtrim(strrep(t(2:end-1), '""', '"'));
    +0357 end
    +0358 end
    +0359 
    +0360 function checkOptions(args, names, functionName)
    +0361 % Options are name-value pairs with known names, so a misspelled option is
    +0362 % an error instead of being taken as a positional argument.
    +0363 id = [functionName ':arguments'];
    +0364 given = args(1:2:end);
    +0365 if mod(numel(args), 2) ~= 0 || ~all(cellfun(@(x) ischar(x) || (isstring(x) && isscalar(x)), given))
    +0366     error(id, 'Options of %s are name-value pairs. Options: %s.', functionName, strjoin(names, ', '))
    +0367 end
    +0368 unknown = setdiff(cellfun(@char, given, 'UniformOutput', false), names);
    +0369 if ~isempty(unknown)
    +0370     error(id, 'Unknown option of %s: %s. Options: %s.', functionName, strjoin(unknown, ', '), ...
    +0371         strjoin(names, ', '))
    +0372 end
    +0373 end
    +
    Generated by m2html © 2005
    + + \ No newline at end of file diff --git a/doc/src/gather_kcats/mergeDLKcatAndFuzzyKcats.html b/doc/src/gather_kcats/mergeDLKcatAndFuzzyKcats.html new file mode 100644 index 00000000..a284969c --- /dev/null +++ b/doc/src/gather_kcats/mergeDLKcatAndFuzzyKcats.html @@ -0,0 +1,215 @@ + + + + Description of mergeDLKcatAndFuzzyKcats + + + + + + + + + +
    Home > src > gather_kcats > mergeDLKcatAndFuzzyKcats.m
    + + + +

    mergeDLKcatAndFuzzyKcats +

    + +

    PURPOSE ^

    +
    mergeDLKcatAndFuzzyKcats Merge DLKcat and BRENDA fuzzy matching results.
    + +

    SYNOPSIS ^

    +
    function mergedKcatList = mergeDLKcatAndFuzzyKcats(kcatListDLKcat, kcatListFuzzy, varargin)
    + +

    DESCRIPTION ^

    +
     mergeDLKcatAndFuzzyKcats  Merge DLKcat and BRENDA fuzzy matching results.
    +
    + Deprecated thin wrapper around mergeKcats, kept for the common DLKcat +
    + fuzzy-BRENDA case. New code should call mergeKcats directly, which also
    + handles a single list that mixes several sources (e.g. an
    + OpenKineticsPredictor result with BRENDA/Sabio-RK/CataPro rows).
    +
    + Merges the results from DLKcat and fuzzy matching to the BRENDA database.
    + Order of preference:
    +
    + 1. BRENDA match with correct E.C. number, with origin (see below) not
    +    lower than the specified topOriginLimit.
    + 2. DLKcat match.
    + 3. BRENDA match with correct E.C. number, with origin below topOriginLimit
    +    but not lower than the bottomOriginLimit.
    + 4. BRENDA match with wildcards in the E.C. number, with not more wildcards
    +    than wildcardLimit, and origin not lower than the bottomOriginLimit.
    +
    + Parameters
    + ----------
    + kcatListDLKcat : struct
    +     kcatList derived from readDLKcatOutput.
    + kcatListFuzzy : struct
    +     kcatList derived from fuzzyKcatMatching.
    +
    + Name-Value Arguments
    + --------------------
    + topOriginLimit : double
    +     origin limit for prioritized BRENDA matches. Origin is explained in
    +     more detail below (default 4: BRENDA matches of origin 5 and 6, from
    +     specific activities, rank after DLKcat; use 6 to rank them above).
    + bottomOriginLimit : double
    +     origin limit for low priority BRENDA matches. Origin is explained in
    +     more detail below (default 6).
    + wildcardLimit : double
    +     maximum number of wildcards in E.C. number of BRENDA matches
    +     (default 3).
    +
    + Returns
    + -------
    + mergedKcatList : struct
    +     merged kcatList with the same field layout produced by mergeKcats
    +     (source, kcatSource, rxns, genes, substrates, kcats, eccodes,
    +     wildcardLvl, origin), keeping only the rows selected by the order of
    +     preference above.
    +
    + Notes
    + -----
    + The origin parameter:
    +
    + - 1 : correct organism, correct substrate, kcat.
    + - 2 : any organism, correct substrate, kcat.
    + - 3 : correct organism, any substrate, kcat.
    + - 4 : any organism, any substrate, kcat.
    + - 5 : correct organism, specific activity.
    + - 6 : any organism, specific activity.
    +
    + Example of wildcards in E.C. number:
    +
    + - 0 : 1.1.1.3   glycerol-3-phosphate dehydrogenase (NAD+).
    + - 1 : 1.1.1.-   oxidoreductase, acting on the CH-OH group of donors, with
    +   NAD+ or NADP+ as acceptor.
    + - 2 : 1.1.-.-   oxidoreductase, acting on the CH-OH group of donors.
    + - 3 : 1.-.-.-   oxidoreductase.
    +
    + Examples
    + --------
    +     % optional arguments may be given positionally or as name-value pairs:
    +     mergedKcatList = mergeDLKcatAndFuzzyKcats(kcatListDLKcat, kcatListFuzzy);
    +     mergedKcatList = mergeDLKcatAndFuzzyKcats(kcatListDLKcat, kcatListFuzzy, 'wildcardLimit', 2);
    +
    + See also
    + --------
    + mergeKcats, readDLKcatOutput, fuzzyKcatMatching, assignKcatValues
    + + +

    CROSS-REFERENCE INFORMATION ^

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

    SOURCE CODE ^

    +
    0001 function mergedKcatList = mergeDLKcatAndFuzzyKcats(kcatListDLKcat, kcatListFuzzy, varargin)
    +0002 % mergeDLKcatAndFuzzyKcats  Merge DLKcat and BRENDA fuzzy matching results.
    +0003 %
    +0004 % Deprecated thin wrapper around mergeKcats, kept for the common DLKcat +
    +0005 % fuzzy-BRENDA case. New code should call mergeKcats directly, which also
    +0006 % handles a single list that mixes several sources (e.g. an
    +0007 % OpenKineticsPredictor result with BRENDA/Sabio-RK/CataPro rows).
    +0008 %
    +0009 % Merges the results from DLKcat and fuzzy matching to the BRENDA database.
    +0010 % Order of preference:
    +0011 %
    +0012 % 1. BRENDA match with correct E.C. number, with origin (see below) not
    +0013 %    lower than the specified topOriginLimit.
    +0014 % 2. DLKcat match.
    +0015 % 3. BRENDA match with correct E.C. number, with origin below topOriginLimit
    +0016 %    but not lower than the bottomOriginLimit.
    +0017 % 4. BRENDA match with wildcards in the E.C. number, with not more wildcards
    +0018 %    than wildcardLimit, and origin not lower than the bottomOriginLimit.
    +0019 %
    +0020 % Parameters
    +0021 % ----------
    +0022 % kcatListDLKcat : struct
    +0023 %     kcatList derived from readDLKcatOutput.
    +0024 % kcatListFuzzy : struct
    +0025 %     kcatList derived from fuzzyKcatMatching.
    +0026 %
    +0027 % Name-Value Arguments
    +0028 % --------------------
    +0029 % topOriginLimit : double
    +0030 %     origin limit for prioritized BRENDA matches. Origin is explained in
    +0031 %     more detail below (default 4: BRENDA matches of origin 5 and 6, from
    +0032 %     specific activities, rank after DLKcat; use 6 to rank them above).
    +0033 % bottomOriginLimit : double
    +0034 %     origin limit for low priority BRENDA matches. Origin is explained in
    +0035 %     more detail below (default 6).
    +0036 % wildcardLimit : double
    +0037 %     maximum number of wildcards in E.C. number of BRENDA matches
    +0038 %     (default 3).
    +0039 %
    +0040 % Returns
    +0041 % -------
    +0042 % mergedKcatList : struct
    +0043 %     merged kcatList with the same field layout produced by mergeKcats
    +0044 %     (source, kcatSource, rxns, genes, substrates, kcats, eccodes,
    +0045 %     wildcardLvl, origin), keeping only the rows selected by the order of
    +0046 %     preference above.
    +0047 %
    +0048 % Notes
    +0049 % -----
    +0050 % The origin parameter:
    +0051 %
    +0052 % - 1 : correct organism, correct substrate, kcat.
    +0053 % - 2 : any organism, correct substrate, kcat.
    +0054 % - 3 : correct organism, any substrate, kcat.
    +0055 % - 4 : any organism, any substrate, kcat.
    +0056 % - 5 : correct organism, specific activity.
    +0057 % - 6 : any organism, specific activity.
    +0058 %
    +0059 % Example of wildcards in E.C. number:
    +0060 %
    +0061 % - 0 : 1.1.1.3   glycerol-3-phosphate dehydrogenase (NAD+).
    +0062 % - 1 : 1.1.1.-   oxidoreductase, acting on the CH-OH group of donors, with
    +0063 %   NAD+ or NADP+ as acceptor.
    +0064 % - 2 : 1.1.-.-   oxidoreductase, acting on the CH-OH group of donors.
    +0065 % - 3 : 1.-.-.-   oxidoreductase.
    +0066 %
    +0067 % Examples
    +0068 % --------
    +0069 %     % optional arguments may be given positionally or as name-value pairs:
    +0070 %     mergedKcatList = mergeDLKcatAndFuzzyKcats(kcatListDLKcat, kcatListFuzzy);
    +0071 %     mergedKcatList = mergeDLKcatAndFuzzyKcats(kcatListDLKcat, kcatListFuzzy, 'wildcardLimit', 2);
    +0072 %
    +0073 % See also
    +0074 % --------
    +0075 % mergeKcats, readDLKcatOutput, fuzzyKcatMatching, assignKcatValues
    +0076 
    +0077 p = parseGECKOargs(varargin, { ...
    +0078     'topOriginLimit',    4; ...
    +0079     'bottomOriginLimit', 6; ...
    +0080     'wildcardLimit',     3});
    +0081 topOriginLimit    = p.topOriginLimit;
    +0082 bottomOriginLimit = p.bottomOriginLimit;
    +0083 wildcardLimit     = p.wildcardLimit;
    +0084 
    +0085 warning(['mergeDLKcatAndFuzzyKcats is deprecated; use mergeKcats instead. ' ...
    +0086     'The old name will be removed in a future release.']);
    +0087 
    +0088 % Fuzzy list first, then DLKcat, so surviving rows keep the legacy order
    +0089 % (fuzzy block followed by DLKcat block).
    +0090 mergedKcatList = mergeKcats({kcatListFuzzy, kcatListDLKcat}, ...
    +0091     {'database_top', 'dlkcat', 'database_bottom'}, ...
    +0092     'topOriginLimit', topOriginLimit, ...
    +0093     'bottomOriginLimit', bottomOriginLimit, ...
    +0094     'wildcardLimit', wildcardLimit);
    +0095 end
    +
    Generated by m2html © 2005
    + + \ No newline at end of file diff --git a/doc/src/gather_kcats/mergeKcats.html b/doc/src/gather_kcats/mergeKcats.html new file mode 100644 index 00000000..38643a3f --- /dev/null +++ b/doc/src/gather_kcats/mergeKcats.html @@ -0,0 +1,414 @@ + + + + Description of mergeKcats + + + + + + + + + +
    Home > src > gather_kcats > mergeKcats.m
    + + + +

    mergeKcats +

    + +

    PURPOSE ^

    +
    mergeKcats Merge any number of kcatLists, keeping the highest-priority
    + +

    SYNOPSIS ^

    +
    function mergedKcatList = mergeKcats(kcatLists, sourcePriority, varargin)
    + +

    DESCRIPTION ^

    +
     mergeKcats  Merge any number of kcatLists, keeping the highest-priority
    + source for each reaction.
    +
    + Generalizes mergeDLKcatAndFuzzyKcats: instead of two fixed inputs (DLKcat
    + + fuzzy BRENDA) it accepts a cell array of kcatLists, each of which may
    + itself mix several sources (for example the output of
    + fetchOpenKineticsPredictor, carrying BRENDA, Sabio-RK and CataPro values
    + in its kcatSource field). A caller-supplied sourcePriority decides which
    + source wins for each reaction.
    +
    + Parameters
    + ----------
    + kcatLists : cell
    +     cell array of kcatList structs (as produced by fuzzyKcatMatching,
    +     readDLKcatOutput, fetchOpenKineticsPredictor, ...).
    + sourcePriority : cell
    +     cell array of tier tokens / source labels, best first. Three
    +     reserved tier tokens may be used instead of a literal source label:
    +
    +     - 'database_exact'  an exact experimental-database measurement
    +       (a BRENDA/Sabio-RK row with no fuzzy metadata, i.e. a direct OKP
    +       hit, no wildcards).
    +     - 'database_top'    a fuzzy BRENDA match with wildcardLvl==0 and
    +       origin<=topOriginLimit.
    +     - 'database_bottom' weaker fuzzy BRENDA matches within
    +       wildcardLimit / bottomOriginLimit.
    +
    +     Any other token is matched against each row's source after folding
    +     to lowercase snake_case (e.g. 'dlkcat', 'catapro'). Sources not
    +     listed are dropped.
    +
    + Name-Value Arguments
    + --------------------
    + topOriginLimit : double
    +     origin limit for database_top (default 4). Origins 5 and 6 are specific
    +     activity times molecular weight kcats, which do not always beat a
    +     prediction; they rank after the other sources and are used where
    +     nothing else exists, or above DLKcat with topOriginLimit 6.
    + bottomOriginLimit : double
    +     origin limit for database_bottom (default 6).
    + wildcardLimit : double
    +     maximum wildcards for database_bottom's wildcard branch (default 3).
    + databaseSources : cell
    +     source labels treated as experimental databases, i.e. routed to the
    +     database_* tiers (default {'brenda','sabio_rk'}).
    +
    + Returns
    + -------
    + mergedKcatList : struct
    +     merged kcatList, keeping only the winning rows per reaction; see
    +     Notes below for its fields. Row order follows the order of the input
    +     lists (each list's surviving rows, in turn), so a two-list call
    +     behaves like the legacy mergeDLKcatAndFuzzyKcats.
    +
    + Notes
    + -----
    + The mergedKcatList structure has the following fields:
    +
    + - source : 'merged'.
    + - kcatSource : per-row provenance, preserved verbatim from the input
    +   lists.
    + - rxns : reaction identifiers.
    + - genes : gene identifiers (where provided by the input lists).
    + - substrates : substrate names (where provided by the input lists).
    + - kcats : selected kcat value in /sec.
    + - eccodes : as used to query BRENDA (where applicable).
    + - wildcardLvl : wildcard level of the source match (where applicable).
    + - origin : specificity level of the source match (where applicable).
    +
    + The origin parameter:
    +
    + - 1 : correct organism, correct substrate, kcat.
    + - 2 : any organism, correct substrate, kcat.
    + - 3 : correct organism, any substrate, kcat.
    + - 4 : any organism, any substrate, kcat.
    + - 5 : correct organism, specific activity.
    + - 6 : any organism, specific activity.
    +
    + Examples
    + --------
    +     % optional arguments may be given positionally or as name-value pairs:
    +     mergedKcatList = mergeKcats({kcatListFuzzy, kcatListDLKcat}, ...
    +         {'database_top', 'dlkcat', 'database_bottom'});
    +     mergedKcatList = mergeKcats({kcatListFuzzy, kcatListOKP}, ...
    +         {'database_exact', 'database_top', 'database_bottom'}, 'wildcardLimit', 2);
    +
    + See also
    + --------
    + mergeDLKcatAndFuzzyKcats, readDLKcatOutput, fuzzyKcatMatching, assignKcatValues
    + + +

    CROSS-REFERENCE INFORMATION ^

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

    SUBFUNCTIONS ^

    + + +

    SOURCE CODE ^

    +
    0001 function mergedKcatList = mergeKcats(kcatLists, sourcePriority, varargin)
    +0002 % mergeKcats  Merge any number of kcatLists, keeping the highest-priority
    +0003 % source for each reaction.
    +0004 %
    +0005 % Generalizes mergeDLKcatAndFuzzyKcats: instead of two fixed inputs (DLKcat
    +0006 % + fuzzy BRENDA) it accepts a cell array of kcatLists, each of which may
    +0007 % itself mix several sources (for example the output of
    +0008 % fetchOpenKineticsPredictor, carrying BRENDA, Sabio-RK and CataPro values
    +0009 % in its kcatSource field). A caller-supplied sourcePriority decides which
    +0010 % source wins for each reaction.
    +0011 %
    +0012 % Parameters
    +0013 % ----------
    +0014 % kcatLists : cell
    +0015 %     cell array of kcatList structs (as produced by fuzzyKcatMatching,
    +0016 %     readDLKcatOutput, fetchOpenKineticsPredictor, ...).
    +0017 % sourcePriority : cell
    +0018 %     cell array of tier tokens / source labels, best first. Three
    +0019 %     reserved tier tokens may be used instead of a literal source label:
    +0020 %
    +0021 %     - 'database_exact'  an exact experimental-database measurement
    +0022 %       (a BRENDA/Sabio-RK row with no fuzzy metadata, i.e. a direct OKP
    +0023 %       hit, no wildcards).
    +0024 %     - 'database_top'    a fuzzy BRENDA match with wildcardLvl==0 and
    +0025 %       origin<=topOriginLimit.
    +0026 %     - 'database_bottom' weaker fuzzy BRENDA matches within
    +0027 %       wildcardLimit / bottomOriginLimit.
    +0028 %
    +0029 %     Any other token is matched against each row's source after folding
    +0030 %     to lowercase snake_case (e.g. 'dlkcat', 'catapro'). Sources not
    +0031 %     listed are dropped.
    +0032 %
    +0033 % Name-Value Arguments
    +0034 % --------------------
    +0035 % topOriginLimit : double
    +0036 %     origin limit for database_top (default 4). Origins 5 and 6 are specific
    +0037 %     activity times molecular weight kcats, which do not always beat a
    +0038 %     prediction; they rank after the other sources and are used where
    +0039 %     nothing else exists, or above DLKcat with topOriginLimit 6.
    +0040 % bottomOriginLimit : double
    +0041 %     origin limit for database_bottom (default 6).
    +0042 % wildcardLimit : double
    +0043 %     maximum wildcards for database_bottom's wildcard branch (default 3).
    +0044 % databaseSources : cell
    +0045 %     source labels treated as experimental databases, i.e. routed to the
    +0046 %     database_* tiers (default {'brenda','sabio_rk'}).
    +0047 %
    +0048 % Returns
    +0049 % -------
    +0050 % mergedKcatList : struct
    +0051 %     merged kcatList, keeping only the winning rows per reaction; see
    +0052 %     Notes below for its fields. Row order follows the order of the input
    +0053 %     lists (each list's surviving rows, in turn), so a two-list call
    +0054 %     behaves like the legacy mergeDLKcatAndFuzzyKcats.
    +0055 %
    +0056 % Notes
    +0057 % -----
    +0058 % The mergedKcatList structure has the following fields:
    +0059 %
    +0060 % - source : 'merged'.
    +0061 % - kcatSource : per-row provenance, preserved verbatim from the input
    +0062 %   lists.
    +0063 % - rxns : reaction identifiers.
    +0064 % - genes : gene identifiers (where provided by the input lists).
    +0065 % - substrates : substrate names (where provided by the input lists).
    +0066 % - kcats : selected kcat value in /sec.
    +0067 % - eccodes : as used to query BRENDA (where applicable).
    +0068 % - wildcardLvl : wildcard level of the source match (where applicable).
    +0069 % - origin : specificity level of the source match (where applicable).
    +0070 %
    +0071 % The origin parameter:
    +0072 %
    +0073 % - 1 : correct organism, correct substrate, kcat.
    +0074 % - 2 : any organism, correct substrate, kcat.
    +0075 % - 3 : correct organism, any substrate, kcat.
    +0076 % - 4 : any organism, any substrate, kcat.
    +0077 % - 5 : correct organism, specific activity.
    +0078 % - 6 : any organism, specific activity.
    +0079 %
    +0080 % Examples
    +0081 % --------
    +0082 %     % optional arguments may be given positionally or as name-value pairs:
    +0083 %     mergedKcatList = mergeKcats({kcatListFuzzy, kcatListDLKcat}, ...
    +0084 %         {'database_top', 'dlkcat', 'database_bottom'});
    +0085 %     mergedKcatList = mergeKcats({kcatListFuzzy, kcatListOKP}, ...
    +0086 %         {'database_exact', 'database_top', 'database_bottom'}, 'wildcardLimit', 2);
    +0087 %
    +0088 % See also
    +0089 % --------
    +0090 % mergeDLKcatAndFuzzyKcats, readDLKcatOutput, fuzzyKcatMatching, assignKcatValues
    +0091 
    +0092 p = parseGECKOargs(varargin, { ...
    +0093     'topOriginLimit',    4; ...
    +0094     'bottomOriginLimit', 6; ...
    +0095     'wildcardLimit',     3; ...
    +0096     'databaseSources',   {'brenda','sabio_rk'}});
    +0097 topOriginLimit    = p.topOriginLimit;
    +0098 bottomOriginLimit = p.bottomOriginLimit;
    +0099 wildcardLimit     = p.wildcardLimit;
    +0100 databaseSources   = p.databaseSources;
    +0101 
    +0102 if (topOriginLimit < 1) || (topOriginLimit > 6)
    +0103     error('topOriginLimit should be between 1 and 6.');
    +0104 end
    +0105 if (bottomOriginLimit < 1) || (bottomOriginLimit > 6)
    +0106     error('bottomOriginLimit should be between 1 and 6.');
    +0107 end
    +0108 if (wildcardLimit < 0) || (wildcardLimit > 3)
    +0109     error('wildcardLimit should be between 0 and 3.');
    +0110 end
    +0111 if isempty(sourcePriority)
    +0112     error('sourcePriority must be a non-empty cell array.');
    +0113 end
    +0114 if ~iscell(kcatLists)
    +0115     error('kcatLists must be a cell array of kcatList structs.');
    +0116 end
    +0117 
    +0118 dbSources = cellfun(@normalizeSource, databaseSources, 'UniformOutput', false);
    +0119 
    +0120 % Rank map: normalised priority token -> rank (1 = best). First wins.
    +0121 rankMap = containers.Map('KeyType','char','ValueType','double');
    +0122 for r = 1:numel(sourcePriority)
    +0123     key = normalizeSource(sourcePriority{r});
    +0124     if ~isKey(rankMap, key)
    +0125         rankMap(key) = r;
    +0126     end
    +0127 end
    +0128 
    +0129 % Concatenate all lists, normalising missing fields per row.
    +0130 rxns = {}; kcats = []; genes = {}; substrates = {};
    +0131 eccodes = {}; wcl = []; origin = []; rawSource = {};
    +0132 for k = 1:numel(kcatLists)
    +0133     s = kcatLists{k};
    +0134     if isempty(s) || ~isfield(s,'rxns') || isempty(s.rxns)
    +0135         continue
    +0136     end
    +0137     n          = numel(s.rxns);
    +0138     rxns       = [rxns;       s.rxns(:)];
    +0139     kcats      = [kcats;      double(s.kcats(:))];
    +0140     genes      = [genes;      getColCell(s, 'genes', n)];
    +0141     substrates = [substrates; getColCell(s, 'substrates', n)];
    +0142     eccodes    = [eccodes;    getColCell(s, 'eccodes', n)];
    +0143     wcl        = [wcl;        getColNum(s, 'wildcardLvl', n)];
    +0144     origin     = [origin;     getColNum(s, 'origin', n)];
    +0145     rawSource  = [rawSource;  getRowSource(s, n)];
    +0146 end
    +0147 
    +0148 N = numel(rxns);
    +0149 if N == 0
    +0150     mergedKcatList = emptyMergedList();
    +0151     return
    +0152 end
    +0153 
    +0154 % Drop rows without a usable turnover number. This also removes the
    +0155 % kcats==0 rows fuzzyKcatMatching emits for unmatched reactions, so a
    +0156 % remaining NaN-metadata database row is unambiguously an exact OKP hit.
    +0157 valid          = kcats > 0;
    +0158 rxns           = rxns(valid);
    +0159 kcats          = kcats(valid);
    +0160 genes          = genes(valid);
    +0161 substrates     = substrates(valid);
    +0162 eccodes        = eccodes(valid);
    +0163 wcl            = wcl(valid);
    +0164 origin         = origin(valid);
    +0165 rawSource      = rawSource(valid);
    +0166 N              = numel(rxns);
    +0167 if N == 0
    +0168     mergedKcatList = emptyMergedList();
    +0169     return
    +0170 end
    +0171 
    +0172 token  = cellfun(@normalizeSource, rawSource, 'UniformOutput', false);
    +0173 isDb   = ismember(token, dbSources);
    +0174 hasMeta = ~isnan(wcl) & ~isnan(origin);
    +0175 
    +0176 % Tier per row ('' marks a database row that fails the quality gate).
    +0177 tier = token;
    +0178 dbIdx = find(isDb);
    +0179 for ii = dbIdx'
    +0180     if ~hasMeta(ii)
    +0181         tier{ii} = 'database_exact';
    +0182     elseif wcl(ii) == 0 && origin(ii) <= topOriginLimit
    +0183         tier{ii} = 'database_top';
    +0184     elseif (wcl(ii) == 0 && origin(ii) > topOriginLimit && origin(ii) <= bottomOriginLimit) || ...
    +0185            (wcl(ii) > 0  && wcl(ii) <= wildcardLimit       && origin(ii) <= bottomOriginLimit)
    +0186         tier{ii} = 'database_bottom';
    +0187     else
    +0188         tier{ii} = '';
    +0189     end
    +0190 end
    +0191 
    +0192 % Rank per row (NaN if the tier is not listed in sourcePriority).
    +0193 rankPerRow = nan(N,1);
    +0194 for ii = 1:N
    +0195     if ~isempty(tier{ii}) && isKey(rankMap, tier{ii})
    +0196         rankPerRow(ii) = rankMap(tier{ii});
    +0197     end
    +0198 end
    +0199 
    +0200 % Warn about non-database sources that were dropped for not being listed.
    +0201 droppedTokens = unique(token(~isDb & isnan(rankPerRow)));
    +0202 if ~isempty(droppedTokens)
    +0203     warning('Dropping rows from source(s) not listed in sourcePriority: %s', ...
    +0204         strjoin(droppedTokens', ', '));
    +0205 end
    +0206 
    +0207 % For each reaction keep all rows of its best (lowest-rank) tier.
    +0208 keep = false(N,1);
    +0209 validRank = ~isnan(rankPerRow);
    +0210 uRxns = unique(rxns(validRank));
    +0211 for k = 1:numel(uRxns)
    +0212     ri = find(strcmp(rxns, uRxns{k}) & validRank);
    +0213     minR = min(rankPerRow(ri));
    +0214     keep(ri(rankPerRow(ri) == minR)) = true;
    +0215 end
    +0216 
    +0217 mergedKcatList             = struct();
    +0218 mergedKcatList.source      = 'merged';
    +0219 mergedKcatList.kcatSource  = rawSource(keep);
    +0220 mergedKcatList.rxns        = rxns(keep);
    +0221 mergedKcatList.genes       = genes(keep);
    +0222 mergedKcatList.substrates  = substrates(keep);
    +0223 mergedKcatList.kcats       = kcats(keep);
    +0224 mergedKcatList.eccodes     = eccodes(keep);
    +0225 mergedKcatList.wildcardLvl = wcl(keep);
    +0226 mergedKcatList.origin      = origin(keep);
    +0227 end
    +0228 
    +0229 % ------------------------------------------------------------------------- %
    +0230 function s = normalizeSource(label)
    +0231 % Fold a source label to lowercase snake_case ('Sabio-RK' -> 'sabio_rk').
    +0232 s = lower(strtrim(char(label)));
    +0233 s = regexprep(s, '[^0-9a-z]+', '_');
    +0234 s = regexprep(s, '^_+|_+$', '');
    +0235 end
    +0236 
    +0237 function v = getColCell(s, name, n)
    +0238 if isfield(s, name) && ~isempty(s.(name))
    +0239     v = s.(name)(:);
    +0240     if numel(v) == 1 && n > 1
    +0241         v = repmat(v, n, 1);
    +0242     end
    +0243 else
    +0244     v = repmat({[]}, n, 1);
    +0245 end
    +0246 end
    +0247 
    +0248 function v = getColNum(s, name, n)
    +0249 if isfield(s, name) && ~isempty(s.(name))
    +0250     v = double(s.(name)(:));
    +0251 else
    +0252     v = nan(n, 1);
    +0253 end
    +0254 end
    +0255 
    +0256 function v = getRowSource(s, n)
    +0257 if isfield(s, 'kcatSource') && ~isempty(s.kcatSource)
    +0258     v = s.kcatSource(:);
    +0259 elseif isfield(s, 'source')
    +0260     v = repmat({char(s.source)}, n, 1);
    +0261 else
    +0262     v = repmat({''}, n, 1);
    +0263 end
    +0264 end
    +0265 
    +0266 function mergedKcatList = emptyMergedList()
    +0267 mergedKcatList             = struct();
    +0268 mergedKcatList.source      = 'merged';
    +0269 mergedKcatList.kcatSource  = {};
    +0270 mergedKcatList.rxns        = {};
    +0271 mergedKcatList.genes       = {};
    +0272 mergedKcatList.substrates  = {};
    +0273 mergedKcatList.kcats       = [];
    +0274 mergedKcatList.eccodes     = {};
    +0275 mergedKcatList.wildcardLvl = [];
    +0276 mergedKcatList.origin      = [];
    +0277 end
    +
    Generated by m2html © 2005
    + + \ No newline at end of file diff --git a/doc/src/gather_kcats/readDLKcatOutput.html b/doc/src/gather_kcats/readDLKcatOutput.html new file mode 100644 index 00000000..fa560d82 --- /dev/null +++ b/doc/src/gather_kcats/readDLKcatOutput.html @@ -0,0 +1,194 @@ + + + + Description of readDLKcatOutput + + + + + + + + + +
    Home > src > gather_kcats > readDLKcatOutput.m
    + + + +

    readDLKcatOutput +

    + +

    PURPOSE ^

    +
    readDLKcatOutput Read the DLKcat output file into a kcatList structure.
    + +

    SYNOPSIS ^

    +
    function kcatList = readDLKcatOutput(model, varargin)
    + +

    DESCRIPTION ^

    +
     readDLKcatOutput  Read the DLKcat output file into a kcatList structure.
    +
    + Reads the DLKcat output file and constructs a kcatList structure, that can
    + be used by assignKcatValues() to populate the ecModel with kcat values.
    +
    + Parameters
    + ----------
    + model : struct
    +     an ecModel in GECKO 3 format (with ecModel.ec structure).
    +
    + Name-Value Arguments
    + --------------------
    + outFile : char
    +     name and path of the DLKcat output file (default: data/DLKcat.tsv from
    +     the obj.params.path folder specified in the modelAdapter).
    + modelAdapter : ModelAdapter
    +     a loaded model adapter (default: the current default model adapter).
    +
    + Returns
    + -------
    + kcatList : struct
    +     structure array with list of DLKcat derived kcat values, with separate
    +     entries for each kcat value.
    +
    + Notes
    + -----
    + The kcatList structure has the following fields:
    +
    + - source : 'DLKcat'.
    + - rxns : reaction identifiers.
    + - genes : gene identifiers.
    + - substrates : substrate names.
    + - kcats : predicted kcat value in /sec.
    +
    + Examples
    + --------
    +     % optional arguments may be given positionally or as name-value pairs:
    +     kcatList = readDLKcatOutput(model);
    +     kcatList = readDLKcatOutput(model, 'outFile', 'myDLKcat.tsv');
    +
    + See also
    + --------
    + runDLKcat, writeDLKcatInput, assignKcatValues
    + + +

    CROSS-REFERENCE INFORMATION ^

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

    SOURCE CODE ^

    +
    0001 function kcatList = readDLKcatOutput(model, varargin)
    +0002 % readDLKcatOutput  Read the DLKcat output file into a kcatList structure.
    +0003 %
    +0004 % Reads the DLKcat output file and constructs a kcatList structure, that can
    +0005 % be used by assignKcatValues() to populate the ecModel with kcat values.
    +0006 %
    +0007 % Parameters
    +0008 % ----------
    +0009 % model : struct
    +0010 %     an ecModel in GECKO 3 format (with ecModel.ec structure).
    +0011 %
    +0012 % Name-Value Arguments
    +0013 % --------------------
    +0014 % outFile : char
    +0015 %     name and path of the DLKcat output file (default: data/DLKcat.tsv from
    +0016 %     the obj.params.path folder specified in the modelAdapter).
    +0017 % modelAdapter : ModelAdapter
    +0018 %     a loaded model adapter (default: the current default model adapter).
    +0019 %
    +0020 % Returns
    +0021 % -------
    +0022 % kcatList : struct
    +0023 %     structure array with list of DLKcat derived kcat values, with separate
    +0024 %     entries for each kcat value.
    +0025 %
    +0026 % Notes
    +0027 % -----
    +0028 % The kcatList structure has the following fields:
    +0029 %
    +0030 % - source : 'DLKcat'.
    +0031 % - rxns : reaction identifiers.
    +0032 % - genes : gene identifiers.
    +0033 % - substrates : substrate names.
    +0034 % - kcats : predicted kcat value in /sec.
    +0035 %
    +0036 % Examples
    +0037 % --------
    +0038 %     % optional arguments may be given positionally or as name-value pairs:
    +0039 %     kcatList = readDLKcatOutput(model);
    +0040 %     kcatList = readDLKcatOutput(model, 'outFile', 'myDLKcat.tsv');
    +0041 %
    +0042 % See also
    +0043 % --------
    +0044 % runDLKcat, writeDLKcatInput, assignKcatValues
    +0045 
    +0046 p = parseGECKOargs(varargin, { ...
    +0047     'outFile',      []; ...
    +0048     'modelAdapter', []});
    +0049 outFile      = p.outFile;
    +0050 modelAdapter = p.modelAdapter;
    +0051 
    +0052 if isempty(modelAdapter)
    +0053     modelAdapter = ModelAdapterManager.getDefault();
    +0054     if isempty(modelAdapter)
    +0055         error('Either send in a modelAdapter or set the default model adapter in the ModelAdapterManager.')
    +0056     end
    +0057 end
    +0058 params = modelAdapter.params;
    +0059 
    +0060 if isempty(outFile)
    +0061     fID      = fopen(fullfile(params.path,'data','DLKcat.tsv'),'r');
    +0062 else
    +0063     fID      = fopen(outFile);
    +0064 end
    +0065 DLKcatOutput = textscan(fID,'%s %s %s %s %s %s','Delimiter','\t','HeaderLines',1);
    +0066 fclose(fID);
    +0067 
    +0068 % Check that DLKcat output file and model match (not fool proof, but good enough)
    +0069 [rxns, genes, subs, kcats] = deal(DLKcatOutput{[1,2,3,6]});
    +0070 
    +0071 % Check if it contains any kcat values
    +0072 if all(cellfun(@isempty,kcats)) || all(strcmpi(kcats,'NA'))
    +0073     error('DLKcat file does not contain any kcat values, please run runDLKcat() first.')
    +0074 end
    +0075 
    +0076 % Check that all substrates are in the model (case-insensitive: an SBML loader can
    +0077 % normalise metabolite-name capitalisation differently than whatever produced the
    +0078 % DLKcat input, and that must not read as a genuinely missing substrate).
    +0079 matchMets = ismember(lower(subs),lower(model.metNames));
    +0080 if ~all(matchMets)
    +0081     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:';
    +0082     error('%s', ravenList(errorText,subs(~matchMets),false))
    +0083 end
    +0084 
    +0085 % Check that all reactions are in model.ec.rxns
    +0086 matchRxns = ismember(rxns,model.ec.rxns);
    +0087 if ~all(matchRxns)
    +0088     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:';
    +0089     error('%s', ravenList(errorText,rxns(~matchRxns),false))
    +0090 end
    +0091 
    +0092 % Filter out entries with no numeric value
    +0093 noOutput        = cellfun(@isempty,regexpi(kcats,'[0-9]'));
    +0094 kcats           = str2double(kcats(~noOutput));
    +0095 rxns(noOutput)  = [];
    +0096 genes(noOutput) = [];
    +0097 subs(noOutput)  = [];
    +0098 
    +0099 % Make kcatList structure
    +0100 kcatList.source     = 'DLKcat';
    +0101 kcatList.rxns       = rxns;
    +0102 kcatList.genes      = genes;
    +0103 kcatList.substrates = subs;
    +0104 kcatList.kcats      = kcats;
    +0105 end
    +
    Generated by m2html © 2005
    + + \ No newline at end of file diff --git a/doc/src/gather_kcats/readOpenKineticsPredictorOutput.html b/doc/src/gather_kcats/readOpenKineticsPredictorOutput.html new file mode 100644 index 00000000..42a93a28 --- /dev/null +++ b/doc/src/gather_kcats/readOpenKineticsPredictorOutput.html @@ -0,0 +1,409 @@ + + + + Description of readOpenKineticsPredictorOutput + + + + + + + + + +
    Home > src > gather_kcats > readOpenKineticsPredictorOutput.m
    + + + +

    readOpenKineticsPredictorOutput +

    + +

    PURPOSE ^

    +
    readOpenKineticsPredictorOutput Read OpenKineticsPredictor output to kcatList.
    + +

    SYNOPSIS ^

    +
    function kcatList = readOpenKineticsPredictorOutput(model, varargin)
    + +

    DESCRIPTION ^

    +
     readOpenKineticsPredictorOutput  Read OpenKineticsPredictor output to kcatList.
    +
    + Reads the OpenKineticsPredictor output file (job-*-output.csv with columns:
    + kcat (1/s), Source kcat, Extra Info kcat, Protein Sequence, Substrate) and
    + constructs a kcatList structure, that can be used by assignKcatValues() to
    + populate the ecModel with kcat values.
    +
    + CatRange predicts a class of kcat values, which OKP returns as its range
    + (for instance '10 to 100 s^-1'). It is read as the geometric midpoint of
    + the range, or half the upper bound for the class starting at 0.
    +
    + The per-entry `Source kcat` column (e.g. 'Prediction from CatPred',
    + 'BRENDA', 'Sabio-RK', 'UniProt') is preserved in kcatList.kcatSource so
    + that assignKcatValues() records the actual provenance of each value.
    +
    + Parameters
    + ----------
    + model : struct
    +     an ecModel in GECKO 3 format (with ecModel.ec structure).
    +
    + Name-Value Arguments
    + --------------------
    + outFile : char
    +     name and path of the OpenKineticsPredictor output CSV. If omitted, a
    +     file selection dialog is opened, starting in the data/ folder specified
    +     by the modelAdapter.
    + modelAdapter : ModelAdapter
    +     a loaded model adapter (default: the current default model adapter).
    +
    + Returns
    + -------
    + kcatList : struct
    +     structure array with list of kcat values from OpenKineticsPredictor,
    +     with separate entries for each kcat value.
    +
    + Notes
    + -----
    + The kcatList structure has the following fields:
    +
    + - source : 'OpenKineticsPredictor'.
    + - rxns : reaction identifiers, matching model.ec.rxns.
    + - genes : gene identifiers, matching model.ec.genes.
    + - substrates : substrate names, matching model.metNames.
    + - kcats : kcat values in /sec.
    + - similarity : the enzyme's highest sequence similarity to the method's
    +   training data, in percent (NaN without the similarity column)
    + - kcatSource : per-entry source as reported by OKP, prefixed with 'OKP-'
    +   (e.g. 'OKP-CatPred', 'OKP-BRENDA', 'OKP-Sabio-RK', 'OKP-UniProt').
    +
    + Examples
    + --------
    +     % optional arguments may be given positionally or as name-value pairs:
    +     kcatList = readOpenKineticsPredictorOutput(model);
    +     kcatList = readOpenKineticsPredictorOutput(model, 'outFile', 'job-output.csv');
    +
    + See also
    + --------
    + writeOpenKineticsPredictorInput, assignKcatValues
    + + +

    CROSS-REFERENCE INFORMATION ^

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

    SUBFUNCTIONS ^

    + + +

    SOURCE CODE ^

    +
    0001 function kcatList = readOpenKineticsPredictorOutput(model, varargin)
    +0002 % readOpenKineticsPredictorOutput  Read OpenKineticsPredictor output to kcatList.
    +0003 %
    +0004 % Reads the OpenKineticsPredictor output file (job-*-output.csv with columns:
    +0005 % kcat (1/s), Source kcat, Extra Info kcat, Protein Sequence, Substrate) and
    +0006 % constructs a kcatList structure, that can be used by assignKcatValues() to
    +0007 % populate the ecModel with kcat values.
    +0008 %
    +0009 % CatRange predicts a class of kcat values, which OKP returns as its range
    +0010 % (for instance '10 to 100 s^-1'). It is read as the geometric midpoint of
    +0011 % the range, or half the upper bound for the class starting at 0.
    +0012 %
    +0013 % The per-entry `Source kcat` column (e.g. 'Prediction from CatPred',
    +0014 % 'BRENDA', 'Sabio-RK', 'UniProt') is preserved in kcatList.kcatSource so
    +0015 % that assignKcatValues() records the actual provenance of each value.
    +0016 %
    +0017 % Parameters
    +0018 % ----------
    +0019 % model : struct
    +0020 %     an ecModel in GECKO 3 format (with ecModel.ec structure).
    +0021 %
    +0022 % Name-Value Arguments
    +0023 % --------------------
    +0024 % outFile : char
    +0025 %     name and path of the OpenKineticsPredictor output CSV. If omitted, a
    +0026 %     file selection dialog is opened, starting in the data/ folder specified
    +0027 %     by the modelAdapter.
    +0028 % modelAdapter : ModelAdapter
    +0029 %     a loaded model adapter (default: the current default model adapter).
    +0030 %
    +0031 % Returns
    +0032 % -------
    +0033 % kcatList : struct
    +0034 %     structure array with list of kcat values from OpenKineticsPredictor,
    +0035 %     with separate entries for each kcat value.
    +0036 %
    +0037 % Notes
    +0038 % -----
    +0039 % The kcatList structure has the following fields:
    +0040 %
    +0041 % - source : 'OpenKineticsPredictor'.
    +0042 % - rxns : reaction identifiers, matching model.ec.rxns.
    +0043 % - genes : gene identifiers, matching model.ec.genes.
    +0044 % - substrates : substrate names, matching model.metNames.
    +0045 % - kcats : kcat values in /sec.
    +0046 % - similarity : the enzyme's highest sequence similarity to the method's
    +0047 %   training data, in percent (NaN without the similarity column)
    +0048 % - kcatSource : per-entry source as reported by OKP, prefixed with 'OKP-'
    +0049 %   (e.g. 'OKP-CatPred', 'OKP-BRENDA', 'OKP-Sabio-RK', 'OKP-UniProt').
    +0050 %
    +0051 % Examples
    +0052 % --------
    +0053 %     % optional arguments may be given positionally or as name-value pairs:
    +0054 %     kcatList = readOpenKineticsPredictorOutput(model);
    +0055 %     kcatList = readOpenKineticsPredictorOutput(model, 'outFile', 'job-output.csv');
    +0056 %
    +0057 % See also
    +0058 % --------
    +0059 % writeOpenKineticsPredictorInput, assignKcatValues
    +0060 
    +0061 p = parseGECKOargs(varargin, { ...
    +0062     'outFile',      []; ...
    +0063     'modelAdapter', []});
    +0064 outFile      = p.outFile;
    +0065 modelAdapter = p.modelAdapter;
    +0066 
    +0067 if isempty(modelAdapter)
    +0068     modelAdapter = ModelAdapterManager.getDefault();
    +0069     if isempty(modelAdapter)
    +0070         error('Either send in a modelAdapter or set the default model adapter in the ModelAdapterManager.')
    +0071     end
    +0072 end
    +0073 params = modelAdapter.params;
    +0074 
    +0075 if isempty(outFile)
    +0076     startDir = fullfile(params.path,'data');
    +0077     if ~exist(startDir,'dir')
    +0078         startDir = params.path;
    +0079     end
    +0080     [fName, fPath] = uigetfile({'*.csv','OpenKineticsPredictor output (*.csv)'; ...
    +0081                                 '*.*','All files (*.*)'}, ...
    +0082                                'Select OpenKineticsPredictor output file', ...
    +0083                                fullfile(startDir, filesep));
    +0084     if isequal(fName,0)
    +0085         error('No file selected.')
    +0086     end
    +0087     outFile = fullfile(fPath, fName);
    +0088 end
    +0089 
    +0090 %% Read OKP output file using readcell to correctly handle quoted fields
    +0091 % that may contain commas in the 'Extra Info kcat' column.
    +0092 if ~exist(outFile,'file')
    +0093     error('Cannot find file: %s', outFile)
    +0094 end
    +0095 raw = readcell(outFile, 'Delimiter', ',', 'TextType', 'char');
    +0096 
    +0097 if size(raw,2) < 5
    +0098     error('OKP output file does not have the expected 5 columns (kcat, Source kcat, Extra Info kcat, Protein Sequence, Substrate): %s', outFile)
    +0099 end
    +0100 
    +0101 % Drop header row; the 'max similarity to <method> training data' column,
    +0102 % when present, gives the similarity.
    +0103 header = cellfun(@(h) char(string(h)), raw(1,:), 'UniformOutput', false);
    +0104 simCol = find(startsWith(header, 'max similarity to'), 1);
    +0105 raw = raw(2:end, :);
    +0106 similarity = nan(size(raw, 1), 1);
    +0107 if ~isempty(simCol)
    +0108     for i = 1:size(raw, 1)
    +0109         v = raw{i, simCol};
    +0110         if isnumeric(v) && ~isempty(v)
    +0111             similarity(i) = v;
    +0112         elseif ischar(v) || isstring(v)
    +0113             similarity(i) = str2double(v);
    +0114         end
    +0115     end
    +0116 end
    +0117 
    +0118 kcatsCol      = raw(:,1);
    +0119 sourceKcatCol = raw(:,2);
    +0120 sequences     = raw(:,4);
    +0121 smiles        = raw(:,5);
    +0122 
    +0123 % Normalize types: readcell returns doubles for numeric cells, char for
    +0124 % strings, and `missing` for empty fields.
    +0125 kcats = nan(size(kcatsCol));
    +0126 for i = 1:numel(kcatsCol)
    +0127     v = kcatsCol{i};
    +0128     if isnumeric(v)
    +0129         kcats(i) = v;
    +0130     elseif ischar(v) || isstring(v)
    +0131         kcats(i) = kcatFromText(char(v));
    +0132     end
    +0133 end
    +0134 
    +0135 sourceKcatCol = normalizeCellStrings(sourceKcatCol);
    +0136 sequences     = normalizeCellStrings(sequences);
    +0137 smiles        = normalizeCellStrings(smiles);
    +0138 
    +0139 %% Filter out entries with no numeric kcat value (NaN). Zero values are
    +0140 % retained here and filtered downstream by assignKcatValues.
    +0141 valid = ~isnan(kcats);
    +0142 kcats         = kcats(valid);
    +0143 sequences     = sequences(valid);
    +0144 smiles        = smiles(valid);
    +0145 sourceKcatCol = sourceKcatCol(valid);
    +0146 similarity    = similarity(valid);
    +0147 
    +0148 if isempty(kcats)
    +0149     error('OKP file does not contain any numeric kcat values. Run the job at https://predictor.openkinetics.org/ first.')
    +0150 end
    +0151 
    +0152 if ~isfield(model,'metSmiles')
    +0153     error('model.metSmiles is required to map SMILES back to metabolites.')
    +0154 end
    +0155 
    +0156 %% Build ec.rxns -> model.rxns index mapping (inverse of the mapping done
    +0157 %  in writeOpenKineticsPredictorInput)
    +0158 if model.ec.geckoLight
    +0159     origRxns = extractAfter(model.ec.rxns, 4);
    +0160 else
    +0161     origRxns = model.ec.rxns;
    +0162 end
    +0163 [foundEcRxn, ecRxnToModelRxn] = ismember(origRxns, model.rxns);
    +0164 if ~all(foundEcRxn)
    +0165     error('Not all entries in model.ec.rxns could be matched to model.rxns.')
    +0166 end
    +0167 
    +0168 %% Resolve each row to matching ec.rxns indices
    +0169 rxnsOut       = cell(0,1);
    +0170 genesOut      = cell(0,1);
    +0171 substratesOut = cell(0,1);
    +0172 kcatsOut      = zeros(0,1);
    +0173 sourceOut     = cell(0,1);
    +0174 similarityOut = zeros(0,1);
    +0175 unmatched     = 0;
    +0176 
    +0177 for i = 1:numel(sequences)
    +0178     % Map protein sequence -> ec.genes indices (columns of rxnEnzMat)
    +0179     proteinIdxs = find(strcmp(model.ec.sequence, sequences{i}));
    +0180     % Map SMILES -> metabolite indices (rows of model.S)
    +0181     metIdxs = find(strcmp(model.metSmiles, smiles{i}));
    +0182 
    +0183     if isempty(proteinIdxs) || isempty(metIdxs)
    +0184         unmatched = unmatched + 1;
    +0185         continue
    +0186     end
    +0187 
    +0188     % model.rxns columns where any of these mets are substrates (S < 0)
    +0189     modelRxnsUsingSub = any(model.S(metIdxs, :) < 0, 1);
    +0190 
    +0191     % Lift to ec.rxns: does the underlying model.rxn consume this metabolite?
    +0192     ecRxnUsesSub = modelRxnsUsingSub(ecRxnToModelRxn).';
    +0193 
    +0194     % ec.rxns catalyzed by any of these protein(s)
    +0195     ecRxnCatalyzed = any(model.ec.rxnEnzMat(:, proteinIdxs) ~= 0, 2);
    +0196 
    +0197     candidateEcRxns = find(ecRxnUsesSub & ecRxnCatalyzed);
    +0198 
    +0199     if isempty(candidateEcRxns)
    +0200         unmatched = unmatched + 1;
    +0201         continue
    +0202     end
    +0203 
    +0204     for k = 1:numel(candidateEcRxns)
    +0205         ecIdx = candidateEcRxns(k);
    +0206 
    +0207         % Pick the gene whose protein both matches this sequence and
    +0208         % catalyzes this ec.rxn
    +0209         catalysts       = find(model.ec.rxnEnzMat(ecIdx, :) ~= 0);
    +0210         matchingProtein = intersect(proteinIdxs, catalysts, 'stable');
    +0211         if ~isempty(matchingProtein)
    +0212             geneName = model.ec.genes{matchingProtein(1)};
    +0213         else
    +0214             geneName = '';
    +0215         end
    +0216 
    +0217         % Pick a metabolite name whose SMILES matches and that is a
    +0218         % substrate of the underlying model.rxn
    +0219         origRxnIdx       = ecRxnToModelRxn(ecIdx);
    +0220         metIsSub         = model.S(metIdxs, origRxnIdx) < 0;
    +0221         substrateMetIdxs = metIdxs(metIsSub);
    +0222         if ~isempty(substrateMetIdxs)
    +0223             subName = model.metNames{substrateMetIdxs(1)};
    +0224         else
    +0225             subName = '';
    +0226         end
    +0227 
    +0228         rxnsOut{end+1,1}       = model.ec.rxns{ecIdx};
    +0229         genesOut{end+1,1}      = geneName;
    +0230         substratesOut{end+1,1} = subName;
    +0231         kcatsOut(end+1,1)      = kcats(i);
    +0232         sourceOut{end+1,1}     = sourceKcatCol{i};
    +0233         similarityOut(end+1,1) = similarity(i);
    +0234     end
    +0235 end
    +0236 
    +0237 if unmatched > 0
    +0238     warning('%d of %d OKP entries could not be matched to an ec.rxn (protein sequence and/or SMILES not found in model, or no enzyme+substrate pair matches).', ...
    +0239         unmatched, numel(sequences));
    +0240 end
    +0241 
    +0242 if isempty(rxnsOut)
    +0243     error('No OKP entries could be mapped to model.ec.rxns.')
    +0244 end
    +0245 
    +0246 %% Build per-entry source labels
    +0247 % Strip leading 'Prediction from ' to keep labels compact, then prefix all
    +0248 % with 'OKP-' so the overall pipeline stage is still identifiable in
    +0249 % model.ec.source.
    +0250 kcatSource = regexprep(sourceOut, '^Prediction from\s+', '');
    +0251 kcatSource = strcat('OKP-', kcatSource);
    +0252 
    +0253 %% Make kcatList structure
    +0254 kcatList.source     = 'OpenKineticsPredictor';
    +0255 kcatList.rxns       = rxnsOut;
    +0256 kcatList.genes      = genesOut;
    +0257 kcatList.substrates = substratesOut;
    +0258 kcatList.kcats      = kcatsOut;
    +0259 kcatList.kcatSource = kcatSource;
    +0260 kcatList.similarity = similarityOut;
    +0261 end
    +0262 
    +0263 function c = normalizeCellStrings(c)
    +0264 % Convert each cell entry to a char row vector; missing/empty -> ''.
    +0265 for i = 1:numel(c)
    +0266     v = c{i};
    +0267     if ismissing(v)
    +0268         c{i} = '';
    +0269     elseif isstring(v)
    +0270         c{i} = char(v);
    +0271     elseif isnumeric(v)
    +0272         if isnan(v)
    +0273             c{i} = '';
    +0274         else
    +0275             c{i} = num2str(v);
    +0276         end
    +0277     elseif ~ischar(v)
    +0278         c{i} = char(string(v));
    +0279     end
    +0280 end
    +0281 end
    +0282 
    +0283 function kcat = kcatFromText(v)
    +0284 % A number, or a CatRange class range '<low> to <high> s^-1' as its
    +0285 % geometric midpoint (half the upper bound when the class starts at 0).
    +0286 kcat = str2double(v);
    +0287 if ~isnan(kcat)
    +0288     return
    +0289 end
    +0290 bounds = regexp(strtrim(v), '^([0-9.eE+-]+)\s+to\s+([0-9.eE+-]+)(\s*s\^-1)?$', 'tokens', 'once');
    +0291 if isempty(bounds)
    +0292     return
    +0293 end
    +0294 low = str2double(bounds{1});
    +0295 high = str2double(bounds{2});
    +0296 if isnan(low) || isnan(high)
    +0297     return
    +0298 elseif low > 0
    +0299     kcat = sqrt(low * high);
    +0300 else
    +0301     kcat = high / 2;
    +0302 end
    +0303 end
    +
    Generated by m2html © 2005
    + + \ No newline at end of file diff --git a/doc/src/gather_kcats/removeStandardKcat.html b/doc/src/gather_kcats/removeStandardKcat.html new file mode 100644 index 00000000..8d64a4c9 --- /dev/null +++ b/doc/src/gather_kcats/removeStandardKcat.html @@ -0,0 +1,143 @@ + + + + Description of removeStandardKcat + + + + + + + + + +
    Home > src > gather_kcats > removeStandardKcat.m
    + + + +

    removeStandardKcat +

    + +

    PURPOSE ^

    +
    removeStandardKcat Remove the standard pseudoenzyme and standard kcats.
    + +

    SYNOPSIS ^

    +
    function model = removeStandardKcat(model)
    + +

    DESCRIPTION ^

    +
     removeStandardKcat  Remove the standard pseudoenzyme and standard kcats.
    +
    + Removes the "standard" pseudoenzyme and standard kcat and MW values, as
    + they were introduced by getStandardKcat. Also standard kcat values that
    + were assigned by getStandardKcat if fillZeroKcat was set to true are
    + removed from model.ec.kcat. Both the model.ec and model.S structures are
    + modified.
    +
    + Parameters
    + ----------
    + model : struct
    +     an ecModel in GECKO 3 format (with ecModel.ec structure) that has
    +     standard kcat values implemented by getStandardKcat.
    +
    + Returns
    + -------
    + model : struct
    +     ecModel without standard pseudoprotein and standard kcat values.
    +
    + Examples
    + --------
    +     model = removeStandardKcat(model);
    +
    + See also
    + --------
    + getStandardKcat, applyKcatConstraints
    + + +

    CROSS-REFERENCE INFORMATION ^

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

    SOURCE CODE ^

    +
    0001 function model = removeStandardKcat(model)
    +0002 % removeStandardKcat  Remove the standard pseudoenzyme and standard kcats.
    +0003 %
    +0004 % Removes the "standard" pseudoenzyme and standard kcat and MW values, as
    +0005 % they were introduced by getStandardKcat. Also standard kcat values that
    +0006 % were assigned by getStandardKcat if fillZeroKcat was set to true are
    +0007 % removed from model.ec.kcat. Both the model.ec and model.S structures are
    +0008 % modified.
    +0009 %
    +0010 % Parameters
    +0011 % ----------
    +0012 % model : struct
    +0013 %     an ecModel in GECKO 3 format (with ecModel.ec structure) that has
    +0014 %     standard kcat values implemented by getStandardKcat.
    +0015 %
    +0016 % Returns
    +0017 % -------
    +0018 % model : struct
    +0019 %     ecModel without standard pseudoprotein and standard kcat values.
    +0020 %
    +0021 % Examples
    +0022 % --------
    +0023 %     model = removeStandardKcat(model);
    +0024 %
    +0025 % See also
    +0026 % --------
    +0027 % getStandardKcat, applyKcatConstraints
    +0028 
    +0029 % Remove standard enzyme from ec structure
    +0030 stdEnzIdx = find(strcmpi(model.ec.enzymes, 'standard'));
    +0031 if ~isempty(stdEnzIdx)
    +0032     model.ec.genes(stdEnzIdx)       = [];
    +0033     model.ec.enzymes(stdEnzIdx)     = [];
    +0034     model.ec.mw(stdEnzIdx)          = [];
    +0035     model.ec.sequence(stdEnzIdx)    = [];
    +0036     if isfield(model.ec,'concs')
    +0037         model.ec.concs(stdEnzIdx)   = [];
    +0038     end
    +0039     rxnEnzIdx = find(model.ec.rxnEnzMat(:,stdEnzIdx));
    +0040     model.ec.rxns(rxnEnzIdx)        = [];
    +0041     model.ec.kcat(rxnEnzIdx)        = [];
    +0042     model.ec.source(rxnEnzIdx)      = [];
    +0043     model.ec.notes(rxnEnzIdx)       = [];
    +0044     model.ec.eccodes(rxnEnzIdx)     = [];
    +0045     model.ec.rxnEnzMat(:,stdEnzIdx) = [];
    +0046     model.ec.rxnEnzMat(rxnEnzIdx,:) = [];
    +0047 end
    +0048 
    +0049 % Remove standard kcat values and reapply kcat constraints for those
    +0050 % specific reactions
    +0051 stdKcatIdx = find(strcmpi(model.ec.source, 'standard'));
    +0052 if ~isempty(stdKcatIdx)
    +0053     model.ec.source(stdKcatIdx)     = {''};
    +0054     model.ec.kcat(stdKcatIdx)       = 0;
    +0055     model = applyKcatConstraints(model,stdKcatIdx);
    +0056 end
    +0057 
    +0058 % Remove standard protein, usage and gene from model structure
    +0059 stdMetIdx = find(strcmpi(model.mets, 'prot_standard'));
    +0060 if ~isempty(stdMetIdx)
    +0061     model       = removeMets(model,stdMetIdx,false,false,false,false);
    +0062 end
    +0063 stdProtEx = find(strcmpi(model.rxns, 'usage_prot_standard'));
    +0064 if ~isempty(stdProtEx)
    +0065     model       = removeReactions(model,stdProtEx,false,false,false);
    +0066 end
    +0067 stdProtGene = find(strcmpi(model.genes, 'standard'));
    +0068 if ~isempty(stdProtGene)
    +0069     model       = removeGenes(model,stdProtGene,false,false,false);
    +0070 end
    +0071 end
    +
    Generated by m2html © 2005
    + + \ No newline at end of file diff --git a/doc/src/gather_kcats/resolveOkpApiKey.html b/doc/src/gather_kcats/resolveOkpApiKey.html new file mode 100644 index 00000000..7a35b449 --- /dev/null +++ b/doc/src/gather_kcats/resolveOkpApiKey.html @@ -0,0 +1,120 @@ + + + + Description of resolveOkpApiKey + + + + + + + + + +
    Home > src > gather_kcats > resolveOkpApiKey.m
    + + + +

    resolveOkpApiKey +

    + +

    PURPOSE ^

    +
    resolveOkpApiKey Resolve the OpenKineticsPredictor API key.
    + +

    SYNOPSIS ^

    +
    function key = resolveOkpApiKey(argKey, basePath)
    + +

    DESCRIPTION ^

    +
     resolveOkpApiKey  Resolve the OpenKineticsPredictor API key.
    +
    + Internal helper shared by submitOpenKineticsPredictor and
    + fetchOpenKineticsPredictor; not intended to be called directly.
    +
    + Checked in order: the argKey input, the OKP_API_KEY environment variable,
    + then a plain-text file data/okpApiKey.txt under basePath (this name is
    + git-ignored by GECKO). The key is a secret and must never be read from the
    + model adapter, which is shared/committed.
    +
    + Parameters
    + ----------
    + argKey : char
    +     an explicitly provided key, or empty to fall through to the
    +     environment variable / file.
    + basePath : char
    +     the model adapter's params.path, under which data/okpApiKey.txt is
    +     looked up.
    +
    + Returns
    + -------
    + key : char
    +     the resolved API key.
    +
    + See also
    + --------
    + submitOpenKineticsPredictor, fetchOpenKineticsPredictor
    + + +

    CROSS-REFERENCE INFORMATION ^

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

    SOURCE CODE ^

    +
    0001 function key = resolveOkpApiKey(argKey, basePath)
    +0002 % resolveOkpApiKey  Resolve the OpenKineticsPredictor API key.
    +0003 %
    +0004 % Internal helper shared by submitOpenKineticsPredictor and
    +0005 % fetchOpenKineticsPredictor; not intended to be called directly.
    +0006 %
    +0007 % Checked in order: the argKey input, the OKP_API_KEY environment variable,
    +0008 % then a plain-text file data/okpApiKey.txt under basePath (this name is
    +0009 % git-ignored by GECKO). The key is a secret and must never be read from the
    +0010 % model adapter, which is shared/committed.
    +0011 %
    +0012 % Parameters
    +0013 % ----------
    +0014 % argKey : char
    +0015 %     an explicitly provided key, or empty to fall through to the
    +0016 %     environment variable / file.
    +0017 % basePath : char
    +0018 %     the model adapter's params.path, under which data/okpApiKey.txt is
    +0019 %     looked up.
    +0020 %
    +0021 % Returns
    +0022 % -------
    +0023 % key : char
    +0024 %     the resolved API key.
    +0025 %
    +0026 % See also
    +0027 % --------
    +0028 % submitOpenKineticsPredictor, fetchOpenKineticsPredictor
    +0029 
    +0030 if ~isempty(argKey)
    +0031     key = strtrim(char(argKey));
    +0032     return
    +0033 end
    +0034 envKey = getenv('OKP_API_KEY');
    +0035 if ~isempty(envKey)
    +0036     key = strtrim(envKey);
    +0037     return
    +0038 end
    +0039 keyFile = fullfile(basePath,'data','okpApiKey.txt');
    +0040 if exist(keyFile,'file')
    +0041     key = strtrim(fileread(keyFile));
    +0042     return
    +0043 end
    +0044 error(['No OpenKineticsPredictor API key found. Provide it as the apiKey ' ...
    +0045        'argument, set the OKP_API_KEY environment variable, or place it in ' ...
    +0046        '%s. Generate a key at https://predictor.openkinetics.org/.'], keyFile);
    +0047 end
    +
    Generated by m2html © 2005
    + + \ No newline at end of file diff --git a/doc/src/gather_kcats/reviewKcatAssignment.html b/doc/src/gather_kcats/reviewKcatAssignment.html new file mode 100644 index 00000000..ac356f8d --- /dev/null +++ b/doc/src/gather_kcats/reviewKcatAssignment.html @@ -0,0 +1,396 @@ + + + + Description of reviewKcatAssignment + + + + + + + + + +
    Home > src > gather_kcats > reviewKcatAssignment.m
    + + + +

    reviewKcatAssignment +

    + +

    PURPOSE ^

    +
    reviewKcatAssignment Flag kcat assignments that deserve a second look.
    + +

    SYNOPSIS ^

    +
    function findings = reviewKcatAssignment(rxnIds,kcats,sources,ecCodes,varargin)
    + +

    DESCRIPTION ^

    +
     reviewKcatAssignment  Flag kcat assignments that deserve a second look.
    +
    + A tuner's largest corrections are rarely discoveries about biology.
    + They are places the assignment went wrong: a value derived from one
    + specific-activity measurement, a database maximum standing in for a
    + distribution with a two-hundred-fold spread, one fallback number reused
    + across a whole family of reactions. Finding those directly is cheaper
    + than inferring them from a fit, and a corrected prior propagates to
    + every model built from the same databases, where a tuned kcat stays in
    + the model it was tuned on.
    +
    + Two design choices, both from measurement rather than taste (see
    + geckopy's gather_kcats/review.py, which this ports):
    +
    + Rank by leverage, and cut the report there. Tightening the checks
    + themselves does not shorten a report nearly as well, because looking
    + odd and mattering are unrelated properties. Filtering by leverage keeps
    + the list short and keeps the entries worth a curator's time.
    +
    + Report a parameter once. Isozyme copies the assignment could not
    + separate share a value and a source, so they share a finding; listing
    + them separately fills the report with duplicates of one decision.
    +
    + Parameters
    + ----------
    + rxnIds, kcats, sources, ecCodes : cell/double
    +     ec.rxns, ec.kcat, ec.source, ec.eccodes (or the equivalent
    +     subset), all the same length.
    +
    + Name-Value Arguments
    + --------------------
    + ecStats : containers.Map
    +     EC code -> struct(nKcat,kcatMax,kcatMedian,values,nSa), as returned
    +     by ecStatsFromBrenda. Checks needing it are skipped when it is
    +     absent, so this still runs without a database.
    + enzymes : cell
    +     protein ids per kcat (cell of cell arrays), used to count how many
    +     other reactions share an enzyme.
    + names : cell
    +     reaction names, same length as rxnIds (default: not shown).
    + leverage : double
    +     per-kcat effect on the distance from a one-at-a-time screen (e.g.
    +     screenKcatLeverage's leverage column, expanded back to
    +     ecModel.ec.rxns positions). Without it findings cannot be ranked
    +     and are returned in input order.
    + slow, fast : double
    +     magnitude check bounds (default 1e-2, 1e4).
    + ecMaxGap : double
    +     how many times the EC median a value must exceed, while sitting
    +     exactly at the EC max, to flag as ec-maximum (default 3.0).
    + repeatMin : double
    +     how many distinct reactions must share one kcat value to flag as
    +     repeated-value (default 5).
    + include : cell
    +     names from {'standard-fallback','tied-isozymes'} to report as well
    +     (default: neither -- both are deliberate choices, not mistakes, so
    +     stay quiet unless asked for).
    + coverage : double
    +     truncate the report to the rows carrying this share of the
    +     *flagged* leverage (default: no truncation).
    + top : double
    +     truncate the report to this many rows (default: no truncation).
    +
    + Returns
    + -------
    + findings : table
    +     one row per free parameter: rxnId, name, ecCode, source, kcat,
    +     leverage, nIsozymes, otherReactions, checks (comma-joined string),
    +     detail. Write to TSV with e.g.
    +         writetable(findings,'findings.tsv','FileType','text','Delimiter','\t')
    +
    + See also
    + --------
    + ecStatsFromBrenda, isozymeTieMap, screenKcatLeverage
    + + +

    CROSS-REFERENCE INFORMATION ^

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

    SUBFUNCTIONS ^

    + + +

    SOURCE CODE ^

    +
    0001 function findings = reviewKcatAssignment(rxnIds,kcats,sources,ecCodes,varargin)
    +0002 % reviewKcatAssignment  Flag kcat assignments that deserve a second look.
    +0003 %
    +0004 % A tuner's largest corrections are rarely discoveries about biology.
    +0005 % They are places the assignment went wrong: a value derived from one
    +0006 % specific-activity measurement, a database maximum standing in for a
    +0007 % distribution with a two-hundred-fold spread, one fallback number reused
    +0008 % across a whole family of reactions. Finding those directly is cheaper
    +0009 % than inferring them from a fit, and a corrected prior propagates to
    +0010 % every model built from the same databases, where a tuned kcat stays in
    +0011 % the model it was tuned on.
    +0012 %
    +0013 % Two design choices, both from measurement rather than taste (see
    +0014 % geckopy's gather_kcats/review.py, which this ports):
    +0015 %
    +0016 % Rank by leverage, and cut the report there. Tightening the checks
    +0017 % themselves does not shorten a report nearly as well, because looking
    +0018 % odd and mattering are unrelated properties. Filtering by leverage keeps
    +0019 % the list short and keeps the entries worth a curator's time.
    +0020 %
    +0021 % Report a parameter once. Isozyme copies the assignment could not
    +0022 % separate share a value and a source, so they share a finding; listing
    +0023 % them separately fills the report with duplicates of one decision.
    +0024 %
    +0025 % Parameters
    +0026 % ----------
    +0027 % rxnIds, kcats, sources, ecCodes : cell/double
    +0028 %     ec.rxns, ec.kcat, ec.source, ec.eccodes (or the equivalent
    +0029 %     subset), all the same length.
    +0030 %
    +0031 % Name-Value Arguments
    +0032 % --------------------
    +0033 % ecStats : containers.Map
    +0034 %     EC code -> struct(nKcat,kcatMax,kcatMedian,values,nSa), as returned
    +0035 %     by ecStatsFromBrenda. Checks needing it are skipped when it is
    +0036 %     absent, so this still runs without a database.
    +0037 % enzymes : cell
    +0038 %     protein ids per kcat (cell of cell arrays), used to count how many
    +0039 %     other reactions share an enzyme.
    +0040 % names : cell
    +0041 %     reaction names, same length as rxnIds (default: not shown).
    +0042 % leverage : double
    +0043 %     per-kcat effect on the distance from a one-at-a-time screen (e.g.
    +0044 %     screenKcatLeverage's leverage column, expanded back to
    +0045 %     ecModel.ec.rxns positions). Without it findings cannot be ranked
    +0046 %     and are returned in input order.
    +0047 % slow, fast : double
    +0048 %     magnitude check bounds (default 1e-2, 1e4).
    +0049 % ecMaxGap : double
    +0050 %     how many times the EC median a value must exceed, while sitting
    +0051 %     exactly at the EC max, to flag as ec-maximum (default 3.0).
    +0052 % repeatMin : double
    +0053 %     how many distinct reactions must share one kcat value to flag as
    +0054 %     repeated-value (default 5).
    +0055 % include : cell
    +0056 %     names from {'standard-fallback','tied-isozymes'} to report as well
    +0057 %     (default: neither -- both are deliberate choices, not mistakes, so
    +0058 %     stay quiet unless asked for).
    +0059 % coverage : double
    +0060 %     truncate the report to the rows carrying this share of the
    +0061 %     *flagged* leverage (default: no truncation).
    +0062 % top : double
    +0063 %     truncate the report to this many rows (default: no truncation).
    +0064 %
    +0065 % Returns
    +0066 % -------
    +0067 % findings : table
    +0068 %     one row per free parameter: rxnId, name, ecCode, source, kcat,
    +0069 %     leverage, nIsozymes, otherReactions, checks (comma-joined string),
    +0070 %     detail. Write to TSV with e.g.
    +0071 %         writetable(findings,'findings.tsv','FileType','text','Delimiter','\t')
    +0072 %
    +0073 % See also
    +0074 % --------
    +0075 % ecStatsFromBrenda, isozymeTieMap, screenKcatLeverage
    +0076 p = parseGECKOargs(varargin, { ...
    +0077     'ecStats', containers.Map('KeyType','char','ValueType','any'); ...
    +0078     'enzymes', {}; ...
    +0079     'names', {}; ...
    +0080     'leverage', []; ...
    +0081     'slow', 1e-2; ...
    +0082     'fast', 1e4; ...
    +0083     'ecMaxGap', 3.0; ...
    +0084     'repeatMin', 5; ...
    +0085     'include', {}; ...
    +0086     'coverage', []; ...
    +0087     'top', []});
    +0088 ecStats   = p.ecStats;
    +0089 enzymes   = p.enzymes;
    +0090 names     = p.names;
    +0091 leverage  = p.leverage;
    +0092 slow      = p.slow;
    +0093 fast      = p.fast;
    +0094 ecMaxGap  = p.ecMaxGap;
    +0095 repeatMin = p.repeatMin;
    +0096 include   = p.include;
    +0097 coverage  = p.coverage;
    +0098 top       = p.top;
    +0099 
    +0100 kcats = kcats(:);
    +0101 n = numel(kcats);
    +0102 if numel(rxnIds) ~= n || numel(sources) ~= n || numel(ecCodes) ~= n
    +0103     error('rxnIds, sources and ecCodes must all have %d entries, matching kcats.', n)
    +0104 end
    +0105 if isempty(leverage)
    +0106     lev = zeros(n,1);
    +0107 else
    +0108     lev = leverage(:);
    +0109 end
    +0110 
    +0111 tie = isozymeTieMap(rxnIds,kcats,'sources',sources);
    +0112 reps = unique(tie);
    +0113 memberLists = cell(numel(reps),1);
    +0114 for r = 1:numel(reps)
    +0115     memberLists{r} = find(tie == reps(r));
    +0116 end
    +0117 
    +0118 % A value reused across many distinct reactions is a fallback wearing a
    +0119 % measurement's label, whatever its source says.
    +0120 reuseMap = containers.Map('KeyType','char','ValueType','any');
    +0121 for i = 1:n
    +0122     key = reuseKey(kcats(i));
    +0123     base = baseReactionLocal(rxnIds{i});
    +0124     if isKey(reuseMap,key)
    +0125         reuseMap(key) = union(reuseMap(key), {base});
    +0126     else
    +0127         reuseMap(key) = {base};
    +0128     end
    +0129 end
    +0130 
    +0131 enzymeRxns = containers.Map('KeyType','char','ValueType','any');
    +0132 if ~isempty(enzymes)
    +0133     for i = 1:n
    +0134         for e = 1:numel(enzymes{i})
    +0135             prot = char(enzymes{i}{e});
    +0136             base = baseReactionLocal(rxnIds{i});
    +0137             if isKey(enzymeRxns,prot)
    +0138                 enzymeRxns(prot) = union(enzymeRxns(prot), {base});
    +0139             else
    +0140                 enzymeRxns(prot) = {base};
    +0141             end
    +0142         end
    +0143     end
    +0144 end
    +0145 
    +0146 rxnIdOut=[]; nameOut=[]; ecOut=[]; sourceOut=[]; kcatOut=[]; leverageOut=[];
    +0147 nIsoOut=[]; otherOut=[]; checksOut=[]; detailOut=[];
    +0148 
    +0149 for r = 1:numel(reps)
    +0150     idx = memberLists{r};
    +0151     i = idx(1);
    +0152     ec = firstEc(ecCodes{i});
    +0153     st = [];
    +0154     if isKey(ecStats,ec)
    +0155         st = ecStats(ec);
    +0156     end
    +0157     checks = {}; detail = {};
    +0158 
    +0159     if ~isempty(st) && st.nKcat == 0
    +0160         checks{end+1} = 'no-ec-evidence'; %#ok<AGROW>
    +0161         if st.nSa > 0
    +0162             detail{end+1} = sprintf('no kcat rows for EC %s; %d specific-activity rows instead', ec, st.nSa); %#ok<AGROW>
    +0163         else
    +0164             detail{end+1} = sprintf('no kcat rows for EC %s', ec); %#ok<AGROW>
    +0165         end
    +0166     end
    +0167     key = reuseKey(kcats(i));
    +0168     if isKey(reuseMap,key) && numel(reuseMap(key)) >= repeatMin
    +0169         checks{end+1} = 'repeated-value'; %#ok<AGROW>
    +0170         detail{end+1} = sprintf('%g 1/s reused across %d reactions', kcats(i), numel(reuseMap(key))); %#ok<AGROW>
    +0171     end
    +0172     if ~isempty(st) && st.nKcat > 0 && isfinite(st.kcatMedian) && st.kcatMedian > 0 ...
    +0173             && abs(kcats(i)-st.kcatMax) <= 1e-9*max(kcats(i),1) && st.kcatMax/st.kcatMedian > ecMaxGap
    +0174         checks{end+1} = 'ec-maximum'; %#ok<AGROW>
    +0175         detail{end+1} = sprintf('took the EC maximum, %.0fx its median over %d rows', st.kcatMax/st.kcatMedian, st.nKcat); %#ok<AGROW>
    +0176     end
    +0177     if kcats(i) < slow || kcats(i) > fast
    +0178         checks{end+1} = 'magnitude'; %#ok<AGROW>
    +0179         detail{end+1} = sprintf('%g 1/s is outside %g-%g', kcats(i), slow, fast); %#ok<AGROW>
    +0180     end
    +0181     if strcmpi(sources{i},'custom') && ~isempty(st) && ismember(round(kcats(i),6), st.values)
    +0182         checks{end+1} = 'custom-duplicate'; %#ok<AGROW>
    +0183         detail{end+1} = 'custom value equals a database value for its own EC'; %#ok<AGROW>
    +0184     end
    +0185     if numel(idx) > 1
    +0186         if ismember('tied-isozymes',include)
    +0187             checks{end+1} = 'tied-isozymes'; %#ok<AGROW>
    +0188         end
    +0189         detail{end+1} = sprintf('%d isozyme copies share this value', numel(idx)); %#ok<AGROW>
    +0190     end
    +0191     if strcmpi(sources{i},'standard')
    +0192         if ~ismember('standard-fallback',include)
    +0193             continue
    +0194         end
    +0195         checks{end+1} = 'standard-fallback'; %#ok<AGROW>
    +0196         detail{end+1} = 'the model''s fallback value, not a measurement'; %#ok<AGROW>
    +0197     end
    +0198 
    +0199     if isempty(checks)
    +0200         continue
    +0201     end
    +0202     others = {};
    +0203     if ~isempty(enzymes)
    +0204         for e = 1:numel(enzymes{i})
    +0205             prot = char(enzymes{i}{e});
    +0206             if isKey(enzymeRxns,prot)
    +0207                 others = union(others, enzymeRxns(prot));
    +0208             end
    +0209         end
    +0210     end
    +0211     others = setdiff(others, {baseReactionLocal(rxnIds{i})});
    +0212 
    +0213     rxnIdOut{end+1,1}   = rxnIds{i}; %#ok<AGROW>
    +0214     if isempty(names)
    +0215         nameOut{end+1,1} = ''; %#ok<AGROW>
    +0216     else
    +0217         nameOut{end+1,1} = names{i}; %#ok<AGROW>
    +0218     end
    +0219     ecOut{end+1,1}       = ec; %#ok<AGROW>
    +0220     sourceOut{end+1,1}   = sources{i}; %#ok<AGROW>
    +0221     kcatOut(end+1,1)     = kcats(i); %#ok<AGROW>
    +0222     leverageOut(end+1,1) = max(lev(idx)); %#ok<AGROW>
    +0223     nIsoOut(end+1,1)     = numel(idx); %#ok<AGROW>
    +0224     otherOut(end+1,1)    = numel(others); %#ok<AGROW>
    +0225     checksOut{end+1,1}   = strjoin(checks,','); %#ok<AGROW>
    +0226     detailOut{end+1,1}   = strjoin(detail,'; '); %#ok<AGROW>
    +0227 end
    +0228 
    +0229 if isempty(rxnIdOut)
    +0230     findings = table(cell(0,1),cell(0,1),cell(0,1),cell(0,1),zeros(0,1),zeros(0,1), ...
    +0231         zeros(0,1),zeros(0,1),cell(0,1),cell(0,1), 'VariableNames', ...
    +0232         {'rxnId','name','ecCode','source','kcat','leverage','nIsozymes','otherReactions','checks','detail'});
    +0233     return
    +0234 end
    +0235 
    +0236 findings = table(rxnIdOut,nameOut,ecOut,sourceOut,kcatOut,leverageOut,nIsoOut,otherOut,checksOut,detailOut, ...
    +0237     'VariableNames',{'rxnId','name','ecCode','source','kcat','leverage','nIsozymes','otherReactions','checks','detail'});
    +0238 findings = sortrows(findings,'leverage','descend');
    +0239 
    +0240 flaggedTotal = sum(findings.leverage);
    +0241 if ~isempty(coverage) && flaggedTotal > 0
    +0242     acc = cumsum(findings.leverage);
    +0243     keepN = find(acc/flaggedTotal >= coverage, 1, 'first');
    +0244     if isempty(keepN)
    +0245         keepN = height(findings);
    +0246     end
    +0247     findings = findings(1:keepN,:);
    +0248 end
    +0249 if ~isempty(top)
    +0250     findings = findings(1:min(top,height(findings)),:);
    +0251 end
    +0252 end
    +0253 
    +0254 function key = reuseKey(kcat)
    +0255 if kcat > 0
    +0256     key = sprintf('%.9f', round(log(kcat),9));
    +0257 else
    +0258     key = 'NONE';
    +0259 end
    +0260 end
    +0261 
    +0262 function ec = firstEc(ecCode)
    +0263 parts = strsplit(char(ecCode), ';');
    +0264 ec = strtrim(parts{1});
    +0265 end
    +0266 
    +0267 function base = baseReactionLocal(rxnId)
    +0268 % Same one-line split as isozymeTieMap's local baseReaction. Kept as a
    +0269 % local duplicate rather than exported from isozymeTieMap.m, since
    +0270 % MATLAB only exposes a file's first function to other files and this is
    +0271 % its only caller here.
    +0272 parts = strsplit(rxnId, '_EXP_');
    +0273 base = parts{1};
    +0274 end
    +
    Generated by m2html © 2005
    + + \ No newline at end of file diff --git a/doc/src/gather_kcats/runDLKcat.html b/doc/src/gather_kcats/runDLKcat.html new file mode 100644 index 00000000..6dc6366e --- /dev/null +++ b/doc/src/gather_kcats/runDLKcat.html @@ -0,0 +1,145 @@ + + + + Description of runDLKcat + + + + + + + + + +
    Home > src > gather_kcats > runDLKcat.m
    + + + +

    runDLKcat +

    + +

    PURPOSE ^

    +
    runDLKcat Run DLKcat to predict kcat values from a Docker image.
    + +

    SYNOPSIS ^

    +
    function runDLKcat(varargin)
    + +

    DESCRIPTION ^

    +
     runDLKcat  Run DLKcat to predict kcat values from a Docker image.
    +
    + Runs DLKcat via a Docker image; once it completes successfully, the
    + DLKcat file is overwritten with the predicted output, in the model-
    + specific 'data' sub-folder taken from modelAdapter (e.g.
    + GECKO/tutorials/tutorial_yeast-GEM/data/DLKcat.tsv).
    +
    + Name-Value Arguments
    + --------------------
    + modelAdapter : ModelAdapter
    +     a loaded model adapter (default: the current default model adapter).
    + filePath : char
    +     path to the DLKcat.tsv file (default: data/DLKcat.tsv).
    +
    + Notes
    + -----
    + 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.
    +
    + See also
    + --------
    + writeDLKcatInput, readDLKcatOutput
    + + +

    CROSS-REFERENCE INFORMATION ^

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

    SOURCE CODE ^

    +
    0001 function runDLKcat(varargin)
    +0002 % runDLKcat  Run DLKcat to predict kcat values from a Docker image.
    +0003 %
    +0004 % Runs DLKcat via a Docker image; once it completes successfully, the
    +0005 % DLKcat file is overwritten with the predicted output, in the model-
    +0006 % specific 'data' sub-folder taken from modelAdapter (e.g.
    +0007 % GECKO/tutorials/tutorial_yeast-GEM/data/DLKcat.tsv).
    +0008 %
    +0009 % Name-Value Arguments
    +0010 % --------------------
    +0011 % modelAdapter : ModelAdapter
    +0012 %     a loaded model adapter (default: the current default model adapter).
    +0013 % filePath : char
    +0014 %     path to the DLKcat.tsv file (default: data/DLKcat.tsv).
    +0015 %
    +0016 % Notes
    +0017 % -----
    +0018 % 1. Requires Docker to be installed, and Docker Desktop running. Visit
    +0019 %    "https://www.docker.com".
    +0020 % 2. Runtime will depend on whether the image is to be downloaded or not.
    +0021 %
    +0022 % See also
    +0023 % --------
    +0024 % writeDLKcatInput, readDLKcatOutput
    +0025 
    +0026 p = parseGECKOargs(varargin, { ...
    +0027     'modelAdapter', []; ...
    +0028     'filePath',     []});
    +0029 modelAdapter = p.modelAdapter;
    +0030 filePath     = p.filePath;
    +0031 
    +0032 if isempty(modelAdapter)
    +0033     modelAdapter = ModelAdapterManager.getDefault();
    +0034     if isempty(modelAdapter)
    +0035         error('Either send in a modelAdapter or set the default model adapter in the ModelAdapterManager.')
    +0036     end
    +0037 end
    +0038 params = modelAdapter.params;
    +0039 % Make sure path is full, not relative
    +0040 [~, params.path] = fileattrib(params.path);
    +0041 params.path=params.path.Name;
    +0042 
    +0043 if isempty(filePath)
    +0044     filePath = fullfile(params.path,'data','DLKcat.tsv');
    +0045 elseif strcmp(filePath(end),{'\','/'})
    +0046     filePath = fullfile(filePath,'DLKcat.tsv');
    +0047 end
    +0048 filePath = checkFileExistence(filePath,1);
    +0049 
    +0050 copyfile(filePath, fullfile(params.path,'data','tempDLKcat.tsv'));
    +0051     
    +0052 
    +0053 %% Check and install requirements
    +0054 % On macOS, Docker might not be properly loaded if MATLAB is started via
    +0055 % launcher and not terminal.
    +0056 if ismac
    +0057     setenv('PATH', strcat('/usr/local/bin', ':', getenv("PATH")));
    +0058 end
    +0059 
    +0060 % Check if Docker is installed
    +0061 [checks.docker.status, checks.docker.out] = system('docker --version');
    +0062 if checks.docker.status ~= 0
    +0063     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.')
    +0064 end
    +0065 
    +0066 disp('Running DLKcat prediction, this may take many minutes, especially the first time.')
    +0067 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"']);
    +0068 delete(fullfile(params.path,'/data/tempDLKcat.tsv'));
    +0069 
    +0070 if status == 0 && exist(fullfile(params.path,'data/tempDLKcatOutput.tsv'))
    +0071     movefile(fullfile(params.path,'/data/tempDLKcatOutput.tsv'), filePath);
    +0072     disp('DKLcat prediction completed.');
    +0073 else    
    +0074     error('DLKcat encountered an error or it did not create any output file.')
    +0075 end
    +0076
    +
    Generated by m2html © 2005
    + + \ No newline at end of file diff --git a/doc/src/gather_kcats/saveKcatSource.html b/doc/src/gather_kcats/saveKcatSource.html new file mode 100644 index 00000000..97493742 --- /dev/null +++ b/doc/src/gather_kcats/saveKcatSource.html @@ -0,0 +1,498 @@ + + + + Description of saveKcatSource + + + + + + + + + +
    Home > src > gather_kcats > saveKcatSource.m
    + + + +

    saveKcatSource +

    + +

    PURPOSE ^

    +
    saveKcatSource Write a kcatList to a kcat source file of the project.
    + +

    SYNOPSIS ^

    +
    function filename = saveKcatSource(model, kcatList, name, varargin)
    + +

    DESCRIPTION ^

    +
     saveKcatSource  Write a kcatList to a kcat source file of the project.
    +
    + Writes the kcat values of kcatList to data/kcats/<name>.tsv in the
    + project folder, the file that loadKcatSource reads back. Rows are keyed
    + by their conventional reaction and enzyme set (see getEcRxnKeys), not
    + by model.ec.rxns, so the file stays valid when the ecModel is rebuilt.
    + kcatsFromBrenda, kcatsFromDLKcat and kcatsFromOKP write these files for
    + their sources; use this function for a kcatList made in another way.
    +
    + The file is UTF-8 text. It starts with '#' header lines (source,
    + generator, parameters, data, kind, created), then a tab-separated table
    + with the columns rxn, enzymes, substrate, kcat, log10_sd, source,
    + detail, ec_code and note, sorted by all columns from rxn onwards.
    + Left out are:
    + - rows whose kcat is not a positive finite number (0 means no value
    +   was found);
    + - rows of model.ec reactions without enzymes, which have no enzyme
    +   constraint and could not be told apart from their isozymes.
    +
    + Parameters
    + ----------
    + model : struct
    +     the ecModel the kcatList refers to.
    + kcatList : struct
    +     kcat values as returned by kcatsFromBrenda, fuzzyKcatMatching,
    +     readDLKcatOutput, readOpenKineticsPredictorOutput or mergeKcats:
    +     fields rxns and kcats, optionally source, substrates, eccodes,
    +     wildcardLvl, origin, kcatSource, log10sd and detail (further
    +     key=value pairs for the detail column).
    + name : char
    +     name of the source; the file is <name>.tsv.
    +
    + Name-Value Arguments
    + --------------------
    + modelAdapter : ModelAdapter
    +     a loaded model adapter (default: the current default model adapter).
    + folder : char
    +     folder to write to (default: data/kcats in the project folder).
    + generator : char
    +     what produced the values (default: 'saveKcatSource').
    + parameters : struct
    +     settings used to produce the values, written as compact JSON with
    +     sorted keys (default: none).
    + data : char
    +     version of the data the values come from, e.g. a BRENDA release
    +     (default: empty).
    + kind : char
    +     'gathered' (default) or 'curated'.
    +
    + A file whose header says 'kind: curated' or 'source: custom', or named
    + custom.tsv, is never written.
    +
    + Returns
    + -------
    + filename : char
    +     the file written.
    +
    + Examples
    + --------
    +     kcatList = fuzzyKcatMatching(ecModel);
    +     saveKcatSource(ecModel, kcatList, 'mybrenda');
    +
    + See also
    + --------
    + kcatsFromBrenda, loadKcatSource, getEcRxnKeys
    + + +

    CROSS-REFERENCE INFORMATION ^

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

    SUBFUNCTIONS ^

    + + +

    SOURCE CODE ^

    +
    0001 function filename = saveKcatSource(model, kcatList, name, varargin)
    +0002 % saveKcatSource  Write a kcatList to a kcat source file of the project.
    +0003 %
    +0004 % Writes the kcat values of kcatList to data/kcats/<name>.tsv in the
    +0005 % project folder, the file that loadKcatSource reads back. Rows are keyed
    +0006 % by their conventional reaction and enzyme set (see getEcRxnKeys), not
    +0007 % by model.ec.rxns, so the file stays valid when the ecModel is rebuilt.
    +0008 % kcatsFromBrenda, kcatsFromDLKcat and kcatsFromOKP write these files for
    +0009 % their sources; use this function for a kcatList made in another way.
    +0010 %
    +0011 % The file is UTF-8 text. It starts with '#' header lines (source,
    +0012 % generator, parameters, data, kind, created), then a tab-separated table
    +0013 % with the columns rxn, enzymes, substrate, kcat, log10_sd, source,
    +0014 % detail, ec_code and note, sorted by all columns from rxn onwards.
    +0015 % Left out are:
    +0016 % - rows whose kcat is not a positive finite number (0 means no value
    +0017 %   was found);
    +0018 % - rows of model.ec reactions without enzymes, which have no enzyme
    +0019 %   constraint and could not be told apart from their isozymes.
    +0020 %
    +0021 % Parameters
    +0022 % ----------
    +0023 % model : struct
    +0024 %     the ecModel the kcatList refers to.
    +0025 % kcatList : struct
    +0026 %     kcat values as returned by kcatsFromBrenda, fuzzyKcatMatching,
    +0027 %     readDLKcatOutput, readOpenKineticsPredictorOutput or mergeKcats:
    +0028 %     fields rxns and kcats, optionally source, substrates, eccodes,
    +0029 %     wildcardLvl, origin, kcatSource, log10sd and detail (further
    +0030 %     key=value pairs for the detail column).
    +0031 % name : char
    +0032 %     name of the source; the file is <name>.tsv.
    +0033 %
    +0034 % Name-Value Arguments
    +0035 % --------------------
    +0036 % modelAdapter : ModelAdapter
    +0037 %     a loaded model adapter (default: the current default model adapter).
    +0038 % folder : char
    +0039 %     folder to write to (default: data/kcats in the project folder).
    +0040 % generator : char
    +0041 %     what produced the values (default: 'saveKcatSource').
    +0042 % parameters : struct
    +0043 %     settings used to produce the values, written as compact JSON with
    +0044 %     sorted keys (default: none).
    +0045 % data : char
    +0046 %     version of the data the values come from, e.g. a BRENDA release
    +0047 %     (default: empty).
    +0048 % kind : char
    +0049 %     'gathered' (default) or 'curated'.
    +0050 %
    +0051 % A file whose header says 'kind: curated' or 'source: custom', or named
    +0052 % custom.tsv, is never written.
    +0053 %
    +0054 % Returns
    +0055 % -------
    +0056 % filename : char
    +0057 %     the file written.
    +0058 %
    +0059 % Examples
    +0060 % --------
    +0061 %     kcatList = fuzzyKcatMatching(ecModel);
    +0062 %     saveKcatSource(ecModel, kcatList, 'mybrenda');
    +0063 %
    +0064 % See also
    +0065 % --------
    +0066 % kcatsFromBrenda, loadKcatSource, getEcRxnKeys
    +0067 
    +0068 names = {'modelAdapter','folder','generator','parameters','data','kind'};
    +0069 checkOptions(varargin, names, 'saveKcatSource');
    +0070 p = parseGECKOargs(varargin, { ...
    +0071     'modelAdapter', []; ...
    +0072     'folder',       []; ...
    +0073     'generator',    'saveKcatSource'; ...
    +0074     'parameters',   struct(); ...
    +0075     'data',         ''; ...
    +0076     'kind',         'gathered'});
    +0077 kind = validatestring(p.kind, {'gathered','curated'});
    +0078 name = char(name);
    +0079 filename = kcatSourceFile(name, p.folder, p.modelAdapter);
    +0080 
    +0081 [baseRxns, enzymeSets] = getEcRxnKeys(model);
    +0082 [found, idx] = ismember(kcatList.rxns(:), model.ec.rxns);
    +0083 if ~all(found)
    +0084     error('saveKcatSource:unknownRxns', '%s', ravenList( ...
    +0085         'These kcatList reactions are not in model.ec.rxns:', kcatList.rxns(~found), false));
    +0086 end
    +0087 
    +0088 n = numel(kcatList.rxns);
    +0089 kcats = double(kcatList.kcats(:));
    +0090 if numel(kcats) ~= n
    +0091     error('saveKcatSource:fields', 'kcatList.kcats and kcatList.rxns differ in length.')
    +0092 end
    +0093 substrate = textColumn(kcatList, 'substrates', n);
    +0094 ecCode    = textColumn(kcatList, 'eccodes', n);
    +0095 extra     = textColumn(kcatList, 'detail', n);
    +0096 if isfield(kcatList, 'kcatSource')
    +0097     source = textColumn(kcatList, 'kcatSource', n);
    +0098 elseif isfield(kcatList, 'source')
    +0099     source = repmat({char(kcatList.source)}, n, 1);
    +0100 else
    +0101     source = repmat({name}, n, 1);
    +0102 end
    +0103 wc     = numColumn(kcatList, 'wildcardLvl', n);
    +0104 origin = numColumn(kcatList, 'origin', n);
    +0105 sd     = numColumn(kcatList, 'log10sd', n);
    +0106 
    +0107 keep = kcats > 0 & isfinite(kcats);
    +0108 noEnzymes = keep & cellfun(@isempty, enzymeSets(idx));
    +0109 if any(noEnzymes)
    +0110     fprintf('%d kcats of reactions without enzymes are not written to %s.\n', sum(noEnzymes), filename);
    +0111 end
    +0112 keep = find(keep & ~noEnzymes);
    +0113 
    +0114 clean = @(c) regexprep(string(c(:)), '[\t\r\n]', ' ');
    +0115 rows = strings(numel(keep), 9);
    +0116 if ~isempty(keep)
    +0117     wcText = strings(numel(keep), 1);
    +0118     hasWc = ~isnan(wc(keep));
    +0119     wcText(hasWc) = "wc=" + string(fix(wc(keep(hasWc))));
    +0120     originText = strings(numel(keep), 1);
    +0121     hasOrigin = ~isnan(origin(keep));
    +0122     originText(hasOrigin) = "origin=" + string(fix(origin(keep(hasOrigin))));
    +0123     detail = join([wcText, originText, strtrim(clean(extra(keep)))], "; ", 2);
    +0124     detail = regexprep(detail, '^(; )+|(; )+$', '');
    +0125     detail = regexprep(detail, '(; ){2,}', '; ');
    +0126     rows(:, 1) = clean(baseRxns(idx(keep)));
    +0127     rows(:, 2) = clean(enzymeSets(idx(keep)));
    +0128     rows(:, 3) = clean(substrate(keep));
    +0129     rows(:, 4) = formatNumbers(kcats(keep));
    +0130     rows(:, 5) = formatNumbers(sd(keep));
    +0131     rows(:, 6) = clean(source(keep));
    +0132     rows(:, 7) = detail;
    +0133     rows(:, 8) = clean(ecCode(keep));
    +0134     % Sorted by the columns in this order, as geckopy sorts tuples: one key
    +0135     % per row, the fields joined by a character below any in the text.
    +0136     [~, order] = sort(join(rows(:, [1 2 3 6 4 5 7 8 9]), char(1), 2));
    +0137     rows = rows(order, :);
    +0138 end
    +0139 
    +0140 folder = fileparts(filename);
    +0141 if ~isfolder(folder)
    +0142     mkdir(folder);
    +0143 end
    +0144 fid = fopen(filename, 'w', 'n', 'UTF-8');
    +0145 if fid < 0
    +0146     error('saveKcatSource:write', 'Cannot write %s', filename)
    +0147 end
    +0148 cleanup = onCleanup(@() fclose(fid));
    +0149 fprintf(fid, '# source: %s\n', name);
    +0150 fprintf(fid, '# generator: %s (GECKO %s)\n', cleanText(p.generator), geckoVersion());
    +0151 fprintf(fid, '# parameters: %s\n', kcatSourceJson(p.parameters));
    +0152 fprintf(fid, '# data: %s\n', cleanText(p.data));
    +0153 fprintf(fid, '# kind: %s\n', kind);
    +0154 fprintf(fid, '# created: %s\n', char(datetime('now', 'TimeZone', 'UTC', 'Format', 'yyyy-MM-dd''T''HH:mm:ss''Z''')));
    +0155 fprintf(fid, 'rxn\tenzymes\tsubstrate\tkcat\tlog10_sd\tsource\tdetail\tec_code\tnote\n');
    +0156 if ~isempty(rows)
    +0157     fprintf(fid, '%s\n', join(rows, sprintf('\t'), 2));
    +0158 end
    +0159 end
    +0160 
    +0161 function col = textColumn(s, field, n)
    +0162 % A kcatList field as an n x 1 cell of char; a cell of several entries
    +0163 % (e.g. all substrates of a reaction) is joined by '; '.
    +0164 col = repmat({''}, n, 1);
    +0165 if ~isfield(s, field) || isempty(s.(field))
    +0166     return
    +0167 end
    +0168 v = s.(field);
    +0169 if ischar(v) || isstring(v)
    +0170     v = cellstr(v);
    +0171 end
    +0172 if numel(v) ~= n
    +0173     error('saveKcatSource:fields', 'kcatList.%s and kcatList.rxns differ in length.', field)
    +0174 end
    +0175 for i = 1:n
    +0176     e = v{i};
    +0177     if iscell(e)
    +0178         e = strjoin(cellfun(@char, e(:)', 'UniformOutput', false), '; ');
    +0179     elseif isstring(e)
    +0180         e = char(e);
    +0181     elseif ~ischar(e)
    +0182         e = '';
    +0183     end
    +0184     col{i} = e;
    +0185 end
    +0186 end
    +0187 
    +0188 function col = numColumn(s, field, n)
    +0189 col = nan(n, 1);
    +0190 if isfield(s, field) && ~isempty(s.(field))
    +0191     if numel(s.(field)) ~= n
    +0192         error('saveKcatSource:fields', 'kcatList.%s and kcatList.rxns differ in length.', field)
    +0193     end
    +0194     col = double(s.(field)(:));
    +0195 end
    +0196 end
    +0197 
    +0198 function t = formatNumbers(x)
    +0199 % formatKcatNumber for a vector, in a few vectorized passes.
    +0200 x = x(:);
    +0201 t = strings(numel(x), 1);
    +0202 whole = isfinite(x) & x == round(x) & abs(x) < 1e15;
    +0203 t(whole) = compose('%d', x(whole));
    +0204 t(isinf(x) & x > 0) = "Inf";
    +0205 t(isinf(x) & x < 0) = "-Inf";
    +0206 open = find(isfinite(x) & ~whole);
    +0207 for digits = 1:17
    +0208     if isempty(open)
    +0209         break
    +0210     end
    +0211     candidate = compose(sprintf('%%.%dg', digits), x(open));
    +0212     hit = str2double(candidate) == x(open);
    +0213     t(open(hit)) = candidate(hit);
    +0214     open = open(~hit);
    +0215 end
    +0216 end
    +0217 
    +0218 function t = cleanText(t)
    +0219 t = regexprep(char(t), '[\t\r\n]', ' ');
    +0220 end
    +0221 
    +0222 function v = geckoVersion()
    +0223 v = '';
    +0224 file = fullfile(findGECKOroot, 'version.txt');
    +0225 if isfile(file)
    +0226     v = strtrim(fileread(file));
    +0227 end
    +0228 end
    +0229 
    +0230 function filename = kcatSourceFile(name, folder, modelAdapter)
    +0231 name = char(name);
    +0232 if isempty(regexp(name, '^[A-Za-z0-9_.-]+$', 'once'))
    +0233     error('saveKcatSource:invalidName', ...
    +0234         'The source name "%s" may only contain letters, digits, ''_'', ''-'' and ''.''.', name)
    +0235 end
    +0236 if isempty(folder)
    +0237     if isempty(modelAdapter)
    +0238         modelAdapter = ModelAdapterManager.getDefault();
    +0239         if isempty(modelAdapter)
    +0240             error('Either send in a modelAdapter or set the default model adapter in the ModelAdapterManager.')
    +0241         end
    +0242     end
    +0243     folder = fullfile(modelAdapter.params.path, 'data', 'kcats');
    +0244 end
    +0245 filename = fullfile(char(folder), [name '.tsv']);
    +0246 if strcmpi(name, 'custom')
    +0247     error('saveKcatSource:curated', ['custom.tsv holds curated kcats and is not ' ...
    +0248         'written by GECKO; edit it by hand.'])
    +0249 end
    +0250 if isfile(filename)
    +0251     meta = readHeaderLines(filename);
    +0252     if (isfield(meta, 'kind') && strcmpi(meta.kind, 'curated')) || ...
    +0253             (isfield(meta, 'source') && strcmpi(meta.source, 'custom'))
    +0254         error('saveKcatSource:curated', '%s is curated by hand and is not overwritten.', filename)
    +0255     end
    +0256 end
    +0257 end
    +0258 
    +0259 function meta = readHeaderLines(filename)
    +0260 % Only the header lines at the top, so that a damaged table does not stop
    +0261 % a gathered file from being written again.
    +0262 meta = struct();
    +0263 fid = fopen(filename, 'r', 'n', 'UTF-8');
    +0264 if fid < 0
    +0265     return
    +0266 end
    +0267 cleanup = onCleanup(@() fclose(fid));
    +0268 line = fgetl(fid);
    +0269 if ischar(line)
    +0270     line = regexprep(line, ['^' char(65279)], '');
    +0271 end
    +0272 while ischar(line) && (isempty(strtrim(line)) || startsWith(unquoteField(line), '#'))
    +0273     [key, value] = parseHeaderLine(line);
    +0274     if ~isempty(key)
    +0275         meta.(key) = value;
    +0276     end
    +0277     line = fgetl(fid);
    +0278 end
    +0279 end
    +0280 
    +0281 function j = kcatSourceJson(v)
    +0282 if isstruct(v) && isscalar(v)
    +0283     f = sort(fieldnames(v));
    +0284     parts = cell(1, numel(f));
    +0285     for k = 1:numel(f)
    +0286         parts{k} = [jsonString(f{k}) ':' kcatSourceJson(v.(f{k}))];
    +0287     end
    +0288     j = ['{' strjoin(parts, ',') '}'];
    +0289 elseif ischar(v) || (isstring(v) && isscalar(v))
    +0290     j = jsonString(char(v));
    +0291 elseif iscell(v)
    +0292     j = ['[' strjoin(cellfun(@kcatSourceJson, v(:)', 'UniformOutput', false), ',') ']'];
    +0293 elseif (isnumeric(v) || islogical(v)) && numel(v) ~= 1
    +0294     j = ['[' strjoin(arrayfun(@kcatSourceJson, v(:)', 'UniformOutput', false), ',') ']'];
    +0295 elseif islogical(v)
    +0296     j = 'false';
    +0297     if v
    +0298         j = 'true';
    +0299     end
    +0300 elseif isnumeric(v)
    +0301     if ~isfinite(v)
    +0302         j = 'null';
    +0303     else
    +0304         j = formatKcatNumber(double(v));
    +0305     end
    +0306 elseif isempty(v)
    +0307     j = 'null';
    +0308 else
    +0309     error('kcatSourceJson:type', 'Parameters of class %s cannot be written.', class(v))
    +0310 end
    +0311 end
    +0312 
    +0313 function s = jsonString(s)
    +0314 % JSON escapes, as Python's json.dumps(ensure_ascii=False).
    +0315 out = '';
    +0316 for c = s
    +0317     switch c
    +0318         case '"', out = [out '\"']; %#ok<AGROW>
    +0319         case '\', out = [out '\\']; %#ok<AGROW>
    +0320         case char(8), out = [out '\b']; %#ok<AGROW>
    +0321         case char(9), out = [out '\t']; %#ok<AGROW>
    +0322         case char(10), out = [out '\n']; %#ok<AGROW>
    +0323         case char(12), out = [out '\f']; %#ok<AGROW>
    +0324         case char(13), out = [out '\r']; %#ok<AGROW>
    +0325         otherwise
    +0326             if double(c) < 32
    +0327                 out = [out sprintf('\\u%04x', double(c))]; %#ok<AGROW>
    +0328             else
    +0329                 out = [out c]; %#ok<AGROW>
    +0330             end
    +0331     end
    +0332 end
    +0333 s = ['"' out '"'];
    +0334 end
    +0335 
    +0336 function t = formatKcatNumber(x)
    +0337 if isnan(x)
    +0338     t = '';
    +0339 elseif isinf(x)
    +0340     t = 'Inf';
    +0341     if x < 0
    +0342         t = '-Inf';
    +0343     end
    +0344 elseif x == round(x) && abs(x) < 1e15
    +0345     t = sprintf('%d', x);
    +0346 else
    +0347     for digits = 1:17
    +0348         t = sprintf('%.*g', digits, x);
    +0349         if str2double(t) == x
    +0350             break
    +0351         end
    +0352     end
    +0353 end
    +0354 end
    +0355 
    +0356 function [key, value] = parseHeaderLine(line)
    +0357 key = ''; value = '';
    +0358 tok = regexp(unquoteField(line), '^\s*#\s*([A-Za-z][A-Za-z0-9_]{0,62})\s*:\s?(.*)$', 'tokens', 'once');
    +0359 if ~isempty(tok)
    +0360     key = lower(tok{1});
    +0361     value = strtrim(tok{2});
    +0362 end
    +0363 end
    +0364 
    +0365 function t = unquoteField(t)
    +0366 t = strtrim(t);
    +0367 if numel(t) >= 2 && t(1) == '"' && t(end) == '"'
    +0368     t = strtrim(strrep(t(2:end-1), '""', '"'));
    +0369 end
    +0370 end
    +0371 
    +0372 function checkOptions(args, names, functionName)
    +0373 % Options are name-value pairs with known names, so a misspelled option is
    +0374 % an error instead of being taken as a positional argument.
    +0375 id = [functionName ':arguments'];
    +0376 given = args(1:2:end);
    +0377 if mod(numel(args), 2) ~= 0 || ~all(cellfun(@(x) ischar(x) || (isstring(x) && isscalar(x)), given))
    +0378     error(id, 'Options of %s are name-value pairs. Options: %s.', functionName, strjoin(names, ', '))
    +0379 end
    +0380 unknown = setdiff(cellfun(@char, given, 'UniformOutput', false), names);
    +0381 if ~isempty(unknown)
    +0382     error(id, 'Unknown option of %s: %s. Options: %s.', functionName, strjoin(unknown, ', '), ...
    +0383         strjoin(names, ', '))
    +0384 end
    +0385 end
    +
    Generated by m2html © 2005
    + + \ No newline at end of file diff --git a/doc/src/gather_kcats/submitOpenKineticsPredictor.html b/doc/src/gather_kcats/submitOpenKineticsPredictor.html new file mode 100644 index 00000000..5ab11f0d --- /dev/null +++ b/doc/src/gather_kcats/submitOpenKineticsPredictor.html @@ -0,0 +1,292 @@ + + + + Description of submitOpenKineticsPredictor + + + + + + + + + +
    Home > src > gather_kcats > submitOpenKineticsPredictor.m
    + + + +

    submitOpenKineticsPredictor +

    + +

    PURPOSE ^

    +
    submitOpenKineticsPredictor Submit a kcat prediction job to OpenKineticsPredictor.
    + +

    SYNOPSIS ^

    +
    function jobId = submitOpenKineticsPredictor(model, varargin)
    + +

    DESCRIPTION ^

    +
     submitOpenKineticsPredictor  Submit a kcat prediction job to OpenKineticsPredictor.
    +
    + Builds the OpenKineticsPredictor input (protein sequences + single-substrate
    + SMILES, via writeOpenKineticsPredictorInput) and submits a kcat prediction
    + job to the OKP REST API (https://predictor.openkinetics.org/). The returned
    + job id is also stored in data/OKP_job.txt, so fetchOpenKineticsPredictor can
    + pick it up later.
    +
    + Predictors available via OKP: CataPro, CatPred, CatRange, DLKcat, EITLEM,
    + KinForm-H, KinForm-L, OmniESI, OmniESI-O2DENet, TurNup, UniKP (see GET
    + /api/v1/methods/). CatRange predicts a class of kcat values;
    + readOpenKineticsPredictorOutput uses its geometric midpoint.
    +
    + Obtaining an API key:
    +   The OKP API requires a personal Bearer key (looks like 'ak_...'). Keys
    +   are free and need no registration:
    +     1. Open https://predictor.openkinetics.org/api-docs in a browser.
    +     2. In the "API key generator" section, click "Generate".
    +     3. Copy the key shown (it is displayed only once). If you lose it,
    +        revoke it on the same page and generate a new one.
    +   Keys are tied to your IP and carry a daily prediction quota that resets
    +   at midnight UTC.
    +
    +   The key is a secret; do NOT put it in the model adapter (which is
    +   shared/committed). Provide it in one of three ways, checked in this
    +   order: the apiKey argument below; the OKP_API_KEY environment variable
    +   (setenv('OKP_API_KEY',...)); or a plain-text file data/okpApiKey.txt in
    +   the model's data folder (this name is git-ignored by GECKO).
    +
    + Parameters
    + ----------
    + model : struct
    +     ecModel in GECKO 3 format (with ecModel.ec structure).
    +
    + Name-Value Arguments
    + --------------------
    + ecRxns : logical
    +     logical vector indicating which reactions to include (default: all
    +     reactions).
    + overwrite : logical
    +     rebuild data/OKP.csv even if it exists (default false; an existing
    +     file is reused).
    + apiKey : char
    +     OKP API key (default: resolved from OKP_API_KEY or data/okpApiKey.txt,
    +     see above).
    + method : char
    +     predictor to use (default: params.okp.method, or 'CataPro').
    + modelAdapter : ModelAdapter
    +     a loaded model adapter (default: the current default model adapter).
    +
    + Returns
    + -------
    + jobId : char
    +     the OKP job identifier (also written to data/OKP_job.txt).
    +
    + Examples
    + --------
    +     jobId = submitOpenKineticsPredictor(model);
    +     jobId = submitOpenKineticsPredictor(model, 'overwrite', true, 'apiKey', 'ak_...', 'method', 'DLKcat');
    +
    + See also
    + --------
    + fetchOpenKineticsPredictor, writeOpenKineticsPredictorInput
    + + +

    CROSS-REFERENCE INFORMATION ^

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

    SUBFUNCTIONS ^

    + + +

    SOURCE CODE ^

    +
    0001 function jobId = submitOpenKineticsPredictor(model, varargin)
    +0002 % submitOpenKineticsPredictor  Submit a kcat prediction job to OpenKineticsPredictor.
    +0003 %
    +0004 % Builds the OpenKineticsPredictor input (protein sequences + single-substrate
    +0005 % SMILES, via writeOpenKineticsPredictorInput) and submits a kcat prediction
    +0006 % job to the OKP REST API (https://predictor.openkinetics.org/). The returned
    +0007 % job id is also stored in data/OKP_job.txt, so fetchOpenKineticsPredictor can
    +0008 % pick it up later.
    +0009 %
    +0010 % Predictors available via OKP: CataPro, CatPred, CatRange, DLKcat, EITLEM,
    +0011 % KinForm-H, KinForm-L, OmniESI, OmniESI-O2DENet, TurNup, UniKP (see GET
    +0012 % /api/v1/methods/). CatRange predicts a class of kcat values;
    +0013 % readOpenKineticsPredictorOutput uses its geometric midpoint.
    +0014 %
    +0015 % Obtaining an API key:
    +0016 %   The OKP API requires a personal Bearer key (looks like 'ak_...'). Keys
    +0017 %   are free and need no registration:
    +0018 %     1. Open https://predictor.openkinetics.org/api-docs in a browser.
    +0019 %     2. In the "API key generator" section, click "Generate".
    +0020 %     3. Copy the key shown (it is displayed only once). If you lose it,
    +0021 %        revoke it on the same page and generate a new one.
    +0022 %   Keys are tied to your IP and carry a daily prediction quota that resets
    +0023 %   at midnight UTC.
    +0024 %
    +0025 %   The key is a secret; do NOT put it in the model adapter (which is
    +0026 %   shared/committed). Provide it in one of three ways, checked in this
    +0027 %   order: the apiKey argument below; the OKP_API_KEY environment variable
    +0028 %   (setenv('OKP_API_KEY',...)); or a plain-text file data/okpApiKey.txt in
    +0029 %   the model's data folder (this name is git-ignored by GECKO).
    +0030 %
    +0031 % Parameters
    +0032 % ----------
    +0033 % model : struct
    +0034 %     ecModel in GECKO 3 format (with ecModel.ec structure).
    +0035 %
    +0036 % Name-Value Arguments
    +0037 % --------------------
    +0038 % ecRxns : logical
    +0039 %     logical vector indicating which reactions to include (default: all
    +0040 %     reactions).
    +0041 % overwrite : logical
    +0042 %     rebuild data/OKP.csv even if it exists (default false; an existing
    +0043 %     file is reused).
    +0044 % apiKey : char
    +0045 %     OKP API key (default: resolved from OKP_API_KEY or data/okpApiKey.txt,
    +0046 %     see above).
    +0047 % method : char
    +0048 %     predictor to use (default: params.okp.method, or 'CataPro').
    +0049 % modelAdapter : ModelAdapter
    +0050 %     a loaded model adapter (default: the current default model adapter).
    +0051 %
    +0052 % Returns
    +0053 % -------
    +0054 % jobId : char
    +0055 %     the OKP job identifier (also written to data/OKP_job.txt).
    +0056 %
    +0057 % Examples
    +0058 % --------
    +0059 %     jobId = submitOpenKineticsPredictor(model);
    +0060 %     jobId = submitOpenKineticsPredictor(model, 'overwrite', true, 'apiKey', 'ak_...', 'method', 'DLKcat');
    +0061 %
    +0062 % See also
    +0063 % --------
    +0064 % fetchOpenKineticsPredictor, writeOpenKineticsPredictorInput
    +0065 
    +0066 p = parseGECKOargs(varargin, { ...
    +0067     'ecRxns',       []; ...
    +0068     'overwrite',    []; ...
    +0069     'apiKey',       []; ...
    +0070     'method',       []; ...
    +0071     'modelAdapter', []});
    +0072 ecRxns       = p.ecRxns;
    +0073 overwrite    = p.overwrite;
    +0074 apiKey       = p.apiKey;
    +0075 method       = p.method;
    +0076 modelAdapter = p.modelAdapter;
    +0077 
    +0078 if isempty(modelAdapter)
    +0079     modelAdapter = ModelAdapterManager.getDefault();
    +0080     if isempty(modelAdapter)
    +0081         error('Either provide a modelAdapter or set the default in ModelAdapterManager.')
    +0082     end
    +0083 end
    +0084 params = modelAdapter.params;
    +0085 
    +0086 if isempty(overwrite)
    +0087     overwrite = false;
    +0088 end
    +0089 if isempty(ecRxns)
    +0090     ecRxns = true(numel(model.ec.rxns),1);
    +0091 elseif ~islogical(ecRxns) || numel(ecRxns) ~= numel(model.ec.rxns)
    +0092     error('ecRxns should be a logical vector with length equal to model.ec.rxns')
    +0093 end
    +0094 
    +0095 apiKey = resolveOkpApiKey(apiKey, params.path);
    +0096 
    +0097 % Resolve predictor method and request options: defaults -> params.okp.* ->
    +0098 % the method argument (highest priority, applied last).
    +0099 okp = struct('method','CataPro', ...
    +0100              'handleLongSequences','truncate', ...
    +0101              'includeSimilarityColumns',true,'canonicalizeSubstrates',true);
    +0102 if isfield(params,'okp')
    +0103     fn = fieldnames(params.okp);
    +0104     for i=1:numel(fn); okp.(fn{i}) = params.okp.(fn{i}); end
    +0105 end
    +0106 if ~isempty(method)
    +0107     okp.method = method;
    +0108 end
    +0109 
    +0110 %% Build (or reuse) the input CSV --- the same function, writing the same
    +0111 % file, as the file-based workflow (writeOpenKineticsPredictorInput /
    +0112 % readOpenKineticsPredictorOutput), rather than a separate reimplementation.
    +0113 filename = fullfile(params.path,'data','OKP.csv');
    +0114 if exist(filename,'file') && ~overwrite
    +0115     fprintf('Using existing %s (set overwrite=true to rebuild).\n', filename);
    +0116 else
    +0117     writeOpenKineticsPredictorInput(model, 'ecRxns', ecRxns, 'modelAdapter', modelAdapter, ...
    +0118         'onlyWithSmiles', true, 'overwrite', true);
    +0119 end
    +0120 
    +0121 %% Submit via the OKP REST API
    +0122 % GECKO only ever predicts kcat.
    +0123 url = 'https://predictor.openkinetics.org/api/v1/submit/';
    +0124 
    +0125 targetsJson = '["kcat"]';
    +0126 methodsJson = ['{"kcat":"' okp.method '"}'];
    +0127 
    +0128 import matlab.net.http.*
    +0129 import matlab.net.http.io.*
    +0130 provider = MultipartFormProvider( ...
    +0131     'file',                     FileProvider(filename), ...
    +0132     'targets',                  targetsJson, ...
    +0133     'methods',                  methodsJson, ...
    +0134     'handleLongSequences',      okp.handleLongSequences, ...
    +0135     'includeSimilarityColumns', boolToStr(okp.includeSimilarityColumns), ...
    +0136     'canonicalizeSubstrates',   boolToStr(okp.canonicalizeSubstrates));
    +0137 header = matlab.net.http.HeaderField('Authorization', ['Bearer ' apiKey]);
    +0138 req    = RequestMessage('POST', header, provider);
    +0139 resp   = req.send(url);
    +0140 
    +0141 data = resp.Body.Data;
    +0142 if resp.StatusCode ~= matlab.net.http.StatusCode.OK && ...
    +0143         resp.StatusCode ~= matlab.net.http.StatusCode.Created
    +0144     error('OKP submit failed (HTTP %d): %s', double(resp.StatusCode), okpErrorText(data));
    +0145 end
    +0146 if ~isstruct(data) || ~isfield(data,'jobId')
    +0147     error('OKP submit returned an unexpected response (no jobId).');
    +0148 end
    +0149 jobId = data.jobId;
    +0150 
    +0151 %% Persist job metadata (plain text, one field per line)
    +0152 metaFile = fullfile(params.path,'data','OKP_job.txt');
    +0153 fID = fopen(metaFile,'w');
    +0154 fprintf(fID,'jobId: %s\n', jobId);
    +0155 fprintf(fID,'method: %s\n', okp.method);
    +0156 fprintf(fID,'submittedAt: %s\n', char(datetime('now','TimeZone','UTC','Format','yyyy-MM-dd''T''HH:mm:ss''Z''')));
    +0157 fclose(fID);
    +0158 
    +0159 fprintf('Submitted OKP job %s (method: %s). Metadata stored at %s\n', jobId, okp.method, metaFile);
    +0160 fprintf('Check progress later with fetchOpenKineticsPredictor, or at https://predictor.openkinetics.org/\n');
    +0161 end
    +0162 
    +0163 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
    +0164 function s = boolToStr(b)
    +0165 if islogical(b) || isnumeric(b)
    +0166     if b; s = 'true'; else; s = 'false'; end
    +0167 else
    +0168     s = char(b);
    +0169 end
    +0170 end
    +0171 
    +0172 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
    +0173 function txt = okpErrorText(data)
    +0174 if isstruct(data) && isfield(data,'error')
    +0175     txt = data.error;
    +0176 elseif ischar(data) || isstring(data)
    +0177     txt = char(data);
    +0178 else
    +0179     txt = 'unknown error';
    +0180 end
    +0181 end
    +
    Generated by m2html © 2005
    + + \ No newline at end of file diff --git a/doc/src/gather_kcats/updateKcatSources.html b/doc/src/gather_kcats/updateKcatSources.html new file mode 100644 index 00000000..71e8a6fc --- /dev/null +++ b/doc/src/gather_kcats/updateKcatSources.html @@ -0,0 +1,373 @@ + + + + Description of updateKcatSources + + + + + + + + + +
    Home > src > gather_kcats > updateKcatSources.m
    + + + +

    updateKcatSources +

    + +

    PURPOSE ^

    +
    updateKcatSources Gather the kcat sources that the configuration needs.
    + +

    SYNOPSIS ^

    +
    function report = updateKcatSources(model, varargin)
    + +

    DESCRIPTION ^

    +
     updateKcatSources  Gather the kcat sources that the configuration needs.
    +
    + Lists the kcat source files that [kcat_assignment] in model_adapter.toml
    + uses (see collectKcats), and gathers those that are missing or outdated
    + with kcatsFromBrenda, kcatsFromECTree, kcatsFromDLKcat and kcatsFromOKP:
    +
    + - a file is outdated when its header records other settings than
    +   [kcat_sources.<name>] asks for (presets set these for brenda and
    +   ec_tree), or, for brenda and ec_tree, another BRENDA release than the
    +   BRENDA files in use;
    + - brenda and ec_tree are made again; dlkcat reads data/DLKcat.tsv if it exists and
    +   runs DLKcat (Docker) otherwise; okp_<method> submits or fetches a job,
    +   and reports it as pending while the job runs;
    + - custom.tsv and other files it cannot gather are left as they are.
    +
    + Requirements are checked first: Docker for a DLKcat run and an
    + OpenKineticsPredictor API key for OKP. Calling it again is safe: files
    + that are current are not gathered again.
    +
    + Per-source settings are read from model_adapter.toml, for instance:
    +
    +     [kcat_sources.brenda]
    +     aggregation = "median"
    +
    +     [kcat_sources.okp_catapro]
    +     method = "CataPro"
    +
    + Parameters
    + ----------
    + model : struct
    +     an ecModel in GECKO 3 format (with ecModel.ec structure).
    +
    + Name-Value Arguments
    + --------------------
    + dryRun : logical
    +     only report what would be gathered (default false).
    + modelAdapter : ModelAdapter
    +     a loaded model adapter (default: the current default model adapter).
    +
    + Returns
    + -------
    + report : table
    +     one row per source: source, status (current, gathered, pending,
    +     outdated, missing, failed or skipped) and note.
    +
    + Examples
    + --------
    +     updateKcatSources(ecModel, 'dryRun', true)
    +     updateKcatSources(ecModel);
    +
    + See also
    + --------
    + collectKcats, assignKcats, kcatsFromBrenda, kcatsFromDLKcat, kcatsFromOKP
    + + +

    CROSS-REFERENCE INFORMATION ^

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

    SUBFUNCTIONS ^

    + + +

    SOURCE CODE ^

    +
    0001 function report = updateKcatSources(model, varargin)
    +0002 % updateKcatSources  Gather the kcat sources that the configuration needs.
    +0003 %
    +0004 % Lists the kcat source files that [kcat_assignment] in model_adapter.toml
    +0005 % uses (see collectKcats), and gathers those that are missing or outdated
    +0006 % with kcatsFromBrenda, kcatsFromECTree, kcatsFromDLKcat and kcatsFromOKP:
    +0007 %
    +0008 % - a file is outdated when its header records other settings than
    +0009 %   [kcat_sources.<name>] asks for (presets set these for brenda and
    +0010 %   ec_tree), or, for brenda and ec_tree, another BRENDA release than the
    +0011 %   BRENDA files in use;
    +0012 % - brenda and ec_tree are made again; dlkcat reads data/DLKcat.tsv if it exists and
    +0013 %   runs DLKcat (Docker) otherwise; okp_<method> submits or fetches a job,
    +0014 %   and reports it as pending while the job runs;
    +0015 % - custom.tsv and other files it cannot gather are left as they are.
    +0016 %
    +0017 % Requirements are checked first: Docker for a DLKcat run and an
    +0018 % OpenKineticsPredictor API key for OKP. Calling it again is safe: files
    +0019 % that are current are not gathered again.
    +0020 %
    +0021 % Per-source settings are read from model_adapter.toml, for instance:
    +0022 %
    +0023 %     [kcat_sources.brenda]
    +0024 %     aggregation = "median"
    +0025 %
    +0026 %     [kcat_sources.okp_catapro]
    +0027 %     method = "CataPro"
    +0028 %
    +0029 % Parameters
    +0030 % ----------
    +0031 % model : struct
    +0032 %     an ecModel in GECKO 3 format (with ecModel.ec structure).
    +0033 %
    +0034 % Name-Value Arguments
    +0035 % --------------------
    +0036 % dryRun : logical
    +0037 %     only report what would be gathered (default false).
    +0038 % modelAdapter : ModelAdapter
    +0039 %     a loaded model adapter (default: the current default model adapter).
    +0040 %
    +0041 % Returns
    +0042 % -------
    +0043 % report : table
    +0044 %     one row per source: source, status (current, gathered, pending,
    +0045 %     outdated, missing, failed or skipped) and note.
    +0046 %
    +0047 % Examples
    +0048 % --------
    +0049 %     updateKcatSources(ecModel, 'dryRun', true)
    +0050 %     updateKcatSources(ecModel);
    +0051 %
    +0052 % See also
    +0053 % --------
    +0054 % collectKcats, assignKcats, kcatsFromBrenda, kcatsFromDLKcat, kcatsFromOKP
    +0055 
    +0056 checkOptions(varargin, {'dryRun','modelAdapter'}, 'updateKcatSources');
    +0057 p = parseGECKOargs(varargin, {'dryRun', false; 'modelAdapter', []});
    +0058 modelAdapter = p.modelAdapter;
    +0059 if isempty(modelAdapter)
    +0060     modelAdapter = ModelAdapterManager.getDefault();
    +0061     if isempty(modelAdapter)
    +0062         error('Either send in a modelAdapter or set the default model adapter in the ModelAdapterManager.')
    +0063     end
    +0064 end
    +0065 params = modelAdapter.params;
    +0066 config = kcatAssignmentConfig(params);
    +0067 kcatDir = fullfile(params.path, 'data', 'kcats');
    +0068 
    +0069 names = {};
    +0070 for s = 1:numel(config.stages)
    +0071     for t = 1:numel(config.stages(s).files)
    +0072         token = config.stages(s).files{t};
    +0073         if startsWith(token, 'database_')
    +0074             token = 'brenda';
    +0075         end
    +0076         if ~any(strcmp(names, token))
    +0077             names{end+1} = token; %#ok<AGROW>
    +0078         end
    +0079     end
    +0080 end
    +0081 
    +0082 status = cell(numel(names), 1);
    +0083 note = cell(numel(names), 1);
    +0084 for k = 1:numel(names)
    +0085     name = names{k};
    +0086     file = fullfile(kcatDir, [name '.tsv']);
    +0087     wanted = struct();
    +0088     if isfield(config.sources, name)
    +0089         wanted = config.sources.(name);
    +0090     end
    +0091     [status{k}, note{k}] = check(name, file, wanted);
    +0092     if any(strcmp(status{k}, {'missing','outdated'})) && ~p.dryRun
    +0093         [status{k}, note{k}] = gather(model, name, wanted, modelAdapter);
    +0094     end
    +0095 end
    +0096 report = table(names(:), status, note, 'VariableNames', {'source','status','note'});
    +0097 disp(report)
    +0098 
    +0099     function [st, nt] = check(name, file, wanted)
    +0100         st = 'current'; nt = '';
    +0101         if strcmp(name, 'custom')
    +0102             st = 'skipped'; nt = 'curated by hand';
    +0103             return
    +0104         elseif ~any(strcmp(name, {'brenda','ec_tree','homologs','dlkcat'})) && ~startsWith(name, 'okp_')
    +0105             st = 'skipped'; nt = 'not a source GECKO gathers';
    +0106             return
    +0107         end
    +0108         if ~isfile(file)
    +0109             st = 'missing';
    +0110             return
    +0111         end
    +0112         meta = readHeaderLines(file);
    +0113         recorded = struct();
    +0114         if isfield(meta, 'parameters') && ~isempty(meta.parameters)
    +0115             recorded = jsondecode(meta.parameters);
    +0116         end
    +0117         f = fieldnames(wanted);
    +0118         for i = 1:numel(f)
    +0119             if ~isfield(recorded, f{i}) || ~isequal(normalizeValue(recorded.(f{i})), normalizeValue(wanted.(f{i})))
    +0120                 st = 'outdated';
    +0121                 nt = sprintf('%s differs from model_adapter.toml', f{i});
    +0122                 return
    +0123             end
    +0124         end
    +0125         if any(strcmp(name, {'brenda','ec_tree','homologs'}))
    +0126             release = brendaRelease(modelAdapter, name);
    +0127             if isfield(meta, 'data') && ~isempty(release) && ~strcmp(meta.data, release)
    +0128                 st = 'outdated';
    +0129                 nt = sprintf('made from %s; GECKO has %s', meta.data, release);
    +0130             end
    +0131         end
    +0132     end
    +0133 end
    +0134 
    +0135 function [st, nt] = gather(model, name, wanted, modelAdapter)
    +0136 st = 'gathered'; nt = '';
    +0137 try
    +0138     if strcmp(name, 'brenda')
    +0139         args = {};
    +0140         if isfield(wanted, 'aggregation'), args = [args, {'aggregation', wanted.aggregation}]; end
    +0141         if isfield(wanted, 'force_wildcard_level'), args = [args, {'forceWClvl', wanted.force_wildcard_level}]; end
    +0142         kcatsFromBrenda(model, args{:}, 'modelAdapter', modelAdapter);
    +0143     elseif strcmp(name, 'ec_tree')
    +0144         args = {};
    +0145         if isfield(wanted, 'k'), args = {'k', double(wanted.k)}; end
    +0146         kcatsFromECTree(model, args{:}, 'modelAdapter', modelAdapter);
    +0147     elseif strcmp(name, 'homologs')
    +0148         args = {};
    +0149         if isfield(wanted, 'k'), args = [args, {'k', double(wanted.k)}]; end
    +0150         if isfield(wanted, 'min_identity'), args = [args, {'minIdentity', double(wanted.min_identity)}]; end
    +0151         if isfield(wanted, 'coverage'), args = [args, {'coverage', double(wanted.coverage)}]; end
    +0152         kcatsFromHomologs(model, args{:}, 'modelAdapter', modelAdapter);
    +0153     elseif strcmp(name, 'dlkcat')
    +0154         run = ~isfile(fullfile(modelAdapter.params.path, 'data', 'DLKcat.tsv'));
    +0155         if run
    +0156             [status, ~] = system('docker --version');
    +0157             if status ~= 0
    +0158                 st = 'failed'; nt = 'DLKcat needs Docker to run';
    +0159                 return
    +0160             end
    +0161         end
    +0162         kcatsFromDLKcat(model, 'run', run, 'modelAdapter', modelAdapter);
    +0163     else % okp_<method>
    +0164         method = okpMethod(name, wanted);
    +0165         resolveOkpApiKey('', modelAdapter.params.path); % errors without a key
    +0166         [~, done] = kcatsFromOKP(model, 'method', method, 'saveAs', name, 'modelAdapter', modelAdapter);
    +0167         if ~done
    +0168             st = 'pending'; nt = sprintf('OKP job for %s still running; call again later', method);
    +0169         end
    +0170     end
    +0171 catch err
    +0172     st = 'failed'; nt = err.message;
    +0173 end
    +0174 end
    +0175 
    +0176 function method = okpMethod(name, wanted)
    +0177 % The OKP method of okp_<method>: from [kcat_sources.okp_<method>] method,
    +0178 % or the known method whose name gives this file name.
    +0179 if isfield(wanted, 'method')
    +0180     method = char(wanted.method);
    +0181     return
    +0182 end
    +0183 known = {'CataPro','CatPred','CatRange','DLKcat','EITLEM','KinForm-H','KinForm-L', ...
    +0184     'OmniESI','OmniESI-O2DENet','TurNup','UniKP'};
    +0185 tags = cellfun(@(m) ['okp_' lower(regexprep(m, '[^A-Za-z0-9]+', '_'))], known, 'UniformOutput', false);
    +0186 hit = strcmp(tags, name);
    +0187 if ~any(hit)
    +0188     error('updateKcatSources:okpMethod', ['Set the OKP method of %s in model_adapter.toml: ' ...
    +0189         '[kcat_sources.%s] method = "..."'], name, name)
    +0190 end
    +0191 method = known{hit};
    +0192 end
    +0193 
    +0194 function v = normalizeValue(v)
    +0195 if isstring(v)
    +0196     v = char(v);
    +0197 end
    +0198 if ischar(v)
    +0199     v = lower(v);
    +0200 elseif islogical(v)
    +0201     v = double(v);
    +0202 end
    +0203 end
    +0204 
    +0205 function release = brendaRelease(modelAdapter, name)
    +0206 % The release line of the BRENDA file a source is made from.
    +0207 release = '';
    +0208 files = struct('brenda', 'kcat.tsv', 'ec_tree', 'measurements.tsv', 'homologs', 'measurements.tsv');
    +0209 fid = fopen(fullfile(modelAdapter.getBrendaDBFolder(), files.(name)), 'r');
    +0210 if fid < 0
    +0211     return
    +0212 end
    +0213 line = fgetl(fid);
    +0214 fclose(fid);
    +0215 tok = regexp(line, '^#\s*(BRENDA release [^ ]+)', 'tokens', 'once');
    +0216 if ~isempty(tok)
    +0217     release = tok{1};
    +0218 end
    +0219 end
    +0220 
    +0221 function meta = readHeaderLines(filename)
    +0222 % Only the header lines at the top, so that a damaged table does not stop
    +0223 % a gathered file from being written again.
    +0224 meta = struct();
    +0225 fid = fopen(filename, 'r', 'n', 'UTF-8');
    +0226 if fid < 0
    +0227     return
    +0228 end
    +0229 cleanup = onCleanup(@() fclose(fid));
    +0230 line = fgetl(fid);
    +0231 if ischar(line)
    +0232     line = regexprep(line, ['^' char(65279)], '');
    +0233 end
    +0234 while ischar(line) && (isempty(strtrim(line)) || startsWith(unquoteField(line), '#'))
    +0235     [key, value] = parseHeaderLine(line);
    +0236     if ~isempty(key)
    +0237         meta.(key) = value;
    +0238     end
    +0239     line = fgetl(fid);
    +0240 end
    +0241 end
    +0242 
    +0243 function [key, value] = parseHeaderLine(line)
    +0244 key = ''; value = '';
    +0245 tok = regexp(unquoteField(line), '^\s*#\s*([A-Za-z][A-Za-z0-9_]{0,62})\s*:\s?(.*)$', 'tokens', 'once');
    +0246 if ~isempty(tok)
    +0247     key = lower(tok{1});
    +0248     value = strtrim(tok{2});
    +0249 end
    +0250 end
    +0251 
    +0252 function t = unquoteField(t)
    +0253 t = strtrim(t);
    +0254 if numel(t) >= 2 && t(1) == '"' && t(end) == '"'
    +0255     t = strtrim(strrep(t(2:end-1), '""', '"'));
    +0256 end
    +0257 end
    +0258 
    +0259 function checkOptions(args, names, functionName)
    +0260 % Options are name-value pairs with known names, so a misspelled option is
    +0261 % an error instead of being taken as a positional argument.
    +0262 id = [functionName ':arguments'];
    +0263 given = args(1:2:end);
    +0264 if mod(numel(args), 2) ~= 0 || ~all(cellfun(@(x) ischar(x) || (isstring(x) && isscalar(x)), given))
    +0265     error(id, 'Options of %s are name-value pairs. Options: %s.', functionName, strjoin(names, ', '))
    +0266 end
    +0267 unknown = setdiff(cellfun(@char, given, 'UniformOutput', false), names);
    +0268 if ~isempty(unknown)
    +0269     error(id, 'Unknown option of %s: %s. Options: %s.', functionName, strjoin(unknown, ', '), ...
    +0270         strjoin(names, ', '))
    +0271 end
    +0272 end
    +
    Generated by m2html © 2005
    + + \ No newline at end of file diff --git a/doc/src/gather_kcats/writeDLKcatInput.html b/doc/src/gather_kcats/writeDLKcatInput.html new file mode 100644 index 00000000..412eb399 --- /dev/null +++ b/doc/src/gather_kcats/writeDLKcatInput.html @@ -0,0 +1,207 @@ + + + + Description of writeDLKcatInput + + + + + + + + + +
    Home > src > gather_kcats > writeDLKcatInput.m
    + + + +

    writeDLKcatInput +

    + +

    PURPOSE ^

    +
    writeDLKcatInput Prepare and write the input file for DLKcat.
    + +

    SYNOPSIS ^

    +
    function writtenTable = writeDLKcatInput(model, varargin)
    + +

    DESCRIPTION ^

    +
     writeDLKcatInput  Prepare and write the input file for DLKcat.
    +
    + Prepares the input for DLKcat, and writes it to data/DLKcat.tsv in the
    + obj.params.path specified in the ModelAdapter.
    +
    + Parameters
    + ----------
    + model : struct
    +     an ecModel in GECKO 3 format (with ecModel.ec structure).
    +
    + Name-Value Arguments
    + --------------------
    + ecRxns : logical
    +     for which reactions (from model.ec.rxns) DLKcat should predict kcat
    +     values, provided as logical vector with same length as model.ec.rxns
    +     (default: all reactions).
    + modelAdapter : ModelAdapter
    +     a loaded model adapter (default: the current default model adapter).
    + onlyWithSmiles : logical
    +     whether to only include metabolites with SMILES (default true).
    + filename : char
    +     path to the input file, including the filename and .tsv extension
    +     (default: data/DLKcat.tsv from the obj.params.path folder specified in
    +     the modelAdapter).
    + overwrite : logical
    +     whether existing file should be overwritten (default false, to prevent
    +     overwriting a file that already contains DLKcat-predicted kcat values).
    +
    + Returns
    + -------
    + writtenTable : cell
    +     the table written, mainly to be used for testing purposes.
    +
    + Examples
    + --------
    +     % optional arguments may be given positionally or as name-value pairs:
    +     writtenTable = writeDLKcatInput(model);
    +     writtenTable = writeDLKcatInput(model, 'onlyWithSmiles', false);
    +
    + See also
    + --------
    + runDLKcat, readDLKcatOutput, extractEnzymeSubstratePairs
    + + +

    CROSS-REFERENCE INFORMATION ^

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

    SOURCE CODE ^

    +
    0001 function writtenTable = writeDLKcatInput(model, varargin)
    +0002 % writeDLKcatInput  Prepare and write the input file for DLKcat.
    +0003 %
    +0004 % Prepares the input for DLKcat, and writes it to data/DLKcat.tsv in the
    +0005 % obj.params.path specified in the ModelAdapter.
    +0006 %
    +0007 % Parameters
    +0008 % ----------
    +0009 % model : struct
    +0010 %     an ecModel in GECKO 3 format (with ecModel.ec structure).
    +0011 %
    +0012 % Name-Value Arguments
    +0013 % --------------------
    +0014 % ecRxns : logical
    +0015 %     for which reactions (from model.ec.rxns) DLKcat should predict kcat
    +0016 %     values, provided as logical vector with same length as model.ec.rxns
    +0017 %     (default: all reactions).
    +0018 % modelAdapter : ModelAdapter
    +0019 %     a loaded model adapter (default: the current default model adapter).
    +0020 % onlyWithSmiles : logical
    +0021 %     whether to only include metabolites with SMILES (default true).
    +0022 % filename : char
    +0023 %     path to the input file, including the filename and .tsv extension
    +0024 %     (default: data/DLKcat.tsv from the obj.params.path folder specified in
    +0025 %     the modelAdapter).
    +0026 % overwrite : logical
    +0027 %     whether existing file should be overwritten (default false, to prevent
    +0028 %     overwriting a file that already contains DLKcat-predicted kcat values).
    +0029 %
    +0030 % Returns
    +0031 % -------
    +0032 % writtenTable : cell
    +0033 %     the table written, mainly to be used for testing purposes.
    +0034 %
    +0035 % Examples
    +0036 % --------
    +0037 %     % optional arguments may be given positionally or as name-value pairs:
    +0038 %     writtenTable = writeDLKcatInput(model);
    +0039 %     writtenTable = writeDLKcatInput(model, 'onlyWithSmiles', false);
    +0040 %
    +0041 % See also
    +0042 % --------
    +0043 % runDLKcat, readDLKcatOutput, extractEnzymeSubstratePairs
    +0044 
    +0045 p = parseGECKOargs(varargin, { ...
    +0046     'ecRxns',         []; ...
    +0047     'modelAdapter',   []; ...
    +0048     'onlyWithSmiles', []; ...
    +0049     'filename',       []; ...
    +0050     'overwrite',      []});
    +0051 ecRxnsSel      = p.ecRxns;
    +0052 modelAdapter   = p.modelAdapter;
    +0053 onlyWithSmiles = p.onlyWithSmiles;
    +0054 filename       = p.filename;
    +0055 overwrite      = p.overwrite;
    +0056 
    +0057 if isempty(ecRxnsSel)
    +0058     ecRxnsSel = true(numel(model.ec.rxns),1);
    +0059 elseif ~logical(ecRxnsSel)
    +0060     error('ecRxns should be provided as logical vector')
    +0061 elseif numel(ecRxnsSel)~=numel(model.ec.rxns)
    +0062     error('Length of ecRxns is not the same as model.ec.rxns')
    +0063 end
    +0064 ecRxnsSel = find(ecRxnsSel); % Change to indices, into the full model.ec.rxns
    +0065 
    +0066 if isempty(modelAdapter)
    +0067     modelAdapter = ModelAdapterManager.getDefault();
    +0068     if isempty(modelAdapter)
    +0069         error('Either send in a modelAdapter or set the default model adapter in the ModelAdapterManager.')
    +0070     end
    +0071 end
    +0072 params = modelAdapter.params;
    +0073 
    +0074 if isempty(onlyWithSmiles)
    +0075     onlyWithSmiles=true;
    +0076 end
    +0077 
    +0078 if isempty(filename)
    +0079     filename = fullfile(params.path,'data','DLKcat.tsv');
    +0080 elseif ~endsWith(filename,'.tsv')
    +0081     error('If filename is provided, it should include the .tsv extension.')
    +0082 end
    +0083 
    +0084 if isempty(overwrite) || ~overwrite % If is true
    +0085     if exist(filename,'file')
    +0086         error([filename ' already exists, either delete it first, or set the overwrite input argument as true'])
    +0087     end
    +0088 end
    +0089 
    +0090 pairs = extractEnzymeSubstratePairs(model, 'ecRxns', ismember((1:numel(model.ec.rxns))', ecRxnsSel), ...
    +0091     'modelAdapter', modelAdapter);
    +0092 
    +0093 % Prepare output
    +0094 out(1,:) = model.ec.rxns(pairs.ecRxn);
    +0095 out(2,:) = model.ec.genes(pairs.protein);
    +0096 out(3,:) = model.metNames(pairs.met);
    +0097 if isfield(model,'metSmiles')
    +0098     out(4,:) = model.metSmiles(pairs.met);
    +0099 else
    +0100     out(4,:) = cell(numel(pairs.met),1);
    +0101 end
    +0102 
    +0103 out(5,:) = model.ec.sequence(pairs.protein);
    +0104 if onlyWithSmiles
    +0105     out(:,cellfun(@isempty,out(4,:))) = [];
    +0106 else
    +0107     out(4,cellfun(@isempty,out(4,:))) = {'None'};
    +0108 end
    +0109 out(6,:) = cell(numel(out(1,:)),1);
    +0110 out(6,:) = {'NA'};
    +0111 
    +0112 % Write file
    +0113 fID = fopen(filename,'w');
    +0114 fprintf(fID,'%s\t%s\t%s\t%s\t%s\t%s\n',out{:});
    +0115 fclose(fID);
    +0116 fprintf('Model-specific DLKcat input stored at %s\n',filename);
    +0117 
    +0118 writtenTable = out;
    +0119 end
    +
    Generated by m2html © 2005
    + + \ No newline at end of file diff --git a/doc/src/gather_kcats/writeOpenKineticsPredictorInput.html b/doc/src/gather_kcats/writeOpenKineticsPredictorInput.html new file mode 100644 index 00000000..4d7b9370 --- /dev/null +++ b/doc/src/gather_kcats/writeOpenKineticsPredictorInput.html @@ -0,0 +1,271 @@ + + + + Description of writeOpenKineticsPredictorInput + + + + + + + + + +
    Home > src > gather_kcats > writeOpenKineticsPredictorInput.m
    + + + +

    writeOpenKineticsPredictorInput +

    + +

    PURPOSE ^

    +
    writeOpenKineticsPredictorInput Write input file for OpenKineticsPredictor.
    + +

    SYNOPSIS ^

    +
    function writeOpenKineticsPredictorInput(model, varargin)
    + +

    DESCRIPTION ^

    +
     writeOpenKineticsPredictorInput  Write input file for OpenKineticsPredictor.
    +
    + Prepares input for OpenKineticsPredictor: protein sequences and single-
    + substrate SMILES, which allows the use of the following predictors: DLKcat;
    + EITLEM; UniKP; KinForm-H; KinForm-L; CataPro; CatPred.
    +
    + The function writes OKP.csv, that can be used as input file at
    + https://predictor.openkinetics.org/
    +
    + The OpenKineticsPredictor output file can be used to generate a kcatList
    + through readOpenKineticsPredictorOutput.
    +
    + Parameters
    + ----------
    + model : struct
    +     ecModel in GECKO 3 format (with ecModel.ec structure).
    +
    + Name-Value Arguments
    + --------------------
    + ecRxns : logical
    +     logical vector indicating which reactions to include (default: all
    +     reactions).
    + modelAdapter : ModelAdapter
    +     a loaded model adapter (default: the current default model adapter).
    + onlyWithSmiles : logical
    +     only include entries with SMILES (default true).
    + overwrite : logical
    +     overwrite existing file (default false).
    +
    + Examples
    + --------
    +     % optional arguments may be given positionally or as name-value pairs:
    +     writeOpenKineticsPredictorInput(model, ecRxns);
    +     writeOpenKineticsPredictorInput(model, 'onlyWithSmiles', false);
    +
    + See also
    + --------
    + readOpenKineticsPredictorOutput, writeDLKcatInput
    + + +

    CROSS-REFERENCE INFORMATION ^

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

    SOURCE CODE ^

    +
    0001 function writeOpenKineticsPredictorInput(model, varargin)
    +0002 % writeOpenKineticsPredictorInput  Write input file for OpenKineticsPredictor.
    +0003 %
    +0004 % Prepares input for OpenKineticsPredictor: protein sequences and single-
    +0005 % substrate SMILES, which allows the use of the following predictors: DLKcat;
    +0006 % EITLEM; UniKP; KinForm-H; KinForm-L; CataPro; CatPred.
    +0007 %
    +0008 % The function writes OKP.csv, that can be used as input file at
    +0009 % https://predictor.openkinetics.org/
    +0010 %
    +0011 % The OpenKineticsPredictor output file can be used to generate a kcatList
    +0012 % through readOpenKineticsPredictorOutput.
    +0013 %
    +0014 % Parameters
    +0015 % ----------
    +0016 % model : struct
    +0017 %     ecModel in GECKO 3 format (with ecModel.ec structure).
    +0018 %
    +0019 % Name-Value Arguments
    +0020 % --------------------
    +0021 % ecRxns : logical
    +0022 %     logical vector indicating which reactions to include (default: all
    +0023 %     reactions).
    +0024 % modelAdapter : ModelAdapter
    +0025 %     a loaded model adapter (default: the current default model adapter).
    +0026 % onlyWithSmiles : logical
    +0027 %     only include entries with SMILES (default true).
    +0028 % overwrite : logical
    +0029 %     overwrite existing file (default false).
    +0030 %
    +0031 % Examples
    +0032 % --------
    +0033 %     % optional arguments may be given positionally or as name-value pairs:
    +0034 %     writeOpenKineticsPredictorInput(model, ecRxns);
    +0035 %     writeOpenKineticsPredictorInput(model, 'onlyWithSmiles', false);
    +0036 %
    +0037 % See also
    +0038 % --------
    +0039 % readOpenKineticsPredictorOutput, writeDLKcatInput
    +0040 
    +0041 [geckoPath, ~] = findGECKOroot();
    +0042 
    +0043 %% Parse inputs
    +0044 p = parseGECKOargs(varargin, { ...
    +0045     'ecRxns',         []; ...
    +0046     'modelAdapter',   []; ...
    +0047     'onlyWithSmiles', []; ...
    +0048     'overwrite',      []});
    +0049 ecRxns         = p.ecRxns;
    +0050 modelAdapter   = p.modelAdapter;
    +0051 onlyWithSmiles = p.onlyWithSmiles;
    +0052 overwrite      = p.overwrite;
    +0053 
    +0054 if isempty(ecRxns)
    +0055     ecRxns = true(numel(model.ec.rxns),1);
    +0056 elseif ~islogical(ecRxns) || numel(ecRxns) ~= numel(model.ec.rxns)
    +0057     error('ecRxns should be a logical vector with length equal to model.ec.rxns')
    +0058 end
    +0059 
    +0060 if isempty(modelAdapter)
    +0061     modelAdapter = ModelAdapterManager.getDefault();
    +0062     if isempty(modelAdapter)
    +0063         error('Either provide a modelAdapter or set the default in ModelAdapterManager.')
    +0064     end
    +0065 end
    +0066 params = modelAdapter.params;
    +0067 
    +0068 if isempty(onlyWithSmiles)
    +0069     onlyWithSmiles = true;
    +0070 end
    +0071 
    +0072 if isempty(overwrite)
    +0073     overwrite = false;
    +0074 end
    +0075 
    +0076 %% Output files
    +0077 filename = fullfile(params.path,'data','OKP.csv');
    +0078 if ~overwrite && exist(filename,'file')
    +0079     error('%s already exists. Set overwrite=true to replace it.', filename)
    +0080 end
    +0081 
    +0082 %% Map ec.rxns to model.rxns
    +0083 if model.ec.geckoLight
    +0084    origRxns = extractAfter(model.ec.rxns, 4);
    +0085 else
    +0086    origRxns = model.ec.rxns;
    +0087 end
    +0088 
    +0089 ecRxnsIdx = find(ecRxns);
    +0090 [found, origRxnIdxs] = ismember(origRxns(ecRxnsIdx), model.rxns);
    +0091 if ~all(found)
    +0092     error('Not all reactions in model.ec.rxns found in model.rxns')
    +0093 end
    +0094 
    +0095 %% Build reduced stoichiometric matrix (ignore certain metabolites)
    +0096 % Load metabolites to ignore (reuses DLKcat files)
    +0097 if exist(fullfile(params.path,'data','DLKcatIgnoreMets.tsv'),'file')
    +0098     ignoreFile = fullfile(params.path,'data','DLKcatIgnoreMets.tsv');
    +0099 else
    +0100     ignoreFile = fullfile(geckoPath,'databases','DLKcatIgnoreMets.tsv');
    +0101 end
    +0102 fID = fopen(ignoreFile);
    +0103 fileData = textscan(fID,'%s %s','delimiter','\t');
    +0104 fclose(fID);
    +0105 [ignoreMets, ignoreSmiles] = deal(fileData{[1,2]});
    +0106 
    +0107 % Normalize metabolite names (remove special characters, lowercase)
    +0108 metsNorm        = lower(regexprep(model.metNames,'[^0-9a-zA-Z]+',''));
    +0109 ignoreMetsNorm  = lower(regexprep(ignoreMets,'[^0-9a-zA-Z]+',''));
    +0110 ignoreSmiles(cellfun(@isempty,ignoreSmiles)) = [];
    +0111 
    +0112 % Mark metabolites to ignore
    +0113 ignoreMetsIdx = ismember(metsNorm, ignoreMetsNorm);
    +0114 if isfield(model,'metSmiles')
    +0115     ignoreMetsIdx = ignoreMetsIdx | ismember(model.metSmiles, ignoreSmiles);
    +0116 end
    +0117 ignoreMetsIdx = ignoreMetsIdx | startsWith(model.mets,'prot_');
    +0118 
    +0119 reducedS = model.S;
    +0120 reducedS(ignoreMetsIdx,:) = 0;
    +0121 
    +0122 %% Remove currency metabolite pairs (reuses DLKcat files)
    +0123 if exist(fullfile(params.path,'data','DLKcatCurrencyMets.tsv'),'file')
    +0124     currencyFile = fullfile(params.path,'data','DLKcatCurrencyMets.tsv');
    +0125 else
    +0126     currencyFile = fullfile(geckoPath,'databases','DLKcatCurrencyMets.tsv');
    +0127 end
    +0128 fID = fopen(currencyFile);
    +0129 fileData = textscan(fID,'%s %s','delimiter','\t');
    +0130 fclose(fID);
    +0131 [currencyMets(:,1), currencyMets(:,2)] = deal(fileData{[1,2]});
    +0132 currencyMets = lower(regexprep(currencyMets,'[^0-9a-zA-Z]+',''));
    +0133 for i=1:size(currencyMets,1)
    +0134     subs = strcmp(currencyMets(i,1),metsNorm);
    +0135     prod = strcmp(currencyMets(i,2),metsNorm);
    +0136     [~,subsRxns]=find(reducedS(subs,:));
    +0137     [~,prodRxns]=find(reducedS(prod,:));
    +0138     pairRxns = intersect(subsRxns,prodRxns);
    +0139     tempRedS=reducedS;
    +0140     tempRedS([find(subs);find(prod)],pairRxns) = 0;
    +0141     % Do not remove currency mets if no substrate remains
    +0142     rxnsWithRemainingSubstrates = any(tempRedS(:,pairRxns) < 0,1);
    +0143     reducedS([find(subs);find(prod)],intersect(pairRxns,pairRxns(rxnsWithRemainingSubstrates))) = 0;
    +0144 end
    +0145 
    +0146 
    +0147 %% Extract substrates for selected reactions only
    +0148 clearedS = reducedS(:, origRxnIdxs);
    +0149 
    +0150 % Find all substrates (negative stoichiometry)
    +0151 [substrateIdxs, reactionIdxs] = find(clearedS < 0);
    +0152 
    +0153 % Find proteins catalyzing each reaction. reactionIdxs indexes clearedS's
    +0154 % columns, i.e. positions within the requested ecRxnsIdx subset -- map back
    +0155 % through ecRxnsIdx to the absolute model.ec.rxnEnzMat row before indexing it.
    +0156 [proteinIdxs, rxnEnzIdxs] = find(model.ec.rxnEnzMat(ecRxnsIdx(reactionIdxs),:)');
    +0157 
    +0158 %% Build output: sequence and SMILES
    +0159 sequences = model.ec.sequence(proteinIdxs);
    +0160 
    +0161 if isfield(model,'metSmiles')
    +0162     smiles = model.metSmiles(substrateIdxs(rxnEnzIdxs));
    +0163 else
    +0164     smiles = cell(size(sequences));
    +0165 end
    +0166 
    +0167 %% Filter empty entries
    +0168 if onlyWithSmiles
    +0169     valid = ~cellfun(@isempty, sequences) & ~cellfun(@isempty, smiles);
    +0170 else
    +0171     valid = ~cellfun(@isempty, sequences);
    +0172     smiles(cellfun(@isempty, smiles)) = {'None'};
    +0173 end
    +0174 
    +0175 sequences = sequences(valid);
    +0176 smiles = smiles(valid);
    +0177 
    +0178 %% Write output file
    +0179 % Sequence and SMILES
    +0180 outTable = [sequences(:)'; smiles(:)'];
    +0181 
    +0182 fID = fopen(filename,'w');
    +0183 fprintf(fID,'Protein Sequence,Substrate\n');
    +0184 fprintf(fID,'%s,%s\n', outTable{:});
    +0185 fclose(fID);
    +0186 fprintf('OpenKineticsPredictor input stored at %s\n', filename);
    +0187 end
    +
    Generated by m2html © 2005
    + + \ No newline at end of file diff --git a/doc/src/geckomat/change_model/applyComplexData.html b/doc/src/geckomat/change_model/applyComplexData.html deleted file mode 100644 index 7275ed19..00000000 --- a/doc/src/geckomat/change_model/applyComplexData.html +++ /dev/null @@ -1,249 +0,0 @@ - - - - Description of applyComplexData - - - - - - - - - -
    Home > src > geckomat > change_model > applyComplexData.m
    - - - -

    applyComplexData -

    - -

    PURPOSE ^

    -
    applyComplexData
    - -

    SYNOPSIS ^

    -
    function [model, foundComplex, proposedComplex] = applyComplexData(model, complexInfo, modelAdapter, verbose)
    - -

    DESCRIPTION ^

    -
     applyComplexData
    -   Apply stochiometry for complex in an ecModel
    -
    - Input:
    -   model           an ecModel in GECKO 3 format (with ecModel.ec structure)
    -   complexInfo     structure as generated by getComplexData. If nothing
    -                   is provided, an attempt will be made to read
    -                   data/ComplexPortal.json from the obj.params.path folder
    -                   specified in the modelAdapter.
    -   modelAdapter    a loaded model adapter (Optional, will otherwise use the
    -                   default model adapter).
    -   verbose         logical if a summary should be shown in the Command
    -                   Window (Optional, default true)
    -
    - Output:
    -   model           ecModel where model.ec.rxnEnzMat is populated with
    -                   subunit stochiometries
    -   foundComplex    complexes that fully matched between the model and the
    -                   complex data
    -   proposedComplex complexes where the model contained >75% but <100% of
    -                   the proteins indicated by Complex Portal, or where the
    -                   model contained more proteins than indicated for that
    -                   complex in Complex Portal.
    -
    - Usage:
    -   [model, foundComplex, proposedComplex] = applyComplexData(ecModel, complexInfo, modelAdapter);
    - - -

    CROSS-REFERENCE INFORMATION ^

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

    SOURCE CODE ^

    -
    0001 function [model, foundComplex, proposedComplex] = applyComplexData(model, complexInfo, modelAdapter, verbose)
    -0002 % applyComplexData
    -0003 %   Apply stochiometry for complex in an ecModel
    -0004 %
    -0005 % Input:
    -0006 %   model           an ecModel in GECKO 3 format (with ecModel.ec structure)
    -0007 %   complexInfo     structure as generated by getComplexData. If nothing
    -0008 %                   is provided, an attempt will be made to read
    -0009 %                   data/ComplexPortal.json from the obj.params.path folder
    -0010 %                   specified in the modelAdapter.
    -0011 %   modelAdapter    a loaded model adapter (Optional, will otherwise use the
    -0012 %                   default model adapter).
    -0013 %   verbose         logical if a summary should be shown in the Command
    -0014 %                   Window (Optional, default true)
    -0015 %
    -0016 % Output:
    -0017 %   model           ecModel where model.ec.rxnEnzMat is populated with
    -0018 %                   subunit stochiometries
    -0019 %   foundComplex    complexes that fully matched between the model and the
    -0020 %                   complex data
    -0021 %   proposedComplex complexes where the model contained >75% but <100% of
    -0022 %                   the proteins indicated by Complex Portal, or where the
    -0023 %                   model contained more proteins than indicated for that
    -0024 %                   complex in Complex Portal.
    -0025 %
    -0026 % Usage:
    -0027 %   [model, foundComplex, proposedComplex] = applyComplexData(ecModel, complexInfo, modelAdapter);
    -0028 
    -0029 if nargin < 4 || isempty(verbose)
    -0030     verbose = true;
    -0031 end
    -0032 
    -0033 if nargin < 3 || isempty(modelAdapter)
    -0034     modelAdapter = ModelAdapterManager.getDefault();
    -0035     if isempty(modelAdapter)
    -0036         error('Either send in a modelAdapter or set the default model adapter in the ModelAdapterManager.')
    -0037     end
    -0038 end
    -0039 params = modelAdapter.params;
    -0040 
    -0041 if nargin<2 || isempty(complexInfo)
    -0042     complexInfo = fullfile(params.path,'data','ComplexPortal.json');
    -0043     if ~isfile(complexInfo)
    -0044         complexInfo = getComplexData([], modelAdapter);
    -0045     end
    -0046 end
    -0047 
    -0048 if ischar(complexInfo) || isstring(complexInfo)
    -0049     jsonStr = fileread(complexInfo);
    -0050     complexData = jsondecode(jsonStr);
    -0051 else
    -0052     complexData = complexInfo;
    -0053 end
    -0054 
    -0055 %Remove prefixes on rxn names for gecko light
    -0056 if ~model.ec.geckoLight
    -0057     rxnNames = model.ec.rxns;
    -0058 else
    -0059     rxnNames = extractAfter(model.ec.rxns,4);
    -0060 end
    -0061 
    -0062 foundComplex = cell(numel(rxnNames),7);
    -0063 foundComplexCount = 0;
    -0064 proposedComplex = cell(numel(rxnNames)*2,8); % Might propose more
    -0065 proposedComplexCount = 0;
    -0066 
    -0067 complexProts = repmat({''}, numel({complexData.complexID})*10, 1);
    -0068 complexMatrix = zeros(numel({complexData.complexID}),numel(complexProts));
    -0069 lastProt = 0;
    -0070 for i=1:size(complexMatrix,1)
    -0071     % Locate proteins (and add if new)
    -0072     protIDs     = complexData(i).protID;
    -0073     [isOld, protMatIdx] = ismember(protIDs,complexProts);
    -0074     newProts    = protIDs(~isOld);
    -0075     complexProts(lastProt+1:lastProt+numel(newProts))=newProts;
    -0076     protMatIdx(~isOld)  = lastProt+1 : lastProt+numel(newProts);
    -0077     lastProt = lastProt + numel(newProts);
    -0078     % Add subunit numbers
    -0079     if all(complexData(i).stochiometry == 0)
    -0080         complexData(i).stochiometry(:) = 1;
    -0081     end
    -0082     complexMatrix(i,protMatIdx) = complexData(i).stochiometry;
    -0083 end
    -0084 
    -0085 % Remove excess space
    -0086 complexMatrix(:,lastProt+1:end) = [];
    -0087 complexProts(lastProt+1:end) = [];
    -0088 progressbar('Assign complexes to reactions')
    -0089 for i = 1:numel(rxnNames)
    -0090     % Get the proteins from the model
    -0091     modelProts = model.ec.enzymes(find(model.ec.rxnEnzMat(i,:)));
    -0092     [protsInMat, protsIdx] = ismember(modelProts,complexProts);
    -0093     if ~any(protsInMat)
    -0094         continue
    -0095     end
    -0096     % Find complexes that includes the model proteins
    -0097     [potComplex,~] = find(complexMatrix(:,protsIdx(protsInMat)));
    -0098     potComplex = unique(potComplex);
    -0099     % Some stats on number of subunits, percentage match etc.
    -0100     matchComplexUnits = sum(logical(complexMatrix(potComplex,protsIdx(protsInMat))),2);
    -0101     totalComplexUnits = sum(logical(complexMatrix(potComplex,:)),2);
    -0102     modComplexUnits = numel(modelProts);
    -0103     percMatch  = matchComplexUnits/modComplexUnits;
    -0104     totalMatch = totalComplexUnits/modComplexUnits;
    -0105     if any(percMatch == 1 & totalMatch == 1)
    -0106         % Exact match
    -0107         complexMatch = find(percMatch == 1 & totalMatch == 1);
    -0108         if numel(complexMatch)>1 % If more than one match, take first match
    -0109             complexMatch = complexMatch(1);
    -0110         end
    -0111         complexMatch = potComplex(complexMatch);
    -0112         foundComplexCount = foundComplexCount + 1;
    -0113         foundComplex{foundComplexCount,1} = model.ec.rxns{i};
    -0114         foundComplex{foundComplexCount,2} = complexData(complexMatch).complexID;
    -0115         foundComplex{foundComplexCount,3} = complexData(complexMatch).name;
    -0116         foundComplex{foundComplexCount,4} = complexData(complexMatch).geneName;
    -0117         foundComplex{foundComplexCount,5} = modelProts;
    -0118         foundComplex{foundComplexCount,6} = complexData(complexMatch).protID;
    -0119         foundComplex{foundComplexCount,7} = complexData(complexMatch).stochiometry;
    -0120 
    -0121         % Apply in rxnEnzMat
    -0122         [~, modelProtsIdx] = ismember(modelProts, model.ec.enzymes);
    -0123         model.ec.rxnEnzMat(i,modelProtsIdx) = complexData(complexMatch).stochiometry;
    -0124     
    -0125     elseif modComplexUnits > 1 % Only suggest potential complex if grRule > 1 protein
    -0126         moreUnitsInData = find(percMatch == 1 & totalMatch > 1);
    -0127         if any(moreUnitsInData)
    -0128             % All ecModel subunits match, but Complex Portal has more subunits
    -0129             % Take the complex with the minimum number of extra subunits
    -0130             [~,propComplex] = min(totalMatch(moreUnitsInData));
    -0131             propComplex     = moreUnitsInData(propComplex);
    -0132             selectComplex   = potComplex(propComplex);
    -0133             proposedComplexCount = proposedComplexCount + 1;
    -0134             proposedComplex{proposedComplexCount,1} = model.ec.rxns{i};
    -0135             proposedComplex{proposedComplexCount,2} = complexData(selectComplex).complexID;
    -0136             proposedComplex{proposedComplexCount,3} = complexData(selectComplex).name;
    -0137             proposedComplex{proposedComplexCount,4} = complexData(selectComplex).geneName;
    -0138             proposedComplex{proposedComplexCount,5} = modelProts;
    -0139             proposedComplex{proposedComplexCount,6} = complexData(selectComplex).protID;
    -0140             proposedComplex{proposedComplexCount,7} = complexData(selectComplex).stochiometry;
    -0141             proposedComplex{proposedComplexCount,8} = totalMatch(propComplex)*100;
    -0142         end
    -0143         otherUnits = find(percMatch >= 0.75 & percMatch < 1 & totalMatch <= 1);
    -0144         if any(otherUnits)
    -0145             % At least 75% of ecModels subunits match, Complex Portal maybe have less or different subunits
    -0146             % Take the complex with highest % match.
    -0147             [~,propComplex] = max(percMatch(otherUnits));
    -0148             propComplex     = otherUnits(propComplex);
    -0149             selectComplex   = potComplex(propComplex);
    -0150             proposedComplexCount = proposedComplexCount + 1;
    -0151             proposedComplex{proposedComplexCount,1} = model.ec.rxns{i};
    -0152             proposedComplex{proposedComplexCount,2} = complexData(selectComplex).complexID;
    -0153             proposedComplex{proposedComplexCount,3} = complexData(selectComplex).name;
    -0154             proposedComplex{proposedComplexCount,4} = complexData(selectComplex).geneName;
    -0155             proposedComplex{proposedComplexCount,5} = modelProts;
    -0156             proposedComplex{proposedComplexCount,6} = complexData(selectComplex).protID;
    -0157             proposedComplex{proposedComplexCount,7} = complexData(selectComplex).stochiometry;
    -0158             proposedComplex{proposedComplexCount,8} = percMatch(propComplex)*100;
    -0159         end
    -0160     end
    -0161     progressbar(i/numel(rxnNames))    
    -0162 end
    -0163 progressbar(1) % Make sure it closes
    -0164 
    -0165 % Remove empty space
    -0166 foundComplex(foundComplexCount+1:end,:) = [];
    -0167 proposedComplex(proposedComplexCount+1:end,:) = [];
    -0168 
    -0169 rowHeadings = {'rxn', 'complexID','name','genes','protID_model','protID_complex','stochiometry'};
    -0170 
    -0171 foundComplex = cell2table(foundComplex, 'VariableNames', rowHeadings);
    -0172 
    -0173 proposedComplex = cell2table(proposedComplex, 'VariableNames', [rowHeadings 'match']);
    -0174 if verbose
    -0175     disp(['A total of ' int2str(numel(foundComplex(:,1))) ' complex have full match, and ' int2str(numel(proposedComplex(:,1))) ' proposed.'])
    -0176 end
    -0177 end
    -
    Generated by m2html © 2005
    - - \ No newline at end of file diff --git a/doc/src/geckomat/change_model/applyCustomKcats.html b/doc/src/geckomat/change_model/applyCustomKcats.html deleted file mode 100644 index 05122e7b..00000000 --- a/doc/src/geckomat/change_model/applyCustomKcats.html +++ /dev/null @@ -1,313 +0,0 @@ - - - - Description of applyCustomKcats - - - - - - - - - -
    Home > src > geckomat > change_model > applyCustomKcats.m
    - - - -

    applyCustomKcats -

    - -

    PURPOSE ^

    -
    applyCustomKcats
    - -

    SYNOPSIS ^

    -
    function [model, rxnUpdated, notMatch] = applyCustomKcats(model, customKcats, modelAdapter)
    - -

    DESCRIPTION ^

    -
     applyCustomKcats
    -   Apply user defined kcats.  Reads data/customKcats.tsv in the obj.params.path
    -   specified in the model adapter. Alternatively, a customKcats structure can
    -   provided, as specified below.
    -
    - Input:
    -   model           an ecModel in GECKO 3 format (with ecModel.ec structure)
    -   customKcats     structure with custom kcat information. If nothing
    -                   is provided, an attempt will be made to read
    -                   data/customKcats.tsv from the obj.params.path folder
    -                   specified in the modelAdapter.
    -   modelAdapter    a loaded model adapter (Optional, will otherwise use the
    -                   default model adapter).
    -
    - Output:
    -   model           ecModel where kcats for defined proteins have been
    -                   changed
    -   rxnUpdated      ids list of updated reactions, new kcats were applied
    -   notMatch        table with the list of reactions which the custom
    -                   information provided does not have full match (> 50%)
    -                   based on GPR rules. Then, they are suggested to be
    -                   curated by the user
    -
    -   customKcats structure:
    -   - proteins    protein identifiers, multiple for the same kcat (in case
    -                 of a protein complex) are separated by ' + '
    -   - genes       gene identifiers (optional, not used in matching)
    -   - gene_name   short gene name (optional, not used in matching)
    -   - kcat        new kcat value (one per entry)
    -   - rxns        reaction identifiers, multiple for the same kcat are
    -                 separated by ',' (see further explanation below)
    -   - notes       will be appended to model.ec.notes (optional)
    -   - stoicho     complex stoichiometry, separated by ' + ' (examples: '1'
    -                 or '3 + 1'), matching the order in proteins field
    -   
    -   Matching order:
    -   (1) reactions are identified by .proteins and .rxns
    -   (2) reactions are identified by .proteins only (empty .rxns entry)
    -       no additional checks are made: is a reaction annotated with these
    -       proteins? => its kcat will be updated, irrespective of the exact
    -       reaction, direction, substrate, etc.
    -   (3) reactions are identified by .rxns only (empty .proteins entry)
    -       no additional checks are made: is a reaction derived from the
    -       original reaction identifier => its kcat will be updated,
    -       irrespective of the annotated protein
    -
    -   customKcats.rxns field:
    -   The reaction identifiers are from the ORIGINAL model, before _EXP_
    -   suffixes were added by makeEcModel. Reaction directionality IS however
    -   specified, with a _REV suffix.
    -   Example entries:
    -   'r_0001'     will match r_0001, r_0001_EXP_1, r_0001_EXP_2 etc., but
    -                not r_0001_REV, r_0001_EXP_1_REV etc.
    -   'r_0001_REV' will match r_0001_REV, r_0001_EXP_1_REV, r_0001_EXP_2_REV,
    -                etc., but not r_0001, r_0001_EXP_1 etc.
    -   Multiple identifiers should be comma separated (e.g. r_0001, r_0002)
    -
    - Usage:
    -   [model, rxnUpdated, notMatch] = applyCustomKcats(model, customKcats, modelAdapter);
    - - -

    CROSS-REFERENCE INFORMATION ^

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

    SOURCE CODE ^

    -
    0001 function [model, rxnUpdated, notMatch] = applyCustomKcats(model, customKcats, modelAdapter)
    -0002 % applyCustomKcats
    -0003 %   Apply user defined kcats.  Reads data/customKcats.tsv in the obj.params.path
    -0004 %   specified in the model adapter. Alternatively, a customKcats structure can
    -0005 %   provided, as specified below.
    -0006 %
    -0007 % Input:
    -0008 %   model           an ecModel in GECKO 3 format (with ecModel.ec structure)
    -0009 %   customKcats     structure with custom kcat information. If nothing
    -0010 %                   is provided, an attempt will be made to read
    -0011 %                   data/customKcats.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 %   model           ecModel where kcats for defined proteins have been
    -0018 %                   changed
    -0019 %   rxnUpdated      ids list of updated reactions, new kcats were applied
    -0020 %   notMatch        table with the list of reactions which the custom
    -0021 %                   information provided does not have full match (> 50%)
    -0022 %                   based on GPR rules. Then, they are suggested to be
    -0023 %                   curated by the user
    -0024 %
    -0025 %   customKcats structure:
    -0026 %   - proteins    protein identifiers, multiple for the same kcat (in case
    -0027 %                 of a protein complex) are separated by ' + '
    -0028 %   - genes       gene identifiers (optional, not used in matching)
    -0029 %   - gene_name   short gene name (optional, not used in matching)
    -0030 %   - kcat        new kcat value (one per entry)
    -0031 %   - rxns        reaction identifiers, multiple for the same kcat are
    -0032 %                 separated by ',' (see further explanation below)
    -0033 %   - notes       will be appended to model.ec.notes (optional)
    -0034 %   - stoicho     complex stoichiometry, separated by ' + ' (examples: '1'
    -0035 %                 or '3 + 1'), matching the order in proteins field
    -0036 %
    -0037 %   Matching order:
    -0038 %   (1) reactions are identified by .proteins and .rxns
    -0039 %   (2) reactions are identified by .proteins only (empty .rxns entry)
    -0040 %       no additional checks are made: is a reaction annotated with these
    -0041 %       proteins? => its kcat will be updated, irrespective of the exact
    -0042 %       reaction, direction, substrate, etc.
    -0043 %   (3) reactions are identified by .rxns only (empty .proteins entry)
    -0044 %       no additional checks are made: is a reaction derived from the
    -0045 %       original reaction identifier => its kcat will be updated,
    -0046 %       irrespective of the annotated protein
    -0047 %
    -0048 %   customKcats.rxns field:
    -0049 %   The reaction identifiers are from the ORIGINAL model, before _EXP_
    -0050 %   suffixes were added by makeEcModel. Reaction directionality IS however
    -0051 %   specified, with a _REV suffix.
    -0052 %   Example entries:
    -0053 %   'r_0001'     will match r_0001, r_0001_EXP_1, r_0001_EXP_2 etc., but
    -0054 %                not r_0001_REV, r_0001_EXP_1_REV etc.
    -0055 %   'r_0001_REV' will match r_0001_REV, r_0001_EXP_1_REV, r_0001_EXP_2_REV,
    -0056 %                etc., but not r_0001, r_0001_EXP_1 etc.
    -0057 %   Multiple identifiers should be comma separated (e.g. r_0001, r_0002)
    -0058 %
    -0059 % Usage:
    -0060 %   [model, rxnUpdated, notMatch] = applyCustomKcats(model, customKcats, modelAdapter);
    -0061 
    -0062 if nargin < 3 || isempty(modelAdapter)
    -0063     modelAdapter = ModelAdapterManager.getDefault();
    -0064     if isempty(modelAdapter)
    -0065         error('Either send in a modelAdapter or set the default model adapter in the ModelAdapterManager.')
    -0066     end
    -0067 end
    -0068 
    -0069 params = modelAdapter.params;
    -0070 
    -0071 if nargin<2 || isempty(customKcats)
    -0072     customKcats = fullfile(params.path,'data','customKcats.tsv');
    -0073 end
    -0074 if isstruct(customKcats)
    -0075     if ~all(isfield(customKcats,{'proteins','kcat','rxns'}))
    -0076         error('The customKcats structure does not have all essential fields.');
    -0077     end
    -0078 elseif isfile(customKcats)
    -0079     fID = fopen(customKcats, 'r');
    -0080     fileContent = textscan(fID, '%s %s %s %f %q %s %s', 'Delimiter', '\t', 'HeaderLines', 1);
    -0081     fclose(fID);
    -0082     clear customKcats
    -0083     customKcats.proteins    = fileContent{1};
    -0084     customKcats.genes       = fileContent{2};
    -0085     customKcats.gene_name   = fileContent{3};
    -0086     customKcats.kcat        = fileContent{4};
    -0087     customKcats.rxns        = fileContent{5};
    -0088     customKcats.notes       = fileContent{6};
    -0089     customKcats.stoicho     = fileContent{7};
    -0090 else
    -0091     error(['Cannot find file: ' customKcats]);
    -0092 end
    -0093 
    -0094 rxnToUpdate = false(length(model.ec.rxns),1);
    -0095 rxnNotMatch = false(length(model.ec.rxns),1);
    -0096 evaluatedRule = cell(length(model.ec.rxns),1);
    -0097 enzInModel = cell(length(model.ec.rxns),1);
    -0098 ecRxnNoSuffix = regexprep(model.ec.rxns,'_EXP_\d+$','');
    -0099 
    -0100 % Implementation for full GECKO formulation
    -0101 if ~model.ec.geckoLight
    -0102     for i = 1:numel(customKcats.proteins)
    -0103         if isempty(customKcats.proteins{i})
    -0104             %If only reaction ID(s) is/are specified (and no proteins),
    -0105             %then apply the kcat to all isozymic reactions
    -0106             rxns    = strtrim(strsplit(customKcats.rxns{i}, ','));
    -0107             rxnIdxs = ismember(ecRxnNoSuffix,rxns);
    -0108             rxnToUpdate(rxnIdxs) = 1;
    -0109             model.ec.kcat(rxnIdxs) = customKcats.kcat(i);
    -0110         else
    -0111             prots = strtrim(strsplit(customKcats.proteins{i}, '+'));
    -0112 
    -0113             % Find the index for the enzymes which kcat will be changed. In
    -0114             % case the protein is not in the model generate a warning.
    -0115             try
    -0116                 enzIdx = cellfun(@(x) find(strcmpi(model.ec.enzymes, x)), prots);
    -0117             catch
    -0118                 enzIdx = [];
    -0119                 printOrange(['WARNING: Protein(s) ' customKcats.proteins{i} ' were not found in the model.']);
    -0120             end
    -0121 
    -0122             % if not specific reactions are defined, find all the reaction
    -0123             % index where the enzyme is used
    -0124             if isempty(customKcats.rxns{i})
    -0125                 temp_rxnIdxs = arrayfun(@(x) find(model.ec.rxnEnzMat(:, x)), enzIdx, 'UniformOutput', false);
    -0126                 % otherwhise, If a set of reactions if defined, only get the index for those
    -0127                 % but ignore any _EXP_ suffixes
    -0128             else
    -0129                 rxns = strtrim(strsplit(customKcats.rxns{i}, ','));
    -0130                 temp_rxnIdxs = arrayfun(@(x) find(strcmpi(ecRxnNoSuffix, x)), rxns, 'UniformOutput', false);
    -0131             end
    -0132 
    -0133             if ~isempty(temp_rxnIdxs)
    -0134                 rxnIdxs = [];
    -0135                 for j = 1:numel(temp_rxnIdxs)
    -0136                     rxnIdxs = [rxnIdxs; temp_rxnIdxs{j}];
    -0137                 end
    -0138 
    -0139                 % Check when multiple proteins are involved, since it can return same rxn n times
    -0140                 rxnIdxs = unique(rxnIdxs); %unique(rxnIdxs{1, :});
    -0141 
    -0142                 for j = 1:numel(rxnIdxs)
    -0143                     % Get all the enzymes involved in the reaction
    -0144                     allEnzInRxn = find(model.ec.rxnEnzMat(rxnIdxs(j),:));
    -0145 
    -0146                     C = intersect(enzIdx, allEnzInRxn);
    -0147 
    -0148                     % Determine the match percentage bewteen the rules
    -0149                     if numel(C) == numel(enzIdx) && numel(C) == numel(allEnzInRxn)
    -0150                         match = 1;
    -0151                     else
    -0152                         if numel(enzIdx) < numel(allEnzInRxn)
    -0153                             match = numel(C) / numel(allEnzInRxn);
    -0154                         else
    -0155                             match = numel(C) / numel(enzIdx);
    -0156                         end
    -0157                     end
    -0158 
    -0159                     % Update the kcat value stored in the model, if match 100%,
    -0160                     % otherwhise if >= 0.5 inform to the user to be validated
    -0161                     if match == 1
    -0162                         rxnToUpdate(rxnIdxs(j)) = 1;
    -0163                         model.ec.kcat(rxnIdxs(j)) = customKcats.kcat(i);
    -0164 
    -0165                         % Add note mentioning manual kcat change
    -0166                         model.ec.source{rxnIdxs(j),1} = 'custom';
    -0167                         if isfield(customKcats,'notes')
    -0168                             if isempty(model.ec.notes{rxnIdxs(j), 1}) && ~isempty(customKcats.notes{i})
    -0169                                 model.ec.notes{rxnIdxs(j), 1} = customKcats.notes{i};
    -0170                             else
    -0171                                 model.ec.notes{rxnIdxs(j), 1} = [model.ec.notes{rxnIdxs(j), 1} ', ' customKcats.notes{i}];
    -0172                             end
    -0173                         end
    -0174                     elseif match >= 0.5 && match < 1
    -0175                         rxnNotMatch(rxnIdxs(j)) = 1;
    -0176                         evaluatedRule{rxnIdxs(j), 1} = customKcats.proteins{i};
    -0177                         enzInModel{rxnIdxs(j), 1} = strjoin(model.ec.enzymes(allEnzInRxn), ' + ');
    -0178                     end
    -0179                 end
    -0180             end
    -0181         end
    -0182     end
    -0183 
    -0184     % Apply the new kcat values to the model
    -0185     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.');
    -0189     end
    -0190 
    -0191     rxnUpdated = model.ec.rxns(find(rxnToUpdate));
    -0192 
    -0193     % Remove from notMatch those reactions already updated
    -0194     remove = and(rxnToUpdate, rxnNotMatch);
    -0195     rxnNotMatch(remove) = 0;
    -0196     evaluatedRule(remove) = '';
    -0197     enzInModel(remove) = '';
    -0198 
    -0199     idRxns = model.ec.rxns(find(rxnNotMatch));
    -0200     fullIdx = cellfun(@(x) find(strcmpi(model.rxns, x)), idRxns);
    -0201     rxnsNames = model.rxnNames(fullIdx);
    -0202     evaluatedRule = evaluatedRule(~cellfun('isempty', evaluatedRule));
    -0203     enzInModel = enzInModel(~cellfun('isempty', enzInModel));
    -0204     rules = model.grRules(fullIdx);
    -0205     notMatch = table(idRxns, rxnsNames, evaluatedRule, enzInModel, rules, ...
    -0206         'VariableNames',{'rxns', 'name', 'custom enzymes', 'enzymes in model', 'rules'});
    -0207 end
    -0208 end
    -
    Generated by m2html © 2005
    - - \ No newline at end of file diff --git a/doc/src/geckomat/change_model/applyKcatConstraints.html b/doc/src/geckomat/change_model/applyKcatConstraints.html deleted file mode 100644 index a36e0e3b..00000000 --- a/doc/src/geckomat/change_model/applyKcatConstraints.html +++ /dev/null @@ -1,183 +0,0 @@ - - - - Description of applyKcatConstraints - - - - - - - - - -
    Home > src > geckomat > change_model > applyKcatConstraints.m
    - - - -

    applyKcatConstraints -

    - -

    PURPOSE ^

    -
    applyKcatConstraints
    - -

    SYNOPSIS ^

    -
    function model = applyKcatConstraints(model,updateRxns)
    - -

    DESCRIPTION ^

    -
     applyKcatConstraints
    -   Applies kcat-derived enzyme constraints to an ecModel. Existing enzyme
    -   constraints are first removed (unless updateRxns is provided), and new
    -   constraints are defined based on the content of model.ec.kcat.
    -
    - Input:
    -   model       an ecModel in GECKO 3 format (with ecModel.ec structure)
    -   updateRxns  if not all enzyme constraints should be updated, this can
    -               be given as either a logical vector of length
    -               model.ec.rxns, a vector of model.ec.rxns indices, or a
    -               (cell array of) string(s) with model.ec.rxns identifiers.
    -               For light models, these reactions should match model.rxns.
    -
    - Output:
    -   model       ecModel where reactions are constrained by enzyme usage
    -               if a kcat value was provided for the reaction-enzyme pair
    -               in model.ec.kcat
    -
    - Usage: model = applyKcatConstraints(model,updateRxns);
    - - -

    CROSS-REFERENCE INFORMATION ^

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

    SOURCE CODE ^

    -
    0001 function model = applyKcatConstraints(model,updateRxns)
    -0002 % applyKcatConstraints
    -0003 %   Applies kcat-derived enzyme constraints to an ecModel. Existing enzyme
    -0004 %   constraints are first removed (unless updateRxns is provided), and new
    -0005 %   constraints are defined based on the content of model.ec.kcat.
    -0006 %
    -0007 % Input:
    -0008 %   model       an ecModel in GECKO 3 format (with ecModel.ec structure)
    -0009 %   updateRxns  if not all enzyme constraints should be updated, this can
    -0010 %               be given as either a logical vector of length
    -0011 %               model.ec.rxns, a vector of model.ec.rxns indices, or a
    -0012 %               (cell array of) string(s) with model.ec.rxns identifiers.
    -0013 %               For light models, these reactions should match model.rxns.
    -0014 %
    -0015 % Output:
    -0016 %   model       ecModel where reactions are constrained by enzyme usage
    -0017 %               if a kcat value was provided for the reaction-enzyme pair
    -0018 %               in model.ec.kcat
    -0019 %
    -0020 % Usage: model = applyKcatConstraints(model,updateRxns);
    -0021 
    -0022 %these lines are for the nargin lines below only
    -0023 if (model.ec.geckoLight)
    -0024     rxns = model.rxns;
    -0025 else
    -0026     rxns = model.ec.rxns;
    -0027 end
    -0028 
    -0029 if nargin<2
    -0030     updateRxns = true(numel(rxns),1);
    -0031 elseif isnumeric(updateRxns)
    -0032     updateRxnsLog = false(numel(rxns),1);
    -0033     updateRxnsLog(updateRxns) = true;
    -0034     updateRxns = updateRxnsLog;
    -0035 elseif iscellstr(updateRxns) || ischar(updateRxns) || isstring(updateRxns)
    -0036     updateRxnsIds = convertCharArray(updateRxns);
    -0037     updateRxns = ismember(rxns,updateRxnsIds);
    -0038 end
    -0039  
    -0040 if isempty(find(updateRxns, 1)) || isempty(updateRxns)
    -0041      error('No reaction to update or updateRxns is logical but without any true value')
    -0042 end
    -0043 
    -0044 if ~isfield(model,'ec')
    -0045     error(['No model.ec structure could be found: the provided model is'...
    -0046            ' 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');
    -0050     return
    -0051 end
    -0052 
    -0053 %Clear existing incorporation of enzyme usage
    -0054 if ~model.ec.geckoLight
    -0055     protMetIdx = startsWith(model.mets,'prot_') & ~strcmp(model.mets,'prot_pool');
    -0056     metabolRxn = unique(model.ec.rxns(updateRxns));
    -0057     metabolRxn = ismember(model.rxns,metabolRxn);
    -0058     model.S(protMetIdx,metabolRxn) = 0;
    -0059 end %no clearing needed for GECKO Light, will be overwritten below
    -0060 %For normal GECKO formulation (full model), where each enzyme is explicitly considered
    -0061 if ~model.ec.geckoLight 
    -0062     %Column 1 = rxn idx; 2 = enzyme idx; 3 = subunit copies; 4 = kcat; 5 = MW
    -0063     newKcats=zeros(numel(updateRxns)*10,5);
    -0064     updateRxns=find(updateRxns);
    -0065     kcatFirst=0;
    -0066     for i=1:numel(updateRxns)
    -0067         j=updateRxns(i);
    -0068         if model.ec.kcat(j) ~= 0
    -0069             enzymes   = find(model.ec.rxnEnzMat(j,:));
    -0070             kcatLast  = kcatFirst+numel(enzymes);
    -0071             kcatFirst = kcatFirst+1;
    -0072             newKcats(kcatFirst:kcatLast,1) = j;
    -0073             newKcats(kcatFirst:kcatLast,2) = enzymes;
    -0074             newKcats(kcatFirst:kcatLast,3) = model.ec.rxnEnzMat(j,enzymes);
    -0075             newKcats(kcatFirst:kcatLast,4) = model.ec.kcat(j);
    -0076             newKcats(kcatFirst:kcatLast,5) = model.ec.mw(enzymes);
    -0077             kcatFirst = kcatLast;
    -0078         end
    -0079     end
    -0080     if exist('kcatLast','var') % If it does not, then no kcats are found
    -0081         newKcats(kcatLast+1:end,:)=[];
    -0082 
    -0083         sel = newKcats(:,4) > 0; %Only apply to non-zero kcat
    -0084         newKcats(sel,4) = newKcats(sel,4) * 3600; %per second -> per hour
    -0085         newKcats(sel,4) = newKcats(sel,5) ./ newKcats(sel,4); %MW/kcat
    -0086         newKcats(sel,4) = newKcats(sel,3) .* newKcats(sel,4); %Multicopy subunits.
    -0087         newKcats(~sel,4) = 0; %Results in zero-cost
    -0088 
    -0089         %Replace rxns and enzymes with their location in model
    -0090         [~,newKcats(:,1)] = ismember(model.ec.rxns(newKcats(:,1)),model.rxns);
    -0091         [~,newKcats(:,2)] = ismember(strcat('prot_',model.ec.enzymes(newKcats(:,2))),model.mets);
    -0092         linearIndices     = sub2ind(size(model.S),newKcats(:,2),newKcats(:,1));
    -0093         model.S(linearIndices) = -newKcats(:,4); %Substrate = negative
    -0094     end
    -0095 else %GECKO light formulation, where prot_pool represents all usages
    -0096     prot_pool_idx = find(ismember(model.mets,'prot_pool'));
    -0097     %first remove the prefix of all rxns
    -0098     modRxns     = extractAfter(model.ec.rxns,4);
    -0099     % Map ec-reactions to model.rxns
    -0100     [hasEc,~]   = ismember(model.rxns,modRxns);
    -0101     hasEc       = find(hasEc & updateRxns);
    -0102     [~,rxnIdx]   = ismember(modRxns,model.rxns);
    -0103     for i = 1:numel(hasEc)
    -0104         % Get all isozymes per reaction
    -0105         ecIdx = find(rxnIdx == hasEc(i));
    -0106         % ecIdx = strcmp(model.rxns(hasEc(i)),modRxns);
    -0107         % Multiply enzymes with their MW (they are then automatically
    -0108         % summed per reaction), and divide by their kcat, to get a vector
    -0109         % of MW/kcat values.
    -0110         MWkcat = (model.ec.rxnEnzMat(ecIdx,:) * model.ec.mw) ./ model.ec.kcat(ecIdx);
    -0111         % If kcat was zero, MWkcat is Inf. If no enzyme info was found,
    -0112         % MWkcat is NaN. Correct both back to zero
    -0113         MWkcat(isinf(MWkcat) | isnan(MWkcat)) = 0;
    -0114         % Select the lowest MW/kcat (= most efficient), and convert to /hour
    -0115         model.S(prot_pool_idx, hasEc(i)) = -min(MWkcat/3600);
    -0116     end
    -0117 end
    -0118 end
    -
    Generated by m2html © 2005
    - - \ No newline at end of file diff --git a/doc/src/geckomat/change_model/findMetSmiles.html b/doc/src/geckomat/change_model/findMetSmiles.html deleted file mode 100644 index afe8697b..00000000 --- a/doc/src/geckomat/change_model/findMetSmiles.html +++ /dev/null @@ -1,170 +0,0 @@ - - - - Description of findMetSmiles - - - - - - - - - -
    Home > src > geckomat > change_model > findMetSmiles.m
    - - - -

    findMetSmiles -

    - -

    PURPOSE ^

    -
    findMetSMILES
    - -

    SYNOPSIS ^

    -
    function [model,noSMILES] = findMetSmiles(model, modelAdapter, verbose)
    - -

    DESCRIPTION ^

    -
     findMetSMILES
    -   Queries PubChem by metabolite names to obtain SMILES. Matches will also
    -   be stored in tutorials/***/data/smilesDB.tsv, that will also be queried
    -   first next time the function is run. If the model already has a
    -   metSmiles field, then non-empty entries will not be overwritten.
    -
    - Input:
    -   model        a model whose metNames field is used to find the relevant SMILES
    -   modelAdapter a loaded model adapter (Optional, will otherwise use the
    -                default model adapter).
    -   verbose      logical whether progress should be reported (Optional,
    -                default true)
    - Ouput:
    -   model        model with model.metSmiles specified.
    -   noSMILES     metabolite names for which no SMILES could be found.
    - - -

    CROSS-REFERENCE INFORMATION ^

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

    SOURCE CODE ^

    -
    0001 function [model,noSMILES] = findMetSmiles(model, modelAdapter, verbose)
    -0002 % findMetSMILES
    -0003 %   Queries PubChem by metabolite names to obtain SMILES. Matches will also
    -0004 %   be stored in tutorials/***/data/smilesDB.tsv, that will also be queried
    -0005 %   first next time the function is run. If the model already has a
    -0006 %   metSmiles field, then non-empty entries will not be overwritten.
    -0007 %
    -0008 % Input:
    -0009 %   model        a model whose metNames field is used to find the relevant SMILES
    -0010 %   modelAdapter a loaded model adapter (Optional, will otherwise use the
    -0011 %                default model adapter).
    -0012 %   verbose      logical whether progress should be reported (Optional,
    -0013 %                default true)
    -0014 % Ouput:
    -0015 %   model        model with model.metSmiles specified.
    -0016 %   noSMILES     metabolite names for which no SMILES could be found.
    -0017 %
    -0018 if nargin < 3 || isempty(verbose)
    -0019     verbose = true;
    -0020 end
    -0021 if nargin < 2 || isempty(modelAdapter)
    -0022     modelAdapter = ModelAdapterManager.getDefault();
    -0023     if isempty(modelAdapter)
    -0024         error('Either send in a modelAdapter or set the default model adapter in the ModelAdapterManager.')
    -0025     end
    -0026 end
    -0027 params = modelAdapter.params;
    -0028 
    -0029 [uniqueNames, ~, uniqueIdx] = unique(regexprep(model.metNames,'^prot_.*',''));
    -0030 uniqueSmiles(1:numel(uniqueNames),1) = {''};
    -0031 metMatch = false(length(uniqueNames),1);
    -0032 metMatch(strcmp(uniqueNames,'')) = 1; % No need trying to match empty fields
    -0033 if verbose; fprintf('Check for local SMILES database... '); end
    -0034 smilesDBfile = (fullfile(params.path,'data','smilesDB.tsv'));
    -0035 if exist(smilesDBfile,'file')==2
    -0036     fID = fopen(smilesDBfile,'r');
    -0037     raw = textscan(fID,'%s %s','Delimiter','\t','HeaderLines',0);
    -0038     fclose(fID);
    -0039     smilesDB.names = raw{1};
    -0040     smilesDB.smile = raw{2};
    -0041     [metMatch, metIdx] = ismember(uniqueNames,smilesDB.names);
    -0042     uniqueSmiles(metMatch) = smilesDB.smile(metIdx(metMatch));
    -0043     if verbose; fprintf('done.\n'); end
    -0044 else
    -0045     if verbose; fprintf('not found.\n'); end
    -0046 end
    -0047 
    -0048 if any(~metMatch)
    -0049     progressbar('Querying PubChem for SMILES by metabolite names')
    -0050     webOptions = weboptions('Timeout', 30);
    -0051     for i = 1:numel(uniqueNames)
    -0052         if metMatch(i)
    -0053             continue;
    -0054         end
    -0055         retry = 0;
    -0056         while retry < 10
    -0057             try
    -0058                 smileResult       = webread(['https://pubchem.ncbi.nlm.nih.gov/rest/pug/compound/name/' uniqueNames{i} '/property/CanonicalSMILES/TXT'], webOptions);
    -0059                 %Sometimes multiple lines are given, with alternative SMILES. Only
    -0060                 %keep the first suggestion.
    -0061                 smileResult       = regexp(smileResult,'(^\S*)\n','once','tokens');
    -0062                 uniqueSmiles{i,1} = smileResult{1,1};
    -0063                 retry = 15; % success: no retry
    -0064             catch exception
    -0065                 %Sometimes the call fails, for example since the server is busy. In those cases
    -0066                 %we will try 10 times. Some errors however are because the metabolite
    -0067                 %name does no exist in the database (404) or some other error (the metabolite contains
    -0068                 %a slash or similar, 400 or 500). In those cases we can
    -0069                 %immediately give up.
    -0070                 if (strcmp(exception.identifier, 'MATLAB:webservices:HTTP404StatusCodeError') || ...
    -0071                         strcmp(exception.identifier, 'MATLAB:webservices:HTTP400StatusCodeError') || ...
    -0072                         strcmp(exception.identifier, 'MATLAB:webservices:HTTP500StatusCodeError'))
    -0073                     uniqueSmiles(i) = {''};
    -0074                     retry = 15;
    -0075                 else
    -0076                     retry = retry + 1;
    -0077                 end
    -0078             end
    -0079         if retry == 10
    -0080             error('Cannot reach PubChem. Check your internet connection and try again.')
    -0081         end
    -0082         end
    -0083         % Append one line each time, in case internet connection is lost
    -0084         % halfway. Open & close file each time to avoid leaving the file
    -0085         % open when breaking the function.
    -0086         out = [uniqueNames(i), uniqueSmiles(i)];
    -0087         fID = fopen(smilesDBfile,'a');
    -0088         fprintf(fID,'%s\t%s\n',out{:});
    -0089         fclose(fID);
    -0090         progressbar(i/numel(uniqueNames))
    -0091     end
    -0092     if verbose
    -0093         fprintf('Model-specific SMILES database stored at %s\n',smilesDBfile);
    -0094     end
    -0095 end
    -0096 newSmiles = uniqueSmiles(uniqueIdx);
    -0097 noSMILES = cellfun(@isempty,uniqueSmiles);
    -0098 successRatio = 1-(numel(find(noSMILES))/numel(uniqueSmiles));
    -0099 fprintf('SMILES could be found for %s%% of the unique metabolite names.\n',num2str(successRatio*100,'%.0f'))
    -0100 noSMILES = uniqueNames(noSMILES);
    -0101 
    -0102 if ~isfield(model,'metSmiles') || all(cellfun(@isempty,model.metSmiles))
    -0103     model.metSmiles = newSmiles;
    -0104 else
    -0105     emptySmiles = cellfun(@isempty,model.metSmiles);
    -0106     model.metSmiles(emptySmiles) = newSmiles(emptySmiles);
    -0107 end
    -0108 progressbar(1) % Make sure it closes
    -0109 end
    -
    Generated by m2html © 2005
    - - \ No newline at end of file diff --git a/doc/src/geckomat/change_model/getComplexData.html b/doc/src/geckomat/change_model/getComplexData.html deleted file mode 100644 index 23a5cbbb..00000000 --- a/doc/src/geckomat/change_model/getComplexData.html +++ /dev/null @@ -1,241 +0,0 @@ - - - - Description of getComplexData - - - - - - - - - -
    Home > src > geckomat > change_model > getComplexData.m
    - - - -

    getComplexData -

    - -

    PURPOSE ^

    -
    getComplexData
    - -

    SYNOPSIS ^

    -
    function complexInfo = getComplexData(taxonomicID, modelAdapter)
    - -

    DESCRIPTION ^

    -
     getComplexData
    -   Download curated complex stochiometries from the EMBL-EBI Complex
    -   Portal database. Writes data/ComplexPortal.json in the obj.params.path
    -   specified in the model adapter.
    -
    - Input:
    -   taxonomicID     taxonomic identifier for which complex data should be
    -                   downloaded. Only taxonomic identifiers allowed are
    -                   those included on Complex Portal:
    -                   https://www.ebi.ac.uk/complexportal/complex/organisms
    -                   If empty, no complex data is downloaded, if 0 (zero),
    -                   complex data from all organisms in Complex Portal is
    -                   downloaded.
    -   modelAdapter    a loaded model adapter (Optional, will otherwise use the
    -                   default model adapter).
    - Output:
    -   complexInfo     structure with data downloaded from Complex Portal.
    -                   Contains the following fields:
    -                   - complexID: id of the complex on Complex Portal
    -                   - name: name of the complex on Complex Portal
    -                   - species: organism containing the complex
    -                   - geneName: names of the genes in the complex
    -                   - protID: Uniprot IDs of the proteins in the complex
    -                   - stochiometry: the complex stochiometry given in the same
    -                     order as the genes and proteins in geneName and protID
    -                   - defined:  0 if Complex Portal has no defined stochiometry
    -                               1 if defined subunit stochiometry is given
    -                               2 if complex consists of sub-complexes, whose
    -                                 subunit stochiometries are given
    - Usage
    -   complexInfo = getComplexData(organism, modelAdapter);
    - - -

    CROSS-REFERENCE INFORMATION ^

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

    SOURCE CODE ^

    -
    0001 function complexInfo = getComplexData(taxonomicID, modelAdapter)
    -0002 % getComplexData
    -0003 %   Download curated complex stochiometries from the EMBL-EBI Complex
    -0004 %   Portal database. Writes data/ComplexPortal.json in the obj.params.path
    -0005 %   specified in the model adapter.
    -0006 %
    -0007 % Input:
    -0008 %   taxonomicID     taxonomic identifier for which complex data should be
    -0009 %                   downloaded. Only taxonomic identifiers allowed are
    -0010 %                   those included on Complex Portal:
    -0011 %                   https://www.ebi.ac.uk/complexportal/complex/organisms
    -0012 %                   If empty, no complex data is downloaded, if 0 (zero),
    -0013 %                   complex data from all organisms in Complex Portal is
    -0014 %                   downloaded.
    -0015 %   modelAdapter    a loaded model adapter (Optional, will otherwise use the
    -0016 %                   default model adapter).
    -0017 % Output:
    -0018 %   complexInfo     structure with data downloaded from Complex Portal.
    -0019 %                   Contains the following fields:
    -0020 %                   - complexID: id of the complex on Complex Portal
    -0021 %                   - name: name of the complex on Complex Portal
    -0022 %                   - species: organism containing the complex
    -0023 %                   - geneName: names of the genes in the complex
    -0024 %                   - protID: Uniprot IDs of the proteins in the complex
    -0025 %                   - stochiometry: the complex stochiometry given in the same
    -0026 %                     order as the genes and proteins in geneName and protID
    -0027 %                   - defined:  0 if Complex Portal has no defined stochiometry
    -0028 %                               1 if defined subunit stochiometry is given
    -0029 %                               2 if complex consists of sub-complexes, whose
    -0030 %                                 subunit stochiometries are given
    -0031 % Usage
    -0032 %   complexInfo = getComplexData(organism, modelAdapter);
    -0033 
    -0034 if nargin < 2 || isempty(modelAdapter)
    -0035     modelAdapter = ModelAdapterManager.getDefault();
    -0036     if isempty(modelAdapter)
    -0037         error('Either send in a modelAdapter or set the default model adapter in the ModelAdapterManager.')
    -0038     end
    -0039 end
    -0040 
    -0041 if nargin<1 || isempty(taxonomicID)
    -0042     taxonomicID = modelAdapter.getParameters().complex.taxonomicID;
    -0043 end
    -0044 
    -0045 params = modelAdapter.params;
    -0046 if isempty(taxonomicID) % Can be empty when gathered from model adapter
    -0047     printOrange('WARNING: No taxonomicID specified.');
    -0048     return
    -0049 elseif taxonomicID == 0
    -0050     taxonomicID = [];
    -0051 end
    -0052 
    -0053 webOptions = weboptions('Timeout', 30);
    -0054 try
    -0055     url1 = 'https://www.ebi.ac.uk/intact/complex-ws/search/*';
    -0056     if ~isempty(taxonomicID)
    -0057         url1 = [url1 '?facets=species&filters=species:("' num2str(taxonomicID) '")'];
    -0058     end
    -0059     data = webread(url1,webOptions);
    -0060 catch ME
    -0061     if (strcmp(ME.identifier,'MATLAB:webservices:HTTP404StatusCodeError'))
    -0062         error('Cannot connect to the Complex Portal, perhaps the server is not responding');
    -0063     end
    -0064 end
    -0065 if data.size == 0
    -0066     error('No data could be gathered from Complex Portal for the specified taxonomicID.')
    -0067 end
    -0068 complexData = cell(data.size,7);
    -0069 
    -0070 progressbar('Retrieving information for complexes');
    -0071 for i = 1:data.size
    -0072     progressbar(i/data.size) % Update progress bar
    -0073     url2 = 'https://www.ebi.ac.uk/intact/complex-ws/complex/';
    -0074     complexID = data.elements(i,1).complexAC;
    -0075     try
    -0076         temp = webread([url2 complexID],webOptions);
    -0077     catch ME
    -0078         if (strcmp(ME.identifier,'MATLAB:webservices:HTTP404StatusCodeError'))
    -0079             printOrange(['WARNING: Cannot retrieve the information for ' complexID '.\n']);
    -0080         end
    -0081         temp = [];
    -0082     end
    -0083 
    -0084     if ~isempty(temp)
    -0085         complexData(i,1) = {temp.complexAc};
    -0086         complexData(i,2) = {temp.name};
    -0087         complexData(i,3) = {temp.species};
    -0088 
    -0089         idxIntType = find(strcmpi({temp.participants.interactorType}, 'protein'));
    -0090 
    -0091         % Some complex reported are 'stable complex', then, save the id
    -0092         % complex and but set the genes and protein to a empty string.
    -0093         if numel(idxIntType) > 0
    -0094             complexData(i,4) = {{temp.participants(idxIntType).name}};
    -0095             complexData(i,5) = {{temp.participants(idxIntType).identifier}};
    -0096         else
    -0097             complexData(i,4) = {{temp.participants.name}};
    -0098             complexData(i,5) = {{temp.participants.identifier}};
    -0099         end
    -0100 
    -0101         % Portal complex has two stochiometry values, a minimum and
    -0102         % maximum value. Only minimum will be store. In some cases,
    -0103         % some complex does not have stochiometry coefficient, then, it
    -0104         % will be fill with zeros
    -0105         if ~cellfun('isempty',{temp.participants.stochiometry})
    -0106             % For some reason, if there is only one protein in the complex
    -0107             % split function does nor return a cell nx2, instead is 2x1,
    -0108             % then assign an incorrect stochiometry
    -0109             switch numel(idxIntType)
    -0110                 case 0 % Contains complexes
    -0111                     stochiometry = split({temp.participants.stochiometry}.', ',');
    -0112                     complexData(i,7) = {2};
    -0113                 case 1 % Contains one protein
    -0114                     stochiometry = split({temp.participants(idxIntType).stochiometry}.', ',').';
    -0115                     complexData(i,7) = {1};
    -0116                 otherwise
    -0117                     stochiometry = split({temp.participants(idxIntType).stochiometry}.', ',');
    -0118                     complexData(i,7) = {1};
    -0119             end
    -0120             values = str2double(erase(stochiometry(:,1),"minValue: ")).';
    -0121             complexData(i,6) = {values};
    -0122         else
    -0123             complexData(i,6) = {repelem(0,numel(complexData{i,4}))};
    -0124             complexData(i,7) = {0};
    -0125         end
    -0126     end
    -0127 end
    -0128 fprintf('\n');
    -0129 
    -0130 % Expand complexes of complexes
    -0131 complexComplex = find([complexData{:,7}]==2);
    -0132 if ~isempty(complexComplex)
    -0133     for i=1:numel(complexComplex)
    -0134         subComplex    = complexData{complexComplex(i),5};
    -0135         subComplexS   = complexData{complexComplex(i),6};
    -0136         subComplexIdx = find(ismember(complexData(:,1),subComplex));
    -0137         allGenes = horzcat(complexData{subComplexIdx,4});
    -0138         allProts = horzcat(complexData{subComplexIdx,5});
    -0139         allStoch = {complexData{subComplexIdx,6}};
    -0140         for j=1:numel(subComplex)
    -0141             allStoch{j}=allStoch{j}*subComplexS(j);
    -0142         end
    -0143         allStoch = horzcat(allStoch{:});
    -0144         [allGenes,ia,ic] = unique(allGenes,'stable');
    -0145         allProts = allProts(ia);
    -0146         allStoch = splitapply(@sum, allStoch', ic);
    -0147         complexData{complexComplex(i),4} = allGenes;
    -0148         complexData{complexComplex(i),5} = allProts;
    -0149         complexData{complexComplex(i),6} = allStoch;
    -0150     end
    -0151 end
    -0152 
    -0153 rowHeadings = {'complexID','name','species','geneName','protID','stochiometry','defined'};
    -0154 
    -0155 complexInfo = cell2struct(complexData, rowHeadings, 2);
    -0156 
    -0157 % Convert to a JSON file
    -0158 jsontxt = jsonencode(cell2table(complexData, 'VariableNames', rowHeadings));
    -0159 % Write to a JSON file
    -0160 fid = fopen(fullfile(params.path,'data','ComplexPortal.json'), 'w');
    -0161 fprintf(fid, '%s', jsontxt);
    -0162 fclose(fid);
    -0163 fprintf('Model-specific ComplexPortal database stored at %s\n',fullfile(params.path,'data','ComplexPortal.json'));
    -0164 end
    -
    Generated by m2html © 2005
    - - \ No newline at end of file diff --git a/doc/src/geckomat/change_model/getKcatAcrossIsozymes.html b/doc/src/geckomat/change_model/getKcatAcrossIsozymes.html deleted file mode 100644 index 319a64ad..00000000 --- a/doc/src/geckomat/change_model/getKcatAcrossIsozymes.html +++ /dev/null @@ -1,102 +0,0 @@ - - - - Description of getKcatAcrossIsozymes - - - - - - - - - -
    Home > src > geckomat > change_model > getKcatAcrossIsozymes.m
    - - - -

    getKcatAcrossIsozymes -

    - -

    PURPOSE ^

    -
    getKcatAcrossIsozymes
    - -

    SYNOPSIS ^

    -
    function model = getKcatAcrossIsozymes(model)
    - -

    DESCRIPTION ^

    -
     getKcatAcrossIsozymes
    -   For reactions without kcat value (0 in model.ec.kcat), isozymes are
    -   found (being based on the same reaction in the conventional GEM), that
    -   do have a kcat value assigned. The mean kcat value of these isozymes
    -   is then used to fill in model.ec.kcat.
    -
    - Input:
    -   model       an ecModel in full GECKO 3 format (with ecModel.ec structure),
    -               not GECKO light
    -
    - Output:
    -   model       an ecModel with kcat values assigned to isozymes in model.ec.kcat
    -
    - Usage: model = getKcatAcrossIsozymes(model);
    - - -

    CROSS-REFERENCE INFORMATION ^

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

    SOURCE CODE ^

    -
    0001 function model = getKcatAcrossIsozymes(model)
    -0002 % getKcatAcrossIsozymes
    -0003 %   For reactions without kcat value (0 in model.ec.kcat), isozymes are
    -0004 %   found (being based on the same reaction in the conventional GEM), that
    -0005 %   do have a kcat value assigned. The mean kcat value of these isozymes
    -0006 %   is then used to fill in model.ec.kcat.
    -0007 %
    -0008 % Input:
    -0009 %   model       an ecModel in full GECKO 3 format (with ecModel.ec structure),
    -0010 %               not GECKO light
    -0011 %
    -0012 % Output:
    -0013 %   model       an ecModel with kcat values assigned to isozymes in model.ec.kcat
    -0014 %
    -0015 % Usage: model = getKcatAcrossIsozymes(model);
    -0016 
    -0017 if model.ec.geckoLight
    -0018     error('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');
    -0022     return
    -0023 end
    -0024 
    -0025 noKcats     = model.ec.kcat==0;
    -0026 rxnIDs      = regexprep(model.ec.rxns,'_EXP_\d+','');
    -0027 noKcatID    = rxnIDs(noKcats);
    -0028 yesKcatID   = rxnIDs(~noKcats);
    -0029 yesKcatVal  = model.ec.kcat(~noKcats);
    -0030 
    -0031 noKcatVal   = cellfun(@(x) strcmp(x, yesKcatID), noKcatID, 'UniformOutput', false);
    -0032 noKcatVal   = cell2mat(cellfun(@(x) mean(yesKcatVal(x)), noKcatVal, 'UniformOutput', false));
    -0033 
    -0034 newKcat     = find(~isnan(noKcatVal));
    -0035 newKcatIdx  = find(noKcats);
    -0036 newKcatIdx  = newKcatIdx(newKcat);
    -0037 newKcat     = noKcatVal(newKcat);
    -0038 
    -0039 model.ec.kcat(newKcatIdx) = newKcat;
    -0040 model.ec.source(newKcatIdx) = {'isozymes'};
    -0041 end
    -0042
    -
    Generated by m2html © 2005
    - - \ No newline at end of file diff --git a/doc/src/geckomat/change_model/getReactionsFromEnzyme.html b/doc/src/geckomat/change_model/getReactionsFromEnzyme.html deleted file mode 100644 index 05f2a275..00000000 --- a/doc/src/geckomat/change_model/getReactionsFromEnzyme.html +++ /dev/null @@ -1,89 +0,0 @@ - - - - Description of getReactionsFromEnzyme - - - - - - - - - -
    Home > src > geckomat > change_model > getReactionsFromEnzyme.m
    - - - -

    getReactionsFromEnzyme -

    - -

    PURPOSE ^

    -
    getReactionsFromEnzyme
    - -

    SYNOPSIS ^

    -
    function [rxns, kcat, idx, rxnNames, grRules] = getReactionsFromEnzyme(ecModel,proteinId)
    - -

    DESCRIPTION ^

    -
     getReactionsFromEnzyme
    -   Get all reactions that are annotated to a particular enzyme.
    -
    - Input:
    -   ecModel     an ecModel in GECKO 3 format (with ecModel.ec structure)
    -   proteinId   protein identifier, matching ecModel.ec.enzymes.
    -
    - Output:
    -   rxns        reactions that are associated with this enzyme
    -   kcat        kcat values of the corresponding reactions
    -   idx         index of the reactions in ecModel.ec.rxns
    -   rxnNames    names of the reactions
    -   grRules     grRules of the reactions
    -
    - Usage: [rxns, kcat, idx, rxnNames, grRules] = getReactionsFromEnzyme(ecModel,proteinId)
    - - -

    CROSS-REFERENCE INFORMATION ^

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

    SOURCE CODE ^

    -
    0001 function [rxns, kcat, idx, rxnNames, grRules] = getReactionsFromEnzyme(ecModel,proteinId)
    -0002 % getReactionsFromEnzyme
    -0003 %   Get all reactions that are annotated to a particular enzyme.
    -0004 %
    -0005 % Input:
    -0006 %   ecModel     an ecModel in GECKO 3 format (with ecModel.ec structure)
    -0007 %   proteinId   protein identifier, matching ecModel.ec.enzymes.
    -0008 %
    -0009 % Output:
    -0010 %   rxns        reactions that are associated with this enzyme
    -0011 %   kcat        kcat values of the corresponding reactions
    -0012 %   idx         index of the reactions in ecModel.ec.rxns
    -0013 %   rxnNames    names of the reactions
    -0014 %   grRules     grRules of the reactions
    -0015 %
    -0016 % Usage: [rxns, kcat, idx, rxnNames, grRules] = getReactionsFromEnzyme(ecModel,proteinId)
    -0017 
    -0018 protIdx     = find(strcmpi(ecModel.ec.enzymes,proteinId));
    -0019 ecRxnIdx    = find(ecModel.ec.rxnEnzMat(:,protIdx));
    -0020 rxns        = ecModel.ec.rxns(ecRxnIdx);
    -0021 kcat        = ecModel.ec.kcat(ecRxnIdx);
    -0022 
    -0023 idx         = ecRxnIdx;
    -0024 
    -0025 [~,rxnIdx]  = ismember(rxns,ecModel.rxns);
    -0026 rxnNames    = ecModel.rxnNames(rxnIdx);
    -0027 grRules     =  ecModel.grRules(rxnIdx);
    -0028 end
    -
    Generated by m2html © 2005
    - - \ No newline at end of file diff --git a/doc/src/geckomat/change_model/index.html b/doc/src/geckomat/change_model/index.html deleted file mode 100644 index 36e59847..00000000 --- a/doc/src/geckomat/change_model/index.html +++ /dev/null @@ -1,29 +0,0 @@ - - - - Index for Directory src\geckomat\change_model - - - - - - - - - - -
    < Master indexIndex for src\geckomat\change_model >
    - -

    Index for src\geckomat\change_model

    - -

    Matlab files in this directory:

    - -
     applyComplexDataapplyComplexData
     applyCustomKcatsapplyCustomKcats
     applyKcatConstraintsapplyKcatConstraints
     findMetSmilesfindMetSMILES
     getComplexDatagetComplexData
     getKcatAcrossIsozymesgetKcatAcrossIsozymes
     getReactionsFromEnzymegetReactionsFromEnzyme
     makeEcModelmakeEcModel
     setKcatForReactionssetKcatForReactions
     setProtPoolSizesetProtPoolSize
    - - - - -
    Generated by m2html © 2005
    - - \ No newline at end of file diff --git a/doc/src/geckomat/change_model/makeEcModel.html b/doc/src/geckomat/change_model/makeEcModel.html deleted file mode 100644 index 1b927758..00000000 --- a/doc/src/geckomat/change_model/makeEcModel.html +++ /dev/null @@ -1,544 +0,0 @@ - - - - Description of makeEcModel - - - - - - - - - -
    Home > src > geckomat > change_model > makeEcModel.m
    - - - -

    makeEcModel -

    - -

    PURPOSE ^

    -
    makeEcModel
    - -

    SYNOPSIS ^

    -
    function [model, noUniprot] = makeEcModel(model, geckoLight, modelAdapter)
    - -

    DESCRIPTION ^

    -
     makeEcModel
    -   Expands a conventional genome-scale model (in RAVEN format) with enzyme
    -   information and prepares the reactions for integration of enzyme usage
    -   coefficients. This function contains all the steps that need to be done
    -   to get a basic ecModel, without incorporating any kcat values or
    -   constraints yet. This function should only have to be run once for a
    -   model.
    -
    - Input:
    -   model        a model in RAVEN format
    -   geckoLight   true if a simplified GECKO light model should be generated.
    -                (Optional, default is false).
    -   modelAdapter a loaded model adapter (Optional, will otherwise use the
    -                default model adapter).
    -
    - Ouput:
    -   model        an ecModel in GECKO 3 format, with a model.ec structure where
    -                enzyme and kcat information are stored. Protein pseudo-
    -                metabolites and their draw reactions are added to the model,
    -                but their usage is not yet implemented (due to absent kcat
    -                values at this stage).
    -   noUniprot    genes for which no information could be found in the
    -                Uniprot database
    -
    - The function goes through the following steps:
    -   1.  Remove gene associations from pseudoreactions.
    -   2.  Invert irreversible backwards reactions.
    -   3.  Correct 'rev' vector to match lb and ub vectors.
    -   4.  Convert to irreversible model (splits reversible reactions).
    -   5.  [Skipped with geckoLight:] Expand model to split reactions with
    -       'OR' in grRules (each reaction is then catalyzed by one enzyme
    -       (complex).
    -   6.  Make empty model.ec structure, that will contain enzyme and kcat
    -       information. One entry per reaction, where isozymes have multiple
    -       entries. This model.ec structure will later be populated with kcat
    -       values. For geckoLight the structure is different, where each
    -       reaction can have multiple isozymes.
    -   7.  Add enzyme information fields to model.ec structure: MW, sequence.
    -   8.  Populate model.ec structure with information from each reaction.
    -   9.  [Skipped with geckoLight:] Add proteins as pseudometabolites.
    -   10. Add prot_pool pseudometabolite.
    -   11. [Skipped with geckoLight:] Add usage reactions for the protein
    -       pseudometabolites, replenishing from the protein pool (default, can
    -       be changed to consider proteomics data at later stage)
    -   12. Add protein pool reaction, without upper bound.
    -
    -   Note that while protein pseudometabolites, draw & pool reactions might
    -   be added to the model, the enzyme usage is not yet incorporated in each
    -   metabolic reaction, so enzymes will not be used. applyKcatConstraints
    -   incorporates protein pseudometabolites in reactions as enzyme usages by
    -   applying the specified kcats as constraints.
    -
    -The EC structure looks as follows
    - Attributes:
    -   geckoLight: 0 if full model, 1 if light
    -         rxns: reaction identifiers that correspond to model.rxns
    -         kcat: kcat values - not set here
    -       source: specifies where the kcats come from - not set here
    -        notes: notes that can be set by downstream functions - not set
    -               here
    -      eccodes: enzyme codes for each enzyme - not set here
    -        genes: the genes involved in the kcats - not necessarily the
    -               same as model.genes, since some genes may not be found in
    -               databases etc.
    -      enzymes: Uniprot protein identifiers for the genes
    -           mw: molecular weights of the enzymes
    -     sequence: sequence of the genes/enzymes
    -        concs: concentrations of the enzymes - not set here
    -    rxnEnzMat: matrix of enzymes and rxns
    -
    - The full model is split on all ORs in the GPRs, meaning that the
    - reactions will be duplicated for each isozyme. Only the rxns with genes
    - are added. The fields rxns, eccodes, kcat, source and notes will
    - therefore have one entry per reaction. The fields genes, enzymes, mw,
    - sequence and concs will have one entry per gene. The rxnEnzMat is a
    - matrix with reactions and genes, mapping which genes are connected to
    - which reaction (where isozymes have different reactions).
    -
    - The light model works a bit differently. The model has the same number of
    - rxns as the original model, but expanded since it is reversible + one the
    - extra prot maintenance rxn and one extra prot_pool rxn. However, the ec
    - fields rxns, eccodes, kcat, source and notes are duplicated for each
    - isozyme, sorted the same way as model.rxns. So, in model.ec.rxns, the
    - same reaction will appear several times after one another, one entry per
    - izozyme, with corresponding values for that isozyme. These fields
    - therefore have the same length as for the full model. The fields genes,
    - enzymes, mw, sequence and concs are the same here as in the full model.
    - The rxnEnzMat maps the model.ec.rxns entries to genes and is therefore of
    - the same size as for the full model.
    -
    - Usage:
    -   [model, noUniprot] = makeEcModel(model, geckoLight, modelAdapter)
    - - -

    CROSS-REFERENCE INFORMATION ^

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

    SUBFUNCTIONS ^

    - - -

    SOURCE CODE ^

    -
    0001 function [model, noUniprot] = makeEcModel(model, geckoLight, modelAdapter)
    -0002 % makeEcModel
    -0003 %   Expands a conventional genome-scale model (in RAVEN format) with enzyme
    -0004 %   information and prepares the reactions for integration of enzyme usage
    -0005 %   coefficients. This function contains all the steps that need to be done
    -0006 %   to get a basic ecModel, without incorporating any kcat values or
    -0007 %   constraints yet. This function should only have to be run once for a
    -0008 %   model.
    -0009 %
    -0010 % Input:
    -0011 %   model        a model in RAVEN format
    -0012 %   geckoLight   true if a simplified GECKO light model should be generated.
    -0013 %                (Optional, default is false).
    -0014 %   modelAdapter a loaded model adapter (Optional, will otherwise use the
    -0015 %                default model adapter).
    -0016 %
    -0017 % Ouput:
    -0018 %   model        an ecModel in GECKO 3 format, with a model.ec structure where
    -0019 %                enzyme and kcat information are stored. Protein pseudo-
    -0020 %                metabolites and their draw reactions are added to the model,
    -0021 %                but their usage is not yet implemented (due to absent kcat
    -0022 %                values at this stage).
    -0023 %   noUniprot    genes for which no information could be found in the
    -0024 %                Uniprot database
    -0025 %
    -0026 % The function goes through the following steps:
    -0027 %   1.  Remove gene associations from pseudoreactions.
    -0028 %   2.  Invert irreversible backwards reactions.
    -0029 %   3.  Correct 'rev' vector to match lb and ub vectors.
    -0030 %   4.  Convert to irreversible model (splits reversible reactions).
    -0031 %   5.  [Skipped with geckoLight:] Expand model to split reactions with
    -0032 %       'OR' in grRules (each reaction is then catalyzed by one enzyme
    -0033 %       (complex).
    -0034 %   6.  Make empty model.ec structure, that will contain enzyme and kcat
    -0035 %       information. One entry per reaction, where isozymes have multiple
    -0036 %       entries. This model.ec structure will later be populated with kcat
    -0037 %       values. For geckoLight the structure is different, where each
    -0038 %       reaction can have multiple isozymes.
    -0039 %   7.  Add enzyme information fields to model.ec structure: MW, sequence.
    -0040 %   8.  Populate model.ec structure with information from each reaction.
    -0041 %   9.  [Skipped with geckoLight:] Add proteins as pseudometabolites.
    -0042 %   10. Add prot_pool pseudometabolite.
    -0043 %   11. [Skipped with geckoLight:] Add usage reactions for the protein
    -0044 %       pseudometabolites, replenishing from the protein pool (default, can
    -0045 %       be changed to consider proteomics data at later stage)
    -0046 %   12. Add protein pool reaction, without upper bound.
    -0047 %
    -0048 %   Note that while protein pseudometabolites, draw & pool reactions might
    -0049 %   be added to the model, the enzyme usage is not yet incorporated in each
    -0050 %   metabolic reaction, so enzymes will not be used. applyKcatConstraints
    -0051 %   incorporates protein pseudometabolites in reactions as enzyme usages by
    -0052 %   applying the specified kcats as constraints.
    -0053 %
    -0054 %The EC structure looks as follows
    -0055 % Attributes:
    -0056 %   geckoLight: 0 if full model, 1 if light
    -0057 %         rxns: reaction identifiers that correspond to model.rxns
    -0058 %         kcat: kcat values - not set here
    -0059 %       source: specifies where the kcats come from - not set here
    -0060 %        notes: notes that can be set by downstream functions - not set
    -0061 %               here
    -0062 %      eccodes: enzyme codes for each enzyme - not set here
    -0063 %        genes: the genes involved in the kcats - not necessarily the
    -0064 %               same as model.genes, since some genes may not be found in
    -0065 %               databases etc.
    -0066 %      enzymes: Uniprot protein identifiers for the genes
    -0067 %           mw: molecular weights of the enzymes
    -0068 %     sequence: sequence of the genes/enzymes
    -0069 %        concs: concentrations of the enzymes - not set here
    -0070 %    rxnEnzMat: matrix of enzymes and rxns
    -0071 %
    -0072 % The full model is split on all ORs in the GPRs, meaning that the
    -0073 % reactions will be duplicated for each isozyme. Only the rxns with genes
    -0074 % are added. The fields rxns, eccodes, kcat, source and notes will
    -0075 % therefore have one entry per reaction. The fields genes, enzymes, mw,
    -0076 % sequence and concs will have one entry per gene. The rxnEnzMat is a
    -0077 % matrix with reactions and genes, mapping which genes are connected to
    -0078 % which reaction (where isozymes have different reactions).
    -0079 %
    -0080 % The light model works a bit differently. The model has the same number of
    -0081 % rxns as the original model, but expanded since it is reversible + one the
    -0082 % extra prot maintenance rxn and one extra prot_pool rxn. However, the ec
    -0083 % fields rxns, eccodes, kcat, source and notes are duplicated for each
    -0084 % isozyme, sorted the same way as model.rxns. So, in model.ec.rxns, the
    -0085 % same reaction will appear several times after one another, one entry per
    -0086 % izozyme, with corresponding values for that isozyme. These fields
    -0087 % therefore have the same length as for the full model. The fields genes,
    -0088 % enzymes, mw, sequence and concs are the same here as in the full model.
    -0089 % The rxnEnzMat maps the model.ec.rxns entries to genes and is therefore of
    -0090 % the same size as for the full model.
    -0091 %
    -0092 % Usage:
    -0093 %   [model, noUniprot] = makeEcModel(model, geckoLight, modelAdapter)
    -0094 
    -0095 if nargin<2
    -0096     geckoLight=false;
    -0097 elseif ~islogical(geckoLight) && ~(geckoLight == 0) && ~(geckoLight == 1)
    -0098     error('geckoLight should be either true or false')
    -0099 end
    -0100 
    -0101 if nargin < 3 || isempty(modelAdapter)
    -0102     modelAdapter = ModelAdapterManager.getDefault();
    -0103     if isempty(modelAdapter)
    -0104         error('Either send in a modelAdapter or set the default model adapter in the ModelAdapterManager.')
    -0105     end
    -0106 end
    -0107 params = modelAdapter.getParameters();
    -0108 compartmentID = strcmp(model.compNames,params.enzyme_comp);
    -0109 if ~any(compartmentID)
    -0110     error(['Compartment ' params.enzyme_comp ' (specified in params.enzyme_comp) '...
    -0111            'cannot be found in model.compNames'])
    -0112 end
    -0113 compartmentID = model.comps(compartmentID);
    -0114 
    -0115 if geckoLight
    -0116     ec.geckoLight=true;
    -0117 else
    -0118     ec.geckoLight=false;
    -0119 end
    -0120 
    -0121 %Check if model is in RAVEN format
    -0122 if any(isfield(model,{'rules','modelID'}))
    -0123     error(['The model is likely loaded using COBRA Toolbox readCbModel(). Instead, use ' ...
    -0124            'RAVEN Toolbox importModel(). Alternatively, you can also convert the ', ...
    -0125            'model in MATLAB using ravenCobraWrapper().'])
    -0126 end
    -0127 
    -0128 %Check for conflicting reaction and metabolite identifiers
    -0129 conflictId = startsWith(model.mets,'prot_');
    -0130 if any(conflictId)
    -0131     error('The identifiers in model.mets are not allowed to start with ''prot_''.')
    -0132 end
    -0133 conflictId = startsWith(model.rxns,{'usage_prot_','prot_pool'}) | ...
    -0134              endsWith(model.rxns,'_REV') | ...
    -0135              ~cellfun(@isempty,regexp(model.rxns,'_EXP_\d+$'));
    -0136 if any(conflictId)
    -0137     error(['The identifiers in model.rxns are not allowed to start with ''usage_prot'' ' ...
    -0138            'or ''prot_pool'', or end with ''_REV'' or ''_EXP_[digit]''.'])
    -0139 end
    -0140 
    -0141 uniprotDB = loadDatabases('both', modelAdapter);
    -0142 uniprotDB = uniprotDB.uniprot;
    -0143 
    -0144 %1: Remove gene rules from pseudoreactions (if any):
    -0145 if exist(fullfile(params.path,'data','pseudoRxns.tsv'),'file')
    -0146     fID        = fopen(fullfile(params.path,'data','pseudoRxns.tsv'));
    -0147     fileData   = textscan(fID,'%s %s','delimiter','\t');
    -0148     fclose(fID);
    -0149     pseudoRxns = fileData{1};
    -0150     pseudoRxns = ismember(model.rxns,pseudoRxns);
    -0151 else
    -0152     pseudoRxns = false(numel(model.rxns),1);
    -0153 end
    -0154 pseudoRxns = find(pseudoRxns | contains(model.rxnNames,'pseudoreaction'));
    -0155 model.grRules(pseudoRxns)       = {''};
    -0156 model.rxnGeneMat(pseudoRxns,:)  = zeros(numel(pseudoRxns), numel(model.genes));
    -0157 
    -0158 %2: Swap direction of reactions that are defined to only carry negative flux
    -0159 to_swap=model.lb < 0 & model.ub == 0;
    -0160 model.S(:,to_swap)=-model.S(:,to_swap);
    -0161 model.ub(to_swap)=-model.lb(to_swap);
    -0162 model.lb(to_swap)=0;
    -0163 
    -0164 %3: Correct rev vector: true if LB < 0 & UB > 0, or it is an exchange reaction:
    -0165 model.rev = false(size(model.rxns));
    -0166 for i = 1:length(model.rxns)
    -0167     if (model.lb(i) < 0 && model.ub(i) > 0) || sum(model.S(:,i) ~= 0) == 1
    -0168         model.rev(i) = true;
    -0169     end
    -0170 end
    -0171 
    -0172 %4: Make irreversible model (appends _REV to reaction IDs to indicate reverse
    -0173 %reactions)
    -0174 [~,exchRxns] = getExchangeRxns(model);
    -0175 nonExchRxns = model.rxns;
    -0176 nonExchRxns(exchRxns) = [];
    -0177 model=convertToIrrev(model, nonExchRxns);
    -0178 
    -0179 %5: Expand model, to separate isozymes (appends _EXP_* to reaction IDs to
    -0180 %indicate duplication)
    -0181 if ~geckoLight
    -0182     model=expandModel(model);
    -0183 end
    -0184 % Sort reactions, so that reversible and isozymic reactions are kept near
    -0185 if ~geckoLight
    -0186     model=sortIdentifiers(model);
    -0187 end
    -0188 
    -0189 %6: Make ec-extension structure, one for gene-associated reaction.
    -0190 %   The structure is different for light and full models
    -0191 rxnWithGene  = find(sum(model.rxnGeneMat,2));
    -0192 if ~geckoLight
    -0193     ec.rxns      = model.rxns(rxnWithGene);
    -0194     emptyCell    = cell(numel(rxnWithGene),1);
    -0195     emptyCell(:) = {''};
    -0196     emptyVect    = zeros(numel(rxnWithGene),1);
    -0197     
    -0198     ec.kcat      = emptyVect;
    -0199     ec.source    = emptyCell; % Strings, like 'dlkcat', 'manual', 'brenda', etc.
    -0200     ec.notes     = emptyCell; % Additional comments
    -0201     ec.eccodes   = emptyCell;
    -0202     ec.concs     = emptyVect;
    -0203 else
    -0204     %Different strategy for GECKO light: Each reaction can exist multiple times in
    -0205     %ec.rxns and similar fields - one time per isozyme. The number of copies is
    -0206     %the number of ORs in the GPR + 1
    -0207     numOrs = count(model.grRules(rxnWithGene), ' or ');
    -0208     cpys = numOrs + 1;
    -0209     prevNumRxns = length(numOrs);
    -0210     cpyIndices = repelem(rxnWithGene, cpys).'; %.' only matter when number of rxns is 1
    -0211     %loop through and add a prefix with an isozyme index to the rxns
    -0212     %we just give a fixed-length number as prefix, and assume that 999 is enough
    -0213     tmpRxns = model.rxns(cpyIndices); %now they have no prefix
    -0214     newRxns = tmpRxns;
    -0215     
    -0216     %add the prefix
    -0217     nextIndex = 1;
    -0218     for i = 1:numel(model.rxns)
    -0219         localRxnIndex = 1;
    -0220         if nextIndex <= length(tmpRxns) && strcmp(model.rxns(i), tmpRxns(nextIndex))
    -0221             while true
    -0222                 tmp = compose('%03d_',localRxnIndex);
    -0223                 newRxns{nextIndex} = [tmp{1} tmpRxns{nextIndex}];
    -0224                 localRxnIndex = localRxnIndex + 1;
    -0225                 if (localRxnIndex >= 1000)
    -0226                     error('Increase index size to 10000 - error in the code.'); %this should never happen, we don't have > 999 isozymes
    -0227                 end
    -0228                 nextIndex = nextIndex + 1;
    -0229                 if  nextIndex > length(tmpRxns) || ~strcmp(model.rxns(i), tmpRxns(nextIndex))
    -0230                     break;
    -0231                 end
    -0232             end
    -0233         end
    -0234     end
    -0235 
    -0236     ec.rxns      = newRxns;
    -0237     
    -0238     emptyCell    = cell(numel(ec.rxns),1);
    -0239     emptyCell(:) = {''};
    -0240     emptyVect    = zeros(numel(ec.rxns),1);
    -0241 
    -0242     ec.kcat      = emptyVect;
    -0243     ec.source    = emptyCell; % Strings, like 'dlkcat', 'manual', 'brenda', etc.
    -0244     ec.notes     = emptyCell; % Additional comments
    -0245     ec.eccodes   = emptyCell;
    -0246     ec.concs     = emptyVect;
    -0247 end
    -0248     
    -0249 %7: Gather enzyme information via UniprotDB
    -0250 uniprotCompatibleGenes = modelAdapter.getUniprotCompatibleGenes(model.genes);
    -0251 [Lia,Locb] = ismember(uniprotCompatibleGenes,uniprotDB.genes);
    -0252 
    -0253 uniprot = modelAdapter.getUniprotIDsFromTable(uniprotCompatibleGenes);
    -0254 if ~isequal(uniprot,uniprotCompatibleGenes)
    -0255     uniprot(cellfun(@isempty,uniprot)) = {''};
    -0256     [Lia,Locb] = ismember(uniprot,uniprotDB.ID);
    -0257 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, or a data/uniprotConversion.tsv file are likely required.')
    -0261 elseif ~isempty(noUniprot)
    -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/change_model/setKcatForReactions.html b/doc/src/geckomat/change_model/setKcatForReactions.html deleted file mode 100644 index cdcb9ea1..00000000 --- a/doc/src/geckomat/change_model/setKcatForReactions.html +++ /dev/null @@ -1,120 +0,0 @@ - - - - Description of setKcatForReactions - - - - - - - - - -
    Home > src > geckomat > change_model > setKcatForReactions.m
    - - - -

    setKcatForReactions -

    - -

    PURPOSE ^

    -
    setKcatForReactions
    - -

    SYNOPSIS ^

    -
    function ecModel = setKcatForReactions(ecModel,rxnIds,kcat)
    - -

    DESCRIPTION ^

    -
     setKcatForReactions
    -   Change the kcat value in ecModel.ec.kcat for selected reactions.
    -   applyKcatConstraints needs to be run afterwards to transfer the kcat
    -   values into the S-matrix.
    -
    - Input:
    -   ecModel     an ecModel in GECKO 3 format (with ecModel.ec structure)
    -   rxnIds      reaction identifier matching ecModel.ec.rxns. If the _EXP_.
    -               suffix is not included, and there are multiple expanded
    -               (isozymic) reactions, then all off those will have their
    -               kcat changed. If rxnIds includes a _EXP_ suffix, then only
    -               that specific reaction will have its kcat changed. If
    -               multiple rxnIds are provided as a cell array, then the
    -               above applies to each rxnIds individual.
    -   kcat        the new kcat value
    -
    - Output:
    -   ecModel     ecModel where selected kcat values in ecModel.ec.kcat are
    -               changed, but not yet applied to the S-matrix (will require
    -               to run applyKcatConstraints). ecModel.ec.source for the
    -               changed reactions will read 'from setKcatForReactions'
    -
    - Usage: ecModel = setKcatForReactions(ecModel,rxnIds,kcat)
    - - -

    CROSS-REFERENCE INFORMATION ^

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

    SOURCE CODE ^

    -
    0001 function ecModel = setKcatForReactions(ecModel,rxnIds,kcat)
    -0002 % setKcatForReactions
    -0003 %   Change the kcat value in ecModel.ec.kcat for selected reactions.
    -0004 %   applyKcatConstraints needs to be run afterwards to transfer the kcat
    -0005 %   values into the S-matrix.
    -0006 %
    -0007 % Input:
    -0008 %   ecModel     an ecModel in GECKO 3 format (with ecModel.ec structure)
    -0009 %   rxnIds      reaction identifier matching ecModel.ec.rxns. If the _EXP_.
    -0010 %               suffix is not included, and there are multiple expanded
    -0011 %               (isozymic) reactions, then all off those will have their
    -0012 %               kcat changed. If rxnIds includes a _EXP_ suffix, then only
    -0013 %               that specific reaction will have its kcat changed. If
    -0014 %               multiple rxnIds are provided as a cell array, then the
    -0015 %               above applies to each rxnIds individual.
    -0016 %   kcat        the new kcat value
    -0017 %
    -0018 % Output:
    -0019 %   ecModel     ecModel where selected kcat values in ecModel.ec.kcat are
    -0020 %               changed, but not yet applied to the S-matrix (will require
    -0021 %               to run applyKcatConstraints). ecModel.ec.source for the
    -0022 %               changed reactions will read 'from setKcatForReactions'
    -0023 %
    -0024 % Usage: ecModel = setKcatForReactions(ecModel,rxnIds,kcat)
    -0025 rxnIds = convertCharArray(rxnIds);
    -0026 
    -0027 hasExp       = ~cellfun(@isempty,regexp(rxnIds,'_EXP_\d+$'));
    -0028 nonExpRxns   = regexprep(ecModel.ec.rxns,'_EXP_\d+$','');
    -0029 rxnsToChange = [];
    -0030 for i=1:numel(hasExp)
    -0031     if hasExp(i) == 1
    -0032         rxnsToChange = [rxnsToChange; find(strcmpi(ecModel.ec.rxns,rxnIds{i}))];
    -0033     else
    -0034         nonExpRxn    = regexprep(rxnIds(i),'_EXP_\d+$','');
    -0035         rxnsToChange = [rxnsToChange; find(strcmpi(nonExpRxns,nonExpRxn))];
    -0036     end
    -0037 end
    -0038 if isscalar(rxnsToChange)
    -0039     if length(kcat) ~= 1
    -0040         error('Found one reaction whose kcat should change, you should provide one kcat value only.')
    -0041     end
    -0042 else
    -0043     if isscalar(kcat)
    -0044         % Is fine, all reactions get the same kcat
    -0045     elseif length(kcat) ~= length(rxnsToChange)
    -0046         error('Found %d reactions whose kcat should change, the new kcat should be either a single value, or a vector of length %d.', length(rxnsToChange), length(rxnsToChange))
    -0047     end
    -0048 end
    -0049 ecModel.ec.kcat(rxnsToChange)   = kcat;
    -0050 ecModel.ec.source(rxnsToChange) = {'setKcatForReactions'};
    -0051 end
    -
    Generated by m2html © 2005
    - - \ No newline at end of file diff --git a/doc/src/geckomat/change_model/setProtPoolSize.html b/doc/src/geckomat/change_model/setProtPoolSize.html deleted file mode 100644 index 853fb50b..00000000 --- a/doc/src/geckomat/change_model/setProtPoolSize.html +++ /dev/null @@ -1,114 +0,0 @@ - - - - Description of setProtPoolSize - - - - - - - - - -
    Home > src > geckomat > change_model > setProtPoolSize.m
    - - - -

    setProtPoolSize -

    - -

    PURPOSE ^

    -
    setProtPoolSize
    - -

    SYNOPSIS ^

    -
    function model = setProtPoolSize(model, Ptot, f, sigma, modelAdapter)
    - -

    DESCRIPTION ^

    -
     setProtPoolSize
    -   Sets the limit of the total protein usage in the model.
    -
    - Input:
    -   model           an ecModel in GECKO 3 format (with ecModel.ec structure)
    -   Ptot            Total cellular protein content in g/gDCW. If not
    -                   specified, the value will be read from the model
    -                   adapter. If not specified in model adapter, 0.5 g/gDCW
    -                   is assumed.
    -   f               Estimated fraction of enzymes in the model. If not
    -                   specified, the value will be read from the model
    -                   adapter. If not specified in model adapter, 0.5 is
    -                   assumed.
    -   sigma           Estimated saturation factor. If not specified, the
    -                   value will be read from the model adapter. If not
    -                   specified in model adapter, 0.5 is assumed.
    -   modelAdapter    a loaded model adapter (Optional, will otherwise use the
    -                   default model adapter).
    -
    - Output:
    -   model           ecModel with protein pool constraint set
    -
    - Usage: model = setProtPoolSize(model, Ptot, f, sigma, modelAdapter)
    - - -

    CROSS-REFERENCE INFORMATION ^

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

    SOURCE CODE ^

    -
    0001 function model = setProtPoolSize(model, Ptot, f, sigma, modelAdapter)
    -0002 % setProtPoolSize
    -0003 %   Sets the limit of the total protein usage in the model.
    -0004 %
    -0005 % Input:
    -0006 %   model           an ecModel in GECKO 3 format (with ecModel.ec structure)
    -0007 %   Ptot            Total cellular protein content in g/gDCW. If not
    -0008 %                   specified, the value will be read from the model
    -0009 %                   adapter. If not specified in model adapter, 0.5 g/gDCW
    -0010 %                   is assumed.
    -0011 %   f               Estimated fraction of enzymes in the model. If not
    -0012 %                   specified, the value will be read from the model
    -0013 %                   adapter. If not specified in model adapter, 0.5 is
    -0014 %                   assumed.
    -0015 %   sigma           Estimated saturation factor. If not specified, the
    -0016 %                   value will be read from the model adapter. If not
    -0017 %                   specified in model adapter, 0.5 is assumed.
    -0018 %   modelAdapter    a loaded model adapter (Optional, will otherwise use the
    -0019 %                   default model adapter).
    -0020 %
    -0021 % Output:
    -0022 %   model           ecModel with protein pool constraint set
    -0023 %
    -0024 % Usage: model = setProtPoolSize(model, Ptot, f, sigma, modelAdapter)
    -0025 
    -0026 if nargin < 5 || isempty(modelAdapter)
    -0027     modelAdapter = ModelAdapterManager.getDefault();
    -0028     if isempty(modelAdapter) && (nargin<2 || isempty(Ptot) || isempty(f) || isempty(sigma))
    -0029         error('Either send in a modelAdapter or set the default model adapter in the ModelAdapterManager.')
    -0030     end
    -0031 end
    -0032 
    -0033 if nargin<4 || isempty(sigma)
    -0034     sigma = modelAdapter.getParameters().sigma;
    -0035 end
    -0036 if nargin<3 || isempty(f)
    -0037     f = modelAdapter.getParameters().f;
    -0038 end
    -0039 if nargin<2 || isempty(Ptot)
    -0040     Ptot = modelAdapter.getParameters().Ptot;
    -0041 end
    -0042 
    -0043 model.lb(strcmp(model.rxns, 'prot_pool_exchange')) = -(Ptot*f*sigma*1000);
    -0044 end
    -0045
    -
    Generated by m2html © 2005
    - - \ No newline at end of file diff --git a/doc/src/geckomat/gather_kcats/fuzzyKcatMatching.html b/doc/src/geckomat/gather_kcats/fuzzyKcatMatching.html deleted file mode 100644 index 86e8db83..00000000 --- a/doc/src/geckomat/gather_kcats/fuzzyKcatMatching.html +++ /dev/null @@ -1,611 +0,0 @@ - - - - Description of fuzzyKcatMatching - - - - - - - - - -
    Home > src > geckomat > gather_kcats > fuzzyKcatMatching.m
    - - - -

    fuzzyKcatMatching -

    - -

    PURPOSE ^

    -
    fuzzyKcatMatching
    - -

    SYNOPSIS ^

    -
    function kcatList = fuzzyKcatMatching(model, ecRxns, modelAdapter, forceWClvl)
    - -

    DESCRIPTION ^

    -
     fuzzyKcatMatching
    -   Matchs the model EC numbers and substrates to the BRENDA database, to
    -   return the corresponding kcats for each reaction. If no exact match is
    -   found, less specific kcat values are found from (a) evolutionary
    -   closely related organism; (b) different substrate; (c) calculated from
    -   specific activities; (d) wildcards in the EC number. The model organism
    -   is provided in the model adapter as obj.params.org_name, and
    -   evolutionary distance to other organisms is determined via KEGG
    -   phylogeny. If an organism name occurs multiple times in KEGG, the first
    -   instance will be used when determining evolutionary distance.
    -
    - Input:
    -   model        an ecModel in GECKO 3 format (with ecModel.ec structure)
    -   ecRxns       for which reactions (from model.ec.rxns) kcat values should
    -                be found, provided as logical vector with same length as
    -                model.ec.rxns. (Opt, default is all reactions)
    -   modelAdapter a loaded model adapter (Optional, will otherwise use the
    -                default model adapter).
    -   forceWClvl   force a minimum wildcard level (Optional, default 0). 
    -
    - Output:
    -   kcatList    structure array with list of BRENDA derived kcat values,
    -               with separate entries for each kcat value
    -               source      'brenda'           
    -               rxns        reaction identifiers
    -               substrate   substrate names
    -               kcat        proposed kcat value in /sec
    -               eccodes     as used to query BRENDA
    -               wildCardLvl which level of EC wild-card was necessary to
    -                           find a match
    -                           0: w.x.y.z
    -                           1: w.x.y.-
    -                           2: w.x.-.-
    -                           3: w.-.-.-
    -               origin      which level of specificity was necessary to
    -                           find a match
    -                           1: correct organism, correct substrate, kcat
    -                           2: any organism, correct substrate, kcat
    -                           3: correct organism, any substrate, kcat
    -                           4: any organism, any substrate, kcat
    -                           5: correct organism, specific activity
    -                           6: any organism, specific activity
    -
    -   Note: If a wildcard is used, origin levels 1 and 2 are ignored. The
    -   last digits in the E.C. number indicate the substrate specificity, so
    -   if this should be ignored, then correct substrate matches should not be
    -   prioritized.
    -
    - Usage:
    -   kcatList = fuzzyKcatMatching(model, ecRxns, modelAdapter, forceWClvl)
    - - -

    CROSS-REFERENCE INFORMATION ^

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

    SUBFUNCTIONS ^

    - - -

    SOURCE CODE ^

    -
    0001 function kcatList = fuzzyKcatMatching(model, ecRxns, modelAdapter, forceWClvl)
    -0002 % fuzzyKcatMatching
    -0003 %   Matchs the model EC numbers and substrates to the BRENDA database, to
    -0004 %   return the corresponding kcats for each reaction. If no exact match is
    -0005 %   found, less specific kcat values are found from (a) evolutionary
    -0006 %   closely related organism; (b) different substrate; (c) calculated from
    -0007 %   specific activities; (d) wildcards in the EC number. The model organism
    -0008 %   is provided in the model adapter as obj.params.org_name, and
    -0009 %   evolutionary distance to other organisms is determined via KEGG
    -0010 %   phylogeny. If an organism name occurs multiple times in KEGG, the first
    -0011 %   instance will be used when determining evolutionary distance.
    -0012 %
    -0013 % Input:
    -0014 %   model        an ecModel in GECKO 3 format (with ecModel.ec structure)
    -0015 %   ecRxns       for which reactions (from model.ec.rxns) kcat values should
    -0016 %                be found, provided as logical vector with same length as
    -0017 %                model.ec.rxns. (Opt, default is all reactions)
    -0018 %   modelAdapter a loaded model adapter (Optional, will otherwise use the
    -0019 %                default model adapter).
    -0020 %   forceWClvl   force a minimum wildcard level (Optional, default 0).
    -0021 %
    -0022 % Output:
    -0023 %   kcatList    structure array with list of BRENDA derived kcat values,
    -0024 %               with separate entries for each kcat value
    -0025 %               source      'brenda'
    -0026 %               rxns        reaction identifiers
    -0027 %               substrate   substrate names
    -0028 %               kcat        proposed kcat value in /sec
    -0029 %               eccodes     as used to query BRENDA
    -0030 %               wildCardLvl which level of EC wild-card was necessary to
    -0031 %                           find a match
    -0032 %                           0: w.x.y.z
    -0033 %                           1: w.x.y.-
    -0034 %                           2: w.x.-.-
    -0035 %                           3: w.-.-.-
    -0036 %               origin      which level of specificity was necessary to
    -0037 %                           find a match
    -0038 %                           1: correct organism, correct substrate, kcat
    -0039 %                           2: any organism, correct substrate, kcat
    -0040 %                           3: correct organism, any substrate, kcat
    -0041 %                           4: any organism, any substrate, kcat
    -0042 %                           5: correct organism, specific activity
    -0043 %                           6: any organism, specific activity
    -0044 %
    -0045 %   Note: If a wildcard is used, origin levels 1 and 2 are ignored. The
    -0046 %   last digits in the E.C. number indicate the substrate specificity, so
    -0047 %   if this should be ignored, then correct substrate matches should not be
    -0048 %   prioritized.
    -0049 %
    -0050 % Usage:
    -0051 %   kcatList = fuzzyKcatMatching(model, ecRxns, modelAdapter, forceWClvl)
    -0052 
    -0053 if nargin<2 || isempty(ecRxns)
    -0054     ecRxns = true(numel(model.ec.rxns),1);
    -0055 elseif isnumeric(ecRxns)
    -0056     ecRxnsVec = false(numel(model.ec.rxns),1);
    -0057     ecRxnsVec(ecRxns) = true;
    -0058     ecRxns = ecRxnsVec;
    -0059 end
    -0060 ecRxns=find(ecRxns); % Get indices instead of logical
    -0061 
    -0062 if nargin < 3 || isempty(modelAdapter)
    -0063     modelAdapter = ModelAdapterManager.getDefault();
    -0064     if isempty(modelAdapter)
    -0065         error('Either send in a modelAdapter or set the default model adapter in the ModelAdapterManager.')
    -0066     end
    -0067 end
    -0068 params = modelAdapter.params;
    -0069 
    -0070 if nargin < 4 || isempty(forceWClvl)
    -0071     forceWClvl = 0;
    -0072 end
    -0073 
    -0074 if ~isfield(model.ec,'eccodes')
    -0075     error('No EC codes defined in model.ec.eccodes. First run getECfromGEM() and/or getECfromDatabase().')
    -0076 end
    -0077 eccodes      = model.ec.eccodes(ecRxns);
    -0078 substrates   = cell(numel(ecRxns),1);
    -0079 substrCoeffs = cell(numel(ecRxns),1);
    -0080 
    -0081 %Need to remove the prefix of GECKO light rxn names in the ec structure
    -0082 if ~model.ec.geckoLight
    -0083     rxnNames = model.ec.rxns;
    -0084 else
    -0085     rxnNames = extractAfter(model.ec.rxns, 4);
    -0086 end
    -0087 [~,originalRxns] = ismember(rxnNames(ecRxns),model.rxns);
    -0088 for i = 1:length(ecRxns)
    -0089     sel = find(model.S(:,originalRxns(i)) < 0);
    -0090     substrates{i}  = model.metNames(sel); 
    -0091     substrCoeffs{i} = -model.S(sel,originalRxns(i));
    -0092 end
    -0093 
    -0094 %Load BRENDA data:
    -0095 [KCATcell, SAcell] = loadBRENDAdata(modelAdapter);
    -0096 
    -0097 %Creates a Structure with KEGG codes for organisms, names and taxonomical
    -0098 %distance matrix and extract the organism index in the KEGG struct
    -0099 phylDistStruct =  KEGG_struct(modelAdapter.getPhylDistStructPath());
    -0100 %Get the KEGG code for the model's organism
    -0101 org_name       = params.org_name;
    -0102 org_index      = find_inKEGG(org_name,phylDistStruct.names);
    -0103 %build an index for genus in the phyl dist struct
    -0104 %first just extract the genus (i.e. the first part of the name)
    -0105 phylDistStruct.genus = lower(regexprep(phylDistStruct.names,'\s.*',''));
    -0106 %create a map for the genuses
    -0107 phylDistStruct.uniqueGenusList = unique(phylDistStruct.genus);
    -0108 phylDistStruct.genusHashMap = containers.Map(phylDistStruct.uniqueGenusList,1:length(phylDistStruct.uniqueGenusList));
    -0109 phylDistStruct.uniqueGenusIndices = cell(length(phylDistStruct.uniqueGenusList),1);
    -0110 
    -0111 %Then for each genus create a list with indices to the names
    -0112 for i = 1:length(phylDistStruct.genus)
    -0113     matchInd = cell2mat(values(phylDistStruct.genusHashMap,phylDistStruct.genus(i)));
    -0114     phylDistStruct.uniqueGenusIndices{matchInd} = [phylDistStruct.uniqueGenusIndices{matchInd};i];
    -0115 end
    -0116 
    -0117 %Allocate output
    -0118 kcats = zeros(length(eccodes),1);
    -0119 mM = length(eccodes);
    -0120 
    -0121 %Create empty kcatInfo
    -0122 %Legacy, no longer given as output, rather used to construct
    -0123 %kcatList.wildcardLvl and kcatList.origin.
    -0124 kcatInfo.info.org_s   = zeros(mM,1);
    -0125 kcatInfo.info.rest_s  = zeros(mM,1);
    -0126 kcatInfo.info.org_ns  = zeros(mM,1);
    -0127 kcatInfo.info.rest_ns = zeros(mM,1);
    -0128 kcatInfo.info.org_sa  = zeros(mM,1);
    -0129 kcatInfo.info.rest_sa = zeros(mM,1);
    -0130 kcatInfo.info.wcLevel = NaN(mM,1);
    -0131 kcatInfo.stats.queries  = 0;
    -0132 kcatInfo.stats.org_s    = 0;
    -0133 kcatInfo.stats.rest_s   = 0;
    -0134 kcatInfo.stats.org_ns   = 0;
    -0135 kcatInfo.stats.rest_ns  = 0;
    -0136 kcatInfo.stats.org_sa   = 0;
    -0137 kcatInfo.stats.rest_sa  = 0;
    -0138 kcatInfo.stats.wc0      = 0;
    -0139 kcatInfo.stats.wc1      = 0;
    -0140 kcatInfo.stats.wc2      = 0;
    -0141 kcatInfo.stats.wc3      = 0;
    -0142 kcatInfo.stats.wc4      = 0;
    -0143 kcatInfo.stats.matrix   = zeros(6,5);
    -0144 
    -0145 %build an EC index to speed things up a bit - many of the ECs appear
    -0146 %many times - unnecessary to compare them all
    -0147 %so, here, each EC string appears only once, and you get a vector with
    -0148 %indices to the rows in KCATcell
    -0149 [ECIndexIds,~,ic] = unique(KCATcell{1});
    -0150 EcIndexIndices = cell(length(ECIndexIds),1);
    -0151 for i = 1:length(EcIndexIndices)
    -0152     EcIndexIndices{i} = find(ic == i).';
    -0153 end
    -0154 
    -0155 %Apply force wildcard level
    -0156 while forceWClvl > 0
    -0157     eccodes=regexprep(eccodes,'(.)*(\.\d+)(\.-)*$','$1\.-$3');
    -0158     forceWClvl = forceWClvl - 1;
    -0159 end
    -0160 if forceWClvl == 1
    -0161     eccodes = regexprep(eccodes,'.*','-\.-\.-\.-');
    -0162 end
    -0163 
    -0164 progressbar('Gathering kcat values by fuzzy matching to BRENDA database')
    -0165 %Main loop:
    -0166 for i = 1:mM
    -0167     %Match:
    -0168     EC = eccodes{i};
    -0169     if ~isempty(EC)
    -0170         EC = strsplit(EC,';');
    -0171         %Try to match direct reaction:
    -0172         if ~isempty(substrates{i})
    -0173             [kcats(i), kcatInfo.info,kcatInfo.stats] = iterativeMatch(EC,substrates{i},substrCoeffs{i},i,KCATcell,...
    -0174                 kcatInfo.info,kcatInfo.stats,org_name,...
    -0175                 phylDistStruct,org_index,SAcell,ECIndexIds,EcIndexIndices);
    -0176         end
    -0177     end
    -0178     progressbar(i/mM)
    -0179 end
    -0180 
    -0181 kcatList.source      = 'brenda';
    -0182 kcatList.rxns        = model.ec.rxns(ecRxns);
    -0183 kcatList.substrates  = substrates;
    -0184 kcatList.kcats       = kcats;
    -0185 kcatList.eccodes     = eccodes;
    -0186 kcatList.wildcardLvl = kcatInfo.info.wcLevel;
    -0187 kcatList.origin      = NaN(numel(model.ec.rxns(ecRxns)),1);
    -0188 % This can be refactored, iterativeMatch and their nested functions can
    -0189 % just directly report the origin number.
    -0190 origin = [kcatInfo.info.org_s kcatInfo.info.rest_s kcatInfo.info.org_ns kcatInfo.info.rest_ns kcatInfo.info.org_sa kcatInfo.info.rest_sa];
    -0191 for i=1:6
    -0192     kcatList.origin(find(origin(:,i))) = i;
    -0193 end
    -0194 end
    -0195 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
    -0196 function [kcat,dir,tot] =iterativeMatch(EC,subs,substrCoeff,i,KCATcell,dir,tot,...
    -0197     name,phylDist,org_index,SAcell,ECIndexIds,EcIndexIndices)
    -0198 %Will iteratively try to match the EC number to some registry in BRENDA,
    -0199 %using each time one additional wildcard.
    -0200 
    -0201 kcat    = zeros(size(EC));
    -0202 origin  = zeros(size(EC));
    -0203 matches = zeros(size(EC));
    -0204 wc_num  = ones(size(EC)).*1000;
    -0205 for k = 1:length(EC)
    -0206     success  = false;
    -0207     while ~success
    -0208         %Atempt match:
    -0209         [kcat(k),origin(k),matches(k)] = mainMatch(EC{k},subs,substrCoeff,KCATcell,...
    -0210             name,phylDist,...
    -0211             org_index,SAcell,ECIndexIds,EcIndexIndices);
    -0212         %If any match found, ends. If not, introduces one extra wild card and
    -0213         %tries again:
    -0214         if origin(k) > 0
    -0215             success   = true;
    -0216             wc_num(k) = sum(EC{k}=='-');
    -0217         else
    -0218             dot_pos  = [2 strfind(EC{k},'.')];
    -0219             wild_num = sum(EC{k}=='-');
    -0220             wc_text  = '-.-.-.-';
    -0221             EC{k}    = [EC{k}(1:dot_pos(4-wild_num)) wc_text(1:2*wild_num+1)];
    -0222         end
    -0223     end
    -0224 end
    -0225 
    -0226 if sum(origin) > 0
    -0227     %For more than one EC: Choose the maximum value among the ones with the
    -0228     %less amount of wildcards and the better origin:
    -0229     best_pos   = (wc_num == min(wc_num));
    -0230     new_origin = origin(best_pos);
    -0231     best_pos   = (origin == min(new_origin(new_origin~=0)));
    -0232     max_pos    = find(kcat == max(kcat(best_pos)));
    -0233     wc_num     = wc_num(max_pos(1));
    -0234     origin     = origin(max_pos(1));
    -0235     matches    = matches(max_pos(1));
    -0236     kcat       = kcat(max_pos(1));
    -0237 
    -0238     %Update dir and tot:
    -0239     dir.org_s(i)   = matches*(origin == 1);
    -0240     dir.rest_s(i)  = matches*(origin == 2);
    -0241     dir.org_ns(i)  = matches*(origin == 3);
    -0242     dir.org_sa(i)  = matches*(origin == 4);
    -0243     dir.rest_ns(i) = matches*(origin == 5);
    -0244     dir.rest_sa(i) = matches*(origin == 6);
    -0245     dir.wcLevel(i) = wc_num;
    -0246     tot.org_s        = tot.org_s   + (origin == 1);
    -0247     tot.rest_s       = tot.rest_s  + (origin == 2);
    -0248     tot.org_ns       = tot.org_ns  + (origin == 3);
    -0249     tot.org_sa       = tot.org_sa  + (origin == 4);
    -0250     tot.rest_ns      = tot.rest_ns + (origin == 5);
    -0251     tot.rest_sa      = tot.rest_sa + (origin == 6);
    -0252     tot.wc0          = tot.wc0     + (wc_num == 0);
    -0253     tot.wc1          = tot.wc1     + (wc_num == 1);
    -0254     tot.wc2          = tot.wc2     + (wc_num == 2);
    -0255     tot.wc3          = tot.wc3     + (wc_num == 3);
    -0256     tot.wc4          = tot.wc4     + (wc_num == 4);
    -0257     tot.queries      = tot.queries + 1;
    -0258     tot.matrix(origin,wc_num+1) = tot.matrix(origin,wc_num+1) + 1;
    -0259 end
    -0260 
    -0261 end
    -0262 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
    -0263 
    -0264 function [kcat,origin,matches] = mainMatch(EC,subs,substrCoeff,KCATcell,...
    -0265     name,phylDist,org_index,SAcell,ECIndexIds,EcIndexIndices)
    -0266 
    -0267 %First make the string matching. This takes time, so we only want to do
    -0268 %this once:
    -0269 %Relaxes matching if wild cards are present:
    -0270 wild     = false;
    -0271 wild_pos = strfind(EC,'-');
    -0272 if ~isempty(wild_pos)
    -0273     EC   = EC(1:wild_pos(1)-1);
    -0274     wild = true;
    -0275 end
    -0276 stringMatchesEC_cell = extract_string_matches(EC,KCATcell{1},wild,ECIndexIds,EcIndexIndices);
    -0277 
    -0278 % Matching function prioritizing organism and substrate specificity when
    -0279 % available.
    -0280 
    -0281 origin = 0;
    -0282 %First try to match organism and substrate:
    -0283 [kcat,matches] = matchKcat(EC,subs,substrCoeff,KCATcell,name,true,false,...
    -0284     phylDist,org_index,SAcell,stringMatchesEC_cell,[]);
    -0285 if matches > 0 && ~wild % If wildcard, ignore substrate match
    -0286     origin = 1;
    -0287     %If no match, try the closest organism but match the substrate:
    -0288 else
    -0289     [kcat,matches] = matchKcat(EC,subs,substrCoeff,KCATcell,'',true,false,...
    -0290         phylDist,org_index,SAcell,stringMatchesEC_cell,[]);
    -0291     if matches > 0 && ~wild % If wildcard, ignore substrate match
    -0292         origin = 2;
    -0293         %If no match, try to match organism but with any substrate:
    -0294     else
    -0295         [kcat,matches] = matchKcat(EC,subs,substrCoeff,KCATcell,name,false,false,...
    -0296             phylDist,org_index,SAcell,stringMatchesEC_cell,[]);
    -0297         if matches > 0
    -0298             origin = 3;
    -0299             %If no match, try to match organism but for any substrate (SA*MW):
    -0300         else
    -0301             %create matching index for SA, has not been needed until now
    -0302             stringMatchesSA = extract_string_matches(EC,SAcell{1},wild,[],[]);
    -0303 
    -0304             [kcat,matches] = matchKcat(EC,subs,substrCoeff,KCATcell,name,false,...
    -0305                 true,phylDist,org_index,...
    -0306                 SAcell,stringMatchesEC_cell,stringMatchesSA);
    -0307             if matches > 0
    -0308                 origin = 4;
    -0309                 %If no match, try any organism and any substrate:
    -0310             else
    -0311                 [kcat,matches] = matchKcat(EC,subs,substrCoeff,KCATcell,'',false,...
    -0312                     false,phylDist,...
    -0313                     org_index,SAcell,stringMatchesEC_cell,stringMatchesSA);
    -0314                 if matches > 0
    -0315                     origin = 5;
    -0316                     %Again if no match, look for any org and SA*MW
    -0317                 else
    -0318                     [kcat,matches] = matchKcat(EC,subs,substrCoeff,KCATcell,'',...
    -0319                         false,true,phylDist,...
    -0320                         org_index,SAcell,stringMatchesEC_cell,stringMatchesSA);
    -0321                     if matches > 0
    -0322                         origin = 6;
    -0323                     end
    -0324                 end
    -0325 
    -0326             end
    -0327         end
    -0328     end
    -0329 end
    -0330 end
    -0331 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
    -0332 function [kcat,matches] = matchKcat(EC,subs,substrCoeff,KCATcell,organism,...
    -0333     substrate,SA,phylDist,...
    -0334     org_index,SAcell,KCATcellMatches,SAcellMatches)
    -0335 
    -0336 %Will go through BRENDA and will record any match. Afterwards, it will
    -0337 %return the average value and the number of matches attained.
    -0338 kcat    = [];
    -0339 matches = 0;
    -0340 
    -0341 if SA
    -0342     %SAcell{1},wild,[],[]
    -0343     EC_indexes = extract_indexes(SAcellMatches,[],SAcell{2},subs,substrate,...
    -0344         organism,org_index,phylDist);
    -0345 
    -0346     kcat       = SAcell{3}(EC_indexes);
    -0347     org_cell   = SAcell{2}(EC_indexes);
    -0348     MW_BRENDA  = SAcell{4}(EC_indexes);
    -0349 
    -0350 else
    -0351     %KCATcell{1},wild,ECIndexIds,EcIndexIndices
    -0352     EC_indexes = extract_indexes(KCATcellMatches,KCATcell{2},KCATcell{3},...
    -0353         subs,substrate,organism,org_index,...
    -0354         phylDist);
    -0355     if substrate
    -0356         for j = 1:length(EC_indexes)
    -0357             indx = EC_indexes(j);
    -0358             for k = 1:length(subs)
    -0359                 if (isempty(subs{k}))
    -0360                     break;
    -0361                 end
    -0362                 %l = logical(strcmpi(model.metNames,subs{k}).*(model.S(:,i)~=0)); %I don't understand the .* (model.S(:,i)~=0) part, it shouldn't be needed?/JG;
    -0363                 if ~isempty(subs{k}) && strcmpi(subs{k},KCATcell{2}(indx))
    -0364                     if KCATcell{4}(indx) > 0
    -0365                         coeff = min(substrCoeff);
    -0366                         kCatTmp = KCATcell{4}(indx);
    -0367                         kcat  = [kcat;kCatTmp/coeff];
    -0368                     end
    -0369                 end
    -0370             end
    -0371         end
    -0372     else
    -0373         kcat = KCATcell{4}(EC_indexes);
    -0374     end
    -0375 end
    -0376 %Return maximum value:
    -0377 if isempty(kcat)
    -0378     kcat = 0;
    -0379 else
    -0380     matches        = length(kcat);
    -0381     [kcat,MaxIndx] = max(kcat);
    -0382 end
    -0383 %Avoid SA*Mw values over the diffusion limit rate  [Bar-Even et al. 2011]
    -0384 if kcat>(1E7)
    -0385     kcat = 1E7;
    -0386 end
    -0387 end
    -0388 
    -0389 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
    -0390 %Make the string matches of the ECs. This is heavy, so only do it once!
    -0391 %
    -0392 function EC_indexes = extract_string_matches(EC,EC_cell,wild,ECIndexIds,EcIndexIndices)
    -0393 EC_indexes = [];
    -0394 EC_indexesOld = [];
    -0395 if wild
    -0396     if (~isempty(ECIndexIds)) %In some cases the EC_cell is not from KCatCell
    -0397         X = find(contains(ECIndexIds, EC));
    -0398         for j = 1:length(X)
    -0399             EC_indexes = [EC_indexes,EcIndexIndices{X(j)}];
    -0400         end
    -0401     else %Not optimized
    -0402         for j=1:length(EC_cell)
    -0403             if strfind(EC_cell{j},EC)==1
    -0404                 EC_indexes = [EC_indexes,j];
    -0405             end
    -0406         end
    -0407     end
    -0408 else
    -0409     if (~isempty(ECIndexIds)) %In some cases the EC_cell is not from KCatCell
    -0410         mtch = find(strcmpi(EC,ECIndexIds));
    -0411         if (~isempty(mtch))
    -0412             EC_indexes = EcIndexIndices{mtch};
    -0413         end
    -0414     else %%Not optimized
    -0415         if ~isempty(EC_cell)
    -0416             EC_indexes = transpose(find(strcmpi(EC,EC_cell)));
    -0417         end
    -0418     end
    -0419 end
    -0420 
    -0421 end
    -0422 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
    -0423 %Extract the indexes of the entries in the BRENDA data that meet the
    -0424 %conditions specified by the search criteria
    -0425 function EC_indexes = extract_indexes(EC_indCellStringMatches,subs_cell,orgs_cell,subs,...
    -0426     substrate,organism, org_index,...
    -0427     phylDist)
    -0428 
    -0429 EC_indexes = EC_indCellStringMatches;%reuse so the string comparisons are not run many times
    -0430 
    -0431 %If substrate=true then it will extract only the substrates appereances
    -0432 %indexes in the EC subset from the BRENDA cell array
    -0433 
    -0434 if substrate
    -0435     if (~isempty(EC_indexes)) %optimization
    -0436         Subs_indexes = [];
    -0437         for l = 1:length(subs)
    -0438             if (isempty(subs{l}))
    -0439                 break;
    -0440             end
    -0441             Subs_indexes = horzcat(Subs_indexes,EC_indexes(strcmpi(subs(l),...
    -0442                 subs_cell(EC_indexes))));
    -0443         end
    -0444         EC_indexes = Subs_indexes;
    -0445     end
    -0446 end
    -0447 
    -0448 EC_orgs = orgs_cell(EC_indexes);
    -0449 %If specific organism values are requested looks for all the organism
    -0450 %repetitions on the subset BRENDA cell array(EC_indexes)
    -0451 if string(organism) ~= ''
    -0452     EC_indexes = EC_indexes(strcmpi(string(organism),EC_orgs));
    -0453 
    -0454     %If KEGG code was assigned to the organism (model) then it will look for
    -0455     %the Kcat value for the closest organism
    -0456 elseif org_index~='*' %&& org_index~=''
    -0457     KEGG_indexes = [];temp = [];
    -0458 
    -0459     %For relating a phyl dist between the modelled organism and the organisms
    -0460     %on the BRENDA cell array it should search for a KEGG code for each of
    -0461     %these
    -0462     for j=1:length(EC_indexes)
    -0463         %Assigns a KEGG index for those found on the KEGG struct
    -0464         orgs_index = find(strcmpi(orgs_cell(EC_indexes(j)),phylDist.names),1);
    -0465         if ~isempty(orgs_index)
    -0466             KEGG_indexes = [KEGG_indexes; orgs_index];
    -0467             temp         = [temp;EC_indexes(j)];
    -0468             %For values related to organisms without KEGG code, then it will
    -0469             %look for KEGG code for the first organism with the same genus
    -0470         else
    -0471             org = orgs_cell{EC_indexes(j)};
    -0472             orgGenus = lower(regexprep(org,'\s.*',''));
    -0473             if isKey(phylDist.genusHashMap,orgGenus) %annoyingly, this seems to be needed
    -0474                 matchInd = cell2mat(values(phylDist.genusHashMap,{orgGenus}));
    -0475                 matches = phylDist.uniqueGenusIndices{matchInd};
    -0476                 k = matches(1);
    -0477                 KEGG_indexes = [KEGG_indexes;k];
    -0478                 temp         = [temp;EC_indexes(j)];
    -0479             end
    -0480         end
    -0481     end
    -0482     %Update the EC_indexes cell array
    -0483     EC_indexes = temp;
    -0484     %Looks for the taxonomically closest organism and saves the index of
    -0485     %its appearences in the BRENDA cell
    -0486     if ~isempty(EC_indexes)
    -0487         distances = phylDist.distMat(org_index,KEGG_indexes);
    -0488         EC_indexes = EC_indexes(distances == min(distances));
    -0489     end
    -0490 end
    -0491 end
    -0492 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
    -0493 function org_index = find_inKEGG(org_name,names)
    -0494 org_index      = find(strcmpi(org_name,names));
    -0495 if numel(org_index)>1
    -0496     org_index = org_index(1);
    -0497 elseif isempty(org_index)
    -0498     org_name    = regexprep(org_name,'\s.*','');
    -0499     org_index   = find(strcmpi(org_name,names));
    -0500     if numel(org_index)>1
    -0501         org_index = org_index(1);
    -0502     elseif isempty(org_index)
    -0503         org_index = '*';
    -0504     end
    -0505 end
    -0506 end
    -0507 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
    -0508 function phylDistStruct =  KEGG_struct(phylpath)
    -0509 load(phylpath)
    -0510 phylDistStruct.ids   = transpose(phylDistStruct.ids);
    -0511 phylDistStruct.names = transpose(phylDistStruct.names);
    -0512 phylDistStruct.names = regexprep(phylDistStruct.names,'\s*\(.*','');
    -0513 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 deleted file mode 100644 index f412d53f..00000000 --- a/doc/src/geckomat/gather_kcats/getStandardKcat.html +++ /dev/null @@ -1,419 +0,0 @@ - - - - Description of getStandardKcat - - - - - - - - - -
    Home > src > geckomat > gather_kcats > getStandardKcat.m
    - - - -

    getStandardKcat -

    - -

    PURPOSE ^

    -
    getStandardKcat
    - -

    SYNOPSIS ^

    -
    function [model, rxnsMissingGPR, standardMW, standardKcat, rxnsNoKcat] = getStandardKcat(model, modelAdapter, threshold, fillZeroKcat)
    - -

    DESCRIPTION ^

    -
     getStandardKcat
    -   Calculate an standard kcat and standard molecular weight (MW) that can
    -   be used to apply enzyme constraints to reactions without any associated
    -   enzymes. Such reactions have either an empty model.grRules field, or
    -   they have no match in model.ec.rxns (which can be the case if the genes
    -   in the model.grRules field could not be mapped to enzymes). This is
    -   done by adding those reactions to model.ec, assign a "standard"
    -   pseudoenzyme with the standard MW (median of all proteins in the
    -   organism) and standard kcat (median from all kcat, or subsystem
    -   specific kcat).
    -
    -   A reaction is assigned a subSystem specific kcat values if the model
    -   has a subSystems field and the reaction is annotated with a subSystem.
    -   Only the first subSystem will be considered if multiple are annotated
    -   to the same reaction.
    -
    -   Exchange, transport and pseudoreactions are filtered out, plus any
    -   reaction identifiers specified in /data/pseudoRxns.tsv in the model
    -   adapter folder.
    -
    -   In addition, reactions that are annotated with an enzyme (and therefore
    -   already in model.ec), but not assigned any reaction-specific kcat value
    -   (their model.ec.kcat entry is either 0 or NaN), can be assigned
    -   standard kcat values by a similar approach. However, those reactions
    -   will not be linked to the "standard" pseudoenzyme, but will use the
    -   enzyme that they had already been associated with.
    -
    -   Any pre-existing standard kcat assignments (identified by 'standard'
    -   entires in model.ec.source) are removed when applying this function.
    -
    - Input:
    -   model           an ecModel in GECKO 3 format (with ecModel.ec structure)
    -   modelAdapter    a loaded model adapter (Optional, will otherwise use
    -                   the default model adapter).
    -   threshold       a threshold to determine when use a kcat value based on
    -                   the mean kcat of the reactions in the same subSystem or
    -                   based on the median value of all the kcat in the model.
    -                   Second option is used when the number of reactions in a
    -                   determined subSystem is < threshold. (Optional, default
    -                   = 10)
    -   fillZeroKcat    logical whether zero kcat values should be replaced
    -                   with standard kcat values. (Optional, default = true).
    -
    - Output:
    -   model           ecModel where model.ec is expanded with a standard
    -                   protein with standard kcat and standard MW, assigned to
    -                   reactions without gene associations.
    -   rxnsMissingGPR  a list of updated rxns identifiers with a standard value
    -   standardMW      the standard MW value calculated
    -   standardKcat    the standard Kcat value calculated 
    -   rxnsNoKcat      a list of rxns identifiers whose zero kcat has been replaced
    -
    -   While model.ec.kcat is populated, applyKcatConstraints would still need
    -   to be run to apply the new constraints to the S-matrix.
    -
    - Usage:
    -    [model, rxnsMissingGPR, standardMW, standardKcat, rxnsNoKcat] = getStandardKcat(model, modelAdapter, threshold, fillZeroKcat);
    - - -

    CROSS-REFERENCE INFORMATION ^

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

    SUBFUNCTIONS ^

    - - -

    SOURCE CODE ^

    -
    0001 function [model, rxnsMissingGPR, standardMW, standardKcat, rxnsNoKcat] = getStandardKcat(model, modelAdapter, threshold, fillZeroKcat)
    -0002 % getStandardKcat
    -0003 %   Calculate an standard kcat and standard molecular weight (MW) that can
    -0004 %   be used to apply enzyme constraints to reactions without any associated
    -0005 %   enzymes. Such reactions have either an empty model.grRules field, or
    -0006 %   they have no match in model.ec.rxns (which can be the case if the genes
    -0007 %   in the model.grRules field could not be mapped to enzymes). This is
    -0008 %   done by adding those reactions to model.ec, assign a "standard"
    -0009 %   pseudoenzyme with the standard MW (median of all proteins in the
    -0010 %   organism) and standard kcat (median from all kcat, or subsystem
    -0011 %   specific kcat).
    -0012 %
    -0013 %   A reaction is assigned a subSystem specific kcat values if the model
    -0014 %   has a subSystems field and the reaction is annotated with a subSystem.
    -0015 %   Only the first subSystem will be considered if multiple are annotated
    -0016 %   to the same reaction.
    -0017 %
    -0018 %   Exchange, transport and pseudoreactions are filtered out, plus any
    -0019 %   reaction identifiers specified in /data/pseudoRxns.tsv in the model
    -0020 %   adapter folder.
    -0021 %
    -0022 %   In addition, reactions that are annotated with an enzyme (and therefore
    -0023 %   already in model.ec), but not assigned any reaction-specific kcat value
    -0024 %   (their model.ec.kcat entry is either 0 or NaN), can be assigned
    -0025 %   standard kcat values by a similar approach. However, those reactions
    -0026 %   will not be linked to the "standard" pseudoenzyme, but will use the
    -0027 %   enzyme that they had already been associated with.
    -0028 %
    -0029 %   Any pre-existing standard kcat assignments (identified by 'standard'
    -0030 %   entires in model.ec.source) are removed when applying this function.
    -0031 %
    -0032 % Input:
    -0033 %   model           an ecModel in GECKO 3 format (with ecModel.ec structure)
    -0034 %   modelAdapter    a loaded model adapter (Optional, will otherwise use
    -0035 %                   the default model adapter).
    -0036 %   threshold       a threshold to determine when use a kcat value based on
    -0037 %                   the mean kcat of the reactions in the same subSystem or
    -0038 %                   based on the median value of all the kcat in the model.
    -0039 %                   Second option is used when the number of reactions in a
    -0040 %                   determined subSystem is < threshold. (Optional, default
    -0041 %                   = 10)
    -0042 %   fillZeroKcat    logical whether zero kcat values should be replaced
    -0043 %                   with standard kcat values. (Optional, default = true).
    -0044 %
    -0045 % Output:
    -0046 %   model           ecModel where model.ec is expanded with a standard
    -0047 %                   protein with standard kcat and standard MW, assigned to
    -0048 %                   reactions without gene associations.
    -0049 %   rxnsMissingGPR  a list of updated rxns identifiers with a standard value
    -0050 %   standardMW      the standard MW value calculated
    -0051 %   standardKcat    the standard Kcat value calculated
    -0052 %   rxnsNoKcat      a list of rxns identifiers whose zero kcat has been replaced
    -0053 %
    -0054 %   While model.ec.kcat is populated, applyKcatConstraints would still need
    -0055 %   to be run to apply the new constraints to the S-matrix.
    -0056 %
    -0057 % Usage:
    -0058 %    [model, rxnsMissingGPR, standardMW, standardKcat, rxnsNoKcat] = getStandardKcat(model, modelAdapter, threshold, fillZeroKcat);
    -0059 
    -0060 if nargin < 2 || isempty(modelAdapter)
    -0061     modelAdapter = ModelAdapterManager.getDefault();
    -0062     if isempty(modelAdapter)
    -0063         error('Either send in a modelAdapter or set the default model adapter in the ModelAdapterManager.')
    -0064     end
    -0065 end
    -0066 params = modelAdapter.getParameters();
    -0067 
    -0068 if nargin < 3 || isempty(threshold)
    -0069     threshold = 10;
    -0070 end
    -0071 
    -0072 if nargin < 4 || isempty(fillZeroKcat)
    -0073     fillZeroKcat = true;
    -0074 end
    -0075 
    -0076 databases = loadDatabases('uniprot', modelAdapter);
    -0077 
    -0078 % An standard MW is defined for all the rxns which does not have a GPR
    -0079 % rule defined. This is based in all the proteins reported for the specific
    -0080 % organism in uniprot
    -0081 standardMW = median(databases.uniprot.MW, 'omitnan');
    -0082 
    -0083 % An standard Kcat is defined for all the rxns which does not have a GPR
    -0084 % rule defined. In this case, the kcat value for a particular reaction is
    -0085 % defined as the mean of the kcat values of the reactions involved in the
    -0086 % same subsystem in which the given reaction is involved. Nevertheless, if
    -0087 % a subSystem have a number of reactions lower than a treshold, the kcat
    -0088 % value will be the median of the kcat in all the reactions of the model.
    -0089 
    -0090 % Remove from the list those with kcat zero
    -0091 rxnsKcatZero = model.ec.kcat > 0;
    -0092 
    -0093 % Get the kcat value based on all the kcats in the model
    -0094 standardKcat = median(model.ec.kcat(rxnsKcatZero), 'omitnan');
    -0095 
    -0096 % If the model have subSystems assigned calculate kcat based on subSystem
    -0097 if isfield(model,'subSystems') && ~all(cellfun(@isempty, model.subSystems))
    -0098     standard = false;
    -0099     if model.ec.geckoLight
    -0100         modRxns = extractAfter(model.ec.rxns,4);
    -0101     else
    -0102         modRxns = model.ec.rxns;
    -0103     end
    -0104     % Map ec-rxns to model.rxns
    -0105     [~,rxnIdx]  = ismember(modRxns,model.rxns);
    -0106     % Choose first subSystem
    -0107     enzSubSystems = flattenCell(model.subSystems(rxnIdx));
    -0108     enzSubSystems = enzSubSystems(:,1);
    -0109     if ~all(cellfun(@isempty, enzSubSystems))
    -0110 
    -0111     % Make list of unique subsystems, and which rxns are linked to them
    -0112     [enzSubSystem_names, ~, rxnToSub] = unique(enzSubSystems);
    -0113     % Make matrix of ec-rxns vs. unique subsystem index
    -0114     ind = sub2ind([numel(enzSubSystem_names) numel(enzSubSystems)],rxnToSub',1:numel(rxnToSub));
    -0115     kcatSubSystem = false([numel(enzSubSystem_names) numel(enzSubSystems)]);
    -0116     kcatSubSystem(ind) = true;
    -0117     % Number of kcats per subSystem
    -0118     kcatsPerSubSystem = sum(kcatSubSystem,2);
    -0119     % Calculate average kcat values per subSystem
    -0120     kcatSubSystem = (kcatSubSystem*model.ec.kcat)./kcatsPerSubSystem;
    -0121     kcatSubSystem(kcatsPerSubSystem < threshold) = standardKcat;
    -0122     else
    -0123         standard = true;
    -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');
    -0129 end
    -0130 
    -0131 % Find reactions without GPR
    -0132 rxnsMissingGPR = find(cellfun(@isempty, model.grRules));
    -0133 
    -0134 % Find reactions with GPR but without model.ec entry (for instance due to
    -0135 % no protein matching)
    -0136 rxnsMissingEnzyme = find(~cellfun(@isempty, model.grRules));
    -0137 if model.ec.geckoLight
    -0138     ecRxnsList = unique(extractAfter(model.ec.rxns,4));
    -0139 else
    -0140     ecRxnsList = model.ec.rxns;
    -0141 end
    -0142 rxnsMissingEnzyme = find(and(~ismember(model.rxns(rxnsMissingEnzyme),ecRxnsList), ~contains(model.rxns(rxnsMissingEnzyme),'usage_prot_')));
    -0143 rxnsMissingGPR = [rxnsMissingGPR;rxnsMissingEnzyme];
    -0144 
    -0145 % Get custom list of reaction IDs to ignore, if existing. First column
    -0146 % contains reaction IDs, second column contains reaction names for
    -0147 % reference only.
    -0148 if exist(fullfile(params.path,'data','pseudoRxns.tsv'),'file')
    -0149     fID        = fopen(fullfile(params.path,'data','pseudoRxns.tsv'));
    -0150     fileData   = textscan(fID,'%s %s','delimiter','\t');
    -0151     fclose(fID);
    -0152     customRxns = fileData{1};
    -0153     customRxns = find(ismember(model.rxns,customRxns));
    -0154 else
    -0155     customRxns = [];
    -0156 end
    -0157 % Get and remove exchange, transport, spontaneous and pseudo reactions
    -0158 [~, exchangeRxns]  = getExchangeRxns(model);
    -0159 transportRxns = getTransportRxns(model);
    -0160 [spontaneousRxns, ~] = modelAdapter.getSpontaneousReactions(model);
    -0161 pseudoRxns = contains(model.rxnNames,'pseudoreaction');
    -0162 slimeRxns = contains(model.rxnNames,'SLIME rxn');
    -0163 rxnsToIgnore = [customRxns; exchangeRxns; find(transportRxns); ...
    -0164                 find(spontaneousRxns); find(pseudoRxns); find(slimeRxns)];
    -0165 rxnsMissingGPR(ismember(rxnsMissingGPR, rxnsToIgnore)) = [];
    -0166 
    -0167 % Only add if not geckoLight & getStandardKcat was not run earlier
    -0168 if ~any(strcmp(model.mets,'prot_standard'))
    -0169     % Add a new gene to be consistent with ec field named standard
    -0170     proteinStdGenes.genes = 'standard';
    -0171     if isfield(model,'geneShortNames')
    -0172         proteinStdGenes.geneShortNames = 'std';
    -0173     end
    -0174     model = addGenesRaven(model, proteinStdGenes);
    -0175 
    -0176     if ~model.ec.geckoLight
    -0177         % Add a new metabolite named prot_standard
    -0178         proteinStdMets.mets         = 'prot_standard';
    -0179         proteinStdMets.metNames     = proteinStdMets.mets;
    -0180         % Validate compartment
    -0181         compartmentID = strcmp(model.compNames,params.enzyme_comp);
    -0182         if ~any(compartmentID)
    -0183             error(['Compartment ' params.enzyme_comp ' (specified in params.enzyme_comp) '...
    -0184                 'cannot be found in model.compNames'])
    -0185         end
    -0186         proteinStdMets.compartments = model.comps(compartmentID);
    -0187 
    -0188         if isfield(model,'metNotes')
    -0189             proteinStdMets.metNotes = 'Standard enzyme-usage pseudometabolite';
    -0190         end
    -0191         model = addMets(model, proteinStdMets);
    -0192 
    -0193         % Add a protein usage reaction if not a light version
    -0194         proteinStdUsageRxn.rxns         = {'usage_prot_standard'};
    -0195         proteinStdUsageRxn.rxnNames     = proteinStdUsageRxn.rxns;
    -0196         proteinStdUsageRxn.mets         = {proteinStdMets.mets, 'prot_pool'};
    -0197         proteinStdUsageRxn.stoichCoeffs = [-1, 1];
    -0198         proteinStdUsageRxn.lb           = -1000;
    -0199         proteinStdUsageRxn.ub           = 0;
    -0200         proteinStdUsageRxn.grRules      = proteinStdGenes.genes;
    -0201 
    -0202         model = addRxns(model, proteinStdUsageRxn);
    -0203     end
    -0204     % Update .ec structure in model
    -0205     model.ec.genes(end+1)      = {'standard'};
    -0206     model.ec.enzymes(end+1)    = {'standard'};
    -0207     model.ec.mw(end+1)         = standardMW;
    -0208     model.ec.sequence(end+1)   = {''};
    -0209     % Additional info
    -0210     if isfield(model.ec,'concs')
    -0211         model.ec.concs(end+1)  = nan();
    -0212     end
    -0213 
    -0214     % Expand the enzyme rxns matrix
    -0215     model.ec.rxnEnzMat =  [model.ec.rxnEnzMat, zeros(length(model.ec.rxns), 1)]; % 1 new enzyme
    -0216     model.ec.rxnEnzMat =  [model.ec.rxnEnzMat; zeros(length(rxnsMissingGPR), length(model.ec.enzymes))]; % new rxns
    -0217 end
    -0218 stdMetIdx = find(strcmpi(model.ec.enzymes, 'standard'));
    -0219 
    -0220 % Remove previous standard kcat assignment
    -0221 oldStandardEnz = find(strcmp(model.ec.source,'standard'));
    -0222 if ~isempty(oldStandardEnz)
    -0223     oldStandardProt = logical(model.ec.rxnEnzMat(oldStandardEnz,stdMetIdx));
    -0224     % If annotated with real enzyme => set kcat to zero
    -0225     model.ec.kcat(oldStandardEnz(~oldStandardProt))        = 0;
    -0226     model.ec.source(oldStandardEnz(~oldStandardProt))      = {''};
    -0227     % If annotated with standard protein => remove entry
    -0228     model.ec.rxns(oldStandardEnz(oldStandardProt))        = [];
    -0229     model.ec.kcat(oldStandardEnz(oldStandardProt))        = [];
    -0230     model.ec.source(oldStandardEnz(oldStandardProt))      = [];
    -0231     model.ec.notes(oldStandardEnz(oldStandardProt))       = [];
    -0232     model.ec.eccodes(oldStandardEnz(oldStandardProt))     = [];
    -0233     model.ec.rxnEnzMat(oldStandardEnz(oldStandardProt),:) = [];
    -0234 end
    -0235 
    -0236 numRxns = length(model.ec.rxns);
    -0237 for i = 1:numel(rxnsMissingGPR)
    -0238     rxnIdx = rxnsMissingGPR(i);
    -0239 
    -0240     % Update .ec structure in model
    -0241     if ~model.ec.geckoLight
    -0242         model.ec.rxns(end+1)     = model.rxns(rxnIdx);
    -0243         % Add prefix in case is light version
    -0244     else
    -0245         model.ec.rxns{end+1}     = ['001_' model.rxns{rxnIdx}];
    -0246     end
    -0247 
    -0248     if ~standard
    -0249         kcatSubSystemIdx = strcmpi(enzSubSystem_names, model.subSystems{rxnIdx}(1));
    -0250         if all(kcatSubSystemIdx)
    -0251             model.ec.kcat(end+1) = kcatSubSystem(kcatSubSystemIdx);
    -0252         else
    -0253             model.ec.kcat(end+1) = standardKcat;
    -0254         end
    -0255     else
    -0256         model.ec.kcat(end+1) = standardKcat;
    -0257     end
    -0258 
    -0259     model.ec.source(end+1)   = {'standard'};
    -0260     model.ec.notes(end+1)    = {''};
    -0261     model.ec.eccodes(end+1)  = {''};
    -0262 
    -0263     % Update the enzyme rxns matrix
    -0264     model.ec.rxnEnzMat(numRxns+i, stdMetIdx) = 1;
    -0265 end
    -0266 % Get the rxns identifiers of the updated rxns
    -0267 rxnsMissingGPR = model.rxns(rxnsMissingGPR);
    -0268 
    -0269 if fillZeroKcat
    -0270     zeroKcat = model.ec.kcat == 0 | isnan(model.ec.kcat);
    -0271     model.ec.kcat(zeroKcat)     = standardKcat;
    -0272     model.ec.source(zeroKcat)   = {'standard'};
    -0273     rxnsNoKcat = model.ec.rxns(zeroKcat);
    -0274 else
    -0275     rxnsNoKcat = [];
    -0276 end
    -0277 end
    -0278 
    -0279 function Cflat = flattenCell(C,strFlag)
    -0280 %FLATTENCELL  Flatten a nested column cell array into a matrix cell array.
    -0281 %
    -0282 % CFLAT = FLATTENCELL(C) takes a column cell array in which one or more
    -0283 % entries is a nested cell array, and flattens it into a 2D matrix cell
    -0284 % array, where the nested entries are spread across new columns.
    -0285 %
    -0286 % CFLAT = FLATTENCELL(C,STRFLAG) if STRFLAG is TRUE, empty entries in the
    -0287 % resulting CFLAT will be replaced with empty strings {''}. Default = FALSE
    -0288 if nargin < 2
    -0289     strFlag = false;
    -0290 end
    -0291 
    -0292 % determine which entries are cells
    -0293 cells = cellfun(@iscell,C);
    -0294 
    -0295 % determine number of elements in each nested cell
    -0296 cellsizes = cellfun(@numel,C);
    -0297 cellsizes(~cells) = 1;  % ignore non-cell entries
    -0298 
    -0299 % flatten single-entry cells
    -0300 Cflat = C;
    -0301 Cflat(cells & (cellsizes == 1)) = cellfun(@(x) x{1},Cflat(cells & (cellsizes == 1)),'UniformOutput',false);
    -0302 
    -0303 % iterate through multi-entry cells
    -0304 multiCells = find(cellsizes > 1);
    -0305 for i = 1:length(multiCells)
    -0306     cellContents = Cflat{multiCells(i)};
    -0307     Cflat(multiCells(i),1:length(cellContents)) = cellContents;
    -0308 end
    -0309 
    -0310 % change empty elements to strings, if specified
    -0311 if ( strFlag )
    -0312     Cflat(cellfun(@isempty,Cflat)) = {''};
    -0313 end
    -0314 end
    -
    Generated by m2html © 2005
    - - \ No newline at end of file diff --git a/doc/src/geckomat/gather_kcats/index.html b/doc/src/geckomat/gather_kcats/index.html deleted file mode 100644 index 3f5abb63..00000000 --- a/doc/src/geckomat/gather_kcats/index.html +++ /dev/null @@ -1,29 +0,0 @@ - - - - Index for Directory src\geckomat\gather_kcats - - - - - - - - - - -
    < Master indexIndex for src\geckomat\gather_kcats >
    - -

    Index for src\geckomat\gather_kcats

    - -

    Matlab files in this directory:

    - -
     fuzzyKcatMatchingfuzzyKcatMatching
     getStandardKcatgetStandardKcat
     mergeDLKcatAndFuzzyKcatsmergeDlkcatAndFuzzyKcats
     readDLKcatOutputreadDLKcatOutput
     removeStandardKcatremoveStandardKcat
     runDLKcatrunDLKcat
     selectKcatValueselectKcatValue
     writeDLKcatInputwriteDLKcatInput
    - - - - -
    Generated by m2html © 2005
    - - \ No newline at end of file diff --git a/doc/src/geckomat/gather_kcats/mergeDLKcatAndFuzzyKcats.html b/doc/src/geckomat/gather_kcats/mergeDLKcatAndFuzzyKcats.html deleted file mode 100644 index 7f9e5908..00000000 --- a/doc/src/geckomat/gather_kcats/mergeDLKcatAndFuzzyKcats.html +++ /dev/null @@ -1,199 +0,0 @@ - - - - Description of mergeDLKcatAndFuzzyKcats - - - - - - - - - -
    Home > src > geckomat > gather_kcats > mergeDLKcatAndFuzzyKcats.m
    - - - -

    mergeDLKcatAndFuzzyKcats -

    - -

    PURPOSE ^

    -
    mergeDlkcatAndFuzzyKcats
    - -

    SYNOPSIS ^

    -
    function mergedKcatList = mergeDLKcatAndFuzzyKcats(kcatListDLKcat, kcatListFuzzy, topOriginLimit, bottomOriginLimit, wildcardLimit)
    - -

    DESCRIPTION ^

    -
     mergeDlkcatAndFuzzyKcats
    -   Merges the results from DLKcat and fuzzy matching to BRENDA database.
    -   Order of preference:
    -   1: BRENDA match with correct E.C. number, with origin (see below) not
    -      lower than the specified topOriginLimit
    -   2: DLKcat match
    -   3: BRENDA match with correct E.C. number, with origin below
    -      topOriginLimit but not lower than the bottomOriginLimit
    -   4: BRENDA match with wildcards in the E.C. number, with not more
    -      wildcards than wildcardLimit, and origin not lower than the
    -      bottomOriginLimit
    -
    - Input:
    -   kcatListDLKcat      kcatList derived from readDLKcatOutput
    -   kcatListFuzzy       kcatList derived from fuzzyKcatMatching
    -   topOriginLimit      origin limit for prioritized BRENDA matches. Origin
    -                       is explained in more detail below. (Optional,
    -                       default 6)
    -   bottomOriginLimit   origin limit for low priority BRENDA matches.
    -                       Origin is explained in more detail below.
    -                       (Optional, default 6)
    -   wildcardLimit       maximum number of wildcards in E.C. number of
    -                       BRENDA matches (Optional, default 3)
    -
    - Output:
    -   mergedKcatList      merged list of kcats
    -   
    - The origin parameter:
    -   1: correct organism, correct substrate, kcat
    -   2: any organism, correct substrate, kcat
    -   3: correct organism, any substrate, kcat
    -   4: any organism, any substrate, kcat
    -   5: correct organism, specific activity
    -   6: any organism, specific activity
    -
    - Example of wildcards in E.C. number:
    -   0: 1.1.1.3      glycerol-3-phosphate dehydrogenase (NAD+)
    -   1: 1.1.1.-      oxidoreductase, acting on the CH-OH group of donors,
    -                   with NAD+ or NADP+ as acceptor
    -   2: 1.1.-.-      oxidoreductase, acting on the CH-OH group of donors
    -   3: 1.-.-.-      oxidoreductase
    -
    - Usage:
    -   mergedKcatList = mergeDLKcatAndFuzzyKcats(kcatListDLKcat, kcatListFuzzy, topOriginLimit, bottomOriginLimit, wildcardLimit)
    - - -

    CROSS-REFERENCE INFORMATION ^

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

    SOURCE CODE ^

    -
    0001 function mergedKcatList = mergeDLKcatAndFuzzyKcats(kcatListDLKcat, kcatListFuzzy, topOriginLimit, bottomOriginLimit, wildcardLimit)
    -0002 % mergeDlkcatAndFuzzyKcats
    -0003 %   Merges the results from DLKcat and fuzzy matching to BRENDA database.
    -0004 %   Order of preference:
    -0005 %   1: BRENDA match with correct E.C. number, with origin (see below) not
    -0006 %      lower than the specified topOriginLimit
    -0007 %   2: DLKcat match
    -0008 %   3: BRENDA match with correct E.C. number, with origin below
    -0009 %      topOriginLimit but not lower than the bottomOriginLimit
    -0010 %   4: BRENDA match with wildcards in the E.C. number, with not more
    -0011 %      wildcards than wildcardLimit, and origin not lower than the
    -0012 %      bottomOriginLimit
    -0013 %
    -0014 % Input:
    -0015 %   kcatListDLKcat      kcatList derived from readDLKcatOutput
    -0016 %   kcatListFuzzy       kcatList derived from fuzzyKcatMatching
    -0017 %   topOriginLimit      origin limit for prioritized BRENDA matches. Origin
    -0018 %                       is explained in more detail below. (Optional,
    -0019 %                       default 6)
    -0020 %   bottomOriginLimit   origin limit for low priority BRENDA matches.
    -0021 %                       Origin is explained in more detail below.
    -0022 %                       (Optional, default 6)
    -0023 %   wildcardLimit       maximum number of wildcards in E.C. number of
    -0024 %                       BRENDA matches (Optional, default 3)
    -0025 %
    -0026 % Output:
    -0027 %   mergedKcatList      merged list of kcats
    -0028 %
    -0029 % The origin parameter:
    -0030 %   1: correct organism, correct substrate, kcat
    -0031 %   2: any organism, correct substrate, kcat
    -0032 %   3: correct organism, any substrate, kcat
    -0033 %   4: any organism, any substrate, kcat
    -0034 %   5: correct organism, specific activity
    -0035 %   6: any organism, specific activity
    -0036 %
    -0037 % Example of wildcards in E.C. number:
    -0038 %   0: 1.1.1.3      glycerol-3-phosphate dehydrogenase (NAD+)
    -0039 %   1: 1.1.1.-      oxidoreductase, acting on the CH-OH group of donors,
    -0040 %                   with NAD+ or NADP+ as acceptor
    -0041 %   2: 1.1.-.-      oxidoreductase, acting on the CH-OH group of donors
    -0042 %   3: 1.-.-.-      oxidoreductase
    -0043 %
    -0044 % Usage:
    -0045 %   mergedKcatList = mergeDLKcatAndFuzzyKcats(kcatListDLKcat, kcatListFuzzy, topOriginLimit, bottomOriginLimit, wildcardLimit)
    -0046 
    -0047 if nargin < 5
    -0048     wildcardLimit = 3;
    -0049 end
    -0050 
    -0051 if nargin < 4
    -0052     bottomOriginLimit = 6;
    -0053 end
    -0054 
    -0055 if nargin < 3
    -0056     topOriginLimit = 6;
    -0057 end
    -0058 
    -0059 if (topOriginLimit < 1) || (topOriginLimit > 6)
    -0060     error('topPrioOriginLimit should be between 1 and 6.');
    -0061 end
    -0062 
    -0063 if (bottomOriginLimit < 1) || (bottomOriginLimit > 6)
    -0064     error('originCutLevel should be between 1 and 6.');
    -0065 end
    -0066 
    -0067 if (wildcardLimit < 0) || (wildcardLimit > 3)
    -0068     error('wildcardCutLevel should be between 0 and 3.');
    -0069 end
    -0070 
    -0071 wc = kcatListFuzzy.wildcardLvl;
    -0072 wc(isnan(wc)) = 1000; %large wildcard
    -0073 
    -0074 origin = kcatListFuzzy.origin;
    -0075 origin(isnan(origin)) = 1000; %large origin
    -0076 
    -0077 prio1 = (wc == 0) & (origin <= topOriginLimit);
    -0078 
    -0079 rxnsWithPrio1 = unique(kcatListFuzzy.rxns(prio1));
    -0080 
    -0081 %Things get a bit complicated since not all reactions are in the kcatLists and
    -0082 %some reactions may appear multiple times
    -0083 prio2 = true(length(kcatListDLKcat.rxns),1);
    -0084 prio2(ismember(kcatListDLKcat.rxns, rxnsWithPrio1)) = false;
    -0085 prio2Rxns = unique(kcatListDLKcat.rxns(prio2));
    -0086 
    -0087 %The prioritization between wildcards and origin is already done in fuzzy matching,
    -0088 %so we can join them here
    -0089 prio3 = ((wc == 0) & (origin > topOriginLimit) & (origin <= bottomOriginLimit)) | ...
    -0090         ((wc > 0) & (wc <= wildcardLimit) & (origin <= bottomOriginLimit));
    -0091 prio3(ismember(kcatListFuzzy.rxns, prio2Rxns)) = false;
    -0092 
    -0093 fuzzyRxns = prio1 | prio3;
    -0094 
    -0095 %Now build the merged list, fuzzy followed by dlkcat
    -0096 %The order of the reactions is therefore not preserved.
    -0097 mergedKcatList               = struct();
    -0098 mergedKcatList.source        = 'Merged DLKcat and fuzzy';
    -0099 [fuzzySrc{1:sum(fuzzyRxns)}] = deal(kcatListFuzzy.source);
    -0100 [dlkcatSrc{1:sum(prio2)}]    = deal(kcatListDLKcat.source);
    -0101 mergedKcatList.kcatSource    = [fuzzySrc.';dlkcatSrc.'];
    -0102 mergedKcatList.rxns          = [kcatListFuzzy.rxns(fuzzyRxns);kcatListDLKcat.rxns(prio2)];
    -0103 mergedKcatList.genes         = [cell(sum(fuzzyRxns),1);kcatListDLKcat.genes(prio2)];
    -0104 mergedKcatList.substrates    = [kcatListFuzzy.substrates(fuzzyRxns);kcatListDLKcat.substrates(prio2)];
    -0105 mergedKcatList.kcats         = [kcatListFuzzy.kcats(fuzzyRxns);kcatListDLKcat.kcats(prio2)];
    -0106 mergedKcatList.eccodes       = [kcatListFuzzy.eccodes(fuzzyRxns);cell(sum(prio2),1)];
    -0107 mergedKcatList.wildcardLvl   = [kcatListFuzzy.wildcardLvl(fuzzyRxns);nan(sum(prio2),1)];
    -0108 mergedKcatList.origin        = [kcatListFuzzy.origin(fuzzyRxns);nan(sum(prio2),1)];
    -0109 end
    -
    Generated by m2html © 2005
    - - \ No newline at end of file diff --git a/doc/src/geckomat/gather_kcats/readDLKcatOutput.html b/doc/src/geckomat/gather_kcats/readDLKcatOutput.html deleted file mode 100644 index cb45963f..00000000 --- a/doc/src/geckomat/gather_kcats/readDLKcatOutput.html +++ /dev/null @@ -1,148 +0,0 @@ - - - - Description of readDLKcatOutput - - - - - - - - - -
    Home > src > geckomat > gather_kcats > readDLKcatOutput.m
    - - - -

    readDLKcatOutput -

    - -

    PURPOSE ^

    -
    readDLKcatOutput
    - -

    SYNOPSIS ^

    -
    function kcatList = readDLKcatOutput(model, outFile, modelAdapter)
    - -

    DESCRIPTION ^

    -
     readDLKcatOutput
    -   Reads the DLKcat output file and constructs a kcatList structure, that
    -   can be used by selectKcatValue() to populate the ecModel with kcat
    -   values.
    -
    - Input:
    -   model           an ecModel in GECKO 3 format (with ecModel.ec structure)
    -   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).
    -
    - Output:
    -   kcatList    structure array with list of DLKcat derived kcat values,
    -               with separate entries for each kcat value
    -               source      'DLKcat'           
    -               rxns        reaction identifiers
    -               genes       gene identifiers
    -               substrate   substrate names
    -               kcat        predicted kcat value in /sec
    -
    - Usage:
    -   kcatList = readDLKcatOutput(model, outFile, modelAdapter)
    - - -

    CROSS-REFERENCE INFORMATION ^

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

    SOURCE CODE ^

    -
    0001 function kcatList = readDLKcatOutput(model, outFile, modelAdapter)
    -0002 % readDLKcatOutput
    -0003 %   Reads the DLKcat output file and constructs a kcatList structure, that
    -0004 %   can be used by selectKcatValue() to populate the ecModel with kcat
    -0005 %   values.
    -0006 %
    -0007 % Input:
    -0008 %   model           an ecModel in GECKO 3 format (with ecModel.ec structure)
    -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/removeStandardKcat.html b/doc/src/geckomat/gather_kcats/removeStandardKcat.html deleted file mode 100644 index 66f03c33..00000000 --- a/doc/src/geckomat/gather_kcats/removeStandardKcat.html +++ /dev/null @@ -1,127 +0,0 @@ - - - - Description of removeStandardKcat - - - - - - - - - -
    Home > src > geckomat > gather_kcats > removeStandardKcat.m
    - - - -

    removeStandardKcat -

    - -

    PURPOSE ^

    -
    removeStandardKcat
    - -

    SYNOPSIS ^

    -
    function model = removeStandardKcat(model)
    - -

    DESCRIPTION ^

    -
     removeStandardKcat
    -   Remove the "standard" pseudoenzyme and standard kcat and MW values, as
    -   they were introduced by getStandardKcat. Also standard kcat values that
    -   were assigned by getStandardKcat if fillZeroKcat was set to true are
    -   removed from model.ec.kcat. Both the model.ec and model.S structures
    -   are modified.
    -
    - Input:
    -   model           an ecModel in GECKO 3 format (with ecModel.ec structure)
    -                   that has standard kcat values implemented by
    -                   getStandardKcat.
    -
    - Output:
    -   model           ecModel without standard pseudoprotein and standard
    -                   kcat values
    -
    - Usage:
    -    model = removeStandardKcat(model);
    - - -

    CROSS-REFERENCE INFORMATION ^

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

    SOURCE CODE ^

    -
    0001 function model = removeStandardKcat(model)
    -0002 % removeStandardKcat
    -0003 %   Remove the "standard" pseudoenzyme and standard kcat and MW values, as
    -0004 %   they were introduced by getStandardKcat. Also standard kcat values that
    -0005 %   were assigned by getStandardKcat if fillZeroKcat was set to true are
    -0006 %   removed from model.ec.kcat. Both the model.ec and model.S structures
    -0007 %   are modified.
    -0008 %
    -0009 % Input:
    -0010 %   model           an ecModel in GECKO 3 format (with ecModel.ec structure)
    -0011 %                   that has standard kcat values implemented by
    -0012 %                   getStandardKcat.
    -0013 %
    -0014 % Output:
    -0015 %   model           ecModel without standard pseudoprotein and standard
    -0016 %                   kcat values
    -0017 %
    -0018 % Usage:
    -0019 %    model = removeStandardKcat(model);
    -0020 
    -0021 % Remove standard enzyme from ec structure
    -0022 stdEnzIdx = find(strcmpi(model.ec.enzymes, 'standard'));
    -0023 if ~isempty(stdEnzIdx)
    -0024     model.ec.genes(stdEnzIdx)       = [];
    -0025     model.ec.enzymes(stdEnzIdx)     = [];
    -0026     model.ec.mw(stdEnzIdx)          = [];
    -0027     model.ec.sequence(stdEnzIdx)    = [];
    -0028     if isfield(model.ec,'concs')
    -0029         model.ec.concs(stdEnzIdx)   = [];
    -0030     end
    -0031     rxnEnzIdx = find(model.ec.rxnEnzMat(:,stdEnzIdx));
    -0032     model.ec.rxns(rxnEnzIdx)        = [];
    -0033     model.ec.kcat(rxnEnzIdx)        = [];
    -0034     model.ec.source(rxnEnzIdx)      = [];
    -0035     model.ec.notes(rxnEnzIdx)       = [];
    -0036     model.ec.eccodes(rxnEnzIdx)     = [];
    -0037     model.ec.rxnEnzMat(:,stdEnzIdx) = [];
    -0038     model.ec.rxnEnzMat(rxnEnzIdx,:) = [];
    -0039 end
    -0040 
    -0041 % Remove standard kcat values and reapply kcat constraints for those
    -0042 % specific reactions
    -0043 stdKcatIdx = find(strcmpi(model.ec.source, 'standard'));
    -0044 if ~isempty(stdKcatIdx)
    -0045     model.ec.source(stdKcatIdx)     = {''};
    -0046     model.ec.kcat(stdKcatIdx)       = 0;
    -0047     model = applyKcatConstraints(model,stdKcatIdx);
    -0048 end
    -0049 
    -0050 % Remove standard protein, usage and gene from model structure
    -0051 stdMetIdx = find(strcmpi(model.mets, 'prot_standard'));
    -0052 if ~isempty(stdMetIdx)
    -0053     model       = removeMets(model,stdMetIdx,false,false,false,false);
    -0054 end
    -0055 stdProtEx = find(strcmpi(model.rxns, 'usage_prot_standard'));
    -0056 if ~isempty(stdProtEx)
    -0057     model       = removeReactions(model,stdProtEx,false,false,false);
    -0058 end
    -0059 stdProtGene = find(strcmpi(model.genes, 'standard'));
    -0060 if ~isempty(stdProtGene)
    -0061     model       = removeGenes(model,stdProtGene,false,false,false);
    -0062 end
    -0063 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 deleted file mode 100644 index 313f2fbe..00000000 --- a/doc/src/geckomat/gather_kcats/runDLKcat.html +++ /dev/null @@ -1,121 +0,0 @@ - - - - Description of runDLKcat - - - - - - - - - -
    Home > src > geckomat > gather_kcats > runDLKcat.m
    - - - -

    runDLKcat -

    - -

    PURPOSE ^

    -
    runDLKcat
    - -

    SYNOPSIS ^

    -
    function runDLKcat(modelAdapter,filePath)
    - -

    DESCRIPTION ^

    -
     runDLKcat
    -   Runs DLKcat to predict kcat values from a Docker image. Once DLKcat is succesfully
    -   run, the DLKcatFile will be overwritten with the DLKcat
    -   output in the model-specific 'data' sub-folder taken from modelAdapter
    -   (e.g. GECKO/tutorials/tutorial_yeast-GEM/data/DLKcat.tsv)
    -
    - 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.
    - - -

    CROSS-REFERENCE INFORMATION ^

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

    SOURCE CODE ^

    -
    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
    -0005 %   output in the model-specific 'data' sub-folder taken from modelAdapter
    -0006 %   (e.g. GECKO/tutorials/tutorial_yeast-GEM/data/DLKcat.tsv)
    -0007 %
    -0008 % Input
    -0009 %   modelAdapter    a loaded model adapter. (Optional, will otherwise use
    -0010 %                   the default model adapter)
    -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 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 
    -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/selectKcatValue.html b/doc/src/geckomat/gather_kcats/selectKcatValue.html deleted file mode 100644 index f82c61fc..00000000 --- a/doc/src/geckomat/gather_kcats/selectKcatValue.html +++ /dev/null @@ -1,181 +0,0 @@ - - - - Description of selectKcatValue - - - - - - - - - -
    Home > src > geckomat > gather_kcats > selectKcatValue.m
    - - - -

    selectKcatValue -

    - -

    PURPOSE ^

    -
    selectKcatValue
    - -

    SYNOPSIS ^

    -
    function [model, rxnIdx] = selectKcatValue(model,kcatList,criteria,overwrite)
    - -

    DESCRIPTION ^

    -
     selectKcatValue
    -   From a kcatList with predicted or suggested kcat values, where each
    -   reaction may have multiple entries, one kcat value is selected and
    -   written to model.ec.kcat. Zero values are discarded from the start. By
    -   default, the maximum value is chosen, but alternatives are available.
    -   The kcatList structure is an output of e.g. readDLKcatOutput,
    -   readGotEnzymesOutput, readManualKcatList.
    -
    - Input:
    -   model       an ecModel in GECKO 3 format (with ecModel.ec structure)
    -   kcatList    structure array with separate entries for each kcat value
    -               source      e.g. 'DLKcat' or 'gotenzymes'           
    -               rxns        reaction identifiers, matching model.rxns
    -               genes       gene identifiers, matching model.genes
    -               substrate   substrates, matching model.mets
    -               kcat        predicted kcat value in /sec
    -   criteria    which kcat value should be selected if multiple values are
    -               provided. Options: 'max', 'min', 'median', 'mean'. (Opt,
    -               default 'max')
    -   overwrite   whether existing kcat values should be overwritten.
    -               Options: 'true', 'false', 'ifHigher'. The last option will
    -               overwrite only if the new kcat value is higher. (Opt,
    -               default 'true')
    -
    - Output:
    -   model       ecModel with updated model.ec.kcat and model.ec.source
    -   rxnIdx      list of reaction indices (matching model.ec.rxns), to
    -               indicate which kcat values have been changed.
    - Usage:
    -   [model, rxnIdx] = selectKcatValue(model,kcatList,criteria,overwrite)
    - - -

    CROSS-REFERENCE INFORMATION ^

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

    SOURCE CODE ^

    -
    0001 function [model, rxnIdx] = selectKcatValue(model,kcatList,criteria,overwrite)
    -0002 % selectKcatValue
    -0003 %   From a kcatList with predicted or suggested kcat values, where each
    -0004 %   reaction may have multiple entries, one kcat value is selected and
    -0005 %   written to model.ec.kcat. Zero values are discarded from the start. By
    -0006 %   default, the maximum value is chosen, but alternatives are available.
    -0007 %   The kcatList structure is an output of e.g. readDLKcatOutput,
    -0008 %   readGotEnzymesOutput, readManualKcatList.
    -0009 %
    -0010 % Input:
    -0011 %   model       an ecModel in GECKO 3 format (with ecModel.ec structure)
    -0012 %   kcatList    structure array with separate entries for each kcat value
    -0013 %               source      e.g. 'DLKcat' or 'gotenzymes'
    -0014 %               rxns        reaction identifiers, matching model.rxns
    -0015 %               genes       gene identifiers, matching model.genes
    -0016 %               substrate   substrates, matching model.mets
    -0017 %               kcat        predicted kcat value in /sec
    -0018 %   criteria    which kcat value should be selected if multiple values are
    -0019 %               provided. Options: 'max', 'min', 'median', 'mean'. (Opt,
    -0020 %               default 'max')
    -0021 %   overwrite   whether existing kcat values should be overwritten.
    -0022 %               Options: 'true', 'false', 'ifHigher'. The last option will
    -0023 %               overwrite only if the new kcat value is higher. (Opt,
    -0024 %               default 'true')
    -0025 %
    -0026 % Output:
    -0027 %   model       ecModel with updated model.ec.kcat and model.ec.source
    -0028 %   rxnIdx      list of reaction indices (matching model.ec.rxns), to
    -0029 %               indicate which kcat values have been changed.
    -0030 % Usage:
    -0031 %   [model, rxnIdx] = selectKcatValue(model,kcatList,criteria,overwrite)
    -0032 
    -0033 if nargin < 4
    -0034     overwrite = 'true';
    -0035 elseif islogical(overwrite)
    -0036     if overwrite
    -0037         overwrite = 'true';
    -0038     else
    -0039         overwrite = 'false';
    -0040     end
    -0041 end
    -0042 if nargin < 3
    -0043     criteria = 'max';
    -0044 end
    -0045 
    -0046 % Remove zero kcat values. Only adjusting fields that are used later.
    -0047 removeZero                      = kcatList.kcats == 0;
    -0048 kcatList.kcats(removeZero)      = [];
    -0049 kcatList.rxns(removeZero)       = [];
    -0050 
    -0051 % Map to model.ec.rxns
    -0052 [sanityCheck,idxInModel] = ismember(kcatList.rxns,model.ec.rxns);
    -0053 if ~all(sanityCheck)
    -0054     error('Not all reactions in kcatList are found in model.ec.rxns')
    -0055 end
    -0056 % Make vector with single kcat value per reaction
    -0057 idxInModelUnique = unique(idxInModel);
    -0058 selectedKcats    = zeros(numel(idxInModelUnique),1);
    -0059 selectedSource   = cell(numel(selectedKcats),1);
    -0060 if ~isfield(kcatList,'kcatSource')
    -0061     kcatList.kcatSource = cell(numel(kcatList.kcats),1);
    -0062     kcatList.kcatSource(:) = {kcatList.source};
    -0063 end
    -0064 for i=1:numel(idxInModelUnique)
    -0065     ind = idxInModelUnique(i);
    -0066     idxMatch = find(idxInModel == ind);
    -0067     % Choose the maximum number
    -0068     switch criteria
    -0069         case 'max'
    -0070             [selectedKcats(i),j] = max(kcatList.kcats(idxMatch));
    -0071         case 'min'
    -0072             [selectedKcats(i),j] = min(kcatList.kcats(idxMatch));
    -0073         case 'median'
    -0074             [selectedKcats(i),j] = median(kcatList.kcats(idxMatch));
    -0075         case 'mean'
    -0076             [selectedKcats(i),j] = mean(kcatList.kcats(idxMatch));
    -0077         otherwise
    -0078             error('Invalid criteria specified')
    -0079     end
    -0080     selectedSource(i)    = kcatList.kcatSource(idxMatch(j));
    -0081 end
    -0082 
    -0083 % Populate model.ec.kcat
    -0084 switch overwrite
    -0085     case 'true'
    -0086         model.ec.kcat(idxInModelUnique) = selectedKcats;
    -0087         model.ec.source(idxInModelUnique) = selectedSource;
    -0088     case 'false'
    -0089         emptyKcats = find(model.ec.kcat == 0);
    -0090         [idxInModelUnique,whickKcats] = intersect(idxInModelUnique,emptyKcats,'stable');
    -0091         model.ec.kcat(idxInModelUnique) = selectedKcats(whickKcats);
    -0092         model.ec.source(idxInModelUnique) = selectedSource(whickKcats);
    -0093         
    -0094     case 'ifHigher'
    -0095         higherKcats = model.ec.kcat(idxInModelUnique) < selectedKcats;
    -0096         selectedKcats(~higherKcats) = [];
    -0097         selectedSource(~higherKcats) = [];
    -0098         idxInModelUnique(~higherKcats) = [];
    -0099         model.ec.kcat(idxInModelUnique) = selectedKcats;
    -0100         model.ec.source(idxInModelUnique) = selectedSource;
    -0101     otherwise
    -0102         error('Invalid overwrite flag specified')
    -0103 end
    -0104 rxnIdx = idxInModelUnique;
    -0105 end
    -
    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 deleted file mode 100644 index b8a1b4ae..00000000 --- a/doc/src/geckomat/gather_kcats/writeDLKcatInput.html +++ /dev/null @@ -1,237 +0,0 @@ - - - - Description of writeDLKcatInput - - - - - - - - - -
    Home > src > geckomat > gather_kcats > writeDLKcatInput.m
    - - - -

    writeDLKcatInput -

    - -

    PURPOSE ^

    -
    writeDLKcatInput
    - -

    SYNOPSIS ^

    -
    function writtenTable = writeDLKcatInput(model, ecRxns, modelAdapter, onlyWithSmiles, filename, overwrite)
    - -

    DESCRIPTION ^

    -
     writeDLKcatInput
    -   Prepares the input for DLKcat, and writes it to data/DLKcat.tsv
    -   in the obj.params.path specified in the ModelAdapter.
    -
    - Input:
    -   model           an ecModel in GECKO 3 format (with ecModel.ec structure)
    -   ecRxns          for which reactions (from model.ec.rxns) DLKcat should
    -                   predict kcat values, provided as logical vector with
    -                   same length as model.ec.rxns. (Opt, default is all
    -                   reactions)
    -   modelAdapter    a loaded model adapter (Optional, will otherwise use the
    -                   default model adapter).
    -   onlyWithSmiles  logical whether to only include metabolites with SMILES
    -                   (optional, default true)
    -   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).
    -
    - Output:
    -   writtenTable    The table written, mainly to be used for testing purposes.
    -
    - Usage:
    -   writtenTable = writeDLKcatInput(model, ecRxns, modelAdapter, onlyWithSmiles, filename, overwrite)
    - - -

    CROSS-REFERENCE INFORMATION ^

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

    SOURCE CODE ^

    -
    0001 function writtenTable = writeDLKcatInput(model, ecRxns, modelAdapter, onlyWithSmiles, filename, overwrite)
    -0002 % writeDLKcatInput
    -0003 %   Prepares the input for DLKcat, and writes it to data/DLKcat.tsv
    -0004 %   in the obj.params.path specified in the ModelAdapter.
    -0005 %
    -0006 % Input:
    -0007 %   model           an ecModel in GECKO 3 format (with ecModel.ec structure)
    -0008 %   ecRxns          for which reactions (from model.ec.rxns) DLKcat should
    -0009 %                   predict kcat values, provided as logical vector with
    -0010 %                   same length as model.ec.rxns. (Opt, default is all
    -0011 %                   reactions)
    -0012 %   modelAdapter    a loaded model adapter (Optional, will otherwise use the
    -0013 %                   default model adapter).
    -0014 %   onlyWithSmiles  logical whether to only include metabolites with SMILES
    -0015 %                   (optional, default true)
    -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 substrates for each reaction
    -0134 [substrates, reactions] = find(clearedRedS<0); %the reactions here are in model.ec.rxns space
    -0135 
    -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/calculateMW.html b/doc/src/geckomat/get_enzyme_data/calculateMW.html deleted file mode 100644 index f3dc7b8a..00000000 --- a/doc/src/geckomat/get_enzyme_data/calculateMW.html +++ /dev/null @@ -1,111 +0,0 @@ - - - - Description of calculateMW - - - - - - - - - -
    Home > src > geckomat > get_enzyme_data > calculateMW.m
    - - - -

    calculateMW -

    - -

    PURPOSE ^

    -
    %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
    - -

    SYNOPSIS ^

    -
    function MW = calculateMW(sequence)
    - -

    DESCRIPTION ^

    -
    %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
    - MW = calculateMW(sequence)
    - Calculates de molecular weight of a protein.
    - 
    - INPUT: Sequence (can include extra things such as spaces or numbers).
    - OUTPUT: Molecular weight number
    - 
    - Benjamín Sánchez. Last edited: 2015-04-13
    -%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
    - - -

    CROSS-REFERENCE INFORMATION ^

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

    SOURCE CODE ^

    -
    0001 
    -0002 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
    -0003 % MW = calculateMW(sequence)
    -0004 % Calculates de molecular weight of a protein.
    -0005 %
    -0006 % INPUT: Sequence (can include extra things such as spaces or numbers).
    -0007 % OUTPUT: Molecular weight number
    -0008 %
    -0009 % Benjamín Sánchez. Last edited: 2015-04-13
    -0010 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
    -0011 
    -0012 function MW = calculateMW(sequence)
    -0013 
    -0014 % A    Alanine
    -0015 % B    Aspartic acid or Asparagine
    -0016 % C    Cysteine
    -0017 % D    Aspartic acid
    -0018 % E    Glutamic acid
    -0019 % F    Phenylalanine
    -0020 % G    Glycine
    -0021 % H    Histidine
    -0022 % I    Isoleucine
    -0023 % J    Leucine or Isoleucine
    -0024 % K    Lysine
    -0025 % L    Leucine
    -0026 % M    Methionine
    -0027 % N    Asparagine
    -0028 % O    Pyrrolysine
    -0029 % P    Proline
    -0030 % Q    Glutamine
    -0031 % R    Arginine
    -0032 % S    Serine
    -0033 % T    Threonine
    -0034 % U    Selenocysteine
    -0035 % V    Valine
    -0036 % W    Tryptophan
    -0037 % X    any
    -0038 % Y    Tyrosine
    -0039 % Z    Glutamic acid or Glutamine
    -0040 
    -0041 aa_codes = {'A','B','C','D','E','F','G','H','I','J','K','L','M','N', ...
    -0042             'O','P','Q','R','S','T','U','V','W','X','Y','Z'};
    -0043 aa_MWs   = [71.08 114.60 103.14 115.09 129.11 147.17 57.05 137.14 ...
    -0044             113.16 113.16 128.17 113.16 131.20 114.10 255.31 97.12 ...
    -0045             128.13 156.19 87.08 101.10 150.04 99.13 186.21 126.50 ...
    -0046             163.17 128.62];
    -0047 
    -0048 MW = 18;
    -0049 for i = 1:length(aa_codes)
    -0050     count = length(strfind(sequence,aa_codes{i}));
    -0051     MW = MW + count*aa_MWs(i);
    -0052 end
    -0053 
    -0054 end
    -0055 
    -0056 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
    -
    Generated by m2html © 2005
    - - \ No newline at end of file diff --git a/doc/src/geckomat/get_enzyme_data/copyECtoGEM.html b/doc/src/geckomat/get_enzyme_data/copyECtoGEM.html deleted file mode 100644 index fdaae97f..00000000 --- a/doc/src/geckomat/get_enzyme_data/copyECtoGEM.html +++ /dev/null @@ -1,98 +0,0 @@ - - - - Description of copyECtoGEM - - - - - - - - - -
    Home > src > geckomat > get_enzyme_data > copyECtoGEM.m
    - - - -

    copyECtoGEM -

    - -

    PURPOSE ^

    -
    copyECtoGEM
    - -

    SYNOPSIS ^

    -
    function ecModel = copyECtoGEM(ecModel, overwrite)
    - -

    DESCRIPTION ^

    -
     copyECtoGEM
    -   Copies EC numbers from ecModel.ec.eccodes to ecModel.eccodes.
    -
    - Input:
    -   ecModel     an ecModel in GECKO 3 format (with ecModel.ec structure)
    -   overwrite   logical that specifies if existing (non-empty) 
    -               ecModel.eccodes entries should be overwritten. Empty
    -               ecModel.eccodes entries are always overwritten if possible.
    -               default false.
    -
    - Output:
    -   ecModel     ecModel with populated model.eccodes
    -
    - Usage:
    -   ecModel = getECfromGEM(ecModel, overwrite)
    - - -

    CROSS-REFERENCE INFORMATION ^

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

    SOURCE CODE ^

    -
    0001 function ecModel = copyECtoGEM(ecModel, overwrite)
    -0002 % copyECtoGEM
    -0003 %   Copies EC numbers from ecModel.ec.eccodes to ecModel.eccodes.
    -0004 %
    -0005 % Input:
    -0006 %   ecModel     an ecModel in GECKO 3 format (with ecModel.ec structure)
    -0007 %   overwrite   logical that specifies if existing (non-empty)
    -0008 %               ecModel.eccodes entries should be overwritten. Empty
    -0009 %               ecModel.eccodes entries are always overwritten if possible.
    -0010 %               default false.
    -0011 %
    -0012 % Output:
    -0013 %   ecModel     ecModel with populated model.eccodes
    -0014 %
    -0015 % Usage:
    -0016 %   ecModel = getECfromGEM(ecModel, overwrite)
    -0017 
    -0018 if nargin < 2 || isempty(overwrite)
    -0019     overwrite = false;
    -0020 end
    -0021 if ~isfield(ecModel.ec,'eccodes')
    -0022     error('ecModel.ec.eccodes does not exist')
    -0023 end
    -0024 
    -0025 [a,b] = ismember(ecModel.rxns,ecModel.ec.rxns);
    -0026 if ~isfield(ecModel,'eccodes')
    -0027     ecModel.eccodes = cell(numel(ecModel.rxns),1);
    -0028 end
    -0029 
    -0030 if overwrite
    -0031     ecModel.eccodes(a) = ecModel.ec.eccodes(b(a));
    -0032 else % Only replace emptyEcCodes
    -0033     emptyEcCodes = cellfun(@isempty, ecModel.eccodes);
    -0034     a = a & emptyEcCodes;
    -0035     ecModel.eccodes(a) = ecModel.ec.eccodes(b(a));
    -0036 end
    -0037 end
    -
    Generated by m2html © 2005
    - - \ No newline at end of file diff --git a/doc/src/geckomat/get_enzyme_data/findECInDB.html b/doc/src/geckomat/get_enzyme_data/findECInDB.html deleted file mode 100644 index a90c456f..00000000 --- a/doc/src/geckomat/get_enzyme_data/findECInDB.html +++ /dev/null @@ -1,222 +0,0 @@ - - - - Description of findECInDB - - - - - - - - - -
    Home > src > geckomat > get_enzyme_data > findECInDB.m
    - - - -

    findECInDB -

    - -

    PURPOSE ^

    -
    findECInDB
    - -

    SYNOPSIS ^

    -
    function [EC,conflicts] = findECInDB(gene_set, DBecNum, DBMW, geneIndex, geneHashMap)
    - -

    DESCRIPTION ^

    -
     findECInDB
    -   Collects enzyme codes for genes from the UniProt or KEGGdatabase.
    -
    - Input:
    -   gene_set    genes from a given metabolic reaction
    -   DBecNum     array of EC numbers
    -   DBMW        array of molecular weights in Da
    -   geneIndex   as generated by getECfromDatabase
    -   geneHashMap as generated by getECfromDatabase
    -
    - Output:
    -   EC          all EC numbers found for the genes in gene_set
    -   conflicts   genes with multiple protein matches
    -
    - Usage:
    -   [EC,conflicts] = findECInDB(gene_set, DBecNum, DBMW, geneIndex, geneHashMap)
    - - -

    CROSS-REFERENCE INFORMATION ^

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

    SUBFUNCTIONS ^

    - - -

    SOURCE CODE ^

    -
    0001 function [EC,conflicts] = findECInDB(gene_set, DBecNum, DBMW, geneIndex, geneHashMap)
    -0002 % findECInDB
    -0003 %   Collects enzyme codes for genes from the UniProt or KEGGdatabase.
    -0004 %
    -0005 % Input:
    -0006 %   gene_set    genes from a given metabolic reaction
    -0007 %   DBecNum     array of EC numbers
    -0008 %   DBMW        array of molecular weights in Da
    -0009 %   geneIndex   as generated by getECfromDatabase
    -0010 %   geneHashMap as generated by getECfromDatabase
    -0011 %
    -0012 % Output:
    -0013 %   EC          all EC numbers found for the genes in gene_set
    -0014 %   conflicts   genes with multiple protein matches
    -0015 %
    -0016 % Usage:
    -0017 %   [EC,conflicts] = findECInDB(gene_set, DBecNum, DBMW, geneIndex, geneHashMap)
    -0018 
    -0019 %Preallocate function variables
    -0020 conflicts = cell(1,2);
    -0021 
    -0022 %Split the gene set and match each gene:
    -0023 %gene_set  = strsplit(grRule,' and '); %this string splitting together with getSimpleGeneSets takes 2.6 s, that is ok.
    -0024 EC_set    = cell(size(gene_set));
    -0025 
    -0026 %find index indices of all genes in one call
    -0027 
    -0028 %this loop is slow
    -0029 for j = 1:length(gene_set)
    -0030      gene = gene_set{j};
    -0031      matches = [];
    -0032      %Get the indexes for all of the proteins related to gene
    -0033      if isKey(geneHashMap,gene) %annoyingly, this seems to be needed
    -0034          matchInd = cell2mat(values(geneHashMap,gene_set(j)));
    -0035          matches = geneIndex{matchInd};
    -0036      end
    -0037      if ~isempty(matches)
    -0038         %Get the indexes of the matched protein(s) with non-empty EC#s
    -0039         nonEmpty = matches(~cellfun(@isempty,DBecNum(matches)));
    -0040         if ~isempty(nonEmpty)
    -0041             [geneECs,ia] = unique(DBecNum(nonEmpty),'stable');
    -0042             %For genes with multiple proteins associated to several
    -0043             %non-empty ecNumbers
    -0044             if length(geneECs)>1
    -0045                 indexes = nonEmpty(ia);
    -0046                 ecNum = DBecNum(indexes);
    -0047                 %Save first match
    -0048                 EC_set{j}  = getECstring(EC_set{j},ecNum{1});
    -0049                 %Save additional matches as potential conflicts
    -0050                 if ~ismember(gene,conflicts{1})
    -0051                     conflicts{1} = [conflicts{1}; {gene}];
    -0052                     conflicts{2} = [conflicts{2}; {indexes}]; 
    -0053                 end
    -0054             else
    -0055                 %If there is a single unique ec number for the matched
    -0056                 %protein(s), then choose the lightest protein
    -0057                 [~,minW]   = min(DBMW(nonEmpty));
    -0058                 matches    = nonEmpty(minW);
    -0059                 EC_set{j}  = getECstring(EC_set{j},DBecNum{matches});
    -0060             end
    -0061         end
    -0062     end
    -0063 
    -0064     if isempty(EC_set{j})
    -0065         EC_set{j} = '';
    -0066     end
    -0067 end
    -0068 
    -0069 %EC: Find union and intersection between all units (only applies for
    -0070 %complexes, i.e. length(EC_set) > 1):
    -0071 uni_EC = strsplit(EC_set{1},' ');
    -0072 int_EC = uni_EC;
    -0073 for j = 2:length(EC_set)
    -0074     other_EC = strsplit(EC_set{j},' ');
    -0075     if isempty(uni_EC)
    -0076         uni_EC = other_EC;
    -0077         int_EC = other_EC;
    -0078     elseif ~isempty(other_EC)
    -0079         uni_EC = compare_wild([uni_EC other_EC]);
    -0080         int_EC = intersection(int_EC,other_EC);
    -0081     end
    -0082 end
    -0083 %Use the intersection found, if any. If not, use the union:
    -0084 if isempty(int_EC)
    -0085     EC_set = uni_EC;
    -0086 else
    -0087     EC_set = int_EC;
    -0088 end
    -0089 
    -0090 %Add new codes as new possible isozymes and remove the initial "EC" text:
    -0091 
    -0092 for i = 1:length(EC_set)
    -0093    if ~isempty(EC_set{i}) 
    -0094        EC_set{i} = extractAfter(EC_set{i},2);%remove 2 first chars
    -0095    end
    -0096 end
    -0097 
    -0098 %EC_set = cellfun(@(x) extractAfter(x,2),EC_set,'UniformOutput',false);%remove 2 first chars
    -0099 EC    = strjoin(EC_set,';');
    -0100 
    -0101 
    -0102 %Delete repeated Uniprots (and the corresponding ECs):
    -0103 %EC(deleted)   = []; %Not sure if this needs to be done somehow, don't think so
    -0104 
    -0105 end
    -0106 
    -0107 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
    -0108 function int_EC = intersection(prev_EC,new_EC)
    -0109 %Finds the common elements between two cell arrays, if any. Also considers
    -0110 %wildcards (e.g. if 'EC1.1.1.1' is in one array and 'EC1.1.1.-' is in the
    -0111 %other one, then 'EC1.1.1.1' is added to the intersection).
    -0112 int_EC = {};
    -0113 for i = 1:length(prev_EC)
    -0114     for j = 1:length(new_EC)
    -0115         new_int = compare_wild({prev_EC{i} new_EC{j}});
    -0116         if length(new_int) == 1
    -0117             int_EC = [int_EC new_int];
    -0118         end
    -0119     end
    -0120 end
    -0121 end
    -0122 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
    -0123 function int_EC = compare_wild(EC)
    -0124 %Goes through a cell array of EC numbers, and erases any repetitions,
    -0125 %considering also wildcards (e.g. will erase 'EC1.2.3.-' if 'EC1.2.3.4' is
    -0126 %already present).
    -0127 
    -0128 %Trim all EC numbers of wild cards (e.g. 'EC1.2.-.-' -> 'EC1.2.'):
    -0129 EC_trimmed = EC;
    -0130 for i = 1:length(EC)
    -0131     %Add a final dot for avoiding issues (e.g. 'EC1.1.1.1' & 'EC1.1.1.12'):
    -0132     ECi = [EC{i} '.'];
    -0133     pos = strfind(ECi,'-');
    -0134     if ~isempty(pos)
    -0135         ECi = ECi(1:pos(1)-1);
    -0136     end
    -0137     EC_trimmed{i} = ECi;
    -0138 end
    -0139 
    -0140 %Compare all EC numbers between them to find if 1 fits in the other:
    -0141 non_repeated = true(1,length(EC));
    -0142 for i = 1:length(EC)-1
    -0143     for j = i+1:length(EC)
    -0144         ECi = EC_trimmed{i};
    -0145         ECj = EC_trimmed{j};
    -0146         %If ECj fits in ECi then ECj can be disregarded:
    -0147         if strfind(ECi,ECj)
    -0148             non_repeated(j) = false;
    -0149         %Else, if ECi fits in ECj then ECi can be disregarded:
    -0150         elseif strfind(ECj,ECi)
    -0151             non_repeated(i) = false;
    -0152         end
    -0153     end
    -0154 end
    -0155 
    -0156 int_EC = EC(non_repeated);
    -0157 
    -0158 end
    -
    Generated by m2html © 2005
    - - \ No newline at end of file diff --git a/doc/src/geckomat/get_enzyme_data/getECfromDatabase.html b/doc/src/geckomat/get_enzyme_data/getECfromDatabase.html deleted file mode 100644 index 1dec3ed3..00000000 --- a/doc/src/geckomat/get_enzyme_data/getECfromDatabase.html +++ /dev/null @@ -1,265 +0,0 @@ - - - - Description of getECfromDatabase - - - - - - - - - -
    Home > src > geckomat > get_enzyme_data > getECfromDatabase.m
    - - - -

    getECfromDatabase -

    - -

    PURPOSE ^

    -
    getECfromDatabase
    - -

    SYNOPSIS ^

    -
    function model = getECfromDatabase(model, ecRxns, action, modelAdapter)
    - -

    DESCRIPTION ^

    -
     getECfromDatabase
    -   Populates the model.ec.eccodes field with enzyme codes that are
    -   extracted from UniProt and KEGG databases, as assigned to the proteins
    -   that catalyze the specific reactions.
    -
    - Input:
    -   model           an ecModel in GECKO 3 format (with ecModel.ec structure)
    -   ecRxns          logical of length model.ec.rxns that specifies which
    -                   model.ec.eccodes entries should be queried. Exiting
    -                   values in model.ec.eccodes will be wiped. Entries that
    -                   are indicated by false will be kept and not modified by
    -                   this function (optional, by default all model.ec.eccodes
    -                   entries are populated by this function)
    -   action          response action if multiple proteins with different EC
    -                   numbers are found for a given gene in a metabolic
    -                   reaction (optional, default 'display')
    -                   - 'display' displays all found multiplicities
    -                   - 'ignore'  ignore multiplicities and use the protein
    -                               with the lowest index in the database.
    -                   - 'add'     adds all the multiple proteins as
    -                               isozymes for the given reaction
    -   modelAdapter    a loaded model adapter (Optional, will otherwise use the
    -                   default model adapter).
    -
    - Output:
    -   model           ecModel with populated model.ec.eccodes
    -
    - Usage:
    -   model = getECfromDatabase(model, ecRxns, action, modelAdapter)
    - - -

    CROSS-REFERENCE INFORMATION ^

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

    SUBFUNCTIONS ^

    - - -

    SOURCE CODE ^

    -
    0001 function model = getECfromDatabase(model, ecRxns, action, modelAdapter)
    -0002 % getECfromDatabase
    -0003 %   Populates the model.ec.eccodes field with enzyme codes that are
    -0004 %   extracted from UniProt and KEGG databases, as assigned to the proteins
    -0005 %   that catalyze the specific reactions.
    -0006 %
    -0007 % Input:
    -0008 %   model           an ecModel in GECKO 3 format (with ecModel.ec structure)
    -0009 %   ecRxns          logical of length model.ec.rxns that specifies which
    -0010 %                   model.ec.eccodes entries should be queried. Exiting
    -0011 %                   values in model.ec.eccodes will be wiped. Entries that
    -0012 %                   are indicated by false will be kept and not modified by
    -0013 %                   this function (optional, by default all model.ec.eccodes
    -0014 %                   entries are populated by this function)
    -0015 %   action          response action if multiple proteins with different EC
    -0016 %                   numbers are found for a given gene in a metabolic
    -0017 %                   reaction (optional, default 'display')
    -0018 %                   - 'display' displays all found multiplicities
    -0019 %                   - 'ignore'  ignore multiplicities and use the protein
    -0020 %                               with the lowest index in the database.
    -0021 %                   - 'add'     adds all the multiple proteins as
    -0022 %                               isozymes for the given reaction
    -0023 %   modelAdapter    a loaded model adapter (Optional, will otherwise use the
    -0024 %                   default model adapter).
    -0025 %
    -0026 % Output:
    -0027 %   model           ecModel with populated model.ec.eccodes
    -0028 %
    -0029 % Usage:
    -0030 %   model = getECfromDatabase(model, ecRxns, action, modelAdapter)
    -0031 
    -0032 if nargin < 2 || isempty(ecRxns)
    -0033     ecRnxs = true(numel(model.ec.rxns),1);
    -0034 end
    -0035 
    -0036 if nargin < 3 || isempty(action)
    -0037     action = 'display';
    -0038 end
    -0039 
    -0040 if nargin < 4 || 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.getParameters();
    -0047 
    -0048 rxnEnzMat = model.ec.rxnEnzMat;
    -0049 genes = modelAdapter.getUniprotCompatibleGenes(model.ec.genes);
    -0050 
    -0051 data    = loadDatabases('both', modelAdapter);
    -0052 uniprot = data.uniprot;
    -0053 kegg    = data.kegg;
    -0054 
    -0055 modelGenes = modelAdapter.getUniprotIDsFromTable(model.genes);
    -0056 DBgenesUniprot  = data.uniprot.genes;
    -0057 if ~isequal(modelGenes,model.genes)
    -0058     [Lia,Locb] = ismember(modelGenes,uniprot.ID);
    -0059     DBgenesUniprot(Locb(Lia)) = model.genes(Lia);
    -0060     keepEntry = unique(Locb(Lia));
    -0061     DBgenesUniprot = DBgenesUniprot(keepEntry);
    -0062 else
    -0063     keepEntry = true(numel(DBgenesUniprot),1);
    -0064 end
    -0065 DBecNumUniprot  = data.uniprot.eccodes(keepEntry);
    -0066 DBMWUniprot     = data.uniprot.MW(keepEntry);
    -0067 %Build an index from gene to prot for faster processing later
    -0068 [geneIndexUniprot,geneHashMapUniprot] = hashGeneToProt(DBgenesUniprot);
    -0069 
    -0070 if ~isempty(kegg)
    -0071     DBgenesKEGG     = data.kegg.genes;
    -0072     DBecNumKEGG     = data.kegg.eccodes;
    -0073     DBMWKEGG        = data.kegg.MW;
    -0074     [geneIndexKEGG,geneHashMapKEGG]       = hashGeneToProt(DBgenesKEGG);
    -0075 end
    -0076 n = size(rxnEnzMat,1);
    -0077 
    -0078 eccodes   = cell(n,1);
    -0079 eccodes(:)= {''};
    -0080 conflicts = cell(1,4);
    -0081 
    -0082 rxnEnzMat = logical(rxnEnzMat);
    -0083 progressbar('Assigning EC numbers from database')
    -0084 for i = 1:n
    -0085     gns = genes(rxnEnzMat(i,:).');
    -0086     if ~isempty(gns)
    -0087         %Find match in Uniprot:
    -0088         [new_EC,multGenes] = findECInDB(gns,DBecNumUniprot,DBMWUniprot,geneIndexUniprot,geneHashMapUniprot);
    -0089         if ~isempty(new_EC)
    -0090             DBase    = 'uniprot';
    -0091             if ~isempty(multGenes{1})
    -0092                 multGenes{3} = DBase;
    -0093             end
    -0094         end
    -0095         if ~isempty(kegg) && (isempty(new_EC) || endsWith(new_EC,'-'))
    -0096             %Find match in KEGG
    -0097             [new_EC_kegg,multGenes] = findECInDB(gns,DBecNumKEGG,DBMWKEGG,geneIndexKEGG,geneHashMapKEGG);
    -0098             if ~isempty(new_EC_kegg)
    -0099                 DBase    = 'kegg';
    -0100                 if ~isempty(multGenes{1})
    -0101                     multGenes{3} = DBase;
    -0102                 end
    -0103                 new_EC=new_EC_kegg;
    -0104             end
    -0105         end
    -0106         eccodes{i} = new_EC;
    -0107 
    -0108         if ~isempty(multGenes{1})
    -0109             %Rxn index
    -0110             conflicts{1} = [conflicts{1};i];
    -0111             %Gene IDs
    -0112             conflicts{2} = [conflicts{2};multGenes{1}];
    -0113             %Indexes in DB
    -0114             conflicts{3} = [conflicts{3};multGenes{2}];
    -0115             %DB name
    -0116             conflicts{4} = [conflicts{4};{multGenes{3}}];
    -0117 
    -0118             %{ I don't understand the purpose of this, let's skip it for now
    -0119             %if strcmpi(action,'add')
    -0120             %    if strcmpi(DBase,'swissprot')
    -0121             %        [uni,EC,MW,Genes] = addMultipleMatches(uni,EC,MW,Genes,multGenes,swissprot);
    -0122             %    elseif strcmpi(DBase,'KEGG')
    -0123             %        [uni,EC,MW,Genes] = addMultipleMatches(uni,EC,MW,Genes,multGenes,kegg);
    -0124             %    end
    -0125             %end
    -0126             %}
    -0127         end
    -0128     end
    -0129     progressbar(i/n)
    -0130 end
    -0131 
    -0132 %Display error message with the multiple gene-protein matches found
    -0133 if strcmpi(action,'display') && ~isempty(conflicts{1})
    -0134     displayErrorMessage(conflicts,uniprot,kegg)
    -0135 end
    -0136 
    -0137 if nargin < 2 || isempty(ecRxns) || all(ecRxns)
    -0138     model.ec.eccodes = eccodes;
    -0139 else
    -0140     if ~isfield(model.ec,'eccodes')
    -0141         model.ec.eccodes(1:numel(model.ec.rxns),1) = {''};
    -0142     end
    -0143     %Probably faster to subset with ecRxns in the beginning of the script,
    -0144     %but this was at the moment simpler to implement.
    -0145     model.ec.eccodes(ecRxns) = eccodes(ecRxns);
    -0146 end
    -0147 
    -0148 function displayErrorMessage(conflicts,uniprot,kegg)
    -0149 STR = ['\n ' num2str(length(conflicts{1})) ' genes with multiple associated proteins were found, please'];
    -0150 STR = [STR, ' revise case by case in the uniprot and kegg files:\n\n'];
    -0151 for i=1:length(conflicts{1})
    -0152     if strcmpi(conflicts{4}{i},'uniprot')
    -0153         DB = uniprot.ID;
    -0154     else
    -0155         DB = kegg.uniprot;
    -0156     end
    -0157     proteins = DB(conflicts{3}{i});
    -0158     STR = [STR, '- gene: ' conflicts{2}{i} '  Proteins: ' strjoin(proteins) '\n'];
    -0159 end
    -0160 STR = [STR, '\nIf a wrongly annotated case was found then call the '];
    -0161 STR = [STR, 'getECfromDatabase.m function again with the option action'];
    -0162 STR = [STR, '= ignore\n\n'];
    -0163 STR = [STR, 'If the conflicting proteins are desired to be kept as isozymes'];
    -0164 STR = [STR, ' then call the getECfromDatabase.m function'];
    -0165 STR = [STR, ' again with the option action = add\n'];
    -0166 error(sprintf(STR))
    -0167 end
    -0168 
    -0169 function [geneIndex,geneHashMap]=hashGeneToProt(proteinDB)
    -0170 
    -0171 [x,y] = size(proteinDB);
    -0172 genesForIndex = reshape(proteinDB, x*y, 1);
    -0173 genesForIndex = genesForIndex(~cellfun(@isempty, genesForIndex));
    -0174 genesForIndex = unique(genesForIndex);
    -0175 geneIndex = cell(length(genesForIndex),1);
    -0176 geneHashMap = containers.Map(genesForIndex,1:length(genesForIndex));
    -0177 protIndices = 1:length(proteinDB(:,1));
    -0178 for i = 1:y
    -0179     tmp1 = proteinDB(:,i);
    -0180     sel = ~cellfun(@isempty, tmp1);
    -0181     indices = cell2mat(values(geneHashMap,tmp1(sel)));
    -0182     protIndicesSel = protIndices(sel);
    -0183     for j = 1:length(indices)
    -0184         geneIndex{indices(j)} = [geneIndex{indices(j)};protIndicesSel(j)];
    -0185     end
    -0186 end
    -0187 end
    -0188 end
    -
    Generated by m2html © 2005
    - - \ No newline at end of file diff --git a/doc/src/geckomat/get_enzyme_data/getECfromGEM.html b/doc/src/geckomat/get_enzyme_data/getECfromGEM.html deleted file mode 100644 index a56cb9d2..00000000 --- a/doc/src/geckomat/get_enzyme_data/getECfromGEM.html +++ /dev/null @@ -1,130 +0,0 @@ - - - - Description of getECfromGEM - - - - - - - - - -
    Home > src > geckomat > get_enzyme_data > getECfromGEM.m
    - - - -

    getECfromGEM -

    - -

    PURPOSE ^

    -
    getECfromGEM
    - -

    SYNOPSIS ^

    -
    function [model, invalidEC, invalidECpos] = getECfromGEM(model, ecRxns)
    - -

    DESCRIPTION ^

    -
     getECfromGEM
    -   Use the model.eccodes to populates the model.ec.eccodes field. EC
    -   numbers that are not formatted as four numbers separated by periods,
    -   possibly with trailing wildcards. Examples: 1.2.3.4 or 1.2.3.- while
    -   invalid EC numbers are 1.2.3 or 1_2_3_4. Multiple EC numbers are
    -   separated by ; for instance 1.2.3.4;1.2.3.5 not 1.2.3.4|1.2.3.5.
    -
    - Input:
    -   model           an ecModel in GECKO 3 format (with ecModel.ec structure)
    -   ecRxns          logical of length model.ec.rxns that specifies for
    -                   which reactions the existing model.ec.eccodes entry
    -                   should be kept and not modified by this function
    -                   (optional, by default all model.ec.eccodes entries
    -                   are populated by this function)
    -
    - Output:
    -   model           ecModel with populated model.ec.eccodes
    -   invalidEC       incorrectly formatted EC numbers
    -   invalidECpos    position of invalidEC in model.eccodes
    -
    - Usage:
    -   [model, invalidEC, invalidECpos] = getECfromGEM(model, ecRxns)
    - - -

    CROSS-REFERENCE INFORMATION ^

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

    SOURCE CODE ^

    -
    0001 function [model, invalidEC, invalidECpos] = getECfromGEM(model, ecRxns)
    -0002 % getECfromGEM
    -0003 %   Use the model.eccodes to populates the model.ec.eccodes field. EC
    -0004 %   numbers that are not formatted as four numbers separated by periods,
    -0005 %   possibly with trailing wildcards. Examples: 1.2.3.4 or 1.2.3.- while
    -0006 %   invalid EC numbers are 1.2.3 or 1_2_3_4. Multiple EC numbers are
    -0007 %   separated by ; for instance 1.2.3.4;1.2.3.5 not 1.2.3.4|1.2.3.5.
    -0008 %
    -0009 % Input:
    -0010 %   model           an ecModel in GECKO 3 format (with ecModel.ec structure)
    -0011 %   ecRxns          logical of length model.ec.rxns that specifies for
    -0012 %                   which reactions the existing model.ec.eccodes entry
    -0013 %                   should be kept and not modified by this function
    -0014 %                   (optional, by default all model.ec.eccodes entries
    -0015 %                   are populated by this function)
    -0016 %
    -0017 % Output:
    -0018 %   model           ecModel with populated model.ec.eccodes
    -0019 %   invalidEC       incorrectly formatted EC numbers
    -0020 %   invalidECpos    position of invalidEC in model.eccodes
    -0021 %
    -0022 % Usage:
    -0023 %   [model, invalidEC, invalidECpos] = getECfromGEM(model, ecRxns)
    -0024 
    -0025 if ~isfield(model,'eccodes')
    -0026     error('The model has no model.eccodes field.')
    -0027 end
    -0028 
    -0029 %Need to remove the prefix of GECKO light rxn names in the ec structure
    -0030 if ~model.ec.geckoLight
    -0031     rxnNames = model.ec.rxns;
    -0032 else
    -0033     rxnNames = extractAfter(model.ec.rxns, 4);
    -0034 end
    -0035 
    -0036 [~,rxnIdxs] = ismember(rxnNames,model.rxns);
    -0037 
    -0038 % Check if eccodes are valid
    -0039 eccodes = model.eccodes;
    -0040 invalidEC = regexprep(eccodes,'(\d\.(\w|-)+\.(\w|-)+\.(\w|-)+)(;\w+\.(\w|-)+\.(\w|-)+\.(\w|-)+)*(.*)','$3');
    -0041 invalidEC = ~cellfun(@isempty,invalidEC);
    -0042 invalidECpos = find(invalidEC);
    -0043 if any(invalidECpos)
    -0044     invalidEC = model.eccodes(invalidEC);
    -0045     if nargout<2
    -0046         fprintf('Skipped incorrectly formatted EC numbers, rerun getECfromGEM with all outputs to get a list.\n')
    -0047     else
    -0048         fprintf('Skipped incorrectly formatted EC numbers.\n')
    -0049     end
    -0050     eccodes(invalidECpos)={''};
    -0051 else
    -0052     invalidEC = [];
    -0053 end
    -0054 if nargin<2 || all(ecRxns)
    -0055     model.ec.eccodes = eccodes(rxnIdxs);
    -0056 else
    -0057     if ~isfield(model.ec,'eccodes')
    -0058         model.ec.eccodes(1:numel(model.ec.rxns),1) = {''};
    -0059     end
    -0060     model.ec.eccodes(ecRxns) = eccodes(rxnIdxs(ecRxns));
    -0061 end
    -0062 end
    -
    Generated by m2html © 2005
    - - \ No newline at end of file diff --git a/doc/src/geckomat/get_enzyme_data/getECstring.html b/doc/src/geckomat/get_enzyme_data/getECstring.html deleted file mode 100644 index e9e930a8..00000000 --- a/doc/src/geckomat/get_enzyme_data/getECstring.html +++ /dev/null @@ -1,73 +0,0 @@ - - - - Description of getECstring - - - - - - - - - -
    Home > src > geckomat > get_enzyme_data > getECstring.m
    - - - -

    getECstring -

    - -

    PURPOSE ^

    -
    %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
    - -

    SYNOPSIS ^

    -
    function EC_set = getECstring(EC_set,ecNumbers)
    - -

    DESCRIPTION ^

    -
    %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
    - EC_set = getECstring(EC_set,ecNumbers)
    - 
    - Provides a single string with all the EC numbers associated to a given
    - protein with according to the next format: "ECX.X.X.X ECX.X.X.X ECX.X.X.X"
    -
    - Ivan Domenzain.      Last edited: 2018-09-06
    -%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
    -In case of several ec numbers for the same protein
    - - -

    CROSS-REFERENCE INFORMATION ^

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

    SOURCE CODE ^

    -
    0001 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
    -0002 % EC_set = getECstring(EC_set,ecNumbers)
    -0003 %
    -0004 % Provides a single string with all the EC numbers associated to a given
    -0005 % protein with according to the next format: "ECX.X.X.X ECX.X.X.X ECX.X.X.X"
    -0006 %
    -0007 % Ivan Domenzain.      Last edited: 2018-09-06
    -0008 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
    -0009 function EC_set = getECstring(EC_set,ecNumbers)
    -0010 %In case of several ec numbers for the same protein
    -0011 new_EC_set = replace(strsplit(ecNumbers,' '),';','');
    -0012 for l = 1:length(new_EC_set)
    -0013     EC_set = [EC_set 'EC' new_EC_set{l}];
    -0014     if l<length(new_EC_set)
    -0015         EC_set = [EC_set ' '];
    -0016     end
    -0017 end
    -0018 end
    -
    Generated by m2html © 2005
    - - \ No newline at end of file diff --git a/doc/src/geckomat/get_enzyme_data/index.html b/doc/src/geckomat/get_enzyme_data/index.html deleted file mode 100644 index 83fceec5..00000000 --- a/doc/src/geckomat/get_enzyme_data/index.html +++ /dev/null @@ -1,29 +0,0 @@ - - - - Index for Directory src\geckomat\get_enzyme_data - - - - - - - - - - -
    < Master indexIndex for src\geckomat\get_enzyme_data >
    - -

    Index for src\geckomat\get_enzyme_data

    - -

    Matlab files in this directory:

    - -
     calculateMW%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
     copyECtoGEMcopyECtoGEM
     findECInDBfindECInDB
     getECfromDatabasegetECfromDatabase
     getECfromGEMgetECfromGEM
     getECstring%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
     loadBRENDAdata%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
     loadDatabasesloadDatabases
    - - - - -
    Generated by m2html © 2005
    - - \ No newline at end of file diff --git a/doc/src/geckomat/get_enzyme_data/loadBRENDAdata.html b/doc/src/geckomat/get_enzyme_data/loadBRENDAdata.html deleted file mode 100644 index 69ad5586..00000000 --- a/doc/src/geckomat/get_enzyme_data/loadBRENDAdata.html +++ /dev/null @@ -1,130 +0,0 @@ - - - - Description of loadBRENDAdata - - - - - - - - - -
    Home > src > geckomat > get_enzyme_data > loadBRENDAdata.m
    - - - -

    loadBRENDAdata -

    - -

    PURPOSE ^

    -
    %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
    - -

    SYNOPSIS ^

    -
    function [KCATcell, SAcell] = loadBRENDAdata(modelAdapter)
    - -

    DESCRIPTION ^

    -
    %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
    - - -

    CROSS-REFERENCE INFORMATION ^

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

    SUBFUNCTIONS ^

    - - -

    SOURCE CODE ^

    -
    0001 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
    -0002 function [KCATcell, SAcell] = loadBRENDAdata(modelAdapter)
    -0003 
    -0004 if nargin < 1 || isempty(modelAdapter)
    -0005     modelAdapter = ModelAdapterManager.getDefault();
    -0006     if isempty(modelAdapter)
    -0007         error('Either send in a modelAdapter or set the default model adapter in the ModelAdapterManager.')
    -0008     end
    -0009 end
    -0010 
    -0011 basePath      = modelAdapter.getBrendaDBFolder();
    -0012 KCAT_file      = fullfile(basePath,'max_KCAT.txt');
    -0013 SA_file        = fullfile(basePath,'max_SA.txt');
    -0014 MW_file        = fullfile(basePath,'max_MW.txt');
    -0015 
    -0016 %Extract BRENDA DATA from files information
    -0017 KCATcell       = openDataFile(KCAT_file,1);
    -0018 scalingFactor = 1/60;    %[umol/min/mg] -> [mmol/s/g]    Old: 60 [umol/min/mg] -> [mmol/h/g]
    -0019 SA            = openDataFile(SA_file,scalingFactor);
    -0020 scalingFactor = 1/1000;  %[g/mol] -> [g/mmol]
    -0021 MW            = openDataFile(MW_file,scalingFactor);
    -0022 
    -0023 for i=1:4
    -0024     SAcell{i} = [];
    -0025 end
    -0026 previousEC = []; EC_indexes = [];
    -0027 
    -0028 %build an index on MW{1} to speed things up a bit
    -0029 %first just extract the genus (i.e. the first part of the name)
    -0030 MWECNum = upper(unique(MW{1}));
    -0031 MWECNumIndices = cell(length(MWECNum),1);
    -0032 MWECNumHashMap = containers.Map(MWECNum,1:length(MWECNum));
    -0033 for i = 1:length(MW{1})
    -0034     matchInd = cell2mat(values(MWECNumHashMap, MW{1}(i)));
    -0035     MWECNumIndices{matchInd} = [MWECNumIndices{matchInd};i];
    -0036 end
    -0037 
    -0038 
    -0039 for i=1:length(SA{1})
    -0040     %Gets the indexes of the EC repetitions in the MW cell for every
    -0041     %new (different) EC
    -0042     if ~strcmpi(SA{1}(i), previousEC)
    -0043         key = upper(SA{1}(i));
    -0044         if isKey(MWECNumHashMap,key) %annoyingly, this seems to be needed
    -0045             matchInd = cell2mat(values(MWECNumHashMap,key));
    -0046             EC_indexes = MWECNumIndices{matchInd};
    -0047         else
    -0048             EC_indexes = [];
    -0049         end
    -0050     end
    -0051     mwEC{1} = MW{3}(EC_indexes); mwEC{2} = MW{4}(EC_indexes);
    -0052     % just looks for the first match because just the maximal value for
    -0053     % each EC# / Orgaism is reported on the file
    -0054     org_index = find(strcmpi(SA{3}(i),mwEC{1}),1);
    -0055     if ~isempty(org_index)
    -0056         SAcell{1} = [SAcell{1};SA{1}(i)];
    -0057         SAcell{2} = [SAcell{2};SA{3}(i)];
    -0058         SAcell{3} = [SAcell{3}; SA{4}(i)*mwEC{2}(org_index)]; %[1/hr]
    -0059         SAcell{4} = [SAcell{4}; mwEC{2}(org_index)];
    -0060     end
    -0061     previousEC = SA{1}(i);
    -0062 end
    -0063 
    -0064 %remove EC in front of all the EC numbers
    -0065 if ~isempty(KCATcell{1})
    -0066     KCATcell{1} = extractAfter(KCATcell{1},2);
    -0067 end
    -0068 if ~isempty(SAcell{1})
    -0069     SAcell{1} = extractAfter(SAcell{1},2);
    -0070 end
    -0071 
    -0072 function data_cell = openDataFile(fileName,scalingFactor)
    -0073 fID          = fopen(fileName);
    -0074 data_cell    = textscan(fID,'%q %q %q %f %q','delimiter','\t');
    -0075 fclose(fID);
    -0076 data_cell{4} = data_cell{4}*scalingFactor;
    -0077 %Split string for each organism in the BRENDA data
    -0078 %{name, taxonomy, KEGG code}
    -0079 data_cell{3}  = regexprep(data_cell{3},'\/\/.*','');
    -0080 end
    -0081 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 deleted file mode 100644 index 8081de2b..00000000 --- a/doc/src/geckomat/get_enzyme_data/loadDatabases.html +++ /dev/null @@ -1,283 +0,0 @@ - - - - Description of loadDatabases - - - - - - - - - -
    Home > src > geckomat > get_enzyme_data > loadDatabases.m
    - - - -

    loadDatabases -

    - -

    PURPOSE ^

    -
    loadDatabases
    - -

    SYNOPSIS ^

    -
    function databases = loadDatabases(selectDatabase,modelAdapter)
    - -

    DESCRIPTION ^

    -
     loadDatabases
    -   Loads (and downloads if necessary) the organism-specific KEGG and
    -   UniProt databases that are required to extract protein information. The
    -   uniprot.ID and kegg.ID are taken from the ModelAdapter.
    -
    - Input:
    -   selectDatabase  which databases should be loaded, either 'uniprot',
    -                   'kegg' or 'both' (optional, default 'both')
    -   modelAdapter    Model adapter. Optional, default will use the default 
    -                   model adapter (send in [] for default).
    -
    - Output:
    -   databases       contains .uniprot and .kegg structures, dependent on
    -                   which databases were selected.
    -
    - Usage:
    -   databases = loadDatabases(selectDatabase,modelAdapter)
    - - -

    CROSS-REFERENCE INFORMATION ^

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

    SUBFUNCTIONS ^

    - - -

    SOURCE CODE ^

    -
    0001 function databases = loadDatabases(selectDatabase,modelAdapter)
    -0002 % loadDatabases
    -0003 %   Loads (and downloads if necessary) the organism-specific KEGG and
    -0004 %   UniProt databases that are required to extract protein information. The
    -0005 %   uniprot.ID and kegg.ID are taken from the ModelAdapter.
    -0006 %
    -0007 % Input:
    -0008 %   selectDatabase  which databases should be loaded, either 'uniprot',
    -0009 %                   'kegg' or 'both' (optional, default 'both')
    -0010 %   modelAdapter    Model adapter. Optional, default will use the default
    -0011 %                   model adapter (send in [] for default).
    -0012 %
    -0013 % Output:
    -0014 %   databases       contains .uniprot and .kegg structures, dependent on
    -0015 %                   which databases were selected.
    -0016 %
    -0017 % Usage:
    -0018 %   databases = loadDatabases(selectDatabase,modelAdapter)
    -0019 
    -0020 if nargin<1
    -0021     selectDatabase = 'both';
    -0022 end
    -0023 
    -0024 if nargin < 2 || isempty(modelAdapter)
    -0025     modelAdapter = ModelAdapterManager.getDefault();
    -0026     if isempty(modelAdapter)
    -0027         error('Either send in a modelAdapter or set the default model adapter in the ModelAdapterManager.')
    -0028     end
    -0029 end
    -0030 
    -0031 params      = modelAdapter.getParameters();
    -0032 kegg.ID      = params.kegg.ID;
    -0033 uniprot.ID   = params.uniprot.ID;
    -0034 filePath    = fullfile(params.path,'data');
    -0035 uniprot.geneIDfield = params.uniprot.geneIDfield;
    -0036 uniprot.type = params.uniprot.type;
    -0037 if strcmp(uniprot.type,'taxonomy')
    -0038     uniprot.type = 'taxonomy_id';
    -0039 end
    -0040 kegg.geneID = params.kegg.geneID;
    -0041 if params.uniprot.reviewed
    -0042     uniprotRev = 'reviewed:true+AND+';
    -0043 else
    -0044     uniprotRev = '';
    -0045 end
    -0046 
    -0047 warning('off', 'MATLAB:MKDIR:DirectoryExists');
    -0048 
    -0049 databases.uniprot = [];
    -0050 databases.kegg = [];
    -0051 
    -0052 %% Uniprot
    -0053 if any(strcmp(selectDatabase,{'uniprot','both'}))
    -0054     uniprotPath = fullfile(filePath,'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');
    -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 ...
    -0061                uniprot.type ':' num2str(uniprot.ID) '&fields=accession%2C' uniprot.geneIDfield ...
    -0062             '%2Cec%2Cmass%2Csequence&format=tsv&compressed=false&sort=protein_name%20asc'];
    -0063         try
    -0064             urlwrite(url,uniprotPath,'Timeout',30);
    -0065             fprintf('Model-specific UniProt database stored at %s\n',uniprotPath);
    -0066         catch
    -0067             error(['Download failed, check your internet connection and try again, or manually download: ' url ...
    -0068                 ' After downloading, store the file as ' uniprotPath])
    -0069         end
    -0070     end
    -0071     if exist(uniprotPath,'file')
    -0072         fid         = fopen(uniprotPath,'r');
    -0073         fileContent = textscan(fid,'%q %q %q %q %q','Delimiter','\t','HeaderLines',1);
    -0074         fclose(fid);
    -0075         databases.uniprot.ID      = fileContent{1};
    -0076         databases.uniprot.genes   = fileContent{2};
    -0077         databases.uniprot.eccodes = fileContent{3};
    -0078         databases.uniprot.MW      = str2double(fileContent{4});
    -0079         databases.uniprot.seq     = fileContent{5};
    -0080     else
    -0081         databases.uniprot = [];
    -0082     end
    -0083     if ~isempty(databases.uniprot)
    -0084         [uniqueIDs,uniqueIdx] = unique(databases.uniprot.ID,'stable');
    -0085         if numel(uniqueIDs) < numel(databases.uniprot.ID)
    -0086             duplID = setdiff(1:numel(databases.uniprot.ID),uniqueIdx);
    -0087             dispEM(['Duplicate entries are found for the following proteins. '...
    -0088                     'Manually curate the ''uniprot.tsv'' file, or adjust the uniprot parameters '...
    -0089                     'in the model adapter:'],true,databases.uniprot.ID(duplID));
    -0090         end
    -0091     end
    -0092 end
    -0093 
    -0094 %% KEGG
    -0095 if any(strcmp(selectDatabase,{'kegg','both'}))
    -0096     keggPath = fullfile(filePath,'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');
    -0100         else
    -0101             downloadKEGG(kegg.ID,keggPath,kegg.geneID);
    -0102         end
    -0103     end
    -0104     if exist(keggPath,'file')
    -0105         fid         = fopen(keggPath,'r');
    -0106         fileContent = textscan(fid,'%q %q %q %q %q %q %q','Delimiter',',','HeaderLines',0);
    -0107         fclose(fid);
    -0108         databases.kegg.uniprot    = fileContent{1};
    -0109         databases.kegg.genes      = fileContent{2};
    -0110         databases.kegg.keggGene   = fileContent{3};
    -0111         databases.kegg.eccodes    = fileContent{4};
    -0112         databases.kegg.MW         = str2double(fileContent{5});
    -0113         databases.kegg.pathway    = fileContent{6};
    -0114         databases.kegg.seq        = fileContent{7};
    -0115     else
    -0116         databases.kegg = [];
    -0117     end
    -0118 end
    -0119 end
    -0120 
    -0121 function downloadKEGG(keggID, filePath, keggGeneID)
    -0122 %% Download gene information
    -0123 progressbar(['Downloading KEGG data for organism code ' keggID])
    -0124 webOptions = weboptions('Timeout',30);
    -0125 try
    -0126     gene_list = webread(['http://rest.kegg.jp/list/' keggID],webOptions);
    -0127 catch ME
    -0128     switch ME.identifier
    -0129         case 'MATLAB:webservices:HTTP400StatusCodeError'
    -0130             error(['Unable to download data form KEGG with a potentially invalid ID: ' keggID ])
    -0131     end
    -0132 end
    -0133 gene_list = regexpi(gene_list, '[^\n]+','match')';
    -0134 gene_id   = regexpi(gene_list,['(?<=' keggID ':)\S+'],'match');
    -0135 
    -0136 % Retrieve information for every gene in the list, 10 genes per query
    -0137 genesPerQuery = 10;
    -0138 queries = ceil(numel(gene_id)/genesPerQuery);
    -0139 keggData  = cell(numel(gene_id),1);
    -0140 for i = 1:queries
    -0141     % Download batches of genes
    -0142     firstIdx = i*genesPerQuery-(genesPerQuery-1);
    -0143     lastIdx  = i*genesPerQuery;
    -0144     if lastIdx > numel(gene_id) % Last query has probably less genes
    -0145         lastIdx = numel(gene_id);
    -0146     end
    -0147     url      = ['http://rest.kegg.jp/get/' keggID ':' strjoin([gene_id{firstIdx:lastIdx}],['+' keggID ':'])];
    -0148 
    -0149     retry = true;
    -0150     while retry
    -0151         try
    -0152             retry = false;
    -0153             out   = webread(url,webOptions);
    -0154         catch
    -0155             retry = true;
    -0156         end
    -0157     end
    -0158     outSplit = strsplit(out,['///' 10]); %10 is new line character
    -0159     if numel(outSplit) < lastIdx-firstIdx+2
    -0160         error('KEGG returns less genes per query') %Reduce genesPerQuery
    -0161     end
    -0162     keggData(firstIdx:lastIdx) = outSplit(1:end-1);
    -0163     progressbar(i/queries)
    -0164 end
    -0165 
    -0166 %% Parsing of info to keggDB format
    -0167 sequence  = regexprep(keggData,'.*AASEQ\s+\d+\s+([A-Z\s])+?\s+NTSEQ.*','$1');
    -0168 %No AASEQ -> no protein -> not of interest
    -0169 noProt    = startsWith(sequence,'ENTRY ');
    -0170 uni       = regexprep(keggData,'.*UniProt: (\S+?)\s.*','$1');
    -0171 noUni     = startsWith(uni,'ENTRY ');
    -0172 uni(noProt | noUni)       = [];
    -0173 keggData(noProt | noUni) = [];
    -0174 sequence(noProt | noUni)  = [];
    -0175 sequence  = regexprep(sequence,'\s*','');
    -0176 keggGene  = regexprep(keggData,'ENTRY\s+(\S+?)\s.+','$1');
    -0177 
    -0178 switch keggGeneID
    -0179     case {'kegg',''}
    -0180         gene_name = keggGene;
    -0181     otherwise
    -0182         % In case there are special characters:
    -0183         keggGeneIDT = regexptranslate('escape',keggGeneID);
    -0184         gene_name = regexprep(keggData,['.+' keggGeneIDT ': (\S+?)\n.+'],'$1');
    -0185         noID = ~contains(keggData,keggGeneIDT);
    -0186         if all(noID)
    -0187             error(['None of the KEGG entries are annotated with the gene identifier ' keggGeneID])
    -0188         else
    -0189             gene_name(noID)= [];
    -0190             keggData(noID) = [];
    -0191             keggGene(noID) = [];
    -0192             sequence(noID) = [];
    -0193             uni(noID)      = [];
    -0194         end
    -0195 end
    -0196 
    -0197 EC_names  = regexprep(keggData,'.*ORTHOLOGY.*\[EC:(.*?)\].*','$1');
    -0198 EC_names(startsWith(EC_names,'ENTRY ')) = {''};
    -0199 
    -0200 MW = cell(numel(sequence),1);
    -0201 for i=1:numel(sequence)
    -0202     if ~isempty(sequence{i})
    -0203         MW{i} = num2str(round(calculateMW(sequence{i})));
    -0204     end
    -0205 end
    -0206 
    -0207 pathway   = regexprep(keggData,'.*PATHWAY\s+(.*?)(BRITE|MODULE).*','$1');
    -0208 pathway(startsWith(pathway,'ENTRY ')) = {''};
    -0209 pathway   = strrep(pathway,[keggID '01100  Metabolic pathways'],'');
    -0210 pathway   = regexprep(pathway,'\n','');
    -0211 pathway   = regexprep(pathway,'           ','');
    -0212 
    -0213 out = [uni, gene_name, keggGene, EC_names, MW, pathway, sequence];
    -0214 out = cell2table(out);
    -0215 
    -0216 writetable(out, filePath, 'FileType', 'text', 'WriteVariableNames',false);
    -0217 fprintf('Model-specific KEGG database stored at %s\n',filePath);
    -0218 end
    -
    Generated by m2html © 2005
    - - \ No newline at end of file diff --git a/doc/src/geckomat/kcat_sensitivity_analysis/Bayesian/abc_max.html b/doc/src/geckomat/kcat_sensitivity_analysis/Bayesian/abc_max.html deleted file mode 100644 index f85f1fa6..00000000 --- a/doc/src/geckomat/kcat_sensitivity_analysis/Bayesian/abc_max.html +++ /dev/null @@ -1,176 +0,0 @@ - - - - Description of abc_max - - - - - - - - - -
    Home > src > geckomat > kcat_sensitivity_analysis > Bayesian > abc_max.m
    - - - -

    abc_max -

    - -

    PURPOSE ^

    -
    abc_max
    - -

    SYNOPSIS ^

    -
    function [rmse,rmseList] = abc_max(ecModel,fluxData,maxGrowth,rxn2block,modelAdapter)
    - -

    DESCRIPTION ^

    -
     abc_max
    -   Internal function in BayesianSensitivityTuning. Gets the average RMSE for
    -   a certain set of growth data and kcats.
    -
    - Input:
    -   ecModel       ecModel that was generated by makeEcModel, or loaded from
    -                 an earlier run. Not compatible with ecModels generated by
    -                 earlier GECKO versions (pre 3.0).
    -   fluxData      Growth data loaded from file.
    -   maxGrowth     Max growth data loaded from file.
    -   rxn2block     List of reactions to block, could be read from file.
    -
    - Output:
    -   rmse          The average RMSE
    - - -

    CROSS-REFERENCE INFORMATION ^

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

    SUBFUNCTIONS ^

    - - -

    SOURCE CODE ^

    -
    0001 function [rmse,rmseList] = abc_max(ecModel,fluxData,maxGrowth,rxn2block,modelAdapter)
    -0002 % abc_max
    -0003 %   Internal function in BayesianSensitivityTuning. Gets the average RMSE for
    -0004 %   a certain set of growth data and kcats.
    -0005 %
    -0006 % Input:
    -0007 %   ecModel       ecModel that was generated by makeEcModel, or loaded from
    -0008 %                 an earlier run. Not compatible with ecModels generated by
    -0009 %                 earlier GECKO versions (pre 3.0).
    -0010 %   fluxData      Growth data loaded from file.
    -0011 %   maxGrowth     Max growth data loaded from file.
    -0012 %   rxn2block     List of reactions to block, could be read from file.
    -0013 %
    -0014 % Output:
    -0015 %   rmse          The average RMSE
    -0016 
    -0017 if nargin < 5 || isempty(modelAdapter)
    -0018     modelAdapter = ModelAdapterManager.getDefault();
    -0019     if isempty(modelAdapter)
    -0020         error('Either send in a modelAdapter or set the default ecModel adapter in the ModelAdapterManager.')
    -0021     end
    -0022 end
    -0023 rmse_1 = []; rmseList1 = []; rmse_2 = []; rmseList2 = [];
    -0024 
    -0025 if ~isfield(ecModel,'excarbon')
    -0026     ecModel = addCarbonNum(ecModel);
    -0027     ecModel.excarbon(ecModel.excarbon == 0) = 1;
    -0028 end
    -0029 
    -0030 %% First test with flux data
    -0031 if ~isempty(fluxData)
    -0032     [rmse_1, rmseList1] = rmsecal(ecModel,fluxData,true,rxn2block,modelAdapter);
    -0033     rmseList1 = [cellstr("fluxData_" + string(1:numel(rmseList1)))',num2cell(rmseList1)];
    -0034 end
    -0035 %% Second test with maximum growth on various carbon sources
    -0036 if ~isempty(maxGrowth)  % simulate the maximal growth rate
    -0037     [rmse_2, rmseList2] = rmsecal(ecModel,maxGrowth,false,rxn2block,modelAdapter);
    -0038     rmseList2 = [cellstr("maxGrowth_" + string(1:numel(rmseList2)))',num2cell(rmseList2)];
    -0039 end
    -0040     
    -0041 %% Combine results
    -0042 rmse        = mean([rmse_1,rmse_2],'omitnan');
    -0043 rmseList    = [rmseList1;rmseList2];
    -0044 end
    -0045 
    -0046 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
    -0047 function [rmse, rmseList] = rmsecal(ecModel,data,constrain,rxn2block,modelAdapter)
    -0048 
    -0049 rmseList = zeros(length(data.conds),1);
    -0050 
    -0051 for i = 1:length(data.conds)
    -0052 
    -0053     % Set carbon source
    -0054     [~,exchIdx] = ismember(data.conds,data.exchMets);
    -0055     if any(exchIdx == 0)
    -0056         missingMets = strjoin(unique(data.conds(exchIdx == 0 )), '; ');
    -0057         error('Carbon source(s) "%s" in the provided fluxData or maxGrowth cannot be matched by name with an exchange reaction.', missingMets);
    -0058     end
    -0059     % Set all other carbon sources to zero
    -0060     model_tmp = setParam(ecModel,'lb',data.exchRxnIDs(unique(exchIdx)),0);
    -0061     % Only allow condition-specific carbon source
    -0062     if constrain % If RMSE is calculated from flux data, then constrain carbon uptake
    -0063         model_tmp = setParam(model_tmp,'lb',data.exchRxnIDs(exchIdx(i)),data.exchFluxes(i,exchIdx(i)));
    -0064     else % If RMSE is calculated from max growth, then do not constrain carbon uptake
    -0065         model_tmp = setParam(model_tmp,'lb',data.exchRxnIDs(exchIdx(i)),-1000);
    -0066     end
    -0067     
    -0068     % Remove carbon source exchange from rxn2block
    -0069     rxn2blockIter = rxn2block;
    -0070     rxn2blockIter(strcmp(rxn2blockIter,data.exchRxnIDs(exchIdx(i)))) = [];
    -0071 
    -0072     % Make anaerobic if relevant
    -0073     o2Flux = data.exchFluxes(i,strcmp('oxygen',data.exchMets));
    -0074     if o2Flux == 0
    -0075         model_tmp = modelAdapter.makeModelAnaerobic(model_tmp);
    -0076     end
    -0077 
    -0078     sol = solveLP(model_tmp);
    -0079     if checkSolution(sol)
    -0080         bioRxn          = getIndexes(model_tmp,data.biomass,'rxns');
    -0081         % Assume that biomass contains 41 Cmmol/gDCW
    -0082         bioMeas         = data.grRate(i) * 41;
    -0083         bioSim          = sol.x(bioRxn) * 41;
    -0084 
    -0085         if constrain
    -0086             fluxToCheck     = ~isnan(data.exchFluxes(i,:));
    -0087             fluxRxnIdx      = getIndexes(model_tmp,data.exchRxnIDs(fluxToCheck),'rxns');
    -0088             cNormMeasFlux   = model_tmp.excarbon(fluxRxnIdx) .* transpose(data.exchFluxes(i,fluxToCheck));
    -0089             cNormSimFlux    = model_tmp.excarbon(fluxRxnIdx) .* sol.x(fluxRxnIdx);
    -0090 
    -0091             % Make sure that selected exchange reactions have zero flux
    -0092             blockRxnIdx     = getIndexes(model_tmp,rxn2blockIter,'rxns');
    -0093             blockSim        = sol.x(blockRxnIdx) .* model_tmp.excarbon(blockRxnIdx);
    -0094             zeroFlux        = blockSim == 0;
    -0095             blockSim(zeroFlux) = [];
    -0096             blockMeas       = zeros(numel(blockSim),1);
    -0097 
    -0098             measured    = [cNormMeasFlux; bioMeas; blockMeas];
    -0099             simulated   = [cNormSimFlux; bioSim; blockSim];
    -0100         else
    -0101             measured    = bioMeas;
    -0102             simulated   = bioSim;
    -0103         end
    -0104         rmseList(i) = sqrt(mse(measured,simulated));
    -0105     else
    -0106         rmseList(i) = NaN;
    -0107     end
    -0108 end
    -0109 rmseList(isnan(rmseList)) = 99; % High penalty for models that failed
    -0110 if isfield(data,'bayesianRMSEweight')
    -0111     rmseList = rmseList .* data.bayesianRMSEweight;
    -0112 end
    -0113 rmse = mean(rmseList);
    -0114 end
    -
    Generated by m2html © 2005
    - - \ No newline at end of file diff --git a/doc/src/geckomat/kcat_sensitivity_analysis/Bayesian/addCarbonNum.html b/doc/src/geckomat/kcat_sensitivity_analysis/Bayesian/addCarbonNum.html deleted file mode 100644 index 1783c4a7..00000000 --- a/doc/src/geckomat/kcat_sensitivity_analysis/Bayesian/addCarbonNum.html +++ /dev/null @@ -1,361 +0,0 @@ - - - - Description of addCarbonNum - - - - - - - - - -
    Home > src > geckomat > kcat_sensitivity_analysis > Bayesian > addCarbonNum.m
    - - - -

    addCarbonNum -

    - -

    PURPOSE ^

    -
    addCarbonNum
    - -

    SYNOPSIS ^

    -
    function model = addCarbonNum(model)
    - -

    DESCRIPTION ^

    -
     addCarbonNum
    -   Adds a carbon number field to the model.
    -
    - Input:
    -   model           ecModel that was generated by makeEcModel, or loaded from
    -                   an earlier run. Not compatible with ecModels generated by
    -                   earlier GECKO versions (pre 3.0).
    - Output:
    -   model           ecModel
    - - -

    CROSS-REFERENCE INFORMATION ^

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

    SUBFUNCTIONS ^

    - - -

    SOURCE CODE ^

    -
    0001 function model = addCarbonNum(model)
    -0002 % addCarbonNum
    -0003 %   Adds a carbon number field to the model.
    -0004 %
    -0005 % Input:
    -0006 %   model           ecModel that was generated by makeEcModel, or loaded from
    -0007 %                   an earlier run. Not compatible with ecModels generated by
    -0008 %                   earlier GECKO versions (pre 3.0).
    -0009 % Output:
    -0010 %   model           ecModel
    -0011 %
    -0012 
    -0013 % get carbonnum for each exchange rxn to further calculation of error
    -0014 model.excarbon = zeros(length(model.rxns),1);
    -0015 [EXrxn, EXrxnIdx] = getExchangeRxns(model);
    -0016 [CarbonNum,EXfors] = getcarbonnum(model,EXrxn);
    -0017 model.excarbon(EXrxnIdx) = CarbonNum;
    -0018 model.excarbon(strcmp(model.rxnNames,'growth')) = 41;
    -0019 
    -0020 function [CarbonNum,EXfors,changedmets] = getcarbonnum(model,exrxn)
    -0021 % getcarbonnum
    -0022 %   Gets carbon numbers matching the model.
    -0023 %
    -0024 % Input:
    -0025 %   model           ecModel that was generated by makeEcModel, or loaded from
    -0026 %                   an earlier run. Not compatible with ecModels generated by
    -0027 %                   earlier GECKO versions (pre 3.0).
    -0028 %   exrxn           Exchange reaction to use for counting
    -0029 % Output:
    -0030 %   model           ecModel
    -0031 %
    -0032 
    -0033 % exrxn must be an exchange rxn and only contain one mets in the equation
    -0034 [~,idx] = ismember(exrxn,model.rxns);
    -0035 EXmets = model.S(:,idx);
    -0036 % find all exchange mets
    -0037 EXmetsIdx = zeros(length(exrxn),1);
    -0038 for k = 1:length(EXmets(1,:))
    -0039     EXmetsIdx(k) = find(EXmets(:,k)); %
    -0040 end
    -0041 EXfors = model.metFormulas(EXmetsIdx);
    -0042 [Ematrix, elements] = getElementalComposition(EXfors,{'C'});
    -0043 Ematrix = Ematrix(:,1);
    -0044 changedmets = exrxn(isnan(Ematrix));
    -0045 Ematrix(isnan(Ematrix)) = 1;
    -0046 CarbonNum = Ematrix;
    -0047 
    -0048 function [Ematrix, elements] = getElementalComposition(formulae, elements, chargeInFormula)
    -0049 % Get the complete elemental composition matrix. It supports formulae with
    -0050 % generic elements, parentheses and decimal places
    -0051 %
    -0052 % USAGE:
    -0053 %    [Ematrix, elements] = getElementalComposition(formulae, elements, chargeInFormula)
    -0054 %
    -0055 % INPUT:
    -0056 %    formulae:        cell array of strings of chemical formulae. Can contain any generic elements starting
    -0057 %                     with a capital letter followed by lowercase letters or '_', followed by a non-negative number.
    -0058 %                     Also support '()', '[]', '{}'. E.g. {'H2O'; '[H2O]2(CuSO4)Generic_element0.5'}
    -0059 % OPTIONAL INPUTS:
    -0060 %    elements:        elements from previous call to preserve the order (default {})
    -0061 %    chargeInFormula: true to accept formulae containing the generic element 'Charge' representing the charges,
    -0062 %                     followed by a real number, e.g., 'HCharge1', 'SO4Charge-2' (default false).
    -0063 %
    -0064 % OUTPUTS:
    -0065 %    Ematrix:         elemental composition matrix (#formulae x #elements)
    -0066 %    elements:         cell array of elements corresponding to the columns of Ematrix
    -0067 %
    -0068 % E.g., [Ematrix, elements] = getElementalComposition({'H2O'; '[H2O]2(CuSO4)Generic_element0.5'}) would return:
    -0069 %  elements = {'H', 'O', 'Cu', 'S', 'Generic_element'}
    -0070 %  Ematrix = [ 2,   1,    0,   0,   0;
    -0071 %              4,   6,    1,   1,   0.5]
    -0072 %
    -0073 % Siu Hung Joshua Chan May 2017
    -0074 
    -0075 if nargin < 3 || isempty(chargeInFormula)
    -0076     chargeInFormula = false;
    -0077 else
    -0078     chargeInFormula = logical(chargeInFormula);
    -0079 end
    -0080 % for recalling the original formula at the top level if there are parentheses
    -0081 % in the formula leading to iterative calling
    -0082 persistent formTopLv
    -0083 persistent formCurLv
    -0084 % for storing error message during iterative calling
    -0085 persistent errMsg
    -0086 persistent errMsgInThisLoop
    -0087 persistent topLvJ
    -0088 persistent selfCall
    -0089 if isempty(selfCall)
    -0090     selfCall = 0;
    -0091 end
    -0092 if ~selfCall
    -0093     [formTopLv, errMsg] = deal('');
    -0094 end
    -0095 
    -0096 if ~isstruct(formulae)
    -0097     if ~iscell(formulae)
    -0098         % make sure it is a cell array of strings
    -0099         formulae = {formulae};
    -0100     end
    -0101 else
    -0102     % also accept COBRA model as input
    -0103     if isfield(formulae, 'metFormulas')
    -0104         formulae = formulae.metFormulas;
    -0105     else
    -0106         error('The 1st input ''formulae'' should be a cell array of strings of formulae or a COBRA model with *.metFormulas')
    -0107     end
    -0108 end
    -0109 
    -0110 if nargin < 2 || isempty(elements)
    -0111     elements = {};
    -0112 elseif numel(unique(elements)) < numel(elements)
    -0113     error('Repeated elements in the input ''elements'' array.')
    -0114 else
    -0115     elements = elements(:)';  % make sure it is a row vector
    -0116 end
    -0117 
    -0118 % the Ematrix
    -0119 Ematrix = zeros(numel(formulae), numel(elements));
    -0120 % replace all brackets and braces by parentheses
    -0121 formulae = regexprep(formulae, '[\[\{]', '\(');
    -0122 formulae = regexprep(formulae, '[\]\}]', '\)');
    -0123 digit = floor(log10(numel(formulae))) + 1;
    -0124 for j = 1:numel(formulae)
    -0125     if ~selfCall
    -0126         % reset top level information for each formula
    -0127         [formTopLv, topLvJ, errMsgInThisLoop] = deal(formulae{j}, j, false);
    -0128     end
    -0129     formulae{j} = strtrim(formulae{j});
    -0130     if ~isempty(formulae{j})
    -0131         % get all outer parentheses
    -0132         parenthesis = [];
    -0133         stP = [];
    -0134         stPpos = [];
    -0135         lv = 0;
    -0136         k = 1;
    -0137         while k <= length(formulae{j})
    -0138             if strcmp(formulae{j}(k),'(')
    -0139                 if lv == 0
    -0140                     pStart = k;
    -0141                 end
    -0142                 lv = lv + 1;
    -0143             elseif strcmp(formulae{j}(k),')')
    -0144                 if lv == 1
    -0145                     parenthesis = [parenthesis; [pStart k]];
    -0146                     % right parenthesis, get the following stoichiometry if any
    -0147                     stPre = regexp(formulae{j}(k+1:end), '^(\+|\-)?\d*\.?\d*', 'match');
    -0148                     if isempty(stPre)
    -0149                         stP = [stP; 1];
    -0150                         stPpos = [stPpos; k k];
    -0151                     else
    -0152                         stCheck = str2double(stPre{1});
    -0153                         s = '';
    -0154                         if isnan(stCheck)
    -0155                             s = 'Invalid';
    -0156                         elseif stCheck < 0
    -0157                             s = 'Negative';
    -0158                         end
    -0159                         if ~isempty(s)  % error if not convertible to number or negative
    -0160                             f = [formulae{j}(parenthesis(end,1):parenthesis(end,2)), stPre{1}];
    -0161                             addErrorMessage(sprintf('    %s stoichiometry in ''%s''\n', s, f))
    -0162                         end
    -0163                         % stoichiometry
    -0164                         stP = [stP; stCheck];
    -0165                         % position of the stoichiometry in the text
    -0166                         stPpos = [stPpos; k + 1, k + length(stPre{1})];
    -0167                         k = k + length(stPre{1});
    -0168                     end
    -0169                 end
    -0170                 lv = lv - 1;
    -0171             end
    -0172             k = k + 1;
    -0173         end
    -0174         if isempty(parenthesis)
    -0175         % No parenthesis, parse the formula
    -0176             re = regexp(formulae{j}, '([A-Z][a-z_]*)((?:\+|\-)?\d*\.?\d*)', 'tokens');
    -0177             s = strjoin(cellfun(@(x) strjoin(x,''), re, 'UniformOutput', false), '');
    -0178             errorFlag = 0;
    -0179             if ~strcmp(s, formulae{j})  % check if the entire formula is retrieved
    -0180                 errorFlag = 1;
    -0181             else
    -0182                 % check the stoichiometry
    -0183                 eleCheck = cellfun(@(x) x{1}, re, 'UniformOutput', false);
    -0184                 stCheck = cellfun(@(x) str2double(x{2}), re);
    -0185                 stCheck(cellfun(@(x) isempty(x{2}), re)) = 1;  % empty value => stoichiometry = 1
    -0186                 if any(isnan(stCheck))
    -0187                     f = strjoin(cellfun(@(x) strjoin(x, ''), re(isnan(stCheck)), 'UniformOutput', false), ''', ''');
    -0188                     [errorFlag, errMsgKey] = deal(2, 'Invalid');
    -0189                 else
    -0190                     % if chargeInFormula is true, detect negative stoich for non-charge elements, else any negative stoich
    -0191                     negSt = (~chargeInFormula | ~strcmp(eleCheck, 'Charge')) & stCheck < 0;
    -0192                     if any(negSt)
    -0193                         f = strjoin(cellfun(@(x) strjoin(x, ''), re(negSt), 'UniformOutput', false), ''', ''');
    -0194                         [errorFlag, errMsgKey] = deal(2, 'Negative');
    -0195                     end
    -0196                 end
    -0197             end
    -0198             if errorFlag > 0
    -0199                 if selfCall <= 1
    -0200                     s2 = sprintf('from the part ''%s''', formulae{j});
    -0201                 elseif selfCall == 2
    -0202                     s2 = sprintf('from the part ''(%s)''', formCurLv);
    -0203                 elseif selfCall == 3
    -0204                     s2 = sprintf('from the part ''(%s)''', formulae{j});
    -0205                 end
    -0206                 if errorFlag == 1
    -0207                     s2 = sprintf(['    Only ''%s'' can be recognized %s.\n'...
    -0208                         '       Each element should start with a capital letter followed by lower case letters'...
    -0209                         ' or ''_'' with indefinite length and followed by a number.\n'], s, s2);
    -0210                 elseif errorFlag == 2
    -0211                     s2 = sprintf('    %s stoichiometry in ''%s'' %s\n', errMsgKey, f, s2);
    -0212                 end
    -0213                 addErrorMessage(s2);
    -0214             end
    -0215             elementJ = repmat({''}, 1, numel(re));
    -0216             nEj = 0;
    -0217             stoichJ = zeros(numel(re),1);
    -0218             for k = 1:numel(re)
    -0219                 [ynK,idK] = ismember(re{k}(1), elementJ(1:nEj));
    -0220                 if ynK
    -0221                     k2 = idK;
    -0222                 else
    -0223                     nEj = nEj + 1;
    -0224                     elementJ{nEj} = re{k}{1};
    -0225                     k2 = nEj;
    -0226                 end
    -0227                 if isempty(re{k}{2})
    -0228                     stoichJ(k2) = stoichJ(k2) + 1;
    -0229                 else
    -0230                     stoichJ(k2) = stoichJ(k2) + str2double(re{k}{2});
    -0231                 end
    -0232             end
    -0233             elementJ = elementJ(1:nEj);
    -0234             stoichJ = stoichJ(1:nEj);
    -0235             [ynE, idE] = ismember(elementJ, elements);  % map to existing elements
    -0236             if any(~ynE)
    -0237                 idE(~ynE) = (numel(elements) + 1):(numel(elements) + sum(~ynE));
    -0238                 Ematrix(:, (numel(elements) + 1):(numel(elements) + sum(~ynE))) = 0;
    -0239                 elements = [elements, elementJ(~ynE)];
    -0240             end
    -0241             Ematrix(j, idE) = stoichJ;
    -0242         else
    -0243             % parentheses found. Iteratively get the formula inside parentheses
    -0244             rest = true(length(formulae{j}),1);
    -0245             for k = 1:size(parenthesis,1)
    -0246                 selfCallCur = selfCall;
    -0247                 selfCall = 3;
    -0248                 [EmatrixK, elements] = getElementalComposition(formulae{j}(...
    -0249                     (parenthesis(k,1)+1):(parenthesis(k,2)-1)), elements, chargeInFormula);
    -0250                 if numel(elements) > size(Ematrix, 2)
    -0251                     Ematrix(:, (size(Ematrix, 2) + 1):numel(elements)) = 0;
    -0252                 end
    -0253                 selfCall = selfCallCur;
    -0254                 Ematrix(j, 1:numel(elements)) = Ematrix(j, 1:numel(elements)) + EmatrixK * stP(k);
    -0255                 rest(parenthesis(k,1):stPpos(k,2)) = false;          
    -0256             end
    -0257             if any(rest)
    -0258                 formCurLv = formulae{j};
    -0259                 selfCallCur = selfCall;
    -0260                 selfCall = 1 + (selfCall >= 1);
    -0261                 while any(rest)
    -0262                     % get the consecutive part of the formula that is not in parentheses
    -0263                     [pStart, pEnd] = deal(find(rest, 1), find(~rest));
    -0264                     pEnd = min(pEnd(pEnd > pStart));
    -0265                     if isempty(pEnd)
    -0266                         pEnd = numel(rest);
    -0267                     else
    -0268                         pEnd = pEnd - 1;
    -0269                     end
    -0270                     [EmatrixK, elements] = getElementalComposition(formulae{j}(pStart:pEnd), elements, chargeInFormula);
    -0271                     if numel(elements) > size(Ematrix, 2)
    -0272                         Ematrix(:, (size(Ematrix, 2) + 1):numel(elements)) = 0;
    -0273                     end
    -0274                     Ematrix(j, 1:numel(elements)) = Ematrix(j, 1:numel(elements)) + EmatrixK;
    -0275                     rest(pStart:pEnd) = false;
    -0276                 end
    -0277                 selfCall = selfCallCur;
    -0278             end
    -0279         end
    -0280     else
    -0281         Ematrix(j,:) = NaN;
    -0282     end
    -0283 end
    -0284 Ematrix = Ematrix(:, 1:numel(elements));
    -0285 if ~selfCall 
    -0286     selfCall = [];
    -0287     if ~isempty(errMsg)
    -0288         error(['%s\n', errMsg], 'Invalid formula input:')
    -0289     end
    -0290 end
    -0291 
    -0292 % nested function for adding error messages
    -0293     function addErrorMessage(s)
    -0294         if ~errMsgInThisLoop
    -0295             errMsg = [errMsg, sprintf(['#%0' num2str(digit) 'd:  %s\n'], topLvJ, formTopLv)];
    -0296             errMsgInThisLoop = true;
    -0297         end
    -0298         errMsg = [errMsg, s];
    -0299     end
    -0300 end
    -0301 
    -0302 end
    -0303 
    -0304 end
    -
    Generated by m2html © 2005
    - - \ No newline at end of file diff --git a/doc/src/geckomat/kcat_sensitivity_analysis/Bayesian/bayesianSensitivityTuning.html b/doc/src/geckomat/kcat_sensitivity_analysis/Bayesian/bayesianSensitivityTuning.html deleted file mode 100644 index 4c99bbda..00000000 --- a/doc/src/geckomat/kcat_sensitivity_analysis/Bayesian/bayesianSensitivityTuning.html +++ /dev/null @@ -1,285 +0,0 @@ - - - - Description of bayesianSensitivityTuning - - - - - - - - - -
    Home > src > geckomat > kcat_sensitivity_analysis > Bayesian > bayesianSensitivityTuning.m
    - - - -

    bayesianSensitivityTuning -

    - -

    PURPOSE ^

    -
    bayesianSensitivityTuning
    - -

    SYNOPSIS ^

    -
    function [ecModel, rmseTrace, kcatTrace, stdTrace] = bayesianSensitivityTuning(ecModel,kcatStd,modelAdapter)
    - -

    DESCRIPTION ^

    -
     bayesianSensitivityTuning
    -   Modifies kcats to better fit experimental data. Currently only works with
    -   light models.
    -
    - Input:
    -   ecModel         ecModel that was generated by makeEcModel, or loaded from
    -                   an earlier run. Not compatible with ecModels generated by
    -                   earlier GECKO versions (pre 3.0).
    -   kcatStd         vector of same length as ecModel.ec.kcat, with the
    -                   initial standard deviations (SD) for the kcat values.
    -                   By default, kcatStd is set by multiplying kcat values
    -                   with params.bayesian.initSDmultiplDef, or by source-
    -                   specific multipliers specified in params.bayesian.
    -                   kcatSources and params.bayesian.initSDmultipl. Instead,
    -                   it is also possible to provide a custom kcatStd vector.
    -   modelAdapter    a loaded model adapter (Optional, will otherwise use the
    -                   default model adapter).
    -
    - Output:
    -   model           ecModel with new kcats, not applied.
    - - -

    CROSS-REFERENCE INFORMATION ^

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

    SOURCE CODE ^

    -
    0001 function [ecModel, rmseTrace, kcatTrace, stdTrace] = bayesianSensitivityTuning(ecModel,kcatStd,modelAdapter)
    -0002 % bayesianSensitivityTuning
    -0003 %   Modifies kcats to better fit experimental data. Currently only works with
    -0004 %   light models.
    -0005 %
    -0006 % Input:
    -0007 %   ecModel         ecModel that was generated by makeEcModel, or loaded from
    -0008 %                   an earlier run. Not compatible with ecModels generated by
    -0009 %                   earlier GECKO versions (pre 3.0).
    -0010 %   kcatStd         vector of same length as ecModel.ec.kcat, with the
    -0011 %                   initial standard deviations (SD) for the kcat values.
    -0012 %                   By default, kcatStd is set by multiplying kcat values
    -0013 %                   with params.bayesian.initSDmultiplDef, or by source-
    -0014 %                   specific multipliers specified in params.bayesian.
    -0015 %                   kcatSources and params.bayesian.initSDmultipl. Instead,
    -0016 %                   it is also possible to provide a custom kcatStd vector.
    -0017 %   modelAdapter    a loaded model adapter (Optional, will otherwise use the
    -0018 %                   default model adapter).
    -0019 %
    -0020 % Output:
    -0021 %   model           ecModel with new kcats, not applied.
    -0022 %
    -0023 if nargin < 3 || isempty(modelAdapter)
    -0024     modelAdapter = ModelAdapterManager.getDefault();
    -0025     if isempty(modelAdapter)
    -0026         error('Either send in a modelAdapter or set the default ecModel adapter in the ModelAdapterManager.')
    -0027     end
    -0028 end
    -0029 
    -0030 %% Load hyperparameters
    -0031 params = modelAdapter.params;
    -0032 initSDmultiplDef    = params.bayesian.initSDmultiplDef;
    -0033 kcatSources         = params.bayesian.kcatSources;
    -0034 initSDmultipl       = params.bayesian.initSDmultipl;
    -0035 scheduleGenerations = params.bayesian.scheduleGenerations;
    -0036 scheduleSamples     = params.bayesian.scheduleSamples;
    -0037 scheduleTarget      = params.bayesian.scheduleTarget;
    -0038 minKeep             = params.bayesian.minKeep;
    -0039 rmseThreshold       = params.bayesian.rmseThreshold;
    -0040 maxGenerations      = params.bayesian.maxGenerations;
    -0041 basePath            = params.path;
    -0042 
    -0043 %% Define initial kcat distributions
    -0044 if nargin < 2 || isempty(kcatStd)
    -0045     kcatStd     = ecModel.ec.kcat .* initSDmultiplDef;
    -0046     for i = 1:numel(kcatSources)
    -0047         selKcats            = strcmpi(ecModel.ec.source,kcatSources{i});
    -0048         kcatStd(selKcats)   = ecModel.ec.kcat(selKcats) .* initSDmultipl(i);
    -0049     end
    -0050 end
    -0051 
    -0052 %% Load data
    -0053 [fluxData, maxGrate, zeroFlux] = loadBayesianData(modelAdapter);
    -0054 
    -0055 % get carbonnum for each exchange rxn to further calculation of error
    -0056 if ~isfield(ecModel,'excarbon')
    -0057     ecModel = addCarbonNum(ecModel);
    -0058     ecModel.excarbon(ecModel.excarbon == 0) = 1;
    -0059 end
    -0060 
    -0061 %these will be updated in the loop below
    -0062 kcats = ecModel.ec.kcat;
    -0063 D     = numel(kcats);
    -0064 
    -0065 rmse = abc_max(ecModel,fluxData,maxGrate,zeroFlux,modelAdapter);
    -0066 fprintf('RMSE with prior kcats: %.2f.\n', rmse)
    -0067 
    -0068 rmseTop   = rmse;
    -0069 kcatTop   = kcats;
    -0070 rmseTrace = rmse;
    -0071 kcatTrace = kcats;
    -0072 stdTrace  = kcatStd;
    -0073 
    -0074 PB1 = ProgressBar2(maxGenerations, ['Run through ' num2str(maxGenerations) ' generations'], 'gui');
    -0075 
    -0076 % Switch off default carbon source, will be set in each sample
    -0077 tmpModel = setParam(ecModel,'lb',modelAdapter.params.c_source,0);
    -0078 
    -0079 %% MAIN ABC-SMC LOOP
    -0080 generation = 1;
    -0081 while rmse > rmseThreshold
    -0082     if generation <= maxGenerations
    -0083         fprintf('Running iteration %d of %d. ', generation, maxGenerations)
    -0084 
    -0085         % Define N and targetFrac dependent on the generation
    -0086         schedulePos = find(generation >= scheduleGenerations, 1, 'last');
    -0087         N           = scheduleSamples(schedulePos);
    -0088         targetFrac  = scheduleTarget(schedulePos); % Acceptance fraction
    -0089 
    -0090         % Sampling
    -0091         if generation == 1
    -0092             % Define randomKcats via lognormal sampling around priors
    -0093             randomKcats = arrayfun(@getrSample, kcats, kcatStd, repmat(N, length(kcats), 1), 'UniformOutput', false);
    -0094             randomKcats = cell2mat(randomKcats);
    -0095         else
    -0096             % Define randomKcats by sampling around previous accepted
    -0097             % solutions using a full-covariance Guassian kernel in log
    -0098             % space, ABC-PMC
    -0099             % Randomly pick N columns with accepted kcat values
    -0100             parent_idx = randi(size(kcatTop,2), [1 N]);
    -0101             parents = log(kcatTop(:, parent_idx));
    -0102 
    -0103             % Compute Cholesky factor of the log-space covariance SigmaLog,
    -0104             % stabilize with 1e-12*i
    -0105             L = chol(SigmaLog + 1e-12*eye(D), 'lower');
    -0106             % Draw normal noise for each proposal and correlate via L
    -0107             Z = randn(D, N);
    -0108             thetaProp = parents + L * Z;
    -0109 
    -0110             % Map back to linear space
    -0111             randomKcats = exp(thetaProp);
    -0112         end
    -0113 
    -0114         if any(randomKcats <= 0, 'all')
    -0115             warning('randomKcats contains non-positive values after sampling; enforcing floor.')
    -0116             randomKcats = max(randomKcats, realmin);
    -0117         end
    -0118 
    -0119         %% Evaluate RMSE for each proposed sample
    -0120         newRmse  = zeros(N,1);
    -0121         PB2 = ProgressBar2(N, ['Simulate ' num2str(N) ' models with random kcats'], 'gui');
    -0122 
    -0123         parfor j = 1:N
    -0124             ecModelIter         = tmpModel;
    -0125             ecModelIter.ec.kcat = randomKcats(:,j);
    -0126             ecModelIter         = applyKcatConstraints(ecModelIter);
    -0127             newRmse(j)          = abc_max(ecModelIter,fluxData,maxGrate,zeroFlux,modelAdapter);
    -0128             count(PB2)
    -0129         end
    -0130 
    -0131         % Leave out zero rmse results: model was unsolvable
    -0132         zeroIdx = (newRmse == 0);
    -0133         newRmse(zeroIdx) = [];
    -0134         randomKcats(:,zeroIdx) = [];
    -0135 
    -0136         % Combine with results from previous generation
    -0137         rmse = [newRmse; rmseTop];
    -0138         kcat = [randomKcats, kcatTop];
    -0139 
    -0140         % Suggested number of accepted samples
    -0141         targetCount = max(1, round(targetFrac * numel(rmse)));
    -0142 
    -0143         % Sort RMSE ascending (best first)
    -0144         [~, ord] = sort(rmse, 'ascend');
    -0145 
    -0146         % Soft guard: check if RMSE curve is flat → soften selection
    -0147         if generation > 5
    -0148             lastWindow = rmseTrace(end-4:end); % Check last 5 RMSE
    -0149             if max(lastWindow) - min(lastWindow) < 1e-6
    -0150                 % Plateau detected → relax selection slightly
    -0151                 targetCount = round(targetCount * 1.3);
    -0152             end
    -0153         end
    -0154 
    -0155         % At least keep minKeep samples
    -0156         targetCount  = max(targetCount, minKeep);
    -0157 
    -0158         % Final accepted indices
    -0159         acc_idx = ord(1:targetCount);
    -0160 
    -0161         % Subset accepted samples
    -0162         rmseTop = rmse(acc_idx);
    -0163         kcatTop = kcat(:, acc_idx);
    -0164 
    -0165         %% Define means and standard deviations from accepted samples
    -0166         ss      = num2cell(kcatTop', 1);
    -0167         [a,b]   = arrayfun(@updateprior, ss);
    -0168         kcats   = transpose(a);
    -0169         kcatStd = transpose(b);
    -0170 
    -0171         %% Build new covariance matrix in log-space, to be used for next sampling
    -0172         thetaAcc = log(kcatTop);
    -0173 
    -0174         % Remove outliers, by filtering out samples whose z-scores had a
    -0175         % Median Absolute Deviation (MAD) of 6 or more
    -0176         z = abs(thetaAcc - median(thetaAcc,2)) ./ (mad(thetaAcc,1,2) + 1e-12);
    -0177         keepMask = median(z,1) < 6;
    -0178         % Fallback if everything gets filtered away
    -0179         if ~any(keepMask)
    -0180             warning('MAD filter removed all samples; disabling filtering this generation.');
    -0181             keepMask = true(1, size(thetaAcc,2));
    -0182         end
    -0183         thetaClean = thetaAcc(:, keepMask);
    -0184 
    -0185         % Determine empirical covariance of samples who were retained
    -0186         Cemp = cov(thetaClean');
    -0187 
    -0188         % Reduce noise in Cemp, through Ledoit-Wolf shrinkage towards a
    -0189         % diagonal covariance
    -0190         alphaLW = 0.1;
    -0191         SigmaLog = (1 - alphaLW) * Cemp + alphaLW * diag(diag(Cemp));
    -0192 
    -0193         %% Track progress (use best, not first)
    -0194         [bestRMSE, bestIdx] = min(rmseTop);
    -0195         rmseTrace = [rmseTrace, bestRMSE];
    -0196         kcatTrace = [kcatTrace, kcats];
    -0197         stdTrace  = [stdTrace,  kcatStd];
    -0198 
    -0199         % Set a feasible/best point for next iteration's model baseline
    -0200         tmpModel.ec.kcat = kcatTop(:, bestIdx);
    -0201         tmpModel = applyKcatConstraints(tmpModel);
    -0202 
    -0203         fprintf('Accepted %d / %d, avg RMSE (accepted): %.2f, best: %.2f.\n', ...
    -0204             numel(rmseTop), numel(rmse), mean(rmseTop), bestRMSE)
    -0205 
    -0206         generation = generation + 1;
    -0207     else
    -0208         fprintf('Halted due to reaching maximum generation limit. Returning best posterior kcats.\n')
    -0209         break
    -0210     end
    -0211     count(PB1)
    -0212 end
    -0213 
    -0214 % Return best posterior kcats (best among last accepted)
    -0215 [~, bestIdx] = min(rmseTop);
    -0216 ecModel.ec.kcat = kcatTop(:, bestIdx);
    -0217 ecModel = applyKcatConstraints(ecModel);
    -0218 fprintf('Final RMSE: %.2f.\n', rmseTop(bestIdx))
    -0219 end
    -
    Generated by m2html © 2005
    - - \ No newline at end of file diff --git a/doc/src/geckomat/kcat_sensitivity_analysis/Bayesian/getrSample.html b/doc/src/geckomat/kcat_sensitivity_analysis/Bayesian/getrSample.html deleted file mode 100644 index 9cd7ec41..00000000 --- a/doc/src/geckomat/kcat_sensitivity_analysis/Bayesian/getrSample.html +++ /dev/null @@ -1,93 +0,0 @@ - - - - Description of getrSample - - - - - - - - - -
    Home > src > geckomat > kcat_sensitivity_analysis > Bayesian > getrSample.m
    - - - -

    getrSample -

    - -

    PURPOSE ^

    -
    getrSample
    - -

    SYNOPSIS ^

    -
    function r = getrSample(mu,sigma,n,method)
    - -

    DESCRIPTION ^

    -
     getrSample
    -   Sample random kcat values from a distribution.
    -
    - Input:
    -   mu      mean of distribution
    -   sigma   standard deviation of distribution
    -   n       number of kcat values to sample
    -   method  shape of distribution: 'lognormal' or 'uniform'. (optional,
    -           default is 'lognormal'). If 'lognormal' is selected, mu and
    -           sigma are automatically converted into log-space
    -
    - Output:
    -   r       sample of kcat values
    - - -

    CROSS-REFERENCE INFORMATION ^

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

    SOURCE CODE ^

    -
    0001 function r = getrSample(mu,sigma,n,method)
    -0002 % getrSample
    -0003 %   Sample random kcat values from a distribution.
    -0004 %
    -0005 % Input:
    -0006 %   mu      mean of distribution
    -0007 %   sigma   standard deviation of distribution
    -0008 %   n       number of kcat values to sample
    -0009 %   method  shape of distribution: 'lognormal' or 'uniform'. (optional,
    -0010 %           default is 'lognormal'). If 'lognormal' is selected, mu and
    -0011 %           sigma are automatically converted into log-space
    -0012 %
    -0013 % Output:
    -0014 %   r       sample of kcat values
    -0015 
    -0016 if nargin < 4
    -0017     method = 'lognormal';
    -0018 end
    -0019 if mu == 0
    -0020     r = zeros(1,n);
    -0021 elseif strcmp(method,'lognormal')
    -0022     % Convert to log-space
    -0023     varLog      = log(1 + (sigma/mu)^2);
    -0024     sigmaLog    = sqrt(varLog);
    -0025     muLog       = log(mu) - 0.5 * varLog;
    -0026 
    -0027     % Take random samples from lognormal distribution
    -0028     r = lognrnd(muLog,sigmaLog,[1,n]);
    -0029 elseif strcmp(method,'uniform')
    -0030     pd = makedist('uniform','lower',mu - sigma,'upper',mu + sigma);
    -0031     t = truncate(pd,0,inf);
    -0032     r = random(t,1,n);
    -0033 end
    -0034 end
    -
    Generated by m2html © 2005
    - - \ No newline at end of file diff --git a/doc/src/geckomat/kcat_sensitivity_analysis/Bayesian/index.html b/doc/src/geckomat/kcat_sensitivity_analysis/Bayesian/index.html deleted file mode 100644 index de423a24..00000000 --- a/doc/src/geckomat/kcat_sensitivity_analysis/Bayesian/index.html +++ /dev/null @@ -1,29 +0,0 @@ - - - - Index for Directory src\geckomat\kcat_sensitivity_analysis\Bayesian - - - - - - - - - - -
    < Master indexIndex for src\geckomat\kcat_sensitivity_analysis\Bayesian >
    - -

    Index for src\geckomat\kcat_sensitivity_analysis\Bayesian

    - -

    Matlab files in this directory:

    - -
     abc_maxabc_max
     addCarbonNumaddCarbonNum
     bayesianSensitivityTuningbayesianSensitivityTuning
     getrSamplegetrSample
     loadBayesianData
     mse
     updatepriorupdateprior
    - - - - -
    Generated by m2html © 2005
    - - \ No newline at end of file diff --git a/doc/src/geckomat/kcat_sensitivity_analysis/Bayesian/loadBayesianData.html b/doc/src/geckomat/kcat_sensitivity_analysis/Bayesian/loadBayesianData.html deleted file mode 100644 index 03cb384a..00000000 --- a/doc/src/geckomat/kcat_sensitivity_analysis/Bayesian/loadBayesianData.html +++ /dev/null @@ -1,63 +0,0 @@ - - - - Description of loadBayesianData - - - - - - - - - -
    Home > src > geckomat > kcat_sensitivity_analysis > Bayesian > loadBayesianData.m
    - - - -

    loadBayesianData -

    - -

    PURPOSE ^

    -
    - -

    SYNOPSIS ^

    -
    function [fluxData, maxGrate, zeroFlux] = loadBayesianData(modelAdapter)
    - -

    DESCRIPTION ^

    -
    - - -

    CROSS-REFERENCE INFORMATION ^

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

    SOURCE CODE ^

    -
    0001 function [fluxData, maxGrate, zeroFlux] = loadBayesianData(modelAdapter)
    -0002 
    -0003 if nargin < 1 || isempty(modelAdapter)
    -0004     modelAdapter = ModelAdapterManager.getDefault();
    -0005     if isempty(modelAdapter)
    -0006         error('Either send in a modelAdapter or set the default ecModel adapter in the ModelAdapterManager.')
    -0007     end
    -0008 end
    -0009 
    -0010 basePath            = modelAdapter.params.path;
    -0011 fluxData = loadFluxData(fullfile(basePath,'data','bayesianFluxData.tsv'));
    -0012 fluxData.biomass = modelAdapter.params.bioRxn;
    -0013 maxGrate = loadFluxData(fullfile(basePath,'data','bayesianMaxGrowth.tsv'));
    -0014 maxGrate.biomass = modelAdapter.params.bioRxn;
    -0015 zeroFlux = table2cell(readtable(fullfile(basePath,'data','bayesianZeroExch.tsv'), 'Delimiter', '\t', 'FileType','delimitedtext'));
    -0016 end
    -
    Generated by m2html © 2005
    - - \ No newline at end of file diff --git a/doc/src/geckomat/kcat_sensitivity_analysis/Bayesian/mse.html b/doc/src/geckomat/kcat_sensitivity_analysis/Bayesian/mse.html deleted file mode 100644 index c13adfa2..00000000 --- a/doc/src/geckomat/kcat_sensitivity_analysis/Bayesian/mse.html +++ /dev/null @@ -1,50 +0,0 @@ - - - - Description of mse - - - - - - - - - -
    Home > src > geckomat > kcat_sensitivity_analysis > Bayesian > mse.m
    - - - -

    mse -

    - -

    PURPOSE ^

    -
    - -

    SYNOPSIS ^

    -
    function err = mse(y,x)
    - -

    DESCRIPTION ^

    -
    - - -

    CROSS-REFERENCE INFORMATION ^

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

    SOURCE CODE ^

    -
    0001 function err = mse(y,x)
    -0002 err = (norm(x(:)-y(:),2).^2)/numel(x);
    -0003 end
    -
    Generated by m2html © 2005
    - - \ No newline at end of file diff --git a/doc/src/geckomat/kcat_sensitivity_analysis/Bayesian/updateprior.html b/doc/src/geckomat/kcat_sensitivity_analysis/Bayesian/updateprior.html deleted file mode 100644 index d0ec2b98..00000000 --- a/doc/src/geckomat/kcat_sensitivity_analysis/Bayesian/updateprior.html +++ /dev/null @@ -1,91 +0,0 @@ - - - - Description of updateprior - - - - - - - - - -
    Home > src > geckomat > kcat_sensitivity_analysis > Bayesian > updateprior.m
    - - - -

    updateprior -

    - -

    PURPOSE ^

    -
    updateprior
    - -

    SYNOPSIS ^

    -
    function [mu,sigma] = updateprior(x,defaultCV)
    - -

    DESCRIPTION ^

    -
     updateprior
    -   Calculates a new distribution from the provided kcat values
    -
    - Input:
    -   x       kcat values
    -
    - Output:
    -   mu      mean
    -   sigma   standard deviation
    - - -

    CROSS-REFERENCE INFORMATION ^

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

    SOURCE CODE ^

    -
    0001 function [mu,sigma] = updateprior(x,defaultCV)
    -0002 % updateprior
    -0003 %   Calculates a new distribution from the provided kcat values
    -0004 %
    -0005 % Input:
    -0006 %   x       kcat values
    -0007 %
    -0008 % Output:
    -0009 %   mu      mean
    -0010 %   sigma   standard deviation
    -0011 
    -0012 if nargin<2
    -0013     defaultCV = 0.25;
    -0014 end
    -0015 
    -0016 if iscell(x), x = x{:}; end
    -0017 
    -0018 % Remove non-positive values—they cannot be logged
    -0019 n_before = numel(x);
    -0020 x = x(x > 0);
    -0021 if isempty(x)
    -0022     error('x cannot be empty or contain only non-positive values.');
    -0023 end
    -0024 if numel(x) < n_before
    -0025     warning('Removed %d non-positive values before fitting.', n_before - numel(x));
    -0026 end
    -0027 
    -0028 if isscalar(x)
    -0029     mu      = x;
    -0030     sigma   = x * defaultCV;
    -0031 else
    -0032     pd      = fitdist(log(x),'normal');
    -0033     mu    = exp(pd.mu + 0.5 * pd.sigma^2);
    -0034     sigma = sqrt( (exp(pd.sigma^2) - 1) * exp(2*pd.mu + pd.sigma^2) );
    -0035 end
    -0036 end
    -
    Generated by m2html © 2005
    - - \ No newline at end of file diff --git a/doc/src/geckomat/kcat_sensitivity_analysis/findMaxValue.html b/doc/src/geckomat/kcat_sensitivity_analysis/findMaxValue.html deleted file mode 100644 index 45bd3106..00000000 --- a/doc/src/geckomat/kcat_sensitivity_analysis/findMaxValue.html +++ /dev/null @@ -1,124 +0,0 @@ - - - - Description of findMaxValue - - - - - - - - - -
    Home > src > geckomat > kcat_sensitivity_analysis > findMaxValue.m
    - - - -

    findMaxValue -

    - -

    PURPOSE ^

    -
    %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
    - -

    SYNOPSIS ^

    -
    function [value,organism,parameter] = findMaxValue(EC_cell,BRENDA,SA_cell)
    - -

    DESCRIPTION ^

    -
    %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
    -function [value,organism,parameter] = findMaxValue(EC_cell,BRENDA, SA_cell)
    -
    - Function that gets the maximum kinetic parameter (Kcat or S.A.*Mw) from 
    - the BRENDA files for the specified set of EC numbers. The algorithm also 
    - returns the organism and the parameter type (Kcat or S.A.) of the query.
    -
    - Ivan Domenzain    Last edited. 2018-02-06
    -%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
    -Looks for the maximum turnover number available for the EC# associated
    -with the uniprot code
    - - -

    CROSS-REFERENCE INFORMATION ^

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

    SOURCE CODE ^

    -
    0001 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
    -0002 %function [value,organism,parameter] = findMaxValue(EC_cell,BRENDA, SA_cell)
    -0003 %
    -0004 % Function that gets the maximum kinetic parameter (Kcat or S.A.*Mw) from
    -0005 % the BRENDA files for the specified set of EC numbers. The algorithm also
    -0006 % returns the organism and the parameter type (Kcat or S.A.) of the query.
    -0007 %
    -0008 % Ivan Domenzain    Last edited. 2018-02-06
    -0009 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
    -0010 function [value,organism,parameter] = findMaxValue(EC_cell,BRENDA,SA_cell)
    -0011     %Looks for the maximum turnover number available for the EC# associated
    -0012     %with the uniprot code
    -0013     EC_cell    = strsplit(EC_cell,' ');
    -0014     value      = [];
    -0015     organism   = [];
    -0016     parameter  = [];
    -0017     for i=1:length(EC_cell)
    -0018         find_flag  = false;
    -0019         %In case that wild cards are present in the EC number the search on
    -0020         %the BRENDA file will be relaxed.
    -0021         if ~isempty(strfind(EC_cell{i},'-'))
    -0022              EC_cell{i} = EC_cell{i}(strfind(EC_cell{i},'-')-1:end);
    -0023              find_flag  = true;
    -0024         end    
    -0025         ECnumber = ['EC' EC_cell{i}];
    -0026         Kcat     = 0; orgK = '';
    -0027         if find_flag == true
    -0028             matching = find(~cellfun(@isempty,strfind(BRENDA{1},ECnumber)));
    -0029         else
    -0030             % If no wild cards are present the EC number search in the
    -0031             % BRENDA file will look for an exact match
    -0032             matching = find(strcmpi(ECnumber,BRENDA{1}));
    -0033         end
    -0034         %Gets the maximum Kcat value for the queried EC#
    -0035         if ~isempty(matching)
    -0036             [Kcat, maxIndx] = max(BRENDA{4}(matching));
    -0037             orgK            = BRENDA{3}(matching(maxIndx));
    -0038         end        
    -0039         % Looks for the maximum SA*Mw value available for the EC number
    -0040         SA_Mw = 0; orgS = '';
    -0041         if find_flag == true
    -0042             matching = find(~cellfun(@isempty,strfind(SA_cell{1},ECnumber)));
    -0043         else
    -0044             matching = find(strcmpi(ECnumber,SA_cell{1}));
    -0045         end
    -0046         %Gets the maximum SA*Mw value for the queried EC#
    -0047         if ~isempty(matching)
    -0048             [SA_Mw, maxIndx] = max(SA_cell{3}(matching));
    -0049             SA_Mw            = SA_Mw; %[1/hr]
    -0050             orgS             = SA_cell{2}(matching(maxIndx));
    -0051         end        
    -0052         %Choose the maximal available value as a turnover number for the EC
    -0053         value  = [value; max(Kcat,SA_Mw)]; 
    -0054 
    -0055         if Kcat>SA_Mw
    -0056             organism  = [organism; {orgK}];
    -0057             parameter = [parameter; {'K_cat'}];
    -0058         else
    -0059             organism  = [organism; {orgS}];
    -0060             parameter = [parameter; {'SA*Mw'}];
    -0061         end   
    -0062     end
    -0063     [value, maxIndx] = max(value);
    -0064     organism         = organism(maxIndx);
    -0065     parameter        = parameter(maxIndx);
    -0066 end
    -0067 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
    -
    Generated by m2html © 2005
    - - \ No newline at end of file diff --git a/doc/src/geckomat/kcat_sensitivity_analysis/index.html b/doc/src/geckomat/kcat_sensitivity_analysis/index.html deleted file mode 100644 index 332553fc..00000000 --- a/doc/src/geckomat/kcat_sensitivity_analysis/index.html +++ /dev/null @@ -1,31 +0,0 @@ - - - - Index for Directory src\geckomat\kcat_sensitivity_analysis - - - - - - - - - - -
    < Master indexIndex for src\geckomat\kcat_sensitivity_analysis >
    - -

    Index for src\geckomat\kcat_sensitivity_analysis

    - -

    Matlab files in this directory:

    - -
     findMaxValue%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
     sensitivityTuningsensitivityTuning
     sigmaFittersigmaFitter
     truncateValues%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
    - - -

    Subsequent directories:

    - - -
    Generated by m2html © 2005
    - - \ No newline at end of file diff --git a/doc/src/geckomat/kcat_sensitivity_analysis/sensitivityTuning.html b/doc/src/geckomat/kcat_sensitivity_analysis/sensitivityTuning.html deleted file mode 100644 index 93a4112f..00000000 --- a/doc/src/geckomat/kcat_sensitivity_analysis/sensitivityTuning.html +++ /dev/null @@ -1,247 +0,0 @@ - - - - Description of sensitivityTuning - - - - - - - - - -
    Home > src > geckomat > kcat_sensitivity_analysis > sensitivityTuning.m
    - - - -

    sensitivityTuning -

    - -

    PURPOSE ^

    -
    sensitivityTuning
    - -

    SYNOPSIS ^

    -
    function [model, tunedKcats] = sensitivityTuning(model, desiredGrowthRate, modelAdapter, foldChange, protToIgnore, verbose)
    - -

    DESCRIPTION ^

    -
     sensitivityTuning
    -    Function that relaxes the most limiting kcats until a certain growth rate
    -    is reached. The function will update kcats in model.ec.kcat.
    -
    - Input:
    -   model              an ecModel in GECKO 3 format (with ecModel.ec structure)
    -   desiredGrowthRate  kcats will be relaxed until this growth rate is reached
    -   modelAdapter       a loaded model adapter (Optional, will otherwise use the
    -                      default model adapter).
    -   foldChange         kcat values will be increased by this fold-change.
    -                      (Opt, default 10)
    -   protToIgnore       vector of protein ids to be ignore in tuned kcats.
    -                      e.g. {'P38122', 'Q99271'} (Optional, default = [])
    -   verbose            logical whether progress should be reported (Optional,
    -                      default true)
    -
    - Output:
    -   model              ecModel with updated model.ec.kcat
    -   tunedKcats         structure with information on tuned kcat values
    -                      rxns     identifiers of reactions with tuned kcat
    -                               values
    -                      rxnNames names of the reactions in tunedKcats.rxns
    -                      enzymes  enzymes that catalyze the reactions in
    -                               tunedKcats.rxns, whose kcat value has been
    -                               tuned.
    -                      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)
    - - -

    CROSS-REFERENCE INFORMATION ^

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

    SOURCE CODE ^

    -
    0001 function [model, tunedKcats] = sensitivityTuning(model, desiredGrowthRate, modelAdapter, foldChange, protToIgnore, verbose)
    -0002 % sensitivityTuning
    -0003 %    Function that relaxes the most limiting kcats until a certain growth rate
    -0004 %    is reached. The function will update kcats in model.ec.kcat.
    -0005 %
    -0006 % Input:
    -0007 %   model              an ecModel in GECKO 3 format (with ecModel.ec structure)
    -0008 %   desiredGrowthRate  kcats will be relaxed until this growth rate is reached
    -0009 %   modelAdapter       a loaded model adapter (Optional, will otherwise use the
    -0010 %                      default model adapter).
    -0011 %   foldChange         kcat values will be increased by this fold-change.
    -0012 %                      (Opt, default 10)
    -0013 %   protToIgnore       vector of protein ids to be ignore in tuned kcats.
    -0014 %                      e.g. {'P38122', 'Q99271'} (Optional, default = [])
    -0015 %   verbose            logical whether progress should be reported (Optional,
    -0016 %                      default true)
    -0017 %
    -0018 % Output:
    -0019 %   model              ecModel with updated model.ec.kcat
    -0020 %   tunedKcats         structure with information on tuned kcat values
    -0021 %                      rxns     identifiers of reactions with tuned kcat
    -0022 %                               values
    -0023 %                      rxnNames names of the reactions in tunedKcats.rxns
    -0024 %                      enzymes  enzymes that catalyze the reactions in
    -0025 %                               tunedKcats.rxns, whose kcat value has been
    -0026 %                               tuned.
    -0027 %                      oldKcat  kcat values in the input model
    -0028 %                      newKcat  kcat values in the output model, after tuning
    -0029 %
    -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 params = modelAdapter.params;
    -0053 if nargin < 2 || isempty(desiredGrowthRate)
    -0054     desiredGrowthRate = params.gR_exp;
    -0055 end
    -0056 
    -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/kcat_sensitivity_analysis/sigmaFitter.html b/doc/src/geckomat/kcat_sensitivity_analysis/sigmaFitter.html deleted file mode 100644 index 91e68124..00000000 --- a/doc/src/geckomat/kcat_sensitivity_analysis/sigmaFitter.html +++ /dev/null @@ -1,158 +0,0 @@ - - - - Description of sigmaFitter - - - - - - - - - -
    Home > src > geckomat > kcat_sensitivity_analysis > sigmaFitter.m
    - - - -

    sigmaFitter -

    - -

    PURPOSE ^

    -
    sigmaFitter
    - -

    SYNOPSIS ^

    -
    function [model, sigma] = sigmaFitter(model, growthRate, Ptot, f, makePlot, modelAdapter)
    - -

    DESCRIPTION ^

    -
     sigmaFitter
    -   Function that fits the average enzyme saturation factor in an ecModel
    -   according to a provided experimentally measured value for the objective
    -   function (i.e. growth rate at specified conditions)
    -
    - INPUTS:
    -   model           an ecModel in GECKO 3 format (with ecModel.ec structure)
    -   growthRate      growth rate that should be reached. If not
    -                   specified, the value will be read from the model
    -                   adapter.
    -   Ptot            Total cellular protein content in g/gDCW. If not
    -                   specified, the value will be read from the model
    -                   adapter. If not specified in model adapter, 0.5 g/gDCW
    -                   is assumed.
    -   f               Estimated fraction of enzymes in the model. If not
    -                   specified, the value will be read from the model
    -                   adapter. If not specified in model adapter, 0.5 is
    -                   assumed.
    -   makePlot        Logical whether a plot should be made. Default true.
    -   modelAdapter    a loaded model adapter (Optional, will otherwise use the
    -                   default model adapter).
    -
    - Output:
    -   model           ecModel with protein pool exchange upper bound adapted
    -                   to the optimal sigma-factor
    -   sigma           optimal sigma-factor
    -
    - Usage:
    -   [model, sigma] = sigmaFitter(model, growthRate, Ptot, f, makePlot, modelAdapter)
    - - -

    CROSS-REFERENCE INFORMATION ^

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

    SOURCE CODE ^

    -
    0001 function [model, sigma] = sigmaFitter(model, growthRate, Ptot, f, makePlot, modelAdapter)
    -0002 % sigmaFitter
    -0003 %   Function that fits the average enzyme saturation factor in an ecModel
    -0004 %   according to a provided experimentally measured value for the objective
    -0005 %   function (i.e. growth rate at specified conditions)
    -0006 %
    -0007 % INPUTS:
    -0008 %   model           an ecModel in GECKO 3 format (with ecModel.ec structure)
    -0009 %   growthRate      growth rate that should be reached. If not
    -0010 %                   specified, the value will be read from the model
    -0011 %                   adapter.
    -0012 %   Ptot            Total cellular protein content in g/gDCW. If not
    -0013 %                   specified, the value will be read from the model
    -0014 %                   adapter. If not specified in model adapter, 0.5 g/gDCW
    -0015 %                   is assumed.
    -0016 %   f               Estimated fraction of enzymes in the model. If not
    -0017 %                   specified, the value will be read from the model
    -0018 %                   adapter. If not specified in model adapter, 0.5 is
    -0019 %                   assumed.
    -0020 %   makePlot        Logical whether a plot should be made. Default true.
    -0021 %   modelAdapter    a loaded model adapter (Optional, will otherwise use the
    -0022 %                   default model adapter).
    -0023 %
    -0024 % Output:
    -0025 %   model           ecModel with protein pool exchange upper bound adapted
    -0026 %                   to the optimal sigma-factor
    -0027 %   sigma           optimal sigma-factor
    -0028 %
    -0029 % Usage:
    -0030 %   [model, sigma] = sigmaFitter(model, growthRate, Ptot, f, makePlot, modelAdapter)
    -0031 
    -0032 if nargin < 6 || isempty(modelAdapter)
    -0033     modelAdapter = ModelAdapterManager.getDefault();
    -0034     if isempty(modelAdapter)
    -0035         error('Either send in a modelAdapter or set the default model adapter in the ModelAdapterManager.')
    -0036     end
    -0037 end
    -0038 
    -0039 if nargin<5 || isempty(makePlot)
    -0040     makePlot = true;
    -0041 end
    -0042 if nargin<4 || isempty(f)
    -0043     f = modelAdapter.getParameters().f;
    -0044 end
    -0045 if nargin<3 || isempty(Ptot)
    -0046     Ptot = modelAdapter.getParameters().Ptot;
    -0047 end
    -0048 if nargin<2 || isempty(growthRate)
    -0049     growthRate = modelAdapter.getParameters().gR_exp;
    -0050 end
    -0051 
    -0052 objValues = [];
    -0053 errors    = [];
    -0054 sigParam  = [];
    -0055 objPos    = find(model.c);
    -0056 %Relax bounds for the objective function
    -0057 model.lb(objPos) = 0;
    -0058 model.ub(objPos) = 1000;
    -0059 hsSol=[];
    -0060 for i=1:100
    -0061     %Constrains the ecModel with the i-th sigma factor
    -0062     sigma = i/100;
    -0063     model = setProtPoolSize(model, Ptot, f, sigma, modelAdapter);
    -0064     [solution, hsSol]  = solveLP(model,0,[],hsSol);
    -0065     if isempty(solution.x)
    -0066         solution.x=zeros(length(model.rxns),1);
    -0067     end
    -0068     objValues = [objValues; solution.x(objPos)];
    -0069     error     = abs(((growthRate-solution.x(objPos))/growthRate)*100);
    -0070     errors    = [errors; error];
    -0071     error     = num2str(((growthRate-solution.x(objPos))/growthRate)*100);
    -0072     sigParam  = [sigParam; sigma];
    -0073 end
    -0074 [~, minIndx] = min(errors);
    -0075 sigma     = sigParam(minIndx);
    -0076 if makePlot
    -0077     figure
    -0078     plot(sigParam,errors,'LineWidth',5)
    -0079     title('Sigma fitting')
    -0080     xlabel('Average enzyme saturation [-]')
    -0081     ylabel('Absolute relative error [%]')
    -0082 end
    -0083 end
    -
    Generated by m2html © 2005
    - - \ No newline at end of file diff --git a/doc/src/geckomat/kcat_sensitivity_analysis/truncateValues.html b/doc/src/geckomat/kcat_sensitivity_analysis/truncateValues.html deleted file mode 100644 index f549a94f..00000000 --- a/doc/src/geckomat/kcat_sensitivity_analysis/truncateValues.html +++ /dev/null @@ -1,76 +0,0 @@ - - - - Description of truncateValues - - - - - - - - - -
    Home > src > geckomat > kcat_sensitivity_analysis > truncateValues.m
    - - - -

    truncateValues -

    - -

    PURPOSE ^

    -
    %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
    - -

    SYNOPSIS ^

    -
    function table = truncateValues(table,cols)
    - -

    DESCRIPTION ^

    -
    %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
    - table = truncateValues(table,cols)
    -   table   cell array or table where some columns have values that should
    -           be truncated
    -   cols    index or indices of columns with values to be truncated
    -
    - Benjamin Sanchez    Last edited: 2018-05-25
    - Eduard Kerkhoven    Last edited: 2018-12-05
    -%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
    - - -

    CROSS-REFERENCE INFORMATION ^

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

    SOURCE CODE ^

    -
    0001 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
    -0002 % table = truncateValues(table,cols)
    -0003 %   table   cell array or table where some columns have values that should
    -0004 %           be truncated
    -0005 %   cols    index or indices of columns with values to be truncated
    -0006 %
    -0007 % Benjamin Sanchez    Last edited: 2018-05-25
    -0008 % Eduard Kerkhoven    Last edited: 2018-12-05
    -0009 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
    -0010 function table = truncateValues(table,cols)
    -0011 
    -0012 [m,n] = size(table);
    -0013 for i = 1:m
    -0014     for j = cols
    -0015         orderMagn  = max([ceil(log10(abs(table{i,j}))),0]);
    -0016         table{i,j} = round(table{i,j},6-orderMagn);
    -0017     end
    -0018 end
    -0019 end
    -0020 
    -0021 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
    -
    Generated by m2html © 2005
    - - \ No newline at end of file diff --git a/doc/src/geckomat/limit_proteins/calculateFfactor.html b/doc/src/geckomat/limit_proteins/calculateFfactor.html deleted file mode 100644 index ae81fe1d..00000000 --- a/doc/src/geckomat/limit_proteins/calculateFfactor.html +++ /dev/null @@ -1,143 +0,0 @@ - - - - Description of calculateFfactor - - - - - - - - - -
    Home > src > geckomat > limit_proteins > calculateFfactor.m
    - - - -

    calculateFfactor -

    - -

    PURPOSE ^

    -
    calculateFfactor
    - -

    SYNOPSIS ^

    -
    function f = calculateFfactor(model, protData, enzymes, modelAdapter)
    - -

    DESCRIPTION ^

    -
     calculateFfactor
    -   Computes the f factor, as a proxy to the mass fraction of proteins
    -   accounted for in an ecModel out of the total protein content in cells.
    -
    - Input:
    -   model        an ecModel in GECKO 3 format (with ecModel.ec structure)
    -   protData     structure with proteome data, from loadProtData (Optional,
    -                by default it instead attempts to load data/paxDB.tsv)
    -   enzymes      list of enzymes (Optional, default model.ec.enzymes)
    -   modelAdapter a loaded model adapter (Optional, will otherwise use the
    -                default model adapter).
    -
    - Output:
    -   f            f-factor
    -
    - Usage:
    -   f = calculateFfactor(model, protData, enzymes, modelAdapter)
    - - -

    CROSS-REFERENCE INFORMATION ^

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

    SOURCE CODE ^

    -
    0001 function f = calculateFfactor(model, protData, enzymes, modelAdapter)
    -0002 % calculateFfactor
    -0003 %   Computes the f factor, as a proxy to the mass fraction of proteins
    -0004 %   accounted for in an ecModel out of the total protein content in cells.
    -0005 %
    -0006 % Input:
    -0007 %   model        an ecModel in GECKO 3 format (with ecModel.ec structure)
    -0008 %   protData     structure with proteome data, from loadProtData (Optional,
    -0009 %                by default it instead attempts to load data/paxDB.tsv)
    -0010 %   enzymes      list of enzymes (Optional, default model.ec.enzymes)
    -0011 %   modelAdapter a loaded model adapter (Optional, will otherwise use the
    -0012 %                default model adapter).
    -0013 %
    -0014 % Output:
    -0015 %   f            f-factor
    -0016 %
    -0017 % Usage:
    -0018 %   f = calculateFfactor(model, protData, enzymes, modelAdapter)
    -0019 
    -0020 if nargin < 4 || isempty(modelAdapter)
    -0021     modelAdapter = ModelAdapterManager.getDefault();
    -0022     if isempty(modelAdapter)
    -0023         error('Either send in a modelAdapter or set the default model adapter in the ModelAdapterManager.')
    -0024     end
    -0025 end
    -0026 params = modelAdapter.getParameters();
    -0027 
    -0028 if nargin < 3 || isempty(enzymes)
    -0029     enzymes = model.ec.enzymes;
    -0030 end
    -0031 
    -0032 % Gather proteome data in protData structure
    -0033 if nargin < 2 || isempty(protData)
    -0034     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');
    -0038         f = 0.5;
    -0039     end
    -0040 end
    -0041 
    -0042 % Gather Uniprot database for finding MW
    -0043 uniprotDB = loadDatabases('uniprot', modelAdapter);
    -0044 uniprotDB = uniprotDB.uniprot;
    -0045 
    -0046 if ischar(protData) && endsWith(protData,'paxDB.tsv')
    -0047     fID         = fopen(fullfile(protData),'r');
    -0048     fileContent = textscan(fID,'%s','delimiter','\n');
    -0049     headerLines = find(startsWith(fileContent{1},'#'),1,'last');
    -0050     fclose(fID);
    -0051 
    -0052     %Read data file, excluding headerlines
    -0053     fID         = fopen(fullfile(protData),'r');
    -0054     fileContent = textscan(fID,'%s %s %f','delimiter','\t','HeaderLines',headerLines);
    -0055     genes       = fileContent{2};
    -0056     %Remove internal geneIDs modifiers
    -0057     genes       = regexprep(genes,'^\d+\.','');
    -0058     level       = fileContent{3};
    -0059     fclose(fID);
    -0060     [a,b]       = ismember(genes,uniprotDB.genes);
    -0061     uniprot     = uniprotDB.ID(b(a));
    -0062     level(~a)   = [];
    -0063     clear protData
    -0064     protData.uniprotIDs = uniprot;
    -0065     protData.level   = level;
    -0066     % Get MW and abundance (unit does not matter, f is fraction)
    -0067     [~,idx] = ismember(protData.uniprotIDs,uniprotDB.ID);
    -0068     protData.MW = uniprotDB.MW(idx);
    -0069     protData.abundances = protData.level .* protData.MW;
    -0070 end
    -0071 
    -0072 avgAbundances = mean(protData.abundances,2);
    -0073 totalProt = sum(avgAbundances,'omitnan');
    -0074 
    -0075 % Get enzymes in model
    -0076 enzymesInModel = ismember(protData.uniprotIDs,enzymes);
    -0077 totalEnz = sum(avgAbundances(enzymesInModel),'omitnan');
    -0078 
    -0079 f = totalEnz/totalProt;
    -0080 end
    -
    Generated by m2html © 2005
    - - \ No newline at end of file diff --git a/doc/src/geckomat/limit_proteins/constrainEnzConcs.html b/doc/src/geckomat/limit_proteins/constrainEnzConcs.html deleted file mode 100644 index cbf7db32..00000000 --- a/doc/src/geckomat/limit_proteins/constrainEnzConcs.html +++ /dev/null @@ -1,128 +0,0 @@ - - - - Description of constrainEnzConcs - - - - - - - - - -
    Home > src > geckomat > limit_proteins > constrainEnzConcs.m
    - - - -

    constrainEnzConcs -

    - -

    PURPOSE ^

    -
    constrainEnzConcs
    - -

    SYNOPSIS ^

    -
    function model = constrainEnzConcs(model, removeConstraints)
    - -

    DESCRIPTION ^

    -
     constrainEnzConcs
    -   Constrain enzyme usages by their concentration as provided in
    -   model.ec.concs. For enzymes with non-NaN entries in model.ec.concs,
    -   their enzyme usage reaction will no longer draw from the protein pool,
    -   but is rather constraint by the measured protein abundance.
    -
    - Input:
    -   model               an ecModel in GECKO 3 format (with ecModel.ec
    -                       structure) with enzyme concentrations in
    -                       model.ec.concs
    -   removeConstraints   logical, whether enzyme concentration
    -                       constraints should be removed (model.ec.concs
    -                       will remain unchanged). (optional, default false)
    -
    - Output:
    -   model   an ecModel constraint with available enzyme concentrations
    -
    - Note: To populate model.ec.concs you should run fillEnzConcs.
    -
    - Usage:
    -   model = constrainEnzConcs(model, removeConstraints)
    - - -

    CROSS-REFERENCE INFORMATION ^

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

    SOURCE CODE ^

    -
    0001 function model = constrainEnzConcs(model, removeConstraints)
    -0002 % constrainEnzConcs
    -0003 %   Constrain enzyme usages by their concentration as provided in
    -0004 %   model.ec.concs. For enzymes with non-NaN entries in model.ec.concs,
    -0005 %   their enzyme usage reaction will no longer draw from the protein pool,
    -0006 %   but is rather constraint by the measured protein abundance.
    -0007 %
    -0008 % Input:
    -0009 %   model               an ecModel in GECKO 3 format (with ecModel.ec
    -0010 %                       structure) with enzyme concentrations in
    -0011 %                       model.ec.concs
    -0012 %   removeConstraints   logical, whether enzyme concentration
    -0013 %                       constraints should be removed (model.ec.concs
    -0014 %                       will remain unchanged). (optional, default false)
    -0015 %
    -0016 % Output:
    -0017 %   model   an ecModel constraint with available enzyme concentrations
    -0018 %
    -0019 % Note: To populate model.ec.concs you should run fillEnzConcs.
    -0020 %
    -0021 % Usage:
    -0022 %   model = constrainEnzConcs(model, removeConstraints)
    -0023 
    -0024 %Enzyme with NaN entry in model.ec.concs => draw from prot_pool
    -0025 %Enzyme with numeric entry in model.ec.concs => exchange reaction with
    -0026 %enzyme level as UB
    -0027 
    -0028 if nargin<2
    -0029     removeConstraints = false;
    -0030 end
    -0031 
    -0032 %Get indices of usage reactions
    -0033 usageRxns = strcat('usage_prot_',model.ec.enzymes);
    -0034 [~, usageRxnsIdx] = ismember(usageRxns, model.rxns);
    -0035 
    -0036 if any(usageRxnsIdx == 0)
    -0037     error('Usage reactions are not defined for all enzymes. This is done by makeEcModel.')
    -0038 end
    -0039 %Get index of protein pool metabolite
    -0040 protPoolIdx = find(ismember(model.mets,'prot_pool'));
    -0041 if ~any(protPoolIdx)
    -0042     error('Cannot find protein pool pseudometabolite.')
    -0043 end
    -0044 
    -0045 %Protein that should be constraint by UB
    -0046 if removeConstraints
    -0047     protCons = [];
    -0048 else
    -0049     protCons = ~isnan(model.ec.concs);
    -0050 end
    -0051 
    -0052 %Set all reactions to draw from prot_pool
    -0053 model.S(protPoolIdx, usageRxnsIdx) = 1;
    -0054 model.lb(usageRxnsIdx) = -1000;
    -0055 
    -0056 %If non-NaN in model.ec.concs, then constrain by UB
    -0057 if any(protCons)
    -0058 %    model.S(protPoolIdx, usageRxnsIdx(protCons)) = 0; % Since GECKO 3.2.0
    -0059     model.lb(usageRxnsIdx(protCons)) = -model.ec.concs(protCons);
    -0060 end
    -0061 end
    -
    Generated by m2html © 2005
    - - \ No newline at end of file diff --git a/doc/src/geckomat/limit_proteins/constrainFluxData.html b/doc/src/geckomat/limit_proteins/constrainFluxData.html deleted file mode 100644 index b086da06..00000000 --- a/doc/src/geckomat/limit_proteins/constrainFluxData.html +++ /dev/null @@ -1,217 +0,0 @@ - - - - Description of constrainFluxData - - - - - - - - - -
    Home > src > geckomat > limit_proteins > constrainFluxData.m
    - - - -

    constrainFluxData -

    - -

    PURPOSE ^

    -
    constrainFluxData
    - -

    SYNOPSIS ^

    -
    function model = constrainFluxData(model, fluxData, condition, maxMinGrowth, looseStrictFlux, modelAdapter)
    - -

    DESCRIPTION ^

    -
     constrainFluxData
    -   Constrains fluxes to the data that is provided in the fluxData
    -   structure, which itself is read by loadFluxData from data/fluxData.tsv.
    -
    - Input:
    -   model           an ecModel in GECKO 3 format (with ecModel.ec structure)
    -   fluxData        structure with flux data
    -                   conds       sampling condition
    -                   Ptot        total protein (g/gDCW)
    -                   grRate      growth rate (1/h)
    -                   exchFluxes  exchange fluxes (mmol/gDCWh)
    -                   exchMets    exchanged metabolites, matching exchFluxes
    -                   exchRxnIDs  exchange reaction IDs, matching exchMets
    -   condition       either index number or name of the sample condition in
    -                   fluxData.conds (Optional, default = 1)
    -   maxMinGrowth    'max' if the provided growth rate should be set as
    -                   maximum growth rate (= upper bound), or 'min' if it
    -                   should be set as minimum growth rate (= lower bound).
    -                   The latter option is suitable if minimization of
    -                   prot_pool_exchange is used as objective function. (Opt,
    -                   default = 'max')
    -   looseStrictFlux how strictly constrained the exchange fluxes should be,
    -                   optional, default = 'loose'
    -                   'loose' if the exchange fluxes should be constraint
    -                           only by the "outer bounds". If exchFluxes(i)
    -                           > 0, LB = 0 and UB = exchFluxes(i). If
    -                           exchFluxes(i) < 0, LB = exchFluxes(i) and
    -                           UB = 0
    -                   0-100   LB and UB constraints are set with a specified
    -                           percentage of variance around exchFluxes. If 10
    -                           is specified, LB = exchFluxes*0.95 and UB =
    -                           exchFluxes*1.05. This allows for 10% variance
    -                           around the exchFluxes values, but strictly
    -                           forces a flux through the exchRxns.
    -   modelAdapter    a loaded model adapter (Optional, will otherwise use
    -                   the default model adapter)
    -
    - Output:
    -   model           an ecModel where fluxes are constraint
    -
    - Note: If a provided constraint is either -1000 or 1000, then the function
    - will update the reaction lower and upper bound to either allow uptake or
    - excretion, irrespective of what option is given as the looseStrictFlux
    - parameter.
    -
    - Usage:
    -   model = constrainFluxData(model, fluxData, condition, maxMinGrowth, looseStrictFlux, modelAdapter)
    - - -

    CROSS-REFERENCE INFORMATION ^

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

    SOURCE CODE ^

    -
    0001 function model = constrainFluxData(model, fluxData, condition, maxMinGrowth, looseStrictFlux, modelAdapter)
    -0002 % constrainFluxData
    -0003 %   Constrains fluxes to the data that is provided in the fluxData
    -0004 %   structure, which itself is read by loadFluxData from data/fluxData.tsv.
    -0005 %
    -0006 % Input:
    -0007 %   model           an ecModel in GECKO 3 format (with ecModel.ec structure)
    -0008 %   fluxData        structure with flux data
    -0009 %                   conds       sampling condition
    -0010 %                   Ptot        total protein (g/gDCW)
    -0011 %                   grRate      growth rate (1/h)
    -0012 %                   exchFluxes  exchange fluxes (mmol/gDCWh)
    -0013 %                   exchMets    exchanged metabolites, matching exchFluxes
    -0014 %                   exchRxnIDs  exchange reaction IDs, matching exchMets
    -0015 %   condition       either index number or name of the sample condition in
    -0016 %                   fluxData.conds (Optional, default = 1)
    -0017 %   maxMinGrowth    'max' if the provided growth rate should be set as
    -0018 %                   maximum growth rate (= upper bound), or 'min' if it
    -0019 %                   should be set as minimum growth rate (= lower bound).
    -0020 %                   The latter option is suitable if minimization of
    -0021 %                   prot_pool_exchange is used as objective function. (Opt,
    -0022 %                   default = 'max')
    -0023 %   looseStrictFlux how strictly constrained the exchange fluxes should be,
    -0024 %                   optional, default = 'loose'
    -0025 %                   'loose' if the exchange fluxes should be constraint
    -0026 %                           only by the "outer bounds". If exchFluxes(i)
    -0027 %                           > 0, LB = 0 and UB = exchFluxes(i). If
    -0028 %                           exchFluxes(i) < 0, LB = exchFluxes(i) and
    -0029 %                           UB = 0
    -0030 %                   0-100   LB and UB constraints are set with a specified
    -0031 %                           percentage of variance around exchFluxes. If 10
    -0032 %                           is specified, LB = exchFluxes*0.95 and UB =
    -0033 %                           exchFluxes*1.05. This allows for 10% variance
    -0034 %                           around the exchFluxes values, but strictly
    -0035 %                           forces a flux through the exchRxns.
    -0036 %   modelAdapter    a loaded model adapter (Optional, will otherwise use
    -0037 %                   the default model adapter)
    -0038 %
    -0039 % Output:
    -0040 %   model           an ecModel where fluxes are constraint
    -0041 %
    -0042 % Note: If a provided constraint is either -1000 or 1000, then the function
    -0043 % will update the reaction lower and upper bound to either allow uptake or
    -0044 % excretion, irrespective of what option is given as the looseStrictFlux
    -0045 % parameter.
    -0046 %
    -0047 % Usage:
    -0048 %   model = constrainFluxData(model, fluxData, condition, maxMinGrowth, looseStrictFlux, modelAdapter)
    -0049 
    -0050 if nargin < 6 || isempty(modelAdapter)
    -0051     modelAdapter = ModelAdapterManager.getDefault();
    -0052     if isempty(modelAdapter)
    -0053         error('Either send in a modelAdapter or set the default model adapter in the ModelAdapterManager.')
    -0054     end
    -0055 end
    -0056 params = modelAdapter.getParameters();
    -0057 
    -0058 if nargin < 5 || isempty(looseStrictFlux)
    -0059     looseStrictFlux = 'loose';
    -0060 end
    -0061 
    -0062 if nargin < 4 || isempty(maxMinGrowth)
    -0063     maxMinGrowth = 'max';
    -0064 end
    -0065 
    -0066 if nargin < 2 || isempty(fluxData)
    -0067     fluxData = loadFluxData(fullfile(params.path,'data','fluxData.tsv'),modelAdapter);
    -0068 end
    -0069 
    -0070 if nargin < 3 || isempty(condition)
    -0071     condition = 1;
    -0072 elseif ~isnumeric(condition)
    -0073     idx = find(strcmp(fluxData.conds,condition));
    -0074     if isempty(condition)
    -0075         error(['Condition ' condition ' cannot be found in fluxData'])
    -0076     else
    -0077         condition = idx;
    -0078     end
    -0079 end
    -0080 
    -0081 % Select the exchange fluxes of specified condition
    -0082 fluxData.exchFluxes = fluxData.exchFluxes(condition,:);
    -0083 
    -0084 %Set original c-source to zero
    -0085 model = setParam(model,'eq',params.c_source,0);
    -0086 %Set growth
    -0087 switch maxMinGrowth
    -0088     case 'max'
    -0089         model = setParam(model,'lb',params.bioRxn,0);
    -0090         model = setParam(model,'ub',params.bioRxn,fluxData.grRate(condition));
    -0091     case 'min'
    -0092         model = setParam(model,'lb',params.bioRxn,fluxData.grRate(condition));
    -0093         model = setParam(model,'ub',params.bioRxn,1000);
    -0094 end
    -0095 
    -0096 naFlux = isnan(fluxData.exchFluxes);
    -0097 negFlux = lt(fluxData.exchFluxes,0); % less than 0
    -0098 ub = fluxData.exchFluxes(~(negFlux | naFlux));
    -0099 posFlux = fluxData.exchRxnIDs(~(negFlux | naFlux));
    -0100 lb = fluxData.exchFluxes(negFlux & ~naFlux);
    -0101 negFlux = fluxData.exchRxnIDs(negFlux & ~naFlux);
    -0102 
    -0103 switch looseStrictFlux
    -0104     case 'loose'
    -0105         model = setParam(model,'lb',negFlux,lb);
    -0106         model = setParam(model,'ub',negFlux,0);
    -0107         model = setParam(model,'lb',posFlux,0);
    -0108         model = setParam(model,'ub',posFlux,ub);
    -0109     otherwise
    -0110         model = setParam(model,'var',fluxData.exchRxnIDs,fluxData.exchFluxes,looseStrictFlux);
    -0111 end
    -0112 extremeFlux = find(abs(fluxData.exchFluxes)==1000);
    -0113 if any(extremeFlux)
    -0114     exchFlux = fluxData.exchFluxes(extremeFlux);
    -0115     if any(exchFlux==-1000)
    -0116         model = setParam(model,'lb',fluxData.exchRxnIDs(extremeFlux(exchFlux==-1000)),-1000);
    -0117         model = setParam(model,'ub',fluxData.exchRxnIDs(extremeFlux(exchFlux==-1000)),0);
    -0118     end
    -0119     if any(exchFlux==1000)
    -0120         model = setParam(model,'lb',fluxData.exchRxnIDs(extremeFlux(exchFlux==1000)),0);
    -0121         model = setParam(model,'ub',fluxData.exchRxnIDs(extremeFlux(exchFlux==1000)),1000);
    -0122     end
    -0123 end
    -0124 end
    -
    Generated by m2html © 2005
    - - \ No newline at end of file diff --git a/doc/src/geckomat/limit_proteins/fillEnzConcs.html b/doc/src/geckomat/limit_proteins/fillEnzConcs.html deleted file mode 100644 index f78b07f3..00000000 --- a/doc/src/geckomat/limit_proteins/fillEnzConcs.html +++ /dev/null @@ -1,115 +0,0 @@ - - - - Description of fillEnzConcs - - - - - - - - - -
    Home > src > geckomat > limit_proteins > fillEnzConcs.m
    - - - -

    fillEnzConcs -

    - -

    PURPOSE ^

    -
    fillEnzConcs
    - -

    SYNOPSIS ^

    -
    function model = fillEnzConcs(model, protData, dataCol)
    - -

    DESCRIPTION ^

    -
     fillEnzConcs
    -   Uses the protein concentrations from protData to fill model.ec.concs.
    -   Protein levels should be provided in mg/gDCW. If no data is provided
    -   a particular protein, its level is NaN. Existing entries in
    -   model.ec.concs are overwritten.
    -
    - Input:
    -   model       an ecModel in GECKO 3 format (with ecModel.ec structure)
    -   protData    structure with proteome data, from loadProtFluxData
    -               uniprotIDs      cell arrray with Uniprot IDs matching
    -                               protData.abundances
    -               abundances      matrix of proteomics data
    -   dataCol     number indicating the column in protData.abundances that
    -               contains the relevant protein concentrations (protData may
    -               contain data from multiple conditions/samples/experiments,
    -               each with their own column in protData.abundances.
    -               Optional, default = 1.
    -
    - Output:
    -   model       an ecModel where model.ec.concs is populated with protein
    -               concentrations.
    -
    - Note: to also constrain the model with the content of model.ec.concs, you
    - should run constrainEnzConcs.
    -
    - Usage:
    -   model = fillEnzConcs(model, protData)
    - - -

    CROSS-REFERENCE INFORMATION ^

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

    SOURCE CODE ^

    -
    0001 function model = fillEnzConcs(model, protData, dataCol)
    -0002 % fillEnzConcs
    -0003 %   Uses the protein concentrations from protData to fill model.ec.concs.
    -0004 %   Protein levels should be provided in mg/gDCW. If no data is provided
    -0005 %   a particular protein, its level is NaN. Existing entries in
    -0006 %   model.ec.concs are overwritten.
    -0007 %
    -0008 % Input:
    -0009 %   model       an ecModel in GECKO 3 format (with ecModel.ec structure)
    -0010 %   protData    structure with proteome data, from loadProtFluxData
    -0011 %               uniprotIDs      cell arrray with Uniprot IDs matching
    -0012 %                               protData.abundances
    -0013 %               abundances      matrix of proteomics data
    -0014 %   dataCol     number indicating the column in protData.abundances that
    -0015 %               contains the relevant protein concentrations (protData may
    -0016 %               contain data from multiple conditions/samples/experiments,
    -0017 %               each with their own column in protData.abundances.
    -0018 %               Optional, default = 1.
    -0019 %
    -0020 % Output:
    -0021 %   model       an ecModel where model.ec.concs is populated with protein
    -0022 %               concentrations.
    -0023 %
    -0024 % Note: to also constrain the model with the content of model.ec.concs, you
    -0025 % should run constrainEnzConcs.
    -0026 %
    -0027 % Usage:
    -0028 %   model = fillEnzConcs(model, protData)
    -0029 
    -0030 if nargin < 3 || isempty(dataCol)
    -0031     dataCol = 1;
    -0032 end
    -0033 
    -0034 uniprotIDs = protData.uniprotIDs;
    -0035 abundances = protData.abundances(:,dataCol);
    -0036 
    -0037 %Redefine an empty model.ec.concs vector
    -0038 model.ec.concs=nan(numel(model.ec.enzymes),1);
    -0039 
    -0040 [a,b] = ismember(uniprotIDs, model.ec.enzymes);
    -0041 model.ec.concs(b(a)) = abundances(a);
    -0042 end
    -
    Generated by m2html © 2005
    - - \ No newline at end of file diff --git a/doc/src/geckomat/limit_proteins/flexibilizeEnzConcs.html b/doc/src/geckomat/limit_proteins/flexibilizeEnzConcs.html deleted file mode 100644 index f63a0379..00000000 --- a/doc/src/geckomat/limit_proteins/flexibilizeEnzConcs.html +++ /dev/null @@ -1,335 +0,0 @@ - - - - Description of flexibilizeEnzConcs - - - - - - - - - -
    Home > src > geckomat > limit_proteins > flexibilizeEnzConcs.m
    - - - -

    flexibilizeEnzConcs -

    - -

    PURPOSE ^

    -
    flexibilizeEnzConcs
    - -

    SYNOPSIS ^

    -
    function [model, flexEnz] = flexibilizeEnzConcs(model, expGrowth, foldChange, iterPerEnzyme, modelAdapter, verbose)
    - -

    DESCRIPTION ^

    -
     flexibilizeEnzConcs
    -   Flexibilize enzyme concentration of an ecModel with constrained with
    -   proteomics data. The upper bound of the protein usage reaction is
    -   changed, while the concentrations in ecModel.ec.concs remain unchanged.
    -
    -   If no (more) limiting enzyme concentrations can be found, it might be
    -   the protein pool exchange that is limiting growth. In that case, an
    -   attempt will be made to relax the protein pool exchange reaction, and
    -   if the growth rate indeed increases, it is suggested to set the protein
    -   pool exchange unconstrained (lb=-1000) before again running
    -   flexibilizeEnzConcs. Such situations, where a proteomics integrated
    -   ecModel is overconstrained, may occur if the ecModel should be able to
    -   simulate maximum growth rate (from e.g. batch cultivation). 
    -   
    -   If relaxing the protein pool exchange does not increase the growth
    -   rate, then this is not due to enzyme constraints, but rather an issue
    -   with the metabolic network itself, or the set nutrient exchange is not
    -   sufficient.
    -
    - Input:
    -   model           an ecModel in GECKO 3 format (with ecModel.ec structure)
    -   expGrowth       estimated experimental growth rate. If not specified,
    -                   the value will be read from the model adapter
    -   foldChange      a value how much increase the enzyme concentration
    -                   (Optional, default = 2)
    -   iterPerEnzyme   the number of iterations that an enzyme can be increased.
    -                   A zero number can be defined. if zero is defined no limit
    -                   will be set, and it will increase the enzyme concentration
    -                   until reach de defined growth rate (Optional, default = 5)
    -   modelAdapter    a loaded model adapter (Optional, will otherwise use the
    -                   default model adapter)
    -   verbose         logical whether progress should be reported (Optional,
    -                   default true)
    -
    - Output:
    -   model           ecModel where the constraint of measured enzyme
    -                   concentrations have been flexibilized (=relaxed) in the
    -                   S-matrix, to allow the model to reach the growth rate
    -                   defined in expGrowth, while the values in
    -                   ecModel.ec.concs have remained untouched.
    -   flexEnz         array with information about flexibilized proteins
    -                   uniprotIDs  enzymes whose usage UB was flexibilized
    -                   oldConcs    original concentrations, from mode.ec.concs
    -                   flexConcs   flexibilized concentrations, new UB in
    -                               model
    -                   ratioIncr   ratio by which the concentration increased,
    -                               the enzymes will be sorted by this field
    -                   frequence   numeric how often the enzyme has been
    -                               step-wise flexibilized
    -
    - Usage:
    -   [model, flexEnz] = flexibilizeEnzConcs(model, expGrowth, foldChange, iterPerEnzyme, modelAdapter, verbose)
    - - -

    CROSS-REFERENCE INFORMATION ^

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

    SOURCE CODE ^

    -
    0001 function [model, flexEnz] = flexibilizeEnzConcs(model, expGrowth, foldChange, iterPerEnzyme, modelAdapter, verbose)
    -0002 % flexibilizeEnzConcs
    -0003 %   Flexibilize enzyme concentration of an ecModel with constrained with
    -0004 %   proteomics data. The upper bound of the protein usage reaction is
    -0005 %   changed, while the concentrations in ecModel.ec.concs remain unchanged.
    -0006 %
    -0007 %   If no (more) limiting enzyme concentrations can be found, it might be
    -0008 %   the protein pool exchange that is limiting growth. In that case, an
    -0009 %   attempt will be made to relax the protein pool exchange reaction, and
    -0010 %   if the growth rate indeed increases, it is suggested to set the protein
    -0011 %   pool exchange unconstrained (lb=-1000) before again running
    -0012 %   flexibilizeEnzConcs. Such situations, where a proteomics integrated
    -0013 %   ecModel is overconstrained, may occur if the ecModel should be able to
    -0014 %   simulate maximum growth rate (from e.g. batch cultivation).
    -0015 %
    -0016 %   If relaxing the protein pool exchange does not increase the growth
    -0017 %   rate, then this is not due to enzyme constraints, but rather an issue
    -0018 %   with the metabolic network itself, or the set nutrient exchange is not
    -0019 %   sufficient.
    -0020 %
    -0021 % Input:
    -0022 %   model           an ecModel in GECKO 3 format (with ecModel.ec structure)
    -0023 %   expGrowth       estimated experimental growth rate. If not specified,
    -0024 %                   the value will be read from the model adapter
    -0025 %   foldChange      a value how much increase the enzyme concentration
    -0026 %                   (Optional, default = 2)
    -0027 %   iterPerEnzyme   the number of iterations that an enzyme can be increased.
    -0028 %                   A zero number can be defined. if zero is defined no limit
    -0029 %                   will be set, and it will increase the enzyme concentration
    -0030 %                   until reach de defined growth rate (Optional, default = 5)
    -0031 %   modelAdapter    a loaded model adapter (Optional, will otherwise use the
    -0032 %                   default model adapter)
    -0033 %   verbose         logical whether progress should be reported (Optional,
    -0034 %                   default true)
    -0035 %
    -0036 % Output:
    -0037 %   model           ecModel where the constraint of measured enzyme
    -0038 %                   concentrations have been flexibilized (=relaxed) in the
    -0039 %                   S-matrix, to allow the model to reach the growth rate
    -0040 %                   defined in expGrowth, while the values in
    -0041 %                   ecModel.ec.concs have remained untouched.
    -0042 %   flexEnz         array with information about flexibilized proteins
    -0043 %                   uniprotIDs  enzymes whose usage UB was flexibilized
    -0044 %                   oldConcs    original concentrations, from mode.ec.concs
    -0045 %                   flexConcs   flexibilized concentrations, new UB in
    -0046 %                               model
    -0047 %                   ratioIncr   ratio by which the concentration increased,
    -0048 %                               the enzymes will be sorted by this field
    -0049 %                   frequence   numeric how often the enzyme has been
    -0050 %                               step-wise flexibilized
    -0051 %
    -0052 % Usage:
    -0053 %   [model, flexEnz] = flexibilizeEnzConcs(model, expGrowth, foldChange, iterPerEnzyme, modelAdapter, verbose)
    -0054 
    -0055 if nargin < 6 || isempty(verbose)
    -0056     verbose = true;
    -0057 end
    -0058 if nargin < 5 || isempty(modelAdapter)
    -0059     modelAdapter = ModelAdapterManager.getDefault();
    -0060     if isempty(modelAdapter)
    -0061         error('Either send in a modelAdapter or set the default model adapter in the ModelAdapterManager.')
    -0062     end
    -0063 end
    -0064 params = modelAdapter.getParameters();
    -0065 
    -0066 if nargin < 4 || isempty(iterPerEnzyme)
    -0067     iterPerEnzyme = 5;
    -0068 end
    -0069 
    -0070 if nargin < 3 || isempty(foldChange)
    -0071     foldChange = 2;
    -0072 end
    -0073 
    -0074 if nargin < 2 || isempty(expGrowth)
    -0075     expGrowth = modelAdapter.getParameters().gR_exp;
    -0076 end
    -0077 
    -0078 % If a zero value is defined, not iteration limit will be set
    -0079 if iterPerEnzyme == 0
    -0080     iterPerEnzyme = inf;
    -0081 end
    -0082 
    -0083 bioRxnIdx = getIndexes(model,params.bioRxn,'rxns');
    -0084 if model.ub(bioRxnIdx) < expGrowth
    -0085     fprintf(['The upper bound of the biomass reaction was %s, while expGrowth '...
    -0086              'is %s. The upper bound has been set to expGrowth.'],...
    -0087              num2str(model.ub(bioRxnIdx)), num2str(expGrowth))
    -0088     model.ub(bioRxnIdx) = expGrowth;
    -0089 end
    -0090 
    -0091 % Keep track if protein pool will be flexibilized
    -0092 changedProtPool = false;
    -0093 
    -0094 % In case the model have not been protein constrained
    -0095 % model = constrainEnzConcs(model);
    -0096 
    -0097 [sol,hs] = solveLP(model);
    -0098 predGrowth = sol.f;
    -0099 
    -0100 % Get those proteins with a concentration defined
    -0101 protConcs = find(~isnan(model.ec.concs));
    -0102 
    -0103 % Get enzymes names with a concentration value
    -0104 proteins = model.ec.enzymes(protConcs);
    -0105 
    -0106 % Store how many time is predicted a enzyme with the highest coeff
    -0107 frequence = zeros(numel(proteins),1);
    -0108 
    -0109 flexBreak=false;
    -0110 if any(protConcs)
    -0111     while predGrowth < expGrowth
    -0112 
    -0113         % Get the control coefficients
    -0114         [~, controlCoeffs] = getConcControlCoeffs(model, proteins, foldChange, 0.75);
    -0115 
    -0116         % Stop looking for limiting proteins all coeffs are zero
    -0117         if any(controlCoeffs)
    -0118 
    -0119             % Find the maximum coefficient index
    -0120             [~,maxIdx] = max(controlCoeffs);
    -0121 
    -0122             % Increase +1 the frequence
    -0123             frequence(maxIdx) = frequence(maxIdx) + 1;
    -0124 
    -0125             % Allow to increase the UB maximum five times
    -0126             if frequence(maxIdx) <= iterPerEnzyme
    -0127 
    -0128                 % Set how much will increase the UB
    -0129                 increase = foldChange*frequence(maxIdx);
    -0130 
    -0131                 % Get usage rxn for the highest coeff
    -0132                 protUsageIdx = strcmpi(model.rxns, strcat('usage_prot_', proteins(maxIdx)));
    -0133 
    -0134                 % replace the UB
    -0135                 model.lb(protUsageIdx) = -(model.ec.concs(protConcs(maxIdx)) * (1+increase));
    -0136 
    -0137                 % Get the new growth rate
    -0138                 sol = solveLP(model,0,[],hs);
    -0139                 predGrowth = sol.f;
    -0140 
    -0141                 if verbose
    -0142                     disp(['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']);
    -0146                 flexBreak=true;
    -0147                 break
    -0148             end
    -0149         else
    -0150             disp('No (more) limiting enzymes have been found. Attempting to increase protein pool exchange...')
    -0151             protPoolIdx = getIndexes(model,'prot_pool_exchange','rxns');
    -0152             oldProtPool = -model.lb(protPoolIdx);
    -0153             tempModel = setParam(model,'lb',protPoolIdx,-1000);
    -0154             tempModel = setParam(tempModel,'ub',bioRxnIdx,expGrowth);
    -0155             sol = solveLP(tempModel);
    -0156             if (sol.f-predGrowth)>1e-10 % There is improvement in growth rate
    -0157                 % Find new protein pool constraint
    -0158                 predGrowth = sol.f;
    -0159                 tempModel = setParam(tempModel,'lb',bioRxnIdx,predGrowth);
    -0160                 tempModel = setParam(tempModel,'obj',protPoolIdx,1);
    -0161                 sol = solveLP(tempModel);
    -0162                 newProtPool = sol.f;
    -0163                 model.lb(protPoolIdx) = -newProtPool;
    -0164                 fprintf(['Changing the lower bound of protein pool exchange from %s ',...
    -0165                          'to %s enabled a\ngrowth rate of %s. It can be helpful to set ', ...
    -0166                          'the lower bound of protein\npool exchange to -1000 before ',...
    -0167                          'running flexibilizeEnzConcs.\n'],num2str(-oldProtPool), ...
    -0168                          num2str(-newProtPool),num2str(predGrowth));
    -0169                 changedProtPool = true;
    -0170             else
    -0171                 fprintf(['Protein pool exchange was also not limiting. Inability to reach growth ',...
    -0172                         'rate is not related to\nenzyme constraints. Maximum growth rate ',...
    -0173                         'is %s.\n'], num2str(predGrowth))
    -0174             end
    -0175             % To return an usable model with these conditions, set the
    -0176             % highest growth rate reached as the experimental value
    -0177             expGrowth = predGrowth;
    -0178             break
    -0179         end
    -0180     end
    -0181 else
    -0182     error('Protein concentrations have not been defined. Please run readProteomics and constrainEnzConcs')
    -0183 end
    -0184 
    -0185 protFlex         = proteins(frequence>0);
    -0186 [~,protUsageIdx] = ismember(strcat('usage_prot_', protFlex), model.rxns);
    -0187 [~,ecProtId]     = ismember(protFlex, model.ec.enzymes);
    -0188 oldConcs         = model.ec.concs(ecProtId);
    -0189 %frequence        = frequence(ecProtId);
    -0190 
    -0191 if flexBreak == false && ~isempty(protFlex)
    -0192     % Not all flexibilized proteins require flexibilization in the end
    -0193     % Test flux distribution with minimum prot_pool usage
    -0194     modelTemp       = setParam(model,'var',params.bioRxn,expGrowth,0.5);
    -0195     modelTemp       = setParam(modelTemp,'obj','prot_pool_exchange',1);
    -0196     sol             = solveLP(modelTemp,1);
    -0197     % Check which concentrations can remain unchanged
    -0198     newConcs        = abs(sol.x(protUsageIdx));
    -0199     keepOld         = newConcs<oldConcs;
    -0200     % Set UBs
    -0201     model.lb(protUsageIdx(keepOld))  = -oldConcs(keepOld);
    -0202     model.lb(protUsageIdx(~keepOld)) = -newConcs(~keepOld);
    -0203     % Output structure
    -0204     protFlex(keepOld) = [];
    -0205     oldConcs(keepOld) = [];
    -0206     newConcs(keepOld) = [];
    -0207     frequence=frequence(frequence>0);
    -0208     frequence(keepOld) = [];
    -0209     
    -0210     flexEnz.uniprotIDs = protFlex;
    -0211     flexEnz.oldConcs   = oldConcs;
    -0212     flexEnz.flexConcs  = newConcs;
    -0213     flexEnz.frequence  = frequence(frequence>0);
    -0214 else
    -0215     protFlex           = proteins(frequence>0);
    -0216     [~, protUsageIdx]  = ismember(strcat('usage_prot_', protFlex), model.rxns);
    -0217 
    -0218     flexEnz.uniprotIDs = protFlex;
    -0219     flexEnz.oldConcs   = model.ec.concs(ecProtId);
    -0220     flexEnz.flexConcs  = abs(model.lb(protUsageIdx));
    -0221     flexEnz.frequence  = frequence(frequence>0);
    -0222 end
    -0223 if changedProtPool
    -0224     flexEnz.uniprotIDs(end+1) = {'prot_pool'};
    -0225     flexEnz.oldConcs(end+1)   = oldProtPool;
    -0226     flexEnz.flexConcs(end+1)  = newProtPool;
    -0227     flexEnz.frequence(end+1)  = 1;
    -0228 end
    -0229 % Sort by biggest ratio increase
    -0230 flexEnz.ratioIncr  = flexEnz.flexConcs./flexEnz.oldConcs;
    -0231 [~,b] = sort(flexEnz.ratioIncr,'descend');
    -0232 flexEnz.ratioIncr  = flexEnz.ratioIncr(b);
    -0233 flexEnz.uniprotIDs = flexEnz.uniprotIDs(b);
    -0234 flexEnz.oldConcs   = flexEnz.oldConcs(b);
    -0235 flexEnz.flexConcs  = flexEnz.flexConcs(b);
    -0236 flexEnz.frequence  = flexEnz.frequence(b);
    -0237 end
    -
    Generated by m2html © 2005
    - - \ No newline at end of file diff --git a/doc/src/geckomat/limit_proteins/getConcControlCoeffs.html b/doc/src/geckomat/limit_proteins/getConcControlCoeffs.html deleted file mode 100644 index 85739751..00000000 --- a/doc/src/geckomat/limit_proteins/getConcControlCoeffs.html +++ /dev/null @@ -1,141 +0,0 @@ - - - - Description of getConcControlCoeffs - - - - - - - - - -
    Home > src > geckomat > limit_proteins > getConcControlCoeffs.m
    - - - -

    getConcControlCoeffs -

    - -

    PURPOSE ^

    -
    getConcControlCoeffs
    - -

    SYNOPSIS ^

    -
    function [enz, controlCoeffs] = getConcControlCoeffs(model, proteins, foldChange, limit)
    - -

    DESCRIPTION ^

    -
     getConcControlCoeffs
    -   Calculate an control coefficients of protein usage.
    -
    - Input:
    -   model           an ecModel in GECKO 3 format (with ecModel.ec structure)
    -   proteins        a list of proteins to calculate the coefficients. (Optional,
    -                   default = model.ec.enzymes)
    -   foldChange      a value how much increase the protein concentration.
    -                   (Optional, default = 2)
    -   limit           a value to determine limiting protein usage reactions.
    -                   Calculate as usage/concentration (Optional, default = 0)
    -
    - Output:
    -   enz             a logical vector of enzymes analyzed
    -   controlCoeffs   a vector array with the coefficients
    -
    - Usage:
    -    [enz, controlCoeffs] = getConcControlCoeffs(model, proteins, foldChange, limit);
    - - -

    CROSS-REFERENCE INFORMATION ^

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

    SOURCE CODE ^

    -
    0001 function [enz, controlCoeffs] = getConcControlCoeffs(model, proteins, foldChange, limit)
    -0002 % getConcControlCoeffs
    -0003 %   Calculate an control coefficients of protein usage.
    -0004 %
    -0005 % Input:
    -0006 %   model           an ecModel in GECKO 3 format (with ecModel.ec structure)
    -0007 %   proteins        a list of proteins to calculate the coefficients. (Optional,
    -0008 %                   default = model.ec.enzymes)
    -0009 %   foldChange      a value how much increase the protein concentration.
    -0010 %                   (Optional, default = 2)
    -0011 %   limit           a value to determine limiting protein usage reactions.
    -0012 %                   Calculate as usage/concentration (Optional, default = 0)
    -0013 %
    -0014 % Output:
    -0015 %   enz             a logical vector of enzymes analyzed
    -0016 %   controlCoeffs   a vector array with the coefficients
    -0017 %
    -0018 % Usage:
    -0019 %    [enz, controlCoeffs] = getConcControlCoeffs(model, proteins, foldChange, limit);
    -0020 
    -0021 if nargin < 4 || isempty(limit)
    -0022     limit = 0;
    -0023 end
    -0024 
    -0025 if nargin < 3 || isempty(foldChange)
    -0026     foldChange = 2;
    -0027 end
    -0028 
    -0029 if nargin < 2 || isempty(proteins)
    -0030     proteins = model.ec.enzymes;
    -0031 end
    -0032 
    -0033 % for now
    -0034 enz = false(length(proteins),1);
    -0035 controlCoeffs = zeros(length(proteins),1);
    -0036 
    -0037 [sol,hs] = solveLP(model);
    -0038 initialGrowth = sol.f;
    -0039 
    -0040 % Get enzyme index
    -0041 [~, protIdx] = ismember(proteins, model.ec.enzymes);
    -0042 
    -0043 % Get the protein usage reactions
    -0044 protUsageRxns = strcat('usage_prot_', model.ec.enzymes(protIdx));
    -0045 [~, protUsageRxnIdx] = ismember(protUsageRxns, model.rxns);
    -0046 
    -0047 for i = 1:numel(proteins)
    -0048     % Get the previous concentration
    -0049     prevConc = model.lb(protUsageRxnIdx(i));
    -0050 
    -0051     % Only consider those with a usage close the UB
    -0052     if (sol.x(protUsageRxnIdx(i))/prevConc) > limit
    -0053         
    -0054         % Update the logical vector
    -0055         enz(i) = 1;
    -0056 
    -0057         % Create a temporal model since coeff will be calculated one enzyme at
    -0058         % the time, without other change
    -0059         tempModel = model;
    -0060         % Increase the concentration by flexfactor
    -0061         newConc = prevConc*(foldChange);
    -0062         tempModel.lb(protUsageRxnIdx(i)) = newConc;
    -0063 
    -0064         % Get the new growth rate after the adjustment
    -0065         [tempSol,hs] = solveLP(tempModel,0,[],hs);
    -0066         tempGrowth = tempSol.f;
    -0067         
    -0068         % Calculate the coeff only if new growth rate is significantly
    -0069         % higher than initial value
    -0070         if (tempGrowth-initialGrowth)>1e-10
    -0071             controlCoeffs(i) = (tempGrowth-initialGrowth)/(prevConc-newConc);
    -0072         end
    -0073     end
    -0074 
    -0075 end
    -0076 end
    -0077
    -
    Generated by m2html © 2005
    - - \ No newline at end of file diff --git a/doc/src/geckomat/limit_proteins/index.html b/doc/src/geckomat/limit_proteins/index.html deleted file mode 100644 index 42f693ff..00000000 --- a/doc/src/geckomat/limit_proteins/index.html +++ /dev/null @@ -1,29 +0,0 @@ - - - - Index for Directory src\geckomat\limit_proteins - - - - - - - - - - -
    < Master indexIndex for src\geckomat\limit_proteins >
    - -

    Index for src\geckomat\limit_proteins

    - -

    Matlab files in this directory:

    - -
     calculateFfactorcalculateFfactor
     constrainEnzConcsconstrainEnzConcs
     constrainFluxDataconstrainFluxData
     fillEnzConcsfillEnzConcs
     flexibilizeEnzConcsflexibilizeEnzConcs
     getConcControlCoeffsgetConcControlCoeffs
     updateProtPoolupdateProtPool
    - - - - -
    Generated by m2html © 2005
    - - \ No newline at end of file diff --git a/doc/src/geckomat/limit_proteins/updateProtPool.html b/doc/src/geckomat/limit_proteins/updateProtPool.html deleted file mode 100644 index e757f1f7..00000000 --- a/doc/src/geckomat/limit_proteins/updateProtPool.html +++ /dev/null @@ -1,151 +0,0 @@ - - - - Description of updateProtPool - - - - - - - - - -
    Home > src > geckomat > limit_proteins > updateProtPool.m
    - - - -

    updateProtPool -

    - -

    PURPOSE ^

    -
    updateProtPool
    - -

    SYNOPSIS ^

    -
    function ecModel = updateProtPool(ecModel, Ptot, modelAdapter)
    - -

    DESCRIPTION ^

    -
     updateProtPool
    -   Obsolete since GECKO 3.2.0, as all (measured and unmeasured) enzymes
    -   are drawn from the protein pool. Instead, use setProtPoolSize. See
    -   https://github.com/SysBioChalmers/GECKO/issues/375 for explanation.
    -
    -   Before GECKO 3.2.0: updates the protein pool to compensate for measured
    -   proteomics data (in model.ec.concs), as only the unmeasured enzymes
    -   draw from the protein pool.
    -
    - Input:
    -   ecModel         an ecModel in GECKO 3 format (with ecModel.ec structure)
    -   Ptot            total protein content in g/gDCW, overwrites the value
    -                   from modelAdapter. For instance, condition-specific
    -                   fluxData.Ptot from loadFluxData can be used. If nothing
    -                   is provided, the modelAdapter value is used.
    -   modelAdapter    a loaded model adapter (Optional, will otherwise use the
    -                   default model adapter).
    -
    - Output:
    -   model           an ecModel where model.ec.concs is populated with
    -                   protein concentrations
    - Usage:
    -   ecModel  = updateProtPool(ecModel, Ptot, modelAdapter)
    - - -

    CROSS-REFERENCE INFORMATION ^

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

    SOURCE CODE ^

    -
    0001 function ecModel  = updateProtPool(ecModel, Ptot, modelAdapter)
    -0002 % updateProtPool
    -0003 %   Obsolete since GECKO 3.2.0, as all (measured and unmeasured) enzymes
    -0004 %   are drawn from the protein pool. Instead, use setProtPoolSize. See
    -0005 %   https://github.com/SysBioChalmers/GECKO/issues/375 for explanation.
    -0006 %
    -0007 %   Before GECKO 3.2.0: updates the protein pool to compensate for measured
    -0008 %   proteomics data (in model.ec.concs), as only the unmeasured enzymes
    -0009 %   draw from the protein pool.
    -0010 %
    -0011 % Input:
    -0012 %   ecModel         an ecModel in GECKO 3 format (with ecModel.ec structure)
    -0013 %   Ptot            total protein content in g/gDCW, overwrites the value
    -0014 %                   from modelAdapter. For instance, condition-specific
    -0015 %                   fluxData.Ptot from loadFluxData can be used. If nothing
    -0016 %                   is provided, the modelAdapter value is used.
    -0017 %   modelAdapter    a loaded model adapter (Optional, will otherwise use the
    -0018 %                   default model adapter).
    -0019 %
    -0020 % Output:
    -0021 %   model           an ecModel where model.ec.concs is populated with
    -0022 %                   protein concentrations
    -0023 % Usage:
    -0024 %   ecModel  = updateProtPool(ecModel, Ptot, modelAdapter)
    -0025 
    -0026 % Do not run from GECKO version 3.2.0 onwards. This can be recognized by
    -0027 % prot_usage reactions that are constrained by proteomics and still draw
    -0028 % from the protein pool
    -0029 protRxns = find(startsWith(ecModel.rxns,'usage_prot_'));
    -0030 poolMetIdx = find(strcmp(ecModel.mets,'prot_pool'));
    -0031 % Selected proteins with proteomics constraints
    -0032 constProtRxns = ~(ecModel.lb(protRxns)==-1000);
    -0033 % Are any still drawing from prot_pool? This is introduced in GECKO 3.2.0.
    -0034 if any(full(ecModel.S(poolMetIdx,protRxns(constProtRxns))))
    -0035     error(['In the provided ecModel, all protein usage reactions, both with ' ...
    -0036         'and without concentration constraints, draw from the protein pool. ' ...
    -0037         'This was introduced with GECKO 3.2.0. Since then, updateProtPool ' ...
    -0038         'has become obsolete, use setProtPoolSize instead to constrain the ' ...
    -0039         'total protein pool with  condition-specific total protein content. See '...
    -0040         '<a href="https://github.com/SysBioChalmers/GECKO/issues/375">here</a> ' ...
    -0041         'for more explanation.'])
    -0042 end
    -0043 
    -0044 if nargin < 3 || isempty(modelAdapter)
    -0045     modelAdapter = ModelAdapterManager.getDefault();
    -0046     if isempty(modelAdapter)
    -0047         error('Either send in a modelAdapter or set the default model adapter in the ModelAdapterManager.')
    -0048     end
    -0049 end
    -0050 params = modelAdapter.params;
    -0051 
    -0052 if nargin < 2 || isempty(Ptot)
    -0053     Ptot = params.Ptot;
    -0054     disp(['Total protein content used: ' num2str(Ptot) ' [g protein/gDw]'])
    -0055 end
    -0056 
    -0057 % Convert Ptot to mg/gDW if provided in g/gDCW (which is default)
    -0058 if Ptot < 1
    -0059     Ptot = Ptot * 1000;
    -0060 end
    -0061 
    -0062 Pmeas = sum(ecModel.ec.concs,'omitnan');
    -0063 if Pmeas == 0
    -0064     error('The model has not yet been populated with proteomics, as ecModel.ec.concs is empty.')
    -0065 end
    -0066 
    -0067 Pnew = (Ptot - Pmeas) * params.f;
    -0068 
    -0069 if Pnew > 0
    -0070     PoolRxnIdx = strcmp(ecModel.rxns,'prot_pool_exchange');
    -0071     ecModel.lb(PoolRxnIdx) = -Pnew*params.sigma;
    -0072     sol = solveLP(ecModel);
    -0073     if isempty(sol.x)
    -0074         error(['Estimating the remaining protein pool by subtracting the ' ...
    -0075                'sum of measured enzyme concentrations (in ecModel.ec.concs) ' ...
    -0076                'from the total protein pool (Ptot) does not yield a functional ' ...
    -0077                'model.'])
    -0078     end
    -0079 else
    -0080     error('The total measured protein mass exceeds the total protein content.')
    -0081 end
    -0082 end
    -
    Generated by m2html © 2005
    - - \ No newline at end of file diff --git a/doc/src/geckomat/model_adapter/ModelAdapter.html b/doc/src/geckomat/model_adapter/ModelAdapter.html deleted file mode 100644 index 7d1301b5..00000000 --- a/doc/src/geckomat/model_adapter/ModelAdapter.html +++ /dev/null @@ -1,115 +0,0 @@ - - - - Description of ModelAdapter - - - - - - - - - -
    Home > src > geckomat > model_adapter > ModelAdapter.m
    - - - -

    ModelAdapter -

    - -

    PURPOSE ^

    -
    Abstract Base class for adapters for different species
    - -

    SYNOPSIS ^

    -
    This is a script file.
    - -

    DESCRIPTION ^

    -
    Abstract Base class for adapters for different species
    - - -

    CROSS-REFERENCE INFORMATION ^

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

    SUBFUNCTIONS ^

    - - -

    SOURCE CODE ^

    -
    0001 %Abstract Base class for adapters for different species
    -0002 classdef (Abstract) ModelAdapter
    -0003     methods (Abstract)
    -0004         [spont,spontRxnNames] = getSpontaneousReactions(obj,model);
    -0005     end
    -0006     methods
    -0007         %not really needed, we could access it directly. Not very nice, but practical
    -0008         function parameters = getParameters(obj)
    -0009             parameters = obj.params;
    -0010         end
    -0011 
    -0012         %This allows for changing parameters in an adapter without
    -0013         %creating a new class. May be convenient, although less clean
    -0014         %function obj = setParameters(obj, parameters)
    -0015         %    obj.mParams = parameters;
    -0016         %end
    -0017 
    -0018         %The genes returned here should match the gene id set in the parameter params.uniprot.geneIDfield
    -0019         function genes = getUniprotCompatibleGenes(obj,inGenes)
    -0020             genes = inGenes;
    -0021         end
    -0022 
    -0023         function uniprotIDs = getUniprotIDsFromTable(obj,modelGenes)
    -0024             conversionTable = fullfile(obj.params.path,'data','uniprotConversion.tsv');
    -0025             if exist(conversionTable,'file')
    -0026                 fID=fopen(conversionTable,'r');
    -0027                 conversionTable = textscan(fID,'%q %q','Delimiter','\t','HeaderLines',1);
    -0028                 fclose(fID);
    -0029 
    -0030                 modelIDs    = conversionTable{1,1};
    -0031                 uniprots    = conversionTable{1,2};
    -0032 
    -0033                 [a,b] = ismember(modelGenes,modelIDs);
    -0034 
    -0035                 uniprotIDs  = strings(numel(modelGenes),1);
    -0036                 uniprotIDs(a)  = uniprots(b(a));
    -0037                 disp('The model genes are matched to Uniprot via the table at data/uniprotConversion.tsv.')
    -0038             else
    -0039                 uniprotIDs = modelGenes;
    -0040             end
    -0041         end
    -0042 
    -0043         function folder = getBrendaDBFolder(obj)
    -0044             folder = fullfile(findGECKOroot(),'databases');
    -0045         end
    -0046 
    -0047         function x = getPhylDistStructPath(obj)
    -0048             x =  fullfile(findRAVENroot(),'external','kegg','keggPhylDist.mat');
    -0049         end
    -0050 
    -0051         % Define a model-specific function in the 'code' subfolder of the
    -0052         % project folder, that can constrain the model to anaerobic
    -0053         % conditions, and refer to this function in the modelAdapter. This
    -0054         % function is used when running bayesianSensitivityTuning.m (via
    -0055         % abc_max.m) if the fluxData has anaerobic conditions.
    -0056         function ecModel = makeModelAnaerobic(obj,ecModel)
    -0057             ecModel = ecModel;
    -0058         end
    -0059     end
    -0060 
    -0061     %To have the params public is a bit "ugly", but very practical
    -0062     %if we want to change a parameter
    -0063     properties (Access = public)
    -0064         params;
    -0065     end
    -0066 end
    -
    Generated by m2html © 2005
    - - \ No newline at end of file diff --git a/doc/src/geckomat/model_adapter/ModelAdapterManager.html b/doc/src/geckomat/model_adapter/ModelAdapterManager.html deleted file mode 100644 index b9c24361..00000000 --- a/doc/src/geckomat/model_adapter/ModelAdapterManager.html +++ /dev/null @@ -1,108 +0,0 @@ - - - - Description of ModelAdapterManager - - - - - - - - - -
    Home > src > geckomat > model_adapter > ModelAdapterManager.m
    - - - -

    ModelAdapterManager -

    - -

    PURPOSE ^

    -
    Abstract Base class for adapters for different species
    - -

    SYNOPSIS ^

    -
    This is a script file.
    - -

    DESCRIPTION ^

    -
    Abstract Base class for adapters for different species
    - - -

    CROSS-REFERENCE INFORMATION ^

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

    SUBFUNCTIONS ^

    - - -

    SOURCE CODE ^

    -
    0001 %Abstract Base class for adapters for different species
    -0002 classdef ModelAdapterManager 
    -0003     methods(Static)
    -0004         function adapter = getAdapter(adapterPath, addToMatlabPath)
    -0005             if nargin < 2
    -0006                 addToMatlabPath = true;
    -0007             end
    -0008             
    -0009             [adapterFolder, adapterClassName, extension] = fileparts(adapterPath);
    -0010             if ~strcmp(extension, '.m')
    -0011                 error('Please provide the full path to the adapter file, including the file extension.');
    -0012             else
    -0013                 s = pathsep;
    -0014                 pathStr = [s, path, s];
    -0015                 onPath = contains(pathStr, [s, adapterFolder, s], 'IgnoreCase', ispc);
    -0016                 % Check if the folder is on the path
    -0017                 if ~onPath
    -0018                     if addToMatlabPath
    -0019                         addpath(adapterFolder);
    -0020                     else
    -0021                         printOrange(['WARNING: The adapter will not be on the MATLAB path, since addToMatlabPath is false\n' ...
    -0022                                      'and it is not currently on the path. Either set addToMatlabPath to true, fix this\n'...
    -0023                                      'manually before calling this function or make sure it is in current directory (not\n'...
    -0024                                      'recommended). If the class is not reachable throughout the entire GECKO use there will\n'...
    -0025                                      'be errors throughout.\n']);
    -0026                     end
    -0027                 end
    -0028 
    -0029             end
    -0030             adapter = feval(adapterClassName);
    -0031         end
    -0032         
    -0033         function out = getDefault()
    -0034             out = ModelAdapterManager.setGetDefault();
    -0035         end
    -0036         
    -0037         function adapter = setDefault(adapterPath, addToMatlabPath)
    -0038             if nargin < 1 || isempty(adapterPath)
    -0039                 adapter = ModelAdapterManager.setGetDefault(adapterPath);
    -0040                 return
    -0041             end
    -0042             if nargin < 2
    -0043                 addToMatlabPath = true;
    -0044             end
    -0045             adapter = ModelAdapterManager.setGetDefault(ModelAdapterManager.getAdapter(adapterPath, addToMatlabPath));
    -0046         end
    -0047         
    -0048     end
    -0049     methods(Static,Access = private)
    -0050         % This is how they recommend defining static variables in Matlab
    -0051         function out = setGetDefault(val)
    -0052             persistent defaultAdapter; %will be empty initially
    -0053             if nargin
    -0054                 defaultAdapter = val;
    -0055             end
    -0056             out = defaultAdapter;
    -0057         end
    -0058     end
    -0059 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 deleted file mode 100644 index 75e6ad25..00000000 --- a/doc/src/geckomat/model_adapter/adapterTemplate.html +++ /dev/null @@ -1,139 +0,0 @@ - - - - Description of adapterTemplate - - - - - - - - - -
    Home > src > geckomat > model_adapter > adapterTemplate.m
    - - - -

    adapterTemplate -

    - -

    PURPOSE ^

    -
    - -

    SYNOPSIS ^

    -
    This is a script file.
    - -

    DESCRIPTION ^

    -
    - - -

    CROSS-REFERENCE INFORMATION ^

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

    SUBFUNCTIONS ^

    - - -

    SOURCE CODE ^

    -
    0001 classdef KEY_CLASSNAME < ModelAdapter
    -0002     methods
    -0003         function obj = KEY_CLASSNAME()
    -0004             % Set initial values of the obj.params - they can be changed by the user
    -0005             
    -0006             % Directory where all model-specific files and scripts are kept.
    -0007             % Is assumed to follow the GECKO-defined folder structure.
    -0008             obj.params.path = fullfile('KEY_PATH', 'KEY_NAME');
    -0009             addpath(fullfile(obj.params.path,'code'));
    -0010 
    -0011             % Path to the conventional GEM that this ecModel will be based on.
    -0012             obj.params.convGEM = fullfile(obj.params.path,'models','yourModel.xml');
    -0013 
    -0014             % Average enzyme saturation factor
    -0015             obj.params.sigma = 0.5;
    -0016 
    -0017             % Total protein content in the cell [g protein/gDw]
    -0018             obj.params.Ptot = 0.5;
    -0019 
    -0020             % Fraction of enzymes in the model [g enzyme/g protein]
    -0021             obj.params.f = 0.5;
    -0022             
    -0023             % Growth rate the model should be able to reach when not
    -0024             % constraint by nutrient uptake (e.g. max growth rate) [1/h]
    -0025             obj.params.gR_exp = 0.41;
    -0026 
    -0027             % Provide your organism scientific name
    -0028             obj.params.org_name = 'genus species';
    -0029             
    -0030             % Taxonomic identifier for Complex Portal
    -0031             obj.params.complex.taxonomicID = [];
    -0032 
    -0033             % Provide your organism KEGG ID, selected at
    -0034             % https://www.genome.jp/kegg/catalog/org_list.html
    -0035             obj.params.kegg.ID = 'sce';
    -0036             % Field for KEGG gene identifier; should match the gene
    -0037             % identifiers used in the model. With 'kegg', it takes the
    -0038             % default KEGG Entry identifier (for example YER023W here:
    -0039             % https://www.genome.jp/dbget-bin/www_bget?sce:YER023W).
    -0040             % Alternatively, gene identifiers from the "Other DBs" section
    -0041             % of the KEGG page can be selected. For example "NCBI-GeneID",
    -0042             % "UniProt", or "Ensembl". Not all DB entries are available for
    -0043             % all organisms and/or genes.
    -0044             obj.params.kegg.geneID = 'kegg';
    -0045 
    -0046             % Provide what identifier should be used to query UniProt.
    -0047             % Select proteome IDs at https://www.uniprot.org/proteomes/
    -0048             % or taxonomy IDs at https://www.uniprot.org/taxonomy.
    -0049             obj.params.uniprot.type = 'taxonomy'; % 'proteome' or 'taxonomy'
    -0050             obj.params.uniprot.ID = '559292'; % should match the ID type
    -0051             % Field for Uniprot gene ID - should match the gene ids used in the
    -0052             % model. It should be one of the "Returned Field" entries under
    -0053             % "Names & Taxonomy" at this page: https://www.uniprot.org/help/return_fields
    -0054             obj.params.uniprot.geneIDfield = 'gene_oln';
    -0055             % Whether only reviewed data from UniProt should be considered.
    -0056             % Reviewed data has highest confidence, but coverage might be (very)
    -0057             % low for non-model organisms
    -0058             obj.params.uniprot.reviewed = false;
    -0059 
    -0060             % Reaction ID for glucose exchange reaction (or other preferred carbon source)
    -0061             obj.params.c_source = 'r_1714'; 
    -0062 
    -0063             % Reaction ID for biomass pseudoreaction
    -0064             obj.params.bioRxn = 'r_4041';
    -0065 
    -0066             % Name of the compartment where the protein pseudometabolites
    -0067             % should be located (all be located in the same compartment,
    -0068             % this does not interfere with them catalyzing reactions in
    -0069             % different compartments). Typically, cytoplasm is chosen.
    -0070             obj.params.enzyme_comp = 'cytoplasm';
    -0071         end
    -0072 
    -0073         % function ecModel = makeModelAnaerobic(ecModel)
    -0074         %     % Define a model-specific function in the 'code' subfolder,
    -0075         %     % that can constrain the model to anaerobic conditions, and
    -0076         %     % include the name of this function here. This is used by
    -0077         %     % bayesianSensitivityTuning.m (via abc_max.m) if the fluxData
    -0078         %     % has anaerobic conditions.
    -0079         %     addpath(fullfile(obj.params.path,'code'));
    -0080         %     ecModel = nameOfModelSpecificFunction(ecModel);
    -0081         % end
    -0082 
    -0083         function [spont,spontRxnNames] = getSpontaneousReactions(obj,model)
    -0084             % Indicates how spontaneous reactions are identified. Here it
    -0085             % is done by the reaction have 'spontaneous' in its name.
    -0086             spont = contains(model.rxnNames,'spontaneous');
    -0087             spontRxnNames = model.rxnNames(spont);
    -0088         end
    -0089     end
    -0090 end
    -
    Generated by m2html © 2005
    - - \ No newline at end of file diff --git a/doc/src/geckomat/model_adapter/index.html b/doc/src/geckomat/model_adapter/index.html deleted file mode 100644 index c588875b..00000000 --- a/doc/src/geckomat/model_adapter/index.html +++ /dev/null @@ -1,29 +0,0 @@ - - - - Index for Directory src\geckomat\model_adapter - - - - - - - - - - -
    < Master indexIndex for src\geckomat\model_adapter >
    - -

    Index for src\geckomat\model_adapter

    - -

    Matlab files in this directory:

    - -
     ModelAdapterAbstract Base class for adapters for different species
     ModelAdapterManagerAbstract Base class for adapters for different species
     adapterTemplate
    - - - - -
    Generated by m2html © 2005
    - - \ No newline at end of file diff --git a/doc/src/geckomat/utilities/addNewRxnsToEC.html b/doc/src/geckomat/utilities/addNewRxnsToEC.html deleted file mode 100644 index 8a416f8d..00000000 --- a/doc/src/geckomat/utilities/addNewRxnsToEC.html +++ /dev/null @@ -1,322 +0,0 @@ - - - - Description of addNewRxnsToEC - - - - - - - - - -
    Home > src > geckomat > utilities > addNewRxnsToEC.m
    - - - -

    addNewRxnsToEC -

    - -

    PURPOSE ^

    -
    addNewRxnsToEC
    - -

    SYNOPSIS ^

    -
    function [model, rxnsAdded, enzAdded] = addNewRxnsToEC(model, newRxns, newEnzymes, modelAdapter)
    - -

    DESCRIPTION ^

    -
     addNewRxnsToEC
    -   Add new reaction to an enzyme-constrained model. This function is 
    -   useful to simulate metabolic manipulations done to an organism such as
    -   integration of new genes that add a new reaction/pathway.
    -
    - Input:
    -   model           an ecModel in GECKO 3 format (with ecModel.ec structure)
    -   newRxns         structure with the new reaction information as follow:
    -                   rxns        cell array with unique strings that
    -                               identifies each reaction
    -                   rxnNames    cell array with the names of each reaction
    -                   equations   cell array with equation strings. Decimal
    -                               coefficients are expressed as "1.2".
    -                               Reversibility is indicated by "<=>" or
    -                               "=>".
    -                   grRules     cell array with the gene-reaction
    -                               relationship for each reaction. For example
    -                               "(A and B) or (C)" means that the reaction
    -                               could be catalyzed by a complex between
    -                               A & B or by C on its own. All the genes
    -                               have to be present in model.genes. Add
    -                               genes with addGenesRaven before calling
    -                               this function if needed (opt, default '')
    -   newEnzymes      structure with the new enzymes information as follow:
    -                   enzymes     cell array with uniprot id
    -                   genes       cell array with the respective gene
    -                   mw          cell array with the MW
    -   modelAdapter    a loaded model adapter (Optional, will otherwise use the
    -                   default model adapter).
    -
    - Output:
    -   model           ecModel whit new reactions
    -   rxnsAdded       cell array with the reactions added
    -
    - Notes:
    -     (i) Write equations as follows:
    -               'xylitol[c] + NAD[c] => D-xylulose[c] + NADH[c] + H+[c]'
    -         Note that the reversibility defined in the equation will be used
    -         to split to construct irreversible reactions (add _REV) and the
    -         rules defined will be used to expand the model (add _EXP_n).
    -        
    -     (2) After add the new reactions, setKcatForReactions or
    -         applyCustomKcats should be run to add the kcat to the reactions,
    -         and subsequently applyKcatConstraints.
    -
    - Usage:
    -   [model, rxnsAdded, enzAdded] = addNewRxnsToEC(model, newRxns, newEnzymes, modelAdapter);
    - - -

    CROSS-REFERENCE INFORMATION ^

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

    SOURCE CODE ^

    -
    0001 function [model, rxnsAdded, enzAdded] = addNewRxnsToEC(model, newRxns, newEnzymes, modelAdapter)
    -0002 % addNewRxnsToEC
    -0003 %   Add new reaction to an enzyme-constrained model. This function is
    -0004 %   useful to simulate metabolic manipulations done to an organism such as
    -0005 %   integration of new genes that add a new reaction/pathway.
    -0006 %
    -0007 % Input:
    -0008 %   model           an ecModel in GECKO 3 format (with ecModel.ec structure)
    -0009 %   newRxns         structure with the new reaction information as follow:
    -0010 %                   rxns        cell array with unique strings that
    -0011 %                               identifies each reaction
    -0012 %                   rxnNames    cell array with the names of each reaction
    -0013 %                   equations   cell array with equation strings. Decimal
    -0014 %                               coefficients are expressed as "1.2".
    -0015 %                               Reversibility is indicated by "<=>" or
    -0016 %                               "=>".
    -0017 %                   grRules     cell array with the gene-reaction
    -0018 %                               relationship for each reaction. For example
    -0019 %                               "(A and B) or (C)" means that the reaction
    -0020 %                               could be catalyzed by a complex between
    -0021 %                               A & B or by C on its own. All the genes
    -0022 %                               have to be present in model.genes. Add
    -0023 %                               genes with addGenesRaven before calling
    -0024 %                               this function if needed (opt, default '')
    -0025 %   newEnzymes      structure with the new enzymes information as follow:
    -0026 %                   enzymes     cell array with uniprot id
    -0027 %                   genes       cell array with the respective gene
    -0028 %                   mw          cell array with the MW
    -0029 %   modelAdapter    a loaded model adapter (Optional, will otherwise use the
    -0030 %                   default model adapter).
    -0031 %
    -0032 % Output:
    -0033 %   model           ecModel whit new reactions
    -0034 %   rxnsAdded       cell array with the reactions added
    -0035 %
    -0036 % Notes:
    -0037 %     (i) Write equations as follows:
    -0038 %               'xylitol[c] + NAD[c] => D-xylulose[c] + NADH[c] + H+[c]'
    -0039 %         Note that the reversibility defined in the equation will be used
    -0040 %         to split to construct irreversible reactions (add _REV) and the
    -0041 %         rules defined will be used to expand the model (add _EXP_n).
    -0042 %
    -0043 %     (2) After add the new reactions, setKcatForReactions or
    -0044 %         applyCustomKcats should be run to add the kcat to the reactions,
    -0045 %         and subsequently applyKcatConstraints.
    -0046 %
    -0047 % Usage:
    -0048 %   [model, rxnsAdded, enzAdded] = addNewRxnsToEC(model, newRxns, newEnzymes, modelAdapter);
    -0049 
    -0050 if nargin < 4 || isempty(modelAdapter)
    -0051     modelAdapter = ModelAdapterManager.getDefault();
    -0052     if isempty(modelAdapter)
    -0053         error('Either send in a modelAdapter or set the default model adapter in the ModelAdapterManager.')
    -0054     end
    -0055 end
    -0056 params = modelAdapter.getParameters();
    -0057 
    -0058 if nargin < 3 || isempty(newEnzymes)
    -0059     newEnzymes = [];
    -0060 end
    -0061 
    -0062 % Validate if GECKO version 3
    -0063 if ~isfield(model, 'ec')
    -0064     error('Input model is not an ecModel in GECKO 3 format (with ecModel.ec structure)')
    -0065 end
    -0066 
    -0067 if model.ec.geckoLight
    -0068     error('addNewRxnsToEC only works on non-light ecModels')
    -0069 else
    -0070     % Check if the new proteins are not already present in the model
    -0071     if ~isempty(newEnzymes)
    -0072         [toRemove,~] = ismember(newEnzymes.enzymes, model.ec.enzymes);
    -0073 
    -0074         % 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']);
    -0077             newEnzymes.enzymes(toRemove) = [];
    -0078             newEnzymes.genes(toRemove) = [];
    -0079             newEnzymes.mw(toRemove) = [];
    -0080         end
    -0081 
    -0082         if ~isempty(newEnzymes.enzymes)
    -0083             
    -0084             % 1. Add new genes
    -0085             genesToAdd.genes = newEnzymes.genes;
    -0086             genesToAdd.geneShortNames = genesToAdd.genes;
    -0087             model = addGenesRaven(model, genesToAdd);
    -0088 
    -0089             % 2. Add new Enzyme-usage pseudometabolite
    -0090 
    -0091             % Validate compartment to add protein pseudoreactions
    -0092             compartmentID = strcmp(model.compNames,params.enzyme_comp);
    -0093             if ~any(compartmentID)
    -0094                 error(['Compartment ' params.enzyme_comp ' (specified in params.enzyme_comp) '...
    -0095                     'cannot be found in model.compNames'])
    -0096             end
    -0097             compartmentID = model.comps(compartmentID);
    -0098 
    -0099             proteinMets.mets         = strcat('prot_', newEnzymes.enzymes);
    -0100             proteinMets.metNames     = proteinMets.mets;
    -0101             proteinMets.compartments = compartmentID;
    -0102             if isfield(model,'metMiriams')
    -0103                 proteinMets.metMiriams = repmat({struct('name',{{'sbo'}},'value',{{'SBO:0000252'}})},numel(proteinMets.mets),1);
    -0104             end
    -0105             if isfield(model,'metCharges')
    -0106                 proteinMets.metCharges = zeros(numel(proteinMets.mets),1);
    -0107             end
    -0108             proteinMets.metNotes = repmat({'Enzyme-usage pseudometabolite'},numel(proteinMets.mets),1);
    -0109             model = addMets(model,proteinMets);
    -0110         end
    -0111         enzAdded = newEnzymes.enzymes(:);  
    -0112     end
    -0113 
    -0114     % 3. Add new reactions
    -0115 
    -0116     % Before add the reactions validate that all the genes in grRules are
    -0117     % present in the model.
    -0118     genesInRules = strjoin(convertCharArray(newRxns.grRules));
    -0119     genesInRules = regexp(genesInRules,' |)|(|and|or','split'); % Remove all grRule punctuation
    -0120     genesInRules = genesInRules(~cellfun(@isempty,genesInRules));  % Remove spaces and empty genes
    -0121     genesInRules = setdiff(unique(genesInRules),model.genes); % Only keep new genes
    -0122 
    -0123     % If there is any gene which is not present, as to be pass as
    -0124     % newEnzymes input
    -0125     if ~isempty(genesInRules)
    -0126         errorText = 'The following genes from grRules are not present in the model, add them as newEnzymes input:';
    -0127         dispEM(errorText,true,genesInRules,false)
    -0128     end
    -0129 
    -0130     % Get reversible reactions to split
    -0131     toIrrev = find(cellfun(@(x) contains(x,'<=>'),newRxns.equations));
    -0132     if ~isempty(toIrrev)
    -0133         for i=1:numel(toIrrev)
    -0134             idx = toIrrev(i);
    -0135             newEquation = split(newRxns.equations(idx),'<=>');
    -0136             % Remove directionality
    -0137             newRxns.equations(idx) = erase(newRxns.equations(idx), '<');
    -0138 
    -0139             % Add a new reaction to the list to be added
    -0140             newRxns.rxns{end+1} = [newRxns.rxns{idx} '_REV'];
    -0141             newRxns.rxnNames{end+1} = [newRxns.rxnNames{idx} ' (reversible)'];
    -0142             newRxns.equations{end+1} = [strtrim(newEquation{2, 1}) ' => ' strtrim(newEquation{1, 1})];
    -0143             newRxns.grRules{end+1} = newRxns.grRules{idx};
    -0144         end
    -0145     end
    -0146 
    -0147     % Get reactions to separate isozymes
    -0148     toSplit = find(cellfun(@(x) contains(x,'or'),newRxns.grRules));
    -0149     if ~isempty(toSplit)
    -0150         for i=1:numel(toSplit)
    -0151             idx = toSplit(i);
    -0152             newRules = split(newRxns.grRules(idx),'or');
    -0153             newRules = strtrim(erase(newRules, {'(' ')'}));
    -0154 
    -0155             for j=1:numel(newRules)
    -0156                 newRxns.rxns{end+1} = [newRxns.rxns{idx} '_EXP_' num2str(j)];
    -0157                 newRxns.rxnNames(end+1) = newRxns.rxnNames(idx);
    -0158                 newRxns.equations(end+1) = newRxns.equations(idx);
    -0159                 newRxns.grRules(end+1) = newRules(j);
    -0160             end
    -0161 
    -0162             % Remove the original one
    -0163             newRxns.rxns(idx) = [];
    -0164             newRxns.rxnNames(idx) = [];
    -0165             newRxns.equations(idx) = [];
    -0166             newRxns.grRules(idx) = [];
    -0167         end
    -0168     end
    -0169 
    -0170     newRxns.lb = zeros(length(newRxns.rxns),1);
    -0171     newRxns.ub = zeros(length(newRxns.rxns),1) + 1000;
    -0172 
    -0173     model = addRxns(model, newRxns, 3, '', true, true);
    -0174 
    -0175     % 4. Add protein usage reactions.
    -0176     usageRxns.rxns            = strcat('usage_',proteinMets.mets);
    -0177     usageRxns.rxnNames        = usageRxns.rxns;
    -0178     usageRxns.mets            = cell(numel(usageRxns.rxns),1);
    -0179     usageRxns.stoichCoeffs    = cell(numel(usageRxns.rxns),1);
    -0180     for i=1:numel(usageRxns.mets)
    -0181         usageRxns.mets{i}         = {proteinMets.mets{i}, 'prot_pool'};
    -0182         usageRxns.stoichCoeffs{i} = [-1,1];
    -0183     end
    -0184     usageRxns.lb              = zeros(numel(usageRxns.rxns),1) - 1000;
    -0185     usageRxns.ub              = zeros(numel(usageRxns.rxns),1);
    -0186     usageRxns.rev             = ones(numel(usageRxns.rxns),1);
    -0187     usageRxns.grRules         = newEnzymes.genes;
    -0188     model = addRxns(model,usageRxns);
    -0189 
    -0190     % 5. Update .ec field with enzyme data
    -0191     model.ec.enzymes    = [model.ec.enzymes; newEnzymes.enzymes(:)];
    -0192     model.ec.genes      = [model.ec.genes; newEnzymes.genes(:)];
    -0193     model.ec.mw         = [model.ec.mw; newEnzymes.mw(:)];
    -0194     model.ec.sequence   = [model.ec.sequence; repmat({''},numel(newEnzymes.enzymes),1)]; 
    -0195     if isfield(model.ec,'concs')
    -0196         model.ec.concs  = [model.ec.concs; NaN(numel(newEnzymes.enzymes),1)];
    -0197     end
    -0198 
    -0199     % 6. Expand the enzyme rxns matrix
    -0200     rxnWithRule = find(~cellfun('isempty',newRxns.grRules));
    -0201 
    -0202     model.ec.rxnEnzMat =  [model.ec.rxnEnzMat, zeros(length(model.ec.rxns), length(newEnzymes.enzymes))]; % add n new enzymes
    -0203     model.ec.rxnEnzMat =  [model.ec.rxnEnzMat; zeros(length(rxnWithRule), length(model.ec.enzymes))]; % add n new rxns
    -0204 
    -0205     % 7. Update .ec field with rxn data
    -0206 
    -0207     % Get reactions to add
    -0208     numRxns = length(model.ec.rxns);
    -0209     for i = 1:numel(rxnWithRule)
    -0210         rxnIdx = rxnWithRule(i);
    -0211 
    -0212         model.ec.rxns(end+1)    = newRxns.rxns(rxnIdx);
    -0213         model.ec.kcat(end+1)    = 0;
    -0214         model.ec.source(end+1)  = {''};
    -0215         model.ec.notes(end+1)   = {''};
    -0216         model.ec.eccodes(end+1) = {''};
    -0217 
    -0218         % Get rules
    -0219         genes = newRxns.grRules(rxnIdx);
    -0220         genes = strtrim(erase(split(genes,'and'), {'(' ')'}));
    -0221         [~,enzIdx] = ismember(genes, model.ec.genes);
    -0222 
    -0223         % Update the enzyme rxns matrix
    -0224         model.ec.rxnEnzMat(numRxns+i, enzIdx) = 1;
    -0225     end
    -0226     
    -0227     rxnsAdded = newRxns.rxns(:);
    -0228 end
    -0229 end
    -
    Generated by m2html © 2005
    - - \ No newline at end of file diff --git a/doc/src/geckomat/utilities/ecFSEOF.html b/doc/src/geckomat/utilities/ecFSEOF.html deleted file mode 100644 index d6d4081f..00000000 --- a/doc/src/geckomat/utilities/ecFSEOF.html +++ /dev/null @@ -1,410 +0,0 @@ - - - - Description of ecFSEOF - - - - - - - - - -
    Home > src > geckomat > utilities > ecFSEOF.m
    - - - -

    ecFSEOF -

    - -

    PURPOSE ^

    -
    ecFSEOF
    - -

    SYNOPSIS ^

    -
    function fseof = ecFSEOF(model,prodTargetRxn,csRxn,nSteps,outputFile,filePath,modelAdapter)
    - -

    DESCRIPTION ^

    -
     ecFSEOF
    -   Function that runs Flux-Scanning with Enforced Objective Function (FSEOF)
    -   for a specified production target.
    -
    - Input:
    -   model          an ecModel in GECKO 3 format (with ecModel.ec structure).
    -   prodTargetRxn  rxn ID for the production target reaction, a exchange
    -                  reaction is recommended.
    -   csRxn          rxn ID for the main carbon source uptake reaction.
    -   nSteps         number of steps for suboptimal objective in FSEOF.
    -                  (Optional, default 16)
    -   outputFile     bolean option to save results in a file. (Optional,
    -                  default false)
    -   filePath       file path for results output. It will store two files:
    -                  - at the genes level, ecFSEOF_genes.tsv
    -                  - at the reactions level, ecFSEOF_rxns.tsv
    -                  (Optional, default in the 'output' sub-folder taken from
    -                  modelAdapter, e.g. output/ecFSEOF_rxns.tsv)
    -   modelAdapter   a loaded model adapter. (Optional, will otherwise use
    -                  the default model adapter)
    -
    - Output:
    -   fseof   an structure with all results. Contains the following fields:
    -           - alpha:             target production used for enforced 
    -                                objetive limits (from minimum to maximum 
    -                                production)
    -           - v_matrix:          fluxes for each target reaction predicted
    -                                and each alpha.
    -           - rxnTargets:        a list with all reactions with fluxes that
    -                                change consistently as target production
    -                                increases.
    -                                Contains: ID, name, slope, gene rule, and
    -                                equation
    -           - transportTargets:  a list with all transport reactions with
    -                                fluxes that change consistently as target
    -                                production increases.
    -                                Contains: ID, name, slope, gene rule, and
    -                                equation
    -           - geneTargets:       a list with all selected targets that
    -                                increase production.
    -                                Contains: gene, shortName, slope, action,
    -                                and essentiality
    -
    - Usage:
    -   fseof = ecFSEOF(model,prodTargetRxn,csRxn,nSteps,outputFile,filePath,filterG,modelAdapter)
    - - -

    CROSS-REFERENCE INFORMATION ^

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

    SOURCE CODE ^

    -
    0001 function fseof = ecFSEOF(model,prodTargetRxn,csRxn,nSteps,outputFile,filePath,modelAdapter)
    -0002 % ecFSEOF
    -0003 %   Function that runs Flux-Scanning with Enforced Objective Function (FSEOF)
    -0004 %   for a specified production target.
    -0005 %
    -0006 % Input:
    -0007 %   model          an ecModel in GECKO 3 format (with ecModel.ec structure).
    -0008 %   prodTargetRxn  rxn ID for the production target reaction, a exchange
    -0009 %                  reaction is recommended.
    -0010 %   csRxn          rxn ID for the main carbon source uptake reaction.
    -0011 %   nSteps         number of steps for suboptimal objective in FSEOF.
    -0012 %                  (Optional, default 16)
    -0013 %   outputFile     bolean option to save results in a file. (Optional,
    -0014 %                  default false)
    -0015 %   filePath       file path for results output. It will store two files:
    -0016 %                  - at the genes level, ecFSEOF_genes.tsv
    -0017 %                  - at the reactions level, ecFSEOF_rxns.tsv
    -0018 %                  (Optional, default in the 'output' sub-folder taken from
    -0019 %                  modelAdapter, e.g. output/ecFSEOF_rxns.tsv)
    -0020 %   modelAdapter   a loaded model adapter. (Optional, will otherwise use
    -0021 %                  the default model adapter)
    -0022 %
    -0023 % Output:
    -0024 %   fseof   an structure with all results. Contains the following fields:
    -0025 %           - alpha:             target production used for enforced
    -0026 %                                objetive limits (from minimum to maximum
    -0027 %                                production)
    -0028 %           - v_matrix:          fluxes for each target reaction predicted
    -0029 %                                and each alpha.
    -0030 %           - rxnTargets:        a list with all reactions with fluxes that
    -0031 %                                change consistently as target production
    -0032 %                                increases.
    -0033 %                                Contains: ID, name, slope, gene rule, and
    -0034 %                                equation
    -0035 %           - transportTargets:  a list with all transport reactions with
    -0036 %                                fluxes that change consistently as target
    -0037 %                                production increases.
    -0038 %                                Contains: ID, name, slope, gene rule, and
    -0039 %                                equation
    -0040 %           - geneTargets:       a list with all selected targets that
    -0041 %                                increase production.
    -0042 %                                Contains: gene, shortName, slope, action,
    -0043 %                                and essentiality
    -0044 %
    -0045 % Usage:
    -0046 %   fseof = ecFSEOF(model,prodTargetRxn,csRxn,nSteps,outputFile,filePath,filterG,modelAdapter)
    -0047 
    -0048 if nargin < 7 || isempty(modelAdapter)
    -0049     modelAdapter = ModelAdapterManager.getDefault();
    -0050     if isempty(modelAdapter)
    -0051         error('Either send in a modelAdapter or set the default model adapter in the ModelAdapterManager.')
    -0052     end
    -0053 end
    -0054 params = modelAdapter.getParameters();
    -0055 
    -0056 if nargin < 5 || isempty(outputFile)
    -0057     outputFile = false;
    -0058 end
    -0059 
    -0060 if nargin < 6 || isempty(filePath)
    -0061     filePath = fullfile(params.path,'output');
    -0062 end
    -0063 
    -0064 if nargin < 4 || isempty(nSteps)
    -0065     nSteps = 16;
    -0066 end
    -0067 
    -0068 % Get relevant rxn indexes
    -0069 prodTargetRxnIdx = getIndexes(model, prodTargetRxn,'rxns');
    -0070 csRxnIdx         = getIndexes(model, csRxn,'rxns');
    -0071 bioRxnIdx        = getIndexes(model, params.bioRxn,'rxns');
    -0072 
    -0073 % Standardize grRules and rxnGeneMat in model
    -0074 [grRules,rxnGeneMat] = standardizeGrRules(model,true);
    -0075 model.grRules        = grRules;
    -0076 model.rxnGeneMat     = rxnGeneMat;
    -0077 
    -0078 % Check carbon source uptake rate and LB defined
    -0079 model = setParam(model, 'obj', params.bioRxn, 1);
    -0080 sol   = solveLP(model);
    -0081 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']);
    -0084 end
    -0085 
    -0086 % run FSEOF analysis
    -0087 
    -0088 % Find out the initial target production.
    -0089 iniTarget = sol.x(prodTargetRxnIdx);
    -0090 
    -0091 % Find out the maximum theoretical yield of target reaction.
    -0092 model     = setParam(model,'obj',prodTargetRxn,1);
    -0093 sol       = solveLP(model,1);
    -0094 % Set to 90%% based on https://doi.org/10.1128/AEM.00115-10
    -0095 maxTarget = sol.x(prodTargetRxnIdx) * 0.9;
    -0096 
    -0097 % Define alpha vector for suboptimal enforced objective values between
    -0098 % minimal production and 90%% of the maximum theoretical yield, initialize
    -0099 % fluxes matriz
    -0100 alpha    = iniTarget:((maxTarget-iniTarget)/(nSteps-1)):maxTarget;
    -0101 v_matrix = zeros(length(model.rxns),length(alpha));
    -0102 
    -0103 % Enforce objective flux iteratively
    -0104 progressbar('Flux Scanning with Enforced Objective Function')
    -0105 for i = 1:nSteps
    -0106     % Enforce the objetive flux of product formation
    -0107     model = setParam(model,'eq',prodTargetRxnIdx,alpha(i));
    -0108 
    -0109     % Restore minimum biomass lb to zero and set it as objective
    -0110     model.lb(bioRxnIdx) = 0;
    -0111     model = setParam(model,'obj',params.bioRxn,1);
    -0112     sol   = solveLP(model,1);
    -0113 
    -0114     % Store flux distribution
    -0115     v_matrix(:,i) = sol.x;
    -0116 
    -0117     progressbar(i/nSteps)
    -0118 end
    -0119 progressbar(1) % Make sure it closes
    -0120 
    -0121 % Take out rxns with no grRule and standard gene
    -0122 withGR         = ~cellfun(@isempty,model.grRules);
    -0123 stdIdx         = contains(model.grRules,'standard');
    -0124 withGR(stdIdx) = 0;
    -0125 target_rxns    = model.rxns(withGR);
    -0126 v_matrix       = v_matrix(withGR,:);
    -0127 rxnGeneM       = model.rxnGeneMat(withGR,:);
    -0128 
    -0129 % Filter out rxns that are always zero
    -0130 zero_flux   = ~all(abs(v_matrix(:,1:nSteps))==0,2);
    -0131 target_rxns = target_rxns(zero_flux,:);
    -0132 v_matrix    = v_matrix(zero_flux,:);
    -0133 rxnGeneM    = rxnGeneM(zero_flux,:);
    -0134 
    -0135 % Identify those rxns that always increase or decrease, and calculate the
    -0136 % slope as the difference in the flux when enforce objetive target
    -0137 % production is set to 90%% of the maximum teorethical yield
    -0138 % << v_matrix(i,nSteps-1) >> and the flux when the enforce objetive target
    -0139 % production is set to the minimum << v_matrix(i,1) >> for the reaction i,
    -0140 % divided by maxTarget-maxTarget/nSteps-1.
    -0141 slope_rxns  = zeros(size(target_rxns));
    -0142 targets     = logical(size(target_rxns));
    -0143 target_type = cell(size(target_rxns));
    -0144 for i = 1:length(target_rxns)
    -0145     if issorted(abs(v_matrix(i,1:nSteps)),'strictascend')
    -0146         % Those reactions that always increase while enforcing target
    -0147         % production are suggested for Over Expression
    -0148         targets(i) = true;
    -0149         slope_rxns(i)  = abs(v_matrix(i,nSteps-1)-v_matrix(i,1))/abs(maxTarget-maxTarget/nSteps-1);
    -0150         target_type(i) = {'OE'};
    -0151     elseif issorted(abs(v_matrix(i,1:nSteps)),'strictdescend')
    -0152         % Those reactions that always decrease while enforcing target
    -0153         % production are suggested for KnockDown or KnockOut. KO are those
    -0154         % reactions which have zero flux when enforcing target production
    -0155         % to 90%% of the maximum theoretical yield.
    -0156         targets(i) = true;
    -0157         slope_rxns(i)  = abs(v_matrix(i,nSteps-1)-v_matrix(i,1))/abs(maxTarget-maxTarget/nSteps-1);
    -0158         if v_matrix(i,nSteps) == 0
    -0159             target_type(i) = {'KO'};
    -0160         else
    -0161             target_type(i) = {'KD'};
    -0162         end
    -0163     end
    -0164 end
    -0165 
    -0166 % Only keep those reaction that shows an increase or decrease pattern.
    -0167 target_rxns = target_rxns(targets);
    -0168 v_matrix    = v_matrix(targets,:);
    -0169 rxnGeneM    = rxnGeneM(targets,:);
    -0170 slope_rxns  = slope_rxns(targets);
    -0171 target_type = target_type(targets);
    -0172 
    -0173 % Order from highest to lowest slope
    -0174 [~,order]   = sort(slope_rxns,'descend');
    -0175 target_rxns = target_rxns(order);
    -0176 v_matrix    = v_matrix(order,:);
    -0177 rxnGeneM    = rxnGeneM(order,:);
    -0178 slope_rxns  = slope_rxns(order);
    -0179 target_type = target_type(order);
    -0180 
    -0181 % Filter out reactions with slope < quantile
    -0182 non_zero_slope  = slope_rxns > quantile(slope_rxns,0.75);
    -0183 target_rxns     = target_rxns(non_zero_slope);
    -0184 v_matrix        = v_matrix(non_zero_slope,:);
    -0185 rxnGeneM        = rxnGeneM(non_zero_slope,:);
    -0186 slope_rxns      = slope_rxns(non_zero_slope);
    -0187 target_type     = target_type(non_zero_slope);
    -0188 
    -0189 % Create gene list of those connected to the remaining rxns
    -0190 genes             = model.genes(sum(rxnGeneM,1) > 0);
    -0191 slope_genes       = zeros(size(genes));
    -0192 rxnGeneM          = rxnGeneM(:,sum(rxnGeneM,1) > 0);
    -0193 target_type_genes = cell(size(genes));
    -0194 essentiality      = cell(size(genes));
    -0195 
    -0196 % Validate for gene essentiality
    -0197 progressbar('Checking for gene essentiality')
    -0198 for i = 1:numel(genes)
    -0199 
    -0200     % Block protein usage to KO al the reactions associated to it.
    -0201     usage_rxn_idx = strcmpi(model.ec.genes, genes{i});
    -0202     usage_rxn = strcat('usage_prot_', model.ec.enzymes(usage_rxn_idx));
    -0203     tempModel = setParam(model, 'eq', usage_rxn, 0);
    -0204     solKO     = solveLP(tempModel);
    -0205     % Check if no feasible solution was found
    -0206     if solKO.stat == -1 || solKO.x(bioRxnIdx) < 1e-8
    -0207         essentiality(i) = {'essential'};
    -0208     end
    -0209 
    -0210     % Since a gene can be involved in multiple reactions, multiple
    -0211     % engineering manipulations can be suggested for the same gene
    -0212     % e.g. (OE and KD). So, reconcilie them, and report only one.
    -0213     
    -0214     % Get reaction index, in targets set, for each gene
    -0215     rxns_for_gene = find(rxnGeneM(:,i) > 0);
    -0216     actions = unique(target_type(rxns_for_gene));
    -0217     if numel(actions) > 1
    -0218         % If any OE is suggested give the highest priority over KD or KO
    -0219         if any(startsWith(actions, 'OE'))
    -0220             target_type_genes(i) = {'OE'};
    -0221             % Otherwise change to KO if not essential
    -0222         elseif ~any(startsWith(actions, 'OE')) && ~isequal(essentiality(i),{'essential'})
    -0223             target_type_genes(i) = {'KO'};
    -0224         else
    -0225             target_type_genes(i) = {'KD'};
    -0226         end
    -0227     else
    -0228         target_type_genes(i) = actions;
    -0229     end
    -0230     % Extract all the slope (from rxns across alphas) conected to
    -0231     % each remaining gene
    -0232     slope_set      = slope_rxns(rxns_for_gene);
    -0233     slope_genes(i) = mean(slope_set);
    -0234 
    -0235     progressbar(i/numel(genes))
    -0236 end
    -0237 progressbar(1) % Make sure it closes
    -0238 
    -0239 % Order genes from highest to lowest slope:
    -0240 [~,order]         = sort(slope_genes,'descend');
    -0241 genes             = genes(order,:);
    -0242 slope_genes       = slope_genes(order,:);
    -0243 target_type_genes = target_type_genes(order,:);
    -0244 essentiality      = essentiality(order,:);
    -0245 
    -0246 % Create output:
    -0247 
    -0248 % Report values used to enforce objective target production
    -0249 fseof.alpha = alpha;
    -0250 
    -0251 % Exclude enzyme usage reactions
    -0252 toKeep = ~startsWith(target_rxns,'usage_prot_');
    -0253 rxnIdx = getIndexes(model,target_rxns(toKeep),'rxns');
    -0254 
    -0255 % Report the fluxes at each alpha
    -0256 fseof.v_matrix = array2table(v_matrix(toKeep,:), ...
    -0257     'VariableNames', string(alpha), 'RowNames', model.rxns(rxnIdx));
    -0258 
    -0259 % Report reaction targets
    -0260 fseof.rxnTargets(:,1) = model.rxns(rxnIdx);
    -0261 fseof.rxnTargets(:,2) = model.rxnNames(rxnIdx);
    -0262 fseof.rxnTargets(:,3) = num2cell(slope_rxns(toKeep));
    -0263 fseof.rxnTargets(:,4) = model.grRules(rxnIdx);
    -0264 fseof.rxnTargets(:,5) = constructEquations(model,rxnIdx);
    -0265 
    -0266 % Identify transport reactions; defined as reactions involving (at least)
    -0267 % one metabolite name in more than one compartment.
    -0268 transportRxns = false(numel(rxnIdx),1);
    -0269 for i = 1:numel(rxnIdx)
    -0270     % Get the involved metabolites in each reaction
    -0271     mets = model.metNames(model.S(:,rxnIdx(i))~=0);
    -0272     % Remove enzyme metabolite
    -0273     mets(startsWith(mets,'prot_')) = [];
    -0274     % Validate if it is a transport reaciton
    -0275     transportRxns(i) = numel(mets) ~= numel(unique(mets));
    -0276 end
    -0277 
    -0278 % Create separate table for transport reactions
    -0279 fseof.transportTargets = fseof.rxnTargets(transportRxns,:);
    -0280 fseof.rxnTargets(transportRxns,:) = [];
    -0281 
    -0282 % Report gene targets
    -0283 geneIdx              = cellfun(@(x) find(strcmpi(model.genes,x)),genes);
    -0284 fseof.geneTargets(:,1) = genes;
    -0285 fseof.geneTargets(:,2) = model.geneShortNames(geneIdx);
    -0286 fseof.geneTargets(:,3) = num2cell(slope_genes);
    -0287 fseof.geneTargets(:,4) = target_type_genes;
    -0288 fseof.geneTargets(:,5) = essentiality;
    -0289 
    -0290 % Save results in a file if defined
    -0291 if outputFile
    -0292     % Write file with gene targets
    -0293     writetable(cell2table(fseof.geneTargets, ...
    -0294         'VariableNames', {'gene_IDs' 'gene_names' 'slope' 'action' 'essentiality'}), ...
    -0295         fullfile(filePath, 'ecFSEOF_genes.tsv'), ...
    -0296         'FileType', 'text', ...
    -0297         'Delimiter', '\t', ...
    -0298         'QuoteStrings', false);
    -0299 
    -0300     % Write file with rxn targets
    -0301     writetable(cell2table(fseof.rxnTargets, ...
    -0302         'VariableNames', {'rxn_IDs' 'rxnNames' 'slope' 'grRules' 'rxn_formula'}), ...
    -0303         fullfile(filePath, 'ecFSEOF_rxns.tsv'), ...
    -0304         'FileType', 'text', ...
    -0305         'Delimiter', '\t', ...
    -0306         'QuoteStrings', false);
    -0307 
    -0308     % Write file with transport targets
    -0309     writetable(cell2table(fseof.transportTargets, ...
    -0310         'VariableNames', {'rxn_IDs' 'rxnNames' 'slope' 'grRules' 'rxn_formula'}), ...
    -0311         fullfile(filePath, 'ecFSEOF_transporter.tsv'), ...
    -0312         'FileType', 'text', ...
    -0313         'Delimiter', '\t', ...
    -0314         'QuoteStrings', false);
    -0315 
    -0316     disp(['ecFSEOF results stored at: ' newline filePath]);
    -0317 end
    -0318 
    -0319 end
    -
    Generated by m2html © 2005
    - - \ No newline at end of file diff --git a/doc/src/geckomat/utilities/ecFVA.html b/doc/src/geckomat/utilities/ecFVA.html deleted file mode 100644 index 110325d0..00000000 --- a/doc/src/geckomat/utilities/ecFVA.html +++ /dev/null @@ -1,146 +0,0 @@ - - - - Description of ecFVA - - - - - - - - - -
    Home > src > geckomat > utilities > ecFVA.m
    - - - -

    ecFVA -

    - -

    PURPOSE ^

    -
    ecFVA
    - -

    SYNOPSIS ^

    -
    function [minFlux, maxFlux] = ecFVA(ecModel, model)
    - -

    DESCRIPTION ^

    -
     ecFVA
    -   Flux variability analysis is performed on the ecModel, and isozymic
    -   reactions are combined to construct ouput minFlux and maxFlux vectors,
    -   which follow the same order of model.rxns. The output from this
    -   function does not include enzyme usage reactions, to observe these, on
    -   could consider running flux variability directly on the ecModel.
    -
    - Input:
    -   ecModel     an ecModel in GECKO 3 format (with ecModel.ec structure)
    -   model       non-ecModel variant of the ecModel, to which the minFlux
    -               and maxFlux will be mapped
    - Output:
    -   minFlux     vector of minimum flux rates, corresponding to model.rxns
    -   maxFlux     vector of maximum flux rates, corresponding to model.rxns
    -
    - Usage: [minFlux, maxFlux] = ecFVA(ecModel, model)
    - - -

    CROSS-REFERENCE INFORMATION ^

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

    SUBFUNCTIONS ^

    - - -

    SOURCE CODE ^

    -
    0001 function [minFlux, maxFlux] = ecFVA(ecModel, model)
    -0002 % ecFVA
    -0003 %   Flux variability analysis is performed on the ecModel, and isozymic
    -0004 %   reactions are combined to construct ouput minFlux and maxFlux vectors,
    -0005 %   which follow the same order of model.rxns. The output from this
    -0006 %   function does not include enzyme usage reactions, to observe these, on
    -0007 %   could consider running flux variability directly on the ecModel.
    -0008 %
    -0009 % Input:
    -0010 %   ecModel     an ecModel in GECKO 3 format (with ecModel.ec structure)
    -0011 %   model       non-ecModel variant of the ecModel, to which the minFlux
    -0012 %               and maxFlux will be mapped
    -0013 % Output:
    -0014 %   minFlux     vector of minimum flux rates, corresponding to model.rxns
    -0015 %   maxFlux     vector of maximum flux rates, corresponding to model.rxns
    -0016 %
    -0017 % Usage: [minFlux, maxFlux] = ecFVA(ecModel, model)
    -0018 
    -0019 rxnIDs = regexprep(ecModel.rxns,'(_REV)?(_EXP_\d+)?','');
    -0020 [rxnIDmap, convRxnID] = findgroups(rxnIDs);
    -0021 
    -0022 solMaxAll = nan(numel(ecModel.rxns),numel(convRxnID));
    -0023 solMinAll = solMaxAll;
    -0024 
    -0025 pool = gcp('nocreate');
    -0026 if isempty(pool)
    -0027     parpool;
    -0028 end
    -0029 
    -0030 D = parallel.pool.DataQueue;
    -0031 progressbar('Running ecFVA');
    -0032 afterEach(D, @nUpdateProgressbar);
    -0033 
    -0034 N = numel(convRxnID);
    -0035 p = 1;
    -0036 
    -0037 parfor i=1:N
    -0038     tmpModel = ecModel;
    -0039     tmpModel.c = zeros(numel(tmpModel.rxns),1);
    -0040 
    -0041     rxnsToOptim = find(rxnIDmap == i);
    -0042     rxnsOptIDs  = ecModel.rxns(rxnsToOptim);
    -0043     rxnsToMin = endsWith(rxnsOptIDs,'_REV') | contains(rxnsOptIDs,'_REV_EXP_');
    -0044     rxnsToMax = rxnsToOptim(~rxnsToMin);
    -0045     rxnsToMin = rxnsToOptim(rxnsToMin);
    -0046 
    -0047     tmpModel.c(rxnsToMax) = 1;
    -0048     tmpModel.c(rxnsToMin) = -1;
    -0049     solMax=solveLP(tmpModel);
    -0050     if ~isempty(solMax.x)
    -0051         solMaxAll(:,i)=solMax.x;
    -0052     end
    -0053     tmpModel.c(rxnsToMax) = -1;
    -0054     tmpModel.c(rxnsToMin) = 1;
    -0055     solMin=solveLP(tmpModel);
    -0056     if ~isempty(solMin.x)
    -0057         solMinAll(:,i)=solMin.x;
    -0058     end    
    -0059     send(D, i);
    -0060 end
    -0061 
    -0062 minFlux=min(solMinAll,[],2,'omitnan');
    -0063 maxFlux=max(solMaxAll,[],2,'omitnan');
    -0064 
    -0065 mappedFlux = mapRxnsToConv(ecModel,model,[minFlux maxFlux]);
    -0066 
    -0067 minFlux=mappedFlux(:,1);
    -0068 maxFlux=mappedFlux(:,2);
    -0069 
    -0070 % Mapped flux might have swapped directionality: min/max might be swapped
    -0071 swapDir = minFlux > maxFlux;
    -0072 if any(swapDir)
    -0073     tmpFlux = minFlux(swapDir);
    -0074     minFlux(swapDir) = maxFlux(swapDir);
    -0075     maxFlux(swapDir) = tmpFlux;
    -0076 end
    -0077 
    -0078 function nUpdateProgressbar(~)
    -0079 progressbar(p/N);
    -0080 p = p + 1;
    -0081 end
    -0082 end
    -
    Generated by m2html © 2005
    - - \ No newline at end of file diff --git a/doc/src/geckomat/utilities/enzymeUsage.html b/doc/src/geckomat/utilities/enzymeUsage.html deleted file mode 100644 index 012d491c..00000000 --- a/doc/src/geckomat/utilities/enzymeUsage.html +++ /dev/null @@ -1,132 +0,0 @@ - - - - Description of enzymeUsage - - - - - - - - - -
    Home > src > geckomat > utilities > enzymeUsage.m
    - - - -

    enzymeUsage -

    - -

    PURPOSE ^

    -
    enzymeUsage
    - -

    SYNOPSIS ^

    -
    function usageData = enzymeUsage(ecModel,fluxes,zero)
    - -

    DESCRIPTION ^

    -
     enzymeUsage
    -   Gives enzyme usages based on a provided flux distribution, as obtained
    -   from a full GECKO model. It can give:
    -   1)  absolute usage: the specific enzyme usage in mg/gDCW, which can
    -       be given for enzymes with- and without concentration information;
    -   2)  capacity usage: the ratio of available enzyme that is used, calcuted
    -       by (absUsage/UB) (note that capacity usage is 0 if an enzyme
    -       concentration was not constrained in the model);
    -   3)  UB: the upper bound of each enzyme exchange reaction, which may not
    -       be the same as the enzyme concentration, if it has been
    -       flexibilized
    -   4)  protID: the protein identifiers for each enzyme (if the model has an
    -       enzymes field than this order is used, otherwise it is given
    -       alphabetically.
    -
    - Input:
    -   ecModel     an ecModel in GECKO 3 format (with ecModel.ec structure)
    -   fluxes      vector of fluxes, for instance sol.x
    -   zero        logical whether also enzymes with zero absolute usage
    -               should be included (Optional, default true)
    -
    - Output:
    -   usageData   structure with enzyme usage data
    -               capUsage    vector of enzyme capacity usages
    -               absUsage    vector of absolute enzyme usages
    -               UB          vector of enzyme exchange reaction upper bounds
    -               protID      string array of matching protein IDs
    -               fluxes      vector of fluxes, copy of input fluxes
    -
    - Usage:
    -   usageData = enzymeUsage(ecModel,fluxes,zero)
    - - -

    CROSS-REFERENCE INFORMATION ^

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

    SOURCE CODE ^

    -
    0001 function usageData = enzymeUsage(ecModel,fluxes,zero)
    -0002 % enzymeUsage
    -0003 %   Gives enzyme usages based on a provided flux distribution, as obtained
    -0004 %   from a full GECKO model. It can give:
    -0005 %   1)  absolute usage: the specific enzyme usage in mg/gDCW, which can
    -0006 %       be given for enzymes with- and without concentration information;
    -0007 %   2)  capacity usage: the ratio of available enzyme that is used, calcuted
    -0008 %       by (absUsage/UB) (note that capacity usage is 0 if an enzyme
    -0009 %       concentration was not constrained in the model);
    -0010 %   3)  UB: the upper bound of each enzyme exchange reaction, which may not
    -0011 %       be the same as the enzyme concentration, if it has been
    -0012 %       flexibilized
    -0013 %   4)  protID: the protein identifiers for each enzyme (if the model has an
    -0014 %       enzymes field than this order is used, otherwise it is given
    -0015 %       alphabetically.
    -0016 %
    -0017 % Input:
    -0018 %   ecModel     an ecModel in GECKO 3 format (with ecModel.ec structure)
    -0019 %   fluxes      vector of fluxes, for instance sol.x
    -0020 %   zero        logical whether also enzymes with zero absolute usage
    -0021 %               should be included (Optional, default true)
    -0022 %
    -0023 % Output:
    -0024 %   usageData   structure with enzyme usage data
    -0025 %               capUsage    vector of enzyme capacity usages
    -0026 %               absUsage    vector of absolute enzyme usages
    -0027 %               UB          vector of enzyme exchange reaction upper bounds
    -0028 %               protID      string array of matching protein IDs
    -0029 %               fluxes      vector of fluxes, copy of input fluxes
    -0030 %
    -0031 % Usage:
    -0032 %   usageData = enzymeUsage(ecModel,fluxes,zero)
    -0033 
    -0034 if nargin<3
    -0035     zero=true;
    -0036 end
    -0037 if ecModel.ec.geckoLight
    -0038     error('This function does not work on GECKO light models.')
    -0039 end
    -0040 usageData.protID      = ecModel.ec.enzymes;
    -0041 [~,rxnIdx] = ismember(strcat('usage_prot_',ecModel.ec.enzymes),ecModel.rxns);
    -0042 
    -0043 usageData.LB          = ecModel.lb(rxnIdx);
    -0044 usageData.absUsage    = abs(fluxes(rxnIdx));
    -0045 usageData.capUsage    = abs(usageData.absUsage./usageData.LB);
    -0046 usageData.fluxes      = fluxes;
    -0047 
    -0048 if ~zero
    -0049     nonzero               = usageData.absUsage<0;
    -0050     usageData.absUsage    = usageData.absUsage(nonzero);
    -0051     usageData.capUsage    = usageData.capUsage(nonzero);
    -0052     usageData.LB          = usageData.LB(nonzero);
    -0053     usageData.protID      = usageData.protID(nonzero);
    -0054 end
    -0055 end
    -
    Generated by m2html © 2005
    - - \ No newline at end of file diff --git a/doc/src/geckomat/utilities/findGECKOroot.html b/doc/src/geckomat/utilities/findGECKOroot.html deleted file mode 100644 index 0c4d1709..00000000 --- a/doc/src/geckomat/utilities/findGECKOroot.html +++ /dev/null @@ -1,74 +0,0 @@ - - - - Description of findGECKOroot - - - - - - - - - -
    Home > src > geckomat > utilities > findGECKOroot.m
    - - - -

    findGECKOroot -

    - -

    PURPOSE ^

    -
    findGECKOroot
    - -

    SYNOPSIS ^

    -
    function [geckoPath, prevDir] = findGECKOroot()
    - -

    DESCRIPTION ^

    -
     findGECKOroot
    -   Finds the root of the GECKO directory, by searching for the path to
    -   GECKO.png. Can also record the current directory, in case a function will
    -   use the geckoPath to navigate to a precise folder, and it should return to
    -   the previous directory afterwards.
    - - -

    CROSS-REFERENCE INFORMATION ^

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

    SOURCE CODE ^

    -
    0001 function [geckoPath, prevDir] = findGECKOroot()
    -0002 % findGECKOroot
    -0003 %   Finds the root of the GECKO directory, by searching for the path to
    -0004 %   GECKO.png. Can also record the current directory, in case a function will
    -0005 %   use the geckoPath to navigate to a precise folder, and it should return to
    -0006 %   the previous directory afterwards.
    -0007 
    -0008 ST=dbstack('-completenames');
    -0009 prevDir = pwd();
    -0010 geckoPath = ST(strcmp({ST.name},'findGECKOroot')).file;
    -0011 rootFound = 0;
    -0012 while rootFound == 0
    -0013     isRoot = exist(fullfile(geckoPath,'GECKOInstaller.m'),'file');
    -0014     if isRoot == 2
    -0015         rootFound = 1;
    -0016     else
    -0017         ravenPathOld = geckoPath;
    -0018         geckoPath = fileparts(geckoPath);
    -0019         if strcmp(ravenPathOld,geckoPath)
    -0020             error('Cannot find the GECKO root directory. Make sure you have not removed the GECKOInstaller.m file from your GECKO installation.')
    -0021         end
    -0022     end
    -0023 end
    -
    Generated by m2html © 2005
    - - \ No newline at end of file diff --git a/doc/src/geckomat/utilities/getSubsetEcModel.html b/doc/src/geckomat/utilities/getSubsetEcModel.html deleted file mode 100644 index a03f28c2..00000000 --- a/doc/src/geckomat/utilities/getSubsetEcModel.html +++ /dev/null @@ -1,139 +0,0 @@ - - - - Description of getSubsetEcModel - - - - - - - - - -
    Home > src > geckomat > utilities > getSubsetEcModel.m
    - - - -

    getSubsetEcModel -

    - -

    PURPOSE ^

    -
    getSubset_ecModel
    - -

    SYNOPSIS ^

    -
    function smallEcModel = getSubsetEcModel(bigEcModel,smallGEM)
    - -

    DESCRIPTION ^

    -
     getSubset_ecModel
    -   Generate a context-specific ecModel (strain/cell-line/tissue) by
    -   mapping reactions and genes from a conventional context-specific GEM to
    -   a general ecModel (bigEcModel), to yield a context-specific ecModel.
    -
    -   Both models (bigEcModel and the smallGEM) should have derived from the
    -   same starting model. If an ecModel with human-GEM 1.15.0 is made
    -   (yielding the bigEcModel), then human-GEM 1.15.0 should also be the
    -   basis from which the context-specific GEM (smallGEM) was generated by
    -   for instance tINIT.
    - 
    - Input:
    -   bigEcModel  enzyme-constrained version of conventional model of
    -                  metabolism for a given species
    -   smallGEM       Reduced model (subset of the general model) for a
    -                  specific strain (microbes) or cell-line/tissues (mammals)
    - 
    - Output:
    -   smallEcModel  Enzyme-constrained version of the context-specific model
    - 
    - Usage: smallEcModel = getSubsetEcModel(smallGEM,bigEcModel)
    - - -

    CROSS-REFERENCE INFORMATION ^

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

    SOURCE CODE ^

    -
    0001 function smallEcModel = getSubsetEcModel(bigEcModel,smallGEM)
    -0002 % getSubset_ecModel
    -0003 %   Generate a context-specific ecModel (strain/cell-line/tissue) by
    -0004 %   mapping reactions and genes from a conventional context-specific GEM to
    -0005 %   a general ecModel (bigEcModel), to yield a context-specific ecModel.
    -0006 %
    -0007 %   Both models (bigEcModel and the smallGEM) should have derived from the
    -0008 %   same starting model. If an ecModel with human-GEM 1.15.0 is made
    -0009 %   (yielding the bigEcModel), then human-GEM 1.15.0 should also be the
    -0010 %   basis from which the context-specific GEM (smallGEM) was generated by
    -0011 %   for instance tINIT.
    -0012 %
    -0013 % Input:
    -0014 %   bigEcModel  enzyme-constrained version of conventional model of
    -0015 %                  metabolism for a given species
    -0016 %   smallGEM       Reduced model (subset of the general model) for a
    -0017 %                  specific strain (microbes) or cell-line/tissues (mammals)
    -0018 %
    -0019 % Output:
    -0020 %   smallEcModel  Enzyme-constrained version of the context-specific model
    -0021 %
    -0022 % Usage: smallEcModel = getSubsetEcModel(smallGEM,bigEcModel)
    -0023 
    -0024 % Check if models were derived from the same starting GEM
    -0025 Rxn_format = regexprep(bigEcModel.rxns,'_REV|_EXP_\d+','');
    -0026 rxnsDiff = find(~ismember(smallGEM.rxns,Rxn_format));
    -0027 if numel(rxnsDiff) > 0
    -0028     dispEM(['While both models should have derived from the same starting ',...
    -0029             'GEM, the following reactions from smallGEM could not be found ',...
    -0030             'in bigEcModel:'],true,smallGEM.rxns(rxnsDiff),false);
    -0031 end
    -0032 
    -0033 % Check if original bigEcModel contains context-dependent protein constraints
    -0034 if any(bigEcModel.lb(startsWith(bigEcModel.rxns,'usage_prot_')) ~= -1000)
    -0035     printOrange(['WARNING: The bigEcModel is constraint by protein concentrations that are\n' ...
    -0036                  'likely not relevant in the constructed smallEcModel.\n']);
    -0037 end
    -0038 
    -0039 % Remove genes (and associated reactions) that are absent in smallGEM
    -0040 genesToRemove  = setdiff(bigEcModel.genes,smallGEM.genes);
    -0041 % If genesToRemove contains "standard", then remove this entry
    -0042 if ismember('standard', genesToRemove)
    -0043     genesToRemove(strcmp(genesToRemove, 'standard')) = [];
    -0044 end
    -0045 smallEcModel = removeGenes(bigEcModel,genesToRemove,true,true,false);
    -0046 
    -0047 % Remove genes from ec-structure
    -0048 enzToRemove = ismember(smallEcModel.ec.genes,genesToRemove);
    -0049 smallEcModel.ec.genes(enzToRemove)       = [];
    -0050 smallEcModel.ec.enzymes(enzToRemove)     = [];
    -0051 smallEcModel.ec.concs(enzToRemove)       = [];
    -0052 smallEcModel.ec.mw(enzToRemove)          = [];
    -0053 smallEcModel.ec.sequence(enzToRemove)    = [];
    -0054 smallEcModel.ec.rxnEnzMat(:,enzToRemove) = [];
    -0055 
    -0056 % Remove any reaction (except prot_ associated) that is absent from smallGEM
    -0057 trimRxns = regexprep(smallEcModel.rxns,'_REV|_EXP_\d+','');
    -0058 protRxns = startsWith(smallEcModel.rxns,{'usage_prot_','prot_pool_exchange'});
    -0059 keepRxns = ismember(trimRxns,smallGEM.rxns) | protRxns;
    -0060 smallEcModel = removeReactions(smallEcModel,~keepRxns, true, true, true);
    -0061 
    -0062 % Remove reactions from ec-structure
    -0063 ecRxnsToRemove = ~ismember(smallEcModel.ec.rxns,smallEcModel.rxns);
    -0064 
    -0065 smallEcModel.ec.rxns(ecRxnsToRemove)        = [];
    -0066 smallEcModel.ec.kcat(ecRxnsToRemove)        = [];
    -0067 smallEcModel.ec.source(ecRxnsToRemove)      = [];
    -0068 smallEcModel.ec.notes(ecRxnsToRemove)       = [];
    -0069 smallEcModel.ec.eccodes(ecRxnsToRemove)     = [];
    -0070 smallEcModel.ec.rxnEnzMat(ecRxnsToRemove,:) = [];
    -0071 end
    -0072
    -
    Generated by m2html © 2005
    - - \ No newline at end of file diff --git a/doc/src/geckomat/utilities/index.html b/doc/src/geckomat/utilities/index.html deleted file mode 100644 index fa531e36..00000000 --- a/doc/src/geckomat/utilities/index.html +++ /dev/null @@ -1,29 +0,0 @@ - - - - Index for Directory src\geckomat\utilities - - - - - - - - - - -
    < Master indexIndex for src\geckomat\utilities >
    - -

    Index for src\geckomat\utilities

    - -

    Matlab files in this directory:

    - -
     addNewRxnsToECaddNewRxnsToEC
     ecFSEOFecFSEOF
     ecFVAecFVA
     enzymeUsageenzymeUsage
     findGECKOrootfindGECKOroot
     getSubsetEcModelgetSubset_ecModel
     loadConventionalGEMloadConventionalGEM
     loadEcModelloadEcModel
     loadFluxDataloadFluxData
     loadProtDataloadProtData
     mapRxnsToConvmapRxnsToConv
     plotEcFVAplotEcFVA
     reportEnzymeUsagereportEnzymeUsage
     saveEcModelsaveECmodel
     startGECKOprojectstartGECKOproject
     updateGECKOdocupdateGeckoDoc
    - - - - -
    Generated by m2html © 2005
    - - \ No newline at end of file diff --git a/doc/src/geckomat/utilities/loadConventionalGEM.html b/doc/src/geckomat/utilities/loadConventionalGEM.html deleted file mode 100644 index eeca7996..00000000 --- a/doc/src/geckomat/utilities/loadConventionalGEM.html +++ /dev/null @@ -1,107 +0,0 @@ - - - - Description of loadConventionalGEM - - - - - - - - - -
    Home > src > geckomat > utilities > loadConventionalGEM.m
    - - - -

    loadConventionalGEM -

    - -

    PURPOSE ^

    -
    loadConventionalGEM
    - -

    SYNOPSIS ^

    -
    function model = loadConventionalGEM(filename, modelAdapter)
    - -

    DESCRIPTION ^

    -
     loadConventionalGEM
    -   Loads the conventional GEM (non-ecModel) from the location specified in
    -   the modelAdapter. By default, it looks in the models/ subdirectory of 
    -   the param.path specified in the modelAdapter. When loading
    -   conventional GEMs from other locations, one can directly use importModel.
    -
    - Input:
    -   filename        name of the model file, located in the the models/
    -                   subfolder of param.path as specified in the
    -                   modelAdapter (Optional, will otherwise use the
    -                   value specified as param.convGEM in the
    -                   modelAdapter)
    -   modelAdapter    a loaded model adapter, from where the model folder is
    -                   read (Optional, will otherwise use the default model adapter).
    -
    - Output:
    -   model           model in RAVEN format
    -
    - Usage:
    -   model = loadConventionalGEM(filename, modelAdapter)
    - - -

    CROSS-REFERENCE INFORMATION ^

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

    SOURCE CODE ^

    -
    0001 function model = loadConventionalGEM(filename, modelAdapter)
    -0002 % loadConventionalGEM
    -0003 %   Loads the conventional GEM (non-ecModel) from the location specified in
    -0004 %   the modelAdapter. By default, it looks in the models/ subdirectory of
    -0005 %   the param.path specified in the modelAdapter. When loading
    -0006 %   conventional GEMs from other locations, one can directly use importModel.
    -0007 %
    -0008 % Input:
    -0009 %   filename        name of the model file, located in the the models/
    -0010 %                   subfolder of param.path as specified in the
    -0011 %                   modelAdapter (Optional, will otherwise use the
    -0012 %                   value specified as param.convGEM in the
    -0013 %                   modelAdapter)
    -0014 %   modelAdapter    a loaded model adapter, from where the model folder is
    -0015 %                   read (Optional, will otherwise use the default model adapter).
    -0016 %
    -0017 % Output:
    -0018 %   model           model in RAVEN format
    -0019 %
    -0020 % Usage:
    -0021 %   model = loadConventionalGEM(filename, modelAdapter)
    -0022 
    -0023 
    -0024 if nargin < 2 || isempty(modelAdapter)
    -0025     modelAdapter = ModelAdapterManager.getDefault();
    -0026     if isempty(modelAdapter)
    -0027         error('Either send in a modelAdapter or set the default model adapter in the ModelAdapterManager.')
    -0028     end
    -0029 end
    -0030 params = modelAdapter.getParameters();
    -0031 if nargin < 1 || isempty(filename)
    -0032     filename = params.convGEM;
    -0033 else
    -0034     filename = fullfile(params.path,'models',[filename, '.xml'])
    -0035 end
    -0036 
    -0037 if endsWith(filename,'.xml')
    -0038     model = importModel(filename);
    -0039 elseif endsWith(filename,'.yml')
    -0040     model = readYAMLmodel(filename);
    -0041 end
    -
    Generated by m2html © 2005
    - - \ No newline at end of file diff --git a/doc/src/geckomat/utilities/loadEcModel.html b/doc/src/geckomat/utilities/loadEcModel.html deleted file mode 100644 index 3654832c..00000000 --- a/doc/src/geckomat/utilities/loadEcModel.html +++ /dev/null @@ -1,112 +0,0 @@ - - - - Description of loadEcModel - - - - - - - - - -
    Home > src > geckomat > utilities > loadEcModel.m
    - - - -

    loadEcModel -

    - -

    PURPOSE ^

    -
    loadEcModel
    - -

    SYNOPSIS ^

    -
    function model = loadEcModel(filename, modelAdapter)
    - -

    DESCRIPTION ^

    -
     loadEcModel
    -   Loads the ecModel that matches the modelAdapter. By default, it loads
    -   the models/ecModel.yml in the directory specified as param.path in
    -   the modelAdapter. Alternative files in the same folder can be loaded by
    -   providing the appropriate filename. If loading models from other
    -   locations, one can directly use readYAMLmodel.
    -
    - Input:
    -   filename        name of the ecModel file (Optional, default 'ecModel.yml').
    -                   Fill should be located in the models/ subfolder of
    -                   param.path as specified in the modelAdapter.
    -   modelAdapter    a loaded model adapter, from where the model folder is
    -                   read (Optional, will otherwise use the default model adapter).
    -
    - Output:
    -   model           an ecModel in GECKO 3 format (with ecModel.ec structure)
    -
    - Usage:
    -   model = loadEcModel(filename, modelAdapter)
    - - -

    CROSS-REFERENCE INFORMATION ^

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

    SOURCE CODE ^

    -
    0001 function model = loadEcModel(filename, modelAdapter)
    -0002 % loadEcModel
    -0003 %   Loads the ecModel that matches the modelAdapter. By default, it loads
    -0004 %   the models/ecModel.yml in the directory specified as param.path in
    -0005 %   the modelAdapter. Alternative files in the same folder can be loaded by
    -0006 %   providing the appropriate filename. If loading models from other
    -0007 %   locations, one can directly use readYAMLmodel.
    -0008 %
    -0009 % Input:
    -0010 %   filename        name of the ecModel file (Optional, default 'ecModel.yml').
    -0011 %                   Fill should be located in the models/ subfolder of
    -0012 %                   param.path as specified in the modelAdapter.
    -0013 %   modelAdapter    a loaded model adapter, from where the model folder is
    -0014 %                   read (Optional, will otherwise use the default model adapter).
    -0015 %
    -0016 % Output:
    -0017 %   model           an ecModel in GECKO 3 format (with ecModel.ec structure)
    -0018 %
    -0019 % Usage:
    -0020 %   model = loadEcModel(filename, modelAdapter)
    -0021 
    -0022 if nargin < 2 || isempty(modelAdapter)
    -0023     modelAdapter = ModelAdapterManager.getDefault();
    -0024     if isempty(modelAdapter)
    -0025         error('Either send in a modelAdapter or set the default model adapter in the ModelAdapterManager.')
    -0026     end
    -0027 end
    -0028 params = modelAdapter.getParameters();
    -0029 if nargin < 1 || isempty(filename)
    -0030     filename = 'ecModel.yml';
    -0031 else
    -0032 end
    -0033 
    -0034 if ~endsWith(filename,{'yml','yaml'})
    -0035     error(['ecModels should preferably be distributed in YAML file format, ', ...
    -0036            'as otherwise model content will be lost. If the model is in ', ...
    -0037            'SBML format, you can use the usual importModel function to load ', ...
    -0038            'this as any other genome-scale model.'])
    -0039 end
    -0040 
    -0041 filename = fullfile(params.path,'models',filename); 
    -0042 if endsWith(filename,{'yml','yaml'})
    -0043     model = readYAMLmodel(filename);
    -0044 elseif endsWith(filename,{'xml','sbml'})
    -0045     model = importModel(filename);
    -0046 end
    -0047 end
    -
    Generated by m2html © 2005
    - - \ No newline at end of file diff --git a/doc/src/geckomat/utilities/loadFluxData.html b/doc/src/geckomat/utilities/loadFluxData.html deleted file mode 100644 index dabf85c0..00000000 --- a/doc/src/geckomat/utilities/loadFluxData.html +++ /dev/null @@ -1,155 +0,0 @@ - - - - Description of loadFluxData - - - - - - - - - -
    Home > src > geckomat > utilities > loadFluxData.m
    - - - -

    loadFluxData -

    - -

    PURPOSE ^

    -
    loadFluxData
    - -

    SYNOPSIS ^

    -
    function fluxData = loadFluxData(fluxDataFile, modelAdapter)
    - -

    DESCRIPTION ^

    -
     loadFluxData
    -   Function that loads total protein measurements and flux data (exchange
    -   fluxes for carbon source,  O2, CO2, etc.)
    -
    - Input:
    -   fluxDataFile    path to file with flux data. (Optional, default
    -                   reads data/fluxData.tsv as specified in modelAdapter)
    -   modelAdapter    a loaded model adapter (Optional, will otherwise use
    -                   the default model adapter)
    -
    - Output:
    -   fluxData                structure with flux data
    -       conds               sampling condition
    -       Ptot                total protein (g/gDCW)
    -       grRate              growth rate (1/h)
    -       exchFluxes          exchange fluxes (mmol/gDCWh)
    -       exchMets            exchanged metabolites, matching exchFluxes
    -       exchRxnIDs          exchange reaction IDs, matching exchMets
    -       bayesianRMSEweight  if column existed in fluxData.tsv, weights for
    -                           RMSE calculation in Bayesian kcat tuning
    -       source              if column existed in fluxData.tsv, description
    -                           where the data comes from
    -
    - Usage:
    -   fluxData = loadFluxData(fluxDataFile, modelAdapter)
    - - -

    CROSS-REFERENCE INFORMATION ^

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

    SOURCE CODE ^

    -
    0001 function fluxData = loadFluxData(fluxDataFile, modelAdapter)
    -0002 % loadFluxData
    -0003 %   Function that loads total protein measurements and flux data (exchange
    -0004 %   fluxes for carbon source,  O2, CO2, etc.)
    -0005 %
    -0006 % Input:
    -0007 %   fluxDataFile    path to file with flux data. (Optional, default
    -0008 %                   reads data/fluxData.tsv as specified in modelAdapter)
    -0009 %   modelAdapter    a loaded model adapter (Optional, will otherwise use
    -0010 %                   the default model adapter)
    -0011 %
    -0012 % Output:
    -0013 %   fluxData                structure with flux data
    -0014 %       conds               sampling condition
    -0015 %       Ptot                total protein (g/gDCW)
    -0016 %       grRate              growth rate (1/h)
    -0017 %       exchFluxes          exchange fluxes (mmol/gDCWh)
    -0018 %       exchMets            exchanged metabolites, matching exchFluxes
    -0019 %       exchRxnIDs          exchange reaction IDs, matching exchMets
    -0020 %       bayesianRMSEweight  if column existed in fluxData.tsv, weights for
    -0021 %                           RMSE calculation in Bayesian kcat tuning
    -0022 %       source              if column existed in fluxData.tsv, description
    -0023 %                           where the data comes from
    -0024 %
    -0025 % Usage:
    -0026 %   fluxData = loadFluxData(fluxDataFile, modelAdapter)
    -0027 
    -0028 if nargin < 2 || 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.getParameters();
    -0035 
    -0036 if nargin < 1 || isempty(fluxDataFile)
    -0037     fluxDataFile = fullfile(params.path,'data','fluxData.tsv');
    -0038 end
    -0039 
    -0040 %Load total protein content and flux data
    -0041 fID       = fopen(fluxDataFile);
    -0042 formatStr = '%s';
    -0043 data      = textscan(fID,formatStr,'Delimiter','\n');
    -0044 fclose(fID);
    -0045 fluxDataRaw  = [];
    -0046 for i=1:length(data{1})
    -0047     row      = data{1}(i);
    -0048     row      = strsplit(row{1},'\t');
    -0049     row      = row(1:end);
    -0050     fluxDataRaw = [fluxDataRaw; row]; 
    -0051 end
    -0052 if size(fluxDataRaw,2) == 0
    -0053     error('The input file %s is likely not tab-delimited.', fluxDataFile)
    -0054 end
    -0055 fluxData            = [];
    -0056 
    -0057 %Find additional fields
    -0058 extraFieldNames     = {'bayesianRMSEweight','source'};
    -0059 extraFieldNumeric   = [true,false];      
    -0060 [~, extraFields]    = ismember(extraFieldNames,fluxDataRaw(1,:));
    -0061 for i=1:numel(extraFields)
    -0062     if extraFields(1) ~= 0
    -0063         if extraFieldNumeric(i)
    -0064             fluxData.(extraFieldNames{i}) = str2double(fluxDataRaw(2:end,extraFields(i)));
    -0065         else
    -0066             fluxData.(extraFieldNames{i}) = fluxDataRaw(2:end,extraFields(i));
    -0067         end
    -0068     end
    -0069 end
    -0070 fluxDataRaw(:,extraFields) = [];
    -0071 
    -0072 %Extract observed byProduct names from file
    -0073 exchRxns = fluxDataRaw(1,4:end);
    -0074 exchMets = strtrim(regexprep(exchRxns,'(.*)\(.*\)$','$1'));
    -0075 exchRxns = regexprep(exchRxns,'.*\((.*)\)$','$1');
    -0076 
    -0077 fluxData.conds      = fluxDataRaw(2:end,1);
    -0078 fluxData.Ptot       = str2double(fluxDataRaw(2:end,2));
    -0079 fluxData.grRate     = str2double(fluxDataRaw(2:end,3));
    -0080 fluxData.exchFluxes = str2double(fluxDataRaw(2:end,4:end));
    -0081 %fluxData.exchFluxes(isnan(fluxData.exchFluxes)) = 0;
    -0082 fluxData.exchMets   = exchMets;
    -0083 fluxData.exchRxnIDs = exchRxns;
    -0084 end
    -
    Generated by m2html © 2005
    - - \ No newline at end of file diff --git a/doc/src/geckomat/utilities/loadProtData.html b/doc/src/geckomat/utilities/loadProtData.html deleted file mode 100644 index 7b5e599a..00000000 --- a/doc/src/geckomat/utilities/loadProtData.html +++ /dev/null @@ -1,245 +0,0 @@ - - - - Description of loadProtData - - - - - - - - - -
    Home > src > geckomat > utilities > loadProtData.m
    - - - -

    loadProtData -

    - -

    PURPOSE ^

    -
    loadProtData
    - -

    SYNOPSIS ^

    -
    function protData = loadProtData(replPerCond, protDataFile, filterData, modelAdapter, minVal, maxRSD, maxMissing, cutLowest, addStdevs)
    - -

    DESCRIPTION ^

    -
     loadProtData
    -   Function that loads absolute proteomics data (in mg/gDCW) and returns
    -   mean values across replicates for each condition in the data file. By
    -   default it also filters the data by various criteria, to remove
    -   uncertain data (see input parameters).
    -
    - Input:
    -   replPerCond     vector with number of replicates for each condition in
    -                   the dataset. Example: [3, 2] if first conditions has
    -                   triplicates and second condition has duplicates.
    -   protDataFile    path to file with proteomics data, where protein levels
    -                   are in mg/gDCW (Optional, default reads 
    -                   data/proteomics.tsv as specified in modelAdapter)
    -                   Alternatively, protDataFile can be a protData structure
    -                   that was previously made by loadProtdata.
    -   filterData      logical whether abundances should be filtered. If
    -                   false, minVal, maxRSD, maxMissing and addStdevs are not
    -                   considered. (Optional, default true)
    -   modelAdapter    a loaded model adapter (Optional, will otherwise use
    -                   the default model adapter)
    -   minVal          threshold of mean protein measurement per condition.
    -                   (Optional, default = 0)
    -   maxRSD          maximum relative standard per condition. (Optional,
    -                   default = 1)
    -   maxMissing      ratio of replicates for which a protein level might be
    -                   missing. (Optional, default = 1/3 (or 1/2 if number of
    -                   replicates = 2))
    -                   If conditions have different number of replicates (as
    -                   indicated in replPerCond), maxMissing can also be a
    -                   vector of the same length as replPerCond, with
    -                   individual maxMissing parameters for each replicate.
    -   cutLowest       percentage of lowest mean values per condition to be
    -                   discared (not considering NaN values). (Optional, default 5)
    -   addStdevs       how many standard deviations should be added to the mean
    -                   value of each protein measurement across replicates,
    -                   broadening the confidence interval. (Optional,
    -                   default = 1)
    -
    - Output:
    -   protData        structure with (filtered) proteome data
    -                   uniprotIDs  cell arrray with Uniprot IDs matching
    -                               protData.abundances
    -                   abundances  matrix of proteomics data, where each
    -                               column contains mean abundances per
    -                               condition
    -
    - Usage:
    -   protData = loadProtData(replPerCond, protDataFile, filterData, modelAdapter, minVal, maxRSD, maxMissing, cutLowest, addStdevs)
    - - -

    CROSS-REFERENCE INFORMATION ^

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

    SOURCE CODE ^

    -
    0001 function protData = loadProtData(replPerCond, protDataFile, filterData, modelAdapter, minVal, maxRSD, maxMissing, cutLowest, addStdevs)
    -0002 % loadProtData
    -0003 %   Function that loads absolute proteomics data (in mg/gDCW) and returns
    -0004 %   mean values across replicates for each condition in the data file. By
    -0005 %   default it also filters the data by various criteria, to remove
    -0006 %   uncertain data (see input parameters).
    -0007 %
    -0008 % Input:
    -0009 %   replPerCond     vector with number of replicates for each condition in
    -0010 %                   the dataset. Example: [3, 2] if first conditions has
    -0011 %                   triplicates and second condition has duplicates.
    -0012 %   protDataFile    path to file with proteomics data, where protein levels
    -0013 %                   are in mg/gDCW (Optional, default reads
    -0014 %                   data/proteomics.tsv as specified in modelAdapter)
    -0015 %                   Alternatively, protDataFile can be a protData structure
    -0016 %                   that was previously made by loadProtdata.
    -0017 %   filterData      logical whether abundances should be filtered. If
    -0018 %                   false, minVal, maxRSD, maxMissing and addStdevs are not
    -0019 %                   considered. (Optional, default true)
    -0020 %   modelAdapter    a loaded model adapter (Optional, will otherwise use
    -0021 %                   the default model adapter)
    -0022 %   minVal          threshold of mean protein measurement per condition.
    -0023 %                   (Optional, default = 0)
    -0024 %   maxRSD          maximum relative standard per condition. (Optional,
    -0025 %                   default = 1)
    -0026 %   maxMissing      ratio of replicates for which a protein level might be
    -0027 %                   missing. (Optional, default = 1/3 (or 1/2 if number of
    -0028 %                   replicates = 2))
    -0029 %                   If conditions have different number of replicates (as
    -0030 %                   indicated in replPerCond), maxMissing can also be a
    -0031 %                   vector of the same length as replPerCond, with
    -0032 %                   individual maxMissing parameters for each replicate.
    -0033 %   cutLowest       percentage of lowest mean values per condition to be
    -0034 %                   discared (not considering NaN values). (Optional, default 5)
    -0035 %   addStdevs       how many standard deviations should be added to the mean
    -0036 %                   value of each protein measurement across replicates,
    -0037 %                   broadening the confidence interval. (Optional,
    -0038 %                   default = 1)
    -0039 %
    -0040 % Output:
    -0041 %   protData        structure with (filtered) proteome data
    -0042 %                   uniprotIDs  cell arrray with Uniprot IDs matching
    -0043 %                               protData.abundances
    -0044 %                   abundances  matrix of proteomics data, where each
    -0045 %                               column contains mean abundances per
    -0046 %                               condition
    -0047 %
    -0048 % Usage:
    -0049 %   protData = loadProtData(replPerCond, protDataFile, filterData, modelAdapter, minVal, maxRSD, maxMissing, cutLowest, addStdevs)
    -0050 
    -0051 if nargin < 8 || isempty(addStdevs)
    -0052     addStdevs = 1;
    -0053 end
    -0054 
    -0055 if nargin < 7 || isempty(maxMissing)
    -0056     maxMissing = 2/3;
    -0057 end
    -0058 
    -0059 if nargin < 6 || isempty(maxRSD)
    -0060     maxRSD = 1;
    -0061 end
    -0062 
    -0063 if nargin < 5 || isempty(minVal)
    -0064     minVal = 0;
    -0065 end
    -0066 
    -0067 if nargin < 4 || isempty(modelAdapter)
    -0068     modelAdapter = ModelAdapterManager.getDefault();
    -0069     if isempty(modelAdapter)
    -0070         error('Either send in a modelAdapter or set the default model adapter in the ModelAdapterManager.')
    -0071     end
    -0072 end
    -0073 params = modelAdapter.getParameters();
    -0074 
    -0075 if nargin < 3 || isempty(filterData)
    -0076     filterData = true;
    -0077 end
    -0078 
    -0079 if nargin < 2 || isempty(protDataFile)
    -0080     protDataFile = fullfile(params.path,'data','proteomics.tsv');
    -0081 end
    -0082 
    -0083 format = '%s';
    -0084 for i=1:sum(replPerCond)
    -0085     format = [format ' %f'];
    -0086 end
    -0087 if ~isstruct(protDataFile)
    -0088     checkFileExistence(protDataFile);
    -0089     fID         = fopen(protDataFile);
    -0090     protDataRaw = textscan(fID,format,'Delimiter','\t','HeaderLines',1,'TreatAsEmpty',{'NA','na','NaN','#VALUE!'});
    -0091     uniprotIDs  = protDataRaw{1};
    -0092     abundances  = cell2mat(protDataRaw(2:end));
    -0093     fclose(fID);
    -0094 else
    -0095     uniprotIDs  = protDataFile.uniprotIDs;
    -0096     abundances  = protDataFile.abundances;
    -0097 end
    -0098 
    -0099 %Remove entriew without ID
    -0100 remData = cellfun(@isempty,uniprotIDs);
    -0101 uniprotIDs(remData,:) = [];
    -0102 abundances(remData,:) = [];
    -0103 m                     = size(abundances,1);
    -0104 filtAbund             = nan(m,numel(replPerCond));
    -0105 
    -0106 if filterData
    -0107     for i=1:numel(replPerCond)
    -0108         condAbund    = abundances(:,1:replPerCond(i));
    -0109         if i<numel(replPerCond)
    -0110             abundances   = abundances(:,replPerCond(i)+1:end);
    -0111         end
    -0112         % First filter maxMissing
    -0113         if size(condAbund,2) > 1
    -0114             if numel(maxMissing)>1
    -0115                 maxMisRepl = maxMissing(i);
    -0116             else
    -0117                 maxMisRepl = maxMissing;
    -0118             end
    -0119             remData = sum(condAbund>0,2)<maxMisRepl*size(condAbund,2);
    -0120             condAbund(remData,:) = nan;
    -0121         end
    -0122         % Filter by RSD
    -0123         remData = (std(condAbund,0,2,'omitnan')./mean(condAbund,2,'omitnan'))>maxRSD;
    -0124         condAbund(remData) = nan;
    -0125         % Add stdevs
    -0126         condAbund = mean(condAbund,2,'omitnan')+(addStdevs*std(condAbund,0,2,'omitnan'));
    -0127         % Filter by minVal
    -0128         remData = mean(condAbund,2,'omitnan')<minVal;
    -0129         condAbund(remData) = nan;
    -0130         % Remove bottom 5%
    -0131         numData  = find(~isnan(condAbund));
    -0132         [~,sortData] = sort(condAbund);
    -0133         lowCutoff = floor(numel(numData)*0.05);
    -0134         condAbund(sortData(1:lowCutoff)) = nan;
    -0135         % Combine conditions
    -0136         filtAbund(:,i) = condAbund;
    -0137     end
    -0138 else
    -0139     for i=1:numel(replPerCond)
    -0140         condAbund    = abundances(:,1:replPerCond(i));
    -0141         if i<numel(replPerCond)
    -0142             abundances = abundances(:,replPerCond(i)+1:end);
    -0143         end
    -0144         filtAbund(:,i) = mean(condAbund,2,'omitnan');
    -0145     end
    -0146 end
    -0147 notAllNan = logical(sum(~isnan(filtAbund),2));
    -0148 protData.abundances = filtAbund(notAllNan,:);
    -0149 protData.uniprotIDs = uniprotIDs(notAllNan);
    -0150 end
    -0151
    -
    Generated by m2html © 2005
    - - \ No newline at end of file diff --git a/doc/src/geckomat/utilities/mapRxnsToConv.html b/doc/src/geckomat/utilities/mapRxnsToConv.html deleted file mode 100644 index f897fcd1..00000000 --- a/doc/src/geckomat/utilities/mapRxnsToConv.html +++ /dev/null @@ -1,122 +0,0 @@ - - - - Description of mapRxnsToConv - - - - - - - - - -
    Home > src > geckomat > utilities > mapRxnsToConv.m
    - - - -

    mapRxnsToConv -

    - -

    PURPOSE ^

    -
    mapRxnsToConv
    - -

    SYNOPSIS ^

    -
    function [mappedFlux, enzUsageFlux, usageEnz] = mapRxnsToConv(ecModel, model, fluxVect)
    - -

    DESCRIPTION ^

    -
     mapRxnsToConv
    -   A vector (or matrix) of fluxes is mapped to the reactions in the
    -   conventional starting model that was used to construct the ecModel. It
    -   is essential that the provided conventional model is indeed the model
    -   that was used to initate ecModel reconstruction.
    -
    - Input:
    -   ecModel         an ecModel in GECKO 3 format (with ecModel.ec structure),
    -                   that was used to obtain fluxVect
    -   model           the starting model for ecModel, to which the reactions
    -                   should be mapped
    -   fluxVect        vector or matrix of flux values, matching ecModel.rxns
    -
    - Output:
    -   mappedFlux      vector or matrix of flux values, matching model.rxns
    -   enzUsageFlux    vector or matrix of flux values from enzyme usage
    -                   reactions, as these are absent from mappedFlux
    -   usageEnz        cell array with protein IDs, matching enzUsageFlux
    -
    - Usage:
    -   [mappedFlux, enzUsageFlux, usageEnz] = mapRxnsToConv(ecModel, model, fluxVect)
    - - -

    CROSS-REFERENCE INFORMATION ^

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

    SOURCE CODE ^

    -
    0001 function [mappedFlux, enzUsageFlux, usageEnz] = mapRxnsToConv(ecModel, model, fluxVect)
    -0002 % mapRxnsToConv
    -0003 %   A vector (or matrix) of fluxes is mapped to the reactions in the
    -0004 %   conventional starting model that was used to construct the ecModel. It
    -0005 %   is essential that the provided conventional model is indeed the model
    -0006 %   that was used to initate ecModel reconstruction.
    -0007 %
    -0008 % Input:
    -0009 %   ecModel         an ecModel in GECKO 3 format (with ecModel.ec structure),
    -0010 %                   that was used to obtain fluxVect
    -0011 %   model           the starting model for ecModel, to which the reactions
    -0012 %                   should be mapped
    -0013 %   fluxVect        vector or matrix of flux values, matching ecModel.rxns
    -0014 %
    -0015 % Output:
    -0016 %   mappedFlux      vector or matrix of flux values, matching model.rxns
    -0017 %   enzUsageFlux    vector or matrix of flux values from enzyme usage
    -0018 %                   reactions, as these are absent from mappedFlux
    -0019 %   usageEnz        cell array with protein IDs, matching enzUsageFlux
    -0020 %
    -0021 % Usage:
    -0022 %   [mappedFlux, enzUsageFlux, usageEnz] = mapRxnsToConv(ecModel, model, fluxVect)
    -0023 
    -0024 if isempty(fluxVect)
    -0025     error('No or empty flux vector provided')
    -0026 end
    -0027 
    -0028 fluxes = fluxVect;
    -0029 rxnIDs = ecModel.rxns;
    -0030 
    -0031 % Invert flux of _REV reactions
    -0032 revRxns = endsWith(rxnIDs,'_REV') | contains(rxnIDs,'_REV_EXP_');
    -0033 fluxes(revRxns,:) = -fluxes(revRxns,:);
    -0034 rxnIDs(revRxns) = replace(rxnIDs(revRxns),'_REV','');
    -0035 % Remove _EXP_. suffixes
    -0036 rxnIDs = regexprep(rxnIDs,'_EXP_\d+','');
    -0037 
    -0038 % Map and sum fluxes to converted reaction IDs
    -0039 [rxnIDmap, convRxnID] = findgroups(rxnIDs);
    -0040 newVect = splitapply(@(x){sum(x,1)}, fluxes, rxnIDmap);
    -0041 newVect = cell2mat(newVect);
    -0042 
    -0043 % Place in same order as in original model
    -0044 [mapCheck,origIdx] = ismember(model.rxns,convRxnID);
    -0045 if ~all(mapCheck)
    -0046     error('Not all reactions from model.rxns can be found in the ecModel. Are you sure that ecModel is derived from model?')
    -0047 end
    -0048 mappedFlux=newVect(origIdx,:);
    -0049 
    -0050 % Separately report enzyme usages
    -0051 usageEnz = startsWith(ecModel.rxns,{'usage_prot_','prot_pool_exchange'});
    -0052 enzUsageFlux = fluxVect(usageEnz,:);
    -0053 usageEnz = regexprep(ecModel.rxns(usageEnz),'usage_prot_','');
    -0054 usageEnz = regexprep(usageEnz,'prot_pool_exchange','pool');
    -0055 end
    -
    Generated by m2html © 2005
    - - \ No newline at end of file diff --git a/doc/src/geckomat/utilities/plotEcFVA.html b/doc/src/geckomat/utilities/plotEcFVA.html deleted file mode 100644 index 31b5b0d8..00000000 --- a/doc/src/geckomat/utilities/plotEcFVA.html +++ /dev/null @@ -1,140 +0,0 @@ - - - - Description of plotEcFVA - - - - - - - - - -
    Home > src > geckomat > utilities > plotEcFVA.m
    - - - -

    plotEcFVA -

    - -

    PURPOSE ^

    -
    plotEcFVA
    - -

    SYNOPSIS ^

    -
    function plotEcFVA(minFlux, maxFlux)
    - -

    DESCRIPTION ^

    -
     plotEcFVA
    -   Plots cumulative distribution functions of ecFVA results from one or
    -   model ecModel(s) and/or GEM(s).
    -
    - Input:
    -   minFlux     vector of minimum flux values, coming from ecFVA. If
    -               multiple ecModels/GEMs are to be visualized, then each
    -               column represents a separate model.
    -   maxFlux     vector of maximum flux values, matching minFlux.
    - - -

    CROSS-REFERENCE INFORMATION ^

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

    SUBFUNCTIONS ^

    - - -

    SOURCE CODE ^

    -
    0001 function plotEcFVA(minFlux, maxFlux)
    -0002 % plotEcFVA
    -0003 %   Plots cumulative distribution functions of ecFVA results from one or
    -0004 %   model ecModel(s) and/or GEM(s).
    -0005 %
    -0006 % Input:
    -0007 %   minFlux     vector of minimum flux values, coming from ecFVA. If
    -0008 %               multiple ecModels/GEMs are to be visualized, then each
    -0009 %               column represents a separate model.
    -0010 %   maxFlux     vector of maximum flux values, matching minFlux.
    -0011 
    -0012 numMods = size(minFlux,2);
    -0013 fluxRanges = cell(3,1);
    -0014 % Ignore zero flux reactions
    -0015 for i=1:numMods
    -0016     zeroFlux = abs(minFlux(:,i)) < 1e-10 & abs(maxFlux(:,i)) < 1e-10;
    -0017     minFlux(zeroFlux,i) = NaN;
    -0018     maxFlux(zeroFlux,i) = NaN;
    -0019     fluxRange = maxFlux(:,i) - minFlux(:,i);
    -0020     fluxRange(isnan(fluxRange)) = [];
    -0021     fluxRanges{i} = fluxRange;
    -0022 end
    -0023 
    -0024 % Plot all together
    -0025 hold on
    -0026 legendText = cell(1,numel(numMods));
    -0027 for i=1:numMods
    -0028     fluxRange = fluxRanges{i};
    -0029     cdfplot(fluxRange)
    -0030     legendText{i} = (['Model #' num2str(i) ' (median: ' num2str(median(fluxRange,'omitnan')) ')']);
    -0031 end
    -0032 set(gca, 'XScale', 'log', 'Xlim', [1e-7 1e4])
    -0033 set(findall(gca, 'Type', 'Line'), 'LineWidth', 2)
    -0034 legend(legendText,  'Location','northwest')
    -0035 title('Flux variability (cumulative distribution)');
    -0036 xlabel('Variability range (mmol/gDCWh)');
    -0037 ylabel('Cumulative distribution');
    -0038 hold off
    -0039 end
    -0040 
    -0041 function cdfplot(X)
    -0042 % cdfplot(X)
    -0043 % displays a plot of the Empirical Cumulative Distribution Function
    -0044 % (CDF) of the input array X in the current figure. The empirical
    -0045 % CDF y=F(x) is defined as the proportion of X values less than or equal to x.
    -0046 % If input X is a matrix, then cdfplot(X) parses it to the vector and
    -0047 % displays CDF of all values.
    -0048 %
    -0049 % EXAMPLE:
    -0050 % figure;
    -0051 % cdfplot(randn(1,100));
    -0052 % hold on;
    -0053 % cdfplot(-log(1-rand(1,100)));
    -0054 % cdfplot(sqrt(randn(1,100).^2 + randn(1,100).^2))
    -0055 % legend('Normal(0,1) CDF', 'Exponential(1) CDF', 'Rayleigh(1) CDF', 4)
    -0056 
    -0057 % Version 1.0
    -0058 % Alex Podgaetsky, September 2003
    -0059 % alex@wavion.co.il
    -0060 %
    -0061 % Revisions:
    -0062 %       Version 1.0 -   initial version
    -0063 
    -0064 tmp = sort(reshape(X,prod(size(X)),1));
    -0065 Xplot = reshape([tmp tmp].',2*length(tmp),1);
    -0066 
    -0067 tmp = [1:length(X)].'/length(X);
    -0068 Yplot = reshape([tmp tmp].',2*length(tmp),1);
    -0069 Yplot = [0; Yplot(1:(end-1))];
    -0070 
    -0071 figure(gcf);
    -0072 hp = plot(Xplot, Yplot);
    -0073 
    -0074 ColOrd = get(gca, 'ColorOrder'); 
    -0075 ord = mod(length(get(gca,'Children')), size(ColOrd,1)); 
    -0076 set(hp, 'Color', ColOrd((ord==0) + (ord>0)*ord, :));
    -0077 if ~ishold
    -0078      xlabel('X', 'FontWeight','b','FontSize',12);
    -0079      ylabel('F(X)', 'FontWeight','b','FontSize',12);
    -0080      title('Empirical CDF', 'FontWeight','b','FontSize',12);
    -0081      grid on;
    -0082 end
    -0083 end
    -
    Generated by m2html © 2005
    - - \ No newline at end of file diff --git a/doc/src/geckomat/utilities/reportEnzymeUsage.html b/doc/src/geckomat/utilities/reportEnzymeUsage.html deleted file mode 100644 index a9d017c7..00000000 --- a/doc/src/geckomat/utilities/reportEnzymeUsage.html +++ /dev/null @@ -1,225 +0,0 @@ - - - - Description of reportEnzymeUsage - - - - - - - - - -
    Home > src > geckomat > utilities > reportEnzymeUsage.m
    - - - -

    reportEnzymeUsage -

    - -

    PURPOSE ^

    -
    reportEnzymeUsage
    - -

    SYNOPSIS ^

    -
    function usageReport = reportEnzymeUsage(ecModel, usageData, highCapUsage, topAbsUsage)
    - -

    DESCRIPTION ^

    -
     reportEnzymeUsage
    -   Summarizes the results from enzymeUsage.
    -
    -  Input:
    -   ecModel         a GECKO3 ecModel
    -   usageData       output from enzymeUsage
    -   highCapUsage    minimum ratio of enzyme capacity usage to be considered
    -                   as high usage (Optional, default 0.9, refering to a 
    -                   minimum of 90% capacity usage)
    -   topAbsUsage     number of top enzymes with highest absolute usage
    -                   (Optional, default 10, returning the top 10 enzymes
    -                   with highest absolute usage. With Inf or 0, all enzymes
    -                   are returned)
    -
    -  Output:
    -   usageReport     table with summary information
    -
    - Usage:
    -   usageReport = reportEnzymeUsage(ecModel, usageData, highCapUsage)
    - - -

    CROSS-REFERENCE INFORMATION ^

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

    SOURCE CODE ^

    -
    0001 function usageReport = reportEnzymeUsage(ecModel, usageData, highCapUsage, topAbsUsage)
    -0002 % reportEnzymeUsage
    -0003 %   Summarizes the results from enzymeUsage.
    -0004 %
    -0005 %  Input:
    -0006 %   ecModel         a GECKO3 ecModel
    -0007 %   usageData       output from enzymeUsage
    -0008 %   highCapUsage    minimum ratio of enzyme capacity usage to be considered
    -0009 %                   as high usage (Optional, default 0.9, refering to a
    -0010 %                   minimum of 90% capacity usage)
    -0011 %   topAbsUsage     number of top enzymes with highest absolute usage
    -0012 %                   (Optional, default 10, returning the top 10 enzymes
    -0013 %                   with highest absolute usage. With Inf or 0, all enzymes
    -0014 %                   are returned)
    -0015 %
    -0016 %  Output:
    -0017 %   usageReport     table with summary information
    -0018 %
    -0019 % Usage:
    -0020 %   usageReport = reportEnzymeUsage(ecModel, usageData, highCapUsage)
    -0021 
    -0022 if nargin < 3 || isempty(highCapUsage)
    -0023     highCapUsage = 0.9;
    -0024 end
    -0025 if nargin < 4 || isempty(topAbsUsage)
    -0026     topAbsUsage = 10;
    -0027 end
    -0028 
    -0029 usageReport = {};
    -0030 
    -0031 % Highest capacity usage
    -0032 highUsageProt = find(usageData.capUsage > highCapUsage);
    -0033 highEnzyme    = usageData.protID(highUsageProt);
    -0034 [~,enzIdx]    = ismember(highEnzyme,ecModel.ec.enzymes);
    -0035 geneIDs       = ecModel.ec.genes(enzIdx);
    -0036 
    -0037 highUsage.protID     = {};
    -0038 highUsage.geneID     = {};
    -0039 highUsage.absUsage   = [];
    -0040 highUsage.capUsage   = [];
    -0041 highUsage.kcat       = [];
    -0042 highUsage.source     = {};
    -0043 highUsage.rxnID      = {};
    -0044 highUsage.rxnNames   = {};
    -0045 highUsage.grRules    = {};
    -0046 
    -0047 for i=1:numel(enzIdx)
    -0048     [rxns, kcat, idx, rxnNames, grRules] = getReactionsFromEnzyme(ecModel,ecModel.ec.enzymes(enzIdx(i)));
    -0049     % See if all reactions carried flux
    -0050     [~,rIdx] = ismember(rxns,ecModel.rxns);
    -0051     carriedFlux = usageData.fluxes(rIdx) > 1e-7;
    -0052     if isscalar(find(carriedFlux))
    -0053         highUsage.protID(end+1,1)      = highEnzyme(i);
    -0054         highUsage.geneID(end+1,1)      = geneIDs(i);
    -0055         highUsage.absUsage(end+1,1)    = usageData.absUsage(enzIdx(i));
    -0056         highUsage.capUsage(end+1,1)    = usageData.capUsage(enzIdx(i));
    -0057         highUsage.kcat(end+1,1)        = kcat(carriedFlux);
    -0058         highUsage.source(end+1,1)      = ecModel.ec.source(idx(carriedFlux));
    -0059         highUsage.rxnID(end+1,1)       = rxns(carriedFlux);
    -0060         highUsage.rxnNames(end+1,1)    = rxnNames(carriedFlux);
    -0061         highUsage.grRules(end+1,1)     = grRules(carriedFlux);
    -0062     else
    -0063         % Add one entry for combined usage
    -0064         highUsage.protID(end+1,1)      = highEnzyme(i);
    -0065         highUsage.geneID(end+1,1)      = geneIDs(i);
    -0066         highUsage.absUsage(end+1,1)    = usageData.absUsage(enzIdx(i));
    -0067         highUsage.capUsage(end+1,1)    = usageData.capUsage(enzIdx(i));
    -0068         highUsage.kcat(end+1,1)        = nan;
    -0069         highUsage.source{end+1,1}      = '===';
    -0070         highUsage.rxnID{end+1,1}       = '===';
    -0071         highUsage.rxnNames{end+1,1}    = 'involved in multiple rxns, usage combined, individual rxns below';
    -0072         highUsage.grRules{end+1,1}     = '===';
    -0073         % Recalculate reaction-specific usage
    -0074 
    -0075         rIdx = rIdx(carriedFlux);
    -0076         enzFlux = usageData.fluxes(rIdx);
    -0077         enzMet = strcat('prot_',highEnzyme{i});
    -0078         [~, enzEcIdx] = ismember(enzMet,ecModel.mets);
    -0079         indAbsUse = full(transpose(-ecModel.S(enzEcIdx,rIdx)).*enzFlux);
    -0080         indCapUse = (indAbsUse /sum(indAbsUse)) * usageData.capUsage(enzIdx(i));
    -0081 
    -0082         rxnNumber = length(rIdx);
    -0083         highUsage.protID(end+1:end+rxnNumber,1)      = highEnzyme(i);
    -0084         highUsage.geneID(end+1:end+rxnNumber,1)      = geneIDs(i);
    -0085         highUsage.absUsage(end+1:end+rxnNumber,1)    = indAbsUse;
    -0086         highUsage.capUsage(end+1:end+rxnNumber,1)    = indCapUse;
    -0087         highUsage.kcat(end+1:end+rxnNumber,1)        = kcat(carriedFlux);
    -0088         highUsage.source(end+1:end+rxnNumber,1)      = ecModel.ec.source(idx(carriedFlux));
    -0089         highUsage.rxnID(end+1:end+rxnNumber,1)       = rxns(carriedFlux);
    -0090         highUsage.rxnNames(end+1:end+rxnNumber,1)    = rxnNames(carriedFlux);
    -0091         highUsage.grRules(end+1:end+rxnNumber,1)     = grRules(carriedFlux);
    -0092     end    
    -0093 end
    -0094 
    -0095 usageReport.highCapUsage = struct2table(highUsage);
    -0096 
    -0097 % Highest absolute usage
    -0098 [~,topUse]          = sort(usageData.absUsage,'descend');
    -0099 topEnzyme           = usageData.protID(topUse(1:topAbsUsage));
    -0100 [~,b]       = ismember(topEnzyme,ecModel.ec.enzymes);
    -0101 geneIDs     = ecModel.ec.genes(b);
    -0102 topUsage.protID     = {};
    -0103 topUsage.geneID     = {};
    -0104 topUsage.absUsage   = [];
    -0105 topUsage.percUsage  = [];
    -0106 topUsage.kcat       = [];
    -0107 topUsage.source     = {};
    -0108 topUsage.rxnID      = {};
    -0109 topUsage.rxnNames   = {};
    -0110 topUsage.grRules    = {};
    -0111 
    -0112 protPool = -ecModel.lb(strcmp(ecModel.rxns,'prot_pool_exchange'));
    -0113 
    -0114 for i=1:numel(topEnzyme)
    -0115     [rxns, kcat, idx, rxnNames, grRules] = getReactionsFromEnzyme(ecModel,topEnzyme{i});
    -0116     % See if all reactions carried flux
    -0117     [~,rIdx] = ismember(rxns,ecModel.rxns);
    -0118     carriedFlux = usageData.fluxes(rIdx) > 1e-7;
    -0119     if isscalar(find(carriedFlux))
    -0120         topUsage.protID(end+1,1)      = topEnzyme(i);
    -0121         topUsage.geneID(end+1,1)      = geneIDs(i);
    -0122         topUsage.absUsage(end+1,1)    = usageData.absUsage(topUse(i));
    -0123         topUsage.percUsage(end+1,1)   = topUsage.absUsage(end,1)/protPool*100;
    -0124         topUsage.kcat(end+1,1)        = kcat(carriedFlux);
    -0125         topUsage.source(end+1,1)      = ecModel.ec.source(idx(carriedFlux));
    -0126         topUsage.rxnID(end+1,1)       = rxns(carriedFlux);
    -0127         topUsage.rxnNames(end+1,1)    = rxnNames(carriedFlux);
    -0128         topUsage.grRules(end+1,1)     = grRules(carriedFlux);
    -0129     else
    -0130         % Add one entry for combined usage
    -0131         topUsage.protID(end+1,1)      = topEnzyme(i);
    -0132         topUsage.geneID(end+1,1)      = geneIDs(i);
    -0133         topUsage.absUsage(end+1,1)    = usageData.absUsage(topUse(i));
    -0134         topUsage.percUsage(end+1,1)   = topUsage.absUsage(end,1)/protPool*100;
    -0135         topUsage.kcat(end+1,1)        = nan;
    -0136         topUsage.source{end+1,1}      = '===';
    -0137         topUsage.rxnID{end+1,1}       = '===';
    -0138         topUsage.rxnNames{end+1,1}    = 'involved in multiple rxns, usage combined, individual rxns below';
    -0139         topUsage.grRules{end+1,1}     = '===';
    -0140         % Recalculate reaction-specific usage
    -0141         rIdx = rIdx(carriedFlux);
    -0142         enzFlux = usageData.fluxes(rIdx);
    -0143         enzMet = strcat('prot_',topEnzyme{i});
    -0144         [~, enzIdx] = ismember(enzMet,ecModel.mets);
    -0145         indUse = full(transpose(-ecModel.S(enzIdx,rIdx)).*enzFlux);
    -0146         rxnNumber = length(rIdx);
    -0147         topUsage.protID(end+1:end+rxnNumber,1)      = topEnzyme(i);
    -0148         topUsage.geneID(end+1:end+rxnNumber,1)      = geneIDs(i);
    -0149         topUsage.absUsage(end+1:end+rxnNumber,1)    = indUse;
    -0150         topUsage.percUsage(end+1:end+rxnNumber,1)   = topUsage.absUsage(end-(rxnNumber-1):end,1)/protPool*100;
    -0151         topUsage.kcat(end+1:end+rxnNumber,1)        = kcat(carriedFlux);
    -0152         topUsage.source(end+1:end+rxnNumber,1)      = ecModel.ec.source(idx(carriedFlux));
    -0153         topUsage.rxnID(end+1:end+rxnNumber,1)       = rxns(carriedFlux);
    -0154         topUsage.rxnNames(end+1:end+rxnNumber,1)    = rxnNames(carriedFlux);
    -0155         topUsage.grRules(end+1:end+rxnNumber,1)     = grRules(carriedFlux);
    -0156     end
    -0157 end
    -0158 usageReport.topAbsUsage     = struct2table(topUsage);
    -0159 usageReport.totalUsageFlux  = protPool;
    -0160 end
    -
    Generated by m2html © 2005
    - - \ No newline at end of file diff --git a/doc/src/geckomat/utilities/saveEcModel.html b/doc/src/geckomat/utilities/saveEcModel.html deleted file mode 100644 index 304a2d2f..00000000 --- a/doc/src/geckomat/utilities/saveEcModel.html +++ /dev/null @@ -1,137 +0,0 @@ - - - - Description of saveEcModel - - - - - - - - - -
    Home > src > geckomat > utilities > saveEcModel.m
    - - - -

    saveEcModel -

    - -

    PURPOSE ^

    -
    saveECmodel
    - -

    SYNOPSIS ^

    -
    function saveEcModel(ecModel,filename,modelAdapter)
    - -

    DESCRIPTION ^

    -
     saveECmodel
    -   Saves the ecModel in either YAML format (= default and preferred, as
    -   all ecModel content is reserved) and/or SBML format (= more widely
    -   compatible with other constraint-based modelling tools, can be used for
    -   running simulations like FBA etc., but this model cannot be loaded back
    -   into MATLAB for applying further GECKO functions, as model.ec is lost).
    -
    -   The ecModel is saved to the ecModel-specific models/ subfolder. For
    -   saving to other locations, writeYAMLmodel or exportModel are more
    -   suitable.
    -
    - Input:
    -   ecModel         an ecModel in GECKO 3 format (with ecModel.ec structure)
    -   filename        ending with either .yml or .xml, specifying if the
    -                   ecModel should be saved in YAML or SBML file format. If
    -                   no file extension is given, the ecModel will be saved
    -                   in YAML format. If no filename is given, 'ecModel.yml'
    -                   is used.
    -   modelAdapter    a loaded model adapter, from where the model folder is
    -                   read (Optional, will otherwise use the default model adapter).
    -
    - Usage:
    -   saveECmodel(ecModel,filename,modelAdapter)
    - - -

    CROSS-REFERENCE INFORMATION ^

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

    SOURCE CODE ^

    -
    0001 function saveEcModel(ecModel,filename,modelAdapter)
    -0002 % saveECmodel
    -0003 %   Saves the ecModel in either YAML format (= default and preferred, as
    -0004 %   all ecModel content is reserved) and/or SBML format (= more widely
    -0005 %   compatible with other constraint-based modelling tools, can be used for
    -0006 %   running simulations like FBA etc., but this model cannot be loaded back
    -0007 %   into MATLAB for applying further GECKO functions, as model.ec is lost).
    -0008 %
    -0009 %   The ecModel is saved to the ecModel-specific models/ subfolder. For
    -0010 %   saving to other locations, writeYAMLmodel or exportModel are more
    -0011 %   suitable.
    -0012 %
    -0013 % Input:
    -0014 %   ecModel         an ecModel in GECKO 3 format (with ecModel.ec structure)
    -0015 %   filename        ending with either .yml or .xml, specifying if the
    -0016 %                   ecModel should be saved in YAML or SBML file format. If
    -0017 %                   no file extension is given, the ecModel will be saved
    -0018 %                   in YAML format. If no filename is given, 'ecModel.yml'
    -0019 %                   is used.
    -0020 %   modelAdapter    a loaded model adapter, from where the model folder is
    -0021 %                   read (Optional, will otherwise use the default model adapter).
    -0022 %
    -0023 % Usage:
    -0024 %   saveECmodel(ecModel,filename,modelAdapter)
    -0025 
    -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.getParameters();
    -0034 if nargin < 2 || isempty(filename)
    -0035     filename = 'ecModel';
    -0036 end
    -0037 filename = fullfile(params.path,'models',filename);
    -0038 
    -0039 ecModel.description = ['Enzyme-constrained model of ' ecModel.id];
    -0040 
    -0041 switch filename(end-3:end)
    -0042     case {'.xml','sbml'}
    -0043         exportModel(ecModel, filename);
    -0044         %Convert notation "e-005" to "e-05 " in stoich. coeffs. to avoid
    -0045         %inconsistencies between Windows and MAC:
    -0046         copyfile(filename,'backup.xml')
    -0047         fin  = fopen('backup.xml', 'r');
    -0048         fout = fopen(filename, 'w');
    -0049         still_reading = true;
    -0050         while still_reading
    -0051             inline = fgets(fin);
    -0052             if ~ischar(inline)
    -0053                 still_reading = false;
    -0054             else
    -0055                 if ~isempty(regexp(inline,'-00[0-9]','once'))
    -0056                     inline = strrep(inline,'-00','-0');
    -0057                 elseif ~isempty(regexp(inline,'-01[0-9]','once'))
    -0058                     inline = strrep(inline,'-01','-1');
    -0059                 end
    -0060                 fwrite(fout, inline);
    -0061             end
    -0062         end
    -0063         fclose('all');
    -0064         delete('backup.xml');
    -0065     otherwise % Assume YAML
    -0066         writeYAMLmodel(ecModel,filename);
    -0067 end
    -0068 end
    -
    Generated by m2html © 2005
    - - \ No newline at end of file diff --git a/doc/src/geckomat/utilities/startGECKOproject.html b/doc/src/geckomat/utilities/startGECKOproject.html deleted file mode 100644 index 190d5b0d..00000000 --- a/doc/src/geckomat/utilities/startGECKOproject.html +++ /dev/null @@ -1,120 +0,0 @@ - - - - Description of startGECKOproject - - - - - - - - - -
    Home > src > geckomat > utilities > startGECKOproject.m
    - - - -

    startGECKOproject -

    - -

    PURPOSE ^

    -
    startGECKOproject
    - -

    SYNOPSIS ^

    -
    function startGECKOproject(name, path)
    - -

    DESCRIPTION ^

    -
     startGECKOproject
    -   Function that create a basic project structure for GECKO. If a project
    -   with the same name exits, the project will not be created
    -
    - Input:
    -   name               an name for the folder struture used in GECKO. Also
    -                      creates a basic adapter class, which must be manually
    -                      adjusted. If not defined, a dialog box will appear.
    -   path               a path where to create the folder. If not defined, a
    -                      dialog box will appear.
    -
    - Usage:
    -   startGECKOproject(name, path)
    - - -

    CROSS-REFERENCE INFORMATION ^

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

    SOURCE CODE ^

    -
    0001 function startGECKOproject(name, path)
    -0002 % startGECKOproject
    -0003 %   Function that create a basic project structure for GECKO. If a project
    -0004 %   with the same name exits, the project will not be created
    -0005 %
    -0006 % Input:
    -0007 %   name               an name for the folder struture used in GECKO. Also
    -0008 %                      creates a basic adapter class, which must be manually
    -0009 %                      adjusted. If not defined, a dialog box will appear.
    -0010 %   path               a path where to create the folder. If not defined, a
    -0011 %                      dialog box will appear.
    -0012 %
    -0013 % Usage:
    -0014 %   startGECKOproject(name, path)
    -0015 
    -0016 if nargin < 1 || isempty(name)
    -0017     prompt = {'Please provide a project name (e.g. ecYeastGEM)'};
    -0018     dlgtitle = 'Project name';
    -0019     dims = [1 100];
    -0020     definput = {'ecModelGEM'};
    -0021     opts.Interpreter = 'tex';
    -0022     name = inputdlg(prompt,dlgtitle,dims,definput,opts);
    -0023     name = char(name);
    -0024 end
    -0025 
    -0026 if nargin < 2 || isempty(path)
    -0027     path = uigetdir('Project Folder path');
    -0028 end
    -0029 
    -0030 fullPath = fullfile(path, name);
    -0031 % Validate if the project does not exits
    -0032 if ~exist(fullPath, 'dir')
    -0033     % Create the subfolder
    -0034     dir = {'code', 'data', 'models', 'output'};
    -0035     for i = 1:length(dir)
    -0036         status = mkdir(fullPath, dir{i});
    -0037         fid = fopen(fullfile(fullPath, dir{i}, '.keep'), 'w');
    -0038         fclose(fid);
    -0039     end
    -0040 
    -0041     % Read the template adapter class
    -0042     fid = fopen(fullfile(findGECKOroot, 'src', 'geckomat', ...
    -0043         'model_adapter', 'adapterTemplate.m'));
    -0044     f = fread(fid, '*char')';
    -0045     fclose(fid);
    -0046 
    -0047     % Replace key values
    -0048     f = strrep(f, 'KEY_CLASSNAME', [name 'Adapter']);
    -0049     f = strrep(f, 'KEY_PATH', path);
    -0050     f = strrep(f, 'KEY_NAME', name);
    -0051 
    -0052     % Save the class file
    -0053     filename = fullfile(path, name, [name 'Adapter.m']);
    -0054     fid = fopen(filename, 'w');
    -0055     fwrite(fid, f);
    -0056     fclose(fid);
    -0057 else
    -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
    -
    Generated by m2html © 2005
    - - \ No newline at end of file diff --git a/doc/src/geckomat/utilities/updateGECKOdoc.html b/doc/src/geckomat/utilities/updateGECKOdoc.html deleted file mode 100644 index 52d4bb00..00000000 --- a/doc/src/geckomat/utilities/updateGECKOdoc.html +++ /dev/null @@ -1,88 +0,0 @@ - - - - Description of updateGECKOdoc - - - - - - - - - -
    Home > src > geckomat > utilities > updateGECKOdoc.m
    - - - -

    updateGECKOdoc -

    - -

    PURPOSE ^

    -
    updateGeckoDoc
    - -

    SYNOPSIS ^

    -
    function updateGECKOdoc()
    - -

    DESCRIPTION ^

    -
     updateGeckoDoc
    -    Updates HTML documentation files for all geckomat GECKO functions. Uses the
    -   m2html functions that are provided with RAVEN.
    -
    - Usage: updateGECKOdoc()
    - - -

    CROSS-REFERENCE INFORMATION ^

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

    SOURCE CODE ^

    -
    0001 function updateGECKOdoc()
    -0002 % updateGeckoDoc
    -0003 %    Updates HTML documentation files for all geckomat GECKO functions. Uses the
    -0004 %   m2html functions that are provided with RAVEN.
    -0005 %
    -0006 % Usage: updateGECKOdoc()
    -0007 
    -0008 %Make sure that RAVEN-provided m2html is used
    -0009 ravenDir=findRAVENroot();
    -0010 path(fullfile(ravenDir,'software','m2html'),path);
    -0011 
    -0012 %Get the GECKO path
    -0013 geckoDir=findGECKOroot();
    -0014 
    -0015 %Remove old doc directory
    -0016 rmdir(fullfile(geckoDir,'doc'),'s');
    -0017 
    -0018 %Get a non-redundant list of GECKO subdirectories containing MATLAB
    -0019 %functions. Absolute paths are not compatible with M2HTML, so convert them
    -0020 %to the relative paths instead.
    -0021 geckoDirs=dir(fullfile(geckoDir,'src','geckomat','**/*.m'));
    -0022 geckoDirs=unique({geckoDirs.folder})';
    -0023 
    -0024 %Make relative path
    -0025 relStart = numel(geckoDir)+2;
    -0026 for i=1:numel(geckoDirs)
    -0027     geckoDirs{i,1} = geckoDirs{i,1}(relStart:end);
    -0028 end
    -0029 
    -0030 %Save the current working directory and go to RAVEN root directory
    -0031 originalDir=pwd;
    -0032 cd(geckoDir);
    -0033 %Generate HTML documentation files for RAVEN MATLAB functions
    -0034 m2html('mFiles',geckoDirs,'htmldir','doc');
    -0035 %Go back to the original working directory
    -0036 cd(originalDir);
    -0037 end
    -
    Generated by m2html © 2005
    - - \ No newline at end of file diff --git a/doc/src/get_enzyme_data/applyECcodes.html b/doc/src/get_enzyme_data/applyECcodes.html new file mode 100644 index 00000000..e6804063 --- /dev/null +++ b/doc/src/get_enzyme_data/applyECcodes.html @@ -0,0 +1,133 @@ + + + + Description of applyECcodes + + + + + + + + + +
    Home > src > get_enzyme_data > applyECcodes.m
    + + + +

    applyECcodes +

    + +

    PURPOSE ^

    +
    applyECcodes Copy EC numbers from ecModel.ec.eccodes to ecModel.eccodes.
    + +

    SYNOPSIS ^

    +
    function ecModel = applyECcodes(ecModel, varargin)
    + +

    DESCRIPTION ^

    +
     applyECcodes  Copy EC numbers from ecModel.ec.eccodes to ecModel.eccodes.
    +
    + Copies the EC numbers stored in the ecModel.ec structure across to the
    + top-level ecModel.eccodes field.
    +
    + Parameters
    + ----------
    + ecModel : struct
    +     an ecModel in GECKO 3 format (with ecModel.ec structure).
    +
    + Name-Value Arguments
    + --------------------
    + overwrite : logical
    +     whether existing (non-empty) ecModel.eccodes entries should be
    +     overwritten by a non-empty ecModel.ec.eccodes entry. Empty
    +     ecModel.eccodes entries are always overwritten if possible (default
    +     false). An empty ecModel.ec.eccodes source entry is never copied, so
    +     it can never erase an existing annotation.
    +
    + Returns
    + -------
    + ecModel : struct
    +     ecModel with populated model.eccodes.
    +
    + Examples
    + --------
    +     % optional arguments may be given positionally or as name-value pairs:
    +     ecModel = applyECcodes(ecModel, true);
    +     ecModel = applyECcodes(ecModel, 'overwrite', true);
    + + +

    CROSS-REFERENCE INFORMATION ^

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

    SOURCE CODE ^

    +
    0001 function ecModel = applyECcodes(ecModel, varargin)
    +0002 % applyECcodes  Copy EC numbers from ecModel.ec.eccodes to ecModel.eccodes.
    +0003 %
    +0004 % Copies the EC numbers stored in the ecModel.ec structure across to the
    +0005 % top-level ecModel.eccodes field.
    +0006 %
    +0007 % Parameters
    +0008 % ----------
    +0009 % ecModel : struct
    +0010 %     an ecModel in GECKO 3 format (with ecModel.ec structure).
    +0011 %
    +0012 % Name-Value Arguments
    +0013 % --------------------
    +0014 % overwrite : logical
    +0015 %     whether existing (non-empty) ecModel.eccodes entries should be
    +0016 %     overwritten by a non-empty ecModel.ec.eccodes entry. Empty
    +0017 %     ecModel.eccodes entries are always overwritten if possible (default
    +0018 %     false). An empty ecModel.ec.eccodes source entry is never copied, so
    +0019 %     it can never erase an existing annotation.
    +0020 %
    +0021 % Returns
    +0022 % -------
    +0023 % ecModel : struct
    +0024 %     ecModel with populated model.eccodes.
    +0025 %
    +0026 % Examples
    +0027 % --------
    +0028 %     % optional arguments may be given positionally or as name-value pairs:
    +0029 %     ecModel = applyECcodes(ecModel, true);
    +0030 %     ecModel = applyECcodes(ecModel, 'overwrite', true);
    +0031 
    +0032 p = parseGECKOargs(varargin, { ...
    +0033     'overwrite', false});
    +0034 overwrite = p.overwrite;
    +0035 
    +0036 if ~isfield(ecModel.ec,'eccodes')
    +0037     error('ecModel.ec.eccodes does not exist')
    +0038 end
    +0039 
    +0040 [a,b] = ismember(ecModel.rxns,ecModel.ec.rxns);
    +0041 if ~isfield(ecModel,'eccodes')
    +0042     ecModel.eccodes = cell(numel(ecModel.rxns),1);
    +0043 end
    +0044 
    +0045 if overwrite
    +0046     % Never overwrite an existing eccodes entry with an empty source: an
    +0047     % unset ec.eccodes value means "no info to copy", not "clear the
    +0048     % annotation".
    +0049     nonEmptySource = false(size(a));
    +0050     nonEmptySource(a) = ~cellfun(@isempty, ecModel.ec.eccodes(b(a)));
    +0051     a = a & nonEmptySource;
    +0052     ecModel.eccodes(a) = ecModel.ec.eccodes(b(a));
    +0053 else % Only replace emptyEcCodes
    +0054     emptyEcCodes = cellfun(@isempty, ecModel.eccodes);
    +0055     a = a & emptyEcCodes;
    +0056     ecModel.eccodes(a) = ecModel.ec.eccodes(b(a));
    +0057 end
    +0058 end
    +
    Generated by m2html © 2005
    + + \ No newline at end of file diff --git a/doc/src/get_enzyme_data/calculateMW.html b/doc/src/get_enzyme_data/calculateMW.html new file mode 100644 index 00000000..5726c557 --- /dev/null +++ b/doc/src/get_enzyme_data/calculateMW.html @@ -0,0 +1,148 @@ + + + + Description of calculateMW + + + + + + + + + +
    Home > src > get_enzyme_data > calculateMW.m
    + + + +

    calculateMW +

    + +

    PURPOSE ^

    +
    calculateMW Calculate the molecular weight of a protein.
    + +

    SYNOPSIS ^

    +
    function MW = calculateMW(sequence)
    + +

    DESCRIPTION ^

    +
     calculateMW  Calculate the molecular weight of a protein.
    +
    + Calculates the molecular weight of a protein from its amino acid sequence.
    + Matching is case-insensitive. Sequences with no recognized residue
    + (including an empty sequence) return NaN, rather than being mistaken for
    + an 18 Da protein.
    +
    + Parameters
    + ----------
    + sequence : char
    +     the amino acid sequence (can include extra things such as spaces or
    +     numbers, which are ignored).
    +
    + Returns
    + -------
    + MW : double
    +     the molecular weight in Da, or NaN if no residue was recognized.
    + + +

    CROSS-REFERENCE INFORMATION ^

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

    SOURCE CODE ^

    +
    0001 function MW = calculateMW(sequence)
    +0002 % calculateMW  Calculate the molecular weight of a protein.
    +0003 %
    +0004 % Calculates the molecular weight of a protein from its amino acid sequence.
    +0005 % Matching is case-insensitive. Sequences with no recognized residue
    +0006 % (including an empty sequence) return NaN, rather than being mistaken for
    +0007 % an 18 Da protein.
    +0008 %
    +0009 % Parameters
    +0010 % ----------
    +0011 % sequence : char
    +0012 %     the amino acid sequence (can include extra things such as spaces or
    +0013 %     numbers, which are ignored).
    +0014 %
    +0015 % Returns
    +0016 % -------
    +0017 % MW : double
    +0018 %     the molecular weight in Da, or NaN if no residue was recognized.
    +0019 
    +0020 % A    Alanine
    +0021 % B    Aspartic acid or Asparagine
    +0022 % C    Cysteine
    +0023 % D    Aspartic acid
    +0024 % E    Glutamic acid
    +0025 % F    Phenylalanine
    +0026 % G    Glycine
    +0027 % H    Histidine
    +0028 % I    Isoleucine
    +0029 % J    Leucine or Isoleucine
    +0030 % K    Lysine
    +0031 % L    Leucine
    +0032 % M    Methionine
    +0033 % N    Asparagine
    +0034 % O    Pyrrolysine
    +0035 % P    Proline
    +0036 % Q    Glutamine
    +0037 % R    Arginine
    +0038 % S    Serine
    +0039 % T    Threonine
    +0040 % U    Selenocysteine
    +0041 % V    Valine
    +0042 % W    Tryptophan
    +0043 % X    any
    +0044 % Y    Tyrosine
    +0045 % Z    Glutamic acid or Glutamine
    +0046 
    +0047 % The 20 standard residues, individually sourced.
    +0048 aa_codes = {'A','C','D','E','F','G','H','I','K','L','M','N','P','Q','R', ...
    +0049             'S','T','V','W','Y'};
    +0050 aa_MWs   = [71.08 103.14 115.09 129.11 147.17 57.05 137.14 113.16 128.17 ...
    +0051             113.16 131.20 114.10 97.12 128.13 156.19 87.08 101.10 99.13 ...
    +0052             186.21 163.17];
    +0053 
    +0054 % Ambiguous / non-standard codes, derived from the standard table above
    +0055 % rather than pre-rounded constants: B/Z average their two possible
    +0056 % residues, X averages across all 20 standard residues, J is Leu-or-Ile
    +0057 % (both 113.16, so either index gives the same value), O/U have no
    +0058 % standard-residue equivalent and keep their literature values.
    +0059 bMW = mean(aa_MWs(ismember(aa_codes,{'D','N'})));
    +0060 zMW = mean(aa_MWs(ismember(aa_codes,{'E','Q'})));
    +0061 xMW = mean(aa_MWs);
    +0062 jMW = aa_MWs(strcmp(aa_codes,'L'));
    +0063 
    +0064 allCodes = [aa_codes, {'B','J','O','U','X','Z'}];
    +0065 allMWs   = [aa_MWs, bMW, jMW, 255.31, 150.04, xMW, zMW];
    +0066 
    +0067 % Average mass of water (g/mol): the two H atoms and one OH that remain
    +0068 % after peptide bond condensation.
    +0069 waterMW = 18.01528;
    +0070 
    +0071 sequence = upper(sequence);
    +0072 MW = waterMW;
    +0073 nMatched = 0;
    +0074 for i = 1:length(allCodes)
    +0075     count = length(strfind(sequence,allCodes{i}));
    +0076     MW = MW + count*allMWs(i);
    +0077     nMatched = nMatched + count;
    +0078 end
    +0079 if nMatched == 0
    +0080     MW = NaN;
    +0081 end
    +0082 
    +0083 end
    +0084 
    +0085 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
    +
    Generated by m2html © 2005
    + + \ No newline at end of file diff --git a/doc/src/get_enzyme_data/findECInDB.html b/doc/src/get_enzyme_data/findECInDB.html new file mode 100644 index 00000000..5db9a685 --- /dev/null +++ b/doc/src/get_enzyme_data/findECInDB.html @@ -0,0 +1,302 @@ + + + + Description of findECInDB + + + + + + + + + +
    Home > src > get_enzyme_data > findECInDB.m
    + + + +

    findECInDB +

    + +

    PURPOSE ^

    +
    findECInDB Look up EC numbers for a reaction's gene set in a UniProt or KEGG index.
    + +

    SYNOPSIS ^

    +
    function [EC,conflicts] = findECInDB(gene_set, DBecNum, DBMW, geneIndex, geneHashMap)
    + +

    DESCRIPTION ^

    +
     findECInDB  Look up EC numbers for a reaction's gene set in a UniProt or KEGG index.
    +
    + For each gene, finds its matching database entries and takes the EC number
    + of the lightest-weight matching protein when a single EC number applies to
    + that gene; genes with several distinct EC numbers among their matches are
    + also reported as conflicts (the first match is still used for EC). Genes
    + without an EC number are left out. When gene_set has more than one gene
    + (an enzyme complex), the numbers found for each gene are combined by
    + intersection where they share a match (a wildcard such as "1.1.1.-" matches
    + the specific codes of its prefix), otherwise by union. The EC set of every
    + gene set, one gene or a complex, is cleaned of a wildcard code such as
    + "1.1.1.-" when a more specific code of the same prefix ("1.1.1.4") is
    + present; only codes with four levels take part, and empty codes are removed.
    +
    + Parameters
    + ----------
    + gene_set : cell
    +     genes from a given metabolic reaction.
    + DBecNum : cell
    +     array of EC numbers.
    + DBMW : double
    +     array of molecular weights in Da.
    + geneIndex : cell
    +     as generated by getECfromDatabase.
    + geneHashMap : containers.Map
    +     as generated by getECfromDatabase.
    +
    + Returns
    + -------
    + EC : char
    +     EC numbers that apply to gene_set, each prefixed with "EC" and
    +     separated by ";" (e.g. "EC1.1.1.1;EC1.1.1.2").
    + conflicts : cell
    +     genes with multiple protein matches.
    +
    + Examples
    + --------
    +     [EC, conflicts] = findECInDB(gene_set, DBecNum, DBMW, geneIndex, geneHashMap);
    +
    + See also
    + --------
    + getECfromDatabase, getECstring
    + + +

    CROSS-REFERENCE INFORMATION ^

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

    SUBFUNCTIONS ^

    + + +

    SOURCE CODE ^

    +
    0001 function [EC,conflicts] = findECInDB(gene_set, DBecNum, DBMW, geneIndex, geneHashMap)
    +0002 % findECInDB  Look up EC numbers for a reaction's gene set in a UniProt or KEGG index.
    +0003 %
    +0004 % For each gene, finds its matching database entries and takes the EC number
    +0005 % of the lightest-weight matching protein when a single EC number applies to
    +0006 % that gene; genes with several distinct EC numbers among their matches are
    +0007 % also reported as conflicts (the first match is still used for EC). Genes
    +0008 % without an EC number are left out. When gene_set has more than one gene
    +0009 % (an enzyme complex), the numbers found for each gene are combined by
    +0010 % intersection where they share a match (a wildcard such as "1.1.1.-" matches
    +0011 % the specific codes of its prefix), otherwise by union. The EC set of every
    +0012 % gene set, one gene or a complex, is cleaned of a wildcard code such as
    +0013 % "1.1.1.-" when a more specific code of the same prefix ("1.1.1.4") is
    +0014 % present; only codes with four levels take part, and empty codes are removed.
    +0015 %
    +0016 % Parameters
    +0017 % ----------
    +0018 % gene_set : cell
    +0019 %     genes from a given metabolic reaction.
    +0020 % DBecNum : cell
    +0021 %     array of EC numbers.
    +0022 % DBMW : double
    +0023 %     array of molecular weights in Da.
    +0024 % geneIndex : cell
    +0025 %     as generated by getECfromDatabase.
    +0026 % geneHashMap : containers.Map
    +0027 %     as generated by getECfromDatabase.
    +0028 %
    +0029 % Returns
    +0030 % -------
    +0031 % EC : char
    +0032 %     EC numbers that apply to gene_set, each prefixed with "EC" and
    +0033 %     separated by ";" (e.g. "EC1.1.1.1;EC1.1.1.2").
    +0034 % conflicts : cell
    +0035 %     genes with multiple protein matches.
    +0036 %
    +0037 % Examples
    +0038 % --------
    +0039 %     [EC, conflicts] = findECInDB(gene_set, DBecNum, DBMW, geneIndex, geneHashMap);
    +0040 %
    +0041 % See also
    +0042 % --------
    +0043 % getECfromDatabase, getECstring
    +0044 
    +0045 %Preallocate function variables
    +0046 conflicts = cell(1,2);
    +0047 
    +0048 %Split the gene set and match each gene:
    +0049 %gene_set  = strsplit(grRule,' and '); %this string splitting together with getSimpleGeneSets takes 2.6 s, that is ok.
    +0050 EC_set    = cell(size(gene_set));
    +0051 
    +0052 %find index indices of all genes in one call
    +0053 
    +0054 %this loop is slow
    +0055 for j = 1:length(gene_set)
    +0056      gene = gene_set{j};
    +0057      matches = [];
    +0058      %Get the indexes for all of the proteins related to gene
    +0059      if isKey(geneHashMap,gene) %annoyingly, this seems to be needed
    +0060          matchInd = cell2mat(values(geneHashMap,gene_set(j)));
    +0061          matches = geneIndex{matchInd};
    +0062      end
    +0063      if ~isempty(matches)
    +0064         %Get the indexes of the matched protein(s) with non-empty EC#s
    +0065         nonEmpty = matches(~cellfun(@isempty,DBecNum(matches)));
    +0066         if ~isempty(nonEmpty)
    +0067             [geneECs,ia] = unique(DBecNum(nonEmpty),'stable');
    +0068             %For genes with multiple proteins associated to several
    +0069             %non-empty ecNumbers
    +0070             if length(geneECs)>1
    +0071                 indexes = nonEmpty(ia);
    +0072                 ecNum = DBecNum(indexes);
    +0073                 %Save first match
    +0074                 EC_set{j}  = getECstring(EC_set{j},ecNum{1});
    +0075                 %Save additional matches as potential conflicts
    +0076                 if ~ismember(gene,conflicts{1})
    +0077                     conflicts{1} = [conflicts{1}; {gene}];
    +0078                     conflicts{2} = [conflicts{2}; {indexes}]; 
    +0079                 end
    +0080             else
    +0081                 %If there is a single unique ec number for the matched
    +0082                 %protein(s), then choose the lightest protein
    +0083                 [~,minW]   = min(DBMW(nonEmpty));
    +0084                 matches    = nonEmpty(minW);
    +0085                 EC_set{j}  = getECstring(EC_set{j},DBecNum{matches});
    +0086             end
    +0087         end
    +0088     end
    +0089 
    +0090     if isempty(EC_set{j})
    +0091         EC_set{j} = '';
    +0092     end
    +0093 end
    +0094 
    +0095 %EC: Split the codes of each gene, leave out the genes without any, and
    +0096 %combine the rest (union and intersection only apply for complexes, i.e. more
    +0097 %than one gene with codes):
    +0098 tokens = cell(size(EC_set));
    +0099 for j = 1:length(EC_set)
    +0100     codes     = strsplit(EC_set{j},' ');
    +0101     tokens{j} = codes(~cellfun(@isempty,codes));
    +0102 end
    +0103 tokens = tokens(~cellfun(@isempty,tokens));
    +0104 if isempty(tokens)
    +0105     EC_set = {};
    +0106 elseif isscalar(tokens)
    +0107     EC_set = dropWildcardParents(tokens{1});
    +0108 else
    +0109     uni_EC = tokens{1};
    +0110     int_EC = tokens{1};
    +0111     for j = 2:length(tokens)
    +0112         uni_EC = dropWildcardParents([uni_EC tokens{j}]);
    +0113         int_EC = wildcardIntersection(int_EC,tokens{j});
    +0114     end
    +0115     %Use the intersection found, if any. If not, use the union:
    +0116     if isempty(int_EC)
    +0117         EC_set = uni_EC;
    +0118     else
    +0119         EC_set = int_EC;
    +0120     end
    +0121     EC_set = dropWildcardParents(EC_set);
    +0122 end
    +0123 
    +0124 %Add new codes as new possible isozymes and remove the initial "EC" text:
    +0125 
    +0126 for i = 1:length(EC_set)
    +0127    if ~isempty(EC_set{i}) 
    +0128        EC_set{i} = extractAfter(EC_set{i},2);%remove 2 first chars
    +0129    end
    +0130 end
    +0131 
    +0132 %EC_set = cellfun(@(x) extractAfter(x,2),EC_set,'UniformOutput',false);%remove 2 first chars
    +0133 if isempty(EC_set)
    +0134     EC = '';
    +0135 else
    +0136     EC = strjoin(EC_set,';');
    +0137 end
    +0138 
    +0139 
    +0140 %Delete repeated Uniprots (and the corresponding ECs):
    +0141 %EC(deleted)   = []; %Not sure if this needs to be done somehow, don't think so
    +0142 
    +0143 end
    +0144 
    +0145 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
    +0146 function int_EC = wildcardIntersection(prev_EC,new_EC)
    +0147 %Finds the common elements between two cell arrays, if any. Also considers
    +0148 %wildcards (e.g. if 'EC1.1.1.1' is in one array and 'EC1.1.1.-' is in the
    +0149 %other one, then 'EC1.1.1.1' is added to the intersection). A pair adds its
    +0150 %code only when one code of the pair is the wildcard parent of the other, or
    +0151 %the two are equal four-level codes.
    +0152 int_EC = {};
    +0153 for i = 1:length(prev_EC)
    +0154     for j = 1:length(new_EC)
    +0155         survivors = dropWildcardParents({prev_EC{i} new_EC{j}});
    +0156         if length(survivors) == 1
    +0157             int_EC = [int_EC survivors];
    +0158         end
    +0159     end
    +0160 end
    +0161 end
    +0162 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
    +0163 function int_EC = dropWildcardParents(EC)
    +0164 %Removes empty codes and every code that is a wildcard parent of another
    +0165 %code in the cell array (e.g. 'EC1.2.3.-' when 'EC1.2.3.4' is present). Only
    +0166 %codes with four levels are compared, so 'EC1.1.1' is neither a parent nor a
    +0167 %child of 'EC1.1.1.4'. Equal codes collapse to the first.
    +0168 EC = EC(~cellfun(@isempty,EC) & ~strcmp(EC,'EC'));
    +0169 keep = true(1,numel(EC));
    +0170 for i = 1:numel(EC)
    +0171     if ~keep(i)
    +0172         continue;
    +0173     end
    +0174     for j = i+1:numel(EC)
    +0175         if ~keep(j)
    +0176             continue;
    +0177         end
    +0178         iInJ = subsumes(EC{i},EC{j});
    +0179         jInI = subsumes(EC{j},EC{i});
    +0180         if iInJ && jInI
    +0181             keep(j) = false;
    +0182         elseif iInJ
    +0183             keep(i) = false;
    +0184             break;
    +0185         elseif jInI
    +0186             keep(j) = false;
    +0187         end
    +0188     end
    +0189 end
    +0190 int_EC = EC(keep);
    +0191 end
    +0192 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
    +0193 function tf = subsumes(general,specific)
    +0194 %True if the code general is equal to or a wildcard parent of the code
    +0195 %specific; both carry the "EC" prefix and need four levels.
    +0196 general  = strsplit(extractAfter(general,2),'.');
    +0197 specific = strsplit(extractAfter(specific,2),'.');
    +0198 tf = false;
    +0199 if numel(general) ~= 4 || numel(specific) ~= 4
    +0200     return;
    +0201 end
    +0202 for k = 1:4
    +0203     if strcmp(general{k},'-')
    +0204         tf = true;
    +0205         return;
    +0206     end
    +0207     if strcmp(specific{k},'-') || ~strcmp(general{k},specific{k})
    +0208         return;
    +0209     end
    +0210 end
    +0211 tf = true;
    +0212 end
    +
    Generated by m2html © 2005
    + + \ No newline at end of file diff --git a/doc/src/get_enzyme_data/getECfromDatabase.html b/doc/src/get_enzyme_data/getECfromDatabase.html new file mode 100644 index 00000000..13327274 --- /dev/null +++ b/doc/src/get_enzyme_data/getECfromDatabase.html @@ -0,0 +1,297 @@ + + + + Description of getECfromDatabase + + + + + + + + + +
    Home > src > get_enzyme_data > getECfromDatabase.m
    + + + +

    getECfromDatabase +

    + +

    PURPOSE ^

    +
    getECfromDatabase Populate model.ec.eccodes from UniProt and KEGG databases.
    + +

    SYNOPSIS ^

    +
    function model = getECfromDatabase(model, varargin)
    + +

    DESCRIPTION ^

    +
     getECfromDatabase  Populate model.ec.eccodes from UniProt and KEGG databases.
    +
    + Populates the model.ec.eccodes field with enzyme codes that are extracted
    + from UniProt and KEGG databases, as assigned to the proteins that catalyze
    + the specific reactions.
    +
    + Parameters
    + ----------
    + model : struct
    +     an ecModel in GECKO 3 format (with ecModel.ec structure).
    +
    + Name-Value Arguments
    + --------------------
    + ecRxns : logical
    +     of length model.ec.rxns that specifies which model.ec.eccodes entries
    +     should be queried. Existing values in model.ec.eccodes will be wiped.
    +     Entries that are indicated by false will be kept and not modified by
    +     this function (by default all model.ec.eccodes entries are populated
    +     by this function).
    + action : char
    +     response action if multiple proteins with different EC numbers are
    +     found for a given gene in a metabolic reaction (default 'display'):
    +
    +     - 'display' displays all found multiplicities.
    +     - 'ignore' ignore multiplicities and use the protein with the lowest
    +       index in the database.
    +     - 'add' adds all the multiple proteins as isozymes for the given
    +       reaction.
    + modelAdapter : ModelAdapter
    +     a loaded model adapter (default: the current default model adapter).
    +
    + Returns
    + -------
    + model : struct
    +     ecModel with populated model.ec.eccodes.
    +
    + Examples
    + --------
    +     % optional arguments may be given positionally or as name-value pairs:
    +     model = getECfromDatabase(model, ecRxns, action, modelAdapter);
    +     model = getECfromDatabase(model, 'action', 'ignore');
    +
    + See also
    + --------
    + getECfromGEM, findECInDB, loadDatabases
    + + +

    CROSS-REFERENCE INFORMATION ^

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

    SUBFUNCTIONS ^

    + + +

    SOURCE CODE ^

    +
    0001 function model = getECfromDatabase(model, varargin)
    +0002 % getECfromDatabase  Populate model.ec.eccodes from UniProt and KEGG databases.
    +0003 %
    +0004 % Populates the model.ec.eccodes field with enzyme codes that are extracted
    +0005 % from UniProt and KEGG databases, as assigned to the proteins that catalyze
    +0006 % the specific reactions.
    +0007 %
    +0008 % Parameters
    +0009 % ----------
    +0010 % model : struct
    +0011 %     an ecModel in GECKO 3 format (with ecModel.ec structure).
    +0012 %
    +0013 % Name-Value Arguments
    +0014 % --------------------
    +0015 % ecRxns : logical
    +0016 %     of length model.ec.rxns that specifies which model.ec.eccodes entries
    +0017 %     should be queried. Existing values in model.ec.eccodes will be wiped.
    +0018 %     Entries that are indicated by false will be kept and not modified by
    +0019 %     this function (by default all model.ec.eccodes entries are populated
    +0020 %     by this function).
    +0021 % action : char
    +0022 %     response action if multiple proteins with different EC numbers are
    +0023 %     found for a given gene in a metabolic reaction (default 'display'):
    +0024 %
    +0025 %     - 'display' displays all found multiplicities.
    +0026 %     - 'ignore' ignore multiplicities and use the protein with the lowest
    +0027 %       index in the database.
    +0028 %     - 'add' adds all the multiple proteins as isozymes for the given
    +0029 %       reaction.
    +0030 % modelAdapter : ModelAdapter
    +0031 %     a loaded model adapter (default: the current default model adapter).
    +0032 %
    +0033 % Returns
    +0034 % -------
    +0035 % model : struct
    +0036 %     ecModel with populated model.ec.eccodes.
    +0037 %
    +0038 % Examples
    +0039 % --------
    +0040 %     % optional arguments may be given positionally or as name-value pairs:
    +0041 %     model = getECfromDatabase(model, ecRxns, action, modelAdapter);
    +0042 %     model = getECfromDatabase(model, 'action', 'ignore');
    +0043 %
    +0044 % See also
    +0045 % --------
    +0046 % getECfromGEM, findECInDB, loadDatabases
    +0047 
    +0048 p = parseGECKOargs(varargin, { ...
    +0049     'ecRxns',       []; ...
    +0050     'action',       'display'; ...
    +0051     'modelAdapter', []});
    +0052 ecRxns       = p.ecRxns;
    +0053 action       = p.action;
    +0054 modelAdapter = p.modelAdapter;
    +0055 
    +0056 if isempty(modelAdapter)
    +0057     modelAdapter = ModelAdapterManager.getDefault();
    +0058     if isempty(modelAdapter)
    +0059         error('Either send in a modelAdapter or set the default model adapter in the ModelAdapterManager.')
    +0060     end
    +0061 end
    +0062 params = modelAdapter.getParameters();
    +0063 
    +0064 rxnEnzMat = model.ec.rxnEnzMat;
    +0065 genes = modelAdapter.getUniprotCompatibleGenes(model.ec.genes);
    +0066 
    +0067 data    = loadDatabases('both', modelAdapter);
    +0068 uniprot = data.uniprot;
    +0069 kegg    = data.kegg;
    +0070 
    +0071 modelGenes = modelAdapter.getUniprotIDsFromTable(model.genes);
    +0072 DBgenesUniprot  = data.uniprot.genes;
    +0073 if ~isequal(modelGenes,model.genes)
    +0074     [Lia,Locb] = ismember(modelGenes,uniprot.ID);
    +0075     DBgenesUniprot(Locb(Lia)) = model.genes(Lia);
    +0076     keepEntry = unique(Locb(Lia));
    +0077     DBgenesUniprot = DBgenesUniprot(keepEntry);
    +0078 else
    +0079     keepEntry = true(numel(DBgenesUniprot),1);
    +0080 end
    +0081 DBecNumUniprot  = data.uniprot.eccodes(keepEntry);
    +0082 DBMWUniprot     = data.uniprot.MW(keepEntry);
    +0083 %Build an index from gene to prot for faster processing later
    +0084 [geneIndexUniprot,geneHashMapUniprot] = hashGeneToProt(DBgenesUniprot);
    +0085 
    +0086 if ~isempty(kegg)
    +0087     DBgenesKEGG     = data.kegg.genes;
    +0088     DBecNumKEGG     = data.kegg.eccodes;
    +0089     DBMWKEGG        = data.kegg.MW;
    +0090     [geneIndexKEGG,geneHashMapKEGG]       = hashGeneToProt(DBgenesKEGG);
    +0091 end
    +0092 n = size(rxnEnzMat,1);
    +0093 
    +0094 eccodes   = cell(n,1);
    +0095 eccodes(:)= {''};
    +0096 conflicts = cell(1,4);
    +0097 
    +0098 rxnEnzMat = logical(rxnEnzMat);
    +0099 PB = progressReport(n, 'Assigning EC numbers from database');
    +0100 for i = 1:n
    +0101     PB.count;
    +0102     gns = genes(rxnEnzMat(i,:).');
    +0103     if ~isempty(gns)
    +0104         %Find match in Uniprot:
    +0105         [new_EC,multGenes] = findECInDB(gns,DBecNumUniprot,DBMWUniprot,geneIndexUniprot,geneHashMapUniprot);
    +0106         if ~isempty(new_EC)
    +0107             DBase    = 'uniprot';
    +0108             if ~isempty(multGenes{1})
    +0109                 multGenes{3} = DBase;
    +0110             end
    +0111         end
    +0112         if ~isempty(kegg) && (isempty(new_EC) || endsWith(new_EC,'-'))
    +0113             %Find match in KEGG
    +0114             [new_EC_kegg,multGenes] = findECInDB(gns,DBecNumKEGG,DBMWKEGG,geneIndexKEGG,geneHashMapKEGG);
    +0115             if ~isempty(new_EC_kegg)
    +0116                 DBase    = 'kegg';
    +0117                 if ~isempty(multGenes{1})
    +0118                     multGenes{3} = DBase;
    +0119                 end
    +0120                 new_EC=new_EC_kegg;
    +0121             end
    +0122         end
    +0123         eccodes{i} = new_EC;
    +0124 
    +0125         if ~isempty(multGenes{1})
    +0126             %Rxn index
    +0127             conflicts{1} = [conflicts{1};i];
    +0128             %Gene IDs
    +0129             conflicts{2} = [conflicts{2};multGenes{1}];
    +0130             %Indexes in DB
    +0131             conflicts{3} = [conflicts{3};multGenes{2}];
    +0132             %DB name
    +0133             conflicts{4} = [conflicts{4};{multGenes{3}}];
    +0134 
    +0135             %{ I don't understand the purpose of this, let's skip it for now
    +0136             %if strcmpi(action,'add')
    +0137             %    if strcmpi(DBase,'swissprot')
    +0138             %        [uni,EC,MW,Genes] = addMultipleMatches(uni,EC,MW,Genes,multGenes,swissprot);
    +0139             %    elseif strcmpi(DBase,'KEGG')
    +0140             %        [uni,EC,MW,Genes] = addMultipleMatches(uni,EC,MW,Genes,multGenes,kegg);
    +0141             %    end
    +0142             %end
    +0143             %}
    +0144         end
    +0145     end
    +0146 end
    +0147 
    +0148 %Display error message with the multiple gene-protein matches found
    +0149 if strcmpi(action,'display') && ~isempty(conflicts{1})
    +0150     displayErrorMessage(conflicts,uniprot,kegg)
    +0151 end
    +0152 
    +0153 if isempty(ecRxns) || all(ecRxns)
    +0154     model.ec.eccodes = eccodes;
    +0155 else
    +0156     if ~isfield(model.ec,'eccodes')
    +0157         model.ec.eccodes(1:numel(model.ec.rxns),1) = {''};
    +0158     end
    +0159     %Probably faster to subset with ecRxns in the beginning of the script,
    +0160     %but this was at the moment simpler to implement.
    +0161     model.ec.eccodes(ecRxns) = eccodes(ecRxns);
    +0162 end
    +0163 
    +0164 function displayErrorMessage(conflicts,uniprot,kegg)
    +0165 STR = ['\n ' num2str(length(conflicts{1})) ' genes with multiple associated proteins were found, please'];
    +0166 STR = [STR, ' revise case by case in the uniprot and kegg files:\n\n'];
    +0167 for i=1:length(conflicts{1})
    +0168     if strcmpi(conflicts{4}{i},'uniprot')
    +0169         DB = uniprot.ID;
    +0170     else
    +0171         DB = kegg.uniprot;
    +0172     end
    +0173     proteins = DB(conflicts{3}{i});
    +0174     STR = [STR, '- gene: ' conflicts{2}{i} '  Proteins: ' strjoin(proteins) '\n'];
    +0175 end
    +0176 STR = [STR, '\nIf a wrongly annotated case was found then call the '];
    +0177 STR = [STR, 'getECfromDatabase.m function again with the option action'];
    +0178 STR = [STR, '= ignore\n\n'];
    +0179 STR = [STR, 'If the conflicting proteins are desired to be kept as isozymes'];
    +0180 STR = [STR, ' then call the getECfromDatabase.m function'];
    +0181 STR = [STR, ' again with the option action = add\n'];
    +0182 error(sprintf(STR))
    +0183 end
    +0184 
    +0185 function [geneIndex,geneHashMap]=hashGeneToProt(proteinDB)
    +0186 
    +0187 [x,y] = size(proteinDB);
    +0188 genesForIndex = reshape(proteinDB, x*y, 1);
    +0189 genesForIndex = genesForIndex(~cellfun(@isempty, genesForIndex));
    +0190 genesForIndex = unique(genesForIndex);
    +0191 geneIndex = cell(length(genesForIndex),1);
    +0192 geneHashMap = containers.Map(genesForIndex,1:length(genesForIndex));
    +0193 protIndices = 1:length(proteinDB(:,1));
    +0194 for i = 1:y
    +0195     tmp1 = proteinDB(:,i);
    +0196     sel = ~cellfun(@isempty, tmp1);
    +0197     indices = cell2mat(values(geneHashMap,tmp1(sel)));
    +0198     protIndicesSel = protIndices(sel);
    +0199     for j = 1:length(indices)
    +0200         geneIndex{indices(j)} = [geneIndex{indices(j)};protIndicesSel(j)];
    +0201     end
    +0202 end
    +0203 end
    +0204 end
    +
    Generated by m2html © 2005
    + + \ No newline at end of file diff --git a/doc/src/get_enzyme_data/getECfromGEM.html b/doc/src/get_enzyme_data/getECfromGEM.html new file mode 100644 index 00000000..f19a1369 --- /dev/null +++ b/doc/src/get_enzyme_data/getECfromGEM.html @@ -0,0 +1,179 @@ + + + + Description of getECfromGEM + + + + + + + + + +
    Home > src > get_enzyme_data > getECfromGEM.m
    + + + +

    getECfromGEM +

    + +

    PURPOSE ^

    +
    getECfromGEM Populate model.ec.eccodes from the model.eccodes field.
    + +

    SYNOPSIS ^

    +
    function [model, invalidEC, invalidECpos] = getECfromGEM(model, varargin)
    + +

    DESCRIPTION ^

    +
     getECfromGEM  Populate model.ec.eccodes from the model.eccodes field.
    +
    + Uses the model.eccodes to populate the model.ec.eccodes field. EC numbers
    + must be formatted as four numbers separated by periods, possibly with
    + trailing wildcards; incorrectly formatted EC numbers are skipped.
    +
    + Parameters
    + ----------
    + model : struct
    +     an ecModel in GECKO 3 format (with ecModel.ec structure).
    +
    + Name-Value Arguments
    + --------------------
    + ecRxns : logical
    +     of length model.ec.rxns that specifies for which reactions the
    +     existing model.ec.eccodes entry should be kept and not modified by
    +     this function (by default all model.ec.eccodes entries are populated
    +     by this function).
    +
    + Returns
    + -------
    + model : struct
    +     ecModel with populated model.ec.eccodes.
    + invalidEC : cell
    +     incorrectly formatted EC numbers.
    + invalidECpos : double
    +     position of invalidEC in model.eccodes.
    +
    + Notes
    + -----
    + Valid EC numbers are e.g. 1.2.3.4 or 1.2.3.-, while invalid EC numbers are
    + 1.2.3 or 1_2_3_4. Multiple EC numbers are separated by ; for instance
    + 1.2.3.4;1.2.3.5 not 1.2.3.4|1.2.3.5.
    +
    + Examples
    + --------
    +     % optional arguments may be given positionally or as name-value pairs:
    +     [model, invalidEC, invalidECpos] = getECfromGEM(model, ecRxns);
    +     [model, invalidEC, invalidECpos] = getECfromGEM(model, 'ecRxns', ecRxns);
    +
    + See also
    + --------
    + getECfromDatabase, applyECcodes
    + + +

    CROSS-REFERENCE INFORMATION ^

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

    SOURCE CODE ^

    +
    0001 function [model, invalidEC, invalidECpos] = getECfromGEM(model, varargin)
    +0002 % getECfromGEM  Populate model.ec.eccodes from the model.eccodes field.
    +0003 %
    +0004 % Uses the model.eccodes to populate the model.ec.eccodes field. EC numbers
    +0005 % must be formatted as four numbers separated by periods, possibly with
    +0006 % trailing wildcards; incorrectly formatted EC numbers are skipped.
    +0007 %
    +0008 % Parameters
    +0009 % ----------
    +0010 % model : struct
    +0011 %     an ecModel in GECKO 3 format (with ecModel.ec structure).
    +0012 %
    +0013 % Name-Value Arguments
    +0014 % --------------------
    +0015 % ecRxns : logical
    +0016 %     of length model.ec.rxns that specifies for which reactions the
    +0017 %     existing model.ec.eccodes entry should be kept and not modified by
    +0018 %     this function (by default all model.ec.eccodes entries are populated
    +0019 %     by this function).
    +0020 %
    +0021 % Returns
    +0022 % -------
    +0023 % model : struct
    +0024 %     ecModel with populated model.ec.eccodes.
    +0025 % invalidEC : cell
    +0026 %     incorrectly formatted EC numbers.
    +0027 % invalidECpos : double
    +0028 %     position of invalidEC in model.eccodes.
    +0029 %
    +0030 % Notes
    +0031 % -----
    +0032 % Valid EC numbers are e.g. 1.2.3.4 or 1.2.3.-, while invalid EC numbers are
    +0033 % 1.2.3 or 1_2_3_4. Multiple EC numbers are separated by ; for instance
    +0034 % 1.2.3.4;1.2.3.5 not 1.2.3.4|1.2.3.5.
    +0035 %
    +0036 % Examples
    +0037 % --------
    +0038 %     % optional arguments may be given positionally or as name-value pairs:
    +0039 %     [model, invalidEC, invalidECpos] = getECfromGEM(model, ecRxns);
    +0040 %     [model, invalidEC, invalidECpos] = getECfromGEM(model, 'ecRxns', ecRxns);
    +0041 %
    +0042 % See also
    +0043 % --------
    +0044 % getECfromDatabase, applyECcodes
    +0045 
    +0046 p = parseGECKOargs(varargin, { ...
    +0047     'ecRxns', []});
    +0048 ecRxns = p.ecRxns;
    +0049 
    +0050 if ~isfield(model,'eccodes')
    +0051     error('The model has no model.eccodes field.')
    +0052 end
    +0053 
    +0054 %Need to remove the prefix of GECKO light rxn names in the ec structure
    +0055 if ~model.ec.geckoLight
    +0056     rxnNames = model.ec.rxns;
    +0057 else
    +0058     rxnNames = extractAfter(model.ec.rxns, 4);
    +0059 end
    +0060 
    +0061 [~,rxnIdxs] = ismember(rxnNames,model.rxns);
    +0062 
    +0063 % Check if eccodes are valid. Each of the four dot-separated components must
    +0064 % be either a run of digits or the wildcard '-'; \w (the previous class) also
    +0065 % matches letters and underscores, so malformed codes such as '1.1.1.n12' or
    +0066 % '1_2_3_4' were incorrectly accepted.
    +0067 eccodes = model.eccodes;
    +0068 invalidEC = regexprep(eccodes,'(\d+\.(\d+|-)\.(\d+|-)\.(\d+|-))(;\d+\.(\d+|-)\.(\d+|-)\.(\d+|-))*(.*)','$3');
    +0069 invalidEC = ~cellfun(@isempty,invalidEC);
    +0070 invalidECpos = find(invalidEC);
    +0071 if any(invalidECpos)
    +0072     invalidEC = model.eccodes(invalidEC);
    +0073     if nargout<2
    +0074         fprintf('Skipped incorrectly formatted EC numbers, rerun getECfromGEM with all outputs to get a list.\n')
    +0075     else
    +0076         fprintf('Skipped incorrectly formatted EC numbers.\n')
    +0077     end
    +0078     eccodes(invalidECpos)={''};
    +0079 else
    +0080     invalidEC = [];
    +0081 end
    +0082 if isempty(ecRxns) || all(ecRxns)
    +0083     model.ec.eccodes = eccodes(rxnIdxs);
    +0084 else
    +0085     if ~isfield(model.ec,'eccodes')
    +0086         model.ec.eccodes(1:numel(model.ec.rxns),1) = {''};
    +0087     end
    +0088     model.ec.eccodes(ecRxns) = eccodes(rxnIdxs(ecRxns));
    +0089 end
    +0090 end
    +
    Generated by m2html © 2005
    + + \ No newline at end of file diff --git a/doc/src/get_enzyme_data/getECstring.html b/doc/src/get_enzyme_data/getECstring.html new file mode 100644 index 00000000..e5fc1e4f --- /dev/null +++ b/doc/src/get_enzyme_data/getECstring.html @@ -0,0 +1,110 @@ + + + + Description of getECstring + + + + + + + + + +
    Home > src > get_enzyme_data > getECstring.m
    + + + +

    getECstring +

    + +

    PURPOSE ^

    +
    getECstring Build a single string of EC numbers for a protein.
    + +

    SYNOPSIS ^

    +
    function EC_set = getECstring(EC_set,ecNumbers)
    + +

    DESCRIPTION ^

    +
     getECstring  Build a single string of EC numbers for a protein.
    +
    + Provides a single string with all the EC numbers associated to a given
    + protein, according to the following format:
    + "ECX.X.X.X ECX.X.X.X ECX.X.X.X".
    +
    + Parameters
    + ----------
    + EC_set : char
    +     existing EC string to which the EC numbers are appended.
    + ecNumbers : char
    +     EC numbers associated to the protein, separated by white space and/or
    +     semicolons.
    +
    + Returns
    + -------
    + EC_set : char
    +     a single string with all the EC numbers, each prefixed with "EC".
    +
    + Examples
    + --------
    +     EC_set = getECstring(EC_set, ecNumbers);
    +
    + See also
    + --------
    + findECInDB
    +In case of several ec numbers for the same protein
    + + +

    CROSS-REFERENCE INFORMATION ^

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

    SOURCE CODE ^

    +
    0001 function EC_set = getECstring(EC_set,ecNumbers)
    +0002 % getECstring  Build a single string of EC numbers for a protein.
    +0003 %
    +0004 % Provides a single string with all the EC numbers associated to a given
    +0005 % protein, according to the following format:
    +0006 % "ECX.X.X.X ECX.X.X.X ECX.X.X.X".
    +0007 %
    +0008 % Parameters
    +0009 % ----------
    +0010 % EC_set : char
    +0011 %     existing EC string to which the EC numbers are appended.
    +0012 % ecNumbers : char
    +0013 %     EC numbers associated to the protein, separated by white space and/or
    +0014 %     semicolons.
    +0015 %
    +0016 % Returns
    +0017 % -------
    +0018 % EC_set : char
    +0019 %     a single string with all the EC numbers, each prefixed with "EC".
    +0020 %
    +0021 % Examples
    +0022 % --------
    +0023 %     EC_set = getECstring(EC_set, ecNumbers);
    +0024 %
    +0025 % See also
    +0026 % --------
    +0027 % findECInDB
    +0028 %In case of several ec numbers for the same protein
    +0029 new_EC_set = regexp(strtrim(ecNumbers),'[;\s]+','split');
    +0030 new_EC_set = new_EC_set(~cellfun(@isempty,new_EC_set));
    +0031 for l = 1:length(new_EC_set)
    +0032     EC_set = [EC_set 'EC' new_EC_set{l}];
    +0033     if l<length(new_EC_set)
    +0034         EC_set = [EC_set ' '];
    +0035     end
    +0036 end
    +0037 end
    +
    Generated by m2html © 2005
    + + \ No newline at end of file diff --git a/doc/src/get_enzyme_data/index.html b/doc/src/get_enzyme_data/index.html new file mode 100644 index 00000000..c4681c7f --- /dev/null +++ b/doc/src/get_enzyme_data/index.html @@ -0,0 +1,29 @@ + + + + Index for Directory src/get_enzyme_data + + + + + + + + + + +
    < Master indexIndex for src/get_enzyme_data >
    + +

    Index for src/get_enzyme_data

    + +

    Matlab files in this directory:

    + +
     applyECcodesapplyECcodes Copy EC numbers from ecModel.ec.eccodes to ecModel.eccodes.
     calculateMWcalculateMW Calculate the molecular weight of a protein.
     findECInDBfindECInDB Look up EC numbers for a reaction's gene set in a UniProt or KEGG index.
     getECfromDatabasegetECfromDatabase Populate model.ec.eccodes from UniProt and KEGG databases.
     getECfromGEMgetECfromGEM Populate model.ec.eccodes from the model.eccodes field.
     getECstringgetECstring Build a single string of EC numbers for a protein.
    + + + + +
    Generated by m2html © 2005
    + + \ No newline at end of file diff --git a/doc/src/io/index.html b/doc/src/io/index.html new file mode 100644 index 00000000..17b25321 --- /dev/null +++ b/doc/src/io/index.html @@ -0,0 +1,29 @@ + + + + Index for Directory src/io + + + + + + + + + + +
    < Master indexIndex for src/io >
    + +

    Index for src/io

    + +

    Matlab files in this directory:

    + +
     loadConventionalGEMloadConventionalGEM Load the conventional GEM (non-ecModel).
     loadEcModelloadEcModel Load the ecModel that matches the modelAdapter.
     loadFluxDataloadFluxData Load total protein measurements and exchange flux data.
     loadProtDataloadProtData Load absolute proteomics data and average over replicates.
     saveEcModelsaveEcModel Save an ecModel in YAML and/or SBML format.
    + + + + +
    Generated by m2html © 2005
    + + \ No newline at end of file diff --git a/doc/src/io/loadConventionalGEM.html b/doc/src/io/loadConventionalGEM.html new file mode 100644 index 00000000..697eb2fd --- /dev/null +++ b/doc/src/io/loadConventionalGEM.html @@ -0,0 +1,136 @@ + + + + Description of loadConventionalGEM + + + + + + + + + +
    Home > src > io > loadConventionalGEM.m
    + + + +

    loadConventionalGEM +

    + +

    PURPOSE ^

    +
    loadConventionalGEM Load the conventional GEM (non-ecModel).
    + +

    SYNOPSIS ^

    +
    function model = loadConventionalGEM(varargin)
    + +

    DESCRIPTION ^

    +
     loadConventionalGEM  Load the conventional GEM (non-ecModel).
    +
    + Loads the conventional GEM (non-ecModel) from the location specified in
    + the modelAdapter. By default, it looks in the models/ subdirectory of the
    + param.path specified in the modelAdapter. When loading conventional GEMs
    + from other locations, one can directly use importModel.
    +
    + Name-Value Arguments
    + --------------------
    + filename : char
    +     name of the model file, without extension, located in the models/
    +     subfolder of param.path as specified in the modelAdapter; it is
    +     loaded as SBML (.xml) (default: the value specified as param.convGEM
    +     in the modelAdapter, which may instead point to a YAML file).
    + modelAdapter : ModelAdapter
    +     a loaded model adapter, from where the model folder is read (default:
    +     the current default model adapter).
    +
    + Returns
    + -------
    + model : struct
    +     model in RAVEN format.
    +
    + Examples
    + --------
    +     % optional arguments may be given positionally or as name-value pairs:
    +     model = loadConventionalGEM(filename, modelAdapter);
    +     model = loadConventionalGEM('filename', filename);
    +
    + See also
    + --------
    + loadEcModel
    + + +

    CROSS-REFERENCE INFORMATION ^

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

    SOURCE CODE ^

    +
    0001 function model = loadConventionalGEM(varargin)
    +0002 % loadConventionalGEM  Load the conventional GEM (non-ecModel).
    +0003 %
    +0004 % Loads the conventional GEM (non-ecModel) from the location specified in
    +0005 % the modelAdapter. By default, it looks in the models/ subdirectory of the
    +0006 % param.path specified in the modelAdapter. When loading conventional GEMs
    +0007 % from other locations, one can directly use importModel.
    +0008 %
    +0009 % Name-Value Arguments
    +0010 % --------------------
    +0011 % filename : char
    +0012 %     name of the model file, without extension, located in the models/
    +0013 %     subfolder of param.path as specified in the modelAdapter; it is
    +0014 %     loaded as SBML (.xml) (default: the value specified as param.convGEM
    +0015 %     in the modelAdapter, which may instead point to a YAML file).
    +0016 % modelAdapter : ModelAdapter
    +0017 %     a loaded model adapter, from where the model folder is read (default:
    +0018 %     the current default model adapter).
    +0019 %
    +0020 % Returns
    +0021 % -------
    +0022 % model : struct
    +0023 %     model in RAVEN format.
    +0024 %
    +0025 % Examples
    +0026 % --------
    +0027 %     % optional arguments may be given positionally or as name-value pairs:
    +0028 %     model = loadConventionalGEM(filename, modelAdapter);
    +0029 %     model = loadConventionalGEM('filename', filename);
    +0030 %
    +0031 % See also
    +0032 % --------
    +0033 % loadEcModel
    +0034 
    +0035 p = parseGECKOargs(varargin, { ...
    +0036     'filename',     []; ...
    +0037     'modelAdapter', []});
    +0038 filename     = p.filename;
    +0039 modelAdapter = p.modelAdapter;
    +0040 
    +0041 if isempty(modelAdapter)
    +0042     modelAdapter = ModelAdapterManager.getDefault();
    +0043     if isempty(modelAdapter)
    +0044         error('Either send in a modelAdapter or set the default model adapter in the ModelAdapterManager.')
    +0045     end
    +0046 end
    +0047 params = modelAdapter.getParameters();
    +0048 if isempty(filename)
    +0049     filename = params.convGEM;
    +0050 else
    +0051     filename = fullfile(params.path,'models',[filename, '.xml'])
    +0052 end
    +0053 
    +0054 if endsWith(filename,'.xml')
    +0055     model = importModel(filename);
    +0056 elseif endsWith(filename,'.yml')
    +0057     model = readYAMLmodel(filename);
    +0058 end
    +
    Generated by m2html © 2005
    + + \ No newline at end of file diff --git a/doc/src/io/loadEcModel.html b/doc/src/io/loadEcModel.html new file mode 100644 index 00000000..3ada7b2e --- /dev/null +++ b/doc/src/io/loadEcModel.html @@ -0,0 +1,170 @@ + + + + Description of loadEcModel + + + + + + + + + +
    Home > src > io > loadEcModel.m
    + + + +

    loadEcModel +

    + +

    PURPOSE ^

    +
    loadEcModel Load the ecModel that matches the modelAdapter.
    + +

    SYNOPSIS ^

    +
    function model = loadEcModel(varargin)
    + +

    DESCRIPTION ^

    +
     loadEcModel  Load the ecModel that matches the modelAdapter.
    +
    + Loads the ecModel that matches the modelAdapter. By default, it loads the
    + models/ecModel.yml in the directory specified as param.path in the
    + modelAdapter. Alternative files in the same folder can be loaded by
    + providing the appropriate filename. If loading models from other
    + locations, one can directly use readYAMLmodel.
    +
    + An ecModel whose protein usage and pool reactions run in the GECKO 3
    + direction is upgraded in the loaded model with upgradeEcModel, with a
    + warning. An ecModel format (gecko_format in the file's metaData, see
    + saveEcModel) above 4 is an error.
    +
    + Name-Value Arguments
    + --------------------
    + filename : char
    +     name of the ecModel file (default 'ecModel.yml'). File should be
    +     located in the models/ subfolder of param.path as specified in the
    +     modelAdapter.
    + modelAdapter : ModelAdapter
    +     a loaded model adapter, from where the model folder is read (default:
    +     the current default model adapter).
    +
    + Returns
    + -------
    + model : struct
    +     an ecModel (with ecModel.ec structure).
    +
    + Examples
    + --------
    +     % optional arguments may be given positionally or as name-value pairs:
    +     model = loadEcModel(filename, modelAdapter);
    +     model = loadEcModel('filename', filename);
    +
    + See also
    + --------
    + loadConventionalGEM, saveEcModel
    + + +

    CROSS-REFERENCE INFORMATION ^

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

    SOURCE CODE ^

    +
    0001 function model = loadEcModel(varargin)
    +0002 % loadEcModel  Load the ecModel that matches the modelAdapter.
    +0003 %
    +0004 % Loads the ecModel that matches the modelAdapter. By default, it loads the
    +0005 % models/ecModel.yml in the directory specified as param.path in the
    +0006 % modelAdapter. Alternative files in the same folder can be loaded by
    +0007 % providing the appropriate filename. If loading models from other
    +0008 % locations, one can directly use readYAMLmodel.
    +0009 %
    +0010 % An ecModel whose protein usage and pool reactions run in the GECKO 3
    +0011 % direction is upgraded in the loaded model with upgradeEcModel, with a
    +0012 % warning. An ecModel format (gecko_format in the file's metaData, see
    +0013 % saveEcModel) above 4 is an error.
    +0014 %
    +0015 % Name-Value Arguments
    +0016 % --------------------
    +0017 % filename : char
    +0018 %     name of the ecModel file (default 'ecModel.yml'). File should be
    +0019 %     located in the models/ subfolder of param.path as specified in the
    +0020 %     modelAdapter.
    +0021 % modelAdapter : ModelAdapter
    +0022 %     a loaded model adapter, from where the model folder is read (default:
    +0023 %     the current default model adapter).
    +0024 %
    +0025 % Returns
    +0026 % -------
    +0027 % model : struct
    +0028 %     an ecModel (with ecModel.ec structure).
    +0029 %
    +0030 % Examples
    +0031 % --------
    +0032 %     % optional arguments may be given positionally or as name-value pairs:
    +0033 %     model = loadEcModel(filename, modelAdapter);
    +0034 %     model = loadEcModel('filename', filename);
    +0035 %
    +0036 % See also
    +0037 % --------
    +0038 % loadConventionalGEM, saveEcModel
    +0039 
    +0040 p = parseGECKOargs(varargin, { ...
    +0041     'filename',     []; ...
    +0042     'modelAdapter', []});
    +0043 filename     = p.filename;
    +0044 modelAdapter = p.modelAdapter;
    +0045 
    +0046 if 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 params = modelAdapter.getParameters();
    +0053 if isempty(filename)
    +0054     filename = 'ecModel.yml';
    +0055 end
    +0056 
    +0057 if ~endsWith(filename,{'yml','yaml'})
    +0058     error(['ecModels should preferably be distributed in YAML file format, ', ...
    +0059            'as otherwise model content will be lost. If the model is in ', ...
    +0060            'SBML format, you can use the usual importModel function to load ', ...
    +0061            'this as any other genome-scale model.'])
    +0062 end
    +0063 
    +0064 filename = fullfile(params.path,'models',filename); 
    +0065 if endsWith(filename,{'yml','yaml'})
    +0066     model = readYAMLmodel(filename);
    +0067 elseif endsWith(filename,{'xml','sbml'})
    +0068     model = importModel(filename);
    +0069 end
    +0070 
    +0071 if isfield(model, 'annotation') && isfield(model.annotation, 'gecko_format') ...
    +0072         && str2double(model.annotation.gecko_format) > 4
    +0073     writer = 'an unknown release';
    +0074     if isfield(model.annotation, 'generator')
    +0075         writer = model.annotation.generator;
    +0076     end
    +0077     error('loadEcModel:format', ['%s has ecModel format %s (written by %s); ' ...
    +0078         'this GECKO reads format 4 and older. Update GECKO to load it.'], ...
    +0079         filename, model.annotation.gecko_format, writer)
    +0080 end
    +0081 [model, changed] = upgradeEcModel(model);
    +0082 if ~isempty(changed)
    +0083     warning('loadEcModel:upgraded', ['%s has %d protein usage and pool reactions in the GECKO 3 ' ...
    +0084         'direction; they are turned forward in the loaded model. upgradeGECKOproject upgrades the ' ...
    +0085         'files of the project.'], filename, numel(changed))
    +0086 end
    +0087 end
    +
    Generated by m2html © 2005
    + + \ No newline at end of file diff --git a/doc/src/io/loadFluxData.html b/doc/src/io/loadFluxData.html new file mode 100644 index 00000000..7232ecc0 --- /dev/null +++ b/doc/src/io/loadFluxData.html @@ -0,0 +1,200 @@ + + + + Description of loadFluxData + + + + + + + + + +
    Home > src > io > loadFluxData.m
    + + + +

    loadFluxData +

    + +

    PURPOSE ^

    +
    loadFluxData Load total protein measurements and exchange flux data.
    + +

    SYNOPSIS ^

    +
    function fluxData = loadFluxData(varargin)
    + +

    DESCRIPTION ^

    +
     loadFluxData  Load total protein measurements and exchange flux data.
    +
    + Loads total protein content and exchange flux data (e.g. carbon source,
    + O2, CO2) from a tab-delimited file.
    +
    + Name-Value Arguments
    + --------------------
    + fluxDataFile : char
    +     path to file with flux data (default reads data/fluxData.tsv as
    +     specified in modelAdapter).
    + modelAdapter : ModelAdapter
    +     a loaded model adapter (default: the current default model adapter).
    +
    + Returns
    + -------
    + fluxData : struct
    +     structure with flux data.
    +
    + Notes
    + -----
    + The fluxData structure has the following fields:
    +
    + - conds : sampling condition.
    + - Ptot : total protein (g/gDCW).
    + - grRate : growth rate (1/h).
    + - exchFluxes : exchange fluxes (mmol/gDCWh).
    + - exchMets : exchanged metabolites, matching exchFluxes.
    + - exchRxnIDs : exchange reaction IDs, matching exchMets.
    + - evotuneRMSEweight : if column existed in fluxData.tsv, weights for RMSE calculation in evotune kcat tuning.
    + - source : if column existed in fluxData.tsv, description where the data comes from.
    +
    + Examples
    + --------
    +     % optional arguments may be given positionally or as name-value pairs:
    +     fluxData = loadFluxData(fluxDataFile, modelAdapter);
    +     fluxData = loadFluxData('fluxDataFile', fluxDataFile);
    +
    + See also
    + --------
    + loadProtData
    + + +

    CROSS-REFERENCE INFORMATION ^

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

    SOURCE CODE ^

    +
    0001 function fluxData = loadFluxData(varargin)
    +0002 % loadFluxData  Load total protein measurements and exchange flux data.
    +0003 %
    +0004 % Loads total protein content and exchange flux data (e.g. carbon source,
    +0005 % O2, CO2) from a tab-delimited file.
    +0006 %
    +0007 % Name-Value Arguments
    +0008 % --------------------
    +0009 % fluxDataFile : char
    +0010 %     path to file with flux data (default reads data/fluxData.tsv as
    +0011 %     specified in modelAdapter).
    +0012 % modelAdapter : ModelAdapter
    +0013 %     a loaded model adapter (default: the current default model adapter).
    +0014 %
    +0015 % Returns
    +0016 % -------
    +0017 % fluxData : struct
    +0018 %     structure with flux data.
    +0019 %
    +0020 % Notes
    +0021 % -----
    +0022 % The fluxData structure has the following fields:
    +0023 %
    +0024 % - conds : sampling condition.
    +0025 % - Ptot : total protein (g/gDCW).
    +0026 % - grRate : growth rate (1/h).
    +0027 % - exchFluxes : exchange fluxes (mmol/gDCWh).
    +0028 % - exchMets : exchanged metabolites, matching exchFluxes.
    +0029 % - exchRxnIDs : exchange reaction IDs, matching exchMets.
    +0030 % - evotuneRMSEweight : if column existed in fluxData.tsv, weights for RMSE calculation in evotune kcat tuning.
    +0031 % - source : if column existed in fluxData.tsv, description where the data comes from.
    +0032 %
    +0033 % Examples
    +0034 % --------
    +0035 %     % optional arguments may be given positionally or as name-value pairs:
    +0036 %     fluxData = loadFluxData(fluxDataFile, modelAdapter);
    +0037 %     fluxData = loadFluxData('fluxDataFile', fluxDataFile);
    +0038 %
    +0039 % See also
    +0040 % --------
    +0041 % loadProtData
    +0042 
    +0043 p = parseGECKOargs(varargin, { ...
    +0044     'fluxDataFile', []; ...
    +0045     'modelAdapter', []});
    +0046 fluxDataFile = p.fluxDataFile;
    +0047 modelAdapter = p.modelAdapter;
    +0048 
    +0049 if isempty(modelAdapter)
    +0050     modelAdapter = ModelAdapterManager.getDefault();
    +0051     if isempty(modelAdapter)
    +0052         error('Either send in a modelAdapter or set the default model adapter in the ModelAdapterManager.')
    +0053     end
    +0054 end
    +0055 params = modelAdapter.getParameters();
    +0056 
    +0057 if isempty(fluxDataFile)
    +0058     fluxDataFile = fullfile(params.path,'data','fluxData.tsv');
    +0059 end
    +0060 
    +0061 %Load total protein content and flux data
    +0062 try
    +0063     fID       = fopen(fluxDataFile);
    +0064     formatStr = '%s';
    +0065     data      = textscan(fID,formatStr,'Delimiter','\n');
    +0066     fclose(fID);
    +0067 catch
    +0068     warning('Failed to load %s.',fluxDataFile);
    +0069     fluxData = [];
    +0070     return
    +0071 end
    +0072 fluxDataRaw  = [];
    +0073 for i=1:length(data{1})
    +0074     row      = data{1}(i);
    +0075     row      = strsplit(row{1},'\t');
    +0076     row      = row(1:end);
    +0077     fluxDataRaw = [fluxDataRaw; row]; 
    +0078 end
    +0079 if size(fluxDataRaw,2) == 0
    +0080     error('The input file %s is likely not tab-delimited.', fluxDataFile)
    +0081 end
    +0082 fluxData            = [];
    +0083 
    +0084 %Find additional fields
    +0085 extraFieldNames     = {'evotuneRMSEweight','source'};
    +0086 extraFieldNumeric   = [true,false];      
    +0087 [logicalExtra, extraFields]    = ismember(extraFieldNames,fluxDataRaw(1,:));
    +0088 extraFields(~logicalExtra) = [];
    +0089 extraFieldNames(~logicalExtra) = [];
    +0090 extraFieldNumeric(~logicalExtra) = [];
    +0091 if any(extraFields)
    +0092     for i=1:numel(extraFields)
    +0093         if extraFieldNumeric(i)
    +0094             fluxData.(extraFieldNames{i}) = str2double(fluxDataRaw(2:end,extraFields(i)));
    +0095         else
    +0096             fluxData.(extraFieldNames{i}) = fluxDataRaw(2:end,extraFields(i));
    +0097         end
    +0098     end
    +0099     fluxDataRaw(:,extraFields) = [];
    +0100 end
    +0101 
    +0102 %Extract observed byProduct names from file
    +0103 exchRxns = fluxDataRaw(1,4:end);
    +0104 exchMets = strtrim(regexprep(exchRxns,'(.*)\(.*\)$','$1'));
    +0105 exchRxns = regexprep(exchRxns,'.*\((.*)\)$','$1');
    +0106 
    +0107 fluxData.conds      = fluxDataRaw(2:end,1);
    +0108 fluxData.Ptot       = str2double(fluxDataRaw(2:end,2));
    +0109 fluxData.grRate     = str2double(fluxDataRaw(2:end,3));
    +0110 fluxData.exchFluxes = str2double(fluxDataRaw(2:end,4:end));
    +0111 %fluxData.exchFluxes(isnan(fluxData.exchFluxes)) = 0;
    +0112 fluxData.exchMets   = exchMets;
    +0113 fluxData.exchRxnIDs = exchRxns;
    +0114 end
    +
    Generated by m2html © 2005
    + + \ No newline at end of file diff --git a/doc/src/io/loadProtData.html b/doc/src/io/loadProtData.html new file mode 100644 index 00000000..6380cea0 --- /dev/null +++ b/doc/src/io/loadProtData.html @@ -0,0 +1,291 @@ + + + + Description of loadProtData + + + + + + + + + +
    Home > src > io > loadProtData.m
    + + + +

    loadProtData +

    + +

    PURPOSE ^

    +
    loadProtData Load absolute proteomics data and average over replicates.
    + +

    SYNOPSIS ^

    +
    function protData = loadProtData(replPerCond, varargin)
    + +

    DESCRIPTION ^

    +
     loadProtData  Load absolute proteomics data and average over replicates.
    +
    + Loads absolute proteomics data (in mg/gDCW) and returns mean values
    + across replicates for each condition in the data file. By default it also
    + filters the data by various criteria, to remove uncertain data (see input
    + parameters).
    +
    + Parameters
    + ----------
    + replPerCond : double
    +     vector with number of replicates for each condition in the dataset.
    +     Example: [3, 2] if first condition has triplicates and second
    +     condition has duplicates.
    +
    + Name-Value Arguments
    + --------------------
    + protDataFile : char
    +     path to file with proteomics data, where protein levels are in
    +     mg/gDCW (default reads data/proteomics.tsv as specified in
    +     modelAdapter). Alternatively, protDataFile can be a protData structure
    +     that was previously made by loadProtData.
    + filterData : logical
    +     whether abundances should be filtered. If false, minVal, maxRSD,
    +     maxMissing, cutLowest and addStdevs are not considered (default true).
    + modelAdapter : ModelAdapter
    +     a loaded model adapter (default: the current default model adapter).
    + minVal : double
    +     minimum mean protein measurement per condition; proteins with a lower
    +     mean abundance are discarded (set to NaN) for that condition (default
    +     0, i.e. no lower threshold).
    + maxRSD : double
    +     maximum relative standard deviation (RSD, the standard deviation
    +     across replicates divided by their mean) allowed per condition;
    +     proteins exceeding it are discarded (set to NaN) for that condition
    +     (default 1, i.e. RSD up to 100%).
    + maxMissing : double
    +     minimum fraction of replicates within a condition that must have a
    +     measured value; proteins with fewer present replicates than this
    +     fraction requires are discarded (set to NaN) for that condition
    +     (default 2/3, i.e. at least two of three replicates must have a
    +     value). If conditions have different number of replicates (as
    +     indicated in replPerCond), maxMissing can also be a vector of the
    +     same length as replPerCond, with individual values per condition.
    + cutLowest : double
    +     percentage of lowest mean values per condition to be discarded (not
    +     considering NaN values) (default 5).
    + addStdevs : double
    +     how many standard deviations should be added to the mean value of
    +     each protein measurement across replicates, broadening the confidence
    +     interval (default 1).
    +
    + Returns
    + -------
    + protData : struct
    +     structure with (filtered) proteome data.
    +
    + Notes
    + -----
    + The protData structure has the following fields:
    +
    + - uniprotIDs : cell array with Uniprot IDs matching protData.abundances.
    + - abundances : matrix of proteomics data, where each column contains mean abundances per condition.
    +
    + Examples
    + --------
    +     % optional arguments may be given positionally or as name-value pairs:
    +     protData = loadProtData(replPerCond, protDataFile, filterData, modelAdapter, minVal, maxRSD, maxMissing, cutLowest, addStdevs);
    +     protData = loadProtData(replPerCond, 'filterData', false);
    +
    + See also
    + --------
    + loadFluxData
    + + +

    CROSS-REFERENCE INFORMATION ^

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

    SOURCE CODE ^

    +
    0001 function protData = loadProtData(replPerCond, varargin)
    +0002 % loadProtData  Load absolute proteomics data and average over replicates.
    +0003 %
    +0004 % Loads absolute proteomics data (in mg/gDCW) and returns mean values
    +0005 % across replicates for each condition in the data file. By default it also
    +0006 % filters the data by various criteria, to remove uncertain data (see input
    +0007 % parameters).
    +0008 %
    +0009 % Parameters
    +0010 % ----------
    +0011 % replPerCond : double
    +0012 %     vector with number of replicates for each condition in the dataset.
    +0013 %     Example: [3, 2] if first condition has triplicates and second
    +0014 %     condition has duplicates.
    +0015 %
    +0016 % Name-Value Arguments
    +0017 % --------------------
    +0018 % protDataFile : char
    +0019 %     path to file with proteomics data, where protein levels are in
    +0020 %     mg/gDCW (default reads data/proteomics.tsv as specified in
    +0021 %     modelAdapter). Alternatively, protDataFile can be a protData structure
    +0022 %     that was previously made by loadProtData.
    +0023 % filterData : logical
    +0024 %     whether abundances should be filtered. If false, minVal, maxRSD,
    +0025 %     maxMissing, cutLowest and addStdevs are not considered (default true).
    +0026 % modelAdapter : ModelAdapter
    +0027 %     a loaded model adapter (default: the current default model adapter).
    +0028 % minVal : double
    +0029 %     minimum mean protein measurement per condition; proteins with a lower
    +0030 %     mean abundance are discarded (set to NaN) for that condition (default
    +0031 %     0, i.e. no lower threshold).
    +0032 % maxRSD : double
    +0033 %     maximum relative standard deviation (RSD, the standard deviation
    +0034 %     across replicates divided by their mean) allowed per condition;
    +0035 %     proteins exceeding it are discarded (set to NaN) for that condition
    +0036 %     (default 1, i.e. RSD up to 100%).
    +0037 % maxMissing : double
    +0038 %     minimum fraction of replicates within a condition that must have a
    +0039 %     measured value; proteins with fewer present replicates than this
    +0040 %     fraction requires are discarded (set to NaN) for that condition
    +0041 %     (default 2/3, i.e. at least two of three replicates must have a
    +0042 %     value). If conditions have different number of replicates (as
    +0043 %     indicated in replPerCond), maxMissing can also be a vector of the
    +0044 %     same length as replPerCond, with individual values per condition.
    +0045 % cutLowest : double
    +0046 %     percentage of lowest mean values per condition to be discarded (not
    +0047 %     considering NaN values) (default 5).
    +0048 % addStdevs : double
    +0049 %     how many standard deviations should be added to the mean value of
    +0050 %     each protein measurement across replicates, broadening the confidence
    +0051 %     interval (default 1).
    +0052 %
    +0053 % Returns
    +0054 % -------
    +0055 % protData : struct
    +0056 %     structure with (filtered) proteome data.
    +0057 %
    +0058 % Notes
    +0059 % -----
    +0060 % The protData structure has the following fields:
    +0061 %
    +0062 % - uniprotIDs : cell array with Uniprot IDs matching protData.abundances.
    +0063 % - abundances : matrix of proteomics data, where each column contains mean abundances per condition.
    +0064 %
    +0065 % Examples
    +0066 % --------
    +0067 %     % optional arguments may be given positionally or as name-value pairs:
    +0068 %     protData = loadProtData(replPerCond, protDataFile, filterData, modelAdapter, minVal, maxRSD, maxMissing, cutLowest, addStdevs);
    +0069 %     protData = loadProtData(replPerCond, 'filterData', false);
    +0070 %
    +0071 % See also
    +0072 % --------
    +0073 % loadFluxData
    +0074 
    +0075 p = parseGECKOargs(varargin, { ...
    +0076     'protDataFile', []; ...
    +0077     'filterData',   true; ...
    +0078     'modelAdapter', []; ...
    +0079     'minVal',       0; ...
    +0080     'maxRSD',       1; ...
    +0081     'maxMissing',   2/3; ...
    +0082     'cutLowest',    5; ...
    +0083     'addStdevs',    1});
    +0084 protDataFile = p.protDataFile;
    +0085 filterData   = p.filterData;
    +0086 modelAdapter = p.modelAdapter;
    +0087 minVal       = p.minVal;
    +0088 maxRSD       = p.maxRSD;
    +0089 maxMissing   = p.maxMissing;
    +0090 cutLowest    = p.cutLowest;
    +0091 addStdevs    = p.addStdevs;
    +0092 
    +0093 if isempty(modelAdapter)
    +0094     modelAdapter = ModelAdapterManager.getDefault();
    +0095     if isempty(modelAdapter)
    +0096         error('Either send in a modelAdapter or set the default model adapter in the ModelAdapterManager.')
    +0097     end
    +0098 end
    +0099 params = modelAdapter.getParameters();
    +0100 
    +0101 if isempty(protDataFile)
    +0102     protDataFile = fullfile(params.path,'data','proteomics.tsv');
    +0103 end
    +0104 
    +0105 format = '%s';
    +0106 for i=1:sum(replPerCond)
    +0107     format = [format ' %f'];
    +0108 end
    +0109 if ~isstruct(protDataFile)
    +0110     checkFileExistence(protDataFile);
    +0111     fID         = fopen(protDataFile);
    +0112     protDataRaw = textscan(fID,format,'Delimiter','\t','HeaderLines',1,'TreatAsEmpty',{'NA','na','NaN','#VALUE!'});
    +0113     uniprotIDs  = protDataRaw{1};
    +0114     abundances  = cell2mat(protDataRaw(2:end));
    +0115     fclose(fID);
    +0116 else
    +0117     uniprotIDs  = protDataFile.uniprotIDs;
    +0118     abundances  = protDataFile.abundances;
    +0119 end
    +0120 
    +0121 %Remove entriew without ID
    +0122 remData = cellfun(@isempty,uniprotIDs);
    +0123 uniprotIDs(remData,:) = [];
    +0124 abundances(remData,:) = [];
    +0125 m                     = size(abundances,1);
    +0126 filtAbund             = nan(m,numel(replPerCond));
    +0127 
    +0128 if filterData
    +0129     for i=1:numel(replPerCond)
    +0130         condAbund    = abundances(:,1:replPerCond(i));
    +0131         if i<numel(replPerCond)
    +0132             abundances   = abundances(:,replPerCond(i)+1:end);
    +0133         end
    +0134         % First filter maxMissing
    +0135         if size(condAbund,2) > 1
    +0136             if numel(maxMissing)>1
    +0137                 maxMisRepl = maxMissing(i);
    +0138             else
    +0139                 maxMisRepl = maxMissing;
    +0140             end
    +0141             remData = sum(condAbund>0,2)<maxMisRepl*size(condAbund,2);
    +0142             condAbund(remData,:) = nan;
    +0143         end
    +0144         % Filter by RSD
    +0145         remData = (std(condAbund,0,2,'omitnan')./mean(condAbund,2,'omitnan'))>maxRSD;
    +0146         condAbund(remData,:) = nan;
    +0147         % Add stdevs
    +0148         condAbund = mean(condAbund,2,'omitnan')+(addStdevs*std(condAbund,0,2,'omitnan'));
    +0149         % Filter by minVal
    +0150         remData = mean(condAbund,2,'omitnan')<minVal;
    +0151         condAbund(remData) = nan;
    +0152         % Remove the lowest cutLowest percent
    +0153         numData  = find(~isnan(condAbund));
    +0154         [~,sortData] = sort(condAbund);
    +0155         lowCutoff = floor(numel(numData)*cutLowest/100);
    +0156         condAbund(sortData(1:lowCutoff)) = nan;
    +0157         % Combine conditions
    +0158         filtAbund(:,i) = condAbund;
    +0159     end
    +0160 else
    +0161     for i=1:numel(replPerCond)
    +0162         condAbund    = abundances(:,1:replPerCond(i));
    +0163         if i<numel(replPerCond)
    +0164             abundances = abundances(:,replPerCond(i)+1:end);
    +0165         end
    +0166         filtAbund(:,i) = mean(condAbund,2,'omitnan');
    +0167     end
    +0168 end
    +0169 notAllNan = logical(sum(~isnan(filtAbund),2));
    +0170 protData.abundances = filtAbund(notAllNan,:);
    +0171 protData.uniprotIDs = uniprotIDs(notAllNan);
    +0172 end
    +0173
    +
    Generated by m2html © 2005
    + + \ No newline at end of file diff --git a/doc/src/io/saveEcModel.html b/doc/src/io/saveEcModel.html new file mode 100644 index 00000000..6df2cd14 --- /dev/null +++ b/doc/src/io/saveEcModel.html @@ -0,0 +1,194 @@ + + + + Description of saveEcModel + + + + + + + + + +
    Home > src > io > saveEcModel.m
    + + + +

    saveEcModel +

    + +

    PURPOSE ^

    +
    saveEcModel Save an ecModel in YAML and/or SBML format.
    + +

    SYNOPSIS ^

    +
    function saveEcModel(ecModel,varargin)
    + +

    DESCRIPTION ^

    +
     saveEcModel  Save an ecModel in YAML and/or SBML format.
    +
    + Saves the ecModel in either YAML format (= default and preferred, as all
    + ecModel content is reserved) and/or SBML format (= more widely compatible
    + with other constraint-based modelling tools, can be used for running
    + simulations like FBA etc., but this model cannot be loaded back into
    + MATLAB for applying further GECKO functions, as model.ec is lost).
    +
    + A YAML file records its ecModel format (gecko_format, see loadEcModel)
    + and the GECKO release that wrote it (generator) in its metaData, in
    + place of the geckopy_version that earlier geckopy releases wrote.
    +
    + The ecModel is saved to the ecModel-specific models/ subfolder. For
    + saving to other locations, writeYAMLmodel or exportModel are more
    + suitable.
    +
    + Parameters
    + ----------
    + ecModel : struct
    +     an ecModel (with ecModel.ec structure).
    +
    + Name-Value Arguments
    + --------------------
    + filename : char
    +     ending with either .yml or .xml, specifying if the ecModel should be
    +     saved in YAML or SBML file format. If no file extension is given, the
    +     ecModel will be saved in YAML format. If no filename is given,
    +     'ecModel.yml' is used.
    + modelAdapter : ModelAdapter
    +     a loaded model adapter, from where the model folder is read (default:
    +     the current default model adapter).
    +
    + Examples
    + --------
    +     % optional arguments may be given positionally or as name-value pairs:
    +     saveEcModel(ecModel,filename,modelAdapter);
    +     saveEcModel(ecModel,'filename',filename);
    +
    + See also
    + --------
    + loadEcModel
    + + +

    CROSS-REFERENCE INFORMATION ^

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

    SUBFUNCTIONS ^

    + + +

    SOURCE CODE ^

    +
    0001 function saveEcModel(ecModel,varargin)
    +0002 % saveEcModel  Save an ecModel in YAML and/or SBML format.
    +0003 %
    +0004 % Saves the ecModel in either YAML format (= default and preferred, as all
    +0005 % ecModel content is reserved) and/or SBML format (= more widely compatible
    +0006 % with other constraint-based modelling tools, can be used for running
    +0007 % simulations like FBA etc., but this model cannot be loaded back into
    +0008 % MATLAB for applying further GECKO functions, as model.ec is lost).
    +0009 %
    +0010 % A YAML file records its ecModel format (gecko_format, see loadEcModel)
    +0011 % and the GECKO release that wrote it (generator) in its metaData, in
    +0012 % place of the geckopy_version that earlier geckopy releases wrote.
    +0013 %
    +0014 % The ecModel is saved to the ecModel-specific models/ subfolder. For
    +0015 % saving to other locations, writeYAMLmodel or exportModel are more
    +0016 % suitable.
    +0017 %
    +0018 % Parameters
    +0019 % ----------
    +0020 % ecModel : struct
    +0021 %     an ecModel (with ecModel.ec structure).
    +0022 %
    +0023 % Name-Value Arguments
    +0024 % --------------------
    +0025 % filename : char
    +0026 %     ending with either .yml or .xml, specifying if the ecModel should be
    +0027 %     saved in YAML or SBML file format. If no file extension is given, the
    +0028 %     ecModel will be saved in YAML format. If no filename is given,
    +0029 %     'ecModel.yml' is used.
    +0030 % modelAdapter : ModelAdapter
    +0031 %     a loaded model adapter, from where the model folder is read (default:
    +0032 %     the current default model adapter).
    +0033 %
    +0034 % Examples
    +0035 % --------
    +0036 %     % optional arguments may be given positionally or as name-value pairs:
    +0037 %     saveEcModel(ecModel,filename,modelAdapter);
    +0038 %     saveEcModel(ecModel,'filename',filename);
    +0039 %
    +0040 % See also
    +0041 % --------
    +0042 % loadEcModel
    +0043 
    +0044 p = parseGECKOargs(varargin, { ...
    +0045     'filename',     []; ...
    +0046     'modelAdapter', []});
    +0047 filename     = p.filename;
    +0048 modelAdapter = p.modelAdapter;
    +0049 
    +0050 if isempty(modelAdapter)
    +0051     modelAdapter = ModelAdapterManager.getDefault();
    +0052     if isempty(modelAdapter)
    +0053         error('Either send in a modelAdapter or set the default model adapter in the ModelAdapterManager.')
    +0054     end
    +0055 end
    +0056 params = modelAdapter.getParameters();
    +0057 if isempty(filename)
    +0058     filename = 'ecModel';
    +0059 end
    +0060 filename = fullfile(params.path,'models',filename);
    +0061 
    +0062 switch filename(end-3:end)
    +0063     case {'.xml','sbml'}
    +0064         exportModel(ecModel, filename);
    +0065         %Convert notation "e-005" to "e-05 " in stoich. coeffs. to avoid
    +0066         %inconsistencies between Windows and MAC:
    +0067         copyfile(filename,'backup.xml')
    +0068         fin  = fopen('backup.xml', 'r');
    +0069         fout = fopen(filename, 'w');
    +0070         still_reading = true;
    +0071         while still_reading
    +0072             inline = fgets(fin);
    +0073             if ~ischar(inline)
    +0074                 still_reading = false;
    +0075             else
    +0076                 if ~isempty(regexp(inline,'-00[0-9]','once'))
    +0077                     inline = strrep(inline,'-00','-0');
    +0078                 elseif ~isempty(regexp(inline,'-01[0-9]','once'))
    +0079                     inline = strrep(inline,'-01','-1');
    +0080                 end
    +0081                 fwrite(fout, inline);
    +0082             end
    +0083         end
    +0084         fclose('all');
    +0085         delete('backup.xml');
    +0086     otherwise % Assume YAML
    +0087         % The ecModel format the file follows (as project_format in
    +0088         % model_adapter.toml) and the release that wrote it.
    +0089         ecModel.annotation.gecko_format = '4';
    +0090         ecModel.annotation.generator = ['GECKO ' geckoVersion()];
    +0091         if isfield(ecModel.annotation, 'geckopy_version')
    +0092             ecModel.annotation = rmfield(ecModel.annotation, 'geckopy_version');
    +0093         end
    +0094         writeYAMLmodel(ecModel,filename);
    +0095 end
    +0096 end
    +0097 
    +0098 function v = geckoVersion()
    +0099 file = fullfile(findGECKOroot, 'version.txt');
    +0100 if isfile(file)
    +0101     v = strtrim(fileread(file));
    +0102 else
    +0103     v = 'unknown';
    +0104 end
    +0105 end
    +
    Generated by m2html © 2005
    + + \ No newline at end of file diff --git a/doc/src/kcat_tuning/evotune/bestParsimonious.html b/doc/src/kcat_tuning/evotune/bestParsimonious.html new file mode 100644 index 00000000..67846d00 --- /dev/null +++ b/doc/src/kcat_tuning/evotune/bestParsimonious.html @@ -0,0 +1,112 @@ + + + + Description of bestParsimonious + + + + + + + + + +
    Home > src > kcat_tuning > evotune > bestParsimonious.m
    + + + +

    bestParsimonious +

    + +

    PURPOSE ^

    +
    bestParsimonious The fewest-changes point whose RMSE is within
    + +

    SYNOPSIS ^

    +
    function point = bestParsimonious(points,varargin)
    + +

    DESCRIPTION ^

    +
     bestParsimonious  The fewest-changes point whose RMSE is within
    + tolerance of the best on a parsimonyFrontier.
    +
    + Defaults to 2%, which is the scale of alternate-optimum noise typically
    + seen from re-solving an LP with a slightly different kcat vector --
    + below that, two vectors are not meaningfully different in fit, so the
    + sparser one wins.
    +
    + Parameters
    + ----------
    + points : struct array
    +     as returned by parsimonyFrontier.
    +
    + Name-Value Arguments
    + --------------------
    + tolerance : double
    +     default 0.02.
    +
    + Returns
    + -------
    + point : struct
    +     the chosen entry of points.
    +
    + See also
    + --------
    + parsimonyFrontier
    + + +

    CROSS-REFERENCE INFORMATION ^

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

    SOURCE CODE ^

    +
    0001 function point = bestParsimonious(points,varargin)
    +0002 % bestParsimonious  The fewest-changes point whose RMSE is within
    +0003 % tolerance of the best on a parsimonyFrontier.
    +0004 %
    +0005 % Defaults to 2%, which is the scale of alternate-optimum noise typically
    +0006 % seen from re-solving an LP with a slightly different kcat vector --
    +0007 % below that, two vectors are not meaningfully different in fit, so the
    +0008 % sparser one wins.
    +0009 %
    +0010 % Parameters
    +0011 % ----------
    +0012 % points : struct array
    +0013 %     as returned by parsimonyFrontier.
    +0014 %
    +0015 % Name-Value Arguments
    +0016 % --------------------
    +0017 % tolerance : double
    +0018 %     default 0.02.
    +0019 %
    +0020 % Returns
    +0021 % -------
    +0022 % point : struct
    +0023 %     the chosen entry of points.
    +0024 %
    +0025 % See also
    +0026 % --------
    +0027 % parsimonyFrontier
    +0028 p = parseGECKOargs(varargin, { ...
    +0029     'tolerance', 0.02});
    +0030 tolerance = p.tolerance;
    +0031 
    +0032 if isempty(points)
    +0033     error('points is empty.')
    +0034 end
    +0035 rmses = [points.rmse];
    +0036 bestRmse = min(rmses);
    +0037 within = points(rmses <= bestRmse * (1+tolerance));
    +0038 [~,idx] = min([within.nChanged]);
    +0039 point = within(idx);
    +0040 end
    +
    Generated by m2html © 2005
    + + \ No newline at end of file diff --git a/doc/src/kcat_tuning/evotune/cmaesKcatTuning.html b/doc/src/kcat_tuning/evotune/cmaesKcatTuning.html new file mode 100644 index 00000000..1ad5de2d --- /dev/null +++ b/doc/src/kcat_tuning/evotune/cmaesKcatTuning.html @@ -0,0 +1,391 @@ + + + + Description of cmaesKcatTuning + + + + + + + + + +
    Home > src > kcat_tuning > evotune > cmaesKcatTuning.m
    + + + +

    cmaesKcatTuning +

    + +

    PURPOSE ^

    +
    cmaesKcatTuning Tune kcats against experimental data with CMA-ES.
    + +

    SYNOPSIS ^

    +
    function [ecModel,result] = cmaesKcatTuning(ecModel,varargin)
    + +

    DESCRIPTION ^

    +
     cmaesKcatTuning  Tune kcats against experimental data with CMA-ES.
    +
    + Configuration comes entirely from modelAdapter.params.evotune: trust
    + tiers (kcatSources/sigma0logSource/sigma0logDefault), maxGrowthWeight,
    + priorPenaltyWeight and tieIsozymes control the search, and
    + maxGenerations/rmseThreshold are its stopping conditions.
    +
    + Vendors a separable (diagonal-covariance) CMA-ES -- MATLAB has no
    + built-in implementation and Global Optimization Toolbox doesn't ship
    + one either. Separable rather than full-covariance because that is what
    + geckopy's own port actually runs (cma's CMA_diagonal=True) and what its
    + defaults were validated against; it is also lower risk to implement
    + correctly. See the "CMA-ES core" local functions below.
    +
    + Parameters
    + ----------
    + ecModel : struct
    +     ecModel with a populated ec.kcat.
    +
    + Name-Value Arguments
    + --------------------
    + modelAdapter : ModelAdapter
    +     a loaded model adapter (default: the current default model adapter).
    + evoData : struct
    +     as returned by loadEvotuneData (default: loaded from modelAdapter).
    + tunableMask, screen, targetImpactShare
    +     control which kcats are searched over, in order of precedence. Pass
    +     tunableMask to fix the set yourself. Otherwise, a mask is built by
    +     selectTunableMask at targetImpactShare (default 0.9), from screen if
    +     given, or from a fresh screenKcatLeverage call otherwise.
    + popsize : double
    +     CMA-ES population size. Defaults to 4 + floor(3*log(n)), the
    +     standard dimension-scaled default, so it adapts to however many
    +     free parameters the mask/tying produced.
    + nProc : double
    +     number of parallel workers used to score each generation's
    +     candidates (default 1, i.e. serial). Requires Parallel Computing
    +     Toolbox for > 1.
    + seed : double
    +     if given, seeds the random draws for a reproducible run.
    + verbose : logical
    +     whether per-generation progress is printed (default true).
    +
    + Returns
    + -------
    + ecModel : struct
    +     mutated: tunable rows carry the best kcat vector CMA-ES found, with
    +     kcat constraints already applied. MATLAB structs are copied on
    +     assignment, so -- unlike geckopy's in-place mutation -- this output
    +     must be captured by the caller.
    + result : struct
    +     rxns/oldKcat/newKcat/groups cover the selected tunable set, tied
    +     groups included (their members share one value in newKcat).
    +     rmseTrace/objectiveTrace record the best-so-far plain RMSE and
    +     optimised objective per generation. nGenerations is how many
    +     generations actually ran. converged is true if
    +     rmseTrace(end) <= params.rmseThreshold.
    +
    + Raises
    + ------
    + error
    +     if there are no tunable kcats, or fewer than two free parameters
    +     remain after masking and tying -- too little for CMA-ES to search
    +     over.
    +
    + See also
    + --------
    + screenKcatLeverage, selectTunableMask, tunePriorPenaltyWeight
    + + +

    CROSS-REFERENCE INFORMATION ^

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

    SUBFUNCTIONS ^

    + + +

    SOURCE CODE ^

    +
    0001 function [ecModel,result] = cmaesKcatTuning(ecModel,varargin)
    +0002 % cmaesKcatTuning  Tune kcats against experimental data with CMA-ES.
    +0003 %
    +0004 % Configuration comes entirely from modelAdapter.params.evotune: trust
    +0005 % tiers (kcatSources/sigma0logSource/sigma0logDefault), maxGrowthWeight,
    +0006 % priorPenaltyWeight and tieIsozymes control the search, and
    +0007 % maxGenerations/rmseThreshold are its stopping conditions.
    +0008 %
    +0009 % Vendors a separable (diagonal-covariance) CMA-ES -- MATLAB has no
    +0010 % built-in implementation and Global Optimization Toolbox doesn't ship
    +0011 % one either. Separable rather than full-covariance because that is what
    +0012 % geckopy's own port actually runs (cma's CMA_diagonal=True) and what its
    +0013 % defaults were validated against; it is also lower risk to implement
    +0014 % correctly. See the "CMA-ES core" local functions below.
    +0015 %
    +0016 % Parameters
    +0017 % ----------
    +0018 % ecModel : struct
    +0019 %     ecModel with a populated ec.kcat.
    +0020 %
    +0021 % Name-Value Arguments
    +0022 % --------------------
    +0023 % modelAdapter : ModelAdapter
    +0024 %     a loaded model adapter (default: the current default model adapter).
    +0025 % evoData : struct
    +0026 %     as returned by loadEvotuneData (default: loaded from modelAdapter).
    +0027 % tunableMask, screen, targetImpactShare
    +0028 %     control which kcats are searched over, in order of precedence. Pass
    +0029 %     tunableMask to fix the set yourself. Otherwise, a mask is built by
    +0030 %     selectTunableMask at targetImpactShare (default 0.9), from screen if
    +0031 %     given, or from a fresh screenKcatLeverage call otherwise.
    +0032 % popsize : double
    +0033 %     CMA-ES population size. Defaults to 4 + floor(3*log(n)), the
    +0034 %     standard dimension-scaled default, so it adapts to however many
    +0035 %     free parameters the mask/tying produced.
    +0036 % nProc : double
    +0037 %     number of parallel workers used to score each generation's
    +0038 %     candidates (default 1, i.e. serial). Requires Parallel Computing
    +0039 %     Toolbox for > 1.
    +0040 % seed : double
    +0041 %     if given, seeds the random draws for a reproducible run.
    +0042 % verbose : logical
    +0043 %     whether per-generation progress is printed (default true).
    +0044 %
    +0045 % Returns
    +0046 % -------
    +0047 % ecModel : struct
    +0048 %     mutated: tunable rows carry the best kcat vector CMA-ES found, with
    +0049 %     kcat constraints already applied. MATLAB structs are copied on
    +0050 %     assignment, so -- unlike geckopy's in-place mutation -- this output
    +0051 %     must be captured by the caller.
    +0052 % result : struct
    +0053 %     rxns/oldKcat/newKcat/groups cover the selected tunable set, tied
    +0054 %     groups included (their members share one value in newKcat).
    +0055 %     rmseTrace/objectiveTrace record the best-so-far plain RMSE and
    +0056 %     optimised objective per generation. nGenerations is how many
    +0057 %     generations actually ran. converged is true if
    +0058 %     rmseTrace(end) <= params.rmseThreshold.
    +0059 %
    +0060 % Raises
    +0061 % ------
    +0062 % error
    +0063 %     if there are no tunable kcats, or fewer than two free parameters
    +0064 %     remain after masking and tying -- too little for CMA-ES to search
    +0065 %     over.
    +0066 %
    +0067 % See also
    +0068 % --------
    +0069 % screenKcatLeverage, selectTunableMask, tunePriorPenaltyWeight
    +0070 p = parseGECKOargs(varargin, { ...
    +0071     'modelAdapter', []; ...
    +0072     'evoData', []; ...
    +0073     'tunableMask', []; ...
    +0074     'screen', []; ...
    +0075     'targetImpactShare', 0.9; ...
    +0076     'popsize', []; ...
    +0077     'nProc', 1; ...
    +0078     'seed', []; ...
    +0079     'verbose', true});
    +0080 modelAdapter      = p.modelAdapter;
    +0081 evoData           = p.evoData;
    +0082 tunableMask       = p.tunableMask;
    +0083 screen            = p.screen;
    +0084 targetImpactShare = p.targetImpactShare;
    +0085 popsize           = p.popsize;
    +0086 nProc             = max(1, round(p.nProc));
    +0087 seed              = p.seed;
    +0088 verbose           = p.verbose;
    +0089 
    +0090 if isempty(modelAdapter)
    +0091     modelAdapter = ModelAdapterManager.getDefault();
    +0092     if isempty(modelAdapter)
    +0093         error('Either send in a modelAdapter or set the default ecModel adapter in the ModelAdapterManager.')
    +0094     end
    +0095 end
    +0096 params = modelAdapter.params.evotune;
    +0097 if isempty(evoData)
    +0098     evoData = loadEvotuneData('modelAdapter', modelAdapter);
    +0099 end
    +0100 
    +0101 if isempty(tunableMask)
    +0102     if isempty(screen)
    +0103         screen = screenKcatLeverage(ecModel, 'modelAdapter',modelAdapter, ...
    +0104             'evoData',evoData, 'nProc',nProc);
    +0105     end
    +0106     tunableMask = selectTunableMask(ecModel, screen, 'targetImpactShare',targetImpactShare);
    +0107 end
    +0108 
    +0109 [tunableIdx,ecRxnIdsTunable,kcat0,groups,sigma0log,tieMap] = ...
    +0110     resolveTunableContext(ecModel,params,tunableMask);
    +0111 
    +0112 reps = find(tieMap == (1:numel(tieMap))');
    +0113 if numel(reps) < 2
    +0114     error('Only %d free parameter(s) after masking and tying; too few for CMA-ES. Widen tunableMask/targetImpactShare.', numel(reps))
    +0115 end
    +0116 [~,assign] = ismember(tieMap, reps);  % assign(i): which column of reps tieMap(i) follows
    +0117 
    +0118 n = numel(reps);
    +0119 x0  = log(kcat0(reps));
    +0120 sig = sigma0log(reps);
    +0121 [loFull,hiFull] = kcatBoundsLocal(kcat0);
    +0122 loLog = log(loFull(reps));
    +0123 hiLog = log(hiFull(reps));
    +0124 
    +0125 if isempty(popsize)
    +0126     popsize = 4 + floor(3*log(n));
    +0127 end
    +0128 popsize = max(4, round(popsize));
    +0129 
    +0130 expand = @(Xlog) exp(Xlog(assign,:));
    +0131 
    +0132 % Baseline: score the untouched prior, and pick up the excarbon-augmented
    +0133 % model to carry through the rest of the run (see evotuneScore's 4th
    +0134 % output -- avoids rescanning metabolite formulas on every candidate).
    +0135 [obj0,rmse0,~,baseModel] = scoreCandidate(ecModel,tunableIdx,ecRxnIdsTunable,evoData,modelAdapter,params,kcat0,kcat0,sigma0log);
    +0136 bestObj = obj0; bestRmse = rmse0; bestVec = kcat0;
    +0137 
    +0138 rmseTrace = []; objectiveTrace = [];
    +0139 
    +0140 [meanX,sigma,D,pSigma,pC,cs,ds,cc,c1,cmu,muEff,w,mu,chiN] = cmaesInit(x0,sig,popsize);
    +0141 
    +0142 if ~isempty(seed)
    +0143     rng(seed);
    +0144 end
    +0145 
    +0146 generation = 0;
    +0147 while generation < params.maxGenerations
    +0148     Z = randn(n,popsize);
    +0149     Xlog = meanX + sigma * (D .* Z);
    +0150     Xlog = min(max(Xlog,loLog),hiLog);
    +0151     % Recompute Z consistent with any clipping (D>0 throughout by construction).
    +0152     Z = (Xlog - meanX) ./ (sigma * D);
    +0153 
    +0154     kcatMatrix = expand(Xlog);
    +0155     objVals = zeros(popsize,1); rmseVals = zeros(popsize,1);
    +0156     if nProc == 1
    +0157         for k = 1:popsize
    +0158             [objVals(k),rmseVals(k),~,baseModel] = scoreCandidate( ...
    +0159                 baseModel,tunableIdx,ecRxnIdsTunable,evoData,modelAdapter,params, ...
    +0160                 kcatMatrix(:,k),kcat0,sigma0log);
    +0161         end
    +0162     else
    +0163         parfor k = 1:popsize
    +0164             [objVals(k),rmseVals(k)] = scoreCandidate( ...
    +0165                 ecModel,tunableIdx,ecRxnIdsTunable,evoData,modelAdapter,params, ...
    +0166                 kcatMatrix(:,k),kcat0,sigma0log);
    +0167         end
    +0168     end
    +0169     generation = generation + 1;
    +0170 
    +0171     [~,ord] = sort(objVals,'ascend');
    +0172     if objVals(ord(1)) < bestObj
    +0173         bestObj = objVals(ord(1));
    +0174         bestRmse = rmseVals(ord(1));
    +0175         bestVec = kcatMatrix(:,ord(1));
    +0176     end
    +0177     rmseTrace(end+1) = bestRmse; %#ok<AGROW>
    +0178     objectiveTrace(end+1) = bestObj; %#ok<AGROW>
    +0179     if verbose
    +0180         fprintf('generation %d: objective %.4f, rmse %.4f\n', generation, bestObj, bestRmse);
    +0181     end
    +0182     if bestRmse <= params.rmseThreshold
    +0183         break
    +0184     end
    +0185 
    +0186     [meanX,sigma,D,pSigma,pC] = cmaesUpdate( ...
    +0187         meanX,sigma,D,pSigma,pC,Z,ord,w,mu,cs,ds,cc,c1,cmu,muEff,chiN,generation);
    +0188 end
    +0189 
    +0190 ecModel.ec.kcat(tunableIdx) = bestVec;
    +0191 ecModel = applyKcatConstraints(ecModel,'updateRxns',ecRxnIdsTunable);
    +0192 
    +0193 result = struct();
    +0194 result.rxns            = ecRxnIdsTunable;
    +0195 result.oldKcat          = kcat0;
    +0196 result.newKcat          = bestVec;
    +0197 result.groups           = groups;
    +0198 result.rmseTrace        = rmseTrace;
    +0199 result.objectiveTrace   = objectiveTrace;
    +0200 result.nGenerations     = generation;
    +0201 result.converged        = bestRmse <= params.rmseThreshold;
    +0202 end
    +0203 
    +0204 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% Scoring core, shared with screenKcatLeverage/tunePriorPenaltyWeight.
    +0205 
    +0206 function [obj,rmse,rmseDetail,ecModel] = scoreCandidate(ecModel,tunableIdx,ecRxnIdsTunable,evoData,modelAdapter,params,kcatVec,kcat0,sigma0log)
    +0207 ecModel.ec.kcat(tunableIdx) = kcatVec;
    +0208 ecModel = applyKcatConstraints(ecModel,'updateRxns',ecRxnIdsTunable);
    +0209 [obj,rmse,rmseDetail,ecModel] = evotuneScore(ecModel,evoData, ...
    +0210     'modelAdapter',modelAdapter, 'maxGrowthWeight',params.maxGrowthWeight, ...
    +0211     'priorPenaltyWeight',params.priorPenaltyWeight, ...
    +0212     'kcatVec',kcatVec, 'kcat0',kcat0, 'sigma0log',sigma0log);
    +0213 end
    +0214 
    +0215 function [lo,hi] = kcatBoundsLocal(kcat0)
    +0216 % Biologically plausible bounds for proposed kcats, in 1/s. The window is
    +0217 % 1e-2 to 1e4 for an ordinary kcat, and always widened far enough to
    +0218 % contain the prior with a hundred-fold margin either side.
    +0219 lo = min(1e-2, kcat0/100);
    +0220 hi = max(1e4, kcat0*100);
    +0221 end
    +0222 
    +0223 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% Separable (diagonal) CMA-ES core.
    +0224 % Standard (mu/mu_w,lambda)-CMA-ES with a diagonal-only covariance update
    +0225 % (Ros & Hansen 2008), operating in log-kcat space. Sampling, ranking,
    +0226 % recombination, step-size (cumulative step-size adaptation) and
    +0227 % per-coordinate variance updates are the textbook equations; see e.g.
    +0228 % Hansen, "The CMA Evolution Strategy: A Tutorial".
    +0229 
    +0230 function [meanX,sigma,D,pSigma,pC,cs,ds,cc,c1,cmu,muEff,w,mu,chiN] = cmaesInit(x0,sig,popsize)
    +0231 n = numel(x0);
    +0232 mu = floor(popsize/2);
    +0233 wRaw = log(mu+0.5) - log((1:mu)');
    +0234 w = wRaw / sum(wRaw);
    +0235 muEff = 1 / sum(w.^2);
    +0236 
    +0237 cs  = (muEff+2) / (n+muEff+5);
    +0238 ds  = 1 + 2*max(0,sqrt((muEff-1)/(n+1))-1) + cs;
    +0239 cc  = (4+muEff/n) / (n+4+2*muEff/n);
    +0240 c1  = 2 / ((n+1.3)^2+muEff);
    +0241 cmu = min(1-c1, 2*(muEff-2+1/muEff) / ((n+2)^2+muEff));
    +0242 chiN = sqrt(n) * (1 - 1/(4*n) + 1/(21*n^2));
    +0243 
    +0244 meanX = x0;
    +0245 % Initial per-coordinate step scaled by each parameter's own prior sigma
    +0246 % (relative to the median), rather than uniform -- mirrors passing
    +0247 % scaling_of_variables to cma in the Python port.
    +0248 D = sig / median(sig);
    +0249 sigma = median(sig);
    +0250 pSigma = zeros(n,1);
    +0251 pC = zeros(n,1);
    +0252 end
    +0253 
    +0254 function [meanX,sigma,D,pSigma,pC] = cmaesUpdate( ...
    +0255     meanX,sigma,D,pSigma,pC,Z,ord,w,mu,cs,ds,cc,c1,cmu,muEff,chiN,generation)
    +0256 n = numel(meanX);
    +0257 Zbest = Z(:,ord(1:mu));
    +0258 zw = Zbest * w;
    +0259 
    +0260 meanX = meanX + sigma * (D .* zw);
    +0261 
    +0262 pSigma = (1-cs)*pSigma + sqrt(cs*(2-cs)*muEff) * zw;
    +0263 sigma = sigma * exp((cs/ds) * (norm(pSigma)/chiN - 1));
    +0264 
    +0265 hSigmaThresh = (1.4 + 2/(n+1)) * chiN;
    +0266 hSigma = (norm(pSigma) / sqrt(1-(1-cs)^(2*generation))) < hSigmaThresh;
    +0267 
    +0268 pC = (1-cc)*pC + hSigma * sqrt(cc*(2-cc)*muEff) * (D .* zw);
    +0269 
    +0270 Cdiag = D.^2;
    +0271 rankMuTerm = (D.*Zbest).^2 * w;
    +0272 Cdiag = (1-c1-cmu)*Cdiag + c1*(pC.^2 + (1-hSigma)*cc*(2-cc)*Cdiag) + cmu*rankMuTerm;
    +0273 Cdiag = max(Cdiag, 1e-300);
    +0274 D = sqrt(Cdiag);
    +0275 end
    +
    Generated by m2html © 2005
    + + \ No newline at end of file diff --git a/doc/src/kcat_tuning/evotune/evotuneScore.html b/doc/src/kcat_tuning/evotune/evotuneScore.html new file mode 100644 index 00000000..1eaa0322 --- /dev/null +++ b/doc/src/kcat_tuning/evotune/evotuneScore.html @@ -0,0 +1,283 @@ + + + + Description of evotuneScore + + + + + + + + + +
    Home > src > kcat_tuning > evotune > evotuneScore.m
    + + + +

    evotuneScore +

    + +

    PURPOSE ^

    +
    evotuneScore Score one ecModel's current kcats against evotune data.
    + +

    SYNOPSIS ^

    +
    function [objective,rmse,rmseDetail,ecModel] = evotuneScore(ecModel,evoData,varargin)
    + +

    DESCRIPTION ^

    +
     evotuneScore  Score one ecModel's current kcats against evotune data.
    +
    + Internal helper used by cmaesKcatTuning, screenKcatLeverage and
    + tunePriorPenaltyWeight to score one ecModel (with a given set of kcats
    + already applied via applyKcatConstraints) against the experimental
    + growth and flux data. Fuses what geckopy splits into simulate.py (the
    + FBA half) and distance.py (the RMSE half) into one function.
    +
    + Parameters
    + ----------
    + ecModel : struct
    +     ecModel with the current candidate kcats already applied (via
    +     applyKcatConstraints). Not mutated.
    + evoData : struct
    +     structure with experimental data to be used, as returned by
    +     loadEvotuneData.
    +
    + Name-Value Arguments
    + --------------------
    + modelAdapter : ModelAdapter
    +     a loaded model adapter (default: the current default model adapter).
    + maxGrowthWeight : double
    +     relative weight of the max-growth dataset against the flux dataset:
    +     (rmseFlux + w*rmseMaxGrate) / (w+1) (default 1.0).
    + priorPenaltyWeight : double
    +     weight on a prior term added to the objective (default 0, i.e. the
    +     objective equals the plain RMSE). See kcatVec/kcat0/sigma0log below.
    + kcatVec, kcat0, sigma0log : double
    +     only used when priorPenaltyWeight > 0: the tunable kcat subset's
    +     current values, prior values, and per-kcat prior log-space std dev,
    +     all the same length and in the same order. The penalty added to the
    +     objective is priorPenaltyWeight * mean((log(kcatVec./kcat0)./sigma0log).^2).
    +
    + Returns
    + -------
    + objective : double
    +     rmse, plus the prior penalty term when priorPenaltyWeight > 0. This
    +     is what a search should minimise.
    + rmse : double
    +     the plain (unpenalised) average RMSE, always comparable across runs
    +     regardless of priorPenaltyWeight.
    + rmseDetail : cell
    +     per-condition RMSE values, labelled by data type and condition index.
    + ecModel : struct
    +     the input ecModel, with ec.excarbon cached on it if it wasn't
    +     already present. MATLAB structs are copied on assignment, not
    +     shared by reference like a Python object, so callers scoring many
    +     candidates in a loop should carry this output back in as the base
    +     copy for the next candidate, rather than recomputing excarbon (an
    +     expensive metabolite-formula scan) on every single call.
    +
    + See also
    + --------
    + cmaesKcatTuning, screenKcatLeverage, loadEvotuneData
    + + +

    CROSS-REFERENCE INFORMATION ^

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

    SUBFUNCTIONS ^

    + + +

    SOURCE CODE ^

    +
    0001 function [objective,rmse,rmseDetail,ecModel] = evotuneScore(ecModel,evoData,varargin)
    +0002 % evotuneScore  Score one ecModel's current kcats against evotune data.
    +0003 %
    +0004 % Internal helper used by cmaesKcatTuning, screenKcatLeverage and
    +0005 % tunePriorPenaltyWeight to score one ecModel (with a given set of kcats
    +0006 % already applied via applyKcatConstraints) against the experimental
    +0007 % growth and flux data. Fuses what geckopy splits into simulate.py (the
    +0008 % FBA half) and distance.py (the RMSE half) into one function.
    +0009 %
    +0010 % Parameters
    +0011 % ----------
    +0012 % ecModel : struct
    +0013 %     ecModel with the current candidate kcats already applied (via
    +0014 %     applyKcatConstraints). Not mutated.
    +0015 % evoData : struct
    +0016 %     structure with experimental data to be used, as returned by
    +0017 %     loadEvotuneData.
    +0018 %
    +0019 % Name-Value Arguments
    +0020 % --------------------
    +0021 % modelAdapter : ModelAdapter
    +0022 %     a loaded model adapter (default: the current default model adapter).
    +0023 % maxGrowthWeight : double
    +0024 %     relative weight of the max-growth dataset against the flux dataset:
    +0025 %     (rmseFlux + w*rmseMaxGrate) / (w+1) (default 1.0).
    +0026 % priorPenaltyWeight : double
    +0027 %     weight on a prior term added to the objective (default 0, i.e. the
    +0028 %     objective equals the plain RMSE). See kcatVec/kcat0/sigma0log below.
    +0029 % kcatVec, kcat0, sigma0log : double
    +0030 %     only used when priorPenaltyWeight > 0: the tunable kcat subset's
    +0031 %     current values, prior values, and per-kcat prior log-space std dev,
    +0032 %     all the same length and in the same order. The penalty added to the
    +0033 %     objective is priorPenaltyWeight * mean((log(kcatVec./kcat0)./sigma0log).^2).
    +0034 %
    +0035 % Returns
    +0036 % -------
    +0037 % objective : double
    +0038 %     rmse, plus the prior penalty term when priorPenaltyWeight > 0. This
    +0039 %     is what a search should minimise.
    +0040 % rmse : double
    +0041 %     the plain (unpenalised) average RMSE, always comparable across runs
    +0042 %     regardless of priorPenaltyWeight.
    +0043 % rmseDetail : cell
    +0044 %     per-condition RMSE values, labelled by data type and condition index.
    +0045 % ecModel : struct
    +0046 %     the input ecModel, with ec.excarbon cached on it if it wasn't
    +0047 %     already present. MATLAB structs are copied on assignment, not
    +0048 %     shared by reference like a Python object, so callers scoring many
    +0049 %     candidates in a loop should carry this output back in as the base
    +0050 %     copy for the next candidate, rather than recomputing excarbon (an
    +0051 %     expensive metabolite-formula scan) on every single call.
    +0052 %
    +0053 % See also
    +0054 % --------
    +0055 % cmaesKcatTuning, screenKcatLeverage, loadEvotuneData
    +0056 
    +0057 p = parseGECKOargs(varargin, { ...
    +0058     'modelAdapter', []; ...
    +0059     'maxGrowthWeight', 1.0; ...
    +0060     'priorPenaltyWeight', 0.0; ...
    +0061     'kcatVec', []; ...
    +0062     'kcat0', []; ...
    +0063     'sigma0log', []});
    +0064 modelAdapter        = p.modelAdapter;
    +0065 maxGrowthWeight     = p.maxGrowthWeight;
    +0066 priorPenaltyWeight  = p.priorPenaltyWeight;
    +0067 
    +0068 if isempty(modelAdapter)
    +0069     modelAdapter = ModelAdapterManager.getDefault();
    +0070     if isempty(modelAdapter)
    +0071         error('Either send in a modelAdapter or set the default ecModel adapter in the ModelAdapterManager.')
    +0072     end
    +0073 end
    +0074 
    +0075 if ~isfield(ecModel,'excarbon')
    +0076     ecModel = fillCarbonNum(ecModel);
    +0077     ecModel.excarbon(ecModel.excarbon == 0) = 1;
    +0078 end
    +0079 
    +0080 rmse_1 = []; rmseDetail1 = []; rmse_2 = []; rmseDetail2 = [];
    +0081 
    +0082 if ~isempty(evoData.fluxData)
    +0083     [rmse_1, rmseDetail1] = simulateCondition(ecModel,evoData.fluxData,true,evoData.zeroFlux,modelAdapter);
    +0084     rmseDetail1 = [cellstr("fluxData_" + string(1:numel(rmseDetail1)))',num2cell(rmseDetail1)];
    +0085 end
    +0086 if ~isempty(evoData.maxGrate)
    +0087     [rmse_2, rmseDetail2] = simulateCondition(ecModel,evoData.maxGrate,false,evoData.zeroFlux,modelAdapter);
    +0088     rmseDetail2 = [cellstr("maxGrowth_" + string(1:numel(rmseDetail2)))',num2cell(rmseDetail2)];
    +0089 end
    +0090 
    +0091 parts = []; weights = [];
    +0092 if ~isempty(rmse_1)
    +0093     parts(end+1) = rmse_1; weights(end+1) = 1.0;
    +0094 end
    +0095 if ~isempty(rmse_2)
    +0096     parts(end+1) = rmse_2; weights(end+1) = maxGrowthWeight;
    +0097 end
    +0098 if isempty(parts)
    +0099     rmse = NaN;
    +0100 else
    +0101     rmse = sum(parts .* weights) / sum(weights);
    +0102 end
    +0103 rmseDetail = [rmseDetail1;rmseDetail2];
    +0104 
    +0105 objective = rmse;
    +0106 if priorPenaltyWeight > 0 && ~isempty(p.kcatVec) && ~isempty(p.kcat0) && ~isempty(p.sigma0log)
    +0107     dev = log(p.kcatVec(:) ./ p.kcat0(:)) ./ p.sigma0log(:);
    +0108     objective = rmse + priorPenaltyWeight * mean(dev.^2);
    +0109 end
    +0110 end
    +0111 
    +0112 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
    +0113 function [rmse, rmseList] = simulateCondition(ecModel,data,constrain,rxn2block,modelAdapter)
    +0114 % One condition's FBA simulation + carbon-weighted RMSE against measured
    +0115 % data.
    +0116 
    +0117 rmseList = zeros(length(data.conds),1);
    +0118 
    +0119 [~,exchIdx] = ismember(data.conds,data.exchMets);
    +0120 if any(exchIdx == 0)
    +0121     missingMets = strjoin(unique(data.conds(exchIdx == 0)), '; ');
    +0122     error('Carbon source(s) "%s" in the provided fluxData or maxGrowth cannot be matched by name with an exchange reaction.', missingMets);
    +0123 end
    +0124 
    +0125 for i = 1:length(data.conds)
    +0126     % Set all other carbon sources to zero, then unblock this condition's
    +0127     model_tmp = setParam(ecModel,'lb',data.exchRxnIDs(unique(exchIdx)),0);
    +0128     if constrain % RMSE from flux data: constrain carbon uptake at the measured rate
    +0129         model_tmp = setParam(model_tmp,'lb',data.exchRxnIDs(exchIdx(i)),data.exchFluxes(i,exchIdx(i)));
    +0130     else % RMSE from max growth: leave carbon uptake fully open
    +0131         model_tmp = setParam(model_tmp,'lb',data.exchRxnIDs(exchIdx(i)),-1000);
    +0132     end
    +0133 
    +0134     % This row's own carbon source is never itself asserted zero-flux.
    +0135     rxn2blockIter = rxn2block;
    +0136     rxn2blockIter(strcmp(rxn2blockIter,data.exchRxnIDs(exchIdx(i)))) = [];
    +0137 
    +0138     o2Flux = data.exchFluxes(i,strcmp('oxygen',data.exchMets));
    +0139     if o2Flux == 0
    +0140         model_tmp = modelAdapter.makeModelAnaerobic(model_tmp);
    +0141     end
    +0142     if ~(isnan(data.Ptot(i)) || data.Ptot(i) == 0)
    +0143         model_tmp = modelAdapter.changeProteinBiomass(model_tmp,data.Ptot(i));
    +0144     end
    +0145 
    +0146     sol = solveLP(model_tmp);
    +0147     if checkSolution(sol)
    +0148         bioRxn  = getIndexes(model_tmp,data.biomass,'rxns');
    +0149         % Biomass carries an assumed 41 Cmmol/gDCW, matching fillCarbonNum.
    +0150         bioMeas = data.grRate(i) * 41;
    +0151         bioSim  = sol.x(bioRxn) * 41;
    +0152 
    +0153         if constrain
    +0154             fluxToCheck   = ~isnan(data.exchFluxes(i,:));
    +0155             fluxRxnIdx    = getIndexes(model_tmp,data.exchRxnIDs(fluxToCheck),'rxns');
    +0156             cNormMeasFlux = model_tmp.excarbon(fluxRxnIdx) .* transpose(data.exchFluxes(i,fluxToCheck));
    +0157             cNormSimFlux  = model_tmp.excarbon(fluxRxnIdx) .* sol.x(fluxRxnIdx);
    +0158 
    +0159             blockRxnIdx = getIndexes(model_tmp,rxn2blockIter,'rxns');
    +0160             blockSim    = sol.x(blockRxnIdx) .* model_tmp.excarbon(blockRxnIdx);
    +0161             % Already-correct zero predictions don't dilute the RMSE.
    +0162             blockSim(blockSim == 0) = [];
    +0163             blockMeas = zeros(numel(blockSim),1);
    +0164 
    +0165             measured  = [cNormMeasFlux; bioMeas; blockMeas];
    +0166             simulated = [cNormSimFlux; bioSim; blockSim];
    +0167         else
    +0168             measured  = bioMeas;
    +0169             simulated = bioSim;
    +0170         end
    +0171         rmseList(i) = sqrt(mean((measured - simulated).^2));
    +0172     else
    +0173         rmseList(i) = NaN;
    +0174     end
    +0175 end
    +0176 rmseList(isnan(rmseList)) = 99; % Fixed penalty for an infeasible condition.
    +0177 if isfield(data,'evotuneRMSEweight') && ~isempty(data.evotuneRMSEweight)
    +0178     rmseList = rmseList .* data.evotuneRMSEweight;
    +0179 end
    +0180 rmse = mean(rmseList);
    +0181 end
    +
    Generated by m2html © 2005
    + + \ No newline at end of file diff --git a/doc/src/kcat_tuning/evotune/index.html b/doc/src/kcat_tuning/evotune/index.html new file mode 100644 index 00000000..36e5aa4b --- /dev/null +++ b/doc/src/kcat_tuning/evotune/index.html @@ -0,0 +1,29 @@ + + + + Index for Directory src/kcat_tuning/evotune + + + + + + + + + + +
    < Master indexIndex for src/kcat_tuning/evotune >
    + +

    Index for src/kcat_tuning/evotune

    + +

    Matlab files in this directory:

    + +
     bestParsimoniousbestParsimonious The fewest-changes point whose RMSE is within
     cmaesKcatTuningcmaesKcatTuning Tune kcats against experimental data with CMA-ES.
     evotuneScoreevotuneScore Score one ecModel's current kcats against evotune data.
     isozymeTieMapisozymeTieMap Index of the parameter each isozyme copy follows.
     loadEvotuneDataloadEvotuneData Load experimental data for evotune (CMA-ES) kcat tuning.
     nChangednChanged How many kcats differ from their prior by more than relTol.
     parsimonyFrontierparsimonyFrontier Score kcat with progressively more of it reverted to
     resolveTunableContextresolveTunableContext The tunable kcat subset plus everything derived
     screenKcatLeveragescreenKcatLeverage Report which kcats the data can actually speak to.
     selectTunableMaskselectTunableMask Build a tunableMask from a screenKcatLeverage report.
     tunePriorPenaltyWeighttunePriorPenaltyWeight Sweep priorPenaltyWeight and report the
    + + + + +
    Generated by m2html © 2005
    + + \ No newline at end of file diff --git a/doc/src/kcat_tuning/evotune/isozymeTieMap.html b/doc/src/kcat_tuning/evotune/isozymeTieMap.html new file mode 100644 index 00000000..89323f72 --- /dev/null +++ b/doc/src/kcat_tuning/evotune/isozymeTieMap.html @@ -0,0 +1,165 @@ + + + + Description of isozymeTieMap + + + + + + + + + +
    Home > src > kcat_tuning > evotune > isozymeTieMap.m
    + + + +

    isozymeTieMap +

    + +

    PURPOSE ^

    +
    isozymeTieMap Index of the parameter each isozyme copy follows.
    + +

    SYNOPSIS ^

    +
    function tieMap = isozymeTieMap(rxnIds,kcat0,varargin)
    + +

    DESCRIPTION ^

    +
     isozymeTieMap  Index of the parameter each isozyme copy follows.
    +
    + A reaction catalysed by several isozymes gets one ec.rxns row per
    + isozyme, each with its own kcat. Where the kcat assignment could tell
    + them apart, those are genuinely different parameters; where it could
    + not, every copy shares the same value from the same source, and an
    + untied search is then free to invent a difference between them that
    + means nothing biologically. Copies group together (and share one
    + parameter) when they share a base reaction (the part of the rxn id
    + before its "_EXP_" isozyme suffix), a prior value, and -- when sources
    + is given -- a source.
    +
    + Parameters
    + ----------
    + rxnIds : cell
    +     ec.rxns entries.
    + kcat0 : double
    +     prior kcat per row, same length as rxnIds.
    +
    + Name-Value Arguments
    + --------------------
    + sources : cell
    +     ec.source entries, same length as rxnIds (default: not used, so
    +     grouping ignores source).
    + relTol : double
    +     relative tolerance for treating two prior values as equal (default
    +     1e-9).
    +
    + Returns
    + -------
    + tieMap : double
    +     one entry per position. tieMap(i) == i for a free parameter,
    +     otherwise the (lower) index of the representative it follows.
    +
    + See also
    + --------
    + cmaesKcatTuning, screenKcatLeverage
    + + +

    CROSS-REFERENCE INFORMATION ^

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

    SUBFUNCTIONS ^

    + + +

    SOURCE CODE ^

    +
    0001 function tieMap = isozymeTieMap(rxnIds,kcat0,varargin)
    +0002 % isozymeTieMap  Index of the parameter each isozyme copy follows.
    +0003 %
    +0004 % A reaction catalysed by several isozymes gets one ec.rxns row per
    +0005 % isozyme, each with its own kcat. Where the kcat assignment could tell
    +0006 % them apart, those are genuinely different parameters; where it could
    +0007 % not, every copy shares the same value from the same source, and an
    +0008 % untied search is then free to invent a difference between them that
    +0009 % means nothing biologically. Copies group together (and share one
    +0010 % parameter) when they share a base reaction (the part of the rxn id
    +0011 % before its "_EXP_" isozyme suffix), a prior value, and -- when sources
    +0012 % is given -- a source.
    +0013 %
    +0014 % Parameters
    +0015 % ----------
    +0016 % rxnIds : cell
    +0017 %     ec.rxns entries.
    +0018 % kcat0 : double
    +0019 %     prior kcat per row, same length as rxnIds.
    +0020 %
    +0021 % Name-Value Arguments
    +0022 % --------------------
    +0023 % sources : cell
    +0024 %     ec.source entries, same length as rxnIds (default: not used, so
    +0025 %     grouping ignores source).
    +0026 % relTol : double
    +0027 %     relative tolerance for treating two prior values as equal (default
    +0028 %     1e-9).
    +0029 %
    +0030 % Returns
    +0031 % -------
    +0032 % tieMap : double
    +0033 %     one entry per position. tieMap(i) == i for a free parameter,
    +0034 %     otherwise the (lower) index of the representative it follows.
    +0035 %
    +0036 % See also
    +0037 % --------
    +0038 % cmaesKcatTuning, screenKcatLeverage
    +0039 p = parseGECKOargs(varargin, { ...
    +0040     'sources', []; ...
    +0041     'relTol', 1e-9});
    +0042 sources = p.sources;
    +0043 relTol  = p.relTol;
    +0044 
    +0045 n = numel(kcat0);
    +0046 if numel(rxnIds) ~= n
    +0047     error('rxnIds has %d entries; kcat0 has %d.', numel(rxnIds), n)
    +0048 end
    +0049 tieMap = (1:n)';
    +0050 
    +0051 keys = cell(n,1);
    +0052 for i = 1:n
    +0053     base = baseReaction(rxnIds{i});
    +0054     if kcat0(i) > 0
    +0055         logKey = sprintf('%d', round(log(kcat0(i)) / relTol));
    +0056     else
    +0057         logKey = 'NONE';
    +0058     end
    +0059     if isempty(sources)
    +0060         srcKey = '';
    +0061     else
    +0062         srcKey = char(sources{i});
    +0063     end
    +0064     keys{i} = strjoin({base, logKey, srcKey}, char(31));
    +0065 end
    +0066 
    +0067 [~, ~, groupIdx] = unique(keys);
    +0068 for g = 1:max(groupIdx)
    +0069     members = find(groupIdx == g);
    +0070     if numel(members) > 1
    +0071         tieMap(members) = members(1);
    +0072     end
    +0073 end
    +0074 end
    +0075 
    +0076 function base = baseReaction(rxnId)
    +0077 % The reaction an ec.rxns entry belongs to, isozyme suffix removed.
    +0078 parts = strsplit(rxnId, '_EXP_');
    +0079 base = parts{1};
    +0080 end
    +
    Generated by m2html © 2005
    + + \ No newline at end of file diff --git a/doc/src/kcat_tuning/evotune/loadEvotuneData.html b/doc/src/kcat_tuning/evotune/loadEvotuneData.html new file mode 100644 index 00000000..97a7e2be --- /dev/null +++ b/doc/src/kcat_tuning/evotune/loadEvotuneData.html @@ -0,0 +1,144 @@ + + + + Description of loadEvotuneData + + + + + + + + + +
    Home > src > kcat_tuning > evotune > loadEvotuneData.m
    + + + +

    loadEvotuneData +

    + +

    PURPOSE ^

    +
    loadEvotuneData Load experimental data for evotune (CMA-ES) kcat tuning.
    + +

    SYNOPSIS ^

    +
    function evoData = loadEvotuneData(varargin)
    + +

    DESCRIPTION ^

    +
     loadEvotuneData  Load experimental data for evotune (CMA-ES) kcat tuning.
    +
    + Reads the three experimental data files used by cmaesKcatTuning from the
    + data subfolder of the model directory defined by the model adapter. Each
    + file is optional: a missing file yields [] (fluxData/maxGrate) or an
    + empty cell array (zeroFlux) rather than an error.
    +
    + Name-Value Arguments
    + --------------------
    + modelAdapter : ModelAdapter
    +     a loaded model adapter (default: the current default model adapter).
    +
    + Returns
    + -------
    + evoData : struct
    +     structure with the loaded experimental data.
    +
    + Notes
    + -----
    + The evoData structure has the following fields:
    +
    + - fluxData : flux data loaded from evotuneFluxData.tsv, with the biomass
    +   reaction id stored in fluxData.biomass. [] if that file isn't present.
    + - maxGrate : maximum growth-rate data loaded from evotuneMaxGrowth.tsv,
    +   with the biomass reaction id stored in maxGrate.biomass. [] if that
    +   file isn't present.
    + - zeroFlux : reaction IDs assumed to carry zero flux, loaded from
    +   evotuneZeroExch.tsv. Empty cell array if that file isn't present.
    +
    + See also
    + --------
    + cmaesKcatTuning, evotuneScore
    + + +

    CROSS-REFERENCE INFORMATION ^

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

    SOURCE CODE ^

    +
    0001 function evoData = loadEvotuneData(varargin)
    +0002 % loadEvotuneData  Load experimental data for evotune (CMA-ES) kcat tuning.
    +0003 %
    +0004 % Reads the three experimental data files used by cmaesKcatTuning from the
    +0005 % data subfolder of the model directory defined by the model adapter. Each
    +0006 % file is optional: a missing file yields [] (fluxData/maxGrate) or an
    +0007 % empty cell array (zeroFlux) rather than an error.
    +0008 %
    +0009 % Name-Value Arguments
    +0010 % --------------------
    +0011 % modelAdapter : ModelAdapter
    +0012 %     a loaded model adapter (default: the current default model adapter).
    +0013 %
    +0014 % Returns
    +0015 % -------
    +0016 % evoData : struct
    +0017 %     structure with the loaded experimental data.
    +0018 %
    +0019 % Notes
    +0020 % -----
    +0021 % The evoData structure has the following fields:
    +0022 %
    +0023 % - fluxData : flux data loaded from evotuneFluxData.tsv, with the biomass
    +0024 %   reaction id stored in fluxData.biomass. [] if that file isn't present.
    +0025 % - maxGrate : maximum growth-rate data loaded from evotuneMaxGrowth.tsv,
    +0026 %   with the biomass reaction id stored in maxGrate.biomass. [] if that
    +0027 %   file isn't present.
    +0028 % - zeroFlux : reaction IDs assumed to carry zero flux, loaded from
    +0029 %   evotuneZeroExch.tsv. Empty cell array if that file isn't present.
    +0030 %
    +0031 % See also
    +0032 % --------
    +0033 % cmaesKcatTuning, evotuneScore
    +0034 p = parseGECKOargs(varargin, { ...
    +0035     'modelAdapter', []});
    +0036 modelAdapter = p.modelAdapter;
    +0037 
    +0038 if isempty(modelAdapter)
    +0039     modelAdapter = ModelAdapterManager.getDefault();
    +0040     if isempty(modelAdapter)
    +0041         error('Either send in a modelAdapter or set the default ecModel adapter in the ModelAdapterManager.')
    +0042     end
    +0043 end
    +0044 
    +0045 basePath = modelAdapter.params.path;
    +0046 
    +0047 evoData.fluxData = loadFluxData(fullfile(basePath,'data','evotuneFluxData.tsv'), modelAdapter);
    +0048 if ~isempty(evoData.fluxData)
    +0049     evoData.fluxData.biomass = modelAdapter.params.bioRxn;
    +0050 end
    +0051 
    +0052 evoData.maxGrate = loadFluxData(fullfile(basePath,'data','evotuneMaxGrowth.tsv'), modelAdapter);
    +0053 if ~isempty(evoData.maxGrate)
    +0054     evoData.maxGrate.biomass = modelAdapter.params.bioRxn;
    +0055 end
    +0056 
    +0057 % Unlike loadFluxData (used for fluxData/maxGrate above, which already
    +0058 % degrades to [] on a missing file), readtable has no such guard, so this
    +0059 % is wrapped explicitly to keep all three files uniformly optional.
    +0060 zeroExchFile = fullfile(basePath,'data','evotuneZeroExch.tsv');
    +0061 if isfile(zeroExchFile)
    +0062     evoData.zeroFlux = table2cell(readtable(zeroExchFile, 'Delimiter', '\t', 'FileType','delimitedtext'));
    +0063 else
    +0064     evoData.zeroFlux = {};
    +0065 end
    +0066 end
    +
    Generated by m2html © 2005
    + + \ No newline at end of file diff --git a/doc/src/kcat_tuning/evotune/nChanged.html b/doc/src/kcat_tuning/evotune/nChanged.html new file mode 100644 index 00000000..b9058947 --- /dev/null +++ b/doc/src/kcat_tuning/evotune/nChanged.html @@ -0,0 +1,98 @@ + + + + Description of nChanged + + + + + + + + + +
    Home > src > kcat_tuning > evotune > nChanged.m
    + + + +

    nChanged +

    + +

    PURPOSE ^

    +
    nChanged How many kcats differ from their prior by more than relTol.
    + +

    SYNOPSIS ^

    +
    function n = nChanged(kcat,kcat0,varargin)
    + +

    DESCRIPTION ^

    +
     nChanged  How many kcats differ from their prior by more than relTol.
    +
    + The 2% default matches the threshold MATLAB's own per-source
    + "unchanged" reporting has historically used.
    +
    + Parameters
    + ----------
    + kcat, kcat0 : double
    +     tuned and prior kcat vectors, same length.
    +
    + Name-Value Arguments
    + --------------------
    + relTol : double
    +     default 0.02.
    +
    + Returns
    + -------
    + n : double
    +     count of entries where abs(log(kcat./kcat0)) > log1p(relTol).
    +
    + See also
    + --------
    + tunePriorPenaltyWeight, parsimonyFrontier
    + + +

    CROSS-REFERENCE INFORMATION ^

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

    SOURCE CODE ^

    +
    0001 function n = nChanged(kcat,kcat0,varargin)
    +0002 % nChanged  How many kcats differ from their prior by more than relTol.
    +0003 %
    +0004 % The 2% default matches the threshold MATLAB's own per-source
    +0005 % "unchanged" reporting has historically used.
    +0006 %
    +0007 % Parameters
    +0008 % ----------
    +0009 % kcat, kcat0 : double
    +0010 %     tuned and prior kcat vectors, same length.
    +0011 %
    +0012 % Name-Value Arguments
    +0013 % --------------------
    +0014 % relTol : double
    +0015 %     default 0.02.
    +0016 %
    +0017 % Returns
    +0018 % -------
    +0019 % n : double
    +0020 %     count of entries where abs(log(kcat./kcat0)) > log1p(relTol).
    +0021 %
    +0022 % See also
    +0023 % --------
    +0024 % tunePriorPenaltyWeight, parsimonyFrontier
    +0025 p = parseGECKOargs(varargin, { ...
    +0026     'relTol', 0.02});
    +0027 relTol = p.relTol;
    +0028 n = sum(abs(log(kcat(:) ./ kcat0(:))) > log1p(relTol));
    +0029 end
    +
    Generated by m2html © 2005
    + + \ No newline at end of file diff --git a/doc/src/kcat_tuning/evotune/parsimonyFrontier.html b/doc/src/kcat_tuning/evotune/parsimonyFrontier.html new file mode 100644 index 00000000..9add89f4 --- /dev/null +++ b/doc/src/kcat_tuning/evotune/parsimonyFrontier.html @@ -0,0 +1,163 @@ + + + + Description of parsimonyFrontier + + + + + + + + + +
    Home > src > kcat_tuning > evotune > parsimonyFrontier.m
    + + + +

    parsimonyFrontier +

    + +

    PURPOSE ^

    +
    parsimonyFrontier Score kcat with progressively more of it reverted to
    + +

    SYNOPSIS ^

    +
    function points = parsimonyFrontier(scoreFcn,kcat,kcat0,sigma0log,varargin)
    + +

    DESCRIPTION ^

    +
     parsimonyFrontier  Score kcat with progressively more of it reverted to
    + prior.
    +
    + A tuned kcat vector that fits well by rewriting every parameter is not
    + a useful answer: changes should be few, and concentrated in the
    + parameters least confident about. This sweeps a revert-threshold (in
    + units of each kcat's own prior sigma) and reports how RMSE trades off
    + against how many kcats stayed at their tuned value, so a sparser
    + result within noise of the best fit can be preferred over the raw
    + tuner output. See bestParsimonious to pick a point off this frontier.
    +
    + Parameters
    + ----------
    + scoreFcn : function_handle
    +     scores one kcat vector; called once per threshold. Build it against
    +     a specific ecModel/evoData, e.g.
    +         scoreFcn = @(vec) evotuneScoreVector(ecModel,tunableIdx, ...
    +             ecRxnIdsTunable,evoData,modelAdapter,params,vec);
    +     where evotuneScoreVector applies vec to ecModel.ec.kcat(tunableIdx),
    +     calls applyKcatConstraints, and returns evotuneScore's plain rmse.
    + kcat, kcat0, sigma0log : double
    +     tuned vector, prior vector, and per-kcat prior sigma, all the same
    +     length.
    +
    + Name-Value Arguments
    + --------------------
    + thresholds : double
    +     sigma cutoffs to sweep, ascending (default
    +     [0 1 2 3 4 6 8 10 15]). 0 reverts nothing, reproducing kcat's own
    +     score.
    +
    + Returns
    + -------
    + points : struct array
    +     one entry per threshold, in the order given: threshold, kcat (the
    +     partially-reverted vector), nChanged, meanDev (mean movement in
    +     sigma units), rmse.
    +
    + See also
    + --------
    + bestParsimonious, nChanged
    + + +

    CROSS-REFERENCE INFORMATION ^

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

    SUBFUNCTIONS ^

    + + +

    SOURCE CODE ^

    +
    0001 function points = parsimonyFrontier(scoreFcn,kcat,kcat0,sigma0log,varargin)
    +0002 % parsimonyFrontier  Score kcat with progressively more of it reverted to
    +0003 % prior.
    +0004 %
    +0005 % A tuned kcat vector that fits well by rewriting every parameter is not
    +0006 % a useful answer: changes should be few, and concentrated in the
    +0007 % parameters least confident about. This sweeps a revert-threshold (in
    +0008 % units of each kcat's own prior sigma) and reports how RMSE trades off
    +0009 % against how many kcats stayed at their tuned value, so a sparser
    +0010 % result within noise of the best fit can be preferred over the raw
    +0011 % tuner output. See bestParsimonious to pick a point off this frontier.
    +0012 %
    +0013 % Parameters
    +0014 % ----------
    +0015 % scoreFcn : function_handle
    +0016 %     scores one kcat vector; called once per threshold. Build it against
    +0017 %     a specific ecModel/evoData, e.g.
    +0018 %         scoreFcn = @(vec) evotuneScoreVector(ecModel,tunableIdx, ...
    +0019 %             ecRxnIdsTunable,evoData,modelAdapter,params,vec);
    +0020 %     where evotuneScoreVector applies vec to ecModel.ec.kcat(tunableIdx),
    +0021 %     calls applyKcatConstraints, and returns evotuneScore's plain rmse.
    +0022 % kcat, kcat0, sigma0log : double
    +0023 %     tuned vector, prior vector, and per-kcat prior sigma, all the same
    +0024 %     length.
    +0025 %
    +0026 % Name-Value Arguments
    +0027 % --------------------
    +0028 % thresholds : double
    +0029 %     sigma cutoffs to sweep, ascending (default
    +0030 %     [0 1 2 3 4 6 8 10 15]). 0 reverts nothing, reproducing kcat's own
    +0031 %     score.
    +0032 %
    +0033 % Returns
    +0034 % -------
    +0035 % points : struct array
    +0036 %     one entry per threshold, in the order given: threshold, kcat (the
    +0037 %     partially-reverted vector), nChanged, meanDev (mean movement in
    +0038 %     sigma units), rmse.
    +0039 %
    +0040 % See also
    +0041 % --------
    +0042 % bestParsimonious, nChanged
    +0043 p = parseGECKOargs(varargin, { ...
    +0044     'thresholds', [0 1 2 3 4 6 8 10 15]});
    +0045 thresholds = p.thresholds;
    +0046 
    +0047 kcat0     = kcat0(:);
    +0048 sigma0log = sigma0log(:);
    +0049 kcat      = kcat(:);
    +0050 
    +0051 points = repmat(struct('threshold',[],'kcat',[],'nChanged',[],'meanDev',[],'rmse',[]), ...
    +0052     numel(thresholds), 1);
    +0053 for t = 1:numel(thresholds)
    +0054     thr = thresholds(t);
    +0055     vec = revertBelow(kcat,kcat0,sigma0log,thr);
    +0056     points(t).threshold = thr;
    +0057     points(t).kcat       = vec;
    +0058     points(t).nChanged   = nChanged(vec,kcat0);
    +0059     points(t).meanDev    = mean(movementInSigma(vec,kcat0,sigma0log));
    +0060     points(t).rmse       = scoreFcn(vec);
    +0061 end
    +0062 end
    +0063 
    +0064 function dev = movementInSigma(kcat,kcat0,sigma0log)
    +0065 % Per-kcat displacement from the prior, in prior standard deviations.
    +0066 dev = abs(log(kcat ./ kcat0)) ./ sigma0log;
    +0067 end
    +0068 
    +0069 function vec = revertBelow(kcat,kcat0,sigma0log,threshold)
    +0070 % Put every kcat that moved less than threshold sigma back on its prior.
    +0071 keep = movementInSigma(kcat,kcat0,sigma0log) >= threshold;
    +0072 vec = kcat0;
    +0073 vec(keep) = kcat(keep);
    +0074 end
    +
    Generated by m2html © 2005
    + + \ No newline at end of file diff --git a/doc/src/kcat_tuning/evotune/resolveTunableContext.html b/doc/src/kcat_tuning/evotune/resolveTunableContext.html new file mode 100644 index 00000000..701fb372 --- /dev/null +++ b/doc/src/kcat_tuning/evotune/resolveTunableContext.html @@ -0,0 +1,144 @@ + + + + Description of resolveTunableContext + + + + + + + + + +
    Home > src > kcat_tuning > evotune > resolveTunableContext.m
    + + + +

    resolveTunableContext +

    + +

    PURPOSE ^

    +
    resolveTunableContext The tunable kcat subset plus everything derived
    + +

    SYNOPSIS ^

    +
    function [tunableIdx,ecRxnIdsTunable,kcat0,groups,sigma0log,tieMap] = resolveTunableContext(ecModel,params,tunableMask)
    + +

    DESCRIPTION ^

    +
     resolveTunableContext  The tunable kcat subset plus everything derived
    + from it: source-group trust tiers and isozyme tie groups.
    +
    + Shared by screenKcatLeverage and cmaesKcatTuning so a screen and the
    + tuning run it feeds are always looking at exactly the same parameters.
    +
    + Parameters
    + ----------
    + ecModel : struct
    +     ecModel with a populated ec.kcat.
    + params : struct
    +     modelAdapter.params.evotune (kcatSources, sigma0logSource,
    +     sigma0logDefault, tieIsozymes).
    + tunableMask : logical
    +     same length as ecModel.ec.rxns; [] to consider every kcat > 0.
    +
    + Returns
    + -------
    + tunableIdx : double
    +     indices into ecModel.ec.rxns/ec.kcat of the tunable subset.
    + ecRxnIdsTunable : cell
    + kcat0 : double
    + groups : cell
    +     source-group name per tunable row ('unlabelled' if unmatched).
    + sigma0log : double
    +     per-row prior std dev in log-space.
    + tieMap : double
    +     isozymeTieMap(ecRxnIdsTunable,kcat0,'sources',groups) if
    +     params.tieIsozymes, otherwise every row is its own free parameter.
    +
    + See also
    + --------
    + screenKcatLeverage, cmaesKcatTuning, isozymeTieMap
    + + +

    CROSS-REFERENCE INFORMATION ^

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

    SOURCE CODE ^

    +
    0001 function [tunableIdx,ecRxnIdsTunable,kcat0,groups,sigma0log,tieMap] = resolveTunableContext(ecModel,params,tunableMask)
    +0002 % resolveTunableContext  The tunable kcat subset plus everything derived
    +0003 % from it: source-group trust tiers and isozyme tie groups.
    +0004 %
    +0005 % Shared by screenKcatLeverage and cmaesKcatTuning so a screen and the
    +0006 % tuning run it feeds are always looking at exactly the same parameters.
    +0007 %
    +0008 % Parameters
    +0009 % ----------
    +0010 % ecModel : struct
    +0011 %     ecModel with a populated ec.kcat.
    +0012 % params : struct
    +0013 %     modelAdapter.params.evotune (kcatSources, sigma0logSource,
    +0014 %     sigma0logDefault, tieIsozymes).
    +0015 % tunableMask : logical
    +0016 %     same length as ecModel.ec.rxns; [] to consider every kcat > 0.
    +0017 %
    +0018 % Returns
    +0019 % -------
    +0020 % tunableIdx : double
    +0021 %     indices into ecModel.ec.rxns/ec.kcat of the tunable subset.
    +0022 % ecRxnIdsTunable : cell
    +0023 % kcat0 : double
    +0024 % groups : cell
    +0025 %     source-group name per tunable row ('unlabelled' if unmatched).
    +0026 % sigma0log : double
    +0027 %     per-row prior std dev in log-space.
    +0028 % tieMap : double
    +0029 %     isozymeTieMap(ecRxnIdsTunable,kcat0,'sources',groups) if
    +0030 %     params.tieIsozymes, otherwise every row is its own free parameter.
    +0031 %
    +0032 % See also
    +0033 % --------
    +0034 % screenKcatLeverage, cmaesKcatTuning, isozymeTieMap
    +0035 isTunable = ecModel.ec.kcat > 0;
    +0036 if ~isempty(tunableMask)
    +0037     isTunable = isTunable & tunableMask(:);
    +0038 end
    +0039 tunableIdx = find(isTunable);
    +0040 if isempty(tunableIdx)
    +0041     if isempty(tunableMask)
    +0042         error('No tunable kcats: ecModel.ec.kcat is all <= 0.')
    +0043     else
    +0044         error('No tunable kcats: ecModel.ec.kcat is all <= 0, or tunableMask excludes every one with a kcat.')
    +0045     end
    +0046 end
    +0047 
    +0048 ecRxnIdsTunable = ecModel.ec.rxns(tunableIdx);
    +0049 kcat0           = ecModel.ec.kcat(tunableIdx);
    +0050 sources         = ecModel.ec.source(tunableIdx);
    +0051 
    +0052 groups    = repmat({'unlabelled'}, numel(tunableIdx), 1);
    +0053 sigma0log = params.sigma0logDefault * ones(numel(tunableIdx),1);
    +0054 for i = 1:numel(params.kcatSources)
    +0055     idx = strcmpi(sources, params.kcatSources{i});
    +0056     groups(idx)    = params.kcatSources(i);
    +0057     sigma0log(idx) = params.sigma0logSource(i);
    +0058 end
    +0059 
    +0060 if isfield(params,'tieIsozymes') && params.tieIsozymes
    +0061     tieMap = isozymeTieMap(ecRxnIdsTunable, kcat0, 'sources', groups);
    +0062 else
    +0063     tieMap = (1:numel(kcat0))';
    +0064 end
    +0065 end
    +
    Generated by m2html © 2005
    + + \ No newline at end of file diff --git a/doc/src/kcat_tuning/evotune/screenKcatLeverage.html b/doc/src/kcat_tuning/evotune/screenKcatLeverage.html new file mode 100644 index 00000000..005602ad --- /dev/null +++ b/doc/src/kcat_tuning/evotune/screenKcatLeverage.html @@ -0,0 +1,246 @@ + + + + Description of screenKcatLeverage + + + + + + + + + +
    Home > src > kcat_tuning > evotune > screenKcatLeverage.m
    + + + +

    screenKcatLeverage +

    + +

    PURPOSE ^

    +
    screenKcatLeverage Report which kcats the data can actually speak to.
    + +

    SYNOPSIS ^

    +
    function screen = screenKcatLeverage(ecModel,varargin)
    + +

    DESCRIPTION ^

    +
     screenKcatLeverage  Report which kcats the data can actually speak to.
    +
    + No optimisation happens here -- this only says which parameters are
    + worth curating or tuning, and can be read on its own well before any
    + tuning run. Each tie-group (isozyme copies sharing a prior and a source
    + move together when params.tieIsozymes) is perturbed up and down by
    + fold, and its leverage is the largest resulting change in RMSE. Groups
    + are ranked by that leverage weighted by sigma0log: a trusted source
    + needs proportionally more measured effect to rank alongside an
    + untrusted one.
    +
    + Costs one simulation per condition per tie-group probed (two probes
    + each, up and down) plus one baseline -- comparable in scale to a full
    + tuning run's evaluation budget, not a cheap pre-check.
    +
    + Parameters
    + ----------
    + ecModel : struct
    +     ecModel with a populated ec.kcat.
    +
    + Name-Value Arguments
    + --------------------
    + modelAdapter : ModelAdapter
    +     a loaded model adapter (default: the current default model adapter).
    + evoData : struct
    +     as returned by loadEvotuneData (default: loaded from modelAdapter).
    + tunableMask : logical
    +     restrict which kcats are screened (default: every ec.kcat > 0).
    + fold : double
    +     fold-change used to perturb each tie-group up and down (default 2.0).
    + nProc : double
    +     number of parallel workers used to score candidate vectors (default
    +     1, i.e. serial). Requires Parallel Computing Toolbox for > 1.
    +
    + Returns
    + -------
    + screen : table
    +     one row per tie-group, sorted by rank descending: rxnId (the
    +     group's representative), nIsozymes, sourceGroup, kcat0, leverage,
    +     sigma0log, rank (leverage*sigma0log), cumLeverageShare (running
    +     total of rank as a fraction of its sum), and positions (a cell
    +     array of indices into ecModel.ec.rxns) -- what selectTunableMask
    +     needs to expand a row back into a mask.
    +
    + See also
    + --------
    + selectTunableMask, cmaesKcatTuning
    + + +

    CROSS-REFERENCE INFORMATION ^

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

    SUBFUNCTIONS ^

    + + +

    SOURCE CODE ^

    +
    0001 function screen = screenKcatLeverage(ecModel,varargin)
    +0002 % screenKcatLeverage  Report which kcats the data can actually speak to.
    +0003 %
    +0004 % No optimisation happens here -- this only says which parameters are
    +0005 % worth curating or tuning, and can be read on its own well before any
    +0006 % tuning run. Each tie-group (isozyme copies sharing a prior and a source
    +0007 % move together when params.tieIsozymes) is perturbed up and down by
    +0008 % fold, and its leverage is the largest resulting change in RMSE. Groups
    +0009 % are ranked by that leverage weighted by sigma0log: a trusted source
    +0010 % needs proportionally more measured effect to rank alongside an
    +0011 % untrusted one.
    +0012 %
    +0013 % Costs one simulation per condition per tie-group probed (two probes
    +0014 % each, up and down) plus one baseline -- comparable in scale to a full
    +0015 % tuning run's evaluation budget, not a cheap pre-check.
    +0016 %
    +0017 % Parameters
    +0018 % ----------
    +0019 % ecModel : struct
    +0020 %     ecModel with a populated ec.kcat.
    +0021 %
    +0022 % Name-Value Arguments
    +0023 % --------------------
    +0024 % modelAdapter : ModelAdapter
    +0025 %     a loaded model adapter (default: the current default model adapter).
    +0026 % evoData : struct
    +0027 %     as returned by loadEvotuneData (default: loaded from modelAdapter).
    +0028 % tunableMask : logical
    +0029 %     restrict which kcats are screened (default: every ec.kcat > 0).
    +0030 % fold : double
    +0031 %     fold-change used to perturb each tie-group up and down (default 2.0).
    +0032 % nProc : double
    +0033 %     number of parallel workers used to score candidate vectors (default
    +0034 %     1, i.e. serial). Requires Parallel Computing Toolbox for > 1.
    +0035 %
    +0036 % Returns
    +0037 % -------
    +0038 % screen : table
    +0039 %     one row per tie-group, sorted by rank descending: rxnId (the
    +0040 %     group's representative), nIsozymes, sourceGroup, kcat0, leverage,
    +0041 %     sigma0log, rank (leverage*sigma0log), cumLeverageShare (running
    +0042 %     total of rank as a fraction of its sum), and positions (a cell
    +0043 %     array of indices into ecModel.ec.rxns) -- what selectTunableMask
    +0044 %     needs to expand a row back into a mask.
    +0045 %
    +0046 % See also
    +0047 % --------
    +0048 % selectTunableMask, cmaesKcatTuning
    +0049 p = parseGECKOargs(varargin, { ...
    +0050     'modelAdapter', []; ...
    +0051     'evoData', []; ...
    +0052     'tunableMask', []; ...
    +0053     'fold', 2.0; ...
    +0054     'nProc', 1});
    +0055 modelAdapter = p.modelAdapter;
    +0056 evoData      = p.evoData;
    +0057 tunableMask  = p.tunableMask;
    +0058 fold         = p.fold;
    +0059 nProc        = max(1, round(p.nProc));
    +0060 
    +0061 if isempty(modelAdapter)
    +0062     modelAdapter = ModelAdapterManager.getDefault();
    +0063     if isempty(modelAdapter)
    +0064         error('Either send in a modelAdapter or set the default ecModel adapter in the ModelAdapterManager.')
    +0065     end
    +0066 end
    +0067 params = modelAdapter.params.evotune;
    +0068 if isempty(evoData)
    +0069     evoData = loadEvotuneData('modelAdapter', modelAdapter);
    +0070 end
    +0071 
    +0072 [tunableIdx,ecRxnIdsTunable,kcat0,groups,sigma0log,tieMap] = ...
    +0073     resolveTunableContext(ecModel,params,tunableMask);
    +0074 
    +0075 reps = find(tieMap == (1:numel(tieMap))');
    +0076 nReps = numel(reps);
    +0077 membersOf = cell(nReps,1);
    +0078 for r = 1:nReps
    +0079     membersOf{r} = find(tieMap == reps(r));
    +0080 end
    +0081 
    +0082 vectors = cell(1 + 2*nReps, 1);
    +0083 vectors{1} = kcat0;
    +0084 for r = 1:nReps
    +0085     members = membersOf{r};
    +0086     up = kcat0; up(members) = up(members) * fold;
    +0087     dn = kcat0; dn(members) = dn(members) / fold;
    +0088     vectors{1 + 2*r - 1} = up;
    +0089     vectors{1 + 2*r}     = dn;
    +0090 end
    +0091 nVec = numel(vectors);
    +0092 rmses = zeros(nVec,1);
    +0093 
    +0094 if nProc == 1
    +0095     % Serial path: carry the excarbon-augmented model from one call into
    +0096     % the next, so the metabolite-formula scan behind it (evotuneScore's
    +0097     % 4th output) runs once for the whole screen rather than once per
    +0098     % probe vector.
    +0099     baseModel = ecModel;
    +0100     for v = 1:nVec
    +0101         [~,rmses(v),~,baseModel] = scoreVector(baseModel,tunableIdx,ecRxnIdsTunable,evoData,modelAdapter,params,vectors{v});
    +0102     end
    +0103 else
    +0104     parfor v = 1:nVec
    +0105         [~,rmses(v)] = scoreVector(ecModel,tunableIdx,ecRxnIdsTunable,evoData,modelAdapter,params,vectors{v});
    +0106     end
    +0107 end
    +0108 
    +0109 baseRmse = rmses(1);
    +0110 rxnId       = cell(nReps,1);
    +0111 nIsozymes   = zeros(nReps,1);
    +0112 sourceGroup = cell(nReps,1);
    +0113 kcat0Col    = zeros(nReps,1);
    +0114 leverage    = zeros(nReps,1);
    +0115 sigma0logCol= zeros(nReps,1);
    +0116 positions   = cell(nReps,1);
    +0117 for r = 1:nReps
    +0118     upRmse = rmses(1 + 2*r - 1);
    +0119     dnRmse = rmses(1 + 2*r);
    +0120     members = membersOf{r};
    +0121     rxnId{r}        = ecRxnIdsTunable{reps(r)};
    +0122     nIsozymes(r)     = numel(members);
    +0123     sourceGroup{r}   = groups{reps(r)};
    +0124     kcat0Col(r)      = kcat0(reps(r));
    +0125     leverage(r)      = max(abs(upRmse - baseRmse), abs(dnRmse - baseRmse));
    +0126     sigma0logCol(r)  = sigma0log(reps(r));
    +0127     positions{r}     = tunableIdx(members);
    +0128 end
    +0129 
    +0130 rnk = leverage .* sigma0logCol;
    +0131 [~,ord] = sort(rnk,'descend');
    +0132 rxnId=rxnId(ord); nIsozymes=nIsozymes(ord); sourceGroup=sourceGroup(ord);
    +0133 kcat0Col=kcat0Col(ord); leverage=leverage(ord); sigma0logCol=sigma0logCol(ord);
    +0134 positions=positions(ord); rnk=rnk(ord);
    +0135 
    +0136 total = sum(rnk);
    +0137 if total > 0
    +0138     cumLeverageShare = cumsum(rnk) / total;
    +0139 else
    +0140     cumLeverageShare = zeros(size(rnk));
    +0141 end
    +0142 
    +0143 screen = table(rxnId,nIsozymes,sourceGroup,kcat0Col,leverage,sigma0logCol,rnk,cumLeverageShare,positions, ...
    +0144     'VariableNames',{'rxnId','nIsozymes','sourceGroup','kcat0','leverage','sigma0log','rank','cumLeverageShare','positions'});
    +0145 end
    +0146 
    +0147 function [obj,rmse,rmseDetail,ecModel] = scoreVector(ecModel,tunableIdx,ecRxnIdsTunable,evoData,modelAdapter,params,kcatVec)
    +0148 ecModel.ec.kcat(tunableIdx) = kcatVec;
    +0149 ecModel = applyKcatConstraints(ecModel,'updateRxns',ecRxnIdsTunable);
    +0150 [obj,rmse,rmseDetail,ecModel] = evotuneScore(ecModel,evoData,'modelAdapter',modelAdapter,'maxGrowthWeight',params.maxGrowthWeight);
    +0151 end
    +
    Generated by m2html © 2005
    + + \ No newline at end of file diff --git a/doc/src/kcat_tuning/evotune/selectTunableMask.html b/doc/src/kcat_tuning/evotune/selectTunableMask.html new file mode 100644 index 00000000..1d88a18a --- /dev/null +++ b/doc/src/kcat_tuning/evotune/selectTunableMask.html @@ -0,0 +1,123 @@ + + + + Description of selectTunableMask + + + + + + + + + +
    Home > src > kcat_tuning > evotune > selectTunableMask.m
    + + + +

    selectTunableMask +

    + +

    PURPOSE ^

    +
    selectTunableMask Build a tunableMask from a screenKcatLeverage report.
    + +

    SYNOPSIS ^

    +
    function mask = selectTunableMask(ecModel,screen,varargin)
    + +

    DESCRIPTION ^

    +
     selectTunableMask  Build a tunableMask from a screenKcatLeverage report.
    +
    + Keeps the fewest highest-ranked groups whose combined leverage reaches
    + targetImpactShare of the total -- a relative cutoff, so the same
    + targetImpactShare selects a comparable quality of parameter set on any
    + model, rather than an absolute leverage value or a fixed count
    + calibrated on a different model's scale.
    +
    + Pure and cheap -- no simulation, only screen is read.
    +
    + Parameters
    + ----------
    + ecModel : struct
    + screen : table
    +     as returned by screenKcatLeverage.
    +
    + Name-Value Arguments
    + --------------------
    + targetImpactShare : double
    +     default 0.9. Not a validated universal constant -- check the
    +     resulting mask's size against screenKcatLeverage's own curve before
    +     trusting it on a new model.
    +
    + Returns
    + -------
    + mask : logical
    +     length numel(ecModel.ec.rxns).
    +
    + See also
    + --------
    + screenKcatLeverage, cmaesKcatTuning
    + + +

    CROSS-REFERENCE INFORMATION ^

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

    SOURCE CODE ^

    +
    0001 function mask = selectTunableMask(ecModel,screen,varargin)
    +0002 % selectTunableMask  Build a tunableMask from a screenKcatLeverage report.
    +0003 %
    +0004 % Keeps the fewest highest-ranked groups whose combined leverage reaches
    +0005 % targetImpactShare of the total -- a relative cutoff, so the same
    +0006 % targetImpactShare selects a comparable quality of parameter set on any
    +0007 % model, rather than an absolute leverage value or a fixed count
    +0008 % calibrated on a different model's scale.
    +0009 %
    +0010 % Pure and cheap -- no simulation, only screen is read.
    +0011 %
    +0012 % Parameters
    +0013 % ----------
    +0014 % ecModel : struct
    +0015 % screen : table
    +0016 %     as returned by screenKcatLeverage.
    +0017 %
    +0018 % Name-Value Arguments
    +0019 % --------------------
    +0020 % targetImpactShare : double
    +0021 %     default 0.9. Not a validated universal constant -- check the
    +0022 %     resulting mask's size against screenKcatLeverage's own curve before
    +0023 %     trusting it on a new model.
    +0024 %
    +0025 % Returns
    +0026 % -------
    +0027 % mask : logical
    +0028 %     length numel(ecModel.ec.rxns).
    +0029 %
    +0030 % See also
    +0031 % --------
    +0032 % screenKcatLeverage, cmaesKcatTuning
    +0033 p = parseGECKOargs(varargin, { ...
    +0034     'targetImpactShare', 0.9});
    +0035 targetImpactShare = p.targetImpactShare;
    +0036 
    +0037 mask = false(numel(ecModel.ec.rxns),1);
    +0038 if isempty(screen) || height(screen) == 0
    +0039     return
    +0040 end
    +0041 prevCum = [0; screen.cumLeverageShare(1:end-1)];
    +0042 keep = prevCum < targetImpactShare;
    +0043 for i = find(keep)'
    +0044     mask(screen.positions{i}) = true;
    +0045 end
    +0046 end
    +
    Generated by m2html © 2005
    + + \ No newline at end of file diff --git a/doc/src/kcat_tuning/evotune/tunePriorPenaltyWeight.html b/doc/src/kcat_tuning/evotune/tunePriorPenaltyWeight.html new file mode 100644 index 00000000..f729d55e --- /dev/null +++ b/doc/src/kcat_tuning/evotune/tunePriorPenaltyWeight.html @@ -0,0 +1,299 @@ + + + + Description of tunePriorPenaltyWeight + + + + + + + + + +
    Home > src > kcat_tuning > evotune > tunePriorPenaltyWeight.m
    + + + +

    tunePriorPenaltyWeight +

    + +

    PURPOSE ^

    +
    tunePriorPenaltyWeight Sweep priorPenaltyWeight and report the
    + +

    SYNOPSIS ^

    +
    function sweepTable = tunePriorPenaltyWeight(ecModel,varargin)
    + +

    DESCRIPTION ^

    +
     tunePriorPenaltyWeight  Sweep priorPenaltyWeight and report the
    + fit/reproducibility trade-off, so the value doesn't have to be picked
    + blind.
    +
    + priorPenaltyWeight charges for moving a kcat away from its prior, and
    + mainly exists to keep large corrections reproducible across seeds
    + rather than landing on an arbitrary point along a flat direction. How
    + strong a charge is enough is model- and data-specific: too little and
    + the search's largest corrections disagree across seeds; too much and
    + the search stops finding real corrections at all. This runs
    + cmaesKcatTuning at every value in candidates, each at every seed in
    + seeds, all against the same tunable set, and reports both fit and
    + cross-seed reproducibility per value.
    +
    + This is exactly as expensive as it sounds: numel(candidates)*numel(seeds)
    + full cmaesKcatTuning runs, none of them reusable across candidates. Pass
    + a screen you already have to at least avoid recomputing that part.
    +
    + Parameters
    + ----------
    + ecModel : struct
    +     ecModel with a populated ec.kcat. Not mutated (MATLAB structs are
    +     copied on assignment; every candidate/seed pair starts fresh from
    +     this input regardless of what earlier runs did).
    +
    + Name-Value Arguments
    + --------------------
    + modelAdapter, evoData, tunableMask, screen, targetImpactShare, popsize,
    + nProc, verbose
    +     as in cmaesKcatTuning.
    + candidates : double
    +     priorPenaltyWeight values to try (default [0.0, 0.01, 0.03, 0.1]).
    + seeds : double
    +     seeds to run each candidate at (default [0, 1]). Reproducibility
    +     columns pool every pair of seeds, so more than two sharpens them
    +     but costs proportionally more.
    + foldThreshold : double
    +     a kcat counts as "moved" past this fold change from its prior
    +     (default 2.0). Matches nChanged's convention loosely (a different
    +     quantity, same spirit).
    +
    + Returns
    + -------
    + sweepTable : table
    +     one row per candidate: priorPenaltyWeight, nSeeds, distanceMean,
    +     distanceSpread (max minus min across seeds), nChangedMean,
    +     nMovers (kcats past foldThreshold in either seed of a pair, summed
    +     over every pair), nBothMoved (past it in both), pctDirectionAgree,
    +     medianFoldSpread and maxFoldSpread (among movers, the largest
    +     fold-change between what two seeds landed on), and fitCost
    +     (distanceMean relative to the best candidate's, as a fraction).
    +
    + See also
    + --------
    + cmaesKcatTuning, screenKcatLeverage, selectTunableMask, nChanged
    + + +

    CROSS-REFERENCE INFORMATION ^

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

    SUBFUNCTIONS ^

    + + +

    SOURCE CODE ^

    +
    0001 function sweepTable = tunePriorPenaltyWeight(ecModel,varargin)
    +0002 % tunePriorPenaltyWeight  Sweep priorPenaltyWeight and report the
    +0003 % fit/reproducibility trade-off, so the value doesn't have to be picked
    +0004 % blind.
    +0005 %
    +0006 % priorPenaltyWeight charges for moving a kcat away from its prior, and
    +0007 % mainly exists to keep large corrections reproducible across seeds
    +0008 % rather than landing on an arbitrary point along a flat direction. How
    +0009 % strong a charge is enough is model- and data-specific: too little and
    +0010 % the search's largest corrections disagree across seeds; too much and
    +0011 % the search stops finding real corrections at all. This runs
    +0012 % cmaesKcatTuning at every value in candidates, each at every seed in
    +0013 % seeds, all against the same tunable set, and reports both fit and
    +0014 % cross-seed reproducibility per value.
    +0015 %
    +0016 % This is exactly as expensive as it sounds: numel(candidates)*numel(seeds)
    +0017 % full cmaesKcatTuning runs, none of them reusable across candidates. Pass
    +0018 % a screen you already have to at least avoid recomputing that part.
    +0019 %
    +0020 % Parameters
    +0021 % ----------
    +0022 % ecModel : struct
    +0023 %     ecModel with a populated ec.kcat. Not mutated (MATLAB structs are
    +0024 %     copied on assignment; every candidate/seed pair starts fresh from
    +0025 %     this input regardless of what earlier runs did).
    +0026 %
    +0027 % Name-Value Arguments
    +0028 % --------------------
    +0029 % modelAdapter, evoData, tunableMask, screen, targetImpactShare, popsize,
    +0030 % nProc, verbose
    +0031 %     as in cmaesKcatTuning.
    +0032 % candidates : double
    +0033 %     priorPenaltyWeight values to try (default [0.0, 0.01, 0.03, 0.1]).
    +0034 % seeds : double
    +0035 %     seeds to run each candidate at (default [0, 1]). Reproducibility
    +0036 %     columns pool every pair of seeds, so more than two sharpens them
    +0037 %     but costs proportionally more.
    +0038 % foldThreshold : double
    +0039 %     a kcat counts as "moved" past this fold change from its prior
    +0040 %     (default 2.0). Matches nChanged's convention loosely (a different
    +0041 %     quantity, same spirit).
    +0042 %
    +0043 % Returns
    +0044 % -------
    +0045 % sweepTable : table
    +0046 %     one row per candidate: priorPenaltyWeight, nSeeds, distanceMean,
    +0047 %     distanceSpread (max minus min across seeds), nChangedMean,
    +0048 %     nMovers (kcats past foldThreshold in either seed of a pair, summed
    +0049 %     over every pair), nBothMoved (past it in both), pctDirectionAgree,
    +0050 %     medianFoldSpread and maxFoldSpread (among movers, the largest
    +0051 %     fold-change between what two seeds landed on), and fitCost
    +0052 %     (distanceMean relative to the best candidate's, as a fraction).
    +0053 %
    +0054 % See also
    +0055 % --------
    +0056 % cmaesKcatTuning, screenKcatLeverage, selectTunableMask, nChanged
    +0057 p = parseGECKOargs(varargin, { ...
    +0058     'modelAdapter', []; ...
    +0059     'evoData', []; ...
    +0060     'tunableMask', []; ...
    +0061     'screen', []; ...
    +0062     'targetImpactShare', 0.9; ...
    +0063     'popsize', []; ...
    +0064     'nProc', 1; ...
    +0065     'verbose', true; ...
    +0066     'candidates', [0.0, 0.01, 0.03, 0.1]; ...
    +0067     'seeds', [0, 1]; ...
    +0068     'foldThreshold', 2.0});
    +0069 modelAdapter      = p.modelAdapter;
    +0070 evoData           = p.evoData;
    +0071 tunableMask       = p.tunableMask;
    +0072 screen            = p.screen;
    +0073 targetImpactShare = p.targetImpactShare;
    +0074 popsize           = p.popsize;
    +0075 nProc             = p.nProc;
    +0076 verbose           = p.verbose;
    +0077 candidates        = p.candidates;
    +0078 seeds             = p.seeds;
    +0079 foldThreshold     = p.foldThreshold;
    +0080 
    +0081 if isempty(modelAdapter)
    +0082     modelAdapter = ModelAdapterManager.getDefault();
    +0083     if isempty(modelAdapter)
    +0084         error('Either send in a modelAdapter or set the default ecModel adapter in the ModelAdapterManager.')
    +0085     end
    +0086 end
    +0087 if isempty(evoData)
    +0088     evoData = loadEvotuneData('modelAdapter', modelAdapter);
    +0089 end
    +0090 if isempty(tunableMask)
    +0091     if isempty(screen)
    +0092         screen = screenKcatLeverage(ecModel, 'modelAdapter',modelAdapter, ...
    +0093             'evoData',evoData, 'nProc',nProc);
    +0094     end
    +0095     tunableMask = selectTunableMask(ecModel, screen, 'targetImpactShare',targetImpactShare);
    +0096 end
    +0097 
    +0098 nCand = numel(candidates);
    +0099 priorPenaltyWeight = zeros(nCand,1);
    +0100 nSeeds             = zeros(nCand,1);
    +0101 distanceMean        = zeros(nCand,1);
    +0102 distanceSpread       = zeros(nCand,1);
    +0103 nChangedMean        = zeros(nCand,1);
    +0104 nMovers              = zeros(nCand,1);
    +0105 nBothMoved           = zeros(nCand,1);
    +0106 pctDirectionAgree   = zeros(nCand,1);
    +0107 medianFoldSpread    = zeros(nCand,1);
    +0108 maxFoldSpread        = zeros(nCand,1);
    +0109 
    +0110 for c = 1:nCand
    +0111     lam = candidates(c);
    +0112     lamParams = modelAdapter.params.evotune;
    +0113     lamParams.priorPenaltyWeight = lam;
    +0114 
    +0115     vectors = cell(numel(seeds),1);
    +0116     distances = zeros(numel(seeds),1);
    +0117     changed = zeros(numel(seeds),1);
    +0118     oldKcat = [];
    +0119     for s = 1:numel(seeds)
    +0120         seedVal = seeds(s);
    +0121         adapterCopy = modelAdapter;
    +0122         adapterCopy.params.evotune = lamParams;
    +0123         [~,res] = cmaesKcatTuning(ecModel, 'modelAdapter',adapterCopy, ...
    +0124             'evoData',evoData, 'tunableMask',tunableMask, ...
    +0125             'popsize',popsize, 'nProc',nProc, 'seed',seedVal, 'verbose',verbose);
    +0126         vectors{s} = res.newKcat;
    +0127         if ~isempty(res.rmseTrace)
    +0128             distances(s) = res.rmseTrace(end);
    +0129         else
    +0130             distances(s) = NaN;
    +0131         end
    +0132         changed(s) = nChanged(res.newKcat, res.oldKcat);
    +0133         oldKcat = res.oldKcat;
    +0134         if verbose
    +0135             fprintf('priorPenaltyWeight=%g seed=%d: distance %.4f, %d changed\n', ...
    +0136                 lam, seedVal, distances(s), changed(s));
    +0137         end
    +0138     end
    +0139 
    +0140     movers = 0; both = 0; agree = 0; spreads = [];
    +0141     for i = 1:numel(vectors)
    +0142         for j = (i+1):numel(vectors)
    +0143             fa = foldChangeLocal(vectors{i}, oldKcat);
    +0144             fb = foldChangeLocal(vectors{j}, oldKcat);
    +0145             moversIJ = (fa > foldThreshold) | (fb > foldThreshold);
    +0146             bothIJ   = (fa > foldThreshold) & (fb > foldThreshold);
    +0147             agreeIJ  = sign(log(vectors{i}(bothIJ) ./ oldKcat(bothIJ))) == ...
    +0148                        sign(log(vectors{j}(bothIJ) ./ oldKcat(bothIJ)));
    +0149             movers = movers + sum(moversIJ);
    +0150             both   = both + sum(bothIJ);
    +0151             agree  = agree + sum(agreeIJ);
    +0152             if any(moversIJ)
    +0153                 ratio = vectors{i}(moversIJ) ./ vectors{j}(moversIJ);
    +0154                 spreads = [spreads; max(ratio, 1./ratio)]; %#ok<AGROW>
    +0155             end
    +0156         end
    +0157     end
    +0158 
    +0159     priorPenaltyWeight(c) = lam;
    +0160     nSeeds(c)              = numel(seeds);
    +0161     distanceMean(c)        = mean(distances);
    +0162     if numel(distances) > 1
    +0163         distanceSpread(c) = max(distances) - min(distances);
    +0164     else
    +0165         distanceSpread(c) = 0;
    +0166     end
    +0167     nChangedMean(c) = mean(changed);
    +0168     nMovers(c)      = movers;
    +0169     nBothMoved(c)   = both;
    +0170     if both > 0
    +0171         pctDirectionAgree(c) = agree / both;
    +0172     else
    +0173         pctDirectionAgree(c) = NaN;
    +0174     end
    +0175     if ~isempty(spreads)
    +0176         medianFoldSpread(c) = median(spreads);
    +0177         maxFoldSpread(c)    = max(spreads);
    +0178     else
    +0179         medianFoldSpread(c) = NaN;
    +0180         maxFoldSpread(c)    = NaN;
    +0181     end
    +0182 end
    +0183 
    +0184 fitCost = distanceMean / min(distanceMean) - 1.0;
    +0185 
    +0186 sweepTable = table(priorPenaltyWeight,nSeeds,distanceMean,distanceSpread,nChangedMean, ...
    +0187     nMovers,nBothMoved,pctDirectionAgree,medianFoldSpread,maxFoldSpread,fitCost);
    +0188 end
    +0189 
    +0190 function f = foldChangeLocal(kcat,kcat0)
    +0191 % Per-kcat fold change from the prior, always >= 1. The only caller of
    +0192 % this in the whole port is this file, so it stays local rather than
    +0193 % getting its own file (see nChanged.m for the parsimony function that
    +0194 % genuinely is needed from two places).
    +0195 f = exp(abs(log(kcat(:) ./ kcat0(:))));
    +0196 end
    +
    Generated by m2html © 2005
    + + \ No newline at end of file diff --git a/doc/src/kcat_tuning/fillCarbonNum.html b/doc/src/kcat_tuning/fillCarbonNum.html new file mode 100644 index 00000000..74806a2f --- /dev/null +++ b/doc/src/kcat_tuning/fillCarbonNum.html @@ -0,0 +1,368 @@ + + + + Description of fillCarbonNum + + + + + + + + + +
    Home > src > kcat_tuning > fillCarbonNum.m
    + + + +

    fillCarbonNum +

    + +

    PURPOSE ^

    +
    + +

    SYNOPSIS ^

    +
    This is a script file.
    + +

    DESCRIPTION ^

    +
    + + +

    CROSS-REFERENCE INFORMATION ^

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

    SUBFUNCTIONS ^

    + + +

    SOURCE CODE ^

    +
    0001 function model = fillCarbonNum(model)
    +0002 % fillCarbonNum  Add a carbon number field to the model.
    +0003 %
    +0004 % Adds a model.excarbon field with the carbon number of each exchange
    +0005 % reaction, used to weight the RMSE during evotune kcat tuning.
    +0006 %
    +0007 % Parameters
    +0008 % ----------
    +0009 % model : struct
    +0010 %     ecModel that was generated by makeEcModel, or loaded from an earlier
    +0011 %     run. Not compatible with ecModels generated by earlier GECKO versions
    +0012 %     (pre 3.0).
    +0013 %
    +0014 % Returns
    +0015 % -------
    +0016 % model : struct
    +0017 %     ecModel with an added model.excarbon field.
    +0018 
    +0019 % get carbonnum for each exchange rxn to further calculation of error
    +0020 model.excarbon = zeros(length(model.rxns),1);
    +0021 [EXrxn, EXrxnIdx] = getExchangeRxns(model);
    +0022 [CarbonNum,EXfors] = getcarbonnum(model,EXrxn);
    +0023 model.excarbon(EXrxnIdx) = CarbonNum;
    +0024 model.excarbon(strcmp(model.rxnNames,'growth')) = 41;
    +0025 
    +0026 function [CarbonNum,EXfors,changedmets] = getcarbonnum(model,exrxn)
    +0027 % getcarbonnum  Get carbon numbers matching the model.
    +0028 %
    +0029 % Parameters
    +0030 % ----------
    +0031 % model : struct
    +0032 %     ecModel that was generated by makeEcModel, or loaded from an earlier
    +0033 %     run. Not compatible with ecModels generated by earlier GECKO versions
    +0034 %     (pre 3.0).
    +0035 % exrxn : cell
    +0036 %     exchange reactions to use for counting.
    +0037 %
    +0038 % Returns
    +0039 % -------
    +0040 % CarbonNum : double
    +0041 %     carbon number for each exchange reaction.
    +0042 % EXfors : cell
    +0043 %     formulae of the exchanged metabolites.
    +0044 % changedmets : cell
    +0045 %     exchange reactions whose carbon number could not be determined.
    +0046 %
    +0047 
    +0048 % exrxn must be an exchange rxn and only contain one mets in the equation
    +0049 [~,idx] = ismember(exrxn,model.rxns);
    +0050 EXmets = model.S(:,idx);
    +0051 % find all exchange mets
    +0052 EXmetsIdx = zeros(length(exrxn),1);
    +0053 for k = 1:length(EXmets(1,:))
    +0054     EXmetsIdx(k) = find(EXmets(:,k)); %
    +0055 end
    +0056 EXfors = model.metFormulas(EXmetsIdx);
    +0057 [Ematrix, elements] = getElementalComposition(EXfors,{'C'});
    +0058 Ematrix = Ematrix(:,1);
    +0059 changedmets = exrxn(isnan(Ematrix));
    +0060 Ematrix(isnan(Ematrix)) = 1;
    +0061 CarbonNum = Ematrix;
    +0062 
    +0063 function [Ematrix, elements] = getElementalComposition(formulae, elements, chargeInFormula)
    +0064 % Get the complete elemental composition matrix. It supports formulae with
    +0065 % generic elements, parentheses and decimal places
    +0066 %
    +0067 % USAGE:
    +0068 %    [Ematrix, elements] = getElementalComposition(formulae, elements, chargeInFormula)
    +0069 %
    +0070 % INPUT:
    +0071 %    formulae:        cell array of strings of chemical formulae. Can contain any generic elements starting
    +0072 %                     with a capital letter followed by lowercase letters or '_', followed by a non-negative number.
    +0073 %                     Also support '()', '[]', '{}'. E.g. {'H2O'; '[H2O]2(CuSO4)Generic_element0.5'}
    +0074 % OPTIONAL INPUTS:
    +0075 %    elements:        elements from previous call to preserve the order (default {})
    +0076 %    chargeInFormula: true to accept formulae containing the generic element 'Charge' representing the charges,
    +0077 %                     followed by a real number, e.g., 'HCharge1', 'SO4Charge-2' (default false).
    +0078 %
    +0079 % OUTPUTS:
    +0080 %    Ematrix:         elemental composition matrix (#formulae x #elements)
    +0081 %    elements:         cell array of elements corresponding to the columns of Ematrix
    +0082 %
    +0083 % E.g., [Ematrix, elements] = getElementalComposition({'H2O'; '[H2O]2(CuSO4)Generic_element0.5'}) would return:
    +0084 %  elements = {'H', 'O', 'Cu', 'S', 'Generic_element'}
    +0085 %  Ematrix = [ 2,   1,    0,   0,   0;
    +0086 %              4,   6,    1,   1,   0.5]
    +0087 %
    +0088 % Siu Hung Joshua Chan May 2017
    +0089 
    +0090 if nargin < 3 || isempty(chargeInFormula)
    +0091     chargeInFormula = false;
    +0092 else
    +0093     chargeInFormula = logical(chargeInFormula);
    +0094 end
    +0095 % for recalling the original formula at the top level if there are parentheses
    +0096 % in the formula leading to iterative calling
    +0097 persistent formTopLv
    +0098 persistent formCurLv
    +0099 % for storing error message during iterative calling
    +0100 persistent errMsg
    +0101 persistent errMsgInThisLoop
    +0102 persistent topLvJ
    +0103 persistent selfCall
    +0104 if isempty(selfCall)
    +0105     selfCall = 0;
    +0106 end
    +0107 if ~selfCall
    +0108     [formTopLv, errMsg] = deal('');
    +0109 end
    +0110 
    +0111 if ~isstruct(formulae)
    +0112     if ~iscell(formulae)
    +0113         % make sure it is a cell array of strings
    +0114         formulae = {formulae};
    +0115     end
    +0116 else
    +0117     % also accept COBRA model as input
    +0118     if isfield(formulae, 'metFormulas')
    +0119         formulae = formulae.metFormulas;
    +0120     else
    +0121         error('The 1st input ''formulae'' should be a cell array of strings of formulae or a COBRA model with *.metFormulas')
    +0122     end
    +0123 end
    +0124 
    +0125 if nargin < 2 || isempty(elements)
    +0126     elements = {};
    +0127 elseif numel(unique(elements)) < numel(elements)
    +0128     error('Repeated elements in the input ''elements'' array.')
    +0129 else
    +0130     elements = elements(:)';  % make sure it is a row vector
    +0131 end
    +0132 
    +0133 % the Ematrix
    +0134 Ematrix = zeros(numel(formulae), numel(elements));
    +0135 % replace all brackets and braces by parentheses
    +0136 formulae = regexprep(formulae, '[\[\{]', '\(');
    +0137 formulae = regexprep(formulae, '[\]\}]', '\)');
    +0138 digit = floor(log10(numel(formulae))) + 1;
    +0139 for j = 1:numel(formulae)
    +0140     if ~selfCall
    +0141         % reset top level information for each formula
    +0142         [formTopLv, topLvJ, errMsgInThisLoop] = deal(formulae{j}, j, false);
    +0143     end
    +0144     formulae{j} = strtrim(formulae{j});
    +0145     if ~isempty(formulae{j})
    +0146         % get all outer parentheses
    +0147         parenthesis = [];
    +0148         stP = [];
    +0149         stPpos = [];
    +0150         lv = 0;
    +0151         k = 1;
    +0152         while k <= length(formulae{j})
    +0153             if strcmp(formulae{j}(k),'(')
    +0154                 if lv == 0
    +0155                     pStart = k;
    +0156                 end
    +0157                 lv = lv + 1;
    +0158             elseif strcmp(formulae{j}(k),')')
    +0159                 if lv == 1
    +0160                     parenthesis = [parenthesis; [pStart k]];
    +0161                     % right parenthesis, get the following stoichiometry if any
    +0162                     stPre = regexp(formulae{j}(k+1:end), '^(\+|\-)?\d*\.?\d*', 'match');
    +0163                     if isempty(stPre)
    +0164                         stP = [stP; 1];
    +0165                         stPpos = [stPpos; k k];
    +0166                     else
    +0167                         stCheck = str2double(stPre{1});
    +0168                         s = '';
    +0169                         if isnan(stCheck)
    +0170                             s = 'Invalid';
    +0171                         elseif stCheck < 0
    +0172                             s = 'Negative';
    +0173                         end
    +0174                         if ~isempty(s)  % error if not convertible to number or negative
    +0175                             f = [formulae{j}(parenthesis(end,1):parenthesis(end,2)), stPre{1}];
    +0176                             addErrorMessage(sprintf('    %s stoichiometry in ''%s''\n', s, f))
    +0177                         end
    +0178                         % stoichiometry
    +0179                         stP = [stP; stCheck];
    +0180                         % position of the stoichiometry in the text
    +0181                         stPpos = [stPpos; k + 1, k + length(stPre{1})];
    +0182                         k = k + length(stPre{1});
    +0183                     end
    +0184                 end
    +0185                 lv = lv - 1;
    +0186             end
    +0187             k = k + 1;
    +0188         end
    +0189         if isempty(parenthesis)
    +0190         % No parenthesis, parse the formula
    +0191             re = regexp(formulae{j}, '([A-Z][a-z_]*)((?:\+|\-)?\d*\.?\d*)', 'tokens');
    +0192             s = strjoin(cellfun(@(x) strjoin(x,''), re, 'UniformOutput', false), '');
    +0193             errorFlag = 0;
    +0194             if ~strcmp(s, formulae{j})  % check if the entire formula is retrieved
    +0195                 errorFlag = 1;
    +0196             else
    +0197                 % check the stoichiometry
    +0198                 eleCheck = cellfun(@(x) x{1}, re, 'UniformOutput', false);
    +0199                 stCheck = cellfun(@(x) str2double(x{2}), re);
    +0200                 stCheck(cellfun(@(x) isempty(x{2}), re)) = 1;  % empty value => stoichiometry = 1
    +0201                 if any(isnan(stCheck))
    +0202                     f = strjoin(cellfun(@(x) strjoin(x, ''), re(isnan(stCheck)), 'UniformOutput', false), ''', ''');
    +0203                     [errorFlag, errMsgKey] = deal(2, 'Invalid');
    +0204                 else
    +0205                     % if chargeInFormula is true, detect negative stoich for non-charge elements, else any negative stoich
    +0206                     negSt = (~chargeInFormula | ~strcmp(eleCheck, 'Charge')) & stCheck < 0;
    +0207                     if any(negSt)
    +0208                         f = strjoin(cellfun(@(x) strjoin(x, ''), re(negSt), 'UniformOutput', false), ''', ''');
    +0209                         [errorFlag, errMsgKey] = deal(2, 'Negative');
    +0210                     end
    +0211                 end
    +0212             end
    +0213             if errorFlag > 0
    +0214                 if selfCall <= 1
    +0215                     s2 = sprintf('from the part ''%s''', formulae{j});
    +0216                 elseif selfCall == 2
    +0217                     s2 = sprintf('from the part ''(%s)''', formCurLv);
    +0218                 elseif selfCall == 3
    +0219                     s2 = sprintf('from the part ''(%s)''', formulae{j});
    +0220                 end
    +0221                 if errorFlag == 1
    +0222                     s2 = sprintf(['    Only ''%s'' can be recognized %s.\n'...
    +0223                         '       Each element should start with a capital letter followed by lower case letters'...
    +0224                         ' or ''_'' with indefinite length and followed by a number.\n'], s, s2);
    +0225                 elseif errorFlag == 2
    +0226                     s2 = sprintf('    %s stoichiometry in ''%s'' %s\n', errMsgKey, f, s2);
    +0227                 end
    +0228                 addErrorMessage(s2);
    +0229             end
    +0230             elementJ = repmat({''}, 1, numel(re));
    +0231             nEj = 0;
    +0232             stoichJ = zeros(numel(re),1);
    +0233             for k = 1:numel(re)
    +0234                 [ynK,idK] = ismember(re{k}(1), elementJ(1:nEj));
    +0235                 if ynK
    +0236                     k2 = idK;
    +0237                 else
    +0238                     nEj = nEj + 1;
    +0239                     elementJ{nEj} = re{k}{1};
    +0240                     k2 = nEj;
    +0241                 end
    +0242                 if isempty(re{k}{2})
    +0243                     stoichJ(k2) = stoichJ(k2) + 1;
    +0244                 else
    +0245                     stoichJ(k2) = stoichJ(k2) + str2double(re{k}{2});
    +0246                 end
    +0247             end
    +0248             elementJ = elementJ(1:nEj);
    +0249             stoichJ = stoichJ(1:nEj);
    +0250             [ynE, idE] = ismember(elementJ, elements);  % map to existing elements
    +0251             if any(~ynE)
    +0252                 idE(~ynE) = (numel(elements) + 1):(numel(elements) + sum(~ynE));
    +0253                 Ematrix(:, (numel(elements) + 1):(numel(elements) + sum(~ynE))) = 0;
    +0254                 elements = [elements, elementJ(~ynE)];
    +0255             end
    +0256             Ematrix(j, idE) = stoichJ;
    +0257         else
    +0258             % parentheses found. Iteratively get the formula inside parentheses
    +0259             rest = true(length(formulae{j}),1);
    +0260             for k = 1:size(parenthesis,1)
    +0261                 selfCallCur = selfCall;
    +0262                 selfCall = 3;
    +0263                 [EmatrixK, elements] = getElementalComposition(formulae{j}(...
    +0264                     (parenthesis(k,1)+1):(parenthesis(k,2)-1)), elements, chargeInFormula);
    +0265                 if numel(elements) > size(Ematrix, 2)
    +0266                     Ematrix(:, (size(Ematrix, 2) + 1):numel(elements)) = 0;
    +0267                 end
    +0268                 selfCall = selfCallCur;
    +0269                 Ematrix(j, 1:numel(elements)) = Ematrix(j, 1:numel(elements)) + EmatrixK * stP(k);
    +0270                 rest(parenthesis(k,1):stPpos(k,2)) = false;          
    +0271             end
    +0272             if any(rest)
    +0273                 formCurLv = formulae{j};
    +0274                 selfCallCur = selfCall;
    +0275                 selfCall = 1 + (selfCall >= 1);
    +0276                 while any(rest)
    +0277                     % get the consecutive part of the formula that is not in parentheses
    +0278                     [pStart, pEnd] = deal(find(rest, 1), find(~rest));
    +0279                     pEnd = min(pEnd(pEnd > pStart));
    +0280                     if isempty(pEnd)
    +0281                         pEnd = numel(rest);
    +0282                     else
    +0283                         pEnd = pEnd - 1;
    +0284                     end
    +0285                     [EmatrixK, elements] = getElementalComposition(formulae{j}(pStart:pEnd), elements, chargeInFormula);
    +0286                     if numel(elements) > size(Ematrix, 2)
    +0287                         Ematrix(:, (size(Ematrix, 2) + 1):numel(elements)) = 0;
    +0288                     end
    +0289                     Ematrix(j, 1:numel(elements)) = Ematrix(j, 1:numel(elements)) + EmatrixK;
    +0290                     rest(pStart:pEnd) = false;
    +0291                 end
    +0292                 selfCall = selfCallCur;
    +0293             end
    +0294         end
    +0295     else
    +0296         Ematrix(j,:) = NaN;
    +0297     end
    +0298 end
    +0299 Ematrix = Ematrix(:, 1:numel(elements));
    +0300 if ~selfCall 
    +0301     selfCall = [];
    +0302     if ~isempty(errMsg)
    +0303         error(['%s\n', errMsg], 'Invalid formula input:')
    +0304     end
    +0305 end
    +0306 
    +0307 % nested function for adding error messages
    +0308     function addErrorMessage(s)
    +0309         if ~errMsgInThisLoop
    +0310             errMsg = [errMsg, sprintf(['#%0' num2str(digit) 'd:  %s\n'], topLvJ, formTopLv)];
    +0311             errMsgInThisLoop = true;
    +0312         end
    +0313         errMsg = [errMsg, s];
    +0314     end
    +0315 end
    +0316 
    +0317 end
    +0318 
    +0319 end
    +
    Generated by m2html © 2005
    + + \ No newline at end of file diff --git a/doc/src/kcat_tuning/index.html b/doc/src/kcat_tuning/index.html new file mode 100644 index 00000000..726a4d99 --- /dev/null +++ b/doc/src/kcat_tuning/index.html @@ -0,0 +1,31 @@ + + + + Index for Directory src/kcat_tuning + + + + + + + + + + +
    < Master indexIndex for src/kcat_tuning >
    + +

    Index for src/kcat_tuning

    + +

    Matlab files in this directory:

    + +
     fillCarbonNum
     sensitivityTuningsensitivityTuning Relax the most limiting kcats to reach a growth rate.
     sigmaFittersigmaFitter Fit the average enzyme saturation factor of an ecModel.
     truncateValuestruncateValues Round values in selected columns to six significant digits.
    + + +

    Subsequent directories:

    + + +
    Generated by m2html © 2005
    + + \ No newline at end of file diff --git a/doc/src/kcat_tuning/sensitivityTuning.html b/doc/src/kcat_tuning/sensitivityTuning.html new file mode 100644 index 00000000..0af02957 --- /dev/null +++ b/doc/src/kcat_tuning/sensitivityTuning.html @@ -0,0 +1,315 @@ + + + + Description of sensitivityTuning + + + + + + + + + +
    Home > src > kcat_tuning > sensitivityTuning.m
    + + + +

    sensitivityTuning +

    + +

    PURPOSE ^

    +
    sensitivityTuning Relax the most limiting kcats to reach a growth rate.
    + +

    SYNOPSIS ^

    +
    function [model, tunedKcats] = sensitivityTuning(model, varargin)
    + +

    DESCRIPTION ^

    +
     sensitivityTuning  Relax the most limiting kcats to reach a growth rate.
    +
    + Iteratively increases the kcat of whichever enzyme currently limits growth
    + the most, until the model reaches the desired growth rate, updating the
    + tuned values in model.ec.kcat. The loop also stops, with a warning, when an
    + iteration raises growth by less than 1e-9.
    +
    + Parameters
    + ----------
    + model : struct
    +     an ecModel in GECKO 3 format (with ecModel.ec structure).
    +
    + Name-Value Arguments
    + --------------------
    + desiredGrowthRate : double
    +     kcats will be relaxed until this growth rate is reached (default: the
    +     experimental growth rate params.gR_exp from the model adapter).
    + modelAdapter : ModelAdapter
    +     a loaded model adapter (default: the current default model adapter).
    + foldChange : double
    +     kcat values will be increased by this fold-change (default 10).
    + protToIgnore : cell
    +     vector of protein ids to be ignored in tuned kcats, e.g. {'P38122',
    +     'Q99271'} (default []).
    + verbose : logical
    +     whether progress should be reported (default true).
    +
    + Returns
    + -------
    + model : struct
    +     ecModel with updated model.ec.kcat.
    + tunedKcats : struct
    +     structure with information on tuned kcat values.
    +
    + Notes
    + -----
    + The tunedKcats structure has the following fields:
    +
    + - rxns : identifiers of reactions with tuned kcat values.
    + - rxnNames : names of the reactions in tunedKcats.rxns.
    + - enzymes : enzymes that catalyze the reactions in tunedKcats.rxns, whose
    +   kcat value has been tuned.
    + - oldKcat : kcat values in the input model.
    + - newKcat : kcat values in the output model, after tuning.
    + - source : source label of each kcat, taken from the input model before
    +   tuning.
    +
    + 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.
    +
    + Examples
    + --------
    +     % optional arguments may be given positionally or as name-value pairs:
    +     [model, tunedKcats] = sensitivityTuning(model);
    +     [model, tunedKcats] = sensitivityTuning(model, 'foldChange', 10);
    +     [model, tunedKcats] = sensitivityTuning(model, desiredGrowthRate, modelAdapter, foldChange, protToIgnore, verbose);
    + + +

    CROSS-REFERENCE INFORMATION ^

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

    SOURCE CODE ^

    +
    0001 function [model, tunedKcats] = sensitivityTuning(model, varargin)
    +0002 % sensitivityTuning  Relax the most limiting kcats to reach a growth rate.
    +0003 %
    +0004 % Iteratively increases the kcat of whichever enzyme currently limits growth
    +0005 % the most, until the model reaches the desired growth rate, updating the
    +0006 % tuned values in model.ec.kcat. The loop also stops, with a warning, when an
    +0007 % iteration raises growth by less than 1e-9.
    +0008 %
    +0009 % Parameters
    +0010 % ----------
    +0011 % model : struct
    +0012 %     an ecModel in GECKO 3 format (with ecModel.ec structure).
    +0013 %
    +0014 % Name-Value Arguments
    +0015 % --------------------
    +0016 % desiredGrowthRate : double
    +0017 %     kcats will be relaxed until this growth rate is reached (default: the
    +0018 %     experimental growth rate params.gR_exp from the model adapter).
    +0019 % modelAdapter : ModelAdapter
    +0020 %     a loaded model adapter (default: the current default model adapter).
    +0021 % foldChange : double
    +0022 %     kcat values will be increased by this fold-change (default 10).
    +0023 % protToIgnore : cell
    +0024 %     vector of protein ids to be ignored in tuned kcats, e.g. {'P38122',
    +0025 %     'Q99271'} (default []).
    +0026 % verbose : logical
    +0027 %     whether progress should be reported (default true).
    +0028 %
    +0029 % Returns
    +0030 % -------
    +0031 % model : struct
    +0032 %     ecModel with updated model.ec.kcat.
    +0033 % tunedKcats : struct
    +0034 %     structure with information on tuned kcat values.
    +0035 %
    +0036 % Notes
    +0037 % -----
    +0038 % The tunedKcats structure has the following fields:
    +0039 %
    +0040 % - rxns : identifiers of reactions with tuned kcat values.
    +0041 % - rxnNames : names of the reactions in tunedKcats.rxns.
    +0042 % - enzymes : enzymes that catalyze the reactions in tunedKcats.rxns, whose
    +0043 %   kcat value has been tuned.
    +0044 % - oldKcat : kcat values in the input model.
    +0045 % - newKcat : kcat values in the output model, after tuning.
    +0046 % - source : source label of each kcat, taken from the input model before
    +0047 %   tuning.
    +0048 %
    +0049 % The model.ec.notes field will contain the original kcat value and source,
    +0050 % unless the kcat has previously been set by sensitivityTuning, in which case
    +0051 % the notes field remains unchanged.
    +0052 %
    +0053 % Examples
    +0054 % --------
    +0055 %     % optional arguments may be given positionally or as name-value pairs:
    +0056 %     [model, tunedKcats] = sensitivityTuning(model);
    +0057 %     [model, tunedKcats] = sensitivityTuning(model, 'foldChange', 10);
    +0058 %     [model, tunedKcats] = sensitivityTuning(model, desiredGrowthRate, modelAdapter, foldChange, protToIgnore, verbose);
    +0059 
    +0060 p = parseGECKOargs(varargin, { ...
    +0061     'desiredGrowthRate', []; ...
    +0062     'modelAdapter',      []; ...
    +0063     'foldChange',        10; ...
    +0064     'protToIgnore',      {}; ...
    +0065     'verbose',           true});
    +0066 desiredGrowthRate = p.desiredGrowthRate;
    +0067 modelAdapter      = p.modelAdapter;
    +0068 foldChange        = p.foldChange;
    +0069 protToIgnore      = p.protToIgnore;
    +0070 verbose           = p.verbose;
    +0071 
    +0072 if isempty(modelAdapter)
    +0073     modelAdapter = ModelAdapterManager.getDefault();
    +0074     if isempty(modelAdapter)
    +0075         error('Either send in a modelAdapter or set the default model adapter in the ModelAdapterManager.')
    +0076     end
    +0077 end
    +0078 params = modelAdapter.params;
    +0079 if isempty(desiredGrowthRate)
    +0080     desiredGrowthRate = params.gR_exp;
    +0081 end
    +0082 
    +0083 kcatList = [];
    +0084 m = model;
    +0085 m.c = double(strcmp(m.rxns, params.bioRxn));% Make sure that growth is maximized
    +0086 
    +0087 [res,hs] = solveLP(m);
    +0088 if isempty(res.x)
    +0089     error('FBA of input model gives no valid result. Reduce protein pool constraint with setProtPoolSize and/or check if exchange constraints are correctly defined.')
    +0090 end
    +0091 % The loop stops when growth rises by less than growthStallTol over the
    +0092 % previous iteration (the first iteration has nothing to compare with).
    +0093 lastGrowth = NaN;
    +0094 growthStallTol = 1e-9;
    +0095 if ~m.ec.geckoLight
    +0096     %for the full model, we first find the draw reaction with the most flux
    +0097     drawRxns = startsWith(m.rxns, 'usage_prot_');
    +0098     idxToIgnore = cellfun(@(x) find(strcmpi(model.rxns, ['usage_prot_' x])), protToIgnore);
    +0099     iteration = 1;
    +0100     while true
    +0101         [res,hs] = solveLP(m,0,[],hs); %skip parsimonius, only takes time
    +0102         if isempty(res.f)
    +0103             printOrange('WARNING: The model has no feasible solution with the increased kcats, tuning stops.\n');
    +0104             break;
    +0105         end
    +0106         if ~isnan(lastGrowth) && res.f <= lastGrowth + growthStallTol
    +0107             printOrange('WARNING: No growth increase from increased kcats - check if the constraints on the uptake reactions are too tight.\n');
    +0108             break;
    +0109         end
    +0110         lastGrowth = res.f;
    +0111         if verbose; disp(['Iteration ' num2str(iteration) ': Growth: ' num2str(lastGrowth)]); end
    +0112         if (lastGrowth >= desiredGrowthRate)
    +0113             break;
    +0114         end
    +0115         %If you get an error here, it is likely due to numerical issues in the solver
    +0116         %The trick where we don't allow low kcats is to fix that, but maybe
    +0117         %it is not enough.
    +0118         iteration            = iteration + 1;
    +0119         %find the highest draw_prot rxn flux
    +0120         drawFluxes           = zeros(length(drawRxns),1);
    +0121         drawFluxes(drawRxns) = res.x(drawRxns);
    +0122         % Remove from the list user defined proteins
    +0123         drawFluxes(idxToIgnore) = 0;
    +0124         if ~any(drawFluxes > 0)
    +0125             printOrange('WARNING: No protein usage reaction carries flux, tuning cannot continue.\n');
    +0126             break;
    +0127         end
    +0128         [~,sel]              = max(drawFluxes); % since bounds 0 to 1000
    +0129         %Now get the metabolite
    +0130         metSel               = m.S(:,sel) > 0; % positive coeff (forward usage)
    +0131         %now find the reaction with the largest consumption of this protein
    +0132         protFluxes           = m.S(metSel,:).' .* res.x; %negative
    +0133         [~,rxnSel]           = min(protFluxes);
    +0134         kcatList             = [kcatList, rxnSel];
    +0135         rxn                  = m.rxns(rxnSel);
    +0136         targetSubRxn         = strcmp(m.ec.rxns, rxn);
    +0137         if ~strcmp(m.ec.source(targetSubRxn),'sensitivityTuning')
    +0138             oldNote          = m.ec.notes{targetSubRxn};
    +0139             newNote          = ['preTuneKcat=' num2str(m.ec.kcat(targetSubRxn)) ' | source:' m.ec.source{targetSubRxn}];
    +0140             if ~isempty(oldNote)
    +0141                 newNote      = [oldNote '; ' newNote];
    +0142             end
    +0143             m.ec.notes{targetSubRxn}    = newNote;
    +0144         end
    +0145         m.ec.kcat(targetSubRxn)     = m.ec.kcat(targetSubRxn) .* foldChange;
    +0146         m.ec.source(targetSubRxn)   = {'sensitivityTuning'};
    +0147         m                    = applyKcatConstraints(m,targetSubRxn);
    +0148     end
    +0149 
    +0150 else
    +0151     origRxns = extractAfter(m.ec.rxns,4);
    +0152     %find the reactions involved in proteins to be ignored
    +0153     idxToIgnore = cellfun(@(x) find(m.ec.rxnEnzMat(:, strcmpi(m.ec.enzymes, x))), protToIgnore, 'UniformOutput', false);
    +0154     %create an unique vector
    +0155     idxToIgnore = unique(cat(1, idxToIgnore{:}));
    +0156     %get the correct idx in model.rxns
    +0157     idxToIgnore = cellfun(@(x) find(strcmpi(m.rxns, x)), origRxns(idxToIgnore));
    +0158     iteration = 1;
    +0159     while true
    +0160         res = solveLP(m,0); %skip parsimonius, only takes time
    +0161         if isempty(res.f)
    +0162             printOrange('WARNING: The model has no feasible solution with the increased kcats, tuning stops.\n');
    +0163             break;
    +0164         end
    +0165         if ~isnan(lastGrowth) && res.f <= lastGrowth + growthStallTol
    +0166             printOrange('No growth increase from increased kcats - check if the constraints on the uptake reactions are too tight.\n');
    +0167             break;
    +0168         end
    +0169         lastGrowth = res.f;
    +0170         if (lastGrowth >= desiredGrowthRate)
    +0171             break;
    +0172         end
    +0173         %If you get an error here, it is likely due to numerical issues in the solver
    +0174         %The trick where we don't allow low kcats is to fix that, but maybe
    +0175         %it is not enough.
    +0176         if verbose; disp(['Iteration ' num2str(iteration) ': Growth: ' num2str(lastGrowth)]); end
    +0177         iteration       = iteration + 1;
    +0178         %find the highest protein usage flux
    +0179         protPoolStoich  = m.S(strcmp(m.mets, 'prot_pool'),:).';
    +0180         protPoolStoich(idxToIgnore) = 0;
    +0181         if ~any(res.x .* protPoolStoich < 0)
    +0182             printOrange('WARNING: No reaction draws on the protein pool, tuning cannot continue.\n');
    +0183             break;
    +0184         end
    +0185         [~,sel]         = min(res.x .* protPoolStoich); %max consumption
    +0186         kcatList        = [kcatList, sel];
    +0187         rxn             = m.rxns(sel.');
    +0188         targetSubRxns   = strcmp(origRxns, rxn);
    +0189         m.ec.kcat(targetSubRxns) = m.ec.kcat(targetSubRxns) .* foldChange;
    +0190         m               = applyKcatConstraints(m,rxn);
    +0191     end
    +0192 end
    +0193 
    +0194 kcatList        = unique(kcatList);
    +0195 tunedKcats.rxns = m.rxns(kcatList);
    +0196 tunedKcats.rxnNames = m.rxnNames(kcatList);
    +0197 if ~model.ec.geckoLight
    +0198     [~, rxnIdx]     = ismember(tunedKcats.rxns,m.ec.rxns);
    +0199 else
    +0200     [~, rxnIdx]     = ismember(tunedKcats.rxns,origRxns);
    +0201 end
    +0202 tunedKcats.enzymes  = cell(numel(kcatList),1);
    +0203 for i=1:numel(rxnIdx)
    +0204     [~, metIdx]     = find(m.ec.rxnEnzMat(rxnIdx(i),:));
    +0205     tunedKcats.enzymes{i}   = strjoin(m.ec.enzymes(metIdx),';');
    +0206 end
    +0207 tunedKcats.oldKcat  = model.ec.kcat(rxnIdx);
    +0208 tunedKcats.newKcat  = m.ec.kcat(rxnIdx);
    +0209 tunedKcats.source   = model.ec.source(rxnIdx);
    +0210 
    +0211 model = m;
    +0212 end
    +
    Generated by m2html © 2005
    + + \ No newline at end of file diff --git a/doc/src/kcat_tuning/sigmaFitter.html b/doc/src/kcat_tuning/sigmaFitter.html new file mode 100644 index 00000000..01d755a6 --- /dev/null +++ b/doc/src/kcat_tuning/sigmaFitter.html @@ -0,0 +1,200 @@ + + + + Description of sigmaFitter + + + + + + + + + +
    Home > src > kcat_tuning > sigmaFitter.m
    + + + +

    sigmaFitter +

    + +

    PURPOSE ^

    +
    sigmaFitter Fit the average enzyme saturation factor of an ecModel.
    + +

    SYNOPSIS ^

    +
    function [model, sigma] = sigmaFitter(model, varargin)
    + +

    DESCRIPTION ^

    +
     sigmaFitter  Fit the average enzyme saturation factor of an ecModel.
    +
    + Scans candidate sigma-factors from 0.01 to 1 in steps of 0.01 and picks the
    + one whose simulated growth rate best matches the provided experimental
    + growth rate, then applies it to the model's protein pool constraint.
    +
    + Parameters
    + ----------
    + model : struct
    +     an ecModel in GECKO 3 format (with ecModel.ec structure).
    +
    + Name-Value Arguments
    + --------------------
    + growthRate : double
    +     growth rate that should be reached (default: read from the model
    +     adapter).
    + Ptot : double
    +     total cellular protein content in g/gDCW (default: read from the model
    +     adapter; if not specified there, 0.5 g/gDCW is assumed).
    + f : double
    +     estimated fraction of enzymes in the model (default: read from the
    +     model adapter; if not specified there, 0.5 is assumed).
    + makePlot : logical
    +     whether a plot should be made (default true).
    + modelAdapter : ModelAdapter
    +     a loaded model adapter (default: the current default model adapter).
    +
    + Returns
    + -------
    + model : struct
    +     ecModel with protein pool exchange upper bound adapted to the optimal
    +     sigma-factor.
    + sigma : double
    +     optimal sigma-factor.
    +
    + Examples
    + --------
    +     % optional arguments may be given positionally or as name-value pairs:
    +     [model, sigma] = sigmaFitter(model);
    +     [model, sigma] = sigmaFitter(model, 'makePlot', false);
    +     [model, sigma] = sigmaFitter(model, growthRate, Ptot, f, makePlot, modelAdapter);
    + + +

    CROSS-REFERENCE INFORMATION ^

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

    SOURCE CODE ^

    +
    0001 function [model, sigma] = sigmaFitter(model, varargin)
    +0002 % sigmaFitter  Fit the average enzyme saturation factor of an ecModel.
    +0003 %
    +0004 % Scans candidate sigma-factors from 0.01 to 1 in steps of 0.01 and picks the
    +0005 % one whose simulated growth rate best matches the provided experimental
    +0006 % growth rate, then applies it to the model's protein pool constraint.
    +0007 %
    +0008 % Parameters
    +0009 % ----------
    +0010 % model : struct
    +0011 %     an ecModel in GECKO 3 format (with ecModel.ec structure).
    +0012 %
    +0013 % Name-Value Arguments
    +0014 % --------------------
    +0015 % growthRate : double
    +0016 %     growth rate that should be reached (default: read from the model
    +0017 %     adapter).
    +0018 % Ptot : double
    +0019 %     total cellular protein content in g/gDCW (default: read from the model
    +0020 %     adapter; if not specified there, 0.5 g/gDCW is assumed).
    +0021 % f : double
    +0022 %     estimated fraction of enzymes in the model (default: read from the
    +0023 %     model adapter; if not specified there, 0.5 is assumed).
    +0024 % makePlot : logical
    +0025 %     whether a plot should be made (default true).
    +0026 % modelAdapter : ModelAdapter
    +0027 %     a loaded model adapter (default: the current default model adapter).
    +0028 %
    +0029 % Returns
    +0030 % -------
    +0031 % model : struct
    +0032 %     ecModel with protein pool exchange upper bound adapted to the optimal
    +0033 %     sigma-factor.
    +0034 % sigma : double
    +0035 %     optimal sigma-factor.
    +0036 %
    +0037 % Examples
    +0038 % --------
    +0039 %     % optional arguments may be given positionally or as name-value pairs:
    +0040 %     [model, sigma] = sigmaFitter(model);
    +0041 %     [model, sigma] = sigmaFitter(model, 'makePlot', false);
    +0042 %     [model, sigma] = sigmaFitter(model, growthRate, Ptot, f, makePlot, modelAdapter);
    +0043 
    +0044 p = parseGECKOargs(varargin, { ...
    +0045     'growthRate',   []; ...
    +0046     'Ptot',         []; ...
    +0047     'f',            []; ...
    +0048     'makePlot',     true; ...
    +0049     'modelAdapter', []});
    +0050 growthRate   = p.growthRate;
    +0051 Ptot         = p.Ptot;
    +0052 f            = p.f;
    +0053 makePlot     = p.makePlot;
    +0054 modelAdapter = p.modelAdapter;
    +0055 
    +0056 if isempty(modelAdapter)
    +0057     modelAdapter = ModelAdapterManager.getDefault();
    +0058     if isempty(modelAdapter)
    +0059         error('Either send in a modelAdapter or set the default model adapter in the ModelAdapterManager.')
    +0060     end
    +0061 end
    +0062 
    +0063 if isempty(makePlot)
    +0064     makePlot = true;
    +0065 end
    +0066 if isempty(f)
    +0067     f = modelAdapter.getParameters().f;
    +0068 end
    +0069 if isempty(Ptot)
    +0070     Ptot = modelAdapter.getParameters().Ptot;
    +0071 end
    +0072 if isempty(growthRate)
    +0073     growthRate = modelAdapter.getParameters().gR_exp;
    +0074 end
    +0075 
    +0076 objValues = [];
    +0077 errors    = [];
    +0078 sigParam  = [];
    +0079 objPos    = find(model.c);
    +0080 %Relax bounds for the objective function
    +0081 model.lb(objPos) = 0;
    +0082 model.ub(objPos) = 1000;
    +0083 hsSol=[];
    +0084 for i=1:100
    +0085     %Constrains the ecModel with the i-th sigma factor
    +0086     sigma = i/100;
    +0087     model = setProtPoolSize(model, Ptot, f, sigma, modelAdapter);
    +0088     [solution, hsSol]  = solveLP(model,0,[],hsSol);
    +0089     if isempty(solution.x)
    +0090         solution.x=zeros(length(model.rxns),1);
    +0091     end
    +0092     objValues = [objValues; solution.x(objPos)];
    +0093     error     = abs(((growthRate-solution.x(objPos))/growthRate)*100);
    +0094     errors    = [errors; error];
    +0095     error     = num2str(((growthRate-solution.x(objPos))/growthRate)*100);
    +0096     sigParam  = [sigParam; sigma];
    +0097 end
    +0098 [~, minIndx] = min(errors);
    +0099 sigma     = sigParam(minIndx);
    +0100 % The loop above leaves the protein pool sized for the *last* sigma tried
    +0101 % (i=100, i.e. sigma=1), not the best-fitting one found by the search --
    +0102 % re-apply it here so the returned model actually matches the returned
    +0103 % sigma, per this function's own documented contract ("ecModel with
    +0104 % protein pool exchange upper bound adapted to the optimal sigma-factor").
    +0105 model = setProtPoolSize(model, Ptot, f, sigma, modelAdapter);
    +0106 if makePlot
    +0107     figure
    +0108     plot(sigParam,errors,'LineWidth',5)
    +0109     title('Sigma fitting')
    +0110     xlabel('Average enzyme saturation [-]')
    +0111     ylabel('Absolute relative error [%]')
    +0112 end
    +0113 end
    +
    Generated by m2html © 2005
    + + \ No newline at end of file diff --git a/doc/src/kcat_tuning/truncateValues.html b/doc/src/kcat_tuning/truncateValues.html new file mode 100644 index 00000000..d7ad3712 --- /dev/null +++ b/doc/src/kcat_tuning/truncateValues.html @@ -0,0 +1,92 @@ + + + + Description of truncateValues + + + + + + + + + +
    Home > src > kcat_tuning > truncateValues.m
    + + + +

    truncateValues +

    + +

    PURPOSE ^

    +
    truncateValues Round values in selected columns to six significant digits.
    + +

    SYNOPSIS ^

    +
    function table = truncateValues(table,cols)
    + +

    DESCRIPTION ^

    +
     truncateValues  Round values in selected columns to six significant digits.
    +
    + Rounds each value in the given columns of a cell array or table to six
    + significant digits, based on the value's order of magnitude.
    +
    + Parameters
    + ----------
    + table : cell or table
    +     a cell array or table where some columns have values that should be
    +     truncated.
    + cols : double
    +     index or indices of columns with values to be truncated.
    +
    + Returns
    + -------
    + table : cell or table
    +     the input with the selected columns rounded.
    + + +

    CROSS-REFERENCE INFORMATION ^

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

    SOURCE CODE ^

    +
    0001 function table = truncateValues(table,cols)
    +0002 % truncateValues  Round values in selected columns to six significant digits.
    +0003 %
    +0004 % Rounds each value in the given columns of a cell array or table to six
    +0005 % significant digits, based on the value's order of magnitude.
    +0006 %
    +0007 % Parameters
    +0008 % ----------
    +0009 % table : cell or table
    +0010 %     a cell array or table where some columns have values that should be
    +0011 %     truncated.
    +0012 % cols : double
    +0013 %     index or indices of columns with values to be truncated.
    +0014 %
    +0015 % Returns
    +0016 % -------
    +0017 % table : cell or table
    +0018 %     the input with the selected columns rounded.
    +0019 
    +0020 [m,n] = size(table);
    +0021 for i = 1:m
    +0022     for j = cols
    +0023         orderMagn  = max([ceil(log10(abs(table{i,j}))),0]);
    +0024         table{i,j} = round(table{i,j},6-orderMagn);
    +0025     end
    +0026 end
    +0027 end
    +0028 
    +0029 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
    +
    Generated by m2html © 2005
    + + \ No newline at end of file diff --git a/doc/src/limit_proteins/calculateFfactor.html b/doc/src/limit_proteins/calculateFfactor.html new file mode 100644 index 00000000..b8185395 --- /dev/null +++ b/doc/src/limit_proteins/calculateFfactor.html @@ -0,0 +1,190 @@ + + + + Description of calculateFfactor + + + + + + + + + +
    Home > src > limit_proteins > calculateFfactor.m
    + + + +

    calculateFfactor +

    + +

    PURPOSE ^

    +
    calculateFfactor Compute the f factor for an ecModel.
    + +

    SYNOPSIS ^

    +
    function f = calculateFfactor(model, varargin)
    + +

    DESCRIPTION ^

    +
     calculateFfactor  Compute the f factor for an ecModel.
    +
    + Computes the f factor, as a proxy to the mass fraction of proteins
    + accounted for in an ecModel out of the total protein content in cells.
    +
    + Parameters
    + ----------
    + model : struct
    +     an ecModel in GECKO 3 format (with ecModel.ec structure).
    +
    + Name-Value Arguments
    + --------------------
    + protData : struct
    +     structure with proteome data, from loadProtData (by default it instead
    +     attempts to load data/paxDB.tsv).
    + enzymes : cell
    +     list of enzymes (default model.ec.enzymes).
    + modelAdapter : ModelAdapter
    +     a loaded model adapter (default: the current default model adapter).
    +
    + Returns
    + -------
    + f : double
    +     f-factor.
    +
    + Examples
    + --------
    +     % optional arguments may be given positionally or as name-value pairs:
    +     f = calculateFfactor(model);
    +     f = calculateFfactor(model, 'enzymes', enzymes);
    +
    + See also
    + --------
    + loadProtData, getProtFromProteomics
    + + +

    CROSS-REFERENCE INFORMATION ^

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

    SOURCE CODE ^

    +
    0001 function f = calculateFfactor(model, varargin)
    +0002 % calculateFfactor  Compute the f factor for an ecModel.
    +0003 %
    +0004 % Computes the f factor, as a proxy to the mass fraction of proteins
    +0005 % accounted for in an ecModel out of the total protein content in cells.
    +0006 %
    +0007 % Parameters
    +0008 % ----------
    +0009 % model : struct
    +0010 %     an ecModel in GECKO 3 format (with ecModel.ec structure).
    +0011 %
    +0012 % Name-Value Arguments
    +0013 % --------------------
    +0014 % protData : struct
    +0015 %     structure with proteome data, from loadProtData (by default it instead
    +0016 %     attempts to load data/paxDB.tsv).
    +0017 % enzymes : cell
    +0018 %     list of enzymes (default model.ec.enzymes).
    +0019 % modelAdapter : ModelAdapter
    +0020 %     a loaded model adapter (default: the current default model adapter).
    +0021 %
    +0022 % Returns
    +0023 % -------
    +0024 % f : double
    +0025 %     f-factor.
    +0026 %
    +0027 % Examples
    +0028 % --------
    +0029 %     % optional arguments may be given positionally or as name-value pairs:
    +0030 %     f = calculateFfactor(model);
    +0031 %     f = calculateFfactor(model, 'enzymes', enzymes);
    +0032 %
    +0033 % See also
    +0034 % --------
    +0035 % loadProtData, getProtFromProteomics
    +0036 
    +0037 p = parseGECKOargs(varargin, { ...
    +0038     'protData',     []; ...
    +0039     'enzymes',      []; ...
    +0040     'modelAdapter', []});
    +0041 protData     = p.protData;
    +0042 enzymes      = p.enzymes;
    +0043 modelAdapter = p.modelAdapter;
    +0044 
    +0045 if isempty(modelAdapter)
    +0046     modelAdapter = ModelAdapterManager.getDefault();
    +0047     if isempty(modelAdapter)
    +0048         error('Either send in a modelAdapter or set the default model adapter in the ModelAdapterManager.')
    +0049     end
    +0050 end
    +0051 params = modelAdapter.getParameters();
    +0052 
    +0053 if isempty(enzymes)
    +0054     enzymes = model.ec.enzymes;
    +0055 end
    +0056 
    +0057 % Gather proteome data in protData structure
    +0058 if isempty(protData)
    +0059     if exist(fullfile(params.path,'data','paxDB.tsv'),'file')
    +0060         protData = fullfile(params.path,'data','paxDB.tsv');
    +0061     else
    +0062         printOrange('WARNING: No proteomics data is provided or can be found. Default f value of 0.5 is returned.\n');
    +0063         f = 0.5;
    +0064         return
    +0065     end
    +0066 end
    +0067 
    +0068 if ischar(protData) && endsWith(protData,'paxDB.tsv')
    +0069     % Gather Uniprot database for finding MW. Only needed here, to map paxDB.tsv's gene
    +0070     % identifiers onto UniProt IDs and molecular weights --- a protData struct supplied by
    +0071     % the caller already carries UniProt IDs and needs no lookup, so this stays inside the
    +0072     % branch that actually uses it rather than running (and potentially downloading or
    +0073     % reading UniProt data) on every call.
    +0074     uniprotDB = loadDatabases('uniprot', modelAdapter);
    +0075     uniprotDB = uniprotDB.uniprot;
    +0076 
    +0077     fID         = fopen(fullfile(protData),'r');
    +0078     fileContent = textscan(fID,'%s','delimiter','\n');
    +0079     headerLines = find(startsWith(fileContent{1},'#'),1,'last');
    +0080     fclose(fID);
    +0081 
    +0082     %Read data file, excluding headerlines
    +0083     fID         = fopen(fullfile(protData),'r');
    +0084     fileContent = textscan(fID,'%s %s %f','delimiter','\t','HeaderLines',headerLines);
    +0085     genes       = fileContent{2};
    +0086     %Remove internal geneIDs modifiers
    +0087     genes       = regexprep(genes,'^\d+\.','');
    +0088     level       = fileContent{3};
    +0089     fclose(fID);
    +0090     [a,b]       = ismember(genes,uniprotDB.genes);
    +0091     uniprot     = uniprotDB.ID(b(a));
    +0092     level(~a)   = [];
    +0093     clear protData
    +0094     protData.uniprotIDs = uniprot;
    +0095     protData.level   = level;
    +0096     % Get MW and abundance (unit does not matter, f is fraction)
    +0097     [~,idx] = ismember(protData.uniprotIDs,uniprotDB.ID);
    +0098     protData.MW = uniprotDB.MW(idx);
    +0099     protData.abundances = protData.level .* protData.MW;
    +0100 end
    +0101 
    +0102 avgAbundances = mean(protData.abundances,2);
    +0103 totalProt = sum(avgAbundances,'omitnan');
    +0104 
    +0105 % Get enzymes in model
    +0106 enzymesInModel = ismember(protData.uniprotIDs,enzymes);
    +0107 totalEnz = sum(avgAbundances(enzymesInModel),'omitnan');
    +0108 
    +0109 f = totalEnz/totalProt;
    +0110 end
    +
    Generated by m2html © 2005
    + + \ No newline at end of file diff --git a/doc/src/limit_proteins/constrainEnzConcs.html b/doc/src/limit_proteins/constrainEnzConcs.html new file mode 100644 index 00000000..9842b8ab --- /dev/null +++ b/doc/src/limit_proteins/constrainEnzConcs.html @@ -0,0 +1,161 @@ + + + + Description of constrainEnzConcs + + + + + + + + + +
    Home > src > limit_proteins > constrainEnzConcs.m
    + + + +

    constrainEnzConcs +

    + +

    PURPOSE ^

    +
    constrainEnzConcs Constrain enzyme usages by their concentration.
    + +

    SYNOPSIS ^

    +
    function model = constrainEnzConcs(model, varargin)
    + +

    DESCRIPTION ^

    +
     constrainEnzConcs  Constrain enzyme usages by their concentration.
    +
    + Constrain enzyme usages by their concentration as provided in
    + model.ec.concs. For enzymes with non-NaN entries in model.ec.concs, their
    + enzyme usage reaction will no longer draw from the protein pool, but is
    + rather constraint by the measured protein abundance.
    +
    + Parameters
    + ----------
    + model : struct
    +     an ecModel in GECKO 3 format (with ecModel.ec structure) with enzyme
    +     concentrations in model.ec.concs.
    +
    + Name-Value Arguments
    + --------------------
    + removeConstraints : logical
    +     whether enzyme concentration constraints should be removed
    +     (model.ec.concs will remain unchanged) (default false).
    +
    + Returns
    + -------
    + model : struct
    +     an ecModel constraint with available enzyme concentrations.
    +
    + Notes
    + -----
    + To populate model.ec.concs you should run fillEnzConcs.
    +
    + Examples
    + --------
    +     % optional arguments may be given positionally or as name-value pairs:
    +     model = constrainEnzConcs(model);
    +     model = constrainEnzConcs(model, 'removeConstraints', true);
    +
    + See also
    + --------
    + fillEnzConcs
    + + +

    CROSS-REFERENCE INFORMATION ^

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

    SOURCE CODE ^

    +
    0001 function model = constrainEnzConcs(model, varargin)
    +0002 % constrainEnzConcs  Constrain enzyme usages by their concentration.
    +0003 %
    +0004 % Constrain enzyme usages by their concentration as provided in
    +0005 % model.ec.concs. For enzymes with non-NaN entries in model.ec.concs, their
    +0006 % enzyme usage reaction will no longer draw from the protein pool, but is
    +0007 % rather constraint by the measured protein abundance.
    +0008 %
    +0009 % Parameters
    +0010 % ----------
    +0011 % model : struct
    +0012 %     an ecModel in GECKO 3 format (with ecModel.ec structure) with enzyme
    +0013 %     concentrations in model.ec.concs.
    +0014 %
    +0015 % Name-Value Arguments
    +0016 % --------------------
    +0017 % removeConstraints : logical
    +0018 %     whether enzyme concentration constraints should be removed
    +0019 %     (model.ec.concs will remain unchanged) (default false).
    +0020 %
    +0021 % Returns
    +0022 % -------
    +0023 % model : struct
    +0024 %     an ecModel constraint with available enzyme concentrations.
    +0025 %
    +0026 % Notes
    +0027 % -----
    +0028 % To populate model.ec.concs you should run fillEnzConcs.
    +0029 %
    +0030 % Examples
    +0031 % --------
    +0032 %     % optional arguments may be given positionally or as name-value pairs:
    +0033 %     model = constrainEnzConcs(model);
    +0034 %     model = constrainEnzConcs(model, 'removeConstraints', true);
    +0035 %
    +0036 % See also
    +0037 % --------
    +0038 % fillEnzConcs
    +0039 
    +0040 %Enzyme with NaN entry in model.ec.concs => draw from prot_pool
    +0041 %Enzyme with numeric entry in model.ec.concs => exchange reaction with
    +0042 %enzyme level as UB
    +0043 
    +0044 p = parseGECKOargs(varargin, { ...
    +0045     'removeConstraints', false});
    +0046 removeConstraints = p.removeConstraints;
    +0047 
    +0048 %Get indices of usage reactions
    +0049 usageRxns = strcat('usage_prot_',model.ec.enzymes);
    +0050 [~, usageRxnsIdx] = ismember(usageRxns, model.rxns);
    +0051 
    +0052 if any(usageRxnsIdx == 0)
    +0053     error('Usage reactions are not defined for all enzymes. This is done by makeEcModel.')
    +0054 end
    +0055 %Get index of protein pool metabolite
    +0056 protPoolIdx = find(ismember(model.mets,'prot_pool'));
    +0057 if ~any(protPoolIdx)
    +0058     error('Cannot find protein pool pseudometabolite.')
    +0059 end
    +0060 
    +0061 %Protein that should be constraint by UB
    +0062 if removeConstraints
    +0063     protCons = [];
    +0064 else
    +0065     protCons = ~isnan(model.ec.concs);
    +0066 end
    +0067 
    +0068 %Set all reactions to draw from prot_pool (forward: prot_pool -> prot_<id>)
    +0069 model.S(protPoolIdx, usageRxnsIdx) = -1;
    +0070 model.lb(usageRxnsIdx) = 0;
    +0071 model.ub(usageRxnsIdx) = 1000;
    +0072 
    +0073 %If non-NaN in model.ec.concs, then constrain by UB
    +0074 if any(protCons)
    +0075 %    model.S(protPoolIdx, usageRxnsIdx(protCons)) = 0; % Since GECKO 3.2.0
    +0076     model.ub(usageRxnsIdx(protCons)) = model.ec.concs(protCons);
    +0077 end
    +0078 end
    +
    Generated by m2html © 2005
    + + \ No newline at end of file diff --git a/doc/src/limit_proteins/constrainFluxData.html b/doc/src/limit_proteins/constrainFluxData.html new file mode 100644 index 00000000..4967c2b1 --- /dev/null +++ b/doc/src/limit_proteins/constrainFluxData.html @@ -0,0 +1,264 @@ + + + + Description of constrainFluxData + + + + + + + + + +
    Home > src > limit_proteins > constrainFluxData.m
    + + + +

    constrainFluxData +

    + +

    PURPOSE ^

    +
    constrainFluxData Constrain ecModel fluxes to provided flux data.
    + +

    SYNOPSIS ^

    +
    function model = constrainFluxData(model, varargin)
    + +

    DESCRIPTION ^

    +
     constrainFluxData  Constrain ecModel fluxes to provided flux data.
    +
    + Constrains fluxes to the data that is provided in the fluxData structure,
    + which itself is read by loadFluxData from data/fluxData.tsv.
    +
    + Parameters
    + ----------
    + model : struct
    +     an ecModel in GECKO 3 format (with ecModel.ec structure).
    +
    + Name-Value Arguments
    + --------------------
    + fluxData : struct
    +     structure with flux data, with the fields:
    +
    +     - conds : sampling condition.
    +     - Ptot : total protein (g/gDCW).
    +     - grRate : growth rate (1/h).
    +     - exchFluxes : exchange fluxes (mmol/gDCWh).
    +     - exchMets : exchanged metabolites, matching exchFluxes.
    +     - exchRxnIDs : exchange reaction IDs, matching exchMets.
    + condition : double or char
    +     either index number or name of the sample condition in fluxData.conds
    +     (default 1).
    + maxMinGrowth : char
    +     'max' if the provided growth rate should be set as maximum growth rate
    +     (= upper bound), or 'min' if it should be set as minimum growth rate
    +     (= lower bound). The latter option is suitable if minimization of
    +     prot_pool_exchange is used as objective function (default 'max').
    + looseStrictFlux : char or double
    +     how strictly constrained the exchange fluxes should be (default
    +     'loose'):
    +
    +     - 'loose' : the exchange fluxes are constraint only by the "outer
    +       bounds". If exchFluxes(i) > 0, LB = 0 and UB = exchFluxes(i). If
    +       exchFluxes(i) < 0, LB = exchFluxes(i) and UB = 0.
    +     - 0-100 : LB and UB constraints are set with a specified percentage of
    +       variance around exchFluxes. If 10 is specified, LB = exchFluxes*0.95
    +       and UB = exchFluxes*1.05. This allows for 10% variance around the
    +       exchFluxes values, but strictly forces a flux through the exchRxns.
    + modelAdapter : ModelAdapter
    +     a loaded model adapter (default: the current default model adapter).
    +
    + Returns
    + -------
    + model : struct
    +     an ecModel where fluxes are constraint.
    +
    + Notes
    + -----
    + If a provided constraint is either -1000 or 1000, then the function will
    + update the reaction lower and upper bound to either allow uptake or
    + excretion, irrespective of what option is given as the looseStrictFlux
    + parameter.
    +
    + Examples
    + --------
    +     % optional arguments may be given positionally or as name-value pairs:
    +     model = constrainFluxData(model);
    +     model = constrainFluxData(model, 'condition', 2);
    +
    + See also
    + --------
    + loadFluxData
    + + +

    CROSS-REFERENCE INFORMATION ^

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

    SOURCE CODE ^

    +
    0001 function model = constrainFluxData(model, varargin)
    +0002 % constrainFluxData  Constrain ecModel fluxes to provided flux data.
    +0003 %
    +0004 % Constrains fluxes to the data that is provided in the fluxData structure,
    +0005 % which itself is read by loadFluxData from data/fluxData.tsv.
    +0006 %
    +0007 % Parameters
    +0008 % ----------
    +0009 % model : struct
    +0010 %     an ecModel in GECKO 3 format (with ecModel.ec structure).
    +0011 %
    +0012 % Name-Value Arguments
    +0013 % --------------------
    +0014 % fluxData : struct
    +0015 %     structure with flux data, with the fields:
    +0016 %
    +0017 %     - conds : sampling condition.
    +0018 %     - Ptot : total protein (g/gDCW).
    +0019 %     - grRate : growth rate (1/h).
    +0020 %     - exchFluxes : exchange fluxes (mmol/gDCWh).
    +0021 %     - exchMets : exchanged metabolites, matching exchFluxes.
    +0022 %     - exchRxnIDs : exchange reaction IDs, matching exchMets.
    +0023 % condition : double or char
    +0024 %     either index number or name of the sample condition in fluxData.conds
    +0025 %     (default 1).
    +0026 % maxMinGrowth : char
    +0027 %     'max' if the provided growth rate should be set as maximum growth rate
    +0028 %     (= upper bound), or 'min' if it should be set as minimum growth rate
    +0029 %     (= lower bound). The latter option is suitable if minimization of
    +0030 %     prot_pool_exchange is used as objective function (default 'max').
    +0031 % looseStrictFlux : char or double
    +0032 %     how strictly constrained the exchange fluxes should be (default
    +0033 %     'loose'):
    +0034 %
    +0035 %     - 'loose' : the exchange fluxes are constraint only by the "outer
    +0036 %       bounds". If exchFluxes(i) > 0, LB = 0 and UB = exchFluxes(i). If
    +0037 %       exchFluxes(i) < 0, LB = exchFluxes(i) and UB = 0.
    +0038 %     - 0-100 : LB and UB constraints are set with a specified percentage of
    +0039 %       variance around exchFluxes. If 10 is specified, LB = exchFluxes*0.95
    +0040 %       and UB = exchFluxes*1.05. This allows for 10% variance around the
    +0041 %       exchFluxes values, but strictly forces a flux through the exchRxns.
    +0042 % modelAdapter : ModelAdapter
    +0043 %     a loaded model adapter (default: the current default model adapter).
    +0044 %
    +0045 % Returns
    +0046 % -------
    +0047 % model : struct
    +0048 %     an ecModel where fluxes are constraint.
    +0049 %
    +0050 % Notes
    +0051 % -----
    +0052 % If a provided constraint is either -1000 or 1000, then the function will
    +0053 % update the reaction lower and upper bound to either allow uptake or
    +0054 % excretion, irrespective of what option is given as the looseStrictFlux
    +0055 % parameter.
    +0056 %
    +0057 % Examples
    +0058 % --------
    +0059 %     % optional arguments may be given positionally or as name-value pairs:
    +0060 %     model = constrainFluxData(model);
    +0061 %     model = constrainFluxData(model, 'condition', 2);
    +0062 %
    +0063 % See also
    +0064 % --------
    +0065 % loadFluxData
    +0066 
    +0067 p = parseGECKOargs(varargin, { ...
    +0068     'fluxData',        []; ...
    +0069     'condition',       []; ...
    +0070     'maxMinGrowth',    []; ...
    +0071     'looseStrictFlux', []; ...
    +0072     'modelAdapter',    []});
    +0073 fluxData        = p.fluxData;
    +0074 condition       = p.condition;
    +0075 maxMinGrowth    = p.maxMinGrowth;
    +0076 looseStrictFlux = p.looseStrictFlux;
    +0077 modelAdapter    = p.modelAdapter;
    +0078 
    +0079 if isempty(modelAdapter)
    +0080     modelAdapter = ModelAdapterManager.getDefault();
    +0081     if isempty(modelAdapter)
    +0082         error('Either send in a modelAdapter or set the default model adapter in the ModelAdapterManager.')
    +0083     end
    +0084 end
    +0085 params = modelAdapter.getParameters();
    +0086 
    +0087 if isempty(looseStrictFlux)
    +0088     looseStrictFlux = 'loose';
    +0089 end
    +0090 
    +0091 if isempty(maxMinGrowth)
    +0092     maxMinGrowth = 'max';
    +0093 end
    +0094 
    +0095 if isempty(fluxData)
    +0096     fluxData = loadFluxData(fullfile(params.path,'data','fluxData.tsv'),modelAdapter);
    +0097 end
    +0098 
    +0099 if isempty(condition)
    +0100     condition = 1;
    +0101 elseif ~isnumeric(condition)
    +0102     idx = find(strcmp(fluxData.conds,condition));
    +0103     if isempty(condition)
    +0104         error(['Condition ' condition ' cannot be found in fluxData'])
    +0105     else
    +0106         condition = idx;
    +0107     end
    +0108 end
    +0109 
    +0110 % Select the exchange fluxes of specified condition
    +0111 fluxData.exchFluxes = fluxData.exchFluxes(condition,:);
    +0112 
    +0113 %Set original c-source to zero
    +0114 model = setParam(model,'eq',params.c_source,0);
    +0115 %Set growth
    +0116 switch maxMinGrowth
    +0117     case 'max'
    +0118         model = setParam(model,'lb',params.bioRxn,0);
    +0119         model = setParam(model,'ub',params.bioRxn,fluxData.grRate(condition));
    +0120     case 'min'
    +0121         model = setParam(model,'lb',params.bioRxn,fluxData.grRate(condition));
    +0122         model = setParam(model,'ub',params.bioRxn,1000);
    +0123 end
    +0124 
    +0125 naFlux = isnan(fluxData.exchFluxes);
    +0126 negFlux = lt(fluxData.exchFluxes,0); % less than 0
    +0127 ub = fluxData.exchFluxes(~(negFlux | naFlux));
    +0128 posFlux = fluxData.exchRxnIDs(~(negFlux | naFlux));
    +0129 lb = fluxData.exchFluxes(negFlux & ~naFlux);
    +0130 negFlux = fluxData.exchRxnIDs(negFlux & ~naFlux);
    +0131 
    +0132 switch looseStrictFlux
    +0133     case 'loose'
    +0134         model = setParam(model,'lb',negFlux,lb);
    +0135         model = setParam(model,'ub',negFlux,0);
    +0136         model = setParam(model,'lb',posFlux,0);
    +0137         model = setParam(model,'ub',posFlux,ub);
    +0138     otherwise
    +0139         model = setParam(model,'var',negFlux,lb,looseStrictFlux);
    +0140         model = setParam(model,'var',posFlux,ub,looseStrictFlux);
    +0141 end
    +0142 extremeFlux = find(abs(fluxData.exchFluxes)==1000);
    +0143 if any(extremeFlux)
    +0144     exchFlux = fluxData.exchFluxes(extremeFlux);
    +0145     if any(exchFlux==-1000)
    +0146         model = setParam(model,'lb',fluxData.exchRxnIDs(extremeFlux(exchFlux==-1000)),-1000);
    +0147         model = setParam(model,'ub',fluxData.exchRxnIDs(extremeFlux(exchFlux==-1000)),0);
    +0148     end
    +0149     if any(exchFlux==1000)
    +0150         model = setParam(model,'lb',fluxData.exchRxnIDs(extremeFlux(exchFlux==1000)),0);
    +0151         model = setParam(model,'ub',fluxData.exchRxnIDs(extremeFlux(exchFlux==1000)),1000);
    +0152     end
    +0153 end
    +0154 end
    +
    Generated by m2html © 2005
    + + \ No newline at end of file diff --git a/doc/src/limit_proteins/fillEnzConcs.html b/doc/src/limit_proteins/fillEnzConcs.html new file mode 100644 index 00000000..03abdcda --- /dev/null +++ b/doc/src/limit_proteins/fillEnzConcs.html @@ -0,0 +1,152 @@ + + + + Description of fillEnzConcs + + + + + + + + + +
    Home > src > limit_proteins > fillEnzConcs.m
    + + + +

    fillEnzConcs +

    + +

    PURPOSE ^

    +
    fillEnzConcs Populate model.ec.concs from proteome data.
    + +

    SYNOPSIS ^

    +
    function model = fillEnzConcs(model, protData, varargin)
    + +

    DESCRIPTION ^

    +
     fillEnzConcs  Populate model.ec.concs from proteome data.
    +
    + Uses the protein concentrations from protData to fill model.ec.concs.
    + Protein levels should be provided in mg/gDCW. If no data is provided for a
    + particular protein, its level is NaN. Existing entries in model.ec.concs
    + are overwritten.
    +
    + Parameters
    + ----------
    + model : struct
    +     an ecModel in GECKO 3 format (with ecModel.ec structure).
    + protData : struct
    +     structure with proteome data, from loadProtFluxData, with the fields:
    +
    +     - uniprotIDs : cell array with Uniprot IDs matching protData.abundances.
    +     - abundances : matrix of proteomics data.
    +
    + Name-Value Arguments
    + --------------------
    + dataCol : double
    +     number indicating the column in protData.abundances that contains the
    +     relevant protein concentrations. protData may contain data from
    +     multiple conditions/samples/experiments, each with their own column in
    +     protData.abundances (default 1).
    +
    + Returns
    + -------
    + model : struct
    +     an ecModel where model.ec.concs is populated with protein
    +     concentrations.
    +
    + Notes
    + -----
    + To also constrain the model with the content of model.ec.concs, you should
    + run constrainEnzConcs.
    +
    + Examples
    + --------
    +     % optional arguments may be given positionally or as name-value pairs:
    +     model = fillEnzConcs(model, protData);
    +     model = fillEnzConcs(model, protData, 'dataCol', 2);
    +
    + See also
    + --------
    + constrainEnzConcs, loadProtFluxData
    + + +

    CROSS-REFERENCE INFORMATION ^

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

    SOURCE CODE ^

    +
    0001 function model = fillEnzConcs(model, protData, varargin)
    +0002 % fillEnzConcs  Populate model.ec.concs from proteome data.
    +0003 %
    +0004 % Uses the protein concentrations from protData to fill model.ec.concs.
    +0005 % Protein levels should be provided in mg/gDCW. If no data is provided for a
    +0006 % particular protein, its level is NaN. Existing entries in model.ec.concs
    +0007 % are overwritten.
    +0008 %
    +0009 % Parameters
    +0010 % ----------
    +0011 % model : struct
    +0012 %     an ecModel in GECKO 3 format (with ecModel.ec structure).
    +0013 % protData : struct
    +0014 %     structure with proteome data, from loadProtFluxData, with the fields:
    +0015 %
    +0016 %     - uniprotIDs : cell array with Uniprot IDs matching protData.abundances.
    +0017 %     - abundances : matrix of proteomics data.
    +0018 %
    +0019 % Name-Value Arguments
    +0020 % --------------------
    +0021 % dataCol : double
    +0022 %     number indicating the column in protData.abundances that contains the
    +0023 %     relevant protein concentrations. protData may contain data from
    +0024 %     multiple conditions/samples/experiments, each with their own column in
    +0025 %     protData.abundances (default 1).
    +0026 %
    +0027 % Returns
    +0028 % -------
    +0029 % model : struct
    +0030 %     an ecModel where model.ec.concs is populated with protein
    +0031 %     concentrations.
    +0032 %
    +0033 % Notes
    +0034 % -----
    +0035 % To also constrain the model with the content of model.ec.concs, you should
    +0036 % run constrainEnzConcs.
    +0037 %
    +0038 % Examples
    +0039 % --------
    +0040 %     % optional arguments may be given positionally or as name-value pairs:
    +0041 %     model = fillEnzConcs(model, protData);
    +0042 %     model = fillEnzConcs(model, protData, 'dataCol', 2);
    +0043 %
    +0044 % See also
    +0045 % --------
    +0046 % constrainEnzConcs, loadProtFluxData
    +0047 
    +0048 p = parseGECKOargs(varargin, { ...
    +0049     'dataCol', 1});
    +0050 dataCol = p.dataCol;
    +0051 if isempty(dataCol); dataCol = 1; end
    +0052 
    +0053 uniprotIDs = protData.uniprotIDs;
    +0054 abundances = protData.abundances(:,dataCol);
    +0055 
    +0056 %Redefine an empty model.ec.concs vector
    +0057 model.ec.concs=nan(numel(model.ec.enzymes),1);
    +0058 
    +0059 [a,b] = ismember(uniprotIDs, model.ec.enzymes);
    +0060 model.ec.concs(b(a)) = abundances(a);
    +0061 end
    +
    Generated by m2html © 2005
    + + \ No newline at end of file diff --git a/doc/src/limit_proteins/flexibilizeEnzConcs.html b/doc/src/limit_proteins/flexibilizeEnzConcs.html new file mode 100644 index 00000000..41a2567e --- /dev/null +++ b/doc/src/limit_proteins/flexibilizeEnzConcs.html @@ -0,0 +1,381 @@ + + + + Description of flexibilizeEnzConcs + + + + + + + + + +
    Home > src > limit_proteins > flexibilizeEnzConcs.m
    + + + +

    flexibilizeEnzConcs +

    + +

    PURPOSE ^

    +
    flexibilizeEnzConcs Flexibilize enzyme concentrations of an ecModel.
    + +

    SYNOPSIS ^

    +
    function [model, flexEnz] = flexibilizeEnzConcs(model, varargin)
    + +

    DESCRIPTION ^

    +
     flexibilizeEnzConcs  Flexibilize enzyme concentrations of an ecModel.
    +
    + Flexibilize enzyme concentration of an ecModel constrained with proteomics
    + data. The upper bound of the protein usage reaction is changed, while the
    + concentrations in ecModel.ec.concs remain unchanged.
    +
    + If no (more) limiting enzyme concentrations can be found, it might be the
    + protein pool exchange that is limiting growth. In that case, an attempt
    + will be made to relax the protein pool exchange reaction, and if the growth
    + rate indeed increases, it is suggested to set the protein pool exchange
    + unconstrained (ub=1000) before again running flexibilizeEnzConcs. Such
    + situations, where a proteomics integrated ecModel is overconstrained, may
    + occur if the ecModel should be able to simulate maximum growth rate (from
    + e.g. batch cultivation).
    +
    + If relaxing the protein pool exchange does not increase the growth rate,
    + then this is not due to enzyme constraints, but rather an issue with the
    + metabolic network itself, or the set nutrient exchange is not sufficient.
    +
    + Parameters
    + ----------
    + model : struct
    +     an ecModel in GECKO 3 format (with ecModel.ec structure).
    +
    + Name-Value Arguments
    + --------------------
    + expGrowth : double
    +     estimated experimental growth rate. If not specified, the value will be
    +     read from the model adapter.
    + foldChange : double
    +     a value how much to increase the enzyme concentration (default 2).
    + iterPerEnzyme : double
    +     the number of iterations that an enzyme can be increased. A zero number
    +     can be defined; if zero is defined no limit will be set, and it will
    +     increase the enzyme concentration until it reaches the defined growth
    +     rate (default 5).
    + modelAdapter : ModelAdapter
    +     a loaded model adapter (default: the current default model adapter).
    + verbose : logical
    +     whether progress should be reported (default true).
    +
    + Returns
    + -------
    + model : struct
    +     ecModel where the constraint of measured enzyme concentrations have
    +     been flexibilized (=relaxed) in the S-matrix, to allow the model to
    +     reach the growth rate defined in expGrowth, while the values in
    +     ecModel.ec.concs have remained untouched.
    + flexEnz : struct
    +     array with information about flexibilized proteins, with the fields:
    +
    +     - uniprotIDs : enzymes whose usage UB was flexibilized.
    +     - oldConcs : original concentrations, from model.ec.concs.
    +     - flexConcs : flexibilized concentrations, new UB in model.
    +     - ratioIncr : ratio by which the concentration increased; the enzymes
    +       will be sorted by this field.
    +     - frequence : numeric how often the enzyme has been step-wise
    +       flexibilized.
    +
    + Examples
    + --------
    +     % optional arguments may be given positionally or as name-value pairs:
    +     [model, flexEnz] = flexibilizeEnzConcs(model);
    +     [model, flexEnz] = flexibilizeEnzConcs(model, 'foldChange', 3);
    +
    + See also
    + --------
    + constrainEnzConcs, getConcControlCoeffs
    + + +

    CROSS-REFERENCE INFORMATION ^

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

    SOURCE CODE ^

    +
    0001 function [model, flexEnz] = flexibilizeEnzConcs(model, varargin)
    +0002 % flexibilizeEnzConcs  Flexibilize enzyme concentrations of an ecModel.
    +0003 %
    +0004 % Flexibilize enzyme concentration of an ecModel constrained with proteomics
    +0005 % data. The upper bound of the protein usage reaction is changed, while the
    +0006 % concentrations in ecModel.ec.concs remain unchanged.
    +0007 %
    +0008 % If no (more) limiting enzyme concentrations can be found, it might be the
    +0009 % protein pool exchange that is limiting growth. In that case, an attempt
    +0010 % will be made to relax the protein pool exchange reaction, and if the growth
    +0011 % rate indeed increases, it is suggested to set the protein pool exchange
    +0012 % unconstrained (ub=1000) before again running flexibilizeEnzConcs. Such
    +0013 % situations, where a proteomics integrated ecModel is overconstrained, may
    +0014 % occur if the ecModel should be able to simulate maximum growth rate (from
    +0015 % e.g. batch cultivation).
    +0016 %
    +0017 % If relaxing the protein pool exchange does not increase the growth rate,
    +0018 % then this is not due to enzyme constraints, but rather an issue with the
    +0019 % metabolic network itself, or the set nutrient exchange is not sufficient.
    +0020 %
    +0021 % Parameters
    +0022 % ----------
    +0023 % model : struct
    +0024 %     an ecModel in GECKO 3 format (with ecModel.ec structure).
    +0025 %
    +0026 % Name-Value Arguments
    +0027 % --------------------
    +0028 % expGrowth : double
    +0029 %     estimated experimental growth rate. If not specified, the value will be
    +0030 %     read from the model adapter.
    +0031 % foldChange : double
    +0032 %     a value how much to increase the enzyme concentration (default 2).
    +0033 % iterPerEnzyme : double
    +0034 %     the number of iterations that an enzyme can be increased. A zero number
    +0035 %     can be defined; if zero is defined no limit will be set, and it will
    +0036 %     increase the enzyme concentration until it reaches the defined growth
    +0037 %     rate (default 5).
    +0038 % modelAdapter : ModelAdapter
    +0039 %     a loaded model adapter (default: the current default model adapter).
    +0040 % verbose : logical
    +0041 %     whether progress should be reported (default true).
    +0042 %
    +0043 % Returns
    +0044 % -------
    +0045 % model : struct
    +0046 %     ecModel where the constraint of measured enzyme concentrations have
    +0047 %     been flexibilized (=relaxed) in the S-matrix, to allow the model to
    +0048 %     reach the growth rate defined in expGrowth, while the values in
    +0049 %     ecModel.ec.concs have remained untouched.
    +0050 % flexEnz : struct
    +0051 %     array with information about flexibilized proteins, with the fields:
    +0052 %
    +0053 %     - uniprotIDs : enzymes whose usage UB was flexibilized.
    +0054 %     - oldConcs : original concentrations, from model.ec.concs.
    +0055 %     - flexConcs : flexibilized concentrations, new UB in model.
    +0056 %     - ratioIncr : ratio by which the concentration increased; the enzymes
    +0057 %       will be sorted by this field.
    +0058 %     - frequence : numeric how often the enzyme has been step-wise
    +0059 %       flexibilized.
    +0060 %
    +0061 % Examples
    +0062 % --------
    +0063 %     % optional arguments may be given positionally or as name-value pairs:
    +0064 %     [model, flexEnz] = flexibilizeEnzConcs(model);
    +0065 %     [model, flexEnz] = flexibilizeEnzConcs(model, 'foldChange', 3);
    +0066 %
    +0067 % See also
    +0068 % --------
    +0069 % constrainEnzConcs, getConcControlCoeffs
    +0070 
    +0071 p = parseGECKOargs(varargin, { ...
    +0072     'expGrowth',     []; ...
    +0073     'foldChange',    []; ...
    +0074     'iterPerEnzyme', []; ...
    +0075     'modelAdapter',  []; ...
    +0076     'verbose',       []});
    +0077 expGrowth     = p.expGrowth;
    +0078 foldChange    = p.foldChange;
    +0079 iterPerEnzyme = p.iterPerEnzyme;
    +0080 modelAdapter  = p.modelAdapter;
    +0081 verbose       = p.verbose;
    +0082 
    +0083 if isempty(verbose)
    +0084     verbose = true;
    +0085 end
    +0086 if isempty(modelAdapter)
    +0087     modelAdapter = ModelAdapterManager.getDefault();
    +0088     if isempty(modelAdapter)
    +0089         error('Either send in a modelAdapter or set the default model adapter in the ModelAdapterManager.')
    +0090     end
    +0091 end
    +0092 params = modelAdapter.getParameters();
    +0093 
    +0094 if isempty(iterPerEnzyme)
    +0095     iterPerEnzyme = 5;
    +0096 end
    +0097 
    +0098 if isempty(foldChange)
    +0099     foldChange = 2;
    +0100 end
    +0101 
    +0102 if isempty(expGrowth)
    +0103     expGrowth = modelAdapter.getParameters().gR_exp;
    +0104 end
    +0105 
    +0106 % If a zero value is defined, not iteration limit will be set
    +0107 if iterPerEnzyme == 0
    +0108     iterPerEnzyme = inf;
    +0109 end
    +0110 
    +0111 bioRxnIdx = getIndexes(model,params.bioRxn,'rxns');
    +0112 if model.ub(bioRxnIdx) < expGrowth
    +0113     fprintf(['The upper bound of the biomass reaction was %s, while expGrowth '...
    +0114              'is %s. The upper bound has been set to expGrowth.'],...
    +0115              num2str(model.ub(bioRxnIdx)), num2str(expGrowth))
    +0116     model.ub(bioRxnIdx) = expGrowth;
    +0117 end
    +0118 
    +0119 % Keep track if protein pool will be flexibilized
    +0120 changedProtPool = false;
    +0121 
    +0122 % In case the model have not been protein constrained
    +0123 % model = constrainEnzConcs(model);
    +0124 
    +0125 [sol,hs] = solveLP(model);
    +0126 predGrowth = sol.f;
    +0127 
    +0128 % Get those proteins with a concentration defined
    +0129 protConcs = find(~isnan(model.ec.concs));
    +0130 
    +0131 % Get enzymes names with a concentration value
    +0132 proteins = model.ec.enzymes(protConcs);
    +0133 
    +0134 % Store how many time is predicted a enzyme with the highest coeff
    +0135 frequence = zeros(numel(proteins),1);
    +0136 
    +0137 flexBreak=false;
    +0138 if any(protConcs)
    +0139     while predGrowth < expGrowth
    +0140 
    +0141         % Get the control coefficients
    +0142         [~, controlCoeffs] = getConcControlCoeffs(model, proteins, foldChange, 0.75);
    +0143 
    +0144         % Stop looking for limiting proteins all coeffs are zero
    +0145         if any(controlCoeffs)
    +0146 
    +0147             % Find the maximum coefficient index
    +0148             [~,maxIdx] = max(controlCoeffs);
    +0149 
    +0150             % Increase +1 the frequence
    +0151             frequence(maxIdx) = frequence(maxIdx) + 1;
    +0152 
    +0153             % Allow to increase the UB maximum five times
    +0154             if frequence(maxIdx) <= iterPerEnzyme
    +0155 
    +0156                 % Set how much will increase the UB
    +0157                 increase = foldChange*frequence(maxIdx);
    +0158 
    +0159                 % Get usage rxn for the highest coeff
    +0160                 protUsageIdx = strcmpi(model.rxns, strcat('usage_prot_', proteins(maxIdx)));
    +0161 
    +0162                 % replace the UB
    +0163                 model.ub(protUsageIdx) = model.ec.concs(protConcs(maxIdx)) * (1+increase);
    +0164 
    +0165                 % Get the new growth rate
    +0166                 sol = solveLP(model,0,[],hs);
    +0167                 predGrowth = sol.f;
    +0168 
    +0169                 if verbose
    +0170                     disp(['Protein ' proteins{maxIdx} ' UB adjusted. Grow: ' num2str(predGrowth)])
    +0171                 end
    +0172             else
    +0173                 printOrange(['WARNING: Limit has been reached. Protein '  proteins{maxIdx} ' seems to be problematic. Consider changing the kcat.\n']);
    +0174                 flexBreak=true;
    +0175                 break
    +0176             end
    +0177         else
    +0178             disp('No (more) limiting enzymes have been found. Attempting to increase protein pool exchange...')
    +0179             protPoolIdx = getIndexes(model,'prot_pool_exchange','rxns');
    +0180             oldProtPool = model.ub(protPoolIdx);
    +0181             tempModel = setParam(model,'ub',protPoolIdx,1000);
    +0182             tempModel = setParam(tempModel,'ub',bioRxnIdx,expGrowth);
    +0183             sol = solveLP(tempModel);
    +0184             if (sol.f-predGrowth)>1e-3 % There is improvement in growth rate
    +0185                 % Find new protein pool constraint
    +0186                 predGrowth = sol.f;
    +0187                 tempModel = setParam(tempModel,'lb',bioRxnIdx,predGrowth);
    +0188                 % minimise pool usage (solveLP maximises the objective, so use -1)
    +0189                 tempModel = setParam(tempModel,'obj',protPoolIdx,-1);
    +0190                 sol = solveLP(tempModel);
    +0191                 newProtPool = sol.x(protPoolIdx);
    +0192                 model.ub(protPoolIdx) = newProtPool;
    +0193                 fprintf(['Changing the upper bound of protein pool exchange from %s ',...
    +0194                          'to %s enabled a\ngrowth rate of %s. It can be helpful to set ', ...
    +0195                          'the upper bound of protein\npool exchange to 1000 before ',...
    +0196                          'running flexibilizeEnzConcs.\n'],num2str(oldProtPool), ...
    +0197                          num2str(newProtPool),num2str(predGrowth));
    +0198                 changedProtPool = true;
    +0199             else
    +0200                 fprintf(['Protein pool exchange was also not limiting. Inability to reach growth ',...
    +0201                         'rate is not related to\nenzyme constraints. Maximum growth rate ',...
    +0202                         'is %s.\n'], num2str(predGrowth))
    +0203             end
    +0204             % To return an usable model with these conditions, set the
    +0205             % highest growth rate reached as the experimental value
    +0206             expGrowth = predGrowth;
    +0207             break
    +0208         end
    +0209     end
    +0210 else
    +0211     error('Protein concentrations have not been defined. Please run readProteomics and constrainEnzConcs')
    +0212 end
    +0213 
    +0214 protFlex         = proteins(frequence>0);
    +0215 [~,protUsageIdx] = ismember(strcat('usage_prot_', protFlex), model.rxns);
    +0216 [~,ecProtId]     = ismember(protFlex, model.ec.enzymes);
    +0217 oldConcs         = model.ec.concs(ecProtId);
    +0218 %frequence        = frequence(ecProtId);
    +0219 
    +0220 if flexBreak == false && ~isempty(protFlex)
    +0221     % Not all flexibilized proteins require flexibilization in the end
    +0222     % Test flux distribution with minimum prot_pool usage
    +0223     modelTemp       = setParam(model,'var',params.bioRxn,expGrowth,0.5);
    +0224     % minimise pool usage (solveLP maximises the objective, so use -1)
    +0225     modelTemp       = setParam(modelTemp,'obj','prot_pool_exchange',-1);
    +0226     sol             = solveLP(modelTemp,1);
    +0227     % Check which concentrations can remain unchanged
    +0228     newConcs        = abs(sol.x(protUsageIdx));
    +0229     keepOld         = newConcs<oldConcs;
    +0230     % Set UBs
    +0231     model.ub(protUsageIdx(keepOld))  = oldConcs(keepOld);
    +0232     model.ub(protUsageIdx(~keepOld)) = newConcs(~keepOld);
    +0233     % Output structure
    +0234     protFlex(keepOld) = [];
    +0235     oldConcs(keepOld) = [];
    +0236     newConcs(keepOld) = [];
    +0237     frequence=frequence(frequence>0);
    +0238     frequence(keepOld) = [];
    +0239     
    +0240     flexEnz.uniprotIDs = protFlex;
    +0241     flexEnz.oldConcs   = oldConcs;
    +0242     flexEnz.flexConcs  = newConcs;
    +0243     flexEnz.frequence  = frequence(frequence>0);
    +0244 else
    +0245     protFlex           = proteins(frequence>0);
    +0246     [~, protUsageIdx]  = ismember(strcat('usage_prot_', protFlex), model.rxns);
    +0247 
    +0248     flexEnz.uniprotIDs = protFlex;
    +0249     flexEnz.oldConcs   = model.ec.concs(ecProtId);
    +0250     flexEnz.flexConcs  = model.ub(protUsageIdx);
    +0251     flexEnz.frequence  = frequence(frequence>0);
    +0252 end
    +0253 if changedProtPool
    +0254     flexEnz.uniprotIDs(end+1) = {'prot_pool'};
    +0255     flexEnz.oldConcs(end+1)   = oldProtPool;
    +0256     flexEnz.flexConcs(end+1)  = newProtPool;
    +0257     flexEnz.frequence(end+1)  = 1;
    +0258 end
    +0259 % Sort by biggest ratio increase
    +0260 flexEnz.ratioIncr  = flexEnz.flexConcs./flexEnz.oldConcs;
    +0261 [~,b] = sort(flexEnz.ratioIncr,'descend');
    +0262 flexEnz.ratioIncr  = flexEnz.ratioIncr(b);
    +0263 flexEnz.uniprotIDs = flexEnz.uniprotIDs(b);
    +0264 flexEnz.oldConcs   = flexEnz.oldConcs(b);
    +0265 flexEnz.flexConcs  = flexEnz.flexConcs(b);
    +0266 flexEnz.frequence  = flexEnz.frequence(b);
    +0267 end
    +
    Generated by m2html © 2005
    + + \ No newline at end of file diff --git a/doc/src/limit_proteins/getConcControlCoeffs.html b/doc/src/limit_proteins/getConcControlCoeffs.html new file mode 100644 index 00000000..c9ad2e55 --- /dev/null +++ b/doc/src/limit_proteins/getConcControlCoeffs.html @@ -0,0 +1,203 @@ + + + + Description of getConcControlCoeffs + + + + + + + + + +
    Home > src > limit_proteins > getConcControlCoeffs.m
    + + + +

    getConcControlCoeffs +

    + +

    PURPOSE ^

    +
    getConcControlCoeffs Calculate control coefficients of protein usage.
    + +

    SYNOPSIS ^

    +
    function [enz, controlCoeffs] = getConcControlCoeffs(model, varargin)
    + +

    DESCRIPTION ^

    +
     getConcControlCoeffs  Calculate control coefficients of protein usage.
    +
    + For each candidate protein whose usage reaction is running above the
    + given limit fraction of its upper bound, temporarily increases that
    + protein's usage upper bound by foldChange, re-solves, and expresses the
    + resulting growth-rate increase per unit of concentration increase as a
    + control coefficient. Proteins below the limit, or whose increase does
    + not measurably raise growth, get a coefficient of zero.
    +
    + Parameters
    + ----------
    + model : struct
    +     an ecModel in GECKO 3 format (with ecModel.ec structure).
    +
    + Name-Value Arguments
    + --------------------
    + proteins : cell
    +     a list of proteins to calculate the coefficients (default
    +     model.ec.enzymes).
    + foldChange : double
    +     a value how much to increase the protein concentration (default 2).
    + limit : double
    +     threshold on the usage/concentration ratio (how saturated a
    +     protein's usage upper bound already is); only proteins with a ratio
    +     above this value are evaluated for a control coefficient (default
    +     0, i.e. any nonzero usage is evaluated).
    +
    + Returns
    + -------
    + enz : logical
    +     flags which of the input proteins had a usage/concentration ratio
    +     above limit and were evaluated for a control coefficient.
    + controlCoeffs : double
    +     control coefficient per input protein (0 for proteins not evaluated
    +     or whose increase did not measurably raise growth).
    +
    + Examples
    + --------
    +     % optional arguments may be given positionally or as name-value pairs:
    +     [enz, controlCoeffs] = getConcControlCoeffs(model);
    +     [enz, controlCoeffs] = getConcControlCoeffs(model, 'foldChange', 3);
    +
    + See also
    + --------
    + flexibilizeEnzConcs
    + + +

    CROSS-REFERENCE INFORMATION ^

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

    SOURCE CODE ^

    +
    0001 function [enz, controlCoeffs] = getConcControlCoeffs(model, varargin)
    +0002 % getConcControlCoeffs  Calculate control coefficients of protein usage.
    +0003 %
    +0004 % For each candidate protein whose usage reaction is running above the
    +0005 % given limit fraction of its upper bound, temporarily increases that
    +0006 % protein's usage upper bound by foldChange, re-solves, and expresses the
    +0007 % resulting growth-rate increase per unit of concentration increase as a
    +0008 % control coefficient. Proteins below the limit, or whose increase does
    +0009 % not measurably raise growth, get a coefficient of zero.
    +0010 %
    +0011 % Parameters
    +0012 % ----------
    +0013 % model : struct
    +0014 %     an ecModel in GECKO 3 format (with ecModel.ec structure).
    +0015 %
    +0016 % Name-Value Arguments
    +0017 % --------------------
    +0018 % proteins : cell
    +0019 %     a list of proteins to calculate the coefficients (default
    +0020 %     model.ec.enzymes).
    +0021 % foldChange : double
    +0022 %     a value how much to increase the protein concentration (default 2).
    +0023 % limit : double
    +0024 %     threshold on the usage/concentration ratio (how saturated a
    +0025 %     protein's usage upper bound already is); only proteins with a ratio
    +0026 %     above this value are evaluated for a control coefficient (default
    +0027 %     0, i.e. any nonzero usage is evaluated).
    +0028 %
    +0029 % Returns
    +0030 % -------
    +0031 % enz : logical
    +0032 %     flags which of the input proteins had a usage/concentration ratio
    +0033 %     above limit and were evaluated for a control coefficient.
    +0034 % controlCoeffs : double
    +0035 %     control coefficient per input protein (0 for proteins not evaluated
    +0036 %     or whose increase did not measurably raise growth).
    +0037 %
    +0038 % Examples
    +0039 % --------
    +0040 %     % optional arguments may be given positionally or as name-value pairs:
    +0041 %     [enz, controlCoeffs] = getConcControlCoeffs(model);
    +0042 %     [enz, controlCoeffs] = getConcControlCoeffs(model, 'foldChange', 3);
    +0043 %
    +0044 % See also
    +0045 % --------
    +0046 % flexibilizeEnzConcs
    +0047 
    +0048 p = parseGECKOargs(varargin, { ...
    +0049     'proteins',   []; ...
    +0050     'foldChange', []; ...
    +0051     'limit',      []});
    +0052 proteins   = p.proteins;
    +0053 foldChange = p.foldChange;
    +0054 limit      = p.limit;
    +0055 
    +0056 if isempty(limit)
    +0057     limit = 0;
    +0058 end
    +0059 
    +0060 if isempty(foldChange)
    +0061     foldChange = 2;
    +0062 end
    +0063 
    +0064 if isempty(proteins)
    +0065     proteins = model.ec.enzymes;
    +0066 end
    +0067 
    +0068 % for now
    +0069 enz = false(length(proteins),1);
    +0070 controlCoeffs = zeros(length(proteins),1);
    +0071 
    +0072 [sol,hs] = solveLP(model);
    +0073 initialGrowth = sol.f;
    +0074 
    +0075 % Get enzyme index
    +0076 [~, protIdx] = ismember(proteins, model.ec.enzymes);
    +0077 
    +0078 % Get the protein usage reactions
    +0079 protUsageRxns = strcat('usage_prot_', model.ec.enzymes(protIdx));
    +0080 [~, protUsageRxnIdx] = ismember(protUsageRxns, model.rxns);
    +0081 
    +0082 for i = 1:numel(proteins)
    +0083     % Get the previous concentration
    +0084     prevConc = model.ub(protUsageRxnIdx(i));
    +0085 
    +0086     % Only consider those with a usage close the UB
    +0087     if (sol.x(protUsageRxnIdx(i))/prevConc) > limit
    +0088         
    +0089         % Update the logical vector
    +0090         enz(i) = 1;
    +0091 
    +0092         % Create a temporal model since coeff will be calculated one enzyme at
    +0093         % the time, without other change
    +0094         tempModel = model;
    +0095         % Increase the concentration by flexfactor
    +0096         newConc = prevConc*(foldChange);
    +0097         tempModel.ub(protUsageRxnIdx(i)) = newConc;
    +0098 
    +0099         % Get the new growth rate after the adjustment
    +0100         [tempSol,hs] = solveLP(tempModel,0,[],hs);
    +0101         tempGrowth = tempSol.f;
    +0102         
    +0103         % Calculate the coeff only if new growth rate is significantly
    +0104         % higher than initial value
    +0105         if (tempGrowth-initialGrowth)>1e-10
    +0106             controlCoeffs(i) = (tempGrowth-initialGrowth)/(newConc-prevConc);
    +0107         end
    +0108     end
    +0109 
    +0110 end
    +0111 end
    +0112
    +
    Generated by m2html © 2005
    + + \ No newline at end of file diff --git a/doc/src/limit_proteins/index.html b/doc/src/limit_proteins/index.html new file mode 100644 index 00000000..a65f38f0 --- /dev/null +++ b/doc/src/limit_proteins/index.html @@ -0,0 +1,29 @@ + + + + Index for Directory src/limit_proteins + + + + + + + + + + +
    < Master indexIndex for src/limit_proteins >
    + +

    Index for src/limit_proteins

    + +

    Matlab files in this directory:

    + +
     calculateFfactorcalculateFfactor Compute the f factor for an ecModel.
     constrainEnzConcsconstrainEnzConcs Constrain enzyme usages by their concentration.
     constrainFluxDataconstrainFluxData Constrain ecModel fluxes to provided flux data.
     fillEnzConcsfillEnzConcs Populate model.ec.concs from proteome data.
     flexibilizeEnzConcsflexibilizeEnzConcs Flexibilize enzyme concentrations of an ecModel.
     getConcControlCoeffsgetConcControlCoeffs Calculate control coefficients of protein usage.
     relaxProteomicsGreedyrelaxProteomicsGreedy Greedy shadow-price-ordered relaxation of proteomics
     updateProtPoolupdateProtPool Update the protein pool to compensate for proteomics.
    + + + + +
    Generated by m2html © 2005
    + + \ No newline at end of file diff --git a/doc/src/limit_proteins/relaxProteomicsGreedy.html b/doc/src/limit_proteins/relaxProteomicsGreedy.html new file mode 100644 index 00000000..1be069c2 --- /dev/null +++ b/doc/src/limit_proteins/relaxProteomicsGreedy.html @@ -0,0 +1,262 @@ + + + + Description of relaxProteomicsGreedy + + + + + + + + + +
    Home > src > limit_proteins > relaxProteomicsGreedy.m
    + + + +

    relaxProteomicsGreedy +

    + +

    PURPOSE ^

    +
    relaxProteomicsGreedy Greedy shadow-price-ordered relaxation of proteomics
    + +

    SYNOPSIS ^

    +
    function result = relaxProteomicsGreedy(model, varargin)
    + +

    DESCRIPTION ^

    +
     relaxProteomicsGreedy  Greedy shadow-price-ordered relaxation of proteomics
    + constraints.
    +
    + While growth is below minimalGrowth, finds the still-proteomics-constrained
    + enzyme (usage_prot_<id> upper bound below defaultUpperBound) with the
    + largest absolute shadow price on its prot_<id> mass-balance constraint,
    + fully relaxes it back to defaultUpperBound, re-solves, and repeats.
    +
    + Parameters
    + ----------
    + model : struct
    +     a full ecModel in GECKO 3 format, with some usage_prot_<id> reactions
    +     constrained below defaultUpperBound (e.g. by constrainEnzConcs).
    +
    + Name-Value Arguments
    + --------------------
    + minimalGrowth : double
    +     target objective value. Required.
    + enzymeSet : cell
    +     subset of uniprot ids eligible for relaxation (default: every
    +     currently proteomics-constrained enzyme).
    + maxIterations : double
    +     safety cap; errors if exceeded while eligible enzymes still remained
    +     (default 100).
    + defaultUpperBound : double
    +     value to restore on a relaxed usage reaction, matching the shared-pool
    +     default makeEcModel itself sets (default 1000).
    +
    + Returns
    + -------
    + result : struct
    +     - relaxed : struct mapping each relaxed uniprot id to its original
    +       model.ec.concs value, so the caller can restore it later.
    +     - trace : struct array, one row per relaxation step, with fields
    +       iteration (0-based), relaxedUniprot, growthBefore, growthAfter,
    +       shadowPrice.
    +     - finalGrowth : objective value when the loop stopped.
    +     - converged : true iff finalGrowth >= minimalGrowth.
    +
    + Examples
    + --------
    +     result = relaxProteomicsGreedy(ecModel, 'minimalGrowth', 0.1);
    +
    + Notes
    + -----
    + Different relaxation strategy from flexibilizeEnzConcs: this one is
    + shadow-price-ordered (one solve per step) and often converges in fewer
    + iterations when one or two enzymes dominate the infeasibility. The
    + trade-off is that it fully unconstrains each picked enzyme with no
    + tighten-back pass, so the result is looser (less proteomics-faithful).
    +
    + There are two distinct non-convergence outcomes: running out of
    + eligible candidates before reaching minimalGrowth returns normally with
    + converged=false; exhausting maxIterations while candidates still
    + remained raises an error instead.
    +
    + See also
    + --------
    + flexibilizeEnzConcs, getEnzymeBottlenecks
    + + +

    CROSS-REFERENCE INFORMATION ^

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

    SOURCE CODE ^

    +
    0001 function result = relaxProteomicsGreedy(model, varargin)
    +0002 % relaxProteomicsGreedy  Greedy shadow-price-ordered relaxation of proteomics
    +0003 % constraints.
    +0004 %
    +0005 % While growth is below minimalGrowth, finds the still-proteomics-constrained
    +0006 % enzyme (usage_prot_<id> upper bound below defaultUpperBound) with the
    +0007 % largest absolute shadow price on its prot_<id> mass-balance constraint,
    +0008 % fully relaxes it back to defaultUpperBound, re-solves, and repeats.
    +0009 %
    +0010 % Parameters
    +0011 % ----------
    +0012 % model : struct
    +0013 %     a full ecModel in GECKO 3 format, with some usage_prot_<id> reactions
    +0014 %     constrained below defaultUpperBound (e.g. by constrainEnzConcs).
    +0015 %
    +0016 % Name-Value Arguments
    +0017 % --------------------
    +0018 % minimalGrowth : double
    +0019 %     target objective value. Required.
    +0020 % enzymeSet : cell
    +0021 %     subset of uniprot ids eligible for relaxation (default: every
    +0022 %     currently proteomics-constrained enzyme).
    +0023 % maxIterations : double
    +0024 %     safety cap; errors if exceeded while eligible enzymes still remained
    +0025 %     (default 100).
    +0026 % defaultUpperBound : double
    +0027 %     value to restore on a relaxed usage reaction, matching the shared-pool
    +0028 %     default makeEcModel itself sets (default 1000).
    +0029 %
    +0030 % Returns
    +0031 % -------
    +0032 % result : struct
    +0033 %     - relaxed : struct mapping each relaxed uniprot id to its original
    +0034 %       model.ec.concs value, so the caller can restore it later.
    +0035 %     - trace : struct array, one row per relaxation step, with fields
    +0036 %       iteration (0-based), relaxedUniprot, growthBefore, growthAfter,
    +0037 %       shadowPrice.
    +0038 %     - finalGrowth : objective value when the loop stopped.
    +0039 %     - converged : true iff finalGrowth >= minimalGrowth.
    +0040 %
    +0041 % Examples
    +0042 % --------
    +0043 %     result = relaxProteomicsGreedy(ecModel, 'minimalGrowth', 0.1);
    +0044 %
    +0045 % Notes
    +0046 % -----
    +0047 % Different relaxation strategy from flexibilizeEnzConcs: this one is
    +0048 % shadow-price-ordered (one solve per step) and often converges in fewer
    +0049 % iterations when one or two enzymes dominate the infeasibility. The
    +0050 % trade-off is that it fully unconstrains each picked enzyme with no
    +0051 % tighten-back pass, so the result is looser (less proteomics-faithful).
    +0052 %
    +0053 % There are two distinct non-convergence outcomes: running out of
    +0054 % eligible candidates before reaching minimalGrowth returns normally with
    +0055 % converged=false; exhausting maxIterations while candidates still
    +0056 % remained raises an error instead.
    +0057 %
    +0058 % See also
    +0059 % --------
    +0060 % flexibilizeEnzConcs, getEnzymeBottlenecks
    +0061 
    +0062 p = parseGECKOargs(varargin, {'minimalGrowth', []; 'enzymeSet', []; ...
    +0063     'maxIterations', []; 'defaultUpperBound', []});
    +0064 minimalGrowth     = p.minimalGrowth;
    +0065 enzymeSet         = p.enzymeSet;
    +0066 maxIterations     = p.maxIterations;
    +0067 defaultUpperBound = p.defaultUpperBound;
    +0068 if isempty(minimalGrowth)
    +0069     error('relaxProteomicsGreedy: minimalGrowth is required.')
    +0070 end
    +0071 if isempty(maxIterations)
    +0072     maxIterations = 100;
    +0073 end
    +0074 if isempty(defaultUpperBound)
    +0075     defaultUpperBound = 1000;
    +0076 end
    +0077 
    +0078 if isfield(model.ec, 'geckoLight') && model.ec.geckoLight
    +0079     error(['relaxProteomicsGreedy requires a full ecModel, not gecko-light: light models have no ' ...
    +0080         'per-enzyme prot_<id> / usage_prot_<id> machinery.'])
    +0081 end
    +0082 
    +0083 usageRxns = strcat('usage_prot_', model.ec.enzymes);
    +0084 [found, usageIdx] = ismember(usageRxns, model.rxns);
    +0085 if ~all(found)
    +0086     error('Usage reactions are not defined for all enzymes. This is done by makeEcModel.')
    +0087 end
    +0088 protMets = strcat('prot_', model.ec.enzymes);
    +0089 [found, protMetIdx] = ismember(protMets, model.mets);
    +0090 if ~all(found)
    +0091     error('Cannot find prot_<id> metabolites for all enzymes. This is done by makeEcModel.')
    +0092 end
    +0093 
    +0094 if isempty(enzymeSet)
    +0095     pool = model.ec.enzymes;
    +0096 else
    +0097     pool = intersect(enzymeSet(:), model.ec.enzymes, 'stable');
    +0098 end
    +0099 [~, poolIdx] = ismember(pool, model.ec.enzymes);
    +0100 poolIdx = poolIdx(poolIdx > 0);
    +0101 candidates = poolIdx(model.ub(usageIdx(poolIdx)) < defaultUpperBound);
    +0102 
    +0103 relaxed = struct();
    +0104 trace = struct('iteration', {}, 'relaxedUniprot', {}, 'growthBefore', {}, ...
    +0105     'growthAfter', {}, 'shadowPrice', {});
    +0106 
    +0107 sol = solveLP(model);
    +0108 if sol.stat == 1
    +0109     growth = sol.f;
    +0110 else
    +0111     growth = -inf;
    +0112 end
    +0113 
    +0114 for it = 0:(maxIterations - 1)
    +0115     if growth >= minimalGrowth
    +0116         result.relaxed = relaxed;
    +0117         result.trace = trace;
    +0118         result.finalGrowth = growth;
    +0119         result.converged = true;
    +0120         return
    +0121     end
    +0122     if isempty(candidates)
    +0123         warning('relaxProteomicsGreedy: no more candidates to relax; stopping.')
    +0124         result.relaxed = relaxed;
    +0125         result.trace = trace;
    +0126         result.finalGrowth = growth;
    +0127         result.converged = false;
    +0128         return
    +0129     end
    +0130 
    +0131     shadowPrices = abs(sol.sPrice(protMetIdx(candidates)));
    +0132     [~, bestPos] = max(shadowPrices);
    +0133     targetIdx = candidates(bestPos);
    +0134     targetUniprot = model.ec.enzymes{targetIdx};
    +0135     sp = sol.sPrice(protMetIdx(targetIdx));
    +0136 
    +0137     relaxed.(matlab.lang.makeValidName(targetUniprot)) = model.ec.concs(targetIdx);
    +0138     model.ub(usageIdx(targetIdx)) = defaultUpperBound;
    +0139     candidates(candidates == targetIdx) = [];
    +0140 
    +0141     newSol = solveLP(model);
    +0142     if newSol.stat == 1
    +0143         newGrowth = newSol.f;
    +0144     else
    +0145         newGrowth = -inf;
    +0146     end
    +0147 
    +0148     trace(end+1) = struct('iteration', it, 'relaxedUniprot', targetUniprot, ...
    +0149         'growthBefore', growth, 'growthAfter', newGrowth, 'shadowPrice', sp); %#ok<AGROW>
    +0150 
    +0151     growth = newGrowth;
    +0152     sol = newSol;
    +0153 end
    +0154 
    +0155 error('relaxProteomicsGreedy: did not converge in %d iterations (final growth %.4g < target %.4g).', ...
    +0156     maxIterations, growth, minimalGrowth)
    +0157 end
    +
    Generated by m2html © 2005
    + + \ No newline at end of file diff --git a/doc/src/limit_proteins/updateProtPool.html b/doc/src/limit_proteins/updateProtPool.html new file mode 100644 index 00000000..1bf0e4a1 --- /dev/null +++ b/doc/src/limit_proteins/updateProtPool.html @@ -0,0 +1,195 @@ + + + + Description of updateProtPool + + + + + + + + + +
    Home > src > limit_proteins > updateProtPool.m
    + + + +

    updateProtPool +

    + +

    PURPOSE ^

    +
    updateProtPool Update the protein pool to compensate for proteomics.
    + +

    SYNOPSIS ^

    +
    function ecModel = updateProtPool(ecModel, varargin)
    + +

    DESCRIPTION ^

    +
     updateProtPool  Update the protein pool to compensate for proteomics.
    +
    + Only applicable to ecModels where unmeasured enzymes draw from the
    + protein pool while measured enzymes (constrained via model.ec.concs) do
    + not: shrinks the protein pool exchange upper bound so it represents only
    + the remaining, unmeasured protein content (total protein content Ptot
    + minus the measured protein mass). For ecModels generated with GECKO
    + 3.2.0 or later, where all enzymes draw from the protein pool regardless
    + of whether they are measured, this function raises an error instead;
    + use setProtPoolSize (see
    + https://github.com/SysBioChalmers/GECKO/issues/375).
    +
    + Parameters
    + ----------
    + ecModel : struct
    +     an ecModel in GECKO 3 format (with ecModel.ec structure).
    +
    + Name-Value Arguments
    + --------------------
    + Ptot : double
    +     total protein content in g/gDCW, overwrites the value from
    +     modelAdapter. For instance, condition-specific fluxData.Ptot from
    +     loadFluxData can be used. If nothing is provided, the modelAdapter
    +     value is used.
    + modelAdapter : ModelAdapter
    +     a loaded model adapter (default: the current default model adapter).
    +
    + Returns
    + -------
    + ecModel : struct
    +     an ecModel where the protein pool exchange reaction's upper bound
    +     has been reduced to reflect only the unmeasured protein content.
    +
    + Examples
    + --------
    +     % optional arguments may be given positionally or as name-value pairs:
    +     ecModel = updateProtPool(ecModel);
    +     ecModel = updateProtPool(ecModel, 'Ptot', 0.5);
    +
    + See also
    + --------
    + setProtPoolSize, loadFluxData
    + + +

    CROSS-REFERENCE INFORMATION ^

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

    SOURCE CODE ^

    +
    0001 function ecModel  = updateProtPool(ecModel, varargin)
    +0002 % updateProtPool  Update the protein pool to compensate for proteomics.
    +0003 %
    +0004 % Only applicable to ecModels where unmeasured enzymes draw from the
    +0005 % protein pool while measured enzymes (constrained via model.ec.concs) do
    +0006 % not: shrinks the protein pool exchange upper bound so it represents only
    +0007 % the remaining, unmeasured protein content (total protein content Ptot
    +0008 % minus the measured protein mass). For ecModels generated with GECKO
    +0009 % 3.2.0 or later, where all enzymes draw from the protein pool regardless
    +0010 % of whether they are measured, this function raises an error instead;
    +0011 % use setProtPoolSize (see
    +0012 % https://github.com/SysBioChalmers/GECKO/issues/375).
    +0013 %
    +0014 % Parameters
    +0015 % ----------
    +0016 % ecModel : struct
    +0017 %     an ecModel in GECKO 3 format (with ecModel.ec structure).
    +0018 %
    +0019 % Name-Value Arguments
    +0020 % --------------------
    +0021 % Ptot : double
    +0022 %     total protein content in g/gDCW, overwrites the value from
    +0023 %     modelAdapter. For instance, condition-specific fluxData.Ptot from
    +0024 %     loadFluxData can be used. If nothing is provided, the modelAdapter
    +0025 %     value is used.
    +0026 % modelAdapter : ModelAdapter
    +0027 %     a loaded model adapter (default: the current default model adapter).
    +0028 %
    +0029 % Returns
    +0030 % -------
    +0031 % ecModel : struct
    +0032 %     an ecModel where the protein pool exchange reaction's upper bound
    +0033 %     has been reduced to reflect only the unmeasured protein content.
    +0034 %
    +0035 % Examples
    +0036 % --------
    +0037 %     % optional arguments may be given positionally or as name-value pairs:
    +0038 %     ecModel = updateProtPool(ecModel);
    +0039 %     ecModel = updateProtPool(ecModel, 'Ptot', 0.5);
    +0040 %
    +0041 % See also
    +0042 % --------
    +0043 % setProtPoolSize, loadFluxData
    +0044 
    +0045 p = parseGECKOargs(varargin, { ...
    +0046     'Ptot',         []; ...
    +0047     'modelAdapter', []});
    +0048 Ptot         = p.Ptot;
    +0049 modelAdapter = p.modelAdapter;
    +0050 
    +0051 % Do not run from GECKO version 3.2.0 onwards. This can be recognized by
    +0052 % prot_usage reactions that are constrained by proteomics and still draw
    +0053 % from the protein pool
    +0054 protRxns = find(startsWith(ecModel.rxns,'usage_prot_'));
    +0055 poolMetIdx = find(strcmp(ecModel.mets,'prot_pool'));
    +0056 % Selected proteins with proteomics constraints
    +0057 constProtRxns = ~(ecModel.ub(protRxns)==1000);
    +0058 % Are any still drawing from prot_pool? This is introduced in GECKO 3.2.0.
    +0059 if any(full(ecModel.S(poolMetIdx,protRxns(constProtRxns))))
    +0060     error(['In the provided ecModel, all protein usage reactions, both with ' ...
    +0061         'and without concentration constraints, draw from the protein pool. ' ...
    +0062         'This was introduced with GECKO 3.2.0. Since then, updateProtPool ' ...
    +0063         'has become obsolete, use setProtPoolSize instead to constrain the ' ...
    +0064         'total protein pool with  condition-specific total protein content. See '...
    +0065         '<a href="https://github.com/SysBioChalmers/GECKO/issues/375">here</a> ' ...
    +0066         'for more explanation.'])
    +0067 end
    +0068 
    +0069 if isempty(modelAdapter)
    +0070     modelAdapter = ModelAdapterManager.getDefault();
    +0071     if isempty(modelAdapter)
    +0072         error('Either send in a modelAdapter or set the default model adapter in the ModelAdapterManager.')
    +0073     end
    +0074 end
    +0075 params = modelAdapter.params;
    +0076 
    +0077 if isempty(Ptot)
    +0078     Ptot = params.Ptot;
    +0079     disp(['Total protein content used: ' num2str(Ptot) ' [g protein/gDw]'])
    +0080 end
    +0081 
    +0082 % Convert Ptot to mg/gDW if provided in g/gDCW (which is default)
    +0083 if Ptot < 1
    +0084     Ptot = Ptot * 1000;
    +0085 end
    +0086 
    +0087 Pmeas = sum(ecModel.ec.concs,'omitnan');
    +0088 if Pmeas == 0
    +0089     error('The model has not yet been populated with proteomics, as ecModel.ec.concs is empty.')
    +0090 end
    +0091 
    +0092 Pnew = (Ptot - Pmeas) * params.f;
    +0093 
    +0094 if Pnew > 0
    +0095     PoolRxnIdx = strcmp(ecModel.rxns,'prot_pool_exchange');
    +0096     ecModel.ub(PoolRxnIdx) = Pnew*params.sigma;
    +0097     sol = solveLP(ecModel);
    +0098     if isempty(sol.x)
    +0099         error(['Estimating the remaining protein pool by subtracting the ' ...
    +0100                'sum of measured enzyme concentrations (in ecModel.ec.concs) ' ...
    +0101                'from the total protein pool (Ptot) does not yield a functional ' ...
    +0102                'model.'])
    +0103     end
    +0104 else
    +0105     error('The total measured protein mass exceeds the total protein content.')
    +0106 end
    +0107 end
    +
    Generated by m2html © 2005
    + + \ No newline at end of file diff --git a/doc/src/model_adapter/ModelAdapter.html b/doc/src/model_adapter/ModelAdapter.html new file mode 100644 index 00000000..afb2103b --- /dev/null +++ b/doc/src/model_adapter/ModelAdapter.html @@ -0,0 +1,178 @@ + + + + Description of ModelAdapter + + + + + + + + + +
    Home > src > model_adapter > ModelAdapter.m
    + + + +

    ModelAdapter +

    + +

    PURPOSE ^

    +
    ModelAdapter Abstract base class for species-specific model adapters.
    + +

    SYNOPSIS ^

    +
    This is a script file.
    + +

    DESCRIPTION ^

    +
     ModelAdapter  Abstract base class for species-specific model adapters.
    +
    + Defines the interface that every species adapter must implement and
    + provides shared default behaviour for retrieving GECKO parameters,
    + mapping model genes to UniProt, and locating reference databases.
    + Concrete subclasses override these methods for a particular organism.
    +
    + Notes
    + -----
    + - params : struct of model-specific GECKO parameters (public property).
    + - getSpontaneousReactions : abstract method that subclasses must define.
    +
    + See also
    + --------
    + ModelAdapterManager
    + + +

    CROSS-REFERENCE INFORMATION ^

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

    SUBFUNCTIONS ^

    + + +

    SOURCE CODE ^

    +
    0001 % ModelAdapter  Abstract base class for species-specific model adapters.
    +0002 %
    +0003 % Defines the interface that every species adapter must implement and
    +0004 % provides shared default behaviour for retrieving GECKO parameters,
    +0005 % mapping model genes to UniProt, and locating reference databases.
    +0006 % Concrete subclasses override these methods for a particular organism.
    +0007 %
    +0008 % Notes
    +0009 % -----
    +0010 % - params : struct of model-specific GECKO parameters (public property).
    +0011 % - getSpontaneousReactions : abstract method that subclasses must define.
    +0012 %
    +0013 % See also
    +0014 % --------
    +0015 % ModelAdapterManager
    +0016 classdef (Abstract) ModelAdapter
    +0017     methods (Abstract)
    +0018         [spont,spontRxnNames] = getSpontaneousReactions(obj,model);
    +0019     end
    +0020     methods
    +0021         %not really needed, we could access it directly. Not very nice, but practical
    +0022         function parameters = getParameters(obj)
    +0023             parameters = obj.params;
    +0024         end
    +0025 
    +0026         %This allows for changing parameters in an adapter without
    +0027         %creating a new class. May be convenient, although less clean
    +0028         %function obj = setParameters(obj, parameters)
    +0029         %    obj.mParams = parameters;
    +0030         %end
    +0031 
    +0032         %The genes returned here should match the gene id set in the parameter params.uniprot.geneIDfield
    +0033         function genes = getUniprotCompatibleGenes(obj,inGenes)
    +0034             genes = inGenes;
    +0035         end
    +0036 
    +0037         %The genes returned here should match the gene id stored in column
    +0038         %2 (databases.kegg.genes) of kegg.tsv. Override when the model
    +0039         %uses identifiers that need transformation before KEGG lookup.
    +0040         function genes = getKeggCompatibleGenes(obj,inGenes)
    +0041             genes = inGenes;
    +0042         end
    +0043 
    +0044         function uniprotIDs = getUniprotIDsFromTable(obj,modelGenes)
    +0045             conversionTable = fullfile(obj.params.path,'data','uniprotConversion.tsv');
    +0046             if exist(conversionTable,'file')
    +0047                 fID=fopen(conversionTable,'r');
    +0048                 conversionTable = textscan(fID,'%q %q','Delimiter','\t','HeaderLines',1);
    +0049                 fclose(fID);
    +0050 
    +0051                 modelIDs    = conversionTable{1,1};
    +0052                 uniprots    = conversionTable{1,2};
    +0053 
    +0054                 [a,b] = ismember(modelGenes,modelIDs);
    +0055 
    +0056                 uniprotIDs  = strings(numel(modelGenes),1);
    +0057                 uniprotIDs(a)  = uniprots(b(a));
    +0058                 disp('The model genes are matched to Uniprot via the table at data/uniprotConversion.tsv.')
    +0059             else
    +0060                 uniprotIDs = modelGenes;
    +0061             end
    +0062         end
    +0063 
    +0064         function folder = getBrendaDBFolder(obj)
    +0065             % The project's data/brenda (geckopy brenda-refresh writes
    +0066             % there) when it exists, otherwise GECKO's BRENDA release,
    +0067             % downloaded once (fetchBrendaAsset).
    +0068             folder = fullfile(obj.params.path,'data','brenda');
    +0069             if ~isfolder(folder)
    +0070                 folder = fetchBrendaAsset();
    +0071             end
    +0072         end
    +0073 
    +0074         function x = getPhylDistStructPath(obj)
    +0075             % RAVEN 3 keeps keggPhylDist.mat under src/reconstruction/kegg
    +0076             % (earlier versions of RAVEN 3 under reconstruction/kegg), RAVEN
    +0077             % 2 under external/kegg.
    +0078             ravenRoot = findRAVENroot();
    +0079             candidates = {fullfile(ravenRoot,'src','reconstruction','kegg','keggPhylDist.mat'), ...
    +0080                 fullfile(ravenRoot,'reconstruction','kegg','keggPhylDist.mat'), ...
    +0081                 fullfile(ravenRoot,'external','kegg','keggPhylDist.mat')};
    +0082             x = candidates{end};
    +0083             for i = 1:numel(candidates)
    +0084                 if isfile(candidates{i})
    +0085                     x = candidates{i};
    +0086                     break
    +0087                 end
    +0088             end
    +0089         end
    +0090 
    +0091         % Define a model-specific function in the 'code' subfolder of the
    +0092         % project folder, that can constrain the model to anaerobic
    +0093         % conditions, and refer to this function in the modelAdapter. This
    +0094         % function is used when running cmaesKcatTuning.m (via
    +0095         % evotuneScore.m) if the fluxData has anaerobic conditions.
    +0096         function ecModel = makeModelAnaerobic(obj,ecModel)
    +0097             ecModel = ecModel;
    +0098             % Example from full_tutorial:
    +0099             % ecModel = anaerobicModel_GECKO(ecModel);
    +0100         end
    +0101         % Similarly, define a function that can change protein content in
    +0102         % the biomass composition
    +0103         function ecModel = changeProteinBiomass(obj,ecModel,Ptot)
    +0104             ecModel = ecModel;
    +0105             % Example from full_tutorial:
    +0106             % ecModel = scaleBioMass(ecModel,'protein',Ptot,'carbohydrate',false);
    +0107         end
    +0108     end
    +0109 
    +0110     %To have the params public is a bit "ugly", but very practical
    +0111     %if we want to change a parameter
    +0112     properties (Access = public)
    +0113         params;
    +0114     end
    +0115 end
    +
    Generated by m2html © 2005
    + + \ No newline at end of file diff --git a/doc/src/model_adapter/ModelAdapterManager.html b/doc/src/model_adapter/ModelAdapterManager.html new file mode 100644 index 00000000..0697b5e4 --- /dev/null +++ b/doc/src/model_adapter/ModelAdapterManager.html @@ -0,0 +1,169 @@ + + + + Description of ModelAdapterManager + + + + + + + + + +
    Home > src > model_adapter > ModelAdapterManager.m
    + + + +

    ModelAdapterManager +

    + +

    PURPOSE ^

    +
    ModelAdapterManager Resolve and cache the active ModelAdapter.
    + +

    SYNOPSIS ^

    +
    This is a script file.
    + +

    DESCRIPTION ^

    +
     ModelAdapterManager  Resolve and cache the active ModelAdapter.
    +
    + Static helper class that loads a model adapter from a file path and
    + stores a process-wide default adapter, so that GECKO functions can
    + retrieve the active adapter without it being passed explicitly.
    +
    + An adapter is loaded from model_adapter.toml (give the file or the
    + project folder; see TomlAdapter) or from an adapter class (give its .m
    + file).
    +
    + Notes
    + -----
    + All methods are static. The default adapter is held in a persistent
    + variable and shared across the whole GECKO session.
    +
    + See also
    + --------
    + ModelAdapter
    + + +

    CROSS-REFERENCE INFORMATION ^

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

    SUBFUNCTIONS ^

    + + +

    SOURCE CODE ^

    +
    0001 % ModelAdapterManager  Resolve and cache the active ModelAdapter.
    +0002 %
    +0003 % Static helper class that loads a model adapter from a file path and
    +0004 % stores a process-wide default adapter, so that GECKO functions can
    +0005 % retrieve the active adapter without it being passed explicitly.
    +0006 %
    +0007 % An adapter is loaded from model_adapter.toml (give the file or the
    +0008 % project folder; see TomlAdapter) or from an adapter class (give its .m
    +0009 % file).
    +0010 %
    +0011 % Notes
    +0012 % -----
    +0013 % All methods are static. The default adapter is held in a persistent
    +0014 % variable and shared across the whole GECKO session.
    +0015 %
    +0016 % See also
    +0017 % --------
    +0018 % ModelAdapter
    +0019 classdef ModelAdapterManager 
    +0020     methods(Static)
    +0021         function adapter = getAdapter(adapterPath, addToMatlabPath)
    +0022             if nargin < 2
    +0023                 addToMatlabPath = true;
    +0024             end
    +0025             ModelAdapterManager.showGECKO4Notice();
    +0026 
    +0027             adapterPath = char(adapterPath);
    +0028             if isfolder(adapterPath)
    +0029                 tomlFile = fullfile(adapterPath, 'model_adapter.toml');
    +0030                 if ~isfile(tomlFile)
    +0031                     error('No model_adapter.toml found in %s.', adapterPath);
    +0032                 end
    +0033                 adapter = TomlAdapter(tomlFile);
    +0034                 return
    +0035             end
    +0036             [adapterFolder, adapterClassName, extension] = fileparts(adapterPath);
    +0037             if strcmp(extension, '.toml')
    +0038                 adapter = TomlAdapter(adapterPath);
    +0039                 return
    +0040             elseif ~strcmp(extension, '.m')
    +0041                 error(['Please provide the project folder, its model_adapter.toml, or the ' ...
    +0042                     'full path to the adapter class file, including the .m extension.']);
    +0043             else
    +0044                 s = pathsep;
    +0045                 pathStr = [s, path, s];
    +0046                 onPath = contains(pathStr, [s, adapterFolder, s], 'IgnoreCase', ispc);
    +0047                 % Check if the folder is on the path
    +0048                 if ~onPath
    +0049                     if addToMatlabPath
    +0050                         addpath(adapterFolder);
    +0051                     else
    +0052                         printOrange(['WARNING: The adapter will not be on the MATLAB path, since addToMatlabPath is false\n' ...
    +0053                                      'and it is not currently on the path. Either set addToMatlabPath to true, fix this\n'...
    +0054                                      'manually before calling this function or make sure it is in current directory (not\n'...
    +0055                                      'recommended). If the class is not reachable throughout the entire GECKO use there will\n'...
    +0056                                      'be errors throughout.\n']);
    +0057                     end
    +0058                 end
    +0059 
    +0060             end
    +0061             adapter = feval(adapterClassName);
    +0062         end
    +0063         
    +0064         function out = getDefault()
    +0065             out = ModelAdapterManager.setGetDefault();
    +0066         end
    +0067         
    +0068         function adapter = setDefault(adapterPath, addToMatlabPath)
    +0069             if nargin < 1 || isempty(adapterPath)
    +0070                 adapter = ModelAdapterManager.setGetDefault(adapterPath);
    +0071                 return
    +0072             end
    +0073             if nargin < 2
    +0074                 addToMatlabPath = true;
    +0075             end
    +0076             adapter = ModelAdapterManager.setGetDefault(ModelAdapterManager.getAdapter(adapterPath, addToMatlabPath));
    +0077         end
    +0078         
    +0079     end
    +0080     methods(Static,Access = private)
    +0081         % This is how they recommend defining static variables in Matlab
    +0082         function out = setGetDefault(val)
    +0083             persistent defaultAdapter; %will be empty initially
    +0084             if nargin
    +0085                 defaultAdapter = val;
    +0086             end
    +0087             out = defaultAdapter;
    +0088         end
    +0089 
    +0090         function showGECKO4Notice()
    +0091             % Remove this method (and its call in getAdapter) in a future
    +0092             % GECKO 4.x release, once users have had time to notice the
    +0093             % backward-incompatible changes from GECKO 3.
    +0094             persistent shown;
    +0095             if isempty(shown)
    +0096                 printOrange(['NOTE: This is GECKO 4, which is not fully backward-compatible\n' ...
    +0097                     'with GECKO 3. See https://gecko-docs.readthedocs.io/en/latest/gecko3-to-gecko4.html\n' ...
    +0098                     'for what changed and how to stay on GECKO 3 (v3.2.5) if needed.\n']);
    +0099                 shown = true;
    +0100             end
    +0101         end
    +0102     end
    +0103 end
    +
    Generated by m2html © 2005
    + + \ No newline at end of file diff --git a/doc/src/model_adapter/TomlAdapter.html b/doc/src/model_adapter/TomlAdapter.html new file mode 100644 index 00000000..7950999f --- /dev/null +++ b/doc/src/model_adapter/TomlAdapter.html @@ -0,0 +1,191 @@ + + + + Description of TomlAdapter + + + + + + + + + +
    Home > src > model_adapter > TomlAdapter.m
    + + + +

    TomlAdapter +

    + +

    PURPOSE ^

    +
    TomlAdapter Model adapter configured by model_adapter.toml.
    + +

    SYNOPSIS ^

    +
    This is a script file.
    + +

    DESCRIPTION ^

    +
     TomlAdapter  Model adapter configured by model_adapter.toml.
    +
    + The model adapter for a project whose parameters are in
    + model_adapter.toml, the configuration file that GECKO and geckopy share.
    + No adapter class has to be written: what used to be code in an adapter
    + class is set in the TOML file.
    +
    + - Spontaneous reactions: [spontaneous] name_contains (reactions whose
    +   name contains the text) and/or file (a TSV of reaction identifiers,
    +   optionally with a second 0/1 column).
    + - Anaerobic conditions and protein content during kcat tuning:
    +   [matlab] make_model_anaerobic and change_protein_biomass name MATLAB
    +   functions, for instance in the project's code folder, which is added
    +   to the MATLAB path. Each takes the ecModel (and, for
    +   change_protein_biomass, the protein content) and returns the ecModel.
    +
    + A project that needs other custom code can keep an adapter class and
    + read its parameters from the TOML file in its constructor:
    +
    +     obj.params = loadAdapterParams(fullfile(projectPath,'model_adapter.toml'));
    +
    + Examples
    + --------
    +     adapter = TomlAdapter(fullfile(projectPath,'model_adapter.toml'));
    +     % or, as the default adapter:
    +     ModelAdapterManager.setDefault(projectPath);
    +
    + See also
    + --------
    + ModelAdapter, ModelAdapterManager, loadAdapterParams, convertAdapterToToml
    + + +

    CROSS-REFERENCE INFORMATION ^

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

    SUBFUNCTIONS ^

    + + +

    SOURCE CODE ^

    +
    0001 % TomlAdapter  Model adapter configured by model_adapter.toml.
    +0002 %
    +0003 % The model adapter for a project whose parameters are in
    +0004 % model_adapter.toml, the configuration file that GECKO and geckopy share.
    +0005 % No adapter class has to be written: what used to be code in an adapter
    +0006 % class is set in the TOML file.
    +0007 %
    +0008 % - Spontaneous reactions: [spontaneous] name_contains (reactions whose
    +0009 %   name contains the text) and/or file (a TSV of reaction identifiers,
    +0010 %   optionally with a second 0/1 column).
    +0011 % - Anaerobic conditions and protein content during kcat tuning:
    +0012 %   [matlab] make_model_anaerobic and change_protein_biomass name MATLAB
    +0013 %   functions, for instance in the project's code folder, which is added
    +0014 %   to the MATLAB path. Each takes the ecModel (and, for
    +0015 %   change_protein_biomass, the protein content) and returns the ecModel.
    +0016 %
    +0017 % A project that needs other custom code can keep an adapter class and
    +0018 % read its parameters from the TOML file in its constructor:
    +0019 %
    +0020 %     obj.params = loadAdapterParams(fullfile(projectPath,'model_adapter.toml'));
    +0021 %
    +0022 % Examples
    +0023 % --------
    +0024 %     adapter = TomlAdapter(fullfile(projectPath,'model_adapter.toml'));
    +0025 %     % or, as the default adapter:
    +0026 %     ModelAdapterManager.setDefault(projectPath);
    +0027 %
    +0028 % See also
    +0029 % --------
    +0030 % ModelAdapter, ModelAdapterManager, loadAdapterParams, convertAdapterToToml
    +0031 classdef TomlAdapter < ModelAdapter
    +0032     methods
    +0033         function obj = TomlAdapter(tomlFile)
    +0034             % TomlAdapter  Load the adapter from model_adapter.toml.
    +0035             %
    +0036             % Parameters
    +0037             % ----------
    +0038             % tomlFile : char
    +0039             %     path to model_adapter.toml, or to the project folder that
    +0040             %     holds it.
    +0041             obj.params = loadAdapterParams(tomlFile);
    +0042             codeFolder = fullfile(obj.params.path, 'code');
    +0043             if isfolder(codeFolder)
    +0044                 addpath(codeFolder);
    +0045             end
    +0046         end
    +0047 
    +0048         function [spont,spontRxnNames] = getSpontaneousReactions(obj,model)
    +0049             % getSpontaneousReactions  Reactions set as spontaneous in [spontaneous].
    +0050             %
    +0051             % Returns
    +0052             % -------
    +0053             % spont : logical
    +0054             %     true for each reaction of model that is spontaneous.
    +0055             % spontRxnNames : cell
    +0056             %     identifiers of those reactions.
    +0057             spont = false(numel(model.rxns),1);
    +0058             if isfield(obj.params,'spontaneous')
    +0059                 s = obj.params.spontaneous;
    +0060                 if isfield(s,'name_contains') && ~isempty(s.name_contains)
    +0061                     spont = spont | contains(model.rxnNames, s.name_contains);
    +0062                 end
    +0063                 if isfield(s,'file') && ~isempty(s.file)
    +0064                     spont = spont | ismember(model.rxns, readSpontaneousFile(s.file));
    +0065                 end
    +0066             end
    +0067             spontRxnNames = model.rxns(spont);
    +0068         end
    +0069 
    +0070         function ecModel = makeModelAnaerobic(obj,ecModel)
    +0071             % makeModelAnaerobic  Run the function named in [matlab] make_model_anaerobic.
    +0072             fun = hookName(obj, 'makeModelAnaerobic');
    +0073             if ~isempty(fun)
    +0074                 ecModel = feval(fun, ecModel);
    +0075             end
    +0076         end
    +0077 
    +0078         function ecModel = changeProteinBiomass(obj,ecModel,Ptot)
    +0079             % changeProteinBiomass  Run the function named in [matlab] change_protein_biomass.
    +0080             fun = hookName(obj, 'changeProteinBiomass');
    +0081             if ~isempty(fun)
    +0082                 ecModel = feval(fun, ecModel, Ptot);
    +0083             end
    +0084         end
    +0085     end
    +0086 end
    +0087 
    +0088 function fun = hookName(obj, field)
    +0089 fun = '';
    +0090 if isfield(obj.params,'matlab') && isfield(obj.params.matlab, field)
    +0091     fun = obj.params.matlab.(field);
    +0092 end
    +0093 end
    +0094 
    +0095 function rxns = readSpontaneousFile(file)
    +0096 % Reaction identifiers in the first column; with a second column, only
    +0097 % rows where it is 1 or true. The first row is a header.
    +0098 fid = fopen(file, 'r');
    +0099 if fid < 0
    +0100     error('GECKO:TomlAdapter', 'Cannot read the spontaneous reactions file %s', file);
    +0101 end
    +0102 header = fgetl(fid);
    +0103 nCols = numel(strsplit(header, '\t'));
    +0104 if nCols >= 2
    +0105     cols = textscan(fid, ['%q %q' repmat(' %*q', 1, nCols-2)], 'Delimiter', '\t');
    +0106     keep = ismember(lower(strtrim(cols{2})), {'1','true'});
    +0107     rxns = cols{1}(keep);
    +0108 else
    +0109     cols = textscan(fid, '%q', 'Delimiter', '\t');
    +0110     rxns = cols{1};
    +0111 end
    +0112 fclose(fid);
    +0113 end
    +
    Generated by m2html © 2005
    + + \ No newline at end of file diff --git a/doc/src/model_adapter/adapterTemplate.html b/doc/src/model_adapter/adapterTemplate.html new file mode 100644 index 00000000..a80cae29 --- /dev/null +++ b/doc/src/model_adapter/adapterTemplate.html @@ -0,0 +1,210 @@ + + + + Description of adapterTemplate + + + + + + + + + +
    Home > src > model_adapter > adapterTemplate.m
    + + + +

    adapterTemplate +

    + +

    PURPOSE ^

    +
    KEY_CLASSNAME Template ModelAdapter to copy and adapt per organism.
    + +

    SYNOPSIS ^

    +
    This is a script file.
    + +

    DESCRIPTION ^

    +
     KEY_CLASSNAME  Template ModelAdapter to copy and adapt per organism.
    +
    + Starting point for a species-specific adapter. Copy this file, rename
    + the class, and edit the parameter values set in the constructor and the
    + getSpontaneousReactions method to match the target organism and model.
    +
    + See also
    + --------
    + ModelAdapter, ModelAdapterManager
    + + +

    CROSS-REFERENCE INFORMATION ^

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

    SUBFUNCTIONS ^

    + + +

    SOURCE CODE ^

    +
    0001 % KEY_CLASSNAME  Template ModelAdapter to copy and adapt per organism.
    +0002 %
    +0003 % Starting point for a species-specific adapter. Copy this file, rename
    +0004 % the class, and edit the parameter values set in the constructor and the
    +0005 % getSpontaneousReactions method to match the target organism and model.
    +0006 %
    +0007 % See also
    +0008 % --------
    +0009 % ModelAdapter, ModelAdapterManager
    +0010 classdef KEY_CLASSNAME < ModelAdapter
    +0011     methods
    +0012         function obj = KEY_CLASSNAME()
    +0013             % KEY_CLASSNAME  Construct the adapter and set default parameters.
    +0014             %
    +0015             % Sets initial values of obj.params; they can be changed by
    +0016             % the user after construction.
    +0017             %
    +0018             % Returns
    +0019             % -------
    +0020             % obj : ModelAdapter
    +0021             %     the constructed adapter instance.
    +0022 
    +0023             % Directory where all model-specific files and scripts are kept.
    +0024             % Is assumed to follow the GECKO-defined folder structure.
    +0025             obj.params.path = fullfile('KEY_PATH', 'KEY_NAME');
    +0026             addpath(fullfile(obj.params.path,'code'));
    +0027 
    +0028             % Path to the conventional GEM that this ecModel will be based on.
    +0029             obj.params.convGEM = fullfile(obj.params.path,'models','yourModel.xml');
    +0030 
    +0031             % Average enzyme saturation factor
    +0032             obj.params.sigma = 0.5;
    +0033 
    +0034             % Total protein content in the cell [g protein/gDw]
    +0035             obj.params.Ptot = 0.5;
    +0036 
    +0037             % Fraction of enzymes in the model [g enzyme/g protein]
    +0038             obj.params.f = 0.5;
    +0039             
    +0040             % Growth rate the model should be able to reach when not
    +0041             % constraint by nutrient uptake (e.g. max growth rate) [1/h]
    +0042             obj.params.gR_exp = 0.41;
    +0043 
    +0044             % Provide your organism scientific name
    +0045             obj.params.org_name = 'genus species';
    +0046 
    +0047             % Which BRENDA aggregate fuzzyKcatMatching reads for each
    +0048             % (EC, substrate, organism) triple: 'max' (the highest
    +0049             % turnover reported) or 'median' (the middle one). Can also
    +0050             % be given per call as
    +0051             % fuzzyKcatMatching(model,'kcatAggregation','median').
    +0052             obj.params.kcatAggregation = 'max';
    +0053             
    +0054             % Taxonomic identifier for Complex Portal
    +0055             obj.params.complex.taxonomicID = [];
    +0056 
    +0057             % Provide your organism KEGG ID, selected at
    +0058             % https://www.genome.jp/kegg/catalog/org_list.html
    +0059             obj.params.kegg.ID = 'sce';
    +0060             % Field for KEGG gene identifier; should match the gene
    +0061             % identifiers used in the model. With 'kegg', it takes the
    +0062             % default KEGG Entry identifier (for example YER023W here:
    +0063             % https://www.genome.jp/dbget-bin/www_bget?sce:YER023W).
    +0064             % Alternatively, gene identifiers from the "Other DBs" section
    +0065             % of the KEGG page can be selected. For example "NCBI-GeneID",
    +0066             % "UniProt", or "Ensembl". Not all DB entries are available for
    +0067             % all organisms and/or genes.
    +0068             obj.params.kegg.geneID = 'kegg';
    +0069 
    +0070             % Provide what identifier should be used to query UniProt.
    +0071             % Select proteome IDs at https://www.uniprot.org/proteomes/
    +0072             % or taxonomy IDs at https://www.uniprot.org/taxonomy.
    +0073             obj.params.uniprot.type = 'taxonomy'; % 'proteome' or 'taxonomy'
    +0074             obj.params.uniprot.ID = '559292'; % should match the ID type
    +0075             % Field for Uniprot gene ID - should match the gene ids used in the
    +0076             % model. It should be one of the "Returned Field" entries under
    +0077             % "Names & Taxonomy" at this page: https://www.uniprot.org/help/return_fields
    +0078             obj.params.uniprot.geneIDfield = 'gene_oln';
    +0079             % Whether only reviewed data from UniProt should be considered.
    +0080             % Reviewed data has highest confidence, but coverage might be (very)
    +0081             % low for non-model organisms
    +0082             obj.params.uniprot.reviewed = false;
    +0083 
    +0084             % Reaction ID for glucose exchange reaction (or other preferred carbon source)
    +0085             obj.params.c_source = 'r_1714'; 
    +0086 
    +0087             % Reaction ID for biomass pseudoreaction
    +0088             obj.params.bioRxn = 'r_4041';
    +0089 
    +0090             % Name of the compartment where the protein pseudometabolites
    +0091             % should be located (all be located in the same compartment,
    +0092             % this does not interfere with them catalyzing reactions in
    +0093             % different compartments). Typically, cytoplasm is chosen.
    +0094             obj.params.enzyme_comp = 'cytoplasm';
    +0095 
    +0096             %% Hyperparameters for evotune (CMA-ES) kcat fitting
    +0097             % Default initial uncertainty (standard deviation in log-space) for kcat values
    +0098             obj.params.evotune.sigma0logDefault    = 0.5;
    +0099             % Data sources for kcat values, ordered from least to most trusted
    +0100             obj.params.evotune.kcatSources         = {'dlkcat','brenda','custom'};
    +0101             % Initial uncertainty for each source (lower = more trusted data)
    +0102             obj.params.evotune.sigma0logSource     = [0.4; 0.2; 0.1];
    +0103 
    +0104             % Weight on the max-growth RMSE against the flux RMSE:
    +0105             % (rmseFlux + w*rmseMaxGrowth) / (w+1). At 1 both count equally.
    +0106             obj.params.evotune.maxGrowthWeight     = 1.0;
    +0107             % Weight on a prior term in the search objective,
    +0108             % rmse + w*mean((log(k/k0)/sigma0log)^2). Keeps large corrections
    +0109             % reproducible across seeds; 0 scores on RMSE alone.
    +0110             obj.params.evotune.priorPenaltyWeight  = 0.03;
    +0111             % Give isozyme copies of one reaction (sharing a prior value and
    +0112             % a source) a single shared kcat, so the search cannot invent a
    +0113             % distinction the kcat assignment never made.
    +0114             obj.params.evotune.tieIsozymes         = true;
    +0115 
    +0116             % Stop optimization when RMSE falls below this threshold
    +0117             obj.params.evotune.rmseThreshold       = 0.2;
    +0118             % Maximum number of CMA-ES generations before termination
    +0119             obj.params.evotune.maxGenerations      = 150;
    +0120         end
    +0121 
    +0122         % function ecModel = makeModelAnaerobic(ecModel)
    +0123         %     % Define a model-specific function in the 'code' subfolder,
    +0124         %     % that can constrain the model to anaerobic conditions, and
    +0125         %     % include the name of this function here. This is used by
    +0126         %     % cmaesKcatTuning.m (via evotuneScore.m) if the fluxData
    +0127         %     % has anaerobic conditions.
    +0128         %     addpath(fullfile(obj.params.path,'code'));
    +0129         %     ecModel = nameOfModelSpecificFunction(ecModel);
    +0130         % end
    +0131 
    +0132         function [spont,spontRxnNames] = getSpontaneousReactions(obj,model)
    +0133             % getSpontaneousReactions  Identify spontaneous reactions in the model.
    +0134             %
    +0135             % Indicates how spontaneous reactions are identified. Here it
    +0136             % is done by the reaction having 'spontaneous' in its name.
    +0137             %
    +0138             % Parameters
    +0139             % ----------
    +0140             % model : struct
    +0141             %     a model in RAVEN format.
    +0142             %
    +0143             % Returns
    +0144             % -------
    +0145             % spont : logical
    +0146             %     true for each reaction identified as spontaneous.
    +0147             % spontRxnNames : cell
    +0148             %     names of the reactions identified as spontaneous.
    +0149             spont = contains(model.rxnNames,'spontaneous');
    +0150             spontRxnNames = model.rxnNames(spont);
    +0151         end
    +0152     end
    +0153 end
    +
    Generated by m2html © 2005
    + + \ No newline at end of file diff --git a/doc/src/model_adapter/convertAdapterToToml.html b/doc/src/model_adapter/convertAdapterToToml.html new file mode 100644 index 00000000..7477b31f --- /dev/null +++ b/doc/src/model_adapter/convertAdapterToToml.html @@ -0,0 +1,316 @@ + + + + Description of convertAdapterToToml + + + + + + + + + +
    Home > src > model_adapter > convertAdapterToToml.m
    + + + +

    convertAdapterToToml +

    + +

    PURPOSE ^

    +
    convertAdapterToToml Write the parameters of an adapter class to model_adapter.toml.
    + +

    SYNOPSIS ^

    +
    function report = convertAdapterToToml(adapter, tomlFile)
    + +

    DESCRIPTION ^

    +
     convertAdapterToToml  Write the parameters of an adapter class to model_adapter.toml.
    +
    + Converts an existing ModelAdapter class (GECKO 3 or 4 style) to
    + model_adapter.toml, the configuration file shared by GECKO and geckopy.
    + Parameter names are translated with adapterParameters.tsv (for instance
    + Ptot becomes p_tot), paths inside the project folder are written
    + relative to it, and parameters without a geckopy name are kept under
    + [matlab.params], so that loadAdapterParams gives back the same params.
    +
    + Methods that the adapter class overrides cannot be written to TOML.
    + They are listed in the report, with how to carry them over:
    + - getSpontaneousReactions: set [spontaneous] name_contains or file;
    + - makeModelAnaerobic, changeProteinBiomass: set [matlab]
    +   make_model_anaerobic or change_protein_biomass to a function name;
    + - other methods: keep the adapter class and let its constructor call
    +   loadAdapterParams.
    +
    + Parameters
    + ----------
    + adapter : ModelAdapter or char
    +     an adapter object, or the path to its .m file.
    + tomlFile : char, optional
    +     file to write (default: model_adapter.toml in the adapter's
    +     params.path). An existing file is not overwritten.
    +
    + Returns
    + -------
    + report : struct
    +     - file: the file written;
    +     - unmapped: parameters written under [matlab.params];
    +     - methods: overridden methods that need carrying over by hand.
    +
    + Examples
    + --------
    +     report = convertAdapterToToml(fullfile(projectPath,'MyGEMAdapter.m'));
    +     adapter = TomlAdapter(projectPath);
    +
    + See also
    + --------
    + TomlAdapter, loadAdapterParams, writeAdapterToml
    + + +

    CROSS-REFERENCE INFORMATION ^

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

    SUBFUNCTIONS ^

    + + +

    SOURCE CODE ^

    +
    0001 function report = convertAdapterToToml(adapter, tomlFile)
    +0002 % convertAdapterToToml  Write the parameters of an adapter class to model_adapter.toml.
    +0003 %
    +0004 % Converts an existing ModelAdapter class (GECKO 3 or 4 style) to
    +0005 % model_adapter.toml, the configuration file shared by GECKO and geckopy.
    +0006 % Parameter names are translated with adapterParameters.tsv (for instance
    +0007 % Ptot becomes p_tot), paths inside the project folder are written
    +0008 % relative to it, and parameters without a geckopy name are kept under
    +0009 % [matlab.params], so that loadAdapterParams gives back the same params.
    +0010 %
    +0011 % Methods that the adapter class overrides cannot be written to TOML.
    +0012 % They are listed in the report, with how to carry them over:
    +0013 % - getSpontaneousReactions: set [spontaneous] name_contains or file;
    +0014 % - makeModelAnaerobic, changeProteinBiomass: set [matlab]
    +0015 %   make_model_anaerobic or change_protein_biomass to a function name;
    +0016 % - other methods: keep the adapter class and let its constructor call
    +0017 %   loadAdapterParams.
    +0018 %
    +0019 % Parameters
    +0020 % ----------
    +0021 % adapter : ModelAdapter or char
    +0022 %     an adapter object, or the path to its .m file.
    +0023 % tomlFile : char, optional
    +0024 %     file to write (default: model_adapter.toml in the adapter's
    +0025 %     params.path). An existing file is not overwritten.
    +0026 %
    +0027 % Returns
    +0028 % -------
    +0029 % report : struct
    +0030 %     - file: the file written;
    +0031 %     - unmapped: parameters written under [matlab.params];
    +0032 %     - methods: overridden methods that need carrying over by hand.
    +0033 %
    +0034 % Examples
    +0035 % --------
    +0036 %     report = convertAdapterToToml(fullfile(projectPath,'MyGEMAdapter.m'));
    +0037 %     adapter = TomlAdapter(projectPath);
    +0038 %
    +0039 % See also
    +0040 % --------
    +0041 % TomlAdapter, loadAdapterParams, writeAdapterToml
    +0042 
    +0043 if ischar(adapter) || isstring(adapter)
    +0044     adapter = ModelAdapterManager.getAdapter(char(adapter));
    +0045 end
    +0046 params = adapter.params;
    +0047 if isfield(params,'path') && isstruct(params.path)
    +0048     params.path = params.path.Name; % a struct path, as some old adapters keep it
    +0049 end
    +0050 projectPath = '';
    +0051 if isfield(params,'path')
    +0052     projectPath = char(params.path);
    +0053 end
    +0054 if nargin < 2 || isempty(tomlFile)
    +0055     tomlFile = fullfile(projectPath, 'model_adapter.toml');
    +0056 end
    +0057 if isfile(tomlFile)
    +0058     error('GECKO:convertAdapterToToml', '%s exists already; it is not overwritten.', tomlFile);
    +0059 end
    +0060 
    +0061 map = readMap();
    +0062 data = struct();
    +0063 used = {};
    +0064 for k = 1:numel(map.tomlKey)
    +0065     field = map.matlabField{k};
    +0066     if isempty(field) || any(strcmp(field, {'evotune.kcatSources','evotune.sigma0logSource'}))
    +0067         continue
    +0068     end
    +0069     [found, value] = getDotted(params, field);
    +0070     if ~found || (isempty(value) && ~ischar(value))
    +0071         if found
    +0072             used{end+1} = field; %#ok<AGROW>
    +0073         end
    +0074         continue
    +0075     end
    +0076     used{end+1} = field; %#ok<AGROW>
    +0077     if any(strcmp(map.tomlKey{k}, {'conv_gem','spontaneous.file'}))
    +0078         value = relativePath(char(value), projectPath);
    +0079     end
    +0080     data = setDotted(data, map.tomlKey{k}, value);
    +0081 end
    +0082 used{end+1} = 'path';
    +0083 
    +0084 % Trust tiers: one group per ec.source value.
    +0085 if isfield(params,'evotune') && isfield(params.evotune,'kcatSources')
    +0086     used = [used, {'evotune.kcatSources','evotune.sigma0logSource'}];
    +0087     sources = params.evotune.kcatSources;
    +0088     widths = params.evotune.sigma0logSource;
    +0089     groups = struct();
    +0090     sigma0 = struct();
    +0091     for k = 1:numel(sources)
    +0092         name = matlab.lang.makeValidName(sources{k});
    +0093         groups.(name).sources = sources(k);
    +0094         sigma0.(name) = widths(k);
    +0095     end
    +0096     data.evotune.source_groups = groups;
    +0097     data.evotune.sigma0_log_source = sigma0;
    +0098 end
    +0099 
    +0100 % Everything else is kept for GECKO under [matlab.params].
    +0101 extra = unusedFields(params, '', used);
    +0102 report.unmapped = {};
    +0103 if ~isempty(fieldnames(extra))
    +0104     data.matlab.params = extra;
    +0105     report.unmapped = flattenNames(extra, '');
    +0106 end
    +0107 
    +0108 report.methods = overriddenMethods(adapter);
    +0109 report.file = tomlFile;
    +0110 
    +0111 header = {sprintf('Model adapter for %s, converted from %s.', ...
    +0112     getOr(params,'org_name','this project'), class(adapter)), ...
    +0113     'Shared by GECKO (MATLAB) and geckopy; see adapterParameters.tsv in GECKO for every key.'};
    +0114 writeAdapterToml(data, tomlFile, header);
    +0115 
    +0116 fprintf('Wrote %s.\n', tomlFile);
    +0117 if ~isempty(report.unmapped)
    +0118     fprintf('Kept for GECKO only, under [matlab.params]: %s\n', strjoin(report.unmapped, ', '));
    +0119 end
    +0120 if ~isempty(report.methods)
    +0121     printOrange(sprintf(['%s overrides methods that a TOML file cannot hold: %s.\n' ...
    +0122         'Set [spontaneous] for getSpontaneousReactions, [matlab] function names for\n' ...
    +0123         'makeModelAnaerobic and changeProteinBiomass, or keep the class and let its\n' ...
    +0124         'constructor call loadAdapterParams.\n'], class(adapter), strjoin(report.methods, ', ')));
    +0125 end
    +0126 end
    +0127 
    +0128 function map = readMap()
    +0129 file = fullfile(fileparts(mfilename('fullpath')), 'adapterParameters.tsv');
    +0130 fid = fopen(file, 'r');
    +0131 cols = textscan(fid, '%s %s %s %s', 'Delimiter', '\t', 'HeaderLines', 1, 'Whitespace', '');
    +0132 fclose(fid);
    +0133 map.tomlKey = cols{1};
    +0134 map.matlabField = cols{2};
    +0135 end
    +0136 
    +0137 function names = overriddenMethods(adapter)
    +0138 % Methods defined by the adapter class itself rather than ModelAdapter.
    +0139 names = {};
    +0140 mc = metaclass(adapter);
    +0141 for k = 1:numel(mc.MethodList)
    +0142     m = mc.MethodList(k);
    +0143     if strcmp(m.DefiningClass.Name, mc.Name) && ~strcmp(m.Name, mc.Name) && ~m.Static
    +0144         names{end+1} = m.Name; %#ok<AGROW>
    +0145     end
    +0146 end
    +0147 names = sort(names);
    +0148 end
    +0149 
    +0150 function extra = unusedFields(s, prefix, used)
    +0151 extra = struct();
    +0152 fields = fieldnames(s);
    +0153 for k = 1:numel(fields)
    +0154     name = fields{k};
    +0155     if ~isempty(prefix)
    +0156         name = [prefix '.' name];
    +0157     end
    +0158     if any(strcmp(name, used))
    +0159         continue
    +0160     end
    +0161     value = s.(fields{k});
    +0162     if isstruct(value) && isscalar(value) && any(startsWith(used, [name '.']))
    +0163         sub = unusedFields(value, name, used);
    +0164         if ~isempty(fieldnames(sub))
    +0165             extra.(fields{k}) = sub;
    +0166         end
    +0167     elseif ~(isempty(value) && ~ischar(value) && ~iscell(value))
    +0168         extra.(fields{k}) = value;
    +0169     end
    +0170 end
    +0171 end
    +0172 
    +0173 function names = flattenNames(s, prefix)
    +0174 names = {};
    +0175 fields = fieldnames(s);
    +0176 for k = 1:numel(fields)
    +0177     name = fields{k};
    +0178     if ~isempty(prefix)
    +0179         name = [prefix '.' name];
    +0180     end
    +0181     if isstruct(s.(fields{k}))
    +0182         names = [names, flattenNames(s.(fields{k}), name)]; %#ok<AGROW>
    +0183     else
    +0184         names{end+1} = name; %#ok<AGROW>
    +0185     end
    +0186 end
    +0187 end
    +0188 
    +0189 function p = relativePath(p, projectPath)
    +0190 p = strrep(p, '\', '/');
    +0191 base = strrep(projectPath, '\', '/');
    +0192 if ~isempty(base) && startsWith(p, [base '/'])
    +0193     p = p(numel(base)+2:end);
    +0194 end
    +0195 end
    +0196 
    +0197 function [found, value] = getDotted(s, key)
    +0198 parts = strsplit(key, '.');
    +0199 value = s;
    +0200 found = true;
    +0201 for k = 1:numel(parts)
    +0202     if ~isstruct(value) || ~isfield(value, parts{k})
    +0203         found = false;
    +0204         value = [];
    +0205         return
    +0206     end
    +0207     value = value.(parts{k});
    +0208 end
    +0209 end
    +0210 
    +0211 function s = setDotted(s, key, value)
    +0212 parts = strsplit(key, '.');
    +0213 if numel(parts) == 1
    +0214     s.(parts{1}) = value;
    +0215     return
    +0216 end
    +0217 if ~isfield(s, parts{1}) || ~isstruct(s.(parts{1}))
    +0218     s.(parts{1}) = struct();
    +0219 end
    +0220 s.(parts{1}) = setDotted(s.(parts{1}), strjoin(parts(2:end), '.'), value);
    +0221 end
    +0222 
    +0223 function v = getOr(s, field, default)
    +0224 v = default;
    +0225 if isfield(s, field) && ~isempty(s.(field))
    +0226     v = s.(field);
    +0227 end
    +0228 end
    +
    Generated by m2html © 2005
    + + \ No newline at end of file diff --git a/doc/src/model_adapter/index.html b/doc/src/model_adapter/index.html new file mode 100644 index 00000000..4845792a --- /dev/null +++ b/doc/src/model_adapter/index.html @@ -0,0 +1,29 @@ + + + + Index for Directory src/model_adapter + + + + + + + + + + +
    < Master indexIndex for src/model_adapter >
    + +

    Index for src/model_adapter

    + +

    Matlab files in this directory:

    + +
     ModelAdapterModelAdapter Abstract base class for species-specific model adapters.
     ModelAdapterManagerModelAdapterManager Resolve and cache the active ModelAdapter.
     TomlAdapterTomlAdapter Model adapter configured by model_adapter.toml.
     adapterTemplateKEY_CLASSNAME Template ModelAdapter to copy and adapt per organism.
     convertAdapterToTomlconvertAdapterToToml Write the parameters of an adapter class to model_adapter.toml.
     loadAdapterParamsloadAdapterParams Read model adapter parameters from a TOML file.
     readAdapterTomlreadAdapterToml Read a model adapter TOML file into a struct.
     writeAdapterTomlwriteAdapterToml Write a struct as a model adapter TOML file.
    + + + + +
    Generated by m2html © 2005
    + + \ No newline at end of file diff --git a/doc/src/model_adapter/loadAdapterParams.html b/doc/src/model_adapter/loadAdapterParams.html new file mode 100644 index 00000000..53482ca9 --- /dev/null +++ b/doc/src/model_adapter/loadAdapterParams.html @@ -0,0 +1,329 @@ + + + + Description of loadAdapterParams + + + + + + + + + +
    Home > src > model_adapter > loadAdapterParams.m
    + + + +

    loadAdapterParams +

    + +

    PURPOSE ^

    +
    loadAdapterParams Read model adapter parameters from a TOML file.
    + +

    SYNOPSIS ^

    +
    function params = loadAdapterParams(tomlFile)
    + +

    DESCRIPTION ^

    +
     loadAdapterParams  Read model adapter parameters from a TOML file.
    +
    + Reads model_adapter.toml, the configuration file shared by GECKO and
    + geckopy, and returns the parameters with GECKO's field names, so that
    + they can be used as ModelAdapter.params. Keys are translated with
    + adapterParameters.tsv (for instance p_tot becomes Ptot); keys that are
    + not given get the default listed there, which is geckopy's default.
    +
    + Parameters
    + ----------
    + tomlFile : char
    +     path to model_adapter.toml, or to the project folder that holds it.
    +
    + Returns
    + -------
    + params : struct
    +     the adapter parameters, as in ModelAdapter.params:
    +     - path: the project folder (the folder of the TOML file);
    +     - convGEM and spontaneous.file: absolute paths;
    +     - evotune.kcatSources and evotune.sigma0logSource: built from the
    +       evotune.source_groups and evotune.sigma0_log_source tables, one
    +       entry per ec.source value;
    +     - fields under [matlab.params] are copied as they are, for
    +       parameters that only GECKO uses.
    +
    + Examples
    + --------
    +     params = loadAdapterParams(fullfile(projectPath,'model_adapter.toml'));
    +
    + See also
    + --------
    + TomlAdapter, readAdapterToml, convertAdapterToToml
    + + +

    CROSS-REFERENCE INFORMATION ^

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

    SUBFUNCTIONS ^

    + + +

    SOURCE CODE ^

    +
    0001 function params = loadAdapterParams(tomlFile)
    +0002 % loadAdapterParams  Read model adapter parameters from a TOML file.
    +0003 %
    +0004 % Reads model_adapter.toml, the configuration file shared by GECKO and
    +0005 % geckopy, and returns the parameters with GECKO's field names, so that
    +0006 % they can be used as ModelAdapter.params. Keys are translated with
    +0007 % adapterParameters.tsv (for instance p_tot becomes Ptot); keys that are
    +0008 % not given get the default listed there, which is geckopy's default.
    +0009 %
    +0010 % Parameters
    +0011 % ----------
    +0012 % tomlFile : char
    +0013 %     path to model_adapter.toml, or to the project folder that holds it.
    +0014 %
    +0015 % Returns
    +0016 % -------
    +0017 % params : struct
    +0018 %     the adapter parameters, as in ModelAdapter.params:
    +0019 %     - path: the project folder (the folder of the TOML file);
    +0020 %     - convGEM and spontaneous.file: absolute paths;
    +0021 %     - evotune.kcatSources and evotune.sigma0logSource: built from the
    +0022 %       evotune.source_groups and evotune.sigma0_log_source tables, one
    +0023 %       entry per ec.source value;
    +0024 %     - fields under [matlab.params] are copied as they are, for
    +0025 %       parameters that only GECKO uses.
    +0026 %
    +0027 % Examples
    +0028 % --------
    +0029 %     params = loadAdapterParams(fullfile(projectPath,'model_adapter.toml'));
    +0030 %
    +0031 % See also
    +0032 % --------
    +0033 % TomlAdapter, readAdapterToml, convertAdapterToToml
    +0034 
    +0035 if isfolder(tomlFile)
    +0036     tomlFile = fullfile(tomlFile, 'model_adapter.toml');
    +0037 end
    +0038 if ~isfile(tomlFile)
    +0039     error('GECKO:loadAdapterParams', 'No model adapter file found at %s', tomlFile);
    +0040 end
    +0041 tomlFile = char(tomlFile);
    +0042 [projectPath, ~, ~] = fileparts(getAbsolutePath(tomlFile));
    +0043 
    +0044 data = readAdapterToml(tomlFile);
    +0045 map = adapterParameterMap();
    +0046 
    +0047 % Unknown keys are errors, as in geckopy, so that a typo is not ignored.
    +0048 known = [map.tomlKey; {'evotune.source_groups'; 'evotune.sigma0_log_source'}];
    +0049 checkKnownKeys(data, '', known, tomlFile);
    +0050 
    +0051 params = struct();
    +0052 params.path = projectPath;
    +0053 for k = 1:numel(map.tomlKey)
    +0054     key = map.tomlKey{k};
    +0055     if any(strcmp(key, {'evotune.source_groups', 'evotune.sigma0_log_source'}))
    +0056         continue
    +0057     end
    +0058     [found, value] = getDotted(data, key);
    +0059     if ~found
    +0060         if isempty(map.default{k})
    +0061             continue
    +0062         end
    +0063         value = map.default{k};
    +0064     end
    +0065     if isempty(map.matlabField{k})
    +0066         field = key; % a key that only geckopy reads keeps its name
    +0067     else
    +0068         field = map.matlabField{k};
    +0069     end
    +0070     params = setDotted(params, field, value);
    +0071 end
    +0072 
    +0073 if ~isfield(params, 'complex')
    +0074     params.complex.taxonomicID = []; % geckopy's default: no Complex Portal query
    +0075 end
    +0076 
    +0077 for f = {'convGEM'}
    +0078     if isfield(params, f{1})
    +0079         params.(f{1}) = projectFile(projectPath, params.(f{1}));
    +0080     end
    +0081 end
    +0082 if isfield(params, 'spontaneous') && isfield(params.spontaneous, 'file')
    +0083     params.spontaneous.file = projectFile(projectPath, params.spontaneous.file);
    +0084 end
    +0085 
    +0086 params = sourceGroups(params, data, tomlFile);
    +0087 
    +0088 if isfield(data, 'matlab') && isfield(data.matlab, 'params')
    +0089     params = mergeStruct(params, data.matlab.params);
    +0090 end
    +0091 end
    +0092 
    +0093 function map = adapterParameterMap()
    +0094 % Reads adapterParameters.tsv into toml keys, MATLAB fields and defaults.
    +0095 file = fullfile(fileparts(mfilename('fullpath')), 'adapterParameters.tsv');
    +0096 fid = fopen(file, 'r');
    +0097 cols = textscan(fid, '%s %s %s %s', 'Delimiter', '\t', 'HeaderLines', 1, ...
    +0098     'Whitespace', '', 'ReturnOnError', false);
    +0099 fclose(fid);
    +0100 map.tomlKey = cols{1};
    +0101 map.matlabField = cols{2};
    +0102 map.default = cell(size(cols{3}));
    +0103 for k = 1:numel(cols{3})
    +0104     if ~isempty(cols{3}{k})
    +0105         map.default{k} = parseDefault(cols{3}{k});
    +0106     end
    +0107 end
    +0108 end
    +0109 
    +0110 function value = parseDefault(text)
    +0111 % A default is written as a TOML value.
    +0112 tmp = [tempname '.toml'];
    +0113 fid = fopen(tmp, 'w');
    +0114 fprintf(fid, 'x = %s\n', text);
    +0115 fclose(fid);
    +0116 cleanup = onCleanup(@() delete(tmp));
    +0117 data = readAdapterToml(tmp);
    +0118 value = data.x;
    +0119 if ischar(value) && isempty(value)
    +0120     value = '';
    +0121 end
    +0122 end
    +0123 
    +0124 function checkKnownKeys(s, prefix, known, tomlFile)
    +0125 fields = fieldnames(s);
    +0126 for k = 1:numel(fields)
    +0127     key = fields{k};
    +0128     if ~isempty(prefix)
    +0129         key = [prefix '.' key];
    +0130     end
    +0131     if strcmp(key, 'matlab.params')
    +0132         continue % free-form parameters for GECKO only
    +0133     end
    +0134     if any(strcmp(key, known)) || any(startsWith(known, [key '.']))
    +0135         if isstruct(s.(fields{k})) && ~any(strcmp(key, known))
    +0136             checkKnownKeys(s.(fields{k}), key, known, tomlFile);
    +0137         end
    +0138         continue
    +0139     end
    +0140     if any(startsWith(key, {'evotune.source_groups.', 'evotune.sigma0_log_source.'}))
    +0141         continue
    +0142     end
    +0143     error('GECKO:loadAdapterParams', ['Unknown key "%s" in %s. Parameters that only ' ...
    +0144         'GECKO uses go under [matlab.params].'], key, tomlFile);
    +0145 end
    +0146 end
    +0147 
    +0148 function params = sourceGroups(params, data, tomlFile)
    +0149 % evotune.source_groups and evotune.sigma0_log_source become the
    +0150 % kcatSources and sigma0logSource lists that evotune reads: one entry per
    +0151 % ec.source value, with its group's prior width.
    +0152 groups = struct();
    +0153 widths = struct();
    +0154 if isfield(data, 'evotune') && isfield(data.evotune, 'source_groups')
    +0155     groups = data.evotune.source_groups;
    +0156     if isfield(data.evotune, 'sigma0_log_source')
    +0157         widths = data.evotune.sigma0_log_source;
    +0158     end
    +0159 else
    +0160     % geckopy's defaults (EvotuneParams.source_groups, sigma0_log_source).
    +0161     groups.dlkcat.sources = {'dlkcat'};
    +0162     groups.brenda.sources = {'brenda'};
    +0163     groups.custom.sources = {'custom'};
    +0164     widths.dlkcat = 0.4;
    +0165     widths.brenda = 0.2;
    +0166     widths.custom = 0.1;
    +0167 end
    +0168 names = fieldnames(groups);
    +0169 if ~isempty(setxor(names, fieldnames(widths)))
    +0170     error('GECKO:loadAdapterParams', ['%s: evotune.sigma0_log_source must have ' ...
    +0171         'the same group names as evotune.source_groups'], tomlFile);
    +0172 end
    +0173 kcatSources = {};
    +0174 sigma0logSource = [];
    +0175 for k = 1:numel(names)
    +0176     group = groups.(names{k});
    +0177     sources = {};
    +0178     if isfield(group, 'sources')
    +0179         sources = group.sources;
    +0180         if ischar(sources)
    +0181             sources = {sources};
    +0182         end
    +0183     end
    +0184     if isfield(group, 'match_okp') && group.match_okp && isfield(params, 'okp')
    +0185         sources{end+1} = params.okp.method; %#ok<AGROW>
    +0186     end
    +0187     kcatSources = [kcatSources, sources]; %#ok<AGROW>
    +0188     sigma0logSource = [sigma0logSource; repmat(widths.(names{k}), numel(sources), 1)]; %#ok<AGROW>
    +0189 end
    +0190 params.evotune.kcatSources = kcatSources;
    +0191 params.evotune.sigma0logSource = sigma0logSource;
    +0192 end
    +0193 
    +0194 function [found, value] = getDotted(s, key)
    +0195 parts = strsplit(key, '.');
    +0196 value = s;
    +0197 found = true;
    +0198 for k = 1:numel(parts)
    +0199     if ~isstruct(value) || ~isfield(value, parts{k})
    +0200         found = false;
    +0201         value = [];
    +0202         return
    +0203     end
    +0204     value = value.(parts{k});
    +0205 end
    +0206 end
    +0207 
    +0208 function s = setDotted(s, key, value)
    +0209 parts = strsplit(key, '.');
    +0210 if numel(parts) == 1
    +0211     s.(parts{1}) = value;
    +0212     return
    +0213 end
    +0214 if ~isfield(s, parts{1}) || ~isstruct(s.(parts{1}))
    +0215     s.(parts{1}) = struct();
    +0216 end
    +0217 s.(parts{1}) = setDotted(s.(parts{1}), strjoin(parts(2:end), '.'), value);
    +0218 end
    +0219 
    +0220 function s = mergeStruct(s, extra)
    +0221 fields = fieldnames(extra);
    +0222 for k = 1:numel(fields)
    +0223     value = extra.(fields{k});
    +0224     if isstruct(value) && isscalar(value) && isfield(s, fields{k}) && isstruct(s.(fields{k}))
    +0225         s.(fields{k}) = mergeStruct(s.(fields{k}), value);
    +0226     else
    +0227         s.(fields{k}) = value;
    +0228     end
    +0229 end
    +0230 end
    +0231 
    +0232 function p = projectFile(projectPath, p)
    +0233 if isempty(p)
    +0234     return
    +0235 end
    +0236 if ~isAbsolute(p)
    +0237     p = fullfile(projectPath, p);
    +0238 end
    +0239 end
    +0240 
    +0241 function tf = isAbsolute(p)
    +0242 tf = startsWith(p, '/') || startsWith(p, '\') || ~isempty(regexp(p, '^[A-Za-z]:', 'once'));
    +0243 end
    +0244 
    +0245 function p = getAbsolutePath(p)
    +0246 if ~isAbsolute(p)
    +0247     p = fullfile(pwd, p);
    +0248 end
    +0249 end
    +
    Generated by m2html © 2005
    + + \ No newline at end of file diff --git a/doc/src/model_adapter/readAdapterToml.html b/doc/src/model_adapter/readAdapterToml.html new file mode 100644 index 00000000..7ff0a18f --- /dev/null +++ b/doc/src/model_adapter/readAdapterToml.html @@ -0,0 +1,548 @@ + + + + Description of readAdapterToml + + + + + + + + + +
    Home > src > model_adapter > readAdapterToml.m
    + + + +

    readAdapterToml +

    + +

    PURPOSE ^

    +
    readAdapterToml Read a model adapter TOML file into a struct.
    + +

    SYNOPSIS ^

    +
    function data = readAdapterToml(filename)
    + +

    DESCRIPTION ^

    +
     readAdapterToml  Read a model adapter TOML file into a struct.
    +
    + Reads the subset of TOML that model adapter files use: comments, bare
    + keys, basic and literal strings, integers, floats, booleans, arrays of
    + these values (also over several lines), tables ([kegg], [a.b.c]) and
    + arrays of tables ([[a]]). Anything else, such as dates, inline tables,
    + multi-line strings or quoted keys, stops with an error that names the
    + line.
    +
    + Parameters
    + ----------
    + filename : char
    +     path to the TOML file.
    +
    + Returns
    + -------
    + data : struct
    +     one field per key, with tables as nested structs and arrays of
    +     tables as struct arrays. Strings are char, numbers double, booleans
    +     logical, arrays of strings a 1xn cell and arrays of numbers or
    +     booleans a 1xn vector. An empty array is an empty cell.
    +
    + Examples
    + --------
    +     data = readAdapterToml(fullfile(projectPath,'model_adapter.toml'));
    +
    + See also
    + --------
    + writeAdapterToml, loadAdapterParams
    + + +

    CROSS-REFERENCE INFORMATION ^

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

    SUBFUNCTIONS ^

    + + +

    SOURCE CODE ^

    +
    0001 function data = readAdapterToml(filename)
    +0002 % readAdapterToml  Read a model adapter TOML file into a struct.
    +0003 %
    +0004 % Reads the subset of TOML that model adapter files use: comments, bare
    +0005 % keys, basic and literal strings, integers, floats, booleans, arrays of
    +0006 % these values (also over several lines), tables ([kegg], [a.b.c]) and
    +0007 % arrays of tables ([[a]]). Anything else, such as dates, inline tables,
    +0008 % multi-line strings or quoted keys, stops with an error that names the
    +0009 % line.
    +0010 %
    +0011 % Parameters
    +0012 % ----------
    +0013 % filename : char
    +0014 %     path to the TOML file.
    +0015 %
    +0016 % Returns
    +0017 % -------
    +0018 % data : struct
    +0019 %     one field per key, with tables as nested structs and arrays of
    +0020 %     tables as struct arrays. Strings are char, numbers double, booleans
    +0021 %     logical, arrays of strings a 1xn cell and arrays of numbers or
    +0022 %     booleans a 1xn vector. An empty array is an empty cell.
    +0023 %
    +0024 % Examples
    +0025 % --------
    +0026 %     data = readAdapterToml(fullfile(projectPath,'model_adapter.toml'));
    +0027 %
    +0028 % See also
    +0029 % --------
    +0030 % writeAdapterToml, loadAdapterParams
    +0031 
    +0032 text = fileread(filename);
    +0033 text = strrep(text, sprintf('\r\n'), newline);
    +0034 lines = strsplit(text, newline, 'CollapseDelimiters', false);
    +0035 
    +0036 data = struct();
    +0037 tablePath = {};   % keys of the current table, each element {name, arrayIndex}
    +0038 arrayNames = {};  % dotted names declared as arrays of tables
    +0039 i = 0;
    +0040 while i < numel(lines)
    +0041     i = i + 1;
    +0042     lineNo = i;
    +0043     line = stripComment(lines{i}, filename, lineNo);
    +0044     if isempty(strtrim(line))
    +0045         continue
    +0046     end
    +0047     trimmed = strtrim(line);
    +0048     if startsWith(trimmed, '[[')
    +0049         if ~endsWith(trimmed, ']]')
    +0050             tomlError(filename, lineNo, 'array of tables header must end with ]]');
    +0051         end
    +0052         keys = splitKey(trimmed(3:end-2), filename, lineNo);
    +0053         [data, tablePath] = appendTableArray(data, keys, arrayNames, filename, lineNo);
    +0054         arrayNames = union(arrayNames, {strjoin(keys, '.')});
    +0055     elseif startsWith(trimmed, '[')
    +0056         if ~endsWith(trimmed, ']')
    +0057             tomlError(filename, lineNo, 'table header must end with ]');
    +0058         end
    +0059         keys = splitKey(trimmed(2:end-1), filename, lineNo);
    +0060         tablePath = resolvePath(data, keys, arrayNames);
    +0061         data = ensureTable(data, tablePath, filename, lineNo);
    +0062     else
    +0063         eq = findUnquoted(line, '=');
    +0064         if isempty(eq)
    +0065             tomlError(filename, lineNo, 'expected key = value');
    +0066         end
    +0067         keys = splitKey(line(1:eq-1), filename, lineNo);
    +0068         valueText = strtrim(line(eq+1:end));
    +0069         % Arrays may span several lines: read on until the brackets close.
    +0070         while startsWith(valueText, '[') && bracketDepth(valueText) > 0
    +0071             if i >= numel(lines)
    +0072                 tomlError(filename, lineNo, 'array is not closed');
    +0073             end
    +0074             i = i + 1;
    +0075             valueText = [valueText ' ' strtrim(stripComment(lines{i}, filename, i))]; %#ok<AGROW>
    +0076         end
    +0077         value = parseValue(valueText, filename, lineNo);
    +0078         data = setKey(data, [tablePath, keyPath(keys)], value, filename, lineNo);
    +0079     end
    +0080 end
    +0081 end
    +0082 
    +0083 function line = stripComment(line, filename, lineNo)
    +0084 % Removes a # comment that is not inside a string.
    +0085 inBasic = false; inLiteral = false; k = 1;
    +0086 while k <= numel(line)
    +0087     c = line(k);
    +0088     if inBasic
    +0089         if c == '\'
    +0090             k = k + 1;
    +0091         elseif c == '"'
    +0092             inBasic = false;
    +0093         end
    +0094     elseif inLiteral
    +0095         if c == ''''
    +0096             inLiteral = false;
    +0097         end
    +0098     elseif c == '"'
    +0099         if k + 2 <= numel(line) && strcmp(line(k:k+2), '"""')
    +0100             tomlError(filename, lineNo, 'multi-line strings are not supported');
    +0101         end
    +0102         inBasic = true;
    +0103     elseif c == ''''
    +0104         if k + 2 <= numel(line) && strcmp(line(k:k+2), '''''''')
    +0105             tomlError(filename, lineNo, 'multi-line strings are not supported');
    +0106         end
    +0107         inLiteral = true;
    +0108     elseif c == '#'
    +0109         line = line(1:k-1);
    +0110         return
    +0111     end
    +0112     k = k + 1;
    +0113 end
    +0114 end
    +0115 
    +0116 function idx = findUnquoted(line, ch)
    +0117 % Position of the first ch outside a string, or empty.
    +0118 idx = [];
    +0119 inBasic = false; inLiteral = false; k = 1;
    +0120 while k <= numel(line)
    +0121     c = line(k);
    +0122     if inBasic
    +0123         if c == '\'
    +0124             k = k + 1;
    +0125         elseif c == '"'
    +0126             inBasic = false;
    +0127         end
    +0128     elseif inLiteral
    +0129         if c == ''''
    +0130             inLiteral = false;
    +0131         end
    +0132     elseif c == '"'
    +0133         inBasic = true;
    +0134     elseif c == ''''
    +0135         inLiteral = true;
    +0136     elseif c == ch
    +0137         idx = k;
    +0138         return
    +0139     end
    +0140     k = k + 1;
    +0141 end
    +0142 end
    +0143 
    +0144 function depth = bracketDepth(text)
    +0145 % Open [ minus closed ] outside strings.
    +0146 depth = 0; inBasic = false; inLiteral = false; k = 1;
    +0147 while k <= numel(text)
    +0148     c = text(k);
    +0149     if inBasic
    +0150         if c == '\'
    +0151             k = k + 1;
    +0152         elseif c == '"'
    +0153             inBasic = false;
    +0154         end
    +0155     elseif inLiteral
    +0156         if c == ''''
    +0157             inLiteral = false;
    +0158         end
    +0159     elseif c == '"'
    +0160         inBasic = true;
    +0161     elseif c == ''''
    +0162         inLiteral = true;
    +0163     elseif c == '['
    +0164         depth = depth + 1;
    +0165     elseif c == ']'
    +0166         depth = depth - 1;
    +0167     end
    +0168     k = k + 1;
    +0169 end
    +0170 end
    +0171 
    +0172 function keys = splitKey(text, filename, lineNo)
    +0173 % Dotted bare key into its parts.
    +0174 keys = strtrim(strsplit(strtrim(text), '.'));
    +0175 for k = 1:numel(keys)
    +0176     if isempty(regexp(keys{k}, '^[A-Za-z][A-Za-z0-9_]*$', 'once'))
    +0177         tomlError(filename, lineNo, sprintf(['key "%s" is not supported: use letters, ' ...
    +0178             'digits and underscores, starting with a letter'], keys{k}));
    +0179     end
    +0180 end
    +0181 end
    +0182 
    +0183 function p = keyPath(keys)
    +0184 p = cellfun(@(k) {k, 0}, keys, 'UniformOutput', false);
    +0185 end
    +0186 
    +0187 function path = resolvePath(data, keys, arrayNames)
    +0188 % Path of {name, index} pairs; a key that names an array of tables refers
    +0189 % to its last element.
    +0190 path = cell(1, numel(keys));
    +0191 for k = 1:numel(keys)
    +0192     idx = 0;
    +0193     if ismember(strjoin(keys(1:k), '.'), arrayNames)
    +0194         idx = numel(getKey(data, [path(1:k-1), {{keys{k}, 0}}]));
    +0195     end
    +0196     path{k} = {keys{k}, idx};
    +0197 end
    +0198 end
    +0199 
    +0200 function [data, tablePath] = appendTableArray(data, keys, arrayNames, filename, lineNo)
    +0201 % Appends a new element to the array of tables named by keys.
    +0202 parent = resolvePath(data, keys(1:end-1), arrayNames);
    +0203 data = ensureTable(data, parent, filename, lineNo);
    +0204 name = strjoin(keys, '.');
    +0205 existing = getKey(data, [parent, {{keys{end}, 0}}]);
    +0206 if isempty(existing) || ~ismember(name, arrayNames)
    +0207     if ~isempty(existing)
    +0208         tomlError(filename, lineNo, sprintf('"%s" is already a table or value', name));
    +0209     end
    +0210     n = 1;
    +0211 else
    +0212     n = numel(existing) + 1;
    +0213 end
    +0214 tablePath = [parent, {{keys{end}, n}}];
    +0215 data = setTableElement(data, parent, keys{end}, n);
    +0216 end
    +0217 
    +0218 function data = ensureTable(data, path, filename, lineNo)
    +0219 if isempty(path)
    +0220     return
    +0221 end
    +0222 name = path{1}{1}; idx = path{1}{2};
    +0223 if ~isfield(data, name)
    +0224     data.(name) = struct();
    +0225 elseif ~isstruct(data.(name))
    +0226     tomlError(filename, lineNo, sprintf('"%s" is already a value, not a table', name));
    +0227 end
    +0228 child = data.(name);
    +0229 if idx == 0
    +0230     child = ensureTable(child, path(2:end), filename, lineNo);
    +0231     data.(name) = child;
    +0232 else
    +0233     element = child(idx);
    +0234     element = ensureTable(element, path(2:end), filename, lineNo);
    +0235     data.(name) = assignElement(child, idx, element);
    +0236 end
    +0237 end
    +0238 
    +0239 function data = setTableElement(data, parent, name, n)
    +0240 % Adds element n (an empty struct) to the table array name under parent.
    +0241 if isempty(parent)
    +0242     if ~isfield(data, name) || isempty(data.(name)) || n == 1
    +0243         data.(name) = struct();
    +0244     else
    +0245         data.(name) = assignElement(data.(name), n, struct());
    +0246     end
    +0247     return
    +0248 end
    +0249 pname = parent{1}{1}; pidx = parent{1}{2};
    +0250 child = data.(pname);
    +0251 if pidx == 0
    +0252     data.(pname) = setTableElement(child, parent(2:end), name, n);
    +0253 else
    +0254     element = setTableElement(child(pidx), parent(2:end), name, n);
    +0255     data.(pname) = assignElement(child, pidx, element);
    +0256 end
    +0257 end
    +0258 
    +0259 function value = getKey(data, path)
    +0260 value = [];
    +0261 node = data;
    +0262 for k = 1:numel(path)
    +0263     name = path{k}{1}; idx = path{k}{2};
    +0264     if ~isstruct(node) || ~isfield(node, name)
    +0265         value = [];
    +0266         return
    +0267     end
    +0268     node = node.(name);
    +0269     if idx > 0
    +0270         node = node(idx);
    +0271     end
    +0272 end
    +0273 value = node;
    +0274 end
    +0275 
    +0276 function data = setKey(data, path, value, filename, lineNo)
    +0277 name = path{1}{1}; idx = path{1}{2};
    +0278 if numel(path) == 1
    +0279     % [] only fills a field that another element of a table array has;
    +0280     % TOML itself has no empty value.
    +0281     if isfield(data, name) && ~isequal(data.(name), [])
    +0282         tomlError(filename, lineNo, sprintf('key "%s" is defined twice', name));
    +0283     end
    +0284     data.(name) = value;
    +0285     return
    +0286 end
    +0287 if ~isfield(data, name)
    +0288     data.(name) = struct();
    +0289 elseif ~isstruct(data.(name))
    +0290     tomlError(filename, lineNo, sprintf('"%s" is already a value, not a table', name));
    +0291 end
    +0292 child = data.(name);
    +0293 if idx == 0
    +0294     data.(name) = setKey(child, path(2:end), value, filename, lineNo);
    +0295 else
    +0296     element = setKey(child(idx), path(2:end), value, filename, lineNo);
    +0297     data.(name) = assignElement(child, idx, element);
    +0298 end
    +0299 end
    +0300 
    +0301 function s = assignElement(s, idx, element)
    +0302 % Assigns element to s(idx), adding fields so the struct array stays
    +0303 % consistent.
    +0304 if idx > numel(s) || isempty(fieldnames(s))
    +0305     if numel(s) == 1 && isempty(fieldnames(s)) && idx == 1
    +0306         s = element;
    +0307         return
    +0308     end
    +0309 end
    +0310 fs = fieldnames(element);
    +0311 for f = 1:numel(fs)
    +0312     if ~isfield(s, fs{f})
    +0313         [s.(fs{f})] = deal([]);
    +0314     end
    +0315 end
    +0316 fs = fieldnames(s);
    +0317 for f = 1:numel(fs)
    +0318     if ~isfield(element, fs{f})
    +0319         element.(fs{f}) = [];
    +0320     end
    +0321 end
    +0322 element = orderfields(element, s(1));
    +0323 s(idx) = element;
    +0324 end
    +0325 
    +0326 function value = parseValue(text, filename, lineNo)
    +0327 text = strtrim(text);
    +0328 if isempty(text)
    +0329     tomlError(filename, lineNo, 'missing value');
    +0330 end
    +0331 switch text(1)
    +0332     case '"'
    +0333         [value, rest] = parseBasicString(text, filename, lineNo);
    +0334     case ''''
    +0335         close = find(text(2:end) == '''', 1) + 1;
    +0336         if isempty(close)
    +0337             tomlError(filename, lineNo, 'string is not closed');
    +0338         end
    +0339         value = text(2:close-1);
    +0340         rest = text(close+1:end);
    +0341     case '['
    +0342         [value, rest] = parseArray(text, filename, lineNo);
    +0343     case '{'
    +0344         tomlError(filename, lineNo, 'inline tables are not supported; use a [table] instead');
    +0345     otherwise
    +0346         [value, rest] = parseScalar(text, filename, lineNo);
    +0347 end
    +0348 if ~isempty(strtrim(rest))
    +0349     tomlError(filename, lineNo, sprintf('unexpected text after the value: %s', strtrim(rest)));
    +0350 end
    +0351 end
    +0352 
    +0353 function [value, rest] = parseBasicString(text, filename, lineNo)
    +0354 value = '';
    +0355 k = 2;
    +0356 while k <= numel(text)
    +0357     c = text(k);
    +0358     if c == '"'
    +0359         rest = text(k+1:end);
    +0360         return
    +0361     elseif c == '\'
    +0362         if k == numel(text)
    +0363             break
    +0364         end
    +0365         e = text(k+1);
    +0366         switch e
    +0367             case 'n', value(end+1) = newline;
    +0368             case 't', value(end+1) = sprintf('\t');
    +0369             case '"', value(end+1) = '"';
    +0370             case '\', value(end+1) = '\';
    +0371             case 'u'
    +0372                 value(end+1) = char(hex2dec(text(k+2:k+5)));
    +0373                 k = k + 4;
    +0374             otherwise
    +0375                 tomlError(filename, lineNo, sprintf('escape \\%s is not supported', e));
    +0376         end
    +0377         k = k + 2;
    +0378         continue
    +0379     else
    +0380         value(end+1) = c; %#ok<AGROW>
    +0381     end
    +0382     k = k + 1;
    +0383 end
    +0384 tomlError(filename, lineNo, 'string is not closed');
    +0385 end
    +0386 
    +0387 function [value, rest] = parseArray(text, filename, lineNo)
    +0388 % Parses [a, b, ...]; returns a cell for strings, a vector otherwise.
    +0389 items = {};
    +0390 k = 2;
    +0391 while true
    +0392     while k <= numel(text) && (isspace(text(k)) || text(k) == ',')
    +0393         k = k + 1;
    +0394     end
    +0395     if k > numel(text)
    +0396         tomlError(filename, lineNo, 'array is not closed');
    +0397     end
    +0398     if text(k) == ']'
    +0399         rest = text(k+1:end);
    +0400         break
    +0401     end
    +0402     if text(k) == '['
    +0403         tomlError(filename, lineNo, 'nested arrays are not supported');
    +0404     end
    +0405     % Find the end of this element.
    +0406     if text(k) == '"'
    +0407         [item, after] = parseBasicString(text(k:end), filename, lineNo);
    +0408         k = numel(text) - numel(after) + 1;
    +0409     elseif text(k) == ''''
    +0410         close = find(text(k+1:end) == '''', 1) + k;
    +0411         if isempty(close)
    +0412             tomlError(filename, lineNo, 'string is not closed');
    +0413         end
    +0414         item = text(k+1:close-1);
    +0415         k = close + 1;
    +0416     else
    +0417         stop = k;
    +0418         while stop <= numel(text) && text(stop) ~= ',' && text(stop) ~= ']'
    +0419             stop = stop + 1;
    +0420         end
    +0421         [item, after] = parseScalar(strtrim(text(k:stop-1)), filename, lineNo);
    +0422         if ~isempty(strtrim(after))
    +0423             tomlError(filename, lineNo, 'unexpected text in array');
    +0424         end
    +0425         k = stop;
    +0426     end
    +0427     items{end+1} = item; %#ok<AGROW>
    +0428 end
    +0429 if isempty(items)
    +0430     value = {};
    +0431 elseif all(cellfun(@ischar, items))
    +0432     value = items;
    +0433 elseif all(cellfun(@(x) isnumeric(x) && isscalar(x), items))
    +0434     value = cell2mat(items);
    +0435 elseif all(cellfun(@islogical, items))
    +0436     value = cell2mat(items);
    +0437 else
    +0438     tomlError(filename, lineNo, 'arrays must hold values of one type');
    +0439 end
    +0440 end
    +0441 
    +0442 function [value, rest] = parseScalar(text, filename, lineNo)
    +0443 token = regexp(text, '^[^\s,\]]+', 'match', 'once');
    +0444 rest = text(numel(token)+1:end);
    +0445 switch token
    +0446     case 'true'
    +0447         value = true;
    +0448     case 'false'
    +0449         value = false;
    +0450     case {'inf', '+inf'}
    +0451         value = Inf;
    +0452     case '-inf'
    +0453         value = -Inf;
    +0454     case {'nan', '+nan', '-nan'}
    +0455         value = NaN;
    +0456     otherwise
    +0457         clean = strrep(token, '_', '');
    +0458         if ~isempty(regexp(clean, '^[+-]?(0|[1-9][0-9]*)$', 'once')) || ...
    +0459                 ~isempty(regexp(clean, '^[+-]?(0|[1-9][0-9]*)(\.[0-9]+)?([eE][+-]?[0-9]+)?$', 'once'))
    +0460             value = str2double(clean);
    +0461         elseif ~isempty(regexp(token, '^\d{4}-\d{2}-\d{2}', 'once'))
    +0462             tomlError(filename, lineNo, 'dates are not supported');
    +0463         else
    +0464             tomlError(filename, lineNo, sprintf('cannot read value "%s"; strings need quotes', token));
    +0465         end
    +0466 end
    +0467 end
    +0468 
    +0469 function tomlError(filename, lineNo, message)
    +0470 error('GECKO:readAdapterToml', '%s, line %d: %s', filename, lineNo, message);
    +0471 end
    +
    Generated by m2html © 2005
    + + \ No newline at end of file diff --git a/doc/src/model_adapter/writeAdapterToml.html b/doc/src/model_adapter/writeAdapterToml.html new file mode 100644 index 00000000..47a6bf67 --- /dev/null +++ b/doc/src/model_adapter/writeAdapterToml.html @@ -0,0 +1,215 @@ + + + + Description of writeAdapterToml + + + + + + + + + +
    Home > src > model_adapter > writeAdapterToml.m
    + + + +

    writeAdapterToml +

    + +

    PURPOSE ^

    +
    writeAdapterToml Write a struct as a model adapter TOML file.
    + +

    SYNOPSIS ^

    +
    function writeAdapterToml(data, filename, header)
    + +

    DESCRIPTION ^

    +
     writeAdapterToml  Write a struct as a model adapter TOML file.
    +
    + Writes the subset of TOML that readAdapterToml reads: values first,
    + then each nested struct as a [table] and each struct array as an array
    + of tables ([[name]]).
    +
    + Parameters
    + ----------
    + data : struct
    +     values may be char or string scalars, numeric or logical scalars or
    +     vectors, cell arrays of char, structs and struct arrays.
    + filename : char
    +     path of the TOML file to write; an existing file is overwritten.
    + header : char or cell, optional
    +     comment lines written at the top of the file (without '#').
    +
    + Examples
    + --------
    +     writeAdapterToml(struct('sigma',0.5), 'model_adapter.toml', ...
    +         {'Adapter for ecYeastGEM'});
    +
    + See also
    + --------
    + readAdapterToml, convertAdapterToToml
    + + +

    CROSS-REFERENCE INFORMATION ^

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

    SUBFUNCTIONS ^

    + + +

    SOURCE CODE ^

    +
    0001 function writeAdapterToml(data, filename, header)
    +0002 % writeAdapterToml  Write a struct as a model adapter TOML file.
    +0003 %
    +0004 % Writes the subset of TOML that readAdapterToml reads: values first,
    +0005 % then each nested struct as a [table] and each struct array as an array
    +0006 % of tables ([[name]]).
    +0007 %
    +0008 % Parameters
    +0009 % ----------
    +0010 % data : struct
    +0011 %     values may be char or string scalars, numeric or logical scalars or
    +0012 %     vectors, cell arrays of char, structs and struct arrays.
    +0013 % filename : char
    +0014 %     path of the TOML file to write; an existing file is overwritten.
    +0015 % header : char or cell, optional
    +0016 %     comment lines written at the top of the file (without '#').
    +0017 %
    +0018 % Examples
    +0019 % --------
    +0020 %     writeAdapterToml(struct('sigma',0.5), 'model_adapter.toml', ...
    +0021 %         {'Adapter for ecYeastGEM'});
    +0022 %
    +0023 % See also
    +0024 % --------
    +0025 % readAdapterToml, convertAdapterToToml
    +0026 
    +0027 if nargin < 3
    +0028     header = {};
    +0029 elseif ischar(header) || isstring(header)
    +0030     header = cellstr(header);
    +0031 end
    +0032 
    +0033 out = {};
    +0034 for k = 1:numel(header)
    +0035     out{end+1} = ['# ' header{k}]; %#ok<AGROW>
    +0036 end
    +0037 if ~isempty(header)
    +0038     out{end+1} = '';
    +0039 end
    +0040 out = writeTable(out, data, {});
    +0041 
    +0042 fid = fopen(filename, 'w');
    +0043 if fid < 0
    +0044     error('GECKO:writeAdapterToml', 'Cannot write %s', filename);
    +0045 end
    +0046 fprintf(fid, '%s\n', out{:});
    +0047 fclose(fid);
    +0048 end
    +0049 
    +0050 function out = writeTable(out, s, prefix)
    +0051 fields = fieldnames(s);
    +0052 tables = {};
    +0053 for k = 1:numel(fields)
    +0054     value = s.(fields{k});
    +0055     if isstruct(value)
    +0056         tables{end+1} = fields{k}; %#ok<AGROW>
    +0057     elseif isempty(value) && ~iscell(value) && ~ischar(value)
    +0058         continue % unset value; TOML has no null
    +0059     else
    +0060         out{end+1} = [fields{k} ' = ' formatValue(value, strjoin([prefix fields(k)], '.'))]; %#ok<AGROW>
    +0061     end
    +0062 end
    +0063 for k = 1:numel(tables)
    +0064     value = s.(tables{k});
    +0065     name = strjoin([prefix tables(k)], '.');
    +0066     if numel(value) == 1
    +0067         out{end+1} = ''; %#ok<AGROW>
    +0068         out{end+1} = ['[' name ']']; %#ok<AGROW>
    +0069         out = writeTable(out, value, [prefix tables(k)]);
    +0070     else
    +0071         for e = 1:numel(value)
    +0072             out{end+1} = ''; %#ok<AGROW>
    +0073             out{end+1} = ['[[' name ']]']; %#ok<AGROW>
    +0074             out = writeTable(out, value(e), [prefix tables(k)]);
    +0075         end
    +0076     end
    +0077 end
    +0078 end
    +0079 
    +0080 function text = formatValue(value, name)
    +0081 if isstring(value) && isscalar(value)
    +0082     value = char(value);
    +0083 end
    +0084 if ischar(value)
    +0085     text = quote(value);
    +0086 elseif iscell(value)
    +0087     if ~all(cellfun(@(x) ischar(x) || (isstring(x) && isscalar(x)), value))
    +0088         error('GECKO:writeAdapterToml', '%s: only cell arrays of text can be written', name);
    +0089     end
    +0090     parts = cellfun(@(x) quote(char(x)), value, 'UniformOutput', false);
    +0091     text = ['[' strjoin(parts(:)', ', ') ']'];
    +0092 elseif islogical(value) || isnumeric(value)
    +0093     if isscalar(value)
    +0094         text = formatScalar(value);
    +0095     else
    +0096         parts = arrayfun(@formatScalar, value(:)', 'UniformOutput', false);
    +0097         text = ['[' strjoin(parts, ', ') ']'];
    +0098     end
    +0099 else
    +0100     error('GECKO:writeAdapterToml', '%s: values of class %s cannot be written', name, class(value));
    +0101 end
    +0102 end
    +0103 
    +0104 function text = formatScalar(x)
    +0105 if islogical(x)
    +0106     if x
    +0107         text = 'true';
    +0108     else
    +0109         text = 'false';
    +0110     end
    +0111 elseif isinf(x)
    +0112     if x > 0
    +0113         text = 'inf';
    +0114     else
    +0115         text = '-inf';
    +0116     end
    +0117 elseif isnan(x)
    +0118     text = 'nan';
    +0119 elseif x == round(x) && abs(x) < 1e15
    +0120     text = sprintf('%d', x);
    +0121 else
    +0122     text = sprintf('%.17g', x);
    +0123     % Use the shortest form that reads back to the same double.
    +0124     for p = 1:17
    +0125         candidate = sprintf('%.*g', p, x);
    +0126         if str2double(candidate) == x
    +0127             text = candidate;
    +0128             break
    +0129         end
    +0130     end
    +0131     if isempty(regexp(text, '[.eE]', 'once'))
    +0132         text = [text '.0'];
    +0133     end
    +0134 end
    +0135 end
    +0136 
    +0137 function text = quote(s)
    +0138 s = strrep(s, '\', '\\');
    +0139 s = strrep(s, '"', '\"');
    +0140 s = strrep(s, sprintf('\t'), '\t');
    +0141 s = strrep(s, newline, '\n');
    +0142 text = ['"' s '"'];
    +0143 end
    +
    Generated by m2html © 2005
    + + \ No newline at end of file diff --git a/doc/src/utilities/buildGECKOdoc.html b/doc/src/utilities/buildGECKOdoc.html new file mode 100644 index 00000000..c2a67786 --- /dev/null +++ b/doc/src/utilities/buildGECKOdoc.html @@ -0,0 +1,94 @@ + + + + Description of buildGECKOdoc + + + + + + + + + +
    Home > src > utilities > buildGECKOdoc.m
    + + + +

    buildGECKOdoc +

    + +

    PURPOSE ^

    +
    buildGECKOdoc Update HTML documentation for all GECKO MATLAB functions.
    + +

    SYNOPSIS ^

    +
    function buildGECKOdoc()
    + +

    DESCRIPTION ^

    +
     buildGECKOdoc  Update HTML documentation for all GECKO MATLAB functions.
    +
    + Updates HTML documentation files for all GECKO MATLAB functions. Uses
    + the m2html functions that are provided with RAVEN.
    +
    + Examples
    + --------
    +     buildGECKOdoc();
    + + +

    CROSS-REFERENCE INFORMATION ^

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

    SOURCE CODE ^

    +
    0001 function buildGECKOdoc()
    +0002 % buildGECKOdoc  Update HTML documentation for all GECKO MATLAB functions.
    +0003 %
    +0004 % Updates HTML documentation files for all GECKO MATLAB functions. Uses
    +0005 % the m2html functions that are provided with RAVEN.
    +0006 %
    +0007 % Examples
    +0008 % --------
    +0009 %     buildGECKOdoc();
    +0010 
    +0011 %Make sure that RAVEN-provided m2html is used
    +0012 ravenDir=findRAVENroot();
    +0013 path(fullfile(ravenDir,'software','m2html'),path);
    +0014 
    +0015 %Get the GECKO path
    +0016 geckoDir=findGECKOroot();
    +0017 
    +0018 %Remove old doc directory
    +0019 rmdir(fullfile(geckoDir,'doc'),'s');
    +0020 
    +0021 %Get a non-redundant list of GECKO subdirectories containing MATLAB
    +0022 %functions. Absolute paths are not compatible with M2HTML, so convert them
    +0023 %to the relative paths instead.
    +0024 geckoDirs=dir(fullfile(geckoDir,'src','**/*.m'));
    +0025 geckoDirs=unique({geckoDirs.folder})';
    +0026 
    +0027 %Make relative path
    +0028 relStart = numel(geckoDir)+2;
    +0029 for i=1:numel(geckoDirs)
    +0030     geckoDirs{i,1} = geckoDirs{i,1}(relStart:end);
    +0031 end
    +0032 
    +0033 %Save the current working directory and go to RAVEN root directory
    +0034 originalDir=pwd;
    +0035 cd(geckoDir);
    +0036 %Generate HTML documentation files for RAVEN MATLAB functions
    +0037 m2html('mFiles',geckoDirs,'htmldir','doc');
    +0038 %Go back to the original working directory
    +0039 cd(originalDir);
    +0040 end
    +
    Generated by m2html © 2005
    + + \ No newline at end of file diff --git a/doc/src/utilities/createGECKOproject.html b/doc/src/utilities/createGECKOproject.html new file mode 100644 index 00000000..e2263cf9 --- /dev/null +++ b/doc/src/utilities/createGECKOproject.html @@ -0,0 +1,157 @@ + + + + Description of createGECKOproject + + + + + + + + + +
    Home > src > utilities > createGECKOproject.m
    + + + +

    createGECKOproject +

    + +

    PURPOSE ^

    +
    createGECKOproject Create a basic project structure for GECKO.
    + +

    SYNOPSIS ^

    +
    function createGECKOproject(varargin)
    + +

    DESCRIPTION ^

    +
     createGECKOproject  Create a basic project structure for GECKO.
    +
    + Creates a basic project structure for GECKO. If a project with the same
    + name exists, the project will not be created.
    +
    + Name-Value Arguments
    + --------------------
    + name : char
    +     a name for the folder structure used in GECKO. Also creates a basic
    +     model adapter, which must be manually adjusted. If not defined, a
    +     dialog box will appear.
    + path : char
    +     a path where to create the folder. If not defined, a dialog box will
    +     appear.
    + adapterFormat : char
    +     'toml' (default) writes model_adapter.toml, which GECKO and geckopy
    +     both read (see TomlAdapter); 'class' writes an adapter class
    +     <name>Adapter.m instead.
    +
    + Examples
    + --------
    +     % optional arguments may be given positionally or as name-value pairs:
    +     createGECKOproject(name, path);
    +     createGECKOproject('name', name);
    +     createGECKOproject('name', name, 'adapterFormat', 'class');
    + + +

    CROSS-REFERENCE INFORMATION ^

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

    SOURCE CODE ^

    +
    0001 function createGECKOproject(varargin)
    +0002 % createGECKOproject  Create a basic project structure for GECKO.
    +0003 %
    +0004 % Creates a basic project structure for GECKO. If a project with the same
    +0005 % name exists, the project will not be created.
    +0006 %
    +0007 % Name-Value Arguments
    +0008 % --------------------
    +0009 % name : char
    +0010 %     a name for the folder structure used in GECKO. Also creates a basic
    +0011 %     model adapter, which must be manually adjusted. If not defined, a
    +0012 %     dialog box will appear.
    +0013 % path : char
    +0014 %     a path where to create the folder. If not defined, a dialog box will
    +0015 %     appear.
    +0016 % adapterFormat : char
    +0017 %     'toml' (default) writes model_adapter.toml, which GECKO and geckopy
    +0018 %     both read (see TomlAdapter); 'class' writes an adapter class
    +0019 %     <name>Adapter.m instead.
    +0020 %
    +0021 % Examples
    +0022 % --------
    +0023 %     % optional arguments may be given positionally or as name-value pairs:
    +0024 %     createGECKOproject(name, path);
    +0025 %     createGECKOproject('name', name);
    +0026 %     createGECKOproject('name', name, 'adapterFormat', 'class');
    +0027 
    +0028 p = parseGECKOargs(varargin, { ...
    +0029     'name', []; ...
    +0030     'path', []; ...
    +0031     'adapterFormat', 'toml'});
    +0032 name = p.name;
    +0033 path = p.path;
    +0034 adapterFormat = validatestring(p.adapterFormat, {'toml','class'});
    +0035 
    +0036 if isempty(name)
    +0037     prompt = {'Please provide a project name (e.g. ecYeastGEM)'};
    +0038     dlgtitle = 'Project name';
    +0039     dims = [1 100];
    +0040     definput = {'ecModelGEM'};
    +0041     opts.Interpreter = 'tex';
    +0042     name = inputdlg(prompt,dlgtitle,dims,definput,opts);
    +0043     name = char(name);
    +0044 end
    +0045 
    +0046 if isempty(path)
    +0047     path = uigetdir('Project Folder path');
    +0048 end
    +0049 
    +0050 fullPath = fullfile(path, name);
    +0051 % Validate if the project does not exits
    +0052 if ~exist(fullPath, 'dir')
    +0053     % Create the subfolder
    +0054     dir = {'code', 'data', 'models', 'output'};
    +0055     for i = 1:length(dir)
    +0056         status = mkdir(fullPath, dir{i});
    +0057         fid = fopen(fullfile(fullPath, dir{i}, '.keep'), 'w');
    +0058         fclose(fid);
    +0059     end
    +0060 
    +0061     % Read the template adapter
    +0062     if strcmp(adapterFormat, 'toml')
    +0063         template = 'adapterTemplate.toml';
    +0064         filename = fullfile(path, name, 'model_adapter.toml');
    +0065     else
    +0066         template = 'adapterTemplate.m';
    +0067         filename = fullfile(path, name, [name 'Adapter.m']);
    +0068     end
    +0069     fid = fopen(fullfile(findGECKOroot, 'src', 'model_adapter', template));
    +0070     f = fread(fid, '*char')';
    +0071     fclose(fid);
    +0072 
    +0073     % Replace key values
    +0074     f = strrep(f, 'KEY_CLASSNAME', [name 'Adapter']);
    +0075     f = strrep(f, 'KEY_PATH', path);
    +0076     f = strrep(f, 'KEY_NAME', name);
    +0077 
    +0078     % Save the adapter
    +0079     fid = fopen(filename, 'w');
    +0080     fwrite(fid, f);
    +0081     fclose(fid);
    +0082 else
    +0083     printOrange('WARNING: A project with the same name exits at the same location. The project was not created.\n');
    +0084 end
    +0085 cd(fullPath)
    +0086 end
    +
    Generated by m2html © 2005
    + + \ No newline at end of file diff --git a/doc/src/utilities/findGECKOroot.html b/doc/src/utilities/findGECKOroot.html new file mode 100644 index 00000000..8f91f961 --- /dev/null +++ b/doc/src/utilities/findGECKOroot.html @@ -0,0 +1,92 @@ + + + + Description of findGECKOroot + + + + + + + + + +
    Home > src > utilities > findGECKOroot.m
    + + + +

    findGECKOroot +

    + +

    PURPOSE ^

    +
    findGECKOroot Find the root of the GECKO directory.
    + +

    SYNOPSIS ^

    +
    function [geckoPath, prevDir] = findGECKOroot()
    + +

    DESCRIPTION ^

    +
     findGECKOroot  Find the root of the GECKO directory.
    +
    + Finds the root of the GECKO directory, by searching for the path to
    + GECKOInstaller.m. Can also record the current directory, in case a function
    + will use the geckoPath to navigate to a precise folder, and it should
    + return to the previous directory afterwards.
    +
    + Returns
    + -------
    + geckoPath : char
    +     path to the root of the GECKO directory.
    + prevDir : char
    +     the current directory at the time of the call, recorded so that a
    +     function can return to it afterwards.
    + + +

    CROSS-REFERENCE INFORMATION ^

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

    SOURCE CODE ^

    +
    0001 function [geckoPath, prevDir] = findGECKOroot()
    +0002 % findGECKOroot  Find the root of the GECKO directory.
    +0003 %
    +0004 % Finds the root of the GECKO directory, by searching for the path to
    +0005 % GECKOInstaller.m. Can also record the current directory, in case a function
    +0006 % will use the geckoPath to navigate to a precise folder, and it should
    +0007 % return to the previous directory afterwards.
    +0008 %
    +0009 % Returns
    +0010 % -------
    +0011 % geckoPath : char
    +0012 %     path to the root of the GECKO directory.
    +0013 % prevDir : char
    +0014 %     the current directory at the time of the call, recorded so that a
    +0015 %     function can return to it afterwards.
    +0016 
    +0017 ST=dbstack('-completenames');
    +0018 prevDir = pwd();
    +0019 geckoPath = ST(strcmp({ST.name},'findGECKOroot')).file;
    +0020 rootFound = 0;
    +0021 while rootFound == 0
    +0022     isRoot = exist(fullfile(geckoPath,'GECKOInstaller.m'),'file');
    +0023     if isRoot == 2
    +0024         rootFound = 1;
    +0025     else
    +0026         ravenPathOld = geckoPath;
    +0027         geckoPath = fileparts(geckoPath);
    +0028         if strcmp(ravenPathOld,geckoPath)
    +0029             error('Cannot find the GECKO root directory. Make sure you have not removed the GECKOInstaller.m file from your GECKO installation.')
    +0030         end
    +0031     end
    +0032 end
    +
    Generated by m2html © 2005
    + + \ No newline at end of file diff --git a/doc/src/utilities/index.html b/doc/src/utilities/index.html new file mode 100644 index 00000000..e028aa29 --- /dev/null +++ b/doc/src/utilities/index.html @@ -0,0 +1,29 @@ + + + + Index for Directory src/utilities + + + + + + + + + + +
    < Master indexIndex for src/utilities >
    + +

    Index for src/utilities

    + +

    Matlab files in this directory:

    + +
     buildGECKOdocbuildGECKOdoc Update HTML documentation for all GECKO MATLAB functions.
     createGECKOprojectcreateGECKOproject Create a basic project structure for GECKO.
     findGECKOrootfindGECKOroot Find the root of the GECKO directory.
     parseGECKOargsparseGECKOargs Resolve optional arguments passed positionally or by name.
     upgradeGECKOprojectupgradeGECKOproject Bring a GECKO 3 project to the GECKO 4 layout.
    + + + + +
    Generated by m2html © 2005
    + + \ No newline at end of file diff --git a/doc/src/utilities/parseGECKOargs.html b/doc/src/utilities/parseGECKOargs.html new file mode 100644 index 00000000..53994f4d --- /dev/null +++ b/doc/src/utilities/parseGECKOargs.html @@ -0,0 +1,195 @@ + + + + Description of parseGECKOargs + + + + + + + + + +
    Home > src > utilities > parseGECKOargs.m
    + + + +

    parseGECKOargs +

    + +

    PURPOSE ^

    +
    parseGECKOargs Resolve optional arguments passed positionally or by name.
    + +

    SYNOPSIS ^

    +
    function args = parseGECKOargs(rawArgs, spec)
    + +

    DESCRIPTION ^

    +
     parseGECKOargs  Resolve optional arguments passed positionally or by name.
    +
    + Helper that lets a GECKO function accept its optional arguments either in
    + the traditional positional order or as name-value pairs, without losing
    + backward compatibility. The required leading arguments stay explicit in the
    + function signature; the optional tail is collected into varargin and passed
    + here together with a specification of the optional parameters.
    +
    + Parameters
    + ----------
    + rawArgs : cell
    +     the function's varargin, i.e. whatever was supplied after the required
    +     positional arguments.
    + spec : cell
    +     an N-by-2 or N-by-3 cell array describing the optional parameters, one
    +     per row:
    +
    +     - column 1 : parameter name (char).
    +     - column 2 : default value, used when the parameter is not supplied.
    +     - column 3 : optional validator, a function handle that is called with
    +       the resolved value and should error on an invalid value. Use [] for
    +       no validation.
    +
    + Returns
    + -------
    + args : struct
    +     a struct with one field per parameter name, holding the resolved value.
    +
    + Notes
    + -----
    + The calling convention is detected from rawArgs: it is treated as name-
    + value pairs only when it has an even number of elements AND every element
    + in a name position is a string matching one of the declared parameter
    + names. Otherwise it is treated as positional and assigned in the order of
    + the spec. A call therefore uses either the positional or the name-value
    + form for the optional tail, not a mix of the two. When an optional tail
    + value could itself be a string equal to a parameter name, use the explicit
    + name-value form to remove the ambiguity.
    +
    + Examples
    + --------
    +     % inside makeEcModel(model, varargin):
    +     p = parseGECKOargs(varargin, { ...
    +         'geckoLight',   false; ...
    +         'modelAdapter', []});
    +     geckoLight   = p.geckoLight;
    +     modelAdapter = p.modelAdapter;
    +
    +     % the caller may then use either form:
    +     makeEcModel(model, true, adapter)                  % positional
    +     makeEcModel(model, 'geckoLight', true)             % named
    + + +

    CROSS-REFERENCE INFORMATION ^

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

    SOURCE CODE ^

    +
    0001 function args = parseGECKOargs(rawArgs, spec)
    +0002 % parseGECKOargs  Resolve optional arguments passed positionally or by name.
    +0003 %
    +0004 % Helper that lets a GECKO function accept its optional arguments either in
    +0005 % the traditional positional order or as name-value pairs, without losing
    +0006 % backward compatibility. The required leading arguments stay explicit in the
    +0007 % function signature; the optional tail is collected into varargin and passed
    +0008 % here together with a specification of the optional parameters.
    +0009 %
    +0010 % Parameters
    +0011 % ----------
    +0012 % rawArgs : cell
    +0013 %     the function's varargin, i.e. whatever was supplied after the required
    +0014 %     positional arguments.
    +0015 % spec : cell
    +0016 %     an N-by-2 or N-by-3 cell array describing the optional parameters, one
    +0017 %     per row:
    +0018 %
    +0019 %     - column 1 : parameter name (char).
    +0020 %     - column 2 : default value, used when the parameter is not supplied.
    +0021 %     - column 3 : optional validator, a function handle that is called with
    +0022 %       the resolved value and should error on an invalid value. Use [] for
    +0023 %       no validation.
    +0024 %
    +0025 % Returns
    +0026 % -------
    +0027 % args : struct
    +0028 %     a struct with one field per parameter name, holding the resolved value.
    +0029 %
    +0030 % Notes
    +0031 % -----
    +0032 % The calling convention is detected from rawArgs: it is treated as name-
    +0033 % value pairs only when it has an even number of elements AND every element
    +0034 % in a name position is a string matching one of the declared parameter
    +0035 % names. Otherwise it is treated as positional and assigned in the order of
    +0036 % the spec. A call therefore uses either the positional or the name-value
    +0037 % form for the optional tail, not a mix of the two. When an optional tail
    +0038 % value could itself be a string equal to a parameter name, use the explicit
    +0039 % name-value form to remove the ambiguity.
    +0040 %
    +0041 % Examples
    +0042 % --------
    +0043 %     % inside makeEcModel(model, varargin):
    +0044 %     p = parseGECKOargs(varargin, { ...
    +0045 %         'geckoLight',   false; ...
    +0046 %         'modelAdapter', []});
    +0047 %     geckoLight   = p.geckoLight;
    +0048 %     modelAdapter = p.modelAdapter;
    +0049 %
    +0050 %     % the caller may then use either form:
    +0051 %     makeEcModel(model, true, adapter)                  % positional
    +0052 %     makeEcModel(model, 'geckoLight', true)             % named
    +0053 
    +0054 if nargin < 2 || isempty(spec)
    +0055     error('parseGECKOargs:noSpec', 'A parameter specification is required.');
    +0056 end
    +0057 
    +0058 names = spec(:, 1);
    +0059 defaults = spec(:, 2);
    +0060 hasValidators = size(spec, 2) >= 3;
    +0061 
    +0062 % Seed every parameter with its default.
    +0063 args = struct();
    +0064 for i = 1:numel(names)
    +0065     args.(names{i}) = defaults{i};
    +0066 end
    +0067 
    +0068 if ~isempty(rawArgs)
    +0069     isNameValue = mod(numel(rawArgs), 2) == 0 && ...
    +0070         all(cellfun(@(x) (ischar(x) || isstring(x)) && isscalar(string(x)) && ...
    +0071         any(strcmpi(x, names)), rawArgs(1:2:end)));
    +0072 
    +0073     if isNameValue
    +0074         for k = 1:2:numel(rawArgs)
    +0075             args.(names{strcmpi(rawArgs{k}, names)}) = rawArgs{k + 1};
    +0076         end
    +0077     else
    +0078         if numel(rawArgs) > numel(names)
    +0079             error('parseGECKOargs:tooManyArgs', ...
    +0080                 'Too many positional arguments: expected at most %d, got %d.', ...
    +0081                 numel(names), numel(rawArgs));
    +0082         end
    +0083         for k = 1:numel(rawArgs)
    +0084             args.(names{k}) = rawArgs{k};
    +0085         end
    +0086     end
    +0087 end
    +0088 
    +0089 % Apply optional validators.
    +0090 if hasValidators
    +0091     for i = 1:numel(names)
    +0092         validator = spec{i, 3};
    +0093         if ~isempty(validator)
    +0094             validator(args.(names{i}));
    +0095         end
    +0096     end
    +0097 end
    +0098 end
    +
    Generated by m2html © 2005
    + + \ No newline at end of file diff --git a/doc/src/utilities/upgradeGECKOproject.html b/doc/src/utilities/upgradeGECKOproject.html new file mode 100644 index 00000000..3c113522 --- /dev/null +++ b/doc/src/utilities/upgradeGECKOproject.html @@ -0,0 +1,409 @@ + + + + Description of upgradeGECKOproject + + + + + + + + + +
    Home > src > utilities > upgradeGECKOproject.m
    + + + +

    upgradeGECKOproject +

    + +

    PURPOSE ^

    +
    upgradeGECKOproject Bring a GECKO 3 project to the GECKO 4 layout.
    + +

    SYNOPSIS ^

    +
    function report = upgradeGECKOproject(projectPath, varargin)
    + +

    DESCRIPTION ^

    +
     upgradeGECKOproject  Bring a GECKO 3 project to the GECKO 4 layout.
    +
    + Lists, and with 'dryRun', false carries out, the steps that bring a
    + project made with GECKO 3 (or an earlier GECKO 4) to the current layout:
    +
    + 1. adapter: an adapter class without model_adapter.toml gets one
    +    (convertAdapterToToml). Methods the class overrides are listed: they
    +    need carrying over by hand. The class itself stays.
    + 2. custom kcats: data/customKcats.tsv becomes data/kcats/custom.tsv
    +    (convertCustomKcats).
    + 3. stored predictions: data/DLKcat.tsv and stored OpenKineticsPredictor
    +    results become kcat source files (kcatsFromDLKcat, kcatsFromOKP with
    +    'useStored'), without running anything.
    + Steps 2 and 3 need the full ecModel the custom kcats and predictions are
    + for ('ecModel'); without it they are listed and skipped.
    + 4. saved ecModels: models/*.yml ecModels made with GECKO 3 get their
    +    protein usage and pool reactions turned forward (upgradeEcModel).
    + 5. project_format = 4 is written to model_adapter.toml.
    + 6. scripts: lines of the project's .m files that call renamed or replaced
    +    functions are listed, not changed.
    +
    + A file that is replaced or converted is first moved to
    + legacy/<yyyy-mm-dd>/ in the project, keeping its place in the folder
    + tree. Steps that are already done are left out, so the function can run
    + again. geckopy has the same as `geckopy upgrade` (upgrade_project).
    +
    + Parameters
    + ----------
    + projectPath : char
    +     the project folder.
    +
    + Name-Value Arguments
    + --------------------
    + dryRun : logical
    +     only list the steps (default true).
    + ecModel : struct
    +     the ecModel the stored predictions were made for (step 3).
    +
    + Returns
    + -------
    + report : table
    +     one row per step: step, status ('to do', 'done', 'skipped', 'failed',
    +     'by hand') and note; script lines are listed one per row.
    +
    + Examples
    + --------
    +     upgradeGECKOproject(projectPath)                    % see what it would do
    +     upgradeGECKOproject(projectPath, 'dryRun', false, 'ecModel', ecModel)
    +
    + See also
    + --------
    + convertAdapterToToml, convertCustomKcats, upgradeEcModel, createGECKOproject
    + + +

    CROSS-REFERENCE INFORMATION ^

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

    SUBFUNCTIONS ^

    + + +

    SOURCE CODE ^

    +
    0001 function report = upgradeGECKOproject(projectPath, varargin)
    +0002 % upgradeGECKOproject  Bring a GECKO 3 project to the GECKO 4 layout.
    +0003 %
    +0004 % Lists, and with 'dryRun', false carries out, the steps that bring a
    +0005 % project made with GECKO 3 (or an earlier GECKO 4) to the current layout:
    +0006 %
    +0007 % 1. adapter: an adapter class without model_adapter.toml gets one
    +0008 %    (convertAdapterToToml). Methods the class overrides are listed: they
    +0009 %    need carrying over by hand. The class itself stays.
    +0010 % 2. custom kcats: data/customKcats.tsv becomes data/kcats/custom.tsv
    +0011 %    (convertCustomKcats).
    +0012 % 3. stored predictions: data/DLKcat.tsv and stored OpenKineticsPredictor
    +0013 %    results become kcat source files (kcatsFromDLKcat, kcatsFromOKP with
    +0014 %    'useStored'), without running anything.
    +0015 % Steps 2 and 3 need the full ecModel the custom kcats and predictions are
    +0016 % for ('ecModel'); without it they are listed and skipped.
    +0017 % 4. saved ecModels: models/*.yml ecModels made with GECKO 3 get their
    +0018 %    protein usage and pool reactions turned forward (upgradeEcModel).
    +0019 % 5. project_format = 4 is written to model_adapter.toml.
    +0020 % 6. scripts: lines of the project's .m files that call renamed or replaced
    +0021 %    functions are listed, not changed.
    +0022 %
    +0023 % A file that is replaced or converted is first moved to
    +0024 % legacy/<yyyy-mm-dd>/ in the project, keeping its place in the folder
    +0025 % tree. Steps that are already done are left out, so the function can run
    +0026 % again. geckopy has the same as `geckopy upgrade` (upgrade_project).
    +0027 %
    +0028 % Parameters
    +0029 % ----------
    +0030 % projectPath : char
    +0031 %     the project folder.
    +0032 %
    +0033 % Name-Value Arguments
    +0034 % --------------------
    +0035 % dryRun : logical
    +0036 %     only list the steps (default true).
    +0037 % ecModel : struct
    +0038 %     the ecModel the stored predictions were made for (step 3).
    +0039 %
    +0040 % Returns
    +0041 % -------
    +0042 % report : table
    +0043 %     one row per step: step, status ('to do', 'done', 'skipped', 'failed',
    +0044 %     'by hand') and note; script lines are listed one per row.
    +0045 %
    +0046 % Examples
    +0047 % --------
    +0048 %     upgradeGECKOproject(projectPath)                    % see what it would do
    +0049 %     upgradeGECKOproject(projectPath, 'dryRun', false, 'ecModel', ecModel)
    +0050 %
    +0051 % See also
    +0052 % --------
    +0053 % convertAdapterToToml, convertCustomKcats, upgradeEcModel, createGECKOproject
    +0054 
    +0055 checkOptions(varargin, {'dryRun','ecModel'}, 'upgradeGECKOproject');
    +0056 p = parseGECKOargs(varargin, {'dryRun', true; 'ecModel', []});
    +0057 projectPath = char(projectPath);
    +0058 if ~isfolder(projectPath)
    +0059     error('upgradeGECKOproject:path', 'No folder %s.', projectPath)
    +0060 end
    +0061 apply = ~p.dryRun;
    +0062 legacy = fullfile(projectPath, 'legacy', char(datetime('now', 'Format', 'yyyy-MM-dd')));
    +0063 toml = fullfile(projectPath, 'model_adapter.toml');
    +0064 rows = cell(0, 3);
    +0065     function add(step, status, note)
    +0066         rows(end+1, :) = {step, status, note};
    +0067     end
    +0068     function keepOriginal(file)
    +0069         % Move a file to legacy/<date>/, at its place in the folder tree.
    +0070         rel = file(numel(projectPath)+2:end);
    +0071         target = fullfile(legacy, rel);
    +0072         if ~isfolder(fileparts(target))
    +0073             mkdir(fileparts(target));
    +0074         end
    +0075         movefile(file, target);
    +0076     end
    +0077 status = 'to do';
    +0078 if apply
    +0079     status = 'done';
    +0080 end
    +0081 
    +0082 % 1. Adapter class -> model_adapter.toml
    +0083 if ~isfile(toml)
    +0084     classFile = adapterClass(projectPath);
    +0085     if isempty(classFile)
    +0086         add('adapter', 'by hand', 'no model_adapter.toml and no adapter class; see createGECKOproject');
    +0087     else
    +0088         note = sprintf('%s -> model_adapter.toml', relative(classFile, projectPath));
    +0089         if apply
    +0090             r = convertAdapterToToml(classFile, toml);
    +0091             if ~isempty(r.methods)
    +0092                 add('adapter methods', 'by hand', ['carry over: ' strjoin(r.methods, ', ')]);
    +0093             end
    +0094         end
    +0095         add('adapter', status, note);
    +0096     end
    +0097 end
    +0098 
    +0099 % 2. customKcats.tsv -> data/kcats/custom.tsv
    +0100 custom = fullfile(projectPath, 'data', 'customKcats.tsv');
    +0101 customOut = fullfile(projectPath, 'data', 'kcats', 'custom.tsv');
    +0102 if isfile(custom) && ~isfile(customOut)
    +0103     note = 'data/customKcats.tsv -> data/kcats/custom.tsv';
    +0104     if isempty(p.ecModel)
    +0105         add('custom kcats', 'skipped', [note '; give the ecModel they are for (''ecModel'')']);
    +0106     else
    +0107         if apply
    +0108             [~, r] = convertCustomKcats(p.ecModel, 'customKcats', custom, 'outFile', customOut, ...
    +0109                 'modelAdapter', projectAdapter(projectPath));
    +0110             keepOriginal(custom);
    +0111             note = sprintf('%s (%d rows)', note, r.rows);
    +0112         end
    +0113         add('custom kcats', status, note);
    +0114     end
    +0115 end
    +0116 
    +0117 % 3. Stored predictions -> kcat source files
    +0118 stored = {};
    +0119 if isfile(fullfile(projectPath, 'data', 'DLKcat.tsv')) && ~isfile(fullfile(projectPath, 'data', 'kcats', 'dlkcat.tsv'))
    +0120     stored{end+1} = 'dlkcat';
    +0121 end
    +0122 okpFiles = dir(fullfile(projectPath, 'data', 'OKP_output*.csv'));
    +0123 for k = 1:numel(okpFiles)
    +0124     method = okpMethod(projectPath, okpFiles(k).name);
    +0125     if ~isempty(method)
    +0126         name = ['okp_' lower(regexprep(regexprep(method, '[^A-Za-z0-9]+', '_'), '^_+|_+$', ''))];
    +0127         if ~isfile(fullfile(projectPath, 'data', 'kcats', [name '.tsv']))
    +0128             stored{end+1} = method; %#ok<AGROW>
    +0129         end
    +0130     end
    +0131 end
    +0132 stored = unique(stored, 'stable');
    +0133 if ~isempty(stored)
    +0134     note = ['stored predictions -> data/kcats: ' strjoin(stored, ', ')];
    +0135     if isempty(p.ecModel)
    +0136         add('predictions', 'skipped', [note '; give the ecModel they were made for (''ecModel'')']);
    +0137     else
    +0138         if apply
    +0139             adapter = projectAdapter(projectPath);
    +0140             for k = 1:numel(stored)
    +0141                 try
    +0142                     if strcmp(stored{k}, 'dlkcat')
    +0143                         kcatsFromDLKcat(p.ecModel, 'modelAdapter', adapter);
    +0144                     else
    +0145                         kcatsFromOKP(p.ecModel, 'method', stored{k}, 'useStored', true, 'modelAdapter', adapter);
    +0146                     end
    +0147                     add('predictions', status, ['stored predictions -> data/kcats: ' stored{k}]);
    +0148                 catch err
    +0149                     add('predictions', 'failed', sprintf('%s: %s', stored{k}, err.message));
    +0150                 end
    +0151             end
    +0152         else
    +0153             add('predictions', status, note);
    +0154         end
    +0155     end
    +0156 end
    +0157 
    +0158 % 4. Saved ecModels: protein reactions turned forward
    +0159 models = dir(fullfile(projectPath, 'models', '*.yml'));
    +0160 for k = 1:numel(models)
    +0161     file = fullfile(models(k).folder, models(k).name);
    +0162     if ~contains(fileread(file), 'prot_pool')
    +0163         continue
    +0164     end
    +0165     try
    +0166         model = readYAMLmodel(file);
    +0167     catch err
    +0168         add('saved ecModel', 'failed', sprintf('%s: %s', relative(file, projectPath), err.message));
    +0169         continue
    +0170     end
    +0171     if isfield(model.annotation, 'gecko_format') && str2double(model.annotation.gecko_format) > 4
    +0172         add('saved ecModel', 'failed', sprintf('%s: ecModel format %s is newer than this GECKO', ...
    +0173             relative(file, projectPath), model.annotation.gecko_format));
    +0174         continue
    +0175     end
    +0176     [model, changed] = upgradeEcModel(model);
    +0177     if isempty(changed)
    +0178         continue
    +0179     end
    +0180     if apply
    +0181         model.annotation.generator = ['GECKO ' geckoVersion()];
    +0182         keepOriginal(file);
    +0183         writeYAMLmodel(model, file);
    +0184     end
    +0185     add('saved ecModel', status, sprintf('%s: %d protein reactions turned forward', ...
    +0186         relative(file, projectPath), numel(changed)));
    +0187 end
    +0188 
    +0189 % 5. project_format in model_adapter.toml
    +0190 adapterRow = strcmp(rows(:, 1), 'adapter') & ~strcmp(rows(:, 2), 'by hand');
    +0191 if isfile(toml) || any(adapterRow)
    +0192     if ~isfile(toml) || isempty(regexp(fileread(toml), '(?m)^\s*project_format\s*=', 'once'))
    +0193         if apply
    +0194             text = fileread(toml);
    +0195             fid = fopen(toml, 'w', 'n', 'UTF-8');
    +0196             fprintf(fid, 'project_format = 4\n%s', text);
    +0197             fclose(fid);
    +0198         end
    +0199         add('project format', status, 'project_format = 4 in model_adapter.toml');
    +0200     end
    +0201 end
    +0202 
    +0203 % 6. Scripts that call renamed or replaced functions
    +0204 renamed = { ...
    +0205     'enzymeUsage', 'getEnzymeUsage'; 'pfbaEnzymes', 'getPfbaEnzymes'; ...
    +0206     'selectKcatValue', 'assignKcatValues'; 'startGECKOproject', 'createGECKOproject'; ...
    +0207     'updateGECKOdoc', 'buildGECKOdoc'; 'copyECtoGEM', 'applyECcodes'; ...
    +0208     'addCarbonNum', 'fillCarbonNum'; 'updateprior', 'updatePrior'; ...
    +0209     'mergeDLKcatAndFuzzyKcats', 'mergeKcats'; ...
    +0210     'fuzzyKcatMatching', 'kcatsFromBrenda (or kcatsFromECTree), then assignKcats'; ...
    +0211     'readDLKcatOutput', 'kcatsFromDLKcat, then assignKcats'; ...
    +0212     'readOpenKineticsPredictorOutput', 'kcatsFromOKP, then assignKcats'; ...
    +0213     'writeOpenKineticsPredictorInput', 'kcatsFromOKP'; ...
    +0214     'applyCustomKcats', 'data/kcats/custom.tsv and assignKcats'};
    +0215 scripts = dir(fullfile(projectPath, '**', '*.m'));
    +0216 for k = 1:numel(scripts)
    +0217     file = fullfile(scripts(k).folder, scripts(k).name);
    +0218     if startsWith(file, fullfile(projectPath, 'legacy'))
    +0219         continue
    +0220     end
    +0221     lines = strsplit(fileread(file), {'\r\n', '\n'});
    +0222     for r = 1:size(renamed, 1)
    +0223         hit = find(~cellfun(@isempty, regexp(lines, ['(?<![\w.])' renamed{r, 1} '\s*\('], 'once')));
    +0224         for h = hit(:)'
    +0225             add('script', 'by hand', sprintf('%s:%d: %s -> %s', relative(file, projectPath), h, ...
    +0226                 renamed{r, 1}, renamed{r, 2}));
    +0227         end
    +0228     end
    +0229 end
    +0230 
    +0231 report = cell2table(rows, 'VariableNames', {'step', 'status', 'note'});
    +0232 if isempty(rows)
    +0233     fprintf('%s has the current GECKO 4 layout.\n', projectPath);
    +0234 else
    +0235     disp(report)
    +0236     if ~apply && any(strcmp(rows(:, 2), 'to do'))
    +0237         fprintf('Run upgradeGECKOproject(projectPath, ''dryRun'', false) to carry out the steps; originals go to %s.\n', legacy);
    +0238     end
    +0239 end
    +0240 end
    +0241 
    +0242 function adapter = projectAdapter(projectPath)
    +0243 % The project's adapter: from model_adapter.toml, or its adapter class.
    +0244 if isfile(fullfile(projectPath, 'model_adapter.toml'))
    +0245     adapter = TomlAdapter(projectPath);
    +0246 else
    +0247     adapter = ModelAdapterManager.getAdapter(adapterClass(projectPath));
    +0248     adapter.params.path = projectPath;
    +0249 end
    +0250 end
    +0251 
    +0252 function file = adapterClass(projectPath)
    +0253 % The adapter class in the project folder, or '' when there is none.
    +0254 file = '';
    +0255 candidates = dir(fullfile(projectPath, '*.m'));
    +0256 for k = 1:numel(candidates)
    +0257     f = fullfile(candidates(k).folder, candidates(k).name);
    +0258     if ~isempty(regexp(fileread(f), '(?m)^\s*classdef\s+\w+\s*<\s*ModelAdapter', 'once'))
    +0259         file = f;
    +0260         return
    +0261     end
    +0262 end
    +0263 end
    +0264 
    +0265 function method = okpMethod(projectPath, outName)
    +0266 % The OKP method of a stored result: from its own job file
    +0267 % (OKP_job_<tag>.txt), or from OKP_job.txt for the shared OKP_output.csv.
    +0268 method = '';
    +0269 if strcmp(outName, 'OKP_output.csv')
    +0270     jobFile = fullfile(projectPath, 'data', 'OKP_job.txt');
    +0271 else
    +0272     jobFile = fullfile(projectPath, 'data', ['OKP_job_' regexprep(outName, '^OKP_output_|\.csv$', '') '.txt']);
    +0273 end
    +0274 if ~isfile(jobFile)
    +0275     return
    +0276 end
    +0277 tok = regexp(fileread(jobFile), '(?m)^method:\s*(\S+)', 'tokens', 'once');
    +0278 if ~isempty(tok)
    +0279     method = tok{1};
    +0280 end
    +0281 end
    +0282 
    +0283 function r = relative(file, projectPath)
    +0284 r = file(numel(projectPath)+2:end);
    +0285 end
    +0286 
    +0287 function checkOptions(args, names, functionName)
    +0288 % Options are name-value pairs with known names, so a misspelled option is
    +0289 % an error instead of being taken as a positional argument.
    +0290 id = [functionName ':arguments'];
    +0291 given = args(1:2:end);
    +0292 if mod(numel(args), 2) ~= 0 || ~all(cellfun(@(x) ischar(x) || (isstring(x) && isscalar(x)), given))
    +0293     error(id, 'Options of %s are name-value pairs. Options: %s.', functionName, strjoin(names, ', '))
    +0294 end
    +0295 unknown = setdiff(cellfun(@char, given, 'UniformOutput', false), names);
    +0296 if ~isempty(unknown)
    +0297     error(id, 'Unknown option of %s: %s. Options: %s.', functionName, strjoin(unknown, ', '), ...
    +0298         strjoin(names, ', '))
    +0299 end
    +0300 end
    +0301 
    +0302 function v = geckoVersion()
    +0303 file = fullfile(findGECKOroot, 'version.txt');
    +0304 if isfile(file)
    +0305     v = strtrim(fileread(file));
    +0306 else
    +0307     v = 'unknown';
    +0308 end
    +0309 end
    +
    Generated by m2html © 2005
    + + \ No newline at end of file diff --git a/src/kcat_tuning/evotune/evotuneScore.m b/src/kcat_tuning/evotune/evotuneScore.m index 71305957..189c4ac9 100644 --- a/src/kcat_tuning/evotune/evotuneScore.m +++ b/src/kcat_tuning/evotune/evotuneScore.m @@ -5,9 +5,7 @@ % tunePriorPenaltyWeight to score one ecModel (with a given set of kcats % already applied via applyKcatConstraints) against the experimental % growth and flux data. Fuses what geckopy splits into simulate.py (the -% FBA half) and distance.py (the RMSE half) into one function, matching -% this module's own predecessor abc_max.m -- there is no MATLAB test -% suite here to benefit from Python's testability-driven split. +% FBA half) and distance.py (the RMSE half) into one function. % % Parameters % ---------- @@ -114,7 +112,7 @@ %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% function [rmse, rmseList] = simulateCondition(ecModel,data,constrain,rxn2block,modelAdapter) % One condition's FBA simulation + carbon-weighted RMSE against measured -% data. Ported from abc_max.m's rmsecal. +% data. rmseList = zeros(length(data.conds),1);