Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,10 @@

## Unreleased

### I/O

* `writeYAMLmodel` writes an ec reaction without enzymes (a row of zeros in `model.ec.rxnEnzMat`) with no `enzymes` entry (was: `- enzymes: !!omap` with nothing under it, which is not valid YAML). `readYAMLmodel` reads a missing `enzymes` entry as a reaction without enzymes, and still reads `- enzymes: !!omap` with no entries and `- enzymes: !!omap []` from files written earlier.

### Manipulation

* `mergeCompartments`: a merged metabolite is the copy already in compartment `s`, if any,
Expand Down
5 changes: 3 additions & 2 deletions src/io/writeYAMLmodel.m
Original file line number Diff line number Diff line change
Expand Up @@ -224,9 +224,10 @@ function writeField(model,fid,fieldName,type,pos,name,keyIndent)
end

elseif strcmp(fieldName,'rxnEnzMat')
%S: create header & write each enzyme in a new line
fprintf(fid,'%s: !!omap\n',name);
%enzymes: create header & write each enzyme in a new line. A
%reaction without enzymes has no entry at all.
if sum(field(pos,:) ~= 0) > 0
fprintf(fid,'%s: !!omap\n',name);
model.enzymes = model.enzymes(field(pos,:) ~= 0);
model.coeffs = field(pos,field(pos,:) ~= 0);
%Sort metabolites:
Expand Down
73 changes: 73 additions & 0 deletions tests/function_tests/tIO.m
Original file line number Diff line number Diff line change
Expand Up @@ -287,6 +287,60 @@ function writeReadYAMLRoundTrip(testCase)
testCase.verifyEqual(numel(m2.rxns), numel(testCase.model.rxns));
end

function writeYAMLmodelOmitsEnzymesOfEcReactionWithoutEnzymes(testCase)
% An ec reaction whose rxnEnzMat row is empty has no enzymes
% entry in the file; the reaction before and after keep theirs.
m = testCase.ecYamlModel();
f = [tempname '.yml'];
testCase.addTeardown(@() delete(f));
evalc('writeYAMLmodel(m, f);');
txt = fileread(f);
% two ec reactions with enzymes and two ec-enzymes entries
testCase.verifyEqual(numel(strfind(txt, '- enzymes:')), 4);
lines = splitlines(txt);
idx = find(strcmp(strtrim(lines), '- id: ec_R2'));
testCase.verifyEqual(numel(idx), 1);
testCase.verifyFalse(contains(lines{idx+1}, 'enzymes'));
testCase.verifyFalse(contains(lines{idx+2}, 'enzymes'));
end

function readYAMLmodelReadsEcReactionWithoutEnzymes(testCase)
% The reaction without enzymes has a zero row in rxnEnzMat and
% keeps its id and kcat; the other rows are unchanged.
m = testCase.ecYamlModel();
f = [tempname '.yml'];
testCase.addTeardown(@() delete(f));
evalc('writeYAMLmodel(m, f);');
evalc('m2 = readYAMLmodel(f);');
testCase.verifyEqual(m2.ec.rxns, m.ec.rxns);
testCase.verifyEqual(m2.ec.kcat, m.ec.kcat, 'AbsTol', 1e-9);
testCase.verifyEqual(full(m2.ec.rxnEnzMat), m.ec.rxnEnzMat);
end

function readYAMLmodelReadsOlderEmptyEnzymesForms(testCase)
% Files written earlier carry a content-less "enzymes: !!omap"
% or "enzymes: !!omap []" for a reaction without enzymes.
m = testCase.ecYamlModel();
f = [tempname '.yml'];
testCase.addTeardown(@() delete(f));
evalc('writeYAMLmodel(m, f);');
txt = fileread(f);
forms = {' - enzymes: !!omap', ' - enzymes: !!omap []'};
for i = 1:numel(forms)
lines = splitlines(txt);
idx = find(strcmp(strtrim(lines), '- id: ec_R2'));
lines = [lines(1:idx+1); forms(i); lines(idx+2:end)];
g = [tempname '.yml'];
testCase.addTeardown(@() delete(g));
fid = fopen(g, 'w');
fprintf(fid, '%s', strjoin(lines, newline));
fclose(fid);
evalc('m2 = readYAMLmodel(g);');
testCase.verifyEqual(m2.ec.rxns, m.ec.rxns);
testCase.verifyEqual(full(m2.ec.rxnEnzMat), m.ec.rxnEnzMat);
end
end

function readYAMLmodelKeepsSubsystemsAligned(testCase)
% Reactions without a subsystem sit between, before and after
% those with one: each subsystem stays with its own reaction,
Expand Down Expand Up @@ -583,4 +637,23 @@ function writeExcelRoundTrips(testCase)
end

end

methods (Access = private)
function m = ecYamlModel(testCase)
% Model with three ec reactions; the second has no enzymes.
m = testCase.model;
m.ec.geckoLight = false;
m.ec.rxns = {'ec_R1'; 'ec_R2'; 'ec_R3'};
m.ec.kcat = [13.7; 5; 2];
m.ec.source = {'brenda'; 'standard'; ''};
m.ec.notes = {''; ''; ''};
m.ec.eccodes = {'1.1.1.1'; ''; ''};
m.ec.genes = m.genes(1:2);
m.ec.enzymes = {'P0A1'; 'P0A2'};
m.ec.mw = [51000; 40000];
m.ec.sequence = {'MABC'; 'MDEF'};
m.ec.concs = [NaN; NaN];
m.ec.rxnEnzMat = [1 2; 0 0; 0 1];
end
end
end
Loading