Skip to content

Commit c5a805b

Browse files
committed
RAVEN 2.10.2
2 parents 6655b71 + ca888bc commit c5a805b

21 files changed

+1095
-1016
lines changed

.github/CONTRIBUTING.md

Lines changed: 67 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,67 @@
1+
## Contributor guidelines
2+
3+
Anybody is welcome to contribute to the development of the RAVEN Toolbox, but please abide by the following guidelines.
4+
5+
Each function should start with a commented section describing the function and explaining the parameters. Existing functions can clarify what style should be used.
6+
7+
### Bugfixes, New Features and Functions
8+
* For any development, whether bug fixes, introducing new functions or new/updated features for existing functions: make a separate branch from `devel` and name the branch for instance after the function/feature you are fixing/developing. If you work on a fix, start the branch name with `fix/`, if you work on a feature, start the branch name with `feat/`. Examples: `fix/format_reactions` or `feat/new_algorithms`.
9+
* Make commits to this branch while developing. Aim for backward compatibility, and try to avoid very new MATLAB functions when possible, to accommodate users with older MATLAB versions.
10+
* When you are happy with your new function/feature, make a pull request to the `devel` branch. Also, see [Pull request](#pull-request) below.
11+
12+
### Semantic Commits
13+
Use semantic commit messages to make it easier to show what you are aiming to do:
14+
* `chore`: updating binaries, KEGG or MetaCyc database files, etc.
15+
* `doc`: updating documentation (in `doc` folder) or explanatory comments in functions.
16+
* `feat`: new feature added, e.g. new function introduced / new parameters / new algorithm / etc.
17+
* `fix`: bugfix.
18+
* `refactor`: see [code refactoring](https://en.wikipedia.org/wiki/Code_refactoring).
19+
* `style`: minor format changes of functions (spaces, semi-colons, etc., no code change).
20+
21+
Examples:
22+
```
23+
feat: exportModel additional export to YAML
24+
chore: update KEGG model to version 83.0
25+
fix: optimizeProb parsing results from Gurobi
26+
```
27+
A more detailed explanation or comments can be left in the commit description.
28+
29+
### External Software Update
30+
* Once the newer version for any external software (BLAST+, CD-HIT, DIAMOND, HMMER, MAFFT, WoLFPSORT) is available, identify the newest version which is simultaneously available for macOS, Unix/Linux and Windows
31+
* Create a separate branch from the `devel` branch and name it e.g. `chore/updateBinaries`
32+
* Commit the changes for each program and operating system separately, e.g. `chore: update HMMER (Win) to 3.2.1`
33+
* As soon as all binaries for particular program are updated through commits, update the corresponding license file, if available and place it in e.g. `software/blast+` directory.
34+
* Update the version number in `RAVENdir/software/version.txt` file.
35+
* Do some testing to ensure that the new binaries are working correctly. Upon successful tests, create a Pull Request to the `devel` branch.
36+
37+
### Pull Requests
38+
* No changes should be directly committed to the `main` or `devel` branches. Commits are made to side branches, after which pull requests are made for merging with `main` or `devel`.
39+
* The person making the pull request and the one accepting the merge _cannot_ be the same person.
40+
* Typically, wait a few days before merging, to allow for other developers to inspect the pull request.
41+
* A merge with the mainbranch invokes a new release (see [versioning](#versioning)).
42+
43+
### Versioning
44+
RAVEN Toolbox follows [semantic versioning](https://semver.org/). After each successful Pull Request (PR) to `main`, the `version.txt` file should be updated in a separate PR. When this PR is merged, a new [release](https://github.com/SysBioChalmers/RAVEN/releases) should be specified, with a list detailing the most significant changes since the previous release.
45+
46+
Ensure that the documentation is also updated (in `devel`) before creating a PR to `main`. It can be updated by running `updateDocumentation()`.
47+
48+
### Categorize Releases
49+
* PRs pushed into `main` should be patch releases by default.
50+
* Developers who push PRs to `devel` may propose target release categories (e.g. minor or patch) that can be commented on and discussed by reviewers and other developers.
51+
* As a result of the above step, minor releases hopefully can be determined.
52+
* To help the process of categorizing releases, some conditions are suggested qualification for minor releases:
53+
* with database updates (e.g. KEGG, MetaCyc)
54+
* script reusability (i.e. with parameter changes in RAVEN functions)
55+
* with binary file changes
56+
57+
## Make a New Release
58+
* Start a PR from develop to main with summary of all PRs since the last release, titled "RAVEN 2.9.3" (replace 2.9.3 with the version of the next release)
59+
* Once ready, locally merge develop into main by accepting all changes using following commands, and push to origin:
60+
* `git checkout main`
61+
* `git pull`
62+
* `git merge -Xtheirs develop -m "RAVEN 2.9.3"` (replace 2.9.3 with the version of the next release)
63+
* `printf "2.9.3" > version.txt` (replace 2.9.3 with the version of the next release)
64+
* `git stage version.txt`
65+
* `git commite --amend --no-edit`
66+
* `git push`
67+
* Initiate a new release, with name and tag "v2.9.3" (replace 2.9.3 with the version of the next release)

README.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -30,4 +30,4 @@ Use [GitHub Discussions](https://github.com/SysBioChalmers/RAVEN/discussions) fo
3030

3131
## Contributing
3232

33-
Contributions are always welcome! Please read the [contributing guidelines](https://github.com/SysBioChalmers/GECKO/blob/main/.github/CONTRIBUTING.md) to get started.
33+
Contributions are always welcome! Please read the [Contributor guidelines](https://github.com/SysBioChalmers/RAVEN/blob/main/.github/CONTRIBUTING.md) to get started.

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)