|
1 | | -function model=mergeModels(models,metParam,supressWarnings) |
| 1 | +function model=mergeModels(models,metParam,supressWarnings,copyToComps) |
2 | 2 | % mergeModels |
3 | 3 | % Merges models into one model structure. Reactions are added without any |
4 | 4 | % checks, so duplicate reactions might appear. Metabolites are matched by |
5 | 5 | % their name and compartment (metaboliteName[comp]), while genes are |
6 | 6 | % matched by their name. |
7 | 7 | % |
| 8 | +% Input: |
8 | 9 | % models a cell array with model structures |
9 | | -% metParam string specifying whether to refer to metabolite name |
10 | | -% (metNames) or ID (mets) for matching (default, metNames) |
11 | | -% supressWarnings true if warnings should be supressed (optional, default |
12 | | -% false) |
| 10 | +% metParam string metabolite name ('metNames') or ID ('mets') are |
| 11 | +% used for matching (optional, default 'metNames') |
| 12 | +% supressWarnings logical whether warnings should be supressed (optional, |
| 13 | +% default false) |
| 14 | +% copyToComps logical whether mergeModels is run via copyToComps |
| 15 | +% (optional, default false) |
13 | 16 | % |
14 | | -% model a model structure with the merged model. Follows the structure |
15 | | -% of normal models but also has 'rxnFrom/metFrom/geneFrom' fields |
16 | | -% to indicate from which model each reaction/metabolite/gene was |
17 | | -% taken |
| 17 | +% Output: |
| 18 | +% model a model structure with the merged model. Follows the |
| 19 | +% structure of normal models but also has 'rxnFrom/ |
| 20 | +% metFrom/geneFrom' fields to indicate from which model |
| 21 | +% each reaction/metabolite/gene was taken. If the model |
| 22 | +% already has 'rxnFrom/metFrom/geneFrom' fields, then |
| 23 | +% these fields are not modified. |
18 | 24 | % |
19 | 25 | % Usage: model=mergeModels(models) |
20 | 26 |
|
| 27 | +arguments |
| 28 | + models; |
| 29 | + metParam {emptyOrTextScalar} = "metNames" |
| 30 | + supressWarnings {emptyOrLogicalScalar} = false |
| 31 | + copyToComps {emptyOrLogicalScalar} = false |
| 32 | +end |
| 33 | + |
| 34 | +metParam = char(metParam); |
| 35 | + |
21 | 36 | %Just return the model |
22 | 37 | if numel(models)<=1 |
23 | 38 | model=models{1}; |
24 | 39 | return; |
25 | 40 | end |
26 | 41 |
|
27 | | -if nargin<2 |
28 | | - metParam='metNames'; |
29 | | -else |
30 | | - metParam=char(metParam); |
31 | | -end |
| 42 | +hasMetFrom = cellfun(@(s) isfield(s,'metFrom'), models); |
| 43 | +hasGeneFrom = cellfun(@(s) isfield(s,'geneFrom'), models); |
| 44 | +hasRxnFrom = cellfun(@(s) isfield(s,'rxnFrom'), models); |
32 | 45 |
|
33 | | -if nargin<3 |
34 | | - supressWarnings=false; |
| 46 | +for i = 1:numel(models) |
| 47 | + if copyToComps |
| 48 | + if hasMetFrom(1) |
| 49 | + models{2}.metFrom = repmat({''},numel(models{i}.mets),1); |
| 50 | + end |
| 51 | + elseif ~any(hasMetFrom) |
| 52 | + models{i}.metFrom = repmat({models{i}.id},numel(models{i}.mets),1); |
| 53 | + elseif ~hasMetFrom(i) |
| 54 | + models{i}.metFrom = repmat({''},numel(models{i}.mets),1); |
| 55 | + end |
| 56 | + if copyToComps |
| 57 | + if hasRxnFrom(1) |
| 58 | + models{2}.rxnFrom = repmat({''},numel(models{i}.rxns),1); |
| 59 | + end |
| 60 | + elseif ~any(hasRxnFrom) |
| 61 | + models{i}.rxnFrom = repmat({models{i}.id},numel(models{i}.rxns),1); |
| 62 | + elseif ~hasRxnFrom(i) |
| 63 | + models{i}.rxnFrom = repmat({''},numel(models{i}.rxns),1); |
| 64 | + end |
| 65 | + if copyToComps |
| 66 | + if hasGeneFrom(1) |
| 67 | + models{2}.geneFrom = repmat({''},numel(models{i}.genes),1); |
| 68 | + end |
| 69 | + elseif ~any(hasGeneFrom) && any(cellfun(@(s) isfield(s,'genes'), models)) |
| 70 | + models{i}.geneFrom = repmat({models{i}.id},numel(models{i}.genes),1); |
| 71 | + elseif ~hasGeneFrom(i) |
| 72 | + models{i}.geneFrom = repmat({''},numel(models{i}.genes),1); |
| 73 | + end |
35 | 74 | end |
36 | 75 |
|
37 | 76 | %Add new functionality in the order specified in models |
38 | 77 | model=models{1}; |
39 | 78 | model.id='MERGED'; |
40 | 79 | model.name=''; |
41 | 80 |
|
42 | | -model.rxnFrom=cell(numel(models{1}.rxns),1); |
43 | | -model.rxnFrom(:)={models{1}.id}; |
44 | | -model.metFrom=cell(numel(models{1}.mets),1); |
45 | | -model.metFrom(:)={models{1}.id}; |
46 | | -if isfield(models{1},'genes') |
47 | | - model.geneFrom=cell(numel(models{1}.genes),1); |
48 | | - model.geneFrom(:)={models{1}.id}; |
49 | | -end |
50 | | - |
51 | 81 | if isfield(model,'equations') |
52 | 82 | model=rmfield(model,'equations'); |
53 | 83 | end |
|
78 | 108 | end |
79 | 109 |
|
80 | 110 | %Add all static stuff |
81 | | - rxnFrom=cell(numel(models{i}.rxns),1); |
82 | | - rxnFrom(:)={models{i}.id}; |
83 | | - model.rxnFrom=[model.rxnFrom;rxnFrom]; |
84 | | - model.rxns=[model.rxns;models{i}.rxns]; |
85 | | - model.rxnNames=[model.rxnNames;models{i}.rxnNames]; |
86 | | - model.lb=[model.lb;models{i}.lb]; |
87 | | - model.ub=[model.ub;models{i}.ub]; |
88 | | - model.c=[model.c;models{i}.c]; |
89 | | - model.rev=[model.rev;models{i}.rev]; |
| 111 | + if any(hasRxnFrom) || (~copyToComps && ~any(hasRxnFrom)) |
| 112 | + model.rxnFrom = [model.rxnFrom; models{i}.rxnFrom]; |
| 113 | + end |
| 114 | + model.rxns = [model.rxns; models{i}.rxns]; |
| 115 | + model.rxnNames = [model.rxnNames; models{i}.rxnNames]; |
| 116 | + model.lb = [model.lb; models{i}.lb]; |
| 117 | + model.ub = [model.ub; models{i}.ub]; |
| 118 | + model.c = [model.c; models{i}.c]; |
| 119 | + model.rev = [model.rev; models{i}.rev]; |
90 | 120 |
|
91 | 121 | if isfield(models{i},'subSystems') |
92 | 122 | if isfield(model,'subSystems') |
|
287 | 317 | end |
288 | 318 |
|
289 | 319 | %Add static info on the metabolites |
290 | | - metFrom=cell(numel(metsToAdd),1); |
291 | | - metFrom(:)={models{i}.id}; |
292 | | - model.metFrom=[model.metFrom;metFrom]; |
293 | | - model.mets=[model.mets;models{i}.mets(metsToAdd)]; |
294 | | - model.metNames=[model.metNames;models{i}.metNames(metsToAdd)]; |
295 | | - model.b=[model.b;zeros(numel(metsToAdd),size(model.b,2))]; |
| 320 | + if any(hasMetFrom) |
| 321 | + model.metFrom = [model.metFrom; models{i}.metFrom(metsToAdd)]; |
| 322 | + end |
| 323 | + model.mets = [model.mets; models{i}.mets(metsToAdd)]; |
| 324 | + model.metNames = [model.metNames; models{i}.metNames(metsToAdd)]; |
| 325 | + model.b = [model.b; zeros(numel(metsToAdd),size(model.b,2))]; |
296 | 326 |
|
297 | 327 | if isfield(model,'unconstrained') |
298 | 328 | if isfield(models{i},'unconstrained') |
|
481 | 511 | if isfield(models{i},'genes') |
482 | 512 | if ~isfield(model,'genes') |
483 | 513 | %If there was no gene info before |
484 | | - model.genes=models{i}.genes; |
485 | | - model.rxnGeneMat=[sparse(numel(model.rxns),numel(models{i}.genes));models{i}.rxnGeneMat]; |
486 | | - emptyGene=cell(numel(model.rxns),1); |
487 | | - emptyGene(:)={''}; |
488 | | - model.grRules=[emptyGene;models{i}.grRules]; |
489 | | - model.geneFrom=cell(numel(models{i}.genes),1); |
490 | | - model.geneFrom(:)={models{i}.id}; |
| 514 | + model.genes = models{i}.genes; |
| 515 | + model.rxnGeneMat = [sparse(numel(model.rxns),numel(models{i}.genes));models{i}.rxnGeneMat]; |
| 516 | + emptyGene = repmat({''},numel(model.rxns),1); |
| 517 | + model.grRules = [emptyGene;models{i}.grRules]; |
| 518 | + if any(hasGeneFrom) |
| 519 | + model.geneFrom = models{i}.geneFrom; |
| 520 | + end |
491 | 521 |
|
492 | 522 | if isfield(models{i},'geneShortNames') |
493 | 523 | model.geneShortNames=models{i}.geneShortNames; |
|
513 | 543 | %Only add extra gene info on new genes. This might not be |
514 | 544 | %correct and should be changed later... |
515 | 545 | if ~isempty(genesToAdd) |
516 | | - model.genes=[model.genes;models{i}.genes(genesToAdd)]; |
517 | | - emptyGene=cell(numel(genesToAdd),1); |
518 | | - emptyGene(:)={models{i}.id}; |
519 | | - model.geneFrom=[model.geneFrom;emptyGene]; |
520 | | - model.rxnGeneMat=[model.rxnGeneMat sparse(size(model.rxnGeneMat,1),numel(genesToAdd))]; |
| 546 | + model.genes = [model.genes; models{i}.genes(genesToAdd)]; |
| 547 | + model.geneFrom = [model.geneFrom; models{i}.geneFrom(genesToAdd)]; |
| 548 | + model.rxnGeneMat = [model.rxnGeneMat sparse(size(model.rxnGeneMat,1),numel(genesToAdd))]; |
521 | 549 |
|
522 | 550 | if isfield(models{i},'geneShortNames') |
523 | 551 | if isfield(model,'geneShortNames') |
|
587 | 615 | %Remap the genes from the new model. The same thing as with |
588 | 616 | %mets; this is a wasteful way to do it but I don't care right |
589 | 617 | %now |
590 | | - [a, b]=ismember(models{i}.genes,model.genes); |
| 618 | + a = ismember(models{i}.genes,model.genes); |
591 | 619 |
|
592 | 620 | %Just a check |
593 | 621 | if ~all(a) |
|
0 commit comments