Skip to content

Commit 90a13ac

Browse files
authored
fix: parsing grRules; addMets and addRxns; importModel annotations; replaceMets and changeGrRules options (#571)
* fix: addMets if metNames and not mets are given * feat: changeGrRules multiple rxns same grRule * fix: addRxns subSystems correct format * fix: subSystems if cell array of cell arrays * fix: importModel if identifiers.org/name:value * refactor: checkModelStruct use getGenesFromGrRules * feat: replaceMets can use identifiers instead * refactor: use getGenesFromGrRules * doc: checkRxn clarify meaning of output
1 parent 166bc4f commit 90a13ac

18 files changed

+1026
-1014
lines changed

core/addExchangeRxns.m

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -62,7 +62,11 @@
6262
model.eccodes=[model.eccodes;filler];
6363
end
6464
if isfield(model,'subSystems')
65-
model.subSystems=[model.subSystems;filler];
65+
fillerSub = filler;
66+
if iscell(model.subSystems(1,1))
67+
fillerSub = repmat({fillerSub},numel(J),1);
68+
end
69+
model.subSystems=[model.subSystems;fillerSub];
6670
end
6771
if isfield(model,'grRules')
6872
model.grRules=[model.grRules;filler];

core/addMets.m

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -70,6 +70,7 @@
7070

7171
%Check some stuff regarding the required fields
7272
if ~isfield(metsToAdd,'mets')
73+
metsToAdd.metNames=convertCharArray(metsToAdd.metNames);
7374
metsToAdd.mets=generateNewIds(newModel,'mets',prefix,numel(metsToAdd.metNames));
7475
else
7576
metsToAdd.mets=convertCharArray(metsToAdd.mets);

core/addRxns.m

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -363,7 +363,7 @@
363363
if ~isfield(newModel,'subSystems')
364364
newModel.subSystems=celllargefiller;
365365
end
366-
newModel.subSystems=[newModel.subSystems;rxnsToAdd.subSystems];
366+
newModel.subSystems=[newModel.subSystems;rxnsToAdd.subSystems(:)];
367367
else
368368
%Fill with standard if it doesn't exist
369369
if isfield(newModel,'subSystems')

core/changeGrRules.m

Lines changed: 11 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -23,22 +23,22 @@
2323
rxns=convertCharArray(rxns);
2424
grRules=convertCharArray(grRules);
2525

26+
if isscalar(grRules) && ~isscalar(rxns)
27+
grRules = repmat(grRules,1,numel(rxns));
28+
end
2629
if ~(numel(grRules)==numel(rxns))
2730
error('Number of rxns and grRules should be identical')
2831
end
2932

30-
for i=1:length(rxns)
31-
% Add genes to model
32-
geneList=transpose(cell(unique(regexp(grRules{i},'[)(]*|( and )*|( or )*','split')))); % Extract individual, unique genes from the geneAssoc provided
33-
geneList=geneList(~cellfun(@isempty, geneList));
34-
genesToAdd.genes=setdiff(geneList,model.genes); % Only keep the genes that are not yet part of the model.genes.
35-
if ~isempty(genesToAdd.genes)
36-
model=addGenesRaven(model,genesToAdd); % Add genes
37-
end
38-
39-
% Find reaction and gene indices
40-
idx=getIndexes(model,rxns,'rxns');
33+
% Add genes to model
34+
geneList = getGenesFromGrRules(grRules);
35+
genesToAdd.genes=setdiff(geneList,model.genes); % Only keep the genes that are not yet part of the model.genes.
36+
if ~isempty(genesToAdd.genes)
37+
model=addGenesRaven(model,genesToAdd); % Add genes
4138
end
39+
40+
% Find reaction and gene indices
41+
idx=getIndexes(model,rxns,'rxns');
4242

4343
% Change gene associations
4444
if replace==true % Replace old gene associations

core/checkModelStruct.m

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -124,9 +124,7 @@ function checkModelStruct(model,throwErrors,trimWarnings)
124124
EM='If "grRules" field exists, the model should also contain a "genes" field';
125125
dispEM(EM,throwErrors);
126126
else
127-
geneList = strjoin(model.grRules);
128-
geneList = regexp(geneList,' |)|(|and|or','split'); % Remove all grRule punctuation
129-
geneList = geneList(~cellfun(@isempty,geneList)); % Remove spaces and empty genes
127+
geneList = getGenesFromGrRules(model.grRules);
130128
geneList = setdiff(unique(geneList),model.genes);
131129
if ~isempty(geneList)
132130
problemGrRules = model.rxns(contains(model.grRules,geneList));

core/checkRxn.m

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -14,11 +14,11 @@
1414
%
1515
% report
1616
% reactants array with reactant indexes
17-
% canMake boolean array, true if the corresponding reactant can be
18-
% synthesized
17+
% canMake boolean array, true if the corresponding reactant can
18+
% be synthesized by the rest of the metabolic network
1919
% products array with product indexes
20-
% canConsume boolean array, true if the corresponding reactant can
21-
% be consumed
20+
% canConsume boolean array, true if the corresponding product can
21+
% be consumed by the rest of the metabolic network
2222
%
2323
% Usage: report=checkRxn(model,rxn,cutoff,revDir,printReport)
2424

core/replaceMets.m

Lines changed: 52 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
function [model, removedRxns, idxDuplRxns]=replaceMets(model,metabolite,replacement,verbose)
1+
function [model, removedRxns, idxDuplRxns]=replaceMets(model,metabolite,replacement,verbose,identifiers)
22
% replaceMets
33
% Replaces metabolite names and annotation with replacement metabolite
44
% that is already in the model. If this results in duplicate metabolites,
@@ -13,42 +13,59 @@
1313
% verbose logical whether to print the ids of reactions that
1414
% involve the replaced metabolite (optional, default
1515
% false)
16+
% identifiers true if 'metabolite' and 'replacement' refer to
17+
% metabolite identifiers instead of metabolite names
18+
% (optional, default false)
1619
%
1720
% Output:
1821
% model model structure with selected metabolites replaced
1922
% removedRxns identifiers of duplicate reactions that were removed
2023
% idxDuplRxns index of removedRxns in original model
2124
%
2225
% Note: This function is useful when the model contains both 'oxygen' and
23-
% 'o2' as metabolites.
26+
% 'o2' as metabolite names. If 'oxygen' and 'o2' are identifiers instead,
27+
% then the 'identifiers' flag should be set to true.
2428
%
2529
% Usage: [model, removedRxns, idxDuplRxns] = replaceMets(model, metabolite, replacement, verbose)
2630

2731
metabolite=char(metabolite);
2832
replacement=char(replacement);
2933

30-
if nargin<4
34+
if nargin<4 || isempty(verbose)
3135
verbose=false;
3236
end
37+
if nargin<5
38+
identifiers = false;
39+
end
3340

3441
% Find occurence of replacement metabolites. Annotation will be taken from
35-
% first metabolite found. Metabolite ID from replacement will be used where
36-
% possible.
37-
repIdx = find(strcmp(replacement,model.metNames));
42+
% first metabolite found.
43+
if identifiers
44+
repIdx = find(strcmp(replacement,model.mets));
45+
else
46+
repIdx = find(strcmp(replacement,model.metNames));
47+
end
3848
if isempty(repIdx)
39-
error('The replacement metabolite name cannot be found in the model.');
49+
error('The replacement metabolite cannot be found in the model.');
4050
end
4151

4252
% Change name and information from metabolite to replacement metabolite
43-
metIdx = find(strcmp(metabolite,model.metNames));
53+
if identifiers
54+
metIdx = find(strcmp(metabolite,model.mets));
55+
else
56+
metIdx = find(strcmp(metabolite,model.metNames));
57+
end
4458
if isempty(metIdx)
45-
error('The to-be-replaced metabolite name cannot be found in the model.');
59+
error('The to-be-replaced metabolite cannot be found in the model.');
4660
end
61+
62+
rxnsWithMet = find(model.S(metIdx,:));
4763
if verbose==true
48-
fprintf('\n\nThe following reactions contain the replaced metabolite as reactant:\n')
49-
fprintf(strjoin(model.rxns(find(model.S(metIdx,:))),'\n'))
64+
fprintf('\n\nThe following reactions contain the to-be-replaced metabolite as reactant:\n')
65+
fprintf(strjoin(model.rxns(rxnsWithMet),'\n'))
5066
fprintf('\n')
5167
end
68+
5269
model.metNames(metIdx) = model.metNames(repIdx(1));
5370
if isfield(model,'metFormulas')
5471
model.metFormulas(metIdx) = model.metFormulas(repIdx(1));
@@ -68,24 +85,32 @@
6885
if isfield(model,'metSmiles')
6986
model.metSmiles(metIdx) = model.metSmiles(repIdx(1));
7087
end
71-
% Run through replacement metabolites and their compartments. If any of the
72-
% to-be-replaced metabolites is already present (checked by
73-
% metaboliteName[compartment], then the replacement metabolite is kept and
74-
% the to-be-replace metabolite ID deleted.
75-
76-
% Build list of metaboliteName[compartment]
77-
metCompsN =cellstr(num2str(model.metComps));
78-
map = containers.Map(cellstr(num2str(transpose(1:length(model.comps)))),model.comps);
79-
metCompsN = map.values(metCompsN);
80-
metCompsN = strcat(lower(model.metNames),'[',metCompsN,']');
8188

8289
idxDelete=[];
83-
for i = 1:length(repIdx)
84-
metCompsNidx=find(strcmp(metCompsN(repIdx(i)), metCompsN));
85-
if length(metCompsNidx)>1
86-
for j = 2:length(metCompsNidx)
87-
model.S(metCompsNidx(1),:) = model.S(metCompsNidx(1),:) + model.S(metCompsNidx(j),:);
88-
idxDelete=[idxDelete; metCompsNidx(j)]; % Make list of metabolite IDs to delete
90+
if identifiers
91+
originalStoch = model.S(metIdx,rxnsWithMet);
92+
model.S(repIdx,rxnsWithMet) = originalStoch;
93+
model.S(metIdx,rxnsWithMet) = 0;
94+
idxDelete = metIdx;
95+
else
96+
% Run through replacement metabolites and their compartments. If any of the
97+
% to-be-replaced metabolites is already present (checked by
98+
% metaboliteName[compartment], then the replacement metabolite is kept and
99+
% the to-be-replace metabolite ID deleted.
100+
101+
% Build list of metaboliteName[compartment]
102+
metCompsN =cellstr(num2str(model.metComps));
103+
map = containers.Map(cellstr(num2str(transpose(1:length(model.comps)))),model.comps);
104+
metCompsN = map.values(metCompsN);
105+
metCompsN = strcat(lower(model.metNames),'[',metCompsN,']');
106+
107+
for i = 1:length(repIdx)
108+
metCompsNidx=find(strcmp(metCompsN(repIdx(i)), metCompsN));
109+
if length(metCompsNidx)>1
110+
for j = 2:length(metCompsNidx)
111+
model.S(metCompsNidx(1),:) = model.S(metCompsNidx(1),:) + model.S(metCompsNidx(j),:);
112+
idxDelete=[idxDelete; metCompsNidx(j)]; % Make list of metabolite IDs to delete
113+
end
89114
end
90115
end
91116
end

doc/core/addExchangeRxns.html

Lines changed: 34 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -126,37 +126,41 @@ <h2><a name="_source"></a>SOURCE CODE <a href="#_top"><img alt="^" border="0" sr
126126
0062 model.eccodes=[model.eccodes;filler];
127127
0063 <span class="keyword">end</span>
128128
0064 <span class="keyword">if</span> isfield(model,<span class="string">'subSystems'</span>)
129-
0065 model.subSystems=[model.subSystems;filler];
130-
0066 <span class="keyword">end</span>
131-
0067 <span class="keyword">if</span> isfield(model,<span class="string">'grRules'</span>)
132-
0068 model.grRules=[model.grRules;filler];
133-
0069 <span class="keyword">end</span>
134-
0070 <span class="keyword">if</span> isfield(model,<span class="string">'rxnFrom'</span>)
135-
0071 model.rxnFrom=[model.rxnFrom;filler];
136-
0072 <span class="keyword">end</span>
137-
0073 <span class="keyword">if</span> isfield(model,<span class="string">'rxnMiriams'</span>)
138-
0074 model.rxnMiriams=[model.rxnMiriams;filler];
139-
0075 <span class="keyword">end</span>
140-
0076 <span class="keyword">if</span> isfield(model,<span class="string">'rxnGeneMat'</span>)
141-
0077 model.rxnGeneMat=[model.rxnGeneMat;sparse(numel(J),numel(model.genes))];
142-
0078 <span class="keyword">end</span>
143-
0079 <span class="keyword">if</span> isfield(model,<span class="string">'rxnComps'</span>)
144-
0080 model.rxnComps=[model.rxnComps;ones(numel(J),1)];
145-
0081 fprintf(<span class="string">'NOTE: The exchange reactions are assigned to the first compartment\n'</span>);
129+
0065 fillerSub = filler;
130+
0066 <span class="keyword">if</span> iscell(model.subSystems(1,1))
131+
0067 fillerSub = repmat({fillerSub},numel(J),1);
132+
0068 <span class="keyword">end</span>
133+
0069 model.subSystems=[model.subSystems;fillerSub];
134+
0070 <span class="keyword">end</span>
135+
0071 <span class="keyword">if</span> isfield(model,<span class="string">'grRules'</span>)
136+
0072 model.grRules=[model.grRules;filler];
137+
0073 <span class="keyword">end</span>
138+
0074 <span class="keyword">if</span> isfield(model,<span class="string">'rxnFrom'</span>)
139+
0075 model.rxnFrom=[model.rxnFrom;filler];
140+
0076 <span class="keyword">end</span>
141+
0077 <span class="keyword">if</span> isfield(model,<span class="string">'rxnMiriams'</span>)
142+
0078 model.rxnMiriams=[model.rxnMiriams;filler];
143+
0079 <span class="keyword">end</span>
144+
0080 <span class="keyword">if</span> isfield(model,<span class="string">'rxnGeneMat'</span>)
145+
0081 model.rxnGeneMat=[model.rxnGeneMat;sparse(numel(J),numel(model.genes))];
146146
0082 <span class="keyword">end</span>
147-
0083 <span class="keyword">if</span> isfield(model,<span class="string">'rxnNotes'</span>)
148-
0084 model.rxnNotes=[model.rxnNotes;filler];
149-
0085 <span class="keyword">end</span>
150-
0086 <span class="keyword">if</span> isfield(model,<span class="string">'rxnReferences'</span>)
151-
0087 model.rxnReferences=[model.rxnReferences;filler];
152-
0088 <span class="keyword">end</span>
153-
0089 <span class="keyword">if</span> isfield(model,<span class="string">'rxnConfidenceScores'</span>)
154-
0090 model.rxnConfidenceScores=[model.rxnConfidenceScores;NaN(numel(J),1)];
155-
0091 <span class="keyword">end</span>
156-
0092 <span class="keyword">if</span> isfield(model,<span class="string">'rxnDeltaG'</span>)
157-
0093 model.rxnDeltaG=[model.rxnDeltaG;NaN(numel(J),1)];
158-
0094 <span class="keyword">end</span>
159-
0095 <span class="keyword">end</span></pre></div>
147+
0083 <span class="keyword">if</span> isfield(model,<span class="string">'rxnComps'</span>)
148+
0084 model.rxnComps=[model.rxnComps;ones(numel(J),1)];
149+
0085 fprintf(<span class="string">'NOTE: The exchange reactions are assigned to the first compartment\n'</span>);
150+
0086 <span class="keyword">end</span>
151+
0087 <span class="keyword">if</span> isfield(model,<span class="string">'rxnNotes'</span>)
152+
0088 model.rxnNotes=[model.rxnNotes;filler];
153+
0089 <span class="keyword">end</span>
154+
0090 <span class="keyword">if</span> isfield(model,<span class="string">'rxnReferences'</span>)
155+
0091 model.rxnReferences=[model.rxnReferences;filler];
156+
0092 <span class="keyword">end</span>
157+
0093 <span class="keyword">if</span> isfield(model,<span class="string">'rxnConfidenceScores'</span>)
158+
0094 model.rxnConfidenceScores=[model.rxnConfidenceScores;NaN(numel(J),1)];
159+
0095 <span class="keyword">end</span>
160+
0096 <span class="keyword">if</span> isfield(model,<span class="string">'rxnDeltaG'</span>)
161+
0097 model.rxnDeltaG=[model.rxnDeltaG;NaN(numel(J),1)];
162+
0098 <span class="keyword">end</span>
163+
0099 <span class="keyword">end</span></pre></div>
160164
<hr><address>Generated by <strong><a href="http://www.artefact.tk/software/matlab/m2html/" title="Matlab Documentation in HTML">m2html</a></strong> &copy; 2005</address>
161165
</body>
162166
</html>

0 commit comments

Comments
 (0)